我有这个虚拟数据集:
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"
我想念什么?
编辑:我在这个使用type.convert()
的问题中尝试了@frank答案。 (感谢坦率;尽管有用的功能,它也不知道。)在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)的最新版本中使用。因此,如果遇到此问题,则比type.convert()
答案 0 :(得分:5)
我愿意...
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。)
所以我想彻底测试一下。当您用“ 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.
答案 1 :(得分:1)
我真的很喜欢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的示例仅评估例如字符类的列。
答案 2 :(得分:0)
这是另外两种方法:
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>