【问题标题】:Efficietly repeat data.table in a list, sequentially replacing columns with the same names from another data.table in a loop高效地在列表中重复 data.table,在循环中按顺序替换另一个 data.table 中的同名列
【发布时间】:2019-08-28 03:48:54
【问题描述】:

我有两个data.tables:

x <- data.table(a = c(1, 2, 3, 4, 1), b = c(2, 3, 4, 1, 2), c = c(3, 4, 1, 2, 3))
y <- data.table(a = c(1, 0, 0, 0, 1), b = c(0, 1, 0, 0, 0), c = c(0, 0, 0, 0, 1))

我想要实现的是创建一个y 列表,其列数的长度是每个下一列都替换为x 中同一列的值。所需的结果应如下所示:

[[1]]
   a b c
1: 1 0 0
2: 2 1 0
3: 3 0 0
4: 4 0 0
5: 1 0 1

[[2]]
   a b c
1: 1 2 0
2: 0 3 0
3: 0 4 0
4: 0 1 0
5: 1 2 1

[[3]]
   a b c
1: 1 0 3
2: 0 1 4
3: 0 0 1
4: 0 0 2
5: 1 0 3

我尝试了什么:

z <- lapply(names(x), function(i) {
  x[ , i, with = FALSE]
})

w <- rep(list(y), ncol(y))

myfun <- function(obj1, obj2) {
  cbind(obj1, obj2)
}

u <- Map(myfun, obj1 = z, obj2 = w)

u <- lapply(u, function(i) {
  setcolorder(i[ , unique(names(i)), with = FALSE], names(x))
})

它给了我想要的结果,但是非常笨拙并且需要太多的步骤,因此,较大的data.tables 可能效率低下。我想以data.table 的方式拥有更多。我尝试了一些我认为可行的方法:

lapply(names(x), function(i) {
  y[ , (i) := x[ , i, with = FALSE]]
})

但是,它返回第一个列表组件为空并将x 的所有值复制到下一个列表组件中。

有人可以帮忙吗?

【问题讨论】:

    标签: r loops replace data.table updates


    【解决方案1】:

    在这里,我们可能需要一个'y'的copy,同时创建list'w'而不是

    w <- rep(list(y), ncol(y))
    

    rep 的以下表达式很诱人。但是,w 元素存在问题,因为它们指向内存中的相同位置

    w <- rep(list(copy(x)), ncol(y))
    

    引用赋值 (:=) 会更改每个循环中的列值,因为它们引用内存中的同一个对象。在第一种情况下,在赋值之后,它也会改变 'y' 以及 'w' list 元素。第二种情况,它只能改变'w'而留下'y',因为我们copyied。要了解该行为,请在 for 循环中执行 set 赋值

    for(j in seq_along(x)) {print(w[[j]][[j]])
            set(w[[j]], i = NULL, j =j, x[[j]])
            print("----")
            print(w[[j]])
       } 
    

    为了避免这种情况,请使用replicate

    w <- replicate(ncol(y), copy(y), simplify = FALSE)
    

    然后执行for 循环(在重新创建对象后,因为值已从上一次运行中替换)

    for(j in seq_along(x)) {print(w[[j]][[j]])
            set(w[[j]], i = NULL, j =j, x[[j]])
            print("----")
            print(w[[j]])
       } 
    

    或基于Map 的分配

    Map(function(u, v) u[, (v) := x[[v]]][],  w, names(x))
    #[[1]]
    #   a b c
    #1: 1 0 0
    #2: 2 1 0
    #3: 3 0 0
    #4: 4 0 0
    #5: 1 0 1
    
    #[[2]]
    #   a b c
    #1: 1 2 0
    #2: 0 3 0
    #3: 0 4 0
    #4: 0 1 0
    #5: 1 2 1
    
    #[[3]]
    #   a b c
    #1: 1 0 3
    #2: 0 1 4
    #3: 0 0 1
    #4: 0 0 2
    #5: 1 0 3
    

    如果我们在创建 'w' 时没有 copyied 'y' 对象,则可以使用来自 base R 的简单 Map 来完成,而不是通过引用进行赋值

    Map(function(u, v) {u[[v]] <- x[[v]]
                        u}, w, names(x))
    

    【讨论】:

    • 像往常一样,快速响应并提供详尽的解释。非常感谢!
    猜你喜欢
    • 2023-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-31
    • 1970-01-01
    相关资源
    最近更新 更多