使用dplyr计算自定义函数第n行

时间:2017-06-27 15:47:46

标签: r dataframe statistics mutate

给出以下数据框:

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计算,该计算允许我在列C和D中summarize()第一行 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行

5 个答案:

答案 0 :(得分:4)

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

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

答案 1 :(得分:4)

以下是使用dplyr roll_sumrRcppRoll的方法。您可以每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)

答案 2 :(得分: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

答案 3 :(得分:1)

修改了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

答案 4 :(得分:1)

我知道您使用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")