После группировки по 'id', используйте mutate_at
, чтобы сделать разницу между значениями и где 'year' равен 1 в столбцах 'value', а затем filter
из строк, имеющих 'year' как 1
library(dplyr)
df1 %>%
group_by(id) %>%
mutate_at(vars(value1:value2), funs(. -.[year == 1])) %>%
filter(year!= 1)
# A tibble: 10 x 4
# Groups: id [5]
# id value1 value2 year
# <int> <int> <int> <int>
# 1 1 9 -3 2
# 2 1 1 0 3
# 3 1 2 -1 4
# 4 2 -2 2 2
# 5 2 -3 2 3
# 6 2 6 0 4
# 7 3 -1 0 2
# 8 3 3 0 3
# 9 4 5 0 2
#10 5 2 1 2
Или аналогичная логика с data.table
library(data.table)
setDT(df1)[, (2:3) := lapply(.SD, function(x) x - x[year == 1]),
by = id, .SDcols = value1:value2][year != 1]
В base R
мы можем сделать
nm1 <- c('value1', 'value2')
df1[nm1] <- df1[nm1] -df1[df1$year==1,
nm1][rep(seq_along(unique(df1$id)), table(df1$id)),]
df1[df1$year != 1,]
data
df1 <- structure(list(id = c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 3L, 3L,
3L, 4L, 4L, 5L, 5L), value1 = c(1L, 10L, 2L, 3L, 4L, 2L, 1L,
10L, 4L, 3L, 7L, 4L, 9L, 5L, 7L), value2 = c(4L, 1L, 4L, 3L,
1L, 3L, 3L, 1L, 5L, 5L, 5L, 2L, 2L, 3L, 4L), year = c(1L, 2L,
3L, 4L, 1L, 2L, 3L, 4L, 1L, 2L, 3L, 1L, 2L, 1L, 2L)), class =
"data.frame", row.names = c(NA, -15L))