Как вычесть все предыдущие строки из ведущей строки в каждые пять строк в R? - PullRequest
1 голос
/ 11 октября 2019

У меня есть большой фрейм данных, который имеет несколько столбцов и тысячи строк. Я хочу заменить значение каждой ведущей строки, вычитая предыдущее значение строки из ведущей строки для каждых пяти строк кадра данных. Например, первое значение должно сохранить свое значение, вторая строка должна быть: 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

Ответы [ 3 ]

3 голосов
/ 11 октября 2019
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
2 голосов
/ 11 октября 2019

Вы можете %/% номер строки минус 1 на 5, чтобы получить группы, затем используйте diff, чтобы получить разницу от предыдущего x (или 0, если нет предыдущего x) от x для всех столбцов x для каждой группы.

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
2 голосов
/ 11 октября 2019

Один из вариантов - создать группирующую переменную, а затем выполнить преобразование с помощью diff, которое определяет разницу соседних элементов столбцов, выбранных в mutate_all (если требуется только подмножество столбцов, используйте mutate_ifили mutate_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

Выше также выдается предупреждение, когда мы используем mutate_all после group_by (ранее это работало - в новых версиях правильный синтаксис будет использовать mutate_at

DF %>% 
   group_by(grp = as.integer(gl(n(), 5, n()))) %>% 
   mutate_at(vars(-group_cols()), ~c(first(.), diff(.))) %>%
   ungroup %>%
   select(-grp)
...