问题描述
我想根据列中的值删除数据框中的行,这些值在使用 R 基础的列表中找不到。
structure(list(CountryCode = c("AUS","CAN","DEU","DNK","ESP","FRA","ITA","JPN","KOR","NHL","nor","SGP","SWE","UK","AUS","UK"),Date = c("Mar 30 - Apr 05 (2010)","Mar 30 - Apr 05 (2010)","Apr 06 - Apr 12 (2010)","Mar 22 - Mar 28 (2000)","Apr 05 - Apr 11 (2000)","Mar 29 - Apr 04 (2000)","Feb 08 - Feb 14 (2000)","Apr 05 - Apr 11 (2000)"
),sumofpct = c(94,95,92,90,96,97,83,89,91,93,84,94,85,86,88,93
),timepoint = c("first","first","last","last"
)),row.names = c(NA,-28L),groups = structure(list(CountryCode = c("AUS",.rows = structure(list(c(1L,15L),c(2L,16L),c(3L,17L),c(4L,18L),c(5L,19L),c(6L,20L
),c(7L,21L),c(8L,22L),c(9L,23L),c(10L,24L),c(11L,25L),c(12L,26L),c(13L,27L),c(14L,28L)),ptype = integer(0),class = c("vctrs_list_of","vctrs_vctr","list"))),14L),class = c("tbl_df","tbl","data.frame"),.drop = TRUE),class = c("grouped_df","tbl_df","data.frame"))
> df
Category.1 Value.1 Category.2 Value.2
A 0.1 A 0.1
A 0.1 A 0.2
A 0.1 A 0.3
A 0.1 B 0.6
A 0.1 B 0.7
A 0.1 B 0.8
A 0.1 C 0.5
A 0.1 C 0.8
A 0.1 C 0.9
. . . .
B 0.3 A 0.1
B 0.4 A 0.2
B 0.5 A 0.3
B 0.1 B 0.6
B 0.2 B 0.7
B 0.3 B 0.8
B 0.3 C 0.5
B 0.8 C 0.8
B 0.6 C 0.9
. . . .
Z 0.1 X 0.1
Z 0.1 X 0.3
Z 0.1 X 0.4
Z 0.1 Y 0.6
Z 0.1 Y 0.8
Z 0.1 Y 0.4
Z 0.1 Z 0.2
Z 0.1 Z 0.1
Z 0.1 Z 0.6
我想过滤满足特定条件的行的数据框。更具体地说,我想保留具有相同类别的行,独立于它们的值,以及不具有相同类别的行,但它们的值分别在列表中。
简化:删除行,其中
> List
A 0.1 0.2 0.3 0.4
B 0.3 0.4 0.5 0.6
C 0.5 0.6 0.8 0.9
. . . . .
Z 0.1 0.2 0.3 0.4
不等于 Category.1
AND Category.2
不在与 Value.1
名称匹配的列表中
OR Category.1
不在与 Value.2
名称匹配的列表中
只要列表中未找到来自 Category.1 或 Category.2 的值之一,并且 Category.1 和 Category.2 不同,则删除该行。
现在,使用 Category.2
找到解决方案非常简单,但我需要在 dplyr
中找到解决方案。以下是有效的 R base
方法:
dyplr 示例(工作):
dplyr
我还能够通过遍历每一行在 df %>% rowwise() %>%
filter(ifelse(Category.1 == Category.2,Category.1 == Category.2,Value.1 %in% List[[Category.1]] &
Value.2 %in% List[[Category.2]]))
中提出解决方案,但这不是最有效的方法,尤其是对于具有 > 10 000 行的数据框,它花费的时间太长.
R 基础示例(有效,但速度较慢):
R base
由于我在这里的主要目标是对数据进行子集化,因此我尝试使用 df[sapply(1:nrow(df),function(x) (df[x,"Category.1"] == df[x,"Category.2"] |
df[x,"Category.1"] != df[x,"Category.2"] &
df[x,"Value.1"] %in% List[[match(df[x,"Category.1"],names(List))]] &
df[x,"Value.2"] %in% List[[match(df[x,"Category.2"],names(List))]])),]
和以下表达式:
subset() 方法(不起作用):
subset()
这只选择subset(df,Category.1 == Category.2 |
Category.1 != Category.2 &
Value.1 %in% List[match(Category.1,names(List)][[1]] &
Value.2 %in% List[match(Category.2,names(List)][[1]])
。不确定,为什么它不起作用。有人有想法吗?
有没有更好的解决方案?
如果有帮助,这里是代表性数据框和列表的代码:
示例数据:
Category.1 == Category.2
为简单起见,列表中的值都相同。
解决方法
这是一个更简单的示例,其中仅应删除第 3 行。对于这个大例子,很难说清楚发生了什么。
df <- data.frame(Category.1 = c("A","A","B","B"),Value.1 = c(.2,.2,.1,.2),Category.2 = c("A",Value.2 = c(0,.3,.2))
vals = c(0.2,0.3,0.6,0.8)
List <- list(A = vals,B = vals)
这是一个有效的解决方案。这是您的工作解决方案的修改版本,我们将 ==
带出 sapply
(它是矢量化的),省略冗余 !=
条件,并使用直接名称索引而不是 {{ 1}}。您共享的较大数据上的 match
使其看起来快 2 倍。
microbenchmark