如何将前导行中的每一行减去 R 中的每五行?

How to subtract every previous rows from the lead row to every five rows in R?

我有一个更大的数据框,它有多个列和数千行。我想通过从数据框的每五行的前导行中减去前一行值来替换每个前导行的值。例如,第一个值应保留其值,第二行应为:second row - first row。同样,第六行应保留其值,但是,第七行将是 seventh row - sixth row。这是一个示例数据框

DF = data.frame(A= c(1:11), B = c(11:21))

输出应该如下所示

> Output
    A  B
1   1 11
2   1  1
3   1  1
4   1  1
5   1  1
6   6 16
7   1  1
8   1  1
9   1  1
10  1  1
11 11 21

一个选项是创建一个分组变量,然后使用 diff 进行转换,这会计算 mutate_all 中所选列的相邻元素的差异(如果只有列的子集是需要使用 mutate_ifmutate_at)

library(dplyr) #v_0.8.3
DF %>% 
   group_by(grp = as.integer(gl(n(), 5, n()))) %>% 
   mutate_all(~c(first(.), diff(.))) %>%
   ungroup %>%
   select(-grp)
# A tibble: 11 x 2
#       A     B
#   <int> <int>
# 1     1    11
# 2     1     1
# 3     1     1
# 4     1     1
# 5     1     1
# 6     6    16
# 7     1     1
# 8     1     1
# 9     1     1
#10     1     1
#11    11    21

当我们在 group_by 之后使用 mutate_all 时,上面也会给出警告(以前它曾经有效 - 在新版本中,正确的语法是使用 mutate_at

DF %>% 
   group_by(grp = as.integer(gl(n(), 5, n()))) %>% 
   mutate_at(vars(-group_cols()), ~c(first(.), diff(.))) %>%
   ungroup %>%
   select(-grp)
f = function(d, n = 5) ave(d, ceiling(seq_along(d)/n), FUN = function(x) c(x[1], diff(x)))
data.frame(lapply(DF, f))
#    A  B
#1   1 11
#2   1  1
#3   1  1
#4   1  1
#5   1  1
#6   6 16
#7   1  1
#8   1  1
#9   1  1
#10  1  1
#11 11 21

另一种选择是创建另一个 data.frame 移动行并直接减去

ind = ave(1:nrow(DF), ceiling(1:nrow(DF)/5), FUN = function(x) c(x[1], x[-length(x)]))
DF2 = DF[ind,] * replace(rep(1, nrow(DF)), diff(ind) == 0, 0)
DF - DF2

可以%/%行号减1乘5得到分组,然后用diff得到与前面x的差值(如果没有则为0 previous x) from x for all columns for every group x for each group.

library(data.table)
setDT(DF)

DF[, lapply(.SD, function(x) diff(c(0, x)))
   , (1:nrow(DF) - 1) %/% 5][, -1]

#      A  B
#  1:  1 11
#  2:  1  1
#  3:  1  1
#  4:  1  1
#  5:  1  1
#  6:  6 16
#  7:  1  1
#  8:  1  1
#  9:  1  1
# 10:  1  1
# 11: 11 21

或者,如@akrun 所述,您可以通过替换

来避免 lapply
lapply(.SD, function(x) diff(c(0, x)))

.SD - shift(.SD, fill = 0)

另一个不太严重的选项:

x <- DF[, !(.I - 1) %% 5]
DF*(1 + x) - DF[DF[, .I - !x]]

#      A  B
#  1:  1 11
#  2:  1  1
#  3:  1  1
#  4:  1  1
#  5:  1  1
#  6:  6 16
#  7:  1  1
#  8:  1  1
#  9:  1  1
# 10:  1  1
# 11: 11 21