簡體   English   中英

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 中定義jdf_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.

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