在R的data.table中,用快速方法将所有空白值替换为NA的方法是什么?

7

我有一个非常大的 data.table 对象(1M 行,220 列),我希望将所有空白('')替换为 NA。我在这个 帖子中找到了解决方案,但对于我的数据表来说速度极慢(已经超过 15 分钟)。 其他帖子中的示例:

 data = data.frame(cats=rep(c('', ' ', 'meow'),1e6),
                   dogs=rep(c("woof", " ", NA),1e6))
 system.time(x<-apply(data, 2, function(x) gsub("^$|^ $", NA, x)))

你是否有更快的方法使用data.table来实现这个需求?

实际上,提供的数据看起来并不像原始数据,这只是一个示例。下面是我真实数据的子集,会出现CharToDate(x)错误:

DT <- data.table(ID=c(10),DEFAULT_DATE=as.Date("2012-07-31"),value='')
system.time(DT[DT=='']<-NA)

1
我认为您在填充rep(dogs=c("woof...中的数据时出现了错误。 - jangorecki
4个回答

17

以下是可能的通用data.table方法。我还将使用您的正则表达式,该正则表达式处理了几种类型的空白(我没有看到其他答案这样做)。您可能不应该在所有列上运行此操作,而只应该在factorcharacter列上运行,因为其他类别不接受空白值。

对于factor

indx <- which(sapply(data, is.factor))
for (j in indx) set(data, i = grep("^$|^ $", data[[j]]), j = j, value = NA_integer_) 

对于字符

indx2 <- which(sapply(data, is.character)) 
for (j in indx2) set(data, i = grep("^$|^ $", data[[j]]), j = j, value = NA_character_)

2
非常感谢(再次感谢)@David。在4.79秒内工作! - Tim_Utrecht
现在我得到的NA值是<NA>,而is.na()函数无法识别它们。如果我将其更改为system.time(for(j in indx) set(data, i = grep("^$|^ $", data[[j]]), j = j, value = NA)),它会失败,可能也是你遇到过的问题?有没有一种方法可以将值设置为“标准”的NA? - Tim_Utrecht
难道不奇怪吗?在 is.na(NA_character_) 中,NA_character 被识别了,但是如果我在 data.table 中使用这个函数,将空格替换为 NA_character_,就不能识别了:data[is.na(DEFAULT_DATE)]->dataNA。或者我漏掉了什么?PS. 请参见问题中的编辑以获取新数据。 - Tim_Utrecht
1
好的,请尝试这个 indx <- which(sapply(data, is.factor)); system.time(for (j in indx) set(data, i = grep("^$|^ $", data[[j]]), j = j, value = NA_integer_)); indx2 <- which(sapply(data, is.character)); system.time(for (j in indx2) set(data, i = grep("^$|^ $", data[[j]]), j = j, value = NA_character_)) - David Arenburg
@DavidArenburg 我不知道为什么,但我正在使用 microbenchmark 包测试 data[data=='']<-NAfor (j in indx2) set(data, i = grep("^$|^ $", data[[j]]), j = j, value = NA_character_),结果告诉我第一种选项更快。 - Oriol Prat
@OriolPrat 你在拿苹果和橙子比较。运行正则表达式与进行精确匹配与data.table无关。这个答案的重点是展示如何使用正确的data.table语法来使用OP的正则表达式。在这种情况下,可能根本不需要正则表达式。虽然 data[data=='']<-NA 不会替换 " " 值。 - David Arenburg

8

使用这种方法:

system.time(data[data==''|data==' ']<-NA)
  user  system elapsed 
  1.47    0.19    1.66 

system.time(y<-apply(data, 2, function(x) gsub("^$|^ $", NA, x)))
  user  system elapsed 
  3.41    0.20    3.64

谢谢,我遇到了 Error in charToDate(x) : character string is not in a standard unambiguous format 的错误。我会尝试解决它,如果达到预期效果我会回来的! - Tim_Utrecht
你不能只使用 '' 来解决这个问题,因为数据中有不同类型的空白。 - David Arenburg
你使用的是哪些数据?我猜想不是你示例中的那组数据吧 ;) - Colonel Beauvel
也许楼主想保留 ' '。@Tim,你能提供更多细节吗? - Colonel Beauvel
OP使用正则表达式来删除它们 gsub("^$|^ $", NA, x)(这几乎是不言自明的) - David Arenburg

3
假设您在填充数据时出现错误,下面是使用您在标签中使用的data.table的解决方法。
library(data.table)
data = data.table(cats=rep(c('', ' ', 'meow'),1000000),dogs=rep(c("woof", " ", NA),1000000))
system.time(data[cats=='', cats := NA][dogs=='', dogs := NA])
#  user  system elapsed 
# 0.056   0.000   0.059 

如果您有很多列,请参考David的评论。

1

尝试了几种不同的方法后,我发现最快捷和最简单的选项是:

data[data==""] <- NA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接