【问题标题】:R reshape2 or dplyr/tidyr: calculating values' percentage of sub-totalR reshape2 或 dplyr/tidyr:计算值在小计中的百分比
【发布时间】:2017-01-24 21:48:43
【问题描述】:

让我们以空气质量数据集为基础。

myaqm <- melt(airquality, id=c("Month", "Day"), na.rm = TRUE)

这让我简化了我的真实数据集。到目前为止,我已经这样做了:

myaqm_dcast <- dcast(myaqm, Day+variable~Month, value.var = "value", sum, margins=c("Day", "variable", "Month"))

这给了我这个:

> head(myaqm_dcast, n=10)
   Day variable     5     6     7     8     9  (all)
1    1    Ozone  41.0   0.0 135.0  39.0  96.0  311.0
2    1  Solar.R 190.0 286.0 269.0  83.0 167.0  995.0
3    1     Wind   7.4   8.6   4.1   6.9   6.9   33.9
4    1     Temp  67.0  78.0  84.0  81.0  91.0  401.0
5    1    (all) 305.4 372.6 492.1 209.9 360.9 1740.9
6    2    Ozone  36.0   0.0  49.0   9.0  78.0  172.0
7    2  Solar.R 118.0 287.0 248.0  24.0 197.0  874.0
8    2     Wind   8.0   9.7   9.2  13.8   5.1   45.8
9    2     Temp  72.0  74.0  85.0  81.0  92.0  404.0
10   2    (all) 234.0 370.7 391.2 127.8 372.1 1495.8

但是,我正在尝试为每个当前数字列创建一个额外的 variables'-percentage-of-days'-subtotal 列。所以我的目标是这样的:

Day     variable        5       5(day %)        6       6(day %)        7       7(day %)        8       8(day %)        9       9(day %)        (all)       (all)(day %)
1       Ozone       41      13.4%       0       0.0%        135     27.4%       39      18.6%       96      26.6%       311     17.9%
1       Solar.R     190     62.2%       286     76.8%       269     54.7%       83      39.5%       167     46.3%       995     57.2%
1       Wind        7.4     2.4%        8.6     2.3%        4.1     0.8%        6.9     3.3%        6.9     1.9%        33.9        1.9%
1       Temp        67      21.9%       78      20.9%       84      17.1%       81      38.6%       91      25.2%       401     23.0%
1       (all)       305.4       100.0%      372.6       100.0%      492.1       100.0%      209.9       100.0%      360.9       100.0%      1740.9      100.0%
2       Ozone       36      15.4%       0       0.0%        49      12.5%       9       7.0%        78      21.0%       172     11.5%
2       Solar.R     118     50.4%       287     77.4%       248     63.4%       24      18.8%       197     52.9%       874     58.4%
2       Wind        8       3.4%        9.7     2.6%        9.2     2.4%        13.8        10.8%       5.1     1.4%        45.8        3.1%
2       Temp        72      30.8%       74      20.0%       85      21.7%       81      63.4%       92      24.7%       404     27.0%
2       (all)       234     100.0%      370.7       100.0%      391.2       100.0%      127.8       100.0%      372.1       100.0%      1495.8      100.0%

对不起,糟糕的格式!但正如您所希望看到的,新的附加列给出了当天和当月每个变量的百分比。

我发现另一个 Stack Overflow 助手建议使用 tidyr 和 dplyr,但我无法根据我的需要调整他们的示例。有人能告诉我该怎么做吗?

【问题讨论】:

    标签: r dplyr tidyr dcast


    【解决方案1】:

    我写了一个百分比函数并将它与 dplyr 一起使用。然后我将这些列连接在一起。

    pct <- function(x) {x/sum(x)}
    
    df <- myaqm_dcast %>%
      filter(variable != "(all)") %>%
      group_by(Day) %>%
      mutate_each(funs(pct), 3:8) %>%
      inner_join(myaqm_dcast, by = c("Day", "variable"))
    

    编辑:您可以根据需要修改百分比函数以打印(*100,粘贴 % 符号)。

    编辑 2:如果您可以在没有(所有)行的情况下生活,我已将其过滤掉。您始终可以使用 summarise_each() 函数计算列总和。

    【讨论】:

    • 如果将每一列除以第 8 列,这将是正确的答案——但这不是问题所在。对于每一列,您必须每 5 行循环一次并除以 (all) 。所以首先你必须按第 5、6、7、8、9 列(全部)融化,然后除以行all
    • 感谢 the_darkside。 Ryan 的回答似乎有效,因为我得到了六个新列,其中的小数与我的示例中的百分比相匹配(感谢 Ryan!),但是我希望您能详细说明您的解释。
      我唯一要补充的是,我必须改用:
      pct 因为我认为包含(全部)总和导致小数是它们应该是的一半。
      注意:暂时推迟接受答案,以防您想添加额外内容。
    • 这是因为 Ryan 的解决方案将 4 个变量中的每一个的值与 (all) 行相加 - 这意味着总数除以应有的数量的两倍。您可以在mutate_each 之前的行中插入slice(-n()),而不是在pct 函数中乘以2。
    • 是的,我错过了原始答案中的(所有)行。对此感到抱歉。
    • @Ryan 作为 'pct' 函数的进一步改进,假设我们想从 (all) 的总和中排除 Wind,但仍希望将其计算为另一个 %。也就是说,(all) == Ozone + Solar.R + Temp,但我们仍然提供 Wind/(all) 的百分比。我们如何在 pct 内执行排除?另外,我应该把这个作为一个新问题来问吗?
    【解决方案2】:

    为什么要重塑数据? Dataframe myaqm 满足tidy data 的要求(每一列是一个变量,每一行是一个观察值)。您可以按以下格式进行计算:

    library(dplyr)
    myaqm %>%
      group_by(Day, variable) %>%
      mutate(all = sum(value),
         perc = paste0(round(100 * value/all, 2), "%")
    

    即使用于创建绘图(例如,通过 ggplot),这种格式也比重新调整的格式更适合。

    如果真的有必要,你可以使用 tidyr/dplyr 重塑:

    ...
    gather(key, val, -c(Month:variable, all)) %>%
    unite(temp, Month, key) %>%
    spread(temp, val)
    

    【讨论】:

    • 感谢您的帮助,但您的百分比似乎是基于给定日期和给定变量的所有月份的总和,而不是给定月份中给定日期的变量总和。对于你的问题“你为什么要重塑你的数据?”让我解释一下客户并说,“因为我付钱给你,让你以那种格式给我。”再次感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 2018-06-20
    • 2016-06-05
    • 1970-01-01
    • 1970-01-01
    • 2015-10-11
    • 2021-08-17
    • 1970-01-01
    • 2012-09-16
    相关资源
    最近更新 更多