【问题标题】:R:Subsetting over all data frames inside a listR:对列表中的所有数据框进行子集化
【发布时间】:2018-04-07 20:18:42
【问题描述】:

我是使用 R 和 stackoverflow 的新手。我正在尝试处理数据框列表并遇到以下问题(希望这是一个很好的复制示例)。假设我有一个包含 3 个 4 列的数据框的列表(我的真实代码包含 10 个 20 列的数据框):

df1 <- data.frame(k=20:0, h_1=rnorm(21), h_2=rnorm(21), h_3= rnorm(21))
df2 <- data.frame(k=20:0, h_1=rnorm(21), h_2=rnorm(21), h_3= rnorm(21))
df3 <- data.frame(k=20:0, h_1=rnorm(21), h_2=rnorm(21), h_3= rnorm(21))
df_list <- list(df1=df1,df2=df2,df3=df3)

对于每个数据框,我都有不同的子集条件:

例如:

#If I would subset them in a singular way outside of the list

df1_s <- df1[which(df1$k <=12 & df1$k >0), df1$h_1] #Taking only rows of k=12 to k=1 
and only the column h_1
df2_s <- df2[which(df2$k <=4 & df2$k >0), df2$h_3]
df3_s <- df3[which(df3$k <=12 & df2$k >0), df2$h_2]

如何以最有效的方式对列表中的三个数据框进行子集化? 我认为使用 lapply 并将子集的数量放入向量中会是一个不错的方法,但我不知道该怎么做或如何在列表中设置子集。

我希望你能帮助我。在发布之前,我尝试在其他帖子中找到解决方案,这些帖子正在处理列表中数据框的子集,但这不适用于我的代码。

【问题讨论】:

    标签: r list dataframe


    【解决方案1】:

    这是mapply 方法(与其他答案相同):

    # function: w/ arguments dataframe and a vector = [column name, upper, lower]
    rook <- function(df, par) {
      out <- df[par[1]][, 1]
      out[out <= par[2] & out > par[3]]
    }
    
    # list of parameters
    par_list <- list(
      c('h_1', 12, 0),
      c('h_3', 4 , 0),
      c('h_2', 12, 0)
    )
    
    # call mapply
    mapply(rook, df_list, par_list)
    

    【讨论】:

      【解决方案2】:

      这是使用基础 R 的解决方案。正如@www 所提到的,其想法是使用应用类型函数(mapplypmap 来自 purrr)将多个参数依次应用于函数。该解决方案还利用eval-parse 构造来进行灵活的子集设置。参见例如这里的讨论http://r.789695.n4.nabble.com/using-a-condition-given-as-string-in-subset-function-how-td1676426.html

      subset_fun <- function(data, criteria, columns) {
        subset(data, eval(parse(text = criteria)), columns)
      }
      
      criterion <- list("k <= 12 & k > 0", "k <= 4 & k > 0", "k <= 12 & k > 0")
      cols <- list("h_1", "h_3", "h_2")
      
      out <- mapply(subset_fun, df_list, criterion, cols)
      str(out)
      # List of 3
      #  $ df1.h_1: num [1:12] -0.0589 1.0677 0.2122 1.4109 -0.6367 ...
      #  $ df2.h_3: num [1:4] -0.826 -1.506 -1.551 0.862
      #  $ df3.h_2: num [1:12] 0.8948 0.0305 0.9131 -0.0219 0.2252 ...
      

      【讨论】:

      • 不错!我喜欢这个答案。
      • 正如famous R user list 所说:如果答案是 parse(),您通常应该重新考虑这个问题。 -- Thomas Lumley R-help(2005 年 2 月)
      【解决方案3】:

      我们可以使用 包中的pmap 函数。关键是定义一个函数,根据k和列名取参数,然后用这些参数组织一个列表,然后使用pmap

      library(tidyverse)
      
      # Define a function 
      subset_fun <- function(dat, k1, k2, col){
        dat2 <- dat %>%
          filter(k <= k1, k > k2) %>%
          pull(col)
        return(dat2)
      }
      
      # Define lists for the function arguments
      par <- list(dat = df_list,                   # List of data frames
                  k1 = list(12, 4, 12),            # The first number 
                  k2 = list(0, 0, 0),              # The second number
                  col = list("h_1", "h_3", "h_2")) # The column name
      
      # Apply the subset_fun
      df_list2 <- pmap(par, subset_fun)
      df_list2
      # $df1
      # [1] -0.6868529 -0.4456620  1.2240818  0.3598138  0.4007715  0.1106827 -0.5558411  1.7869131
      # [9]  0.4978505 -1.9666172  0.7013559 -0.4727914
      # 
      # $df2
      # [1] -0.9474746 -0.4905574 -0.2560922  1.8438620
      # 
      # $df3
      # [1] -0.2803953  0.5629895 -0.3724388  0.9769734 -0.3745809  1.0527115 -1.0491770 -1.2601552
      # [9]  3.2410399 -0.4168576  0.2982276  0.6365697
      

      数据

      set.seed(123)
      
      df1 <- data.frame(k=20:0, h_1=rnorm(21), h_2=rnorm(21), h_3= rnorm(21))
      df2 <- data.frame(k=20:0, h_1=rnorm(21), h_2=rnorm(21), h_3= rnorm(21))
      df3 <- data.frame(k=20:0, h_1=rnorm(21), h_2=rnorm(21), h_3= rnorm(21))
      df_list <- list(df1=df1,df2=df2,df3=df3)
      

      【讨论】:

      • 我无法访问所有包(和咕噜声)。有没有办法用 plyr oder base R 做到这一点?
      • @rook1996 然后按照其他人的建议使用mapply
      【解决方案4】:

      考虑Mapmapply 的包装器以返回数据帧的列表。并且因为您对一列进行了子集化,为了避免作为向量返回,请使用 data.frame 回退并使用 setNames 重命名。

      这里选择mapplyMap,与lapply 同级,因为您希望在等长对象列表中逐个迭代。 Mapply 接受无限数量的参数,这里有四个,要求长度等于或倍数:

      low_limits <- c(0, 0, 0)
      high_limits <- c(12, 4, 12)
      h_cols <- c("h_1", "h_2", "h_3")
      
      subset_fct <- function(df, lo, hi, col)  
                     setNames(data.frame(df[which(df$k > lo & df$k <= hi), col]), col)
      
      new_df_list <- Map(subset_fct, df_list, low_limits, high_limits, h_cols)
      
      # EQUIVALENT CALL
      new_df_list <- mapply(subset_fct, df_list, low_limits, 
                            high_limits, h_cols, SIMPLIFY = FALSE)
      

      输出 (在顶部使用set.seed(456) 来重现随机数)

      new_df_list
      
      # $df1
      #           h_1
      # 1   1.0073523
      # 2   0.5732347
      # 3  -0.9158105
      # 4   1.3110974
      # 5   0.9887263
      # 6   1.6539287
      # 7  -1.4408052
      # 8   1.9473564
      # 9   1.7369362
      # 10  0.3874833
      # 11  2.2800340
      # 12  1.5378833
      
      # $df2
      #           h_2
      # 1  0.11815133
      # 2  0.86990262
      # 3 -0.09193621
      # 4  0.06889879
      
      # $df3
      #           h_3
      # 1  -1.4122604
      # 2  -0.9997605
      # 3  -2.3107388
      # 4   0.9386188
      # 5  -1.3881885
      # 6  -0.6116866
      # 7   0.3184948
      # 8  -0.2354058
      # 9   1.0750520
      # 10 -0.1007956
      # 11  1.0701526
      # 12  1.0358389
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-02-20
        • 2017-07-21
        • 2021-12-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-13
        • 2013-08-15
        相关资源
        最近更新 更多