簡體   English   中英

數據幀列表的功能,還返回R中的數據幀

[英]Function of a list of data frames, to return also a data frame in R

我有以下格式的數據幀 列表

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要少; 因此,我嘗試使用apply函數之一來完成此操作。

由於這是一個列表,因此lapply似乎是正確的,只是它似乎跨越了錯誤的邊距-也就是說,這是列表中的意思,而不是列表中的平均值。

> 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解決方案很快就變得毛茸茸-或至少我對getattribute東西的循環太笨拙不知道長度為N的整潔方式)

在可以解決此問題的rapply,tapply,eapply,* apply函數之一中是否缺少某些東西,或者總的來說我很傻?

更新

謝謝大家的幫助。 當我測試Amelia庫中的多個插補時,我遇到了這個問題,想看看從長期的角度來看,模擬時刻的分布是什么。 (它們返回的對象的形狀是這樣的,並且具有與原始數據幀相對應的上述屬性,並且沒有丟失的數據。)

這是我整理的要點

我喜歡user20650的答案不需要額外的復制(要點上的imputer2),因此當我開始擴展到1000個列表時,它變得比需要合並新數據幀的列表快得多。

有點古怪,但我還沒有完全解決,就是我運行imputer1與imputer2所產生的值看起來相同,但是a == b是錯誤的。 我假設一個四舍五入的問題。

我還在尋找一種在該結構上應用一般函數(例如均值或sd)(不進行復制)而不是逐項計算的方法,但是無論如何我的問題都解決了,我將其留給另一個問題。

# 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)

另一個選項將列表l轉換為數組a (使用此處建議的方法),並在前兩個維度上應用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

嘗試合並,然后計算您的均值:

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)

這是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)

(我認為)如果每個數據幀中的某些變量不同或順序不同,則先前的答案將失敗(肯定是我先前的回答)。 下面一個相當可怕的功能,但它似乎起作用。

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)

編輯

這里的示例在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)

使用@ user20650的示例進行了測試。 兩個相等數字的平均值應為相同數字。

 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代碼:對於每個列名,我們使用數字索引獲取數據框,並使用字符索引獲取列,然后將這些列“ c綁定”在一起並傳遞給rowMeans 然后使用setNames rowMean -ed值列表提供名稱,最后將其轉換為數據框。

請注意,這不會獲取多於兩個的列表中的所有數據框...僅考慮前兩個。

> 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM