代码之家  ›  专栏  ›  技术社区  ›  Banjo

数据帧中重复id的压缩因子变量

r
  •  1
  • Banjo  · 技术社区  · 7 年前

    我有一个重复id's的数据帧,id代表一个特定的实体。ID是重复的,因为数据集引用了一个每个实体都可以经历多次的过程。

    下面是一个小例子 dat

    library(dplyr)
    glimpse(dat)
    Observations: 6
    Variables: 3
    $ ID      <dbl> 1, 1, 1, 2, 2, 2
    $ Amount  <dbl> 10, 70, 80, 50, 10, 10
    $ Product <fct> A, B, C, B, E, A
    

    ID 代表实体, Amount 表示实体已花费的金额,以及 Product 代表实体购买的货物。

    问题是我必须“浓缩”这些数据。因此,每个id/实体只能出现一次。对于连续变量,这不是问题,因为我可以简单地计算每个id的平均值。

    library(tidyr)
    
    dat_con_ID <- dat %>% 
        select(ID) %>% 
        unique()
    
    dat_con_Amount <- dat %>% 
        group_by(ID) %>% 
        summarise(Amount = mean(Amount))
    
    dat_con <- inner_join(dat_con_ID, dat_con_Amount, by = "ID")
    
    glimpse(dat_con)
    Observations: 2
    Variables: 2
    $ ID     <dbl> 1, 2
    $ Amount <dbl> 53.33333, 23.33333
    

    问题是,我无法计算 产品 因为它是一个分类变量。一个选择是用这个因子做一个虚拟变量并计算平均值。但由于原始数据帧非常大,这不是一个好的解决方案。你知道怎么处理这个问题吗?

    2 回复  |  直到 7 年前
        1
  •  1
  •   Sathish    7 年前

    可能是你想这么做:

    我在用 data.table 图书馆。我还修改了您的数据,为 ID = 1 ,以便您可以看到输出中的差异。

    数据:

    library('data.table')
    dat <- data.table(ID =as.double(c(1, 1, 1, 2, 2, 2,1)),
                      Amount = as.double(c( 10, 70, 80, 50, 10, 10, 20)),
                      Product = factor( c('A', 'B', 'C', 'B', 'E', 'A', 'A')))
    

    代码:

    # average amount per id
    dat[, .(avg_amt = mean(Amount)), by = .(ID) ]
    #    ID  avg_amt
    # 1:  1 45.00000
    # 2:  2 23.33333
    
    # average product per id
    dat[, .SD[, .N, by = Product ][, .( avg_pdt = N/sum(N), Product)], by = .(ID) ]
    #    ID   avg_pdt Product
    # 1:  1 0.5000000       A
    # 2:  1 0.2500000       B
    # 3:  1 0.2500000       C
    # 4:  2 0.3333333       B
    # 5:  2 0.3333333       E
    # 6:  2 0.3333333       A
    
    # combining average amount and average product per id
    dat[, .SD[, .N, by = Product ][, .( Product,
                                        avg_pdt = N/sum(N), 
                                        avg_amt = mean(Amount))],
        by = .(ID) ]
    #    ID Product   avg_pdt  avg_amt
    # 1:  1       A 0.5000000 45.00000
    # 2:  1       B 0.2500000 45.00000
    # 3:  1       C 0.2500000 45.00000
    # 4:  2       B 0.3333333 23.33333
    # 5:  2       E 0.3333333 23.33333
    # 6:  2       A 0.3333333 23.33333    
    
        2
  •  1
  •   markus    7 年前

    编辑

    另一个想法是 count 根据“id”计算“product” mean “数量”和每个产品的相对频率。 spread 按“产品”列出的数据将以宽格式结束。 因此,每个id/实体只能出现一次。

    dat %>% 
      add_count(Product, ID) %>% 
      group_by(ID) %>% 
      mutate(Amount = mean(Amount),
             n = n / n()) %>%
      unique() %>% 
      spread(Product, n, sep = "_") %>% 
      ungroup()
    # A tibble: 2 x 6
    #     ID Amount Product_A Product_B Product_C Product_E
    #  <dbl>  <dbl>     <dbl>     <dbl>     <dbl>     <dbl>
    #1    1.   45.0     0.500     0.250     0.250    NA    
    #2    2.   23.3     0.333     0.333    NA         0.333
    

    我的第一次尝试,不是Op想要的,而是万一有人感兴趣:

    正如@steveb在评论中所建议的,您可以总结一下 Product 作为一根绳子。

    library(dplyr)
    dat %>% 
     group_by(ID) %>% 
     summarise(Amount = mean(Amount),
               Product = toString( sort(unique(Product)))
               )
     # A tibble: 2 x 3
    #     ID Amount Product
    #  <dbl>  <dbl> <chr>  
    #1    1.   45.0 A, B, C
    #2    2.   23.3 A, B, E
    

    数据

    dat <- structure(list(ID = c(1, 1, 1, 2, 2, 2, 1), Amount = c(10, 70, 
    80, 50, 10, 10, 20), Product = structure(c(1L, 2L, 3L, 2L, 4L, 
    1L, 1L), .Label = c("A", "B", "C", "E"), class = "factor")), .Names = c("ID", 
    "Amount", "Product"), row.names = c(NA, -7L), .internal.selfref = <pointer: 0x2c14528>, class = c("tbl_df", 
    "tbl", "data.frame"))