Я пытаюсь сдвинуть вниз (запаздывать) определенные столбцы в фрейме данных на n строк (например, на 2 строки). Я нашел только сообщения об отставании от определенных столбцов на 1 строку. Вот некоторые ложные данные.
df <- data.frame(
A = seq(1,7),
B = seq(8,14),
C = seq(15,21),
D = seq(22,28)
)
df
> df
A B C D
1 8 15 22
2 9 16 23
3 10 17 24
4 11 18 25
5 12 19 26
6 13 20 27
7 14 21 28
Здесь я хотел бы сдвинуть вниз значения в столбцах A, C и D на n строк и добавить новые строки в мой фрейм данных, чтобы создать другой фрейм данных. Пример желаемого результата с задержкой в две строки будет выглядеть так.
> df.lag.example
A B C D
NA 8 NA NA
NA 9 NA NA
1 10 15 22
2 11 16 23
3 12 17 24
4 13 18 25
5 14 19 26
6 NA 20 27
7 NA 21 28
Вот что-то быстрое и грязное:
foo <- function(df, n, lag_cols) {
result <- df[c(rep(NA, n), 1L:(nrow(df))), ]
non_lag_cols <- setdiff(names(df), lag_cols)
result[non_lag_cols] <- lapply(
result[(n+1):(nrow(result)), non_lag_cols, drop=FALSE],
\(x) c(x, rep(NA, n))
)
return(result)
}
foo(df, 2, c("A", "C", "D"))
# A B C D
# NA NA 8 NA NA
# NA.1 NA 9 NA NA
# 1 1 10 15 22
# 2 2 11 16 23
# 3 3 12 17 24
# 4 4 13 18 25
# 5 5 14 19 26
# 6 6 NA 20 27
# 7 7 NA 21 28
library(dplyr)
rbind(df, df[0,][rep(NA, 2),]) %>%
mutate(across(-2, ~lag(., 2))) %>%
`rownames<-`(NULL)
#> A B C D
#> 1 NA 8 NA NA
#> 2 NA 9 NA NA
#> 3 1 10 15 22
#> 4 2 11 16 23
#> 5 3 12 17 24
#> 6 4 13 18 25
#> 7 5 14 19 26
#> 8 6 NA 20 27
#> 9 7 NA 21 28
Created on 2024-04-18 with reprex v2.0.2
Вот небольшая функция (которая на самом деле просто обобщает решение, данное @M--), где вы можете использовать tidy-selection для выбора столбцов. Также можно указать направление (dir
) «вниз» или «вверх» и количество (n
) смен:
library(dplyr)
shift <- function(data, cols, dir = "down", ...) {
dir <- match.arg(dir, c("down", "up"))
f <- if (dir == "down") list(lag, lead) else list(lead, lag)
bind_cols(transmute(data, across({{cols}}, ~ f[[1]](.x, ...))),
transmute(data, across(!{{cols}}, ~ f[[2]](.x, ...)))) |>
select(all_of(names(data)))
}
n
передается lag()
/lead()
через ...
.
Применение
shift(df, c(A, C, D), n = 2) # default shift "down"
# A B C D
# 1 NA 8 NA NA
# 2 NA 9 NA NA
# 3 1 10 15 22
# 4 2 11 16 23
# 5 3 12 17 24
# 6 4 13 18 25
# 7 5 14 19 26
# 8 6 NA 20 27
# 9 7 NA 21 28
# Same as above, but shows some tidy selection
shift(df, -B, n = 2)
shift(df, c(A, C:D), n = 2)
shift(df, matches("^(A|C|D)"), n = 2)
Примечание. transmute()
заменен на mutate(..., .keep = "none")
и его можно легко заменить.