【问题标题】:Using lapply to group list of data frames by column使用 lapply 按列对数据框列表进行分组
【发布时间】:2020-03-07 15:50:34
【问题描述】:

我有一个包含多个数据框的列表。我想按类别 (A) 对数据进行排序,并使用 lapply-command 对频率 (B) 求和。

数据为df_list

df_list
$`df.1`

        A       B
1   Apples      2
2   Pears       5
3   Apples      6
4   Pears       1
5   Apples      3


$`df.2`
        A       B
1   Oranges     2
2   Pineapples  5
3   Oranges     6
4   Pineapples  1
5   Oranges     3

预期的结果 df_list_2 如下所示:

df_list_2
$`df.1`

        A       B
1   Apples      11
2   Pears       6       

$`df.2`
        A       B
1   Oranges     11
2   Pineapples  6

我基于 lapply 尝试了以下代码:

df_list_2<-df_list[, lapply(B, sum), by = A]

但是,我收到一个错误代码,提示找不到 A

要么我弄错了 lapply 命令在这种情况下的工作方式,要么我对它应该如何工作的理解有缺陷。 非常感谢任何帮助。

【问题讨论】:

  • 看起来您已经从代码中的 data.table 中提取了一些详细信息,但在这里没有引用它。您所做的只是 data.table 解决方案的一半,所以如果这是您所追求的,您需要指定。

标签: r list dataframe group-by lapply


【解决方案1】:

OP 帖子中的data.table 语法可以更改为

library(data.table)
lapply(df_list, function(x) as.data.table(x)[, .(B = sum(B)), by = A])
#$df.1
#        A  B
#1: Apples 11
#2:  Pears  6

#$df.2
#            A  B
#1:    Oranges 11
#2: Pineapples  6

数据

df_list <- list(df.1 = structure(list(A = structure(c(1L, 2L, 1L, 2L, 1L
), .Label = c("Apples", "Pears"), class = "factor"), B = c(2L, 
5L, 6L, 1L, 3L)), class = "data.frame", row.names = c("1", "2", 
"3", "4", "5")), df.2 = structure(list(A = structure(c(1L, 2L, 
1L, 2L, 1L), .Label = c("Oranges", "Pineapples"), class = "factor"), 
    B = c(2L, 5L, 6L, 1L, 3L)), class = "data.frame", row.names = c("1", 
"2", "3", "4", "5")))

【讨论】:

    【解决方案2】:

    我担心您可能对lapply 和提取运算符 ([) 没有一个清晰的概念。记住lapply(list, function) 将指定的function 应用到你给它的list 的每个元素。 Extract 为您提供您指定的元素:

    x <- c('a', 'b', 'c')
    x[2]
    ## "b"
    

    我想在你的 R 工作区的某个地方你有一个对象名称 B 这就是为什么你没有得到类似

    的错误
    ## Error in lapply(B, sum) : object 'B' not found
    

    相反,如果您(无意或有意)同时定义了 AB,您会看到错误

    ## Error in df_list[, lapply(B, sum), by = A] : incorrect number of dimensions
    

    因为那根本不是如何使用[;请记住,您只需将索引或布尔值以及偶尔的可选参数传递给[,但by 不是其中之一。

    所以没有进一步的告别,这就是我将如何做到这一点(在基础 R 中):

    # make some data
    a <- c(1, 2, 1, 2, 1)
    b <- c(2, 5, 6, 1, 3)
    df_list <- list(df.1 = data.frame(A = c('Apples', 'Pears')[a], B = b), 
                    df.2 = data.frame(A = c('Oranges', 'Pineapples')[a], B = b))
    
    # simplify it
    df_list_2 <- lapply(df_list, function(x) {
        aggregate(list(B = x$B), list(A = x$A), sum)
    })
    
    # the desired result
    df_list_2
    
    ## $df.1
    ##        A  B
    ## 1 Apples 11
    ## 2  Pears  6
    ## 
    ## $df.2
    ##            A  B
    ## 1    Oranges 11
    ## 2 Pineapples  6
    

    您可以利用data.frame 只是一个列表这一事实,并像这样缩短您的代码:

    df_list_2 <- lapply(df_list, function(x) {
        aggregate(x['B'], x['A'], sum)
    })
    

    但第一种写法应该有助于更清楚地说明我们在做什么

    【讨论】:

    • 感谢您花时间解释发生了什么,安迪。这很有帮助。
    【解决方案3】:

    您需要在lapplyaggregate

    lapply(df_list, function(x) aggregate(B~A, x, sum))
    
    #[[1]]
    #       A  B
    #1 Apples 11
    #2  Pears  6
    
    #[[2]]
    #           A  B
    #1    Oranges 11
    #2 Pineapples  6
    

    使用来自purrrdplyrmap 会是

    library(dplyr)
    purrr::map(df_list, ~.x %>% group_by(A) %>% summarise(sum = sum(B)))
    

    数据

    df_list <- list(structure(list(A = structure(c(1L, 2L, 1L, 2L, 1L), 
    .Label = c("Apples", "Pears"), class = "factor"), B = c(2L, 5L, 6L, 1L, 3L)), 
    class = "data.frame", row.names = c("1", "2", "3", "4", "5")), 
    structure(list(A = structure(c(1L, 2L, 1L, 2L, 1L), .Label = c("Oranges", 
    "Pineapples"), class = "factor"), B = c(2L, 5L, 6L, 1L, 3L)), class = "data.frame", 
    row.names = c("1", "2", "3", "4", "5")))
    

    【讨论】:

      猜你喜欢
      • 2022-01-22
      • 2020-11-05
      • 2021-09-26
      • 2019-08-29
      • 1970-01-01
      • 2019-11-07
      • 1970-01-01
      • 2017-07-05
      • 2020-08-05
      相关资源
      最近更新 更多