【问题标题】:R data.table: subgroup weighted percent of groupR data.table:组的子组加权百分比
【发布时间】:2015-09-05 18:56:39
【问题描述】:

我有一个data.table 喜欢:

library(data.table)
widgets <- data.table(serial_no=1:100, 
                      color=rep_len(c("red","green","blue","black"),length.out=100),
                      style=rep_len(c("round","pointy","flat"),length.out=100),
                      weight=rep_len(1:5,length.out=100) )

虽然我不确定这是最data.table 的方式,但我可以使用tablelength 在一个步骤中逐组计算子组频率——例如,回答“红色的百分比是多少”的问题小部件是圆形的吗?”

编辑:此代码未提供正确答案

# example A
widgets[, list(style = unique(style), 
               style_pct_of_color_by_count = 
                 as.numeric(table(style)/length(style)) ), by=color]

#    color  style style_pct_of_color_by_count
# 1:   red  round                        0.32
# 2:   red pointy                        0.32
# 3:   red   flat                        0.36
# 4: green pointy                        0.32
# ...

但我无法使用这种方法来回答诸如“按重量计算,红色小部件的圆形百分比是多少?”之类的问题。我只能想出一个两步的方法:

# example B
widgets[,list(cs_weight=sum(weight)),by=list(color,style)][,list(style, style_pct_of_color_by_weight=cs_weight/sum(cs_weight)),by=color]

#    color  style style_pct_of_color_by_weight
# 1:   red  round                    0.3466667
# 2:   red pointy                    0.3466667
# 3:   red   flat                    0.3066667
# 4: green pointy                    0.3333333
# ...

我正在寻找 B 和 A 的单步方法(如果可以改进),以加深我对按组操作的 data.table 语法的理解。请注意,这个问题与Weighted sum of variables by groups with data.table 不同,因为我的问题涉及子组并避免多个步骤。 TYVM。

【问题讨论】:

  • 查看下面@Frank 的回复,我注意到我的尝试A 不仅尴尬而且不正确——例如,我检查了widgets[,sum(style=="round" &amp; color=="red")/sum(color=="red")] # 0.36

标签: r data.table grouping


【解决方案1】:

计算color 中每个style 的频率表,然后为每一行查找该表中该行style 的频率,最后除以该color 中的行数。

widgets[, frac := table(style)[style] / .N, by = color]

给予:

  > widgets
     serial_no color  style weight frac
  1:         1   red  round      1 0.36
  2:         2 green pointy      2 0.36
  3:         3  blue   flat      3 0.36
  4:         4 black  round      4 0.36
  5:         5   red pointy      5 0.32
  6:         6 green   flat      1 0.32
  7:         7  blue  round      2 0.32
  8:         8 black pointy      3 0.32
  9:         9   red   flat      4 0.32
 10:        10 green  round      5 0.32
 ... etc ...

如果需要,这可以很容易地转换为 base 或 dplyr:

# base
prop <- function(x) table(x)[x] / length(x)
transform(widgets, frac = ave(style, color, FUN = prop))

# dplyr - uses prop function from above
library(dplyr)
widgets %>% group_by(color) %>% mutate(frac = prop(style)) %>% ungroup

【讨论】:

    【解决方案2】:

    使用dplyr 可能是个好主意

    df <- widgets %>% 
      group_by(color, style) %>%
      summarise(count = n()) %>%
      mutate(freq = count/sum(count))
    
    df2 <- widgets %>% 
      group_by(color, style) %>%
      summarise(count_w = sum(weight)) %>%
      mutate(freq = count_w/sum(count_w))  
    

    【讨论】:

    • 谢谢@drsh1 我很欣赏dplyr 在这里很直观和有用。我的具体问题是如何使用data.table 语法。
    【解决方案3】:

    这几乎是一个步骤:

    # A
    widgets[,{
        totwt = .N
        .SD[,.(frac=.N/totwt),by=style]
    },by=color]
        # color  style frac
     # 1:   red  round 0.36
     # 2:   red pointy 0.32
     # 3:   red   flat 0.32
     # 4: green pointy 0.36
     # 5: green   flat 0.32
     # 6: green  round 0.32
     # 7:  blue   flat 0.36
     # 8:  blue  round 0.32
     # 9:  blue pointy 0.32
    # 10: black  round 0.36
    # 11: black pointy 0.32
    # 12: black   flat 0.32
    
    # B
    widgets[,{
        totwt = sum(weight)
        .SD[,.(frac=sum(weight)/totwt),by=style]
    },by=color]
     #    color  style      frac
     # 1:   red  round 0.3466667
     # 2:   red pointy 0.3466667
     # 3:   red   flat 0.3066667
     # 4: green pointy 0.3333333
     # 5: green   flat 0.3200000
     # 6: green  round 0.3466667
     # 7:  blue   flat 0.3866667
     # 8:  blue  round 0.2933333
     # 9:  blue pointy 0.3200000
    # 10: black  round 0.3733333
    # 11: black pointy 0.3333333
    # 12: black   flat 0.2933333
    

    它是如何工作的:在进入更精细的组(colorstyle)进行制表之前,为顶级组(color)构建分母。


    替代品。如果styles 在每个color 中重复并且这仅用于显示目的,请尝试table

    # A
    widgets[,
      prop.table(table(color,style),1)
    ]
    #        style
    # color   flat pointy round
    #   black 0.32   0.32  0.36
    #   blue  0.36   0.32  0.32
    #   green 0.32   0.36  0.32
    #   red   0.32   0.32  0.36
    
    # B
    widgets[,rep(1L,sum(weight)),by=.(color,style)][,
      prop.table(table(color,style),1)
    ]
    
    #        style
    # color        flat    pointy     round
    #   black 0.2933333 0.3333333 0.3733333
    #   blue  0.3866667 0.3200000 0.2933333
    #   green 0.3200000 0.3333333 0.3466667
    #   red   0.3066667 0.3466667 0.3466667
    

    对于 B,这会扩展数据,以便每个重量单位都有一个观察值。对于大数据,这样的扩展将是一个坏主意(因为它会消耗大量内存)。此外,weight 必须是整数;否则,它的总和将被默默地截断为一(例如,尝试rep(1,2.5) # [1] 1 1)。

    【讨论】:

    • 我就是这样做的,但我也有兴趣找到更好的方法。
    • 谢谢@Frank——我需要一段时间来理解点符号和嵌入的分配,但这是一个很好的方法。
    • 你的第一个版本可以在没有临时变量的情况下重写如下:widgets[, .(frac = .SD[, .N, by=style]$N / .N), by=color]
    • @Arun style 列也应该在结果中。
    猜你喜欢
    • 1970-01-01
    • 2015-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-26
    • 2023-02-22
    • 1970-01-01
    相关资源
    最近更新 更多