根据列表中未找到的列中的值删除 R 数据框中的行

问题描述

我想根据列中的值删除数据框中的行,这些值在使用 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