对任意数量的列采用 R tibble 中列的滚动差异
Taking rolling differences of columns in R tibble for arbitrary number of columns
我想对每对连续的列求差,但对任意数量的列求差。例如...
df <- as.tibble(data.frame(group = rep(c("a", "b", "c"), each = 4),
subgroup = rep(c("adam", "boy", "charles", "david"), times = 3),
iter1 = 1:12,
iter2 = c(13:22, NA, 24),
iter3 = c(25:35, NA)))
我想按列计算差异。我通常会使用...
df %>%
mutate(diff_iter2 = iter2 - iter1,
diff_iter3 = iter3 - iter2)
但是...我想:
- 容纳任意数量的列并且
- 这样对待 NA:
如果我们减去的数字是 NA,那么结果应该是 NA。例如。 NA - 11 = NA
如果我们要减去的数字是 NA,那么 NA 将被有效地视为 0。例如35 - 不适用 = 35
结果应该是这样的...
group subgroup iter1 iter2 iter3 diff_iter2 diff_iter3
<chr> <chr> <int> <dbl> <int> <dbl> <dbl>
1 a adam 1 13 25 12 12
2 a boy 2 14 26 12 12
3 a charles 3 15 27 12 12
4 a david 4 16 28 12 12
5 b adam 5 17 29 12 12
6 b boy 6 18 30 12 12
7 b charles 7 19 31 12 12
8 b david 8 20 32 12 12
9 c adam 9 21 33 12 12
10 c boy 10 22 34 12 12
11 c charles 11 NA 35 NA 35
12 c david 12 24 NA 12 NA
最初,这个 df 是长格式的,但问题是我相信 lag() 函数在组内的位置上运行,并且所有组都不相同,因为有些组缺少记录(因此 NA 在更宽 table 如上所示)。
从长格式开始就可以了,但请假设上面显示的带有 NA 值的记录不会存在于那个较长的数据帧中。
感谢任何帮助。
tidyverse
中的一个选项是 - 循环 across
'iter' 的列而不是 iter1
,然后 get
通过替换列值列名 (cur_column()
) 子串通过用 str_replace
减去 1 (as.numeric(x) -1
),然后根据 OP 将 NA
元素替换为 0 (replace_na
)逻辑,从循环列中减去并通过在 .names
中添加前缀来创建新列("diff_{.col}"
- {.col}
将是原始列名称)
library(dplyr)
library(stringr)
library(tidyr)
df <- df %>%
mutate(across(iter2:iter3, ~
. - replace_na(get(str_replace(cur_column(), '\d+',
function(x) as.numeric(x) - 1)), 0), .names = 'diff_{.col}'))
-输出
df
# A tibble: 12 × 7
group subgroup iter1 iter2 iter3 diff_iter2 diff_iter3
<chr> <chr> <int> <dbl> <int> <dbl> <dbl>
1 a adam 1 13 25 12 12
2 a boy 2 14 26 12 12
3 a charles 3 15 27 12 12
4 a david 4 16 28 12 12
5 b adam 5 17 29 12 12
6 b boy 6 18 30 12 12
7 b charles 7 19 31 12 12
8 b david 8 20 32 12 12
9 c adam 9 21 33 12 12
10 c boy 10 22 34 12 12
11 c charles 11 NA 35 NA 35
12 c david 12 24 NA 12 NA
找到名称以iter、ix开头的列,然后将除第一个以外的所有列作为df1,除最后一个以外的所有列作为df2,并将df2中的NA替换为0。然后将它们相减并cbind df。没有使用包。
ix <- grep("^iter", names(df))
df1 <- df[tail(ix, -1)]
df2 <- df[head(ix, -1)]
df2[is.na(df2)] <- 0
cbind(df, diff = df1 - df2)
给予:
group subgroup iter1 iter2 iter3 diff.iter2 diff.iter3
1 a adam 1 13 25 12 12
2 a boy 2 14 26 12 12
3 a charles 3 15 27 12 12
4 a david 4 16 28 12 12
5 b adam 5 17 29 12 12
6 b boy 6 18 30 12 12
7 b charles 7 19 31 12 12
8 b david 8 20 32 12 12
9 c adam 9 21 33 12 12
10 c boy 10 22 34 12 12
11 c charles 11 NA 35 NA 35
12 c david 12 24 NA 12 NA
我想对每对连续的列求差,但对任意数量的列求差。例如...
df <- as.tibble(data.frame(group = rep(c("a", "b", "c"), each = 4),
subgroup = rep(c("adam", "boy", "charles", "david"), times = 3),
iter1 = 1:12,
iter2 = c(13:22, NA, 24),
iter3 = c(25:35, NA)))
我想按列计算差异。我通常会使用...
df %>%
mutate(diff_iter2 = iter2 - iter1,
diff_iter3 = iter3 - iter2)
但是...我想:
- 容纳任意数量的列并且
- 这样对待 NA:
如果我们减去的数字是 NA,那么结果应该是 NA。例如。 NA - 11 = NA
如果我们要减去的数字是 NA,那么 NA 将被有效地视为 0。例如35 - 不适用 = 35
结果应该是这样的...
group subgroup iter1 iter2 iter3 diff_iter2 diff_iter3
<chr> <chr> <int> <dbl> <int> <dbl> <dbl>
1 a adam 1 13 25 12 12
2 a boy 2 14 26 12 12
3 a charles 3 15 27 12 12
4 a david 4 16 28 12 12
5 b adam 5 17 29 12 12
6 b boy 6 18 30 12 12
7 b charles 7 19 31 12 12
8 b david 8 20 32 12 12
9 c adam 9 21 33 12 12
10 c boy 10 22 34 12 12
11 c charles 11 NA 35 NA 35
12 c david 12 24 NA 12 NA
最初,这个 df 是长格式的,但问题是我相信 lag() 函数在组内的位置上运行,并且所有组都不相同,因为有些组缺少记录(因此 NA 在更宽 table 如上所示)。
从长格式开始就可以了,但请假设上面显示的带有 NA 值的记录不会存在于那个较长的数据帧中。
感谢任何帮助。
tidyverse
中的一个选项是 - 循环 across
'iter' 的列而不是 iter1
,然后 get
通过替换列值列名 (cur_column()
) 子串通过用 str_replace
减去 1 (as.numeric(x) -1
),然后根据 OP 将 NA
元素替换为 0 (replace_na
)逻辑,从循环列中减去并通过在 .names
中添加前缀来创建新列("diff_{.col}"
- {.col}
将是原始列名称)
library(dplyr)
library(stringr)
library(tidyr)
df <- df %>%
mutate(across(iter2:iter3, ~
. - replace_na(get(str_replace(cur_column(), '\d+',
function(x) as.numeric(x) - 1)), 0), .names = 'diff_{.col}'))
-输出
df
# A tibble: 12 × 7
group subgroup iter1 iter2 iter3 diff_iter2 diff_iter3
<chr> <chr> <int> <dbl> <int> <dbl> <dbl>
1 a adam 1 13 25 12 12
2 a boy 2 14 26 12 12
3 a charles 3 15 27 12 12
4 a david 4 16 28 12 12
5 b adam 5 17 29 12 12
6 b boy 6 18 30 12 12
7 b charles 7 19 31 12 12
8 b david 8 20 32 12 12
9 c adam 9 21 33 12 12
10 c boy 10 22 34 12 12
11 c charles 11 NA 35 NA 35
12 c david 12 24 NA 12 NA
找到名称以iter、ix开头的列,然后将除第一个以外的所有列作为df1,除最后一个以外的所有列作为df2,并将df2中的NA替换为0。然后将它们相减并cbind df。没有使用包。
ix <- grep("^iter", names(df))
df1 <- df[tail(ix, -1)]
df2 <- df[head(ix, -1)]
df2[is.na(df2)] <- 0
cbind(df, diff = df1 - df2)
给予:
group subgroup iter1 iter2 iter3 diff.iter2 diff.iter3
1 a adam 1 13 25 12 12
2 a boy 2 14 26 12 12
3 a charles 3 15 27 12 12
4 a david 4 16 28 12 12
5 b adam 5 17 29 12 12
6 b boy 6 18 30 12 12
7 b charles 7 19 31 12 12
8 b david 8 20 32 12 12
9 c adam 9 21 33 12 12
10 c boy 10 22 34 12 12
11 c charles 11 NA 35 NA 35
12 c david 12 24 NA 12 NA