【问题标题】:How should I drop blocks of NAs from an R data.table我应该如何从 R data.table 中删除 NA 块
【发布时间】:2012-12-31 00:28:59
【问题描述】:

我有一个带有多列键的大 R data.table,其中一些值列包含一些 NA。我想删除一个或多个值列中完全不适用的组,但保留整个组。对键的每一列重复此操作。

举个简单的例子:

library(data.table)
DT = data.table(
    Series = rep(letters[1:12], each = 3), 
    Id = 1:12,
    Value1 = c(1:3, NA, 5:9, rep(NA,3), 1:3, NA, 5:9, rep(NA,3), 1:3, NA, 5:9, rep(NA,3)), 
    Value2 = c(rep(NA,3), 1:4, NA, 6:9, rep(NA,3), 1:9, 1:9, rep(NA,3)))
DT
    Series Id Value1 Value2
 1:      a  1      1     NA
 2:      a  2      2     NA
 3:      a  3      3     NA
 4:      b  4     NA      1
 5:      b  5      5      2
 6:      b  6      6      3
 7:      c  7      7      4
 8:      c  8      8     NA
 9:      c  9      9      6
10:      d 10     NA      7
11:      d 11     NA      8
12:      d 12     NA      9
13:      e  1      1     NA
14:      e  2      2     NA
15:      e  3      3     NA
16:      f  4     NA      1
17:      f  5      5      2
18:      f  6      6      3
19:      g  7      7      4
20:      g  8      8      5
21:      g  9      9      6
22:      h 10     NA      7
23:      h 11     NA      8
24:      h 12     NA      9
25:      i  1      1      1
26:      i  2      2      2
27:      i  3      3      3
28:      j  4     NA      4
29:      j  5      5      5
30:      j  6      6      6
31:      k  7      7      7
32:      k  8      8      8
33:      k  9      9      9
34:      l 10     NA     NA
35:      l 11     NA     NA
36:      l 12     NA     NA
    Series Id Value1 Value2

所以我想放弃:

  • 系列:a、d、e、h 和 l
  • ID:4、10,11 和 12

正确的结果应该是这样的:

    Series Id Value1 Value2
 1:      b  5      5      2
 2:      b  6      6      3
 3:      c  7      7      4
 4:      c  8      8     NA
 5:      c  9      9      6
 6:      f  5      5      2
 7:      f  6      6      3
 8:      g  7      7      4
 9:      g  8      8      5
10:      g  9      9      6
11:      i  1      1      1
12:      i  2      2      2
13:      i  3      3      3
14:      j  5      5      5
15:      j  6      6      6
16:      k  7      7      7
17:      k  8      8      8
18:      k  9      9      9
    Series Id Value1 Value2

到目前为止我所管理的:

我可以像这样找到 Value1 不适用的系列:

DT[, sum(1-is.na(Value1)) == 0, by = Series][V1 == TRUE]

我什至可以做到

setkey(DT, Series)
DT = DT[DT[, sum(1-is.na(Value)) == 0, by = Series][V1 != TRUE]]

但现在我的 V1 出现在决赛桌。

【问题讨论】:

  • 为什么不只是na.omit(DT)
  • na.omit 只是删除了所有的 NA。我只想在整个“块”为 NA 时删除。因此在示例中,m 或 z 没有值,因此应该将它们删除,但我不想将 b 系列中的两个 NA 删除
  • 然后@Arun 有你的答案,但你不应该需要as.logical
  • 有趣,DT[, .SD[all(!is.na(Value))], by=Series] 工作正常。
  • 刚刚做了一个大的编辑,试图让问题更清晰,并使用更好/更简单的例子。从 Arun 的回答看来 .SD 是要走的路,可能是逻辑上的或者可以整理出多个值列,但是我该如何处理多个键列。一次做一个是唯一的方法吗? (因为我不能同时拥有两个键)

标签: r data.table


【解决方案1】:

您可以这样做来获取那些不是所有Value 都是NA 的条目:

setkey(DT, "Series")
DT[, .SD[(!all(is.na(Value)))], by=Series]

!all 周围的括号需要避免 Matthew 将研究的非连接语法(参见 cmets)。和这个一样:

DT[, .SD[as.logical(!all(is.na(Value)))], by=Series]

在此基础上回答新的澄清问题:

allNA = function(x) all(is.na(x))     # define helper function
for (i in c("Id","Series"))
    DT = DT[, if (!any(sapply(.SD,allNA))) .SD else NULL, by=i]
DT
    Series Id Value1 Value2
 1:      i  1      1      1
 2:      i  2      2      2
 3:      i  3      3      3
 4:      b  5      5      2
 5:      b  6      6      3
 6:      f  5      5      2
 7:      f  6      6      3
 8:      j  5      5      5
 9:      j  6      6      6
10:      c  7      7      4
11:      c  8      8     NA
12:      c  9      9      6
13:      g  7      7      4
14:      g  8      8      5
15:      g  9      9      6
16:      k  7      7      7
17:      k  8      8      8
18:      k  9      9      9

不过,这会改变顺序。所以不正是要求的结果。以下保持顺序,也应该更快。

# starting fresh from original DT in question again
DT[,drop:=FALSE]
for (i in c("Series","Id"))
    DT[,drop:=drop|any(sapply(.SD,allNA)),by=i]
DT[(!drop)][,drop:=NULL][]
    Series Id Value1 Value2
 1:      b  5      5      2
 2:      b  6      6      3
 3:      c  7      7      4
 4:      c  8      8     NA
 5:      c  9      9      6
 6:      f  5      5      2
 7:      f  6      6      3
 8:      g  7      7      4
 9:      g  8      8      5
10:      g  9      9      6
11:      i  1      1      1
12:      i  2      2      2
13:      i  3      3      3
14:      j  5      5      5
15:      j  6      6      6
16:      k  7      7      7
17:      k  8      8      8
18:      k  9      9      9

【讨论】:

  • +1 ! = 不加入,但我不确定为什么它不起作用(不应该对逻辑产生影响,可能是不加入与回收结合的概率,也许)
  • 好的,现在我明白了。 .SD[(!all(is.na(Value)))](带括号)有效!
  • parens 也可以阻止! 的非连接解释。当你说没用时,你的意思是什么,请问哪个版本的 data.table?谢谢。
  • 谢谢,这比我的效果好得多,但是知道如何将它扩展到多列吗?
  • setkey(DT,Series)[unique(DT[,na.omit(Value),by=Series][,Series]),] 也可以。但我懒得创建一个用于基准测试的大数据表。
【解决方案2】:

使用complete.cases函数怎么样?

DT[complete.cases(DT),]

它将删除列值为 NA 的行

> DT[complete.cases(DT),]
    Series Id Value1 Value2
 1:      b  4      4      1
 2:      b  5      5      2
 3:      b  6      6      3
 4:      c  7      7      4
 5:      c  8      8      5
 6:      c  9      9      6
 7:      f  4      4      1
 8:      f  5      5      2
 9:      f  6      6      3
10:      g  7      7      4
11:      g  8      8      5
12:      g  9      9      6
13:      j  4      4      1
14:      j  5      5      2
15:      j  6      6      3
16:      k  7      7      4
17:      k  8      8      5
18:      k  9      9      6

【讨论】:

  • 不错的功能,知道有用,但我想要一个“notempty.cases”功能 - 只删除一列完全为空的那些案例,并保留其他 NA。
  • 好的,那么您应该更改数据集示例,因为所有具有 NA 值的变量,对于相同字母的 3 行(在 Value1 和 value2 中)都有 NA 值
猜你喜欢
  • 1970-01-01
  • 2015-05-06
  • 1970-01-01
  • 2012-05-21
  • 1970-01-01
  • 2013-09-28
  • 1970-01-01
  • 1970-01-01
  • 2022-09-22
相关资源
最近更新 更多