【问题标题】:How to properly use ifelse() inside j of data.table?如何在data.table的j中正确使用ifelse()?
【发布时间】:2018-08-01 03:34:03
【问题描述】:

我的目标是做到以下几点:

我有一个超过 100 万行和 4 列的 data.table。我想添加带有“1”或“0”的第五列,具体取决于以下条件:如果第 3 列为零,后跟第 3 列的下一行中的任何非零值(如滑动长度为 2) 的窗口,则应将“1”添加到第 5 列,否则应添加“0”。此二进制在第 5 列中的行位置应与非零值相同。此外,我想根据一个键(即列的子集)来执行此操作,如下面的代码所示。

我无法在 data.table 中实现这一点(我刚刚开始使用它)。我编写了以下代码,它可以满足我的要求,但是速度非常慢(> 5 s /迭代):

# all_movement_fit_tidy is a data.table with dim 1.2 mio x 4
# set key "fly" in all_movement_fit_tidy
setkey(all_movement_fit_tidy, fly)
genotypes <- unique(all_movement_fit_tidy$fly)
DT_list <- list()
i <- 1
for(genotype in genotypes){

# Get subset of data.table by genotype
genotype_movement <- all_movement_fit_tidy[genotype]

# Calculate initiation list - figure out how to do this in data.table
initiation <- list()
for(j in 1:(nrow(genotype_movement) - 1)){

  initiation[j] <- ifelse(genotype_movement[j, "mm"] == 0 & 
  genotype_movement[j + 1, "mm"] != 0, 1, 0)
}

# Add a 0 to the end of the list to equal number of rows,
# then bind it to genotype_movement
initiation[length(initiation) + 1] <- 0
genotype_movement <- cbind(genotype_movement, as.numeric(initiation))
colnames(genotype_movement)[5] <- "initiation"

# Save this data table in a list of data.tables (DT_list)
DT_list[[i]] <- genotype_movement

i <- i + 1
}

之后,我会将携带所有data.tables的DT_list的所有条目绑定到一个data.table中。这段代码这么慢的原因是以下部分:

initiation <- list()
for(j in 1:(nrow(genotype_movement) - 1)){

 initiation[j] <- ifelse(genotype_movement[j, "mm"] == 0 & 
 genotype_movement[j + 1, "mm"] != 0, 1, 0)
}

在这里,我循环遍历 data.table 子集的每一行,并将 ifelse() 函数的结果分配给一个列表。如何在 data.table 的 j 参数中执行此操作?我尝试过类似的方法:

genotype_movement[, initiation := function(x) for(i in 
1:nrow(genotype_movement) ifelse(.SD[i, "mm"] == 0 & .SD[i + 1, "mm" != 
0, 1, 0)]

但这不起作用,因为 ifelse() 函数返回无法分配给初始列的单个值。

【问题讨论】:

  • DT[, col5:= shift(col3) ==0 &amp; col3 != 0] ?
  • 我不知道 shift,这很棒,谢谢,它有效。我为实现这一点而编写的代码显然很荒谬。
  • 仅供参考,可能还有其他方法可以解决此问题,但是由于您没有提供可重现的示例,因此无法进行调查。对于您的下一个问题,请查看stackoverflow.com/a/28481250
  • @Frank 谢谢你,非常有用的评论,我会记住的。

标签: r datatable data.table


【解决方案1】:

你掉进了兔子洞。这是向上的方式:

DT[, col5:= shift(col3, fill = -1) == 0 & col3 != 0]

# or
DT[, col5:= shift(col3, fill = -1) == 0 & col3 != 0, keyby = key(DT)]

【讨论】:

  • 完美,感谢您提供快速准确的解决方案。
  • 以防万一有人因为同样的问题访问这个页面:一旦 Hugh 的解决方案被实现,如果你使用 keyby = key(DT),NA 将在每个满足 col3 的列子集的开头引入!= 0,因为 shift() 不能落后于列的开头。但是,如果 col3 != 0 为 FALSE,则不会引入 NA,而是会引入 FALSE,因为据推测,在这种情况下 shift() 不会执行。只是要注意这种差异。
  • 嘿@pat_krat,您可能需要考虑在我对shift 的编辑中使用fill 参数,以避免每个键的第一个条目中出现任何值`。
猜你喜欢
  • 1970-01-01
  • 2020-04-20
  • 1970-01-01
  • 1970-01-01
  • 2016-05-21
  • 2017-10-01
  • 2017-03-11
  • 2021-12-14
  • 2017-01-02
相关资源
最近更新 更多