数据帧列表的功能,也返回R中的数据帧

时间:2014-03-30 01:09:09

标签: r list aggregate apply

我有以下表单的数据框 列表

str(mylist)
List of 2
 $ df1:'data.frame':    50 obs. of  4 variables:
  ..$ var1: num [1:50] 0.114 0.622 0.609 0.623 0.861 ...
  ..$ var2: num [1:50] -1.221 1.819 0.195 1.232 0.786 ...
  ..$ var3: num [1:50] -0.14 -1.003 -0.352 0.647 0.424 ...
  ..$ Y   : num [1:50] -1.24 1.38 0.3 2.44 2.09 ...
 $ df2:'data.frame':    50 obs. of  4 variables:
  ..$ var1: num [1:50] 0.114 0.622 0.609 0.623 0.861 ...
  ..$ var2: num [1:50] -1.221 1.819 0.195 1.232 0.786 ...
  ..$ var3: num [1:50] -0.14 -1.003 -0.352 0.647 0.424 ...
  ..$ Y   : num [1:50] -1.24 1.38 0.3 2.44 2.09 ...
 - attr(*, "class")= chr [1:2] "mi" "list"

我试图返回列表中对应于正确变量的数据框的方式,也作为数据框,看起来像:

> str(dfnew)
'data.frame':   50 obs. of  4 variables:
 $ var1: num  0.114 0.622 0.609 0.623 0.861 ...
 $ var2: num  -1.221 1.819 0.195 1.232 0.786 ...
 $ var3: num  -0.14 -1.003 -0.352 0.647 0.424 ...
 $ Y   : num  -1.24 1.38 0.3 2.44 2.09 ...

所以,有些事情......

dfnew[1,1] <- mean(mylist[[1]]$var1[1], mylist[[2]]$var1[1], na.rm=T)
dfnew[2,1] <- mean(mylist[[1]]$var1[2], mylist[[2]]$var1[2], na.rm=T)
...
dfnew[50,1] <- mean(mylist[[1]]$var1[50], mylist[[2]]$var1[50], na.rm=T)
...
dfnew[1,2] <- mean(mylist[[1]]$var2[1], mylist[[2]]$var2[1], na.rm=T)
...
dfnew[50,4] <- mean(mylist[[1]]$var4[50], mylist[[2]]$var4[50], na.rm=T)

我可以看到如何用for循环来做这件事......

...或者通过创建每个变量的数据框,

var1df <- cbind(df1$var1, df2$var1)
var2df <- cbind(df1$var2, df2$var2) # and if there are up to var1000?...
...
dfnew$var1 <- rowMeans(var1df)
dfnew$var2 <- rowMeans(var2df)
...

但这比我更喜欢复制并且看起来不像惯用的R;所以我试图用其中一个应用函数来做。

由于这是一个列表,lapply似乎是正确的,除了它似乎跨越了错误的边界 - 也就是说,它在列表中意味着,而不是列表中的平均值。 / p>

> lapply(mylist, FUN=mean)
$df1
[1] NA

$df2
[1] NA

Warning messages:
1: In mean.default(X[[1L]], ...) :
  argument is not numeric or logical: returning NA
2: In mean.default(X[[2L]], ...) :
  argument is not numeric or logical: returning NA

对于另一个边距,交叉列表而不是列表中没有设置lapply。

定期应用,这让我设置一个边距,这是一个列表,而不是矩阵或数据框。

> apply(mylist, MARGIN = 2, FUN=mean)
Error in apply(mylist, MARGIN = 2, FUN = mean) : 
  dim(X) must have a positive length

(我的实际列表有超过2个数据帧,所以很多更简单的loopy或merge-y解决方案很快就会变得多毛 - 或者至少我对循环太笨拙了over getattribute东西知道如何干净地完成N的长度。)

我是否会在一个解决这个问题的rapply,tapply,eapply,* apply函数中缺少某些东西,或者一般来说我是愚蠢的东西?

更新

感谢大家提供的有用答案。当我测试Amelia库进行多次插补时,我遇到了这个问题,并且想要了解模拟时刻的长期传播方式。 (它们返回的对象形状如下,并且具有与原始数据框相对应的上述属性,并且没有丢失的数据。)

Here's a gist我整理了它。

我喜欢user20650的答案不需要额外的复制(gist中的imputer2),所以当我开始扩展到1000的列表时,它变得比需要合并新数据帧的速度快得多。

什么是古怪的,我还没有完全解决的是,我运行的imputer1与imputer2产生的值看起来相同,但是a == b是假的。我假设一个四舍五入的问题。

我还在寻找一种方法在这个结构上应用像mean或sd这样的通用函数(没有复制),而不是逐项计算它们,但无论如何我的问题已经解决了,我会把它留给另一个问题。

6 个答案:

答案 0 :(得分:2)

# data
l <- list(df1 = mtcars[1:5,1:5] , df2 = mtcars[1:5,1:5], df3 = mtcars[1:5,1:5])

# note you can just add dataframes eg
o1 <- (l[[1]] + l[[2]] + l[[3]])/3

# So if you have many df in list - to get the average by summing and dividing by list length
f <- function(x) Reduce("+", x)
o2 <- f(l)/length(l)

all.equal(o1,o2)

答案 1 :(得分:2)

另一个选项,它将列表l转换为数组a(使用建议here的方法)并在前两个维度上应用mean。这假设l中的所有数据帧都具有一致的结构。在这里,我再次使用@ user20650的示例列表。

l <- list(df1=mtcars[1:5, 1:5], df2=mtcars[1:5, 1:5], df3=mtcars[1:5, 1:5])
a <- array(unlist(l), dim=c(nrow(l[[1]]), ncol(l[[1]]), length(l)), 
           dimnames=c(dimnames(l[[1]]), list(names(l))))
apply(a, 1:2, mean)

                   mpg cyl disp  hp drat
Mazda RX4         21.0   6  160 110 3.90
Mazda RX4 Wag     21.0   6  160 110 3.90
Datsun 710        22.8   4  108  93 3.85
Hornet 4 Drive    21.4   6  258 110 3.08
Hornet Sportabout 18.7   8  360 175 3.15

答案 2 :(得分:1)

尝试合并,然后计算您的方法:

df <- Reduce(rbind, lapply(mylist, function(df) {
  df$id <- seq_len(nrow(df))
  df
}))
df <- aggregate(. ~ id, df, mean)[, -1]

实施例

mylist <- lapply(seq_len(3), function(x) iris[, 1:4] + runif(1, 0, 1))
sapply(seq_len(3), function(i) mylist[[i]][1,1])
# [1] 5.368424 6.097071 5.681132
# Apply above code
head(df)
#   Sepal.Length Sepal.Width Petal.Length Petal.Width
# 1     5.715542    4.115542     2.015542   0.8155424
# 2     5.515542    3.615542     2.015542   0.8155424
# 3     5.315542    3.815542     1.915542   0.8155424
# 4     5.215542    3.715542     2.115542   0.8155424
# 5     5.615542    4.215542     2.015542   0.8155424
# 6     6.015542    4.515542     2.315542   1.0155424

请注意mean(c(5.368424, 6.097071, 5.681132)) = 5.715542)

答案 3 :(得分:1)

以下是mapply的选项:

as.data.frame(mapply(function(a, b) (a + b) / 2, df.lst[[1]], df.lst[[2]]))

这适用于任意数量的列。 mapply将成对地循环每个数据框中的每一列。

以下是我们使用的数据:

df.lst <- replicate(2, data.frame(var1=runif(10), var2=sample(1:10)), simplify=F)

答案 4 :(得分:1)

(我认为)如果每个数据框中的某些变量不同或者它们的顺序不同,那么之前的答案将会失败(当然是我之前的答案)。下面是一个相当可怕的功能,但似乎有效。

l <- list(df1 = mtcars[1:5,1:5] , df2 = mtcars[1:5,1:5], df3 = mtcars[1:5,1:5])

# Allow for different variables
l2 <- list(df1 = mtcars[1:5,1:5] , df2 = mtcars[1:5,2:6], df3 = mtcars[1:5,4:7])

new.f <- function(lst) {
                l <- lst
                un.nm <- unique(unlist(lapply(l , names)))
                o <- lapply(un.nm , function(x) {
                         lapply(l , function(z) {
                               if(x %in% names(z)) z[x] else NA
                          })  
                       })
                # combine for each variable
                l <- lapply(o , function(x) do.call(cbind, x))
                mn <- lapply(l , rowMeans , na.rm=TRUE)
        names(mn) <- lapply(l ,function(i) unique(names(i)[names(i) %in% un.nm]))
               data.frame(do.call(cbind , mn))
          }


all.equal(f(l)/length(l) , new.f(l))

f(l2) # fails
# Error in Ops.data.frame(init, x[[i]]) : 
  #+ only defined for equally-sized data frames

new.f(l2)

修改

此示例Join matrices by both colnames and rownames in R 提供了一种更简洁的方法,如果每个列表元素中有不同的列。

l <- lapply(l2 , function(i) as.data.frame(as.table(as.matrix(i))))
tmp <- do.call(rbind , l)
tmp <- aggregate(Freq ~ Var1 + Var2, tmp, mean)
xtabs(Freq ~ Var1 + Var2, tmp)

答案 5 :(得分:0)

使用@ user20650&#39>测试。两个相等数字的平均值应该是相同的数字。

 as.data.frame( setNames(
         lapply( names(mylist[[1]]), function (nm){
              rowMeans( cbind(mylist[[1]][[nm]], mylist[[2]][[nm]] ) ) }),
         names(mylist[[1]]
        ) ) )
#--------------
   mpg cyl disp  hp drat
1 21.0   6  160 110 3.90
2 21.0   6  160 110 3.90
3 22.8   4  108  93 3.85
4 21.4   6  258 110 3.08
5 18.7   8  360 175 3.15

您从内到外读取R代码:对于每个列名,我们使用数字索引来获取数据帧和字符索引以获取列,然后这些列被绑定&#39;一起传递给rowMeans。然后,此rowMean - ed值列表将使用setNames命名,最后转换为数据帧。

请注意,这不会使列表中的所有数据帧都超过两个......只考虑前两个。

> str(mylist)
List of 3
 $ df1:'data.frame':    5 obs. of  5 variables:
  ..$ mpg : num [1:5] 21 21 22.8 21.4 18.7
  ..$ cyl : num [1:5] 6 6 4 6 8
  ..$ disp: num [1:5] 160 160 108 258 360
  ..$ hp  : num [1:5] 110 110 93 110 175
  ..$ drat: num [1:5] 3.9 3.9 3.85 3.08 3.15
 $ df2:'data.frame':    5 obs. of  5 variables:
  ..$ mpg : num [1:5] 21 21 22.8 21.4 18.7
  ..$ cyl : num [1:5] 6 6 4 6 8
  ..$ disp: num [1:5] 160 160 108 258 360
  ..$ hp  : num [1:5] 110 110 93 110 175
  ..$ drat: num [1:5] 3.9 3.9 3.85 3.08 3.15
 $ df3:'data.frame':    5 obs. of  5 variables:
  ..$ mpg : num [1:5] 21 21 22.8 21.4 18.7
  ..$ cyl : num [1:5] 6 6 4 6 8
  ..$ disp: num [1:5] 160 160 108 258 360
  ..$ hp  : num [1:5] 110 110 93 110 175
  ..$ drat: num [1:5] 3.9 3.9 3.85 3.08 3.15