【问题标题】:R: Assigning vectors from a list of vectors as a value of the column in a data frame from a list of data framesR:将向量列表中的向量分配为数据框列表中数据框中列的值
【发布时间】:2015-04-29 13:17:25
【问题描述】:

我有两个长度相等的列表:一个是数据帧列表,另一个是向量列表,使得每个向量的长度与第一个列表的相应数据帧中的行数一致。我想将第二个列表中的向量分配为每个数据帧中第一列的值。用下面的代码可能会更容易解释:

for (i in seq_along(data)){
   data[[c(i, 1)]] = links[[i]]
                         }

,其中data 是数据帧列表,links 是向量列表。虽然这段代码运行良好,而且没有特别需要避免for 循环,但我想知道是否有其他方法可以在没有for 的情况下执行相同的操作?

【问题讨论】:

  • 请包括dput(data)dplut(links) 的输出,或每个对象的最小代表性示例。
  • c(i,1) 是一个向量,但据我所知,[[ 仅适用于标量。
  • @nrussell,谢谢,下次会做。

标签: r list


【解决方案1】:

由于datalinks具有相同的长度,并且您正在一对一替换,Map()和/或mapply()将是一个不错的选择。使用来自其他答案的数据,

data <- list(data.frame(a = 1:3, b = 4:6), data.frame(a = 10:14, b = 15:19))
links <- list(7:9, 20:24)

你可以的

Map("[<-", data, 1, value = links)
# [[1]]
#   a b
# 1 7 4
# 2 8 5
# 3 9 6
#
# [[2]]
#    a  b
# 1 20 15
# 2 21 16
# 3 22 17
# 4 23 18
# 5 24 19

虽然只有R神知道这有多安全。使用匿名函数会更安全。

Map(function(x, y, z) { x[y] <- z; x }, data, 1, links)

【讨论】:

  • 啊,我忘了Map()mapply(),很好的补充@RichardScriven。虽然我想指出Map()mapply() 的包装器,mapply()sapply() 的包装器,而sapply()lapply() 的包装器,所以这简化为相同的代码,尽管肯定比我在回答中给出的直接lapply() 呼叫更简洁和优雅。
  • 虽然这不是相同的代码。您正在使用覆盖原始数据的&lt;&lt;-,并且没有必要这样做。这也有点危险。加上mapply() 不是sapply() 的包装。它在.Internal(mapply()) 处输入C 代码。在mapply() 中根本没有提到sapply()。但我明白你的意思。
  • 其实我对&lt;&lt;-的使用更符合OP想要做的事情;他问题中的代码也覆盖了原始数据(尽管通过=)。但我只是假设,对于您的解决方案,您可以通过将 Map() 调用的返回值分配给原始变量(即 data &lt;- Map(...))来完全覆盖原始数据,所以我认为这种差异并不显着。
  • 是的,但是如果您将结果称为其他名称,则不会被覆盖,例如data2 &lt;- Map(...)
  • 啊哈,你说得对:“mapply 是 sapply 的多变量 版本”(stat.ethz.ch/R-manual/R-devel/library/base/html/mapply.html)。我认为这意味着它是一个包装器,但事实并非如此。好点子。
【解决方案2】:

由于您的数据已经被分成独立的列表组件,因此如果没有某种循环(隐藏或显式),就无法执行此操作。这是因为不可能以任何一种矢量化或整体的方式对多个独立的列表组件进行操作;列表的本质是一系列(允许的)异构对象,不能作为一个单元访问。

你可以用lapply()中的隐藏循环来替换for循环,但是麻烦的意义不大:

l1 <- list(data.frame(a=1:3,b=4:6), data.frame(a=10:14,b=15:19) );
l2 <- list(7:9, 20:24 );
invisible(lapply(seq_along(l1), function(i) l1[[i]][,1] <<- l2[[i]] ));
l1;
## [[1]]
##   a b
## 1 7 4
## 2 8 5
## 3 9 6
## 
## [[2]]
##    a  b
## 1 20 15
## 2 21 16
## 3 22 17
## 4 23 18
## 5 24 19

或者,您可以暂时或永久地完全重组数据,但这显然超出了您的问题范围。例如,这是一种暂时rbind()/c() 输入允许作为一个单元执行第一列替换的方法,在split()ting 回到原始列表形式之前(还应该注意,我必须无论如何使用sapply() 只是为了获得用于将聚合的data.frame 拆分回单独的data.frames 的长度)(还应该注意,这只有在所有data.frames 具有相同的数量和名称时才有效列):

unname(split(transform(do.call(rbind,l1),a=do.call(c,l2)),rep(seq_along(l2),sapply(l2,length))));
## [[1]]
##   a b
## 1 7 4
## 2 8 5
## 3 9 6
## 
## [[2]]
##    a  b
## 4 20 15
## 5 21 16
## 6 22 17
## 7 23 18
## 8 24 19

如您所见,for 循环显然比这些替代方案更直接、更合理。

【讨论】:

    猜你喜欢
    • 2021-01-18
    • 2021-12-29
    • 2014-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多