【问题标题】:How do I create a loop and/or a function to divide 200 columns (and create 200 new columns/variables) by another column to get a percentage?如何创建循环和/或函数以将 200 列(并创建 200 个新列/变量)除以另一列以获得百分比?
【发布时间】:2019-09-19 21:33:36
【问题描述】:

如何创建循环和/或函数以将 200 列(并创建 200 个新列/变量)除以另一列以获得百分比?

如何循环执行此操作,以便可以处理 200 列?以及如何命名 命名列,使其成为前面带有“p_”的旧列名? 这可能吗?

例如,我正在尝试做这样的事情,但有 200 列。

fans <- data.frame(
  population = c(1234, 5678, 2345, 6789, 3456, 7890,
                4567, 8901, 5678, 9012, 6789),
  bearsfans = c(123, 234, 345, 456, 567,678, 789, 890, 901, 135, 246),
  packersfans = c(11,22,33,44,55,66,77,88,99,100,122),
  vikingsfans = c(39, 49, 59, 61, 32, 22, 31, 92, 52, 10, 122))

print(fans)

attach(fans)

## create new columns which are the ratio of fans to population

fans$p_bearsfan = bearsfans/population
print(fans)


 Output:
 ##     population bearsfans packersfans vikingsfans p_bearsfan
 ##  1        1234       123          11          39 0.09967585
 ##  2        5678       234          22          49 0.04121169

【问题讨论】:

    标签: r function loops


    【解决方案1】:
    temp <- sapply(fans[-1], function(x) x / fans$population)
    colnames(temp) <- paste0("p_", colnames(temp))
    cbind(fans, temp)
    
    
    
    population bearsfans packersfans vikingsfans p_bearsfans p_packersfans p_vikingsfans
    1        1234       123          11          39  0.09967585   0.008914100   0.031604538
    2        5678       234          22          49  0.04121169   0.003874604   0.008629799
    3        2345       345          33          59  0.14712154   0.014072495   0.025159915
    4        6789       456          44          61  0.06716748   0.006481072   0.008985123
    5        3456       567          55          32  0.16406250   0.015914352   0.009259259
    6        7890       678          66          22  0.08593156   0.008365019   0.002788340
    7        4567       789          77          31  0.17276111   0.016860083   0.006787826
    8        8901       890          88          92  0.09998877   0.009886530   0.010335917
    9        5678       901          99          52  0.15868263   0.017435717   0.009158154
    10       9012       135         100          10  0.01498003   0.011096316   0.001109632
    11       6789       246         122         122  0.03623509   0.017970246   0.017970246
    

    【讨论】:

    • 极好,成功了!谢谢!我是新手,必须有一种简单的方法来做到这一点,但我是函数新手。
    • 欢迎您。请注意,您只能将一个答案标记为已接受,但请随意选择您最喜欢的答案。 :)
    • 知道了。我是新手:)
    • @shp5009 虽然您只能选择一个答案作为接受的答案,但您可以投票任意数量;-)
    • 没错,但是你需要 15 声望。 2去!我赞成这个问题。和你的答案;)
    【解决方案2】:

    如果您对后缀的新列名(而不是前缀)感到满意,这是使用dplyr::mutate_at 的单行代码。我在这里假设所有相关列都以单词"fans" 结尾。

    带后缀

    fans %>% mutate_at(vars(ends_with("fans")), list(percent = ~.x / population))
    #   population bearsfans packersfans vikingsfans bearsfans_percent
    #1        1234       123          11          39        0.09967585
    #2        5678       234          22          49        0.04121169
    #3        2345       345          33          59        0.14712154
    #4        6789       456          44          61        0.06716748
    #5        3456       567          55          32        0.16406250
    #6        7890       678          66          22        0.08593156
    #7        4567       789          77          31        0.17276111
    #8        8901       890          88          92        0.09998877
    #9        5678       901          99          52        0.15868263
    #10       9012       135         100          10        0.01498003
    #11       6789       246         122         122        0.03623509
    #   packersfans_percent vikingsfans_percent
    #1          0.008914100         0.031604538
    #2          0.003874604         0.008629799
    #3          0.014072495         0.025159915
    #4          0.006481072         0.008985123
    #5          0.015914352         0.009259259
    #6          0.008365019         0.002788340
    #7          0.016860083         0.006787826
    #8          0.009886530         0.010335917
    #9          0.017435717         0.009158154
    #10         0.011096316         0.001109632
    #11         0.017970246         0.017970246
    

    带前缀

    要将后缀变成前缀需要更多步骤

    fans %>%
        mutate_at(vars(ends_with("fans")), list(percent = ~.x / population)) %>%
        rename_at(vars(ends_with("percent")), ~sub("(.+)_percent", "p_\\1", .x))
    #   population bearsfans packersfans vikingsfans p_bearsfans p_packersfans
    #1        1234       123          11          39  0.09967585   0.008914100
    #2        5678       234          22          49  0.04121169   0.003874604
    #3        2345       345          33          59  0.14712154   0.014072495
    #4        6789       456          44          61  0.06716748   0.006481072
    #5        3456       567          55          32  0.16406250   0.015914352
    #6        7890       678          66          22  0.08593156   0.008365019
    #7        4567       789          77          31  0.17276111   0.016860083
    #8        8901       890          88          92  0.09998877   0.009886530
    #9        5678       901          99          52  0.15868263   0.017435717
    #10       9012       135         100          10  0.01498003   0.011096316
    #11       6789       246         122         122  0.03623509   0.017970246
    #   p_vikingsfans
    #1    0.031604538
    #2    0.008629799
    #3    0.025159915
    #4    0.008985123
    #5    0.009259259
    #6    0.002788340
    #7    0.006787826
    #8    0.010335917
    #9    0.009158154
    #10   0.001109632
    #11   0.017970246
    

    【讨论】:

    • 谢谢。这很有帮助。我可能不应该在变量名称中添加粉丝,而只是在思考列。我的变量确实有一组具有相同后缀的名称,但不是全部,并且后缀因组而异。有些列的名称完全不同。有没有办法只通过列号来做,仍然在变量名的开头或结尾添加“p_”?
    • @shp5009 当然;您可以直接指定列号。例如,fans %&gt;% mutate_at(2:3, list(percent = ~.x / population)) 仅基于列 2:3 创建新的百分比列。
    【解决方案3】:

    我们可以直接用一列分割多列。我们使用grep 选择以"fans" 结尾的列,并使用这些名称来分配新列。

    cols <- grep("fans$", names(fans), value = TRUE)
    fans[paste0("p_", cols)] <- fans[cols]/fans$population
    
    fans
    #   population bearsfans packersfans vikingsfans p_bearsfans p_packersfans p_vikingsfans
    #1        1234       123          11          39     0.09968      0.008914      0.031605
    #2        5678       234          22          49     0.04121      0.003875      0.008630
    #3        2345       345          33          59     0.14712      0.014072      0.025160
    #4        6789       456          44          61     0.06717      0.006481      0.008985
    #5        3456       567          55          32     0.16406      0.015914      0.009259
    #6        7890       678          66          22     0.08593      0.008365      0.002788
    #7        4567       789          77          31     0.17276      0.016860      0.006788
    #8        8901       890          88          92     0.09999      0.009887      0.010336
    #9        5678       901          99          52     0.15868      0.017436      0.009158
    #10       9012       135         100          10     0.01498      0.011096      0.001110
    #11       6789       246         122         122     0.03624      0.017970      0.017970
    

    另附注:Why is it not advisable to use attach() in R, and what should I use instead?

    【讨论】:

      【解决方案4】:

      数据

        fans <- data.frame(
        population = c(1234, 5678, 2345, 6789, 3456, 7890,
                       4567, 8901, 5678, 9012, 6789),
        bearsfans = c(123, 234, 345, 456, 567,678, 789, 890, 901, 135, 246),
        packersfans = c(11,22,33,44,55,66,77,88,99,100,122),
        vikingsfans = c(39, 49, 59, 61, 32, 22, 31, 92, 52, 10, 122))
      

      简单的解决方案

      for (c in names(fans)[-1]){
        fans[[paste0("p_",c)]] <- fans[[c]] / fans[["population"]]
      }
      

      【讨论】:

      • 没有必要有两个嵌套循环(applyfor 中),并且会产生不必要的开销。事实上,这里不需要apply,因为R中的简单除法/已经矢量化了。
      • [继续] 所以for 循环将变为for (c in names(fans)[2:ncol(fans)]) fans[[paste0("p_",c)]] &lt;- fans[[c]] / fans[["population"]]
      • @MauritsEvers 是的,我同意,这是非常低效的 - 我意识到这一点。编辑了我的帖子。
      • @MauritsEvers 出于好奇,我检查了apply 的解决方案有多慢。它仍然比 mutate 快近 10 倍(但比简单循环列慢 3 倍 - 此线程中发布的所有速度中最快的)。
      • 您应该在答案中包含这些基准测试的结果。我相信这对 OP 和未来的读者来说会很有趣。我当然会感兴趣。 mutate_at 不是最快的方法,这并不让我感到惊讶。 tidyverse 方法通常更多的是关于代码的可读性(甚至会受到一些人的质疑)而不是关于速度。
      猜你喜欢
      • 2014-10-21
      • 1970-01-01
      • 2021-12-09
      • 1970-01-01
      • 1970-01-01
      • 2019-08-12
      • 2016-03-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多