【问题标题】:Compute custom function nth row using dplyr使用 dplyr 计算自定义函数第 n 行
【发布时间】:2017-11-30 18:43:08
【问题描述】:

给定以下数据框:

A   B        C       D
1   92.44   14261   13183
2   92.43   14244   13166
3   94.24   14730   13882
4   97.42   12149   11836
5   94.75   14431   13674
6   95.91   11038   10587
7   95.66   14886   14240
8   94.94   12587   11950
9   94.27   13251   12492
10  94.89   12789   12135

我正在尝试使用 R 创建 rowwise 计算,它允许我 summarize() C 和 D 列中的前 4 行,将它们相应地划分并用下一行替换。

replace(nth row + 1) = SUM(C) / SUM(D)

这是我尝试过的

df %>% mutate(B=replace(mpB, nrow(4)=summarise(C/D), NA))   

期望的输出

A   B        C      D
1   92.44   14261   13183
2   92.43   14244   13166
3   94.24   14730   13882
4   97.42   12149   11836
5   94.01   14431   13674
6   95.91   11038   10587
7   95.66   14886   14240
8   94.94   12587   11950
9   94.27   13251   12492
10  95.18   12789   12135

*用所需的计算更新第 5 行和第 10 行

【问题讨论】:

  • 我不太确定你想要达到什么输出,但也许这是一个开始; df %>% mutate(group4 = (1:n() - 1) %/% 4) %>% group_by(group4) %>% summarise(summary = sum(C)/sum(D))
  • @eipi10 这可以帮助我入门,我如何获取分组的输出并使用 mutate 替换和更新下一行。 IE.. 更新第 5 行和第 10 行,%>% mutate(B=replace(B))?

标签: r dataframe statistics dplyr


【解决方案1】:

如果我理解正确,这就是你想要的:

df %>% 
  mutate(group5 = (1:n() - 1) %/% 5) %>% # (using eipi10's method)
  group_by(group5) %>% 
  mutate(B = ifelse(row_number() == 5, # update only 5th row of each group
                    round(100 * sum(D[1:4]) / sum(C[1:4]), 2), 
                    B)) %>% 
  ungroup %>% 
  select(-group5)
# # A tibble: 10 × 4
#        A     B     C     D
#    <int> <dbl> <int> <int>
# 1      1 92.44 14261 13183
# 2      2 92.43 14244 13166
# 3      3 94.24 14730 13882
# 4      4 97.42 12149 11836
# 5      5 94.01 14431 13674
# 6      6 95.91 11038 10587
# 7      7 95.66 14886 14240
# 8      8 94.94 12587 11950
# 9      9 94.27 13251 12492
# 10    10 95.18 12789 12135

【讨论】:

    【解决方案2】:

    以下是使用来自RcppRolldplyrroll_sumr 的方法。您可以每 5 周使用 ifelsemutate B 列。为此,您可以使用A %% 5,它是 A 列的模数乘以 5。当它为 0 时,您将前四个星期相加并根据要求除以 D/C。 lag(roll_sumr(D,4)/roll_sumr(C,4)*100)

    library(dplyr);library(RcppRoll)
    df%>%
      mutate(B=ifelse(A %% 5 ==0,
                      lag(roll_sumr(D,4)/roll_sumr(C,4)*100),
                      B))
    
        A        B     C     D
    1   1 92.44000 14261 13183
    2   2 92.43000 14244 13166
    3   3 94.24000 14730 13882
    4   4 97.42000 12149 11836
    5   5 94.01091 14431 13674
    6   6 95.91000 11038 10587
    7   7 95.66000 14886 14240
    8   8 94.94000 12587 11950
    9   9 94.27000 13251 12492
    10 10 95.18373 12789 12135
    

    数据

    df <- read.table(text="A   B        C       D
                     1   92.44   14261   13183
                     2   92.43   14244   13166
                     3   94.24   14730   13882
                     4   97.42   12149   11836
                     5   94.75   14431   13674
                     6   95.91   11038   10587
                     7   95.66   14886   14240
                     8   94.94   12587   11950
                     9   94.27   13251   12492
                     10  94.89   12789   12135",header=TRUE,stringsAsFactors=FALSE)
    

    【讨论】:

      【解决方案3】:

      我不确定您的分析目标是什么,但删除每组中的四个数据行之一并将其替换为前一组的汇总结果行似乎很奇怪。等待更多信息,这里有一些其他选项。

      要按组创建摘要,您可以:

      df = df %>% mutate(group4 = (1:n() - 1) %/% 4) # Create groups of four consecutive rows
      
      df %>% 
          group_by(group4) %>% 
          summarise(summary = sum(C)/sum(D))
      
        group4  summary
         <dbl>    <dbl>
      1      0 1.063706
      2      1 1.049375
      3      2 1.057376
      

      要插入摘要行,您可以执行以下操作,但这样您的数据将不整洁,并且难以进行额外的分析:

      df = df %>% mutate(group4 = (1:n() - 1) %/% 4) # Create groups of four consecutive rows
      df = bind_rows(df,
                     df %>% 
                       group_by(group4) %>% 
                       summarise(CD = sum(C)/sum(D))) %>%
        arrange(group4)
      
          A     B     C     D group4       CD
      1   1 92.44 14261 13183      0       NA
      2   2 92.43 14244 13166      0       NA
      3   3 94.24 14730 13882      0       NA
      4   4 97.42 12149 11836      0       NA
      5  NA    NA    NA    NA      0 1.063706
      6   5 94.75 14431 13674      1       NA
      7   6 95.91 11038 10587      1       NA
      8   7 95.66 14886 14240      1       NA
      9   8 94.94 12587 11950      1       NA
      10 NA    NA    NA    NA      1 1.049375
      11  9 94.27 13251 12492      2       NA
      12 10 94.89 12789 12135      2       NA
      13 NA    NA    NA    NA      2 1.057376
      

      您还可以将每个组的摘要添加为新列:

      df = df %>% 
        mutate(group4 = (1:n() - 1) %/% 4) %>%
        group_by(group4) %>% 
        mutate(CD = sum(C)/sum(D))
      
             A     B     C     D group4       CD
       1     1 92.44 14261 13183      0 1.063706
       2     2 92.43 14244 13166      0 1.063706
       3     3 94.24 14730 13882      0 1.063706
       4     4 97.42 12149 11836      0 1.063706
       5     5 94.75 14431 13674      1 1.049375
       6     6 95.91 11038 10587      1 1.049375
       7     7 95.66 14886 14240      1 1.049375
       8     8 94.94 12587 11950      1 1.049375
       9     9 94.27 13251 12492      2 1.057376
      10    10 94.89 12789 12135      2 1.057376
      

      【讨论】:

        【解决方案4】:

        修改了 Scarabee 的答案

        d %>% 
            mutate(g1 = (A - 1)%/%5, 
                   g2 = A%%5 == 0) %>% 
            group_by(g1) %>% 
            mutate(V = 100 * sum(D[!g2]/sum(C[!g2]))) %>% 
            ungroup() %>% 
            mutate(B = if_else(g2, round(V, 2), B)) %>% 
            select(-g1, -g2)
        
        #>        A     B     C     D
        #>    <int> <dbl> <int> <int>
        #>  1     1 92.44 14261 13183
        #>  2     2 92.43 14244 13166
        #>  3     3 94.24 14730 13882
        #>  4     4 97.42 12149 11836
        #>  5     5 94.01 14431 13674
        #>  6     6 95.91 11038 10587
        #>  7     7 95.66 14886 14240
        #>  8     8 94.94 12587 11950
        #>  9     9 94.27 13251 12492
        #> 10    10 95.18 12789 12135
        

        【讨论】:

          【解决方案5】:

          我知道你问过如何使用 dplyr 来执行此操作,但这里有另一个使用 data.table 的选项。

          dat[, grp := rep(1:(dim(dat)[1]/5), each = 5)]
          dat[, B := round(c(B[1:4], 100*sum(D[1:4])/sum(C[1:4])), 2), by = grp]
          dat[, .(A, B, C, D)]
          

          结果:

               A     B     C     D
           1:  1 92.44 14261 13183
           2:  2 92.43 14244 13166
           3:  3 94.24 14730 13882
           4:  4 97.42 12149 11836
           5:  5 94.01 14431 13674
           6:  6 95.91 11038 10587
           7:  7 95.66 14886 14240
           8:  8 94.94 12587 11950
           9:  9 94.27 13251 12492
          10: 10 95.18 12789 12135
          

          使用以下方法生成的数据:

          dat <- fread("A   B        C       D
          1   92.44   14261   13183
          2   92.43   14244   13166
          3   94.24   14730   13882
          4   97.42   12149   11836
          5   94.75   14431   13674
          6   95.91   11038   10587
          7   95.66   14886   14240
          8   94.94   12587   11950
          9   94.27   13251   12492
          10  94.89   12789   12135")
          

          【讨论】:

            猜你喜欢
            • 2015-02-05
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多