压缩数据框中重复ID的因子变量

时间:2018-05-30 16:54:30

标签: r

我有一个带有重复ID的数据框。 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

问题是,我无法计算Product的平均值,因为它是一个分类变量。一个选项是从该因子中制作一个虚拟变量并计算平均值。但由于原始数据框架非常庞大,因此这不是一个好的解决方案。任何想法如何处理这个问题?

2 个答案:

答案 0 :(得分:1)

修改

另一个想法是count&#39;产品&#39;根据“ID&#39;”,计算“{金额”的mean&#39;以及每种产品的相对频率。 spread数据来自&#39;产品&#39;以宽格式结束数据。 因此,每个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"))

答案 1 :(得分:1)

可能是你想要这样做:

我正在使用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