gpt4 book ai didi

使用 `by = .I` 在 data.table 中的行操作

转载 作者:行者123 更新时间:2023-12-03 23:35:13 25 4
gpt4 key购买 nike

这是关于 row operations in data.table 的一个很好的 SO 解释

我想到的一种替代方法是使用独特的 id对于每一行,然后使用 by 应用一个函数争论。像这样:

library(data.table)

dt <- data.table(V0 =LETTERS[c(1,1,2,2,3)],
V1=1:5,
V2=3:7,
V3=5:1)

# create a column with row positions
dt[, rowpos := .I]

# calculate standard deviation by row
dt[ , sdd := sd(.SD[, -1, with=FALSE]), by = rowpos ]

问题:
  • 是否有充分的理由不使用这种方法?也许其他更有效的选择?
  • 为什么使用 by = .I不一样吗?
    dt[ , sdd := sd(.SD[, -1, with=FALSE]), by = .I ]
  • 最佳答案

    注意:此答案的第 (3) 部分已于 2019 年 4 月更新,这是由于 data.table 随着时间的推移发生了许多更改,从而使原始版本已过时。此外,使用参数 with=从 data.table 的所有实例中删除,因为它已被弃用。
    1) 好吧,一个不使用它的原因,至少对于 rowsums例如性能和创建不必要的列。与下面的选项 f2 相比,它几乎快了 4 倍,并且不需要 rowpos 列(请注意,原始问题使用 rowSums 作为示例函数,这部分答案对此进行了响应。OP 之后编辑了问题以使用不同的功能,对此答案的第 3 部分更相关`):

    dt <- data.table(V0 =LETTERS[c(1,1,2,2,3)], V1=1:5, V2=3:7, V3=5:1)
    f1 <- function(dt){
    dt[, rowpos := .I]
    dt[ , sdd := rowSums(.SD[, 2:4]), by = rowpos ] }
    f2 <- function(dt) dt[, sdd := rowSums(.SD), .SDcols= 2:4]

    library(microbenchmark)
    microbenchmark(f1(dt),f2(dt))
    # Unit: milliseconds
    # expr min lq mean median uq max neval cld
    # f1(dt) 3.669049 3.732434 4.013946 3.793352 3.972714 5.834608 100 b
    # f2(dt) 1.052702 1.085857 1.154132 1.105301 1.138658 2.825464 100 a
    2) 关于你的第二个问题,虽然 dt[, sdd := sum(.SD[, 2:4]), by = .I]不起作用, dt[, sdd := sum(.SD[, 2:4]), by = 1:NROW(dt)]完美地工作。鉴于根据 ?data.table “.I 是一个等于 seq_len(nrow(x)) 的整数向量”,人们可能认为它们是等价的。然而,不同之处在于 .I用于 j ,不在 by .注意 .I 的值在 data.table 中内部计算,因此不能预先作为参数值传入,如 by=.I .
    还可以预期 by = .I应该只是抛出一个错误。但这不会发生,因为加载了 data.table包创建一个对象 .I在可从全局环境访问的 data.table 命名空间中,其值为 NULL .您可以通过键入 .I 来测试这一点。在命令提示符下。 (注意,同样适用于 .SD.EACHI.N.GRP.BY )
    .I
    # Error: object '.I' not found
    library(data.table)
    .I
    # NULL
    data.table::.I
    # NULL
    这样做的结果是 by = .I 的行为相当于 by = NULL .
    3) 尽管我们已经在第 1 部分中看到了 rowSums 的情况。 ,它已经有效地按行循环,还有比创建 rowpos 列更快的方法。但是当我们没有快速的按行函数时循环怎么办?
    对标 by = rowposby = 1:NROW(dt)版本针对 for循环 set()在这里提供信息。我们发现循环遍历 setfor循环比使用 data.table 的 by 的任何一种方法都慢循环的论据。然而, by 之间的时间差异可以忽略不计。创建一个附加列和使用 seq_len(NROW(dt)) 的循环.没有任何性能差异,似乎 f.nrow可能更可取,但只是基于更简洁而不是创建不必要的列
    dt <- data.table(V0 = rep(LETTERS[c(1,1,2,2,3)], 1e3), V1=1:5, V2=3:7, V3=5:1)

    f.rowpos <- function() {
    dt[, rowpos := .I]
    dt[, sdd := sum(.SD[, 2:4]), by = rowpos ]
    }

    f.nrow <- function() {
    dt[, sdd := sum(.SD[, 2:4]), by = seq_len(NROW(dt)) ]
    }

    f.forset<- function() {
    for (i in seq_len(NROW(dt))) set(dt, i, 'sdd', sum(dt[i, 2:4]))
    }

    microbenchmark(f.rowpos(),f.nrow(), f.forset(), times = 5)
    # Unit: milliseconds
    # expr min lq mean median uq max neval
    # f.rowpos() 559.1115 575.3162 580.2853 578.6865 588.5532 599.7591 5
    # f.nrow() 558.4327 582.4434 584.6893 587.1732 588.6689 606.7282 5
    # f.forset() 1172.6560 1178.8399 1298.4842 1255.4375 1292.7393 1592.7486 5
    所以,总而言之 ,即使在没有优化函数的情况下,例如 rowSums已经按行操作,有使用 rowpos 列的替代方法,虽然速度不快,但不需要创建冗余列。

    关于使用 `by = .I` 在 data.table 中的行操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37667335/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com