【问题标题】:Remove rows in R data frame based on values in columns not found in a list根据列表中未找到的列中的值删除 R 数据框中的行
【发布时间】:2021-07-15 09:41:43
【问题描述】:

我想根据列中的值删除数据框中的行,这些值在使用 R 基础的列表中找不到。

我有一个简化的数据框,如下所示:

> 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 的行,独立于它们的 Value,以及不具有相同 Category 的行,但它们的分别在列表中找到。

简化:删除行,其中

Category.1 不等于 Category.2

AND Value.1不在与Category.1名称匹配的列表中

Value.2不在与Category.2名称匹配的列表中

只要在列表中未找到 Category.1 或 Category.2 中的值之一,并且 Category.1 和 Category.2 不同,则删除该行。

现在,通过dplyr 找到解决方案非常简单,但我需要在R base 中找到解决方案。这是有效的dplyr 方法:

dyplr 示例(工作):

df %>% rowwise() %>% 
       filter(ifelse(Category.1 == Category.2, 
                     Category.1 == Category.2, 
                     Value.1 %in% List[[Category.1]] & 
                     Value.2 %in% List[[Category.2]]))

我还能够通过循环遍历每一行在R base 中提出解决方案,但这不是最有效的方法,尤其是对于具有 > 10 000 行的数据框,它需要的时间太长了。

R 基础示例(工作,但速度慢):

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。不确定,为什么它不起作用。有人有想法吗?

有没有更好的解决方案?

如果有帮助,这里是代表数据框和列表的代码:

示例数据:

df <- data.frame(Category.1 = rep(LETTERS, each = 7), Value.1 = rep(seq(0.2, 0.8, 0.1), length(LETTERS)),
                 Category.2 = sample(rep(LETTERS, each = 7)), Value.2 = rep(rev(seq(0.2, 0.8, 0.1)), length(LETTERS)))

List <- setNames(lapply(LETTERS,  function(x) c(0.2, 0.3, 0.6, 0.8)), LETTERS)

为简单起见,列表中的值都相同。

【问题讨论】:

  • 如果你放弃坚持使用base R,我建议anti_join
  • 您打印List 的方式看起来像是data.frame,甚至可能是matrix,而不是list。您能否以更可重复的方式共享您的数据? dput(head(List))dput(df[1:10, ]) 可以复制/粘贴并包含所有类和结构信息 - 如果您在问题中包含这些输出,它将更容易为您提供帮助。
  • 我现在添加了一个有代表性的数据集。
  • @GregorThomas 我已经添加了dfList。很抱歉最初的混乱,很难粘贴列表。为回答您的问题,对象List 属于list 类。 &gt; class(List) [1] "list"
  • 我很惊讶你说dplyr 方法有效,当我在你的数据上尝试它时出现“递归索引”错误。

标签: r base


【解决方案1】:

这是一个更简单的示例,只应删除第 3 行。举个大例子,很难说到底发生了什么。

df <- data.frame(Category.1 = c("A", "A", "B", "B"), Value.1 = c(.2, .2, .1, .2),
                 Category.2 = c("A", "B", "A", "B"), Value.2 = c(0, .3, .2, .2))

vals = c(0.2, 0.3, 0.6, 0.8)
List <- list(A = vals, B = vals)

这是一个可行的解决方案。这是您的工作解决方案的修改版本,我们将==sapply 中取出(它是矢量化的),省略了多余的!= 条件,并使用直接名称索引而不是matchmicrobenchmark 在您共享的较大数据上使其看起来快 2 倍。

df[
  df[, "Category.1"] == df[, "Category.2"] | 
  sapply(1:nrow(df), function(x) {
  df[x,"Value.1"] %in% List[[df[x,"Category.1"]]] &
    df[x,"Value.2"] %in% List[[df[x,"Category.1"]]]
  }), 
]

#   Category.1 Value.1 Category.2 Value.2
# 1          A     0.2          A     0.0
# 2          A     0.2          B     0.3
# 4          B     0.2          B     0.2

【讨论】:

  • 谢谢!这种修改确实加快了速度。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-13
  • 2021-08-19
  • 2012-05-02
  • 2021-06-23
  • 1970-01-01
  • 2021-10-23
相关资源
最近更新 更多