【问题标题】:Replacing all missing values in R data.table with a value用一个值替换 R data.table 中的所有缺失值
【发布时间】:2013-12-30 09:24:43
【问题描述】:

如果你有一个 R data.table 有缺失值,你如何用值 0 替换所有这些值?例如

aa = data.table(V1=1:10,V2=c(1,2,2,3,3,3,4,4,4,4))
bb = data.table(V1=3:6,X=letters[1:4])
setkey(aa,V1)
setkey(bb,V1)
tt = bb[aa]

    V1  X V2
 1:  1 NA  1
 2:  2 NA  2
 3:  3  a  2
 4:  4  b  3
 5:  5  c  3
 6:  6  d  3
 7:  7 NA  4
 8:  8 NA  4
 9:  9 NA  4
10: 10 NA  4

有什么方法可以在一行中做到这一点?如果它只是一个矩阵,你可以这样做:

tt[is.na(tt)] = 0

【问题讨论】:

  • tt[is.na(tt)] = 0 为我工作。
  • 你说得对,我不知道我在看哪里。随意回答我会接受的。
  • +1 为好问题。但是您选择的答案不是惯用的方式。我建议你重新考虑。
  • 想到我会如何想要这个工作,tt[is.na(tt), .SD := 0] 浮现在脑海
  • @eddi,嗯,这看起来不错,而且实施起来可能并不难......会考虑一下。

标签: r data.table


【解决方案1】:

is.na(作为一个原始类型)的开销相对较少,而且通常非常快。因此,您可以遍历列并使用set 替换NA with0`。

使用<- 分配将导致所有列的副本,这不是使用data.table 的惯用方式。

首先我将说明如何做到这一点,然后展示如何缓慢处理大量数据(由于副本):

一种有效的方法:

for (i in seq_along(tt)) set(tt, i=which(is.na(tt[[i]])), j=i, value=0)

您会在此处收到警告,“0”被强制转换为字符以匹配列的类型。你可以忽略它。

你为什么不在这里使用<-

# by reference - idiomatic way
set.seed(45)
tt <- data.table(matrix(sample(c(NA, rnorm(10)), 1e7*3, TRUE), ncol=3))
tracemem(tt)
# modifies value by reference - no copy
system.time({
for (i in seq_along(tt)) 
    set(tt, i=which(is.na(tt[[i]])), j=i, value=0)
})
#   user  system elapsed 
#  0.284   0.083   0.386 

# by copy - NOT the idiomatic way
set.seed(45)
tt <- data.table(matrix(sample(c(NA, rnorm(10)), 1e7*3, TRUE), ncol=3))
tracemem(tt)
# makes copy
system.time({tt[is.na(tt)] <- 0})
# a bunch of "tracemem" output showing the copies being made
#   user  system elapsed 
#  4.110   0.976   5.187 

【讨论】:

  • 很好的答案。不是严格要求,但是没有 for 循环的任何方法,例如使用 lapply?或者这是否也会复制列?
  • 无论我是否在每次运行之前使用tracemem(tt),我都没有接近您所看到的时间增加,相应的经过时间大约为 0.34 和 0.42。 &lt;- 速度较慢,但​​远不及您的基准测试那么慢。
  • @thelatemail,我又检查了一遍。这是 0.386 对 5.05 秒。
  • 在运行system.time之前是否再次生成了tt?第一个通过引用修改它...
  • 我一直在使用tt2 &lt;- tt &lt;- data.table(... 并在tt 上运行第一个for 代码块,在tt2 上运行第二个&lt;- 代码
【解决方案2】:

这里没有什么异常:

tt[is.na(tt)] = 0

..会起作用的。

这有点令人困惑,但是考虑到:

tt[is.na(tt)]

...当前返回:

[.data.table(tt, is.na(tt)) 中的错误:i 是无效类型 (矩阵)。也许将来一个 2 列矩阵可以返回一个列表 DT 的元素(本着 FAQ 2.14 中的 A[B] 的精神)。请让 datatable-help 知道您是否愿意,或者将您的 cmets 添加到 FR #1611。

【讨论】:

  • 是的,我认为发生的事情是我尝试了它并得到了那个错误并且很困惑,没有想到实际上试图将它直接设置为零。谢谢!
  • 这不是惯用的方式,因为这会复制所有列。
  • 完美。当我看到那个错误时,我停了下来。 Whodathunk 任务在那之后会起作用......
  • 我认为这是因为在尝试进行选择时调用了 data.table 特定代码,但在进行替换操作时使用了一般 data.frame 代码。令人困惑,但这是一个特别边缘的例子。
【解决方案3】:

我会使用data.tablelapply,即:

tt[,lapply(.SD,function(kkk) ifelse(is.na(kkk),-666,kkk)),.SDcols=names(tt)]

屈服于:

V1    X V2
 1:  1 -666  1
 2:  2 -666  2
 3:  3    a  2
 4:  4    b  3
 5:  5    c  3
 6:  6    d  3
 7:  7 -666  4
 8:  8 -666  4
 9:  9 -666  4
10: 10 -666  4

【讨论】:

  • 这很慢,因为ifelse() 会更新所有值。使用Arun's benchmark code,比使用set()的循环慢15倍。
【解决方案4】:

OP发布的具体问题也可以通过

tt[is.na(X), X := 0]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-11-14
    • 1970-01-01
    • 1970-01-01
    • 2021-08-21
    • 1970-01-01
    • 2020-08-10
    • 1970-01-01
    • 2023-01-13
    相关资源
    最近更新 更多