【问题标题】:Replacing "NA" (NA string) with NA inplace data.table用 NA inplace data.table 替换“NA”(NA 字符串)
【发布时间】:2018-08-08 16:36:25
【问题描述】:

我有这个虚拟数据集:

abc <- data.table(a = c("NA", "bc", "x"), b = c(1, 2, 3), c = c("n", "NA", "NA"))

我试图用标准 NA 替换“NA”;使用 data.table 就位。我试过了:

for(i in names(abc)) (abc[which(abc[[i]] == "NA"), i := NA])
for(i in names(abc)) (abc[which(abc[[i]] == "NA"), i := NA_character_])
for(i in names(abc)) (set(abc, which(abc[[i]] == "NA"), i, NA))

但是我仍然得到:

abc$a 
"NA" "bc" "x"

我错过了什么?

编辑:我在这个问题中尝试了@frank 答案,它使用了type.convert()。 (感谢弗兰克;不知道这种晦涩难懂但有用的函数)在type.convert() 的文档中提到:“这主要是 read.table 的辅助函数。”所以我想彻底测试一下。当您有一个用“NA”(NA 字符串)填充的完整列时,此函数会产生较小的副作用。在这种情况下,type.convert() 正在将列转换为逻辑。对于这种情况,abc 将是:

abc <- data.table(a = c("NA", "bc", "x"), b = c(1, 2, 3), c = c("n", "NA", "NA"), d = c("NA", "NA", "NA"))

EDIT2:总结原始问题中的代码:

for(i in names(abc)) (set(abc, which(abc[[i]] == "NA"), i, NA))

工作正常,但仅适用于当前最新版本的 data.table (> 1.11.4)。因此,如果遇到这个问题,那么最好更新 data.table 并使用此代码而不是type.convert()

【问题讨论】:

  • 我们为您提供了不同的做事方式,因为我们中的许多人都避免了循环......但是可以让您的代码工作。为我尝试for(i in names(abc)) (abc[which(abc[[i]] == "NA"), (i) := NA]),看看是否可行。 i := 说“将结果存储在“i”列中。(i) := 说“将“i”的内容评估为列名,然后将结果存储在那里”。不要忘记 RStudio 不会更新数据表的视图当您运行代码时。您必须关闭预览,然后重新打开它才能看到结果。这样做是为了提高速度。
  • 仅供参考,您的 for(i in names(abc)) (set(abc, which(abc[[i]] == "NA"), i, NA)) 在我的计算机上工作...您只需在 RStudio 中刷新视图,因为使用 := 的数据表更新不会自动刷新视图。

标签: r data.table


【解决方案1】:

我愿意……

chcols = names(abc)[sapply(abc, is.character)]
abc[, (chcols) := lapply(.SD, type.convert, as.is=TRUE), .SDcols=chcols]

产生

> str(abc)
Classes ‘data.table’ and 'data.frame':  3 obs. of  3 variables:
 $ a: chr  NA "bc" "x"
 $ b: num  1 2 3
 $ c: chr  "n" NA NA
 - attr(*, ".internal.selfref")=<externalptr> 

您的DT[, i :=] 代码不起作用,因为它创建了一个字面上名为“i”的列;正如@AdamSampson 指出的那样,您的set 代码已经可以工作了。 (注意:OP 从 data.table 1.10.4-3 升级到 1.11.4,之前他们的 comp 就是这种情况。)


所以我想彻底测试一下。当您有一个用“NA”(NA 字符串)填充的完整列时,此函数会产生较小的副作用。在这种情况下,type.convert() 正在将列转换为逻辑。

哦,对了。对于这个问题,您的原始方法更安全:

# op's new example
abc <- data.table(a = c("NA", "bc", "x"), b = c(1, 2, 3), c = c("n", "NA", "NA"), d = c("NA", "NA", "NA"))

# op's original code
for(i in names(abc)) 
  set(abc, which(abc[[i]] == "NA"), i, NA)

旁注:NA 具有逻辑类型;并且通常 data.table 在将不一致类型的值分配给列时会发出警告,但我猜他们在 NA 的异常中写了:

DT = data.table(x = 1:2)
DT[1, x := NA]
# no problem, even though x is int and NA is logi

DT = data.table(x = 1:2)
DT[1, x := TRUE]
# Warning message:
# In `[.data.table`(DT, 1, `:=`(x, TRUE)) :
#   Coerced 'logical' RHS to 'integer' to match the column's type. Either change the target column ['x'] to 'logical' first (by creating a new 'logical' vector length 2 (nrows of entire table) and assign that; i.e. 'replace' column), or coerce RHS to 'integer' (e.g. 1L, NA_[real|integer]_, as.*, etc) to make your intent clear and for speed. Or, set the column type correctly up front when you create the table and stick to it, please.

【讨论】:

  • 请原谅,但 set() 方法在我的带有 data.table 1.10.4.3 的计算机上不起作用。虽然我在设置命令后打印abc$a,但我仍然得到"NA" "bc" "x"
  • @abhiieor 嗯,不知道为什么会这样。 (我在 r 3.3.3 上从 github 运行 data.table 版本 1.11.5)您可以尝试升级到最新的 CRAN 版本 1.11.4,以防它是一个短期错误。我看到它在 RStudio (1.0.44) 和 R 控制台中都有效
  • 确实在 1.11.4 中解决了。应该已经更新了 data.table。
【解决方案2】:

我真的很喜欢 Frank 的回复,但我想补充一下,因为它假定您只对字符向量执行更改。我还将尝试包含一些有关“为什么”有效的信息。

要替换所有 NA,您可以执行以下操作:

chcols = names(abc)
abc[,(chcols) := lapply(.SD, function(x) ifelse(x == "NA",NA,x)),.SDcols = chcols]

让我们分解一下我们在这里所做的事情。

我们正在查看 abc 中的每一行(因为第一个逗号之前没有任何内容)。

下一个逗号之后是列。让我们分解一下。

我们将结果放入 chcols 中列出的所有列中。 (chcols) 告诉 data.table 方法评估保存在 chcols 对象中的名称向量。如果您省略括号并使用chcols,它将尝试将结果存储在名为 chcols 的列中,而不是使用您想要的列名。

.SD 正在返回一个 data.table,其中包含.SDcols 中列出的每一列的结果(在我的情况下,它正在返回所有列......)。但我们想一次评估一列。因此,我们使用lapply 一次将一个函数应用于.SD 中的每一列。

您可以使用任何能够返回正确值的函数。弗兰克使用了type.convert。我正在使用一个匿名函数来评估 ifelse 语句。我使用了ifelse,因为它评估并返回整个向量/列。

您已经知道如何使用:= 替换原地值。

在下一列之后,您要么输入by 信息,要么输入其他选项。我们将以.SDcols 的形式添加其他选项。

我们需要添加一个.SDcols = chcols 来告诉 data.table 哪些列要包含在 .SD 中。我的代码正在评估所有列,所以如果你离开 .SDcols 我的代码仍然可以工作。但不考虑此列是一个坏习惯,因为如果您更改为仅评估某些列,将来可能会浪费时间。 Frank 的示例仅评估了例如字符类的列。

【讨论】:

  • 作为另一个放在那里的函数示例,您也可以使用replace(x, x=="NA", NA);以我的经验, ifelse 使用起来更麻烦。不确定我是否明白想要包含所有列的意思。除了字符列之外,没有“NA”这样的东西,对吧?
  • 甜蜜。我总是忘记更换。每次忘记更换时,我都需要在我的发誓罐旁边放一个“更换”罐。
  • 至于非字符列中的NA,我不确定他的数据。 NA 仅表示“不可用”或缺失。我决定谨慎行事,并假设他的集合中其他类型的数据可能缺少数据。
【解决方案3】:

这里有另外两种方法:

子集

library(data.table)
abcd <- data.table(a = c("NA", "bc", "x"), b = c(1, 2, 3),
                   c = c("n", "NA", "NA"), d = c("NA", "NA", "NA"))

for (col in names(abcd)) abcd[get(col) == "NA", (col) := NA]
abcd[]
      a b    c    d
1: <NA> 1    n <NA>
2:   bc 2 <NA> <NA>
3:    x 3 <NA> <NA>

加入时更新

这里data.table对变量类型比较严格。

abcd <- data.table(a = c("NA", "bc", "x"), b = c(1, 2, 3),
                   c = c("n", "NA", "NA"), d = c("NA", "NA", "NA"))

for (col in names(abcd)) 
  if (is.character(abcd[[col]])) 
    abcd[.("NA", NA_character_), on = paste0(col, "==V1"), (col) := V2][]
abcd
      a b    c    d
1: <NA> 1    n <NA>
2:   bc 2 <NA> <NA>
3:    x 3 <NA> <NA>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-16
    • 2014-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-06
    • 1970-01-01
    相关资源
    最近更新 更多