【问题标题】:Filter a dataframe by its entry按条目过滤数据框
【发布时间】:2016-11-24 23:43:50
【问题描述】:

如何按特定值过滤数据集,该值可能出现在数据框中的任何位置,不一定在任何一列或一行下?

假设我有一个这样的数据框。

   id gender group Student_Math_1 Student_Math_2 Student_Read_1 Student_Read_2
   46      M   Red             23             45             37             56
   46      M   Red             34             36             33             78
   46      M   Red             56             63             58             NA
   62      F  Blue             59             NA             NA             68
   62      F  Blue             NA             68             87             73
   38      M   Red             78             57             NA             65
   38      M   Red             NA             75             54             NA
   17      F  Blue             74             NA             56             72
   17      F  Blue             75             61             NA             79
   17      F  Blue             NA             74             43             81

我正在尝试对这个数据框进行子集化,以便保留包含值 68 的所有行和列,而不管它在数据框内的哪个位置出现。

最终的输出是

   id gender group Student_Math_1 Student_Math_2 Student_Read_1 Student_Read_2

   62      F  Blue             59             NA             NA             68
   62      F  Blue             NA             68             87             73

欢迎任何提示或建议。提前致谢。

df = structure(list(id = c(46, 46, 46, 62, 62, 38, 38, 17, 17, 17), 
    gender = structure(c(2L, 2L, 2L, 1L, 1L, 2L, 2L, 1L, 1L, 
    1L), .Label = c("F", "M"), class = "factor"), group = structure(c(2L, 
    2L, 2L, 1L, 1L, 2L, 2L, 1L, 1L, 1L), .Label = c("Blue", "Red"
    ), class = "factor"), Student_Math_1 = c(23, 34, 56, 59, 
    NA, 78, NA, 74, 75, NA), Student_Math_2 = c(45, 36, 63, NA, 
    68, 57, 75, NA, 61, 74), Student_Read_1 = c(37, 33, 58, NA, 
    87, NA, 54, 56, NA, 43), Student_Read_2 = c(56, 78, NA, 68, 
    73, 65, NA, 72, 79, 81)), .Names = c("id", "gender", "group", 
"Student_Math_1", "Student_Math_2", "Student_Read_1", "Student_Read_2"
), row.names = c(NA, -10L), class = "data.frame")

【问题讨论】:

  • 一般来说,你可以考虑将你的数据结构从宽格式改成长格式。第 4 到 7 列似乎包含所有相同类型的数据(成绩?百分比?),而列标题看起来像属性(测试名称?)。宽格式通常是您在 Excel 电子表格中收集数据时得到的,但长格式通常更便于在 R 中进行数据操作或聚合。

标签: r dataframe subset


【解决方案1】:

怎么样:

## use data from "Student_Math_1" column to "Student_Read_2" column
df[rowSums(df[4:7] == 68, na.rm = TRUE) > 0, ]

#  id gender group Student_Math_1 Student_Math_2 Student_Read_1 Student_Read_2
#4 62      F  Blue             59             NA             NA             68
#5 62      F  Blue             NA             68             87             73

注意,df[4:7] == 68 返回一个逻辑矩阵(与NA),我们将rowSumsna.rm = TRUE 结合使用。在这样的算术运算中,TRUE 被视为 1,FALSE 被视为 0。


跟进

感谢 Ben Bolker 提醒这个更具可读性的解决方案,如果你正在学习 R,你当然需要掌握它:

df[apply(df[4:7] == 68, 1L, any, na.rm = TRUE), ]

按行应用any(与na.rm = TRUE)。我不记得我在哪里比较了这两者的性能。但我不会费心做一个快速的实验:

library(microbenchmark)

## For simplicity / neatness, I generate a logical matrix `X` without `NA`
X <- matrix(sample(c(TRUE, FALSE), 2000 * 10, replace = TRUE), 2000)

## also measuring 989's solution
microbenchmark(ZL = rowSums(X) > 0,
               Ben = apply(X, 1L, any),
               "989" = unique(which(X, arr.ind = T)[,1]))

#Unit: microseconds
# expr     min      lq      mean  median      uq     max neval cld
#   ZL  144.24  149.76  183.3516  164.86  172.48 2077.80   100 a  
#  Ben 5610.08 5730.78 6003.0660 5779.20 5861.46 8021.72   100   c
#  989 1571.72 1639.58 2033.4224 1664.78 1721.18 5339.48   100  b 

【讨论】:

  • 哎呀。 df[apply(df[,3:7]==68,1,any,na.rm=TRUE),],这并没有比这个解决方案更清楚。
  • 一般来说,我喜欢 any()/all() 的可读性(而不是对强制为 0/1 的逻辑进行数字运算),但在这种情况下,我同意它没有多大帮助。我认为像这样的操作的时间差异通常是微不足道的,除非使用真正巨大的数据......
  • @BenBolker - 有趣 - 我认为在时间上会有更大的惩罚。在 100k 行上,差异仍然只有几分之一秒。如果 1M 行或以上,可能会大幅增加。
  • @ZheyuanLi,我只能删除我的cmets。我已经做到了。
【解决方案2】:

或者,

df[unique(which(df==68, arr.ind = T)[,1]),]

#  id gender group Student_Math_1 Student_Math_2 Student_Read_1 Student_Read_2
#5 62      F  Blue             NA             68             87             73
#4 62      F  Blue             59             NA             NA             68

在这种情况下,您不需要关心列的位置或出现NAs 的位置。 unique 用于 68 每行出现多次的情况。

【讨论】:

  • 这会在68 连续出现多次的情况下返回重复行。
  • @989,我发现这个解决方案很简单,完全符合我的预期
猜你喜欢
  • 2018-08-13
  • 1970-01-01
  • 1970-01-01
  • 2018-03-08
  • 2019-03-07
  • 1970-01-01
  • 1970-01-01
  • 2019-09-21
相关资源
最近更新 更多