![](/img/trans.png)
[英]Apply a function to the rows of a data frame return a list of data frames
[英]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.