【问题标题】:Speed up this loop to create dummy columns with data.table and set in R [duplicate]加快此循环以使用 data.table 创建虚拟列并在 R 中设置 [重复]
【发布时间】:2016-11-26 08:04:06
【问题描述】:

我有一个数据表,我想为每个唯一的日期创建一个新列,然后在日期与列名匹配的每一行中分配一个 1

我已经使用 for 循环完成了这项工作,但我想知道是否有任何方法可以使用 data.table 和 set 对其进行优化?

这是一个例子

dt <- data.table(Week_Day = c("Monday", "Tuesday", "Wednesday",
                          "Thursday", "Friday", "Saturday", "Sunday"))

Day <- unique(dt$Week_Day)
for (i in 1:length(Day)) {
    if (Day[i] != "Sunday") {
        dt[, Day[i] := ifelse(Week_Day == Day[i], 1, 0)]
    }
}

我的表有 298k 行,虽然执行时间不长(如下),但它是长脚本的一部分,而且我有很多低效的循环,所以我试图缩短整体运行时间。

运行时间:

user  system elapsed
0.99    0.06    1.05

提前致谢。

【问题讨论】:

标签: r performance data.table dummy-variable model.matrix


【解决方案1】:

这是一种不同的方法,在我的机器上比问题中的原始方法表现更好

1) 获取除周日以外的独特日子

Day <- setdiff(dt$Week_Day, "Sunday")

2) 用 0 初始化新列:

dt[, (Day) := 0L]

3) 在循环中通过引用更新 1:

for(x in Day) {
  set(dt, i = which(dt[["Week_Day"]] == x), j = x, value = 1L)
}

简单的性能比较:

dt1 <- data.table(Week_Day = sample(c("Monday", "Tuesday", "Wednesday",
                              "Thursday", "Friday", "Saturday", "Sunday"), 3e5, TRUE))

dt2 <- copy(dt1)


system.time({
  Day <- setdiff(unique(dt$Week_Day), "Sunday")
  dt1[, (Day) := 0L]
  for(x in Day) {
    set(dt1, i = which(dt1[["Week_Day"]] == x), j = x, value = 1L)
  }
})
#       User      System verstrichen 
#      0.029       0.003       0.032 

system.time({
  Day <- unique(dt$Week_Day)
  for (i in 1:length(Day)) {
    if (Day[i] != "Sunday") {
      dt2[, Day[i] := ifelse(Week_Day == Day[i], 1L, 0L)]
    }
  }
})

#       User      System verstrichen 
#      0.138       0.070       0.210 


all.equal(dt1, dt2)
#[1] TRUE

【讨论】:

  • 太棒了!在我的 300k 行数据中,执行时间是:user system elapsed0.02 0.00 0.01 这导致我发布另一个关于嵌套循环花费“太”长时间的问题。
  • Week_Day 上使用索引可能会加快速度,因为我们似乎多次对其进行了子集化。
  • @docendo 我也使用了您的解决方案来添加季节性变量,但是在错误地添加新变量时,我省略了“Day”周围的括号dt1[, (Day) := 0L]这样做意味着“Day”变量仍然存在并且我有 NA,我本来希望是零。你知道加括号有什么作用吗?只是为了让我能准确地理解正在发生的事情。谢谢
  • @MidnightDataGeek 通过添加括号,计算里面的表达式。否则,该列仅称为“日”。您可以查看 github 上 data.table 的小插图以获取更多信息
【解决方案2】:

这是一种加快速度的尝试:

Day <- unique(dt$Week_Day)
setkey(dt, Week_Day)

# create columns of 0s
dt[, (Day) := 0L]

for (i in seq_along(head(Day, -1))) {
     dt[Day[i], Day[i] := 1L]
}

这实现了两个data.table 加速,包括在第二个链中的二分搜索和通过引用替换消除ifelse

【讨论】:

  • 谢谢,@arun。我不知道有可能以这种方式用:=“矢量化”变量的创建。真的很酷的技术。
  • 当然,RHS 只是先循环到 LHS 的长度,然后再循环到行数..(为方便起见)。
  • @Arun 谢谢!这在我的机器上也非常快。 user system elapsed 0.03 0.00 0.03 我现在知道我的脚本一定效率很低,因为我有很多嵌套循环。我将在某个时候发布另一个问题。感谢您的帮助:)
猜你喜欢
  • 2013-09-23
  • 1970-01-01
  • 1970-01-01
  • 2015-08-20
  • 2020-08-19
  • 2015-10-22
  • 1970-01-01
  • 2018-03-31
  • 2021-04-21
相关资源
最近更新 更多