【问题标题】:R sum of rows for different group of columns that start with similar stringR以相似字符串开头的不同列组的行总和
【发布时间】:2015-05-21 20:59:31
【问题描述】:

我对 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))])

但是数据集中还有很多变量,我想知道是否有一种方法可以只用一行代码来做到这一点。例如,以某种方式将以相同字符串开头的变量分组在一起,然后应用行函数。

提前致谢!

【问题讨论】:

  • 好吧,如果这是您需要经常执行的操作,那么听起来您的数据格式不正确。使用“长”格式而不是您当前拥有的“宽”格式的数据会更容易。如果您想这样做,还有很多其他关于重塑的问题。

标签: r rowsum


【解决方案1】:

一种可能的解决方案是转置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

【讨论】:

  • 哦哦,如此接近...我想我更喜欢你的 (+1)
  • @BrodieG 不知道,我在这里使用了两次t,所以不确定它会如何扩展。 (+1)也给你:)。用_t 代替"" 顺便说一句,这是个好主意。
  • 感谢大家的回复。直到现在我还不知道什么是正则表达式,但由于我不明白为什么“_.*$”部分起作用,我不得不做一些阅读,发现这里不需要 $,cbind(df, t(rowsum(t(df), sub("_.*", "_t", names(df))))) 工作得很好.
【解决方案2】:

同意 MrFlick 的观点,您可能希望以长格式放置数据(请参阅reshape2tidyr),但要回答您的问题:

cbind(
  df, 
  sapply(split.default(df, sub("_.*$", "_t", names(df))), rowSums)
)

会成功的

【讨论】:

    【解决方案3】:

    如果您将数据放入tidy format,从长远来看,您的情况会更好。问题是数据是宽格式而不是长格式。而变量名称,例如emp_1,实际上是两个独立的数据:人的类别和人的 ID 号(或类似的东西)。这是解决您的 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 拆分为单独的列classidextract()。最后,我们按类分组并对每个类中的值求和。结果:

    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
    

    【讨论】:

    • 您应该在这里为每个类获取两个值。另外,它是如何连接回原始数据的?
    • 我看到原始问题如何得到两个答案(即)每行一个。但似乎重点是总结它们?如果不是,那么这里有一个隐藏变量。在原始 df 中,需要有另一列指定标识每一行的内容。该列将包含在对group_by() 的调用中。合并回原始数据更容易。可以使用mutate() 代替summarize 来添加包含该数据的新列。或者可以left_join()这个新的数据框回到整理好的数据框。
    【解决方案4】:

    另一个可能的解决方案是使用 dplyr R 行函数。 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"))))
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-18
      • 2023-01-29
      • 1970-01-01
      • 1970-01-01
      • 2021-05-08
      • 2021-02-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多