R以相似字符串开头的不同列组的行总和
R sum of rows for different group of columns that start with similar string
我是R的新手,第一次敢在这里提问。
我正在使用李克特量表的数据集,我想对共享名称中第一个字符串的不同列组进行行求和。
下面我构建了一个只有 2 行的数据框来说明我采用的方法,但我希望收到有关如何编写更有效的方法的反馈。
df <- as.data.frame(rbind(rep(sample(1:5),4),rep(sample(1:5),4)))
var.names <- c("emp_1","emp_2","emp_3","emp_4","sat_1","sat_2"
,"sat_3","res_1","res_2","res_3","res_4","com_1",
"com_2","com_3","com_4","com_5","cap_1","cap_2",
"cap_3","cap_4")
names(df) <- var.names
所以,我所做的是使用 grep 函数,以便能够对以特定字符串开头的指定变量的行求和,并将它们存储在新变量中。但是我必须为每个变量写一行新代码。
df$emp_t <- rowSums(df[, grep("\bemp.", names(df))])
df$sat_t <- rowSums(df[, grep("\bsat.", names(df))])
df$res_t <- rowSums(df[, grep("\bres.", names(df))])
df$com_t <- rowSums(df[, grep("\bcom.", names(df))])
df$cap_t <- rowSums(df[, grep("\bcap.", names(df))])
但是数据集中有更多的变量,我想知道是否有一种方法只用一行代码就可以做到这一点。例如,一些方法将以相同字符串开头的变量组合在一起,然后应用行函数。
提前致谢!
一种可能的解决方案是转置 df
并使用基本 R rowsum
函数(使用 set.seed(123)
)
计算正确列的总和
cbind(df, t(rowsum(t(df), sub("_.*", "_t", names(df)))))
# emp_1 emp_2 emp_3 emp_4 sat_1 sat_2 sat_3 res_1 res_2 res_3 res_4 com_1 com_2 com_3 com_4 com_5 cap_1 cap_2 cap_3 cap_4 cap_t
# 1 2 4 5 3 1 2 4 5 3 1 2 4 5 3 1 2 4 5 3 1 13
# 2 1 3 4 2 5 1 3 4 2 5 1 3 4 2 5 1 3 4 2 5 14
# com_t emp_t res_t sat_t
# 1 15 14 11 7
# 2 15 10 12 9
同意 MrFlick 的观点,您可能希望以长格式放置数据(参见 reshape2
、tidyr
),但要回答您的问题:
cbind(
df,
sapply(split.default(df, sub("_.*$", "_t", names(df))), rowSums)
)
会成功的
如果您将数据放入 tidy format 中,那么在长期 运行 中您会过得更好。问题是数据是宽格式而不是长格式。而变量名,例如 emp_1
,实际上是两个独立的数据:人的 class 和人的身份证号码(或类似的东西)。这是解决 dplyr 和 tidyr 问题的方法。
library(dplyr)
library(tidyr)
df %>%
gather(key, value) %>%
extract(key, c("class", "id"), "([[:alnum:]]+)_([[:alnum:]]+)") %>%
group_by(class) %>%
summarize(class_sum = sum(value))
首先我们使用 gather()
将数据帧从宽格式转换为长格式。然后我们将值 emp_1
拆分为单独的列 class
和 id
以及 extract()
。最后,我们按 class 分组并对每个 class 中的值求和。结果:
Source: local data frame [5 x 2]
class class_sum
1 cap 26
2 com 30
3 emp 23
4 res 22
5 sat 19
另一种可能的解决方案是使用 dplyr R rowwise 函数。 https://www.tidyverse.org/blog/2020/04/dplyr-1-0-0-rowwise/
df %>%
rowwise() %>%
mutate(emp_sum = sum(c_across(starts_with("emp"))),
sat_sum = sum(c_across(starts_with("sat"))),
res_sum = sum(c_across(starts_with("res"))),
com_sum = sum(c_across(starts_with("com"))),
cap_sum = sum(c_across(starts_with("cap"))))
我是R的新手,第一次敢在这里提问。
我正在使用李克特量表的数据集,我想对共享名称中第一个字符串的不同列组进行行求和。
下面我构建了一个只有 2 行的数据框来说明我采用的方法,但我希望收到有关如何编写更有效的方法的反馈。
df <- as.data.frame(rbind(rep(sample(1:5),4),rep(sample(1:5),4)))
var.names <- c("emp_1","emp_2","emp_3","emp_4","sat_1","sat_2"
,"sat_3","res_1","res_2","res_3","res_4","com_1",
"com_2","com_3","com_4","com_5","cap_1","cap_2",
"cap_3","cap_4")
names(df) <- var.names
所以,我所做的是使用 grep 函数,以便能够对以特定字符串开头的指定变量的行求和,并将它们存储在新变量中。但是我必须为每个变量写一行新代码。
df$emp_t <- rowSums(df[, grep("\bemp.", names(df))])
df$sat_t <- rowSums(df[, grep("\bsat.", names(df))])
df$res_t <- rowSums(df[, grep("\bres.", names(df))])
df$com_t <- rowSums(df[, grep("\bcom.", names(df))])
df$cap_t <- rowSums(df[, grep("\bcap.", names(df))])
但是数据集中有更多的变量,我想知道是否有一种方法只用一行代码就可以做到这一点。例如,一些方法将以相同字符串开头的变量组合在一起,然后应用行函数。
提前致谢!
一种可能的解决方案是转置 df
并使用基本 R rowsum
函数(使用 set.seed(123)
)
cbind(df, t(rowsum(t(df), sub("_.*", "_t", names(df)))))
# emp_1 emp_2 emp_3 emp_4 sat_1 sat_2 sat_3 res_1 res_2 res_3 res_4 com_1 com_2 com_3 com_4 com_5 cap_1 cap_2 cap_3 cap_4 cap_t
# 1 2 4 5 3 1 2 4 5 3 1 2 4 5 3 1 2 4 5 3 1 13
# 2 1 3 4 2 5 1 3 4 2 5 1 3 4 2 5 1 3 4 2 5 14
# com_t emp_t res_t sat_t
# 1 15 14 11 7
# 2 15 10 12 9
同意 MrFlick 的观点,您可能希望以长格式放置数据(参见 reshape2
、tidyr
),但要回答您的问题:
cbind(
df,
sapply(split.default(df, sub("_.*$", "_t", names(df))), rowSums)
)
会成功的
如果您将数据放入 tidy format 中,那么在长期 运行 中您会过得更好。问题是数据是宽格式而不是长格式。而变量名,例如 emp_1
,实际上是两个独立的数据:人的 class 和人的身份证号码(或类似的东西)。这是解决 dplyr 和 tidyr 问题的方法。
library(dplyr)
library(tidyr)
df %>%
gather(key, value) %>%
extract(key, c("class", "id"), "([[:alnum:]]+)_([[:alnum:]]+)") %>%
group_by(class) %>%
summarize(class_sum = sum(value))
首先我们使用 gather()
将数据帧从宽格式转换为长格式。然后我们将值 emp_1
拆分为单独的列 class
和 id
以及 extract()
。最后,我们按 class 分组并对每个 class 中的值求和。结果:
Source: local data frame [5 x 2]
class class_sum
1 cap 26
2 com 30
3 emp 23
4 res 22
5 sat 19
另一种可能的解决方案是使用 dplyr R rowwise 函数。 https://www.tidyverse.org/blog/2020/04/dplyr-1-0-0-rowwise/
df %>%
rowwise() %>%
mutate(emp_sum = sum(c_across(starts_with("emp"))),
sat_sum = sum(c_across(starts_with("sat"))),
res_sum = sum(c_across(starts_with("res"))),
com_sum = sum(c_across(starts_with("com"))),
cap_sum = sum(c_across(starts_with("cap"))))