na.trim 在具有 data.table 的特定列上

na.trim on specific column with data.table

我正在尝试在 data.table 对象的单个列上使用包 zoo 中的 na.trim。这是我的数据:

DT <- data.table(id=c(rep("a",3),rep("b",3)),
                 col1=c(NA,1,2,NA,3,NA),col2=c(NA,NA,5,NA,NA,NA))
   id col1 col2
1:  a   NA   NA
2:  a    1   NA
3:  a    2    5
4:  b   NA   NA
5:  b    3   NA
6:  b   NA   NA

我想删除具有 leading NA 的行,使用 na.trim 并按 id 分组。这是我期待的结果:

   id col1 col2
1:  a    1   NA
2:  a    2    5
3:  b    3   NA
4:  b   NA   NA

这是我到目前为止所尝试过的方法。这会删除前导 NA 但会删除 col2:

DT[,na.trim(col1),by=id]
   id V1
1:  a  1
2:  a  2
3:  b  3

这也不起作用:

DT[,.SD[na.trim(col1)],by=id]
   id col1 col2
1:  a   NA   NA
2:  a    1   NA
3:  b   NA   NA

不使用 zoo-package 的可能解决方案:

DT[DT[, .I[!!cumsum(!is.na(col1))], by = id]$V1]

你得到:

   id col1 col2
1:  a    1   NA
2:  a    2    5
3:  b    3   NA
4:  b   NA   NA

这是做什么的:

  • 使用 DT[, .I[!!cumsum(!is.na(col1))], id]$V1 您可以创建一个行号向量来保留。通过使用 !!cumsum(!is.na(col1)),您可以确保仅省略 col1 的前导缺失值。
  • 接下来使用该向量对 data.table.
  • 进行子集化
  • !!cumsum(!is.na(col1))cumsum(!is.na(col1))!=0 的作用相同。使用 !! 将所有大于零的数字转换为 TRUE 并将所有零转换为 FALSE.
  • .I 不一定需要,您还可以使用:DT[DT[, !!cumsum(!is.na(col1)), by = id]$V1] 将 data.table 与逻辑向量进行子集化。

@lmo 来自评论的 cummax 的两个备选方案:

# alternative 1:
DT[DT[, !!(cummax(!is.na(col1))), by = id]$V1]

# alternative 2:
DT[as.logical(DT[, cummax(!is.na(col1)), by = id]$V1)]

@jogo 的另一种选择:

DT[, .SD[!!cumsum(!is.na(col1))], by = id]

@Frank 的另一种选择:

DT[, .SD[ rleid(col1) > 1L | !is.na(col1) ], by = id]

na.trim 可以像这样与 data.table 一起使用。有关其参数的更多信息,请参阅 ?na.trim

DT[, na.trim(.SD, sides = "left", is.na = "all"), by = id]

给予:

   id col1 col2
1:  a    1   NA
2:  a    2    5
3:  b    3   NA
4:  b   NA   NA

已添加:

在评论发帖者中阐明,na.trim 仅应对第 1 列 NA 进行操作。在那种情况下,附加一列行号,.I,并在使用这些行号涉及 na.trim 子集之后。

DT[DT[, na.trim(data.table(col1, .I), "left"), by = id]$.I, ]