在条件来自另一列的数据框中求和
Summing across in a dataframe with condition coming from another column
这不是一个很好的问题标题。我想对每个组的数据框中的某些列求和,不包括我的每个组的一列。一个简单的例子如下:
df <- tibble(group_name = c("A", "B","C"), mean_A = c(1,2,3), mean_B = c(2,3,4), mean_C=c(3,4,5))
df %>% group_by(group_name) %>% mutate(m1 = sum(across(contains("mean"))))
这将创建列 m1,它是每个组的 mean_a、mean_b、mean_c 的总和。我想要做的是排除 a 组的 mean_a,b 组的 mean_b 和 c 组的 mean_c。但以下内容不起作用(不足为奇)。
df %>% group_by(group_name) %>% mutate(m1 = sum(across(c(contains("mean") & !contains(group_name)))))
你知道我该怎么做吗?我的原始数据包含更多组,因此很难手工完成。
编辑:我已经尝试了以下以基本方式解决它的方法,但是有些东西(可能是?grepl)在这里似乎效果不佳,我得到了错误的结果。
df %>% pivot_longer(!group_name) %>% mutate(value2 = case_when(grepl(group_name, name) ~ 0, TRUE ~ value)) %>% group_by(group_name) %>% summarise(m1 = sum(value2))
Edit2:发现上面有什么问题,下面是有效的,但仍然有很多警告,所以我建议人们遵循下面 TarJae 的回复
df %>% pivot_longer(!group_name) %>% group_by(group_name) %>% mutate(value2 = case_when(grepl(group_name, name) ~ 0, TRUE ~ value)) %>% group_by(group_name) %>% summarise(m1 = sum(value2))
这是我们可以做到的一种方法:
- 我们创建一个辅助列来匹配列名
- 如果列名称与助手名称匹配,我们将平均列的值设置为 zeor。
- 然后我们用
transmute
和select
计算rowSums
- 最后我们
cbind
列 m1
到 df
:
library(dplyr)
df %>%
mutate(helper = paste0("mean_", group_name)) %>%
mutate(across(starts_with("mean"), ~ifelse(cur_column()==helper, 0, .))) %>%
transmute(m1 = select(., contains("mean")) %>%
rowSums()) %>%
cbind(df)
m1 group_name mean_a mean_b mean_c
1 5 a 1 2 3
2 6 b 2 3 4
3 7 c 3 4 5
这是另一个选项,您可以直接将 group_name
与 tidyselect 助手一起使用:
df %>%
rowwise() %>%
mutate(m1 = rowSums(select(across(starts_with("mean")), -ends_with(group_name)))) %>%
ungroup()
输出
group_name mean_A mean_B mean_C m1
<chr> <dbl> <dbl> <dbl> <dbl>
1 A 1 2 3 5
2 B 2 3 4 6
3 C 3 4 5 7
工作原理
across
的 row-wise 输出是 1 行小标题,仅包含以 "mean"
. 开头的变量
select
从 across
的输出中取消选择以 group_name
. 的值结尾的变量子集
- 此时您剩下一个 1 x 2 的小标题,然后使用
rowSums
. 求和
这不是一个很好的问题标题。我想对每个组的数据框中的某些列求和,不包括我的每个组的一列。一个简单的例子如下:
df <- tibble(group_name = c("A", "B","C"), mean_A = c(1,2,3), mean_B = c(2,3,4), mean_C=c(3,4,5))
df %>% group_by(group_name) %>% mutate(m1 = sum(across(contains("mean"))))
这将创建列 m1,它是每个组的 mean_a、mean_b、mean_c 的总和。我想要做的是排除 a 组的 mean_a,b 组的 mean_b 和 c 组的 mean_c。但以下内容不起作用(不足为奇)。
df %>% group_by(group_name) %>% mutate(m1 = sum(across(c(contains("mean") & !contains(group_name)))))
你知道我该怎么做吗?我的原始数据包含更多组,因此很难手工完成。
编辑:我已经尝试了以下以基本方式解决它的方法,但是有些东西(可能是?grepl)在这里似乎效果不佳,我得到了错误的结果。
df %>% pivot_longer(!group_name) %>% mutate(value2 = case_when(grepl(group_name, name) ~ 0, TRUE ~ value)) %>% group_by(group_name) %>% summarise(m1 = sum(value2))
Edit2:发现上面有什么问题,下面是有效的,但仍然有很多警告,所以我建议人们遵循下面 TarJae 的回复
df %>% pivot_longer(!group_name) %>% group_by(group_name) %>% mutate(value2 = case_when(grepl(group_name, name) ~ 0, TRUE ~ value)) %>% group_by(group_name) %>% summarise(m1 = sum(value2))
这是我们可以做到的一种方法:
- 我们创建一个辅助列来匹配列名
- 如果列名称与助手名称匹配,我们将平均列的值设置为 zeor。
- 然后我们用
transmute
和select
计算rowSums
- 最后我们
cbind
列m1
到df
:
library(dplyr)
df %>%
mutate(helper = paste0("mean_", group_name)) %>%
mutate(across(starts_with("mean"), ~ifelse(cur_column()==helper, 0, .))) %>%
transmute(m1 = select(., contains("mean")) %>%
rowSums()) %>%
cbind(df)
m1 group_name mean_a mean_b mean_c
1 5 a 1 2 3
2 6 b 2 3 4
3 7 c 3 4 5
这是另一个选项,您可以直接将 group_name
与 tidyselect 助手一起使用:
df %>%
rowwise() %>%
mutate(m1 = rowSums(select(across(starts_with("mean")), -ends_with(group_name)))) %>%
ungroup()
输出
group_name mean_A mean_B mean_C m1
<chr> <dbl> <dbl> <dbl> <dbl>
1 A 1 2 3 5
2 B 2 3 4 6
3 C 3 4 5 7
工作原理
across
的 row-wise 输出是 1 行小标题,仅包含以"mean"
. 开头的变量
select
从across
的输出中取消选择以group_name
. 的值结尾的变量子集
- 此时您剩下一个 1 x 2 的小标题,然后使用
rowSums
. 求和