当列为因子时,R data.table 将 "NULL" 替换为 `NA`
R data.table replace "NULL" with `NA` when columns are factors
我通过 ODBC 从 SQL 数据库中提取了一些数据,列自动设置为 factor
。它类似于以下内容:
library(RODBC)
library(data.table)
data <- data.table(sqlQuery(channel, query))
我的数据看起来像这样,只是多了很多列:
data <- data.table("C1"=as.factor(c(letters[1:4], "NULL", letters[5])),
"C2"=as.factor(c(rnorm(3), "NULL", rnorm(2))),
"C3"=as.factor(c(letters[1], "NULL", letters[2:4], "NULL")))
> data
C1 C2 C3
1: a -0.190200079604691 a
2: b 0.310548914832963 NULL
3: c 0.0153099116493453 b
4: d NULL c
5: NULL 0.157187027626419 d
6: e 0.118537540781528 NULL
> str(data)
Classes ‘data.table’ and 'data.frame': 6 obs. of 3 variables:
$ C1: Factor w/ 6 levels "a","b","c","d",..: 1 2 3 4 6 5
$ C2: Factor w/ 6 levels "-0.190200079604691",..: 1 5 2 6 4 3
$ C3: Factor w/ 5 levels "a","b","c","d",..: 1 5 2 3 4 5
- attr(*, ".internal.selfref")=<externalptr>
如何将 "NULL" 替换为 NA
?这里我希望 R
将这些 SQL "NULL" 字符串视为缺失值 NA
。我尝试了以下方法,但似乎 NA
会导致问题。
for (col in names(data)) {
set(data, which(data[[col]]=="NULL"), col, NA)
}
> Error in set(data, which(data[[col]] == "NULL"), col, NA) :
Can't assign to column 'C1' (type 'factor') a value of type 'logical' (not character, factor, integer or numeric)
RODBC 解决方案
感谢@user20650 的建议,您可以通过执行 data <- data.table(sqlQuery(channel, query, na.strings=c("NA", "NULL")))
来控制 sqlQuery
中的缺失值。但是,如果您的数据源格式不正确,仍然有可能出现此问题,因此这不是 post.
的通用解决方案。
这是一种方法:
data[,names(data):=lapply(.SD,function(x){
z <- levels(x)
z[z=="NULL"] <- NA
`levels<-`(x,z)
})]
要查看发生了什么,请查看 lapply(data,levels)
,您会发现 "NULL"
已消失。
(谢谢,@akrun:)使用 car
包可以获得更简洁直观的变体:
library(car)
data[,names(data):=lapply(.SD, recode, '"NULL"=NA')]
在data.table
世界中,通常可以通过引用进行修改。在这种情况下,看起来像...
for (j in names(data)) setattr(data[[j]],"levels",{
z <- levels(data[[j]])
z[z=="NULL"] <- NA
z
})
这避免了像 `levels<-`
那样复制整个向量。
这达到了预期的效果,而且更加紧凑:
is.na(data) <- data == "NULL"
注意回复:评论 问:is.na
函数与 is.na<-
函数有很大不同。此处使用的后一个是将 NA 值分配给由赋值运算符的 RHS 上的逻辑表达式定义的项。有 is.na.data.frame
方法但没有 is.na[<-.dataframe
方法。所以不确定这是否是纯粹的引用策略,因为它不是用 [.data.frame
语法实现的。它可能正在使用“is.na<-.default”。
我认为在稍微考虑一下“is.na<-.default”(就是 {x[value] <- NA; x}
)之后,最终会将此调用分派给 [<-.data.table
所以它可能会“通过参考”完成。
我通过 ODBC 从 SQL 数据库中提取了一些数据,列自动设置为 factor
。它类似于以下内容:
library(RODBC)
library(data.table)
data <- data.table(sqlQuery(channel, query))
我的数据看起来像这样,只是多了很多列:
data <- data.table("C1"=as.factor(c(letters[1:4], "NULL", letters[5])),
"C2"=as.factor(c(rnorm(3), "NULL", rnorm(2))),
"C3"=as.factor(c(letters[1], "NULL", letters[2:4], "NULL")))
> data
C1 C2 C3
1: a -0.190200079604691 a
2: b 0.310548914832963 NULL
3: c 0.0153099116493453 b
4: d NULL c
5: NULL 0.157187027626419 d
6: e 0.118537540781528 NULL
> str(data)
Classes ‘data.table’ and 'data.frame': 6 obs. of 3 variables:
$ C1: Factor w/ 6 levels "a","b","c","d",..: 1 2 3 4 6 5
$ C2: Factor w/ 6 levels "-0.190200079604691",..: 1 5 2 6 4 3
$ C3: Factor w/ 5 levels "a","b","c","d",..: 1 5 2 3 4 5
- attr(*, ".internal.selfref")=<externalptr>
如何将 "NULL" 替换为 NA
?这里我希望 R
将这些 SQL "NULL" 字符串视为缺失值 NA
。我尝试了以下方法,但似乎 NA
会导致问题。
for (col in names(data)) {
set(data, which(data[[col]]=="NULL"), col, NA)
}
> Error in set(data, which(data[[col]] == "NULL"), col, NA) :
Can't assign to column 'C1' (type 'factor') a value of type 'logical' (not character, factor, integer or numeric)
RODBC 解决方案
感谢@user20650 的建议,您可以通过执行 data <- data.table(sqlQuery(channel, query, na.strings=c("NA", "NULL")))
来控制 sqlQuery
中的缺失值。但是,如果您的数据源格式不正确,仍然有可能出现此问题,因此这不是 post.
这是一种方法:
data[,names(data):=lapply(.SD,function(x){
z <- levels(x)
z[z=="NULL"] <- NA
`levels<-`(x,z)
})]
要查看发生了什么,请查看 lapply(data,levels)
,您会发现 "NULL"
已消失。
(谢谢,@akrun:)使用 car
包可以获得更简洁直观的变体:
library(car)
data[,names(data):=lapply(.SD, recode, '"NULL"=NA')]
在data.table
世界中,通常可以通过引用进行修改。在这种情况下,看起来像...
for (j in names(data)) setattr(data[[j]],"levels",{
z <- levels(data[[j]])
z[z=="NULL"] <- NA
z
})
这避免了像 `levels<-`
那样复制整个向量。
这达到了预期的效果,而且更加紧凑:
is.na(data) <- data == "NULL"
注意回复:评论 问:is.na
函数与 is.na<-
函数有很大不同。此处使用的后一个是将 NA 值分配给由赋值运算符的 RHS 上的逻辑表达式定义的项。有 is.na.data.frame
方法但没有 is.na[<-.dataframe
方法。所以不确定这是否是纯粹的引用策略,因为它不是用 [.data.frame
语法实现的。它可能正在使用“is.na<-.default”。
我认为在稍微考虑一下“is.na<-.default”(就是 {x[value] <- NA; x}
)之后,最终会将此调用分派给 [<-.data.table
所以它可能会“通过参考”完成。