[英]Using lapply in R to loop through a list of data.frames in R
[英]R loop through columns in list of data frames
假設以下數據框(實際上我的數據框有數千行):
year<-c(2010,2010,2010,2011,2011,2011,2012,2012,2013,2013)
a1<-rnorm(10)
a2<-rnorm(10)
b1<-rnorm(10)
b2<-rnorm(10)
c1<-rnorm(10)
c2<-rnorm(10)
我使用以下代碼創建了一個由多個數據框組成的列表,它將原始數據框按年份拆分為子集。
#split datasets into years
df.list<-split(df, df$year)
#Name of datasets df plus year
dfnames <- str_c("df", names(df.list))
names(df.list)<-dfnames
我想將以下循環應用於列表的所有數據幀:
#df_target is a new data frame that stores the results and j is the indicator for it:
df_target <- NULL
j <- 1
for(i in seq(2, 7, 2)) {
df_target[[j]] <- (df[i]*df[i+1])/(sum(df[i+1]))
j <- j+1
}
}
該代碼適用於一個數據框,但是,我想將數據框拆分為按年份分組的多個數據框,然后遍歷各列。
因此,我使用以下 function 將上述循環應用於列表中的所有數據幀:
df_target <- NULL
j <- 1
fnc <- function(x){
for(i in seq(2, 7, 2)) {
df_target[[j]] <- (x[i]*x[i+1])/(sum(x[i+1]))
j <- j+1
}
}
sapply(df.list, fnc)
使用此代碼,我沒有收到任何錯誤消息,但是列表中的兩個數據幀都是 NULL。我到底做錯了什么?
df_target 應該是一個包含列 a_new= (a1 a2)/sum(a2)、b_new= (b1 b2)/sum(b2) 和 c_new= (c1*c2)/sum(c2) 的數據框,但每年分開。
您需要在 function 中定義j
和df_target
,並設置它應該返回什么(就像現在一樣,它計算df_target
,但不返回它):
fnc <- function(x){
df_target <- NULL
j <- 1
for(i in seq(2, 7, 2)) {
df_target[[j]] <- (x[i]*x[i+1])/(sum(x[i+1]))
j <- j+1
}
return(df_target)
}
但請記住,這將是 output 一個列表矩陣,對於sapply
df.list
是 select,您將創建一個 3 元素的df_target
列表,因此 output 在控制台中將如下所示:
> sapply(df.list, fnc)
df2010 df2011 df2012 df2013
[1,] List,1 List,1 List,1 List,1
[2,] List,1 List,1 List,1 List,1
[3,] List,1 List,1 List,1 List,1
但會是這樣的:
為了獲得更清晰的 output,我們可以設置df_target
來創建一個數據框,其中包含每年的值:
fnc <- function(x){
df_target <- as.data.frame(matrix(nrow=nrow(x), ncol=3))
for(i in seq(2, 7, 2)) {
df_target[,i/2] <- (x[i]*x[i+1])/(sum(x[i+1]))
}
return(df_target)}
這每年返回一個 df,但如果我們使用sapply
,我們將得到一個類似 output 的列表矩陣,因此最好將 function 定義為每年循環一次:
fnc <- function(y){
df_target.list <- list()
k=1
for(j in y){
df_target <- as.data.frame(matrix(nrow=nrow(j), ncol=3))
for(i in seq(2, 7, 2)) {
df_target[,i/2] <- (j[i]*j[i+1])/(sum(j[i+1]))
}
df_target.list[[names(y)[k]]] = df_target
k=k+1
}
return(df_target.list)}
Output:
> fnc(df.list)
$df2010
V1 V2 V3
1 -0.10971160 0.01688244 -0.16339367
2 0.05440564 0.57554210 -0.06803244
3 0.03185178 0.90598561 -0.68692401
$df2011
V1 V2 V3
1 -0.43090055 0.007152131 0.3930606
2 0.15050644 0.329092942 -0.1367295
3 0.07336839 -0.423631930 -0.1504056
$df2012
V1 V2 V3
1 0.5540294 0.4561862 0.09169914
2 0.1153931 -1.1311450 0.81853691
$df2013
V1 V2 V3
1 0.4322934 0.5286973 0.2136495
2 -0.2412705 0.1316942 0.1455196
這是一個tidyverse
解決方案。 試着一點一點地運行它,這樣你就可以看到它做了什么。
首先,它將 rowid 添加為一列,以確保稍后可以識別唯一的行。 然后它使用pivot_longer
重塑數據以將數據放入長格式,然后pivot_wider
部分反轉它。 然后將數據分組並運行計算。 這是在內部運行一個循環。
library(tidyverse)
set.seed(123)
tibble(
year = c(2010, 2010, 2010, 2011, 2011, 2011, 2012, 2012, 2013, 2013),
a1 = rnorm(10),
a2 = rnorm(10),
b1 = rnorm(10),
b2 = rnorm(10),
c1 = rnorm(10),
c2 = rnorm(10)
) %>%
rowid_to_column() %>%
pivot_longer(cols = -c(year, rowid), names_to = c("nameA", "name12"), names_pattern = "(\\w)(\\d)" ) %>%
pivot_wider(names_from = name12, values_from = value) %>%
group_by(nameA) %>%
mutate(j = `1` * `2` / (sum(`2`)))
#> # A tibble: 30 x 6
#> # Groups: nameA [3]
#> rowid year nameA `1` `2` j
#> <int> <dbl> <chr> <dbl> <dbl> <dbl>
#> 1 1 2010 a -0.560 1.22 -0.329
#> 2 1 2010 b -1.07 0.426 -0.141
#> 3 1 2010 c -0.695 0.253 -0.0794
#> 4 2 2010 a -0.230 0.360 -0.0397
#> 5 2 2010 b -0.218 -0.295 0.0200
#> 6 2 2010 c -0.208 -0.0285 0.00268
#> 7 3 2010 a 1.56 0.401 0.299
#> 8 3 2010 b -1.03 0.895 -0.285
#> 9 3 2010 c -1.27 -0.0429 0.0245
#> 10 4 2011 a 0.0705 0.111 0.00374
#> # … with 20 more rows
由reprex package (v0.3.0) 創建於 2020-10-26
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.