如何逐行求和?

Posted

技术标签:

【中文标题】如何逐行求和?【英文标题】:How to sum rows by rows? 【发布时间】:2017-10-23 18:10:13 【问题描述】:

我现在是 R 的新手...所以我将人口普查研究作为大学项目进行。 用于说明这是我的 data.frame 的一部分

             MUN          X1990  X1991  X1992 X1993
1     Angra dos Reis (RJ)    11    10    10    10
2            Aperibé (RJ)    NA    NA    NA    NA
3           Araruama (RJ)  12040 14589 14231 14231
4              Areal (RJ)    NA    NA    NA     3
5 Armação dos Búzios (RJ)    NA    NA    NA    NA

我的问题是我需要总结一些我知道/将指定名称的城市行(因为我不知道它会出现的顺序,或者它们是否会出现在我的所有表格中),以及结果应该连续显示。

例如, 我想将“Areal”行与“Angra dos Reis”行相加,结果存储在另一个创建的行中(我们称结果行:X) 所以结果应该是:

             MUN          X1990  X1991  X1992 X1993
1     Angra dos Reis (RJ)    11    10    10    10
2            Aperibé (RJ)    NA    NA    NA    NA
3           Araruama (RJ)  12040 14589 14231 14231
4              Areal (RJ)    NA    NA    NA     3
5 Armação dos Búzios (RJ)    NA    NA    NA    NA
6          X                 11    10    10    13

我试图创建一个 for 循环和一个 if 循环,但我做不到。

【问题讨论】:

rbind(mydf, data.frame(MUN = 'X', as.data.frame.list(colSums(mydf[c(1,4), -1], na.rm = TRUE)))) 谢谢兄弟,它似乎工作。但你能解释一下代码吗?尤其是as.data.frame.list(colSums(mydf[c(1,4), -1] colSums 的那部分?为什么 c(1,4), -1? -1,这是为什么呢? 看看它做了什么,从里到外剖析:先看看mydf[c(1,4), -1]做了什么,然后用colSums包裹起来,等等 哦,我明白了,谢谢。但问题是我不知道我想总结的城市会出现在哪一行,或者他们是否会出现,所以如果我不计算第一列mydf[c(1,4), -1],我就不能直呼他们的名字。如果我把-1 拿出来,我会得到一个错误:**x 必须是数字**。我试图改变as.data.frame.numeric,但它不起作用 【参考方案1】:

这与 Jaap 的评论非常相似,但更详细地说明并明确使用行名:

mat = as.matrix(dat[, 2:5])
row.names(mat) = dat$MUN
mat = rbind(mat, colSums(mat[c("Angra dos Reis (RJ)", "Areal (RJ)"), ], na.rm = T))
row.names(mat)[nrow(mat)] = "X"
mat
#                         X1990 X1991 X1992 X1993
# Angra dos Reis (RJ)        11    10    10    10
# Aperibé (RJ)               NA    NA    NA    NA
# Araruama (RJ)           12040 14589 14231 14231
# Areal (RJ)                 NA    NA    NA     3
# Armação dos Búzios (RJ)    NA    NA    NA    NA
# X                          11    10    10    13

结果是matrix,如果需要,您可以将其转换回数据框:

dat_result = data.frame(MUN = row.names(mat), mat, row.names = NULL)

我不喜欢您的数据格式作为数据框。我要么将其转换为矩阵(如上所述),要么将其转换为长格式,例如tidyr::gather(dat, key = year, value = value, -MUN),然后使用data.tabledplyr“按组”处理它。


使用这些数据:

dat = read.table(text = "             MUN          X1990  X1991  X1992 X1993
1     'Angra dos Reis (RJ)'    11    10    10    10
2            'Aperibé (RJ)'    NA    NA    NA    NA
3           'Araruama (RJ)'  12040 14589 14231 14231
4              'Areal (RJ)'    NA    NA    NA     3
5 'Armação dos Búzios (RJ)'    NA    NA    NA    NA", header= T)

【讨论】:

我不太了解矩阵,但如果我使用矩阵,我将无法使用字符和数字,对吗?据我所知,这就是矩阵和数据框之间的区别。无论如何,我看到你在那里做了什么,为数据框中的行名创建了一个变量。如果您从第二个 collummat = as.matrix(dat[, 2:5]) 开始计数,我只是不明白我们如何能够按名称调用行。另外,如果你能为我解释一下最后一行row.names(mat)[nrow(mat)] = "X" 您对矩阵的定义是正确的——只有一种数据类型。但除非您有更多列,否则您使用MUN 的方式感觉更像是行名而不是​​列名。由于使用row.names(mat) = dat$MUN 设置名称,我能够按名称调用行。 最后一位 row.names(mat)[nrow(mat)] = "X" 只是将最后一行的名称设置为“X”。 nrow(mat) 是行数——也就是最后一行的数。【参考方案2】:

解决方案可以使用 sqldf 包。如果数据框的名称是df,你可以这样做:

library(sqldf)
result <- sqldf("SELECT * FROM df UNION 
       SELECT 'X', SUM(X1990), SUM(X1991), SUM(X1992), SUM(X1993) FROM df
       WHERE MUN IN ('Angra dos Reis (RJ)', 'Areal (RJ)')")

【讨论】:

【参考方案3】:

这是dplyr 解决方案:

library(dplyr)
df %>%
  filter(MUN %in% c("Angra dos Reis (RJ)", "Areal (RJ)")) %>%
  summarize_if(is.numeric, sum, na.rm = TRUE) %>%
  as.list(.) %>%
  c(MUN = "X") %>%
  bind_rows(df, .)

结果:

                      MUN X1990 X1991 X1992 X1993
1     Angra dos Reis (RJ)    11    10    10    10
2            Aperibé (RJ)    NA    NA    NA    NA
3           Araruama (RJ) 12040 14589 14231 14231
4              Areal (RJ)    NA    NA    NA     3
5 Armação dos Búzios (RJ)    NA    NA    NA    NA
6                       X    11    10    10    13

数据(来自@Gregor 和stringsAsFactors = FALSE):

df = read.table(text = "             MUN          X1990  X1991  X1992 X1993
                 1     'Angra dos Reis (RJ)'    11    10    10    10
                 2            'Aperibé (RJ)'    NA    NA    NA    NA
                 3           'Araruama (RJ)'  12040 14589 14231 14231
                 4              'Areal (RJ)'    NA    NA    NA     3
                 5 'Armação dos Búzios (RJ)'    NA    NA    NA    NA", header= T, stringsAsFactors = FALSE)

【讨论】:

【参考方案4】:

我假设您希望将您知道/指定名称的两个市政当局的数据相加,然后将它们的总和添加到表的末尾。我不确定这种理解是否正确。如果以下代码不是您需要的,您可能需要再次指定您的问题(例如,关于您是否需要每次汇总多个城市或一次仅计算两个城市等)

另外,如果你需要多次调用我提出的函数或者你的表真的很大,它需要在速度方面进行改进,例如,使用包data.table而不是base R(既然你说你是初学者,我坚持使用base R)。

为了满足您尽可能保留 NA 值的要求,我使用了Joshua Ulrich 提出的代码作为对这个问题rowSums but keeping NA values 的回答。

data <- data.frame(MUN = c("Angra dos Reis (RJ)", "Aperibé (RJ)", "Araruama (RJ)", "Areal (RJ)", "Armação dos Búzios (RJ)")
               ,X1990 = c(11, NA, 12040, NA, NA)
               ,X1991 = c(10, NA, 14589, NA, NA)
               ,X1992 = c(10, NA, 14231, NA, NA)
               ,X1993 = c(10, NA, 12231, 3, NA)
)

sum_rows <- function(df, row1, row2) 

  #get the indices of the two rows to be summed
  #grep returns the position in a vector at which a certain element is stored
  #here the name of the municipality 
  index_row1 <-  grep(row1, df$MUN, fixed=T)
  index_row2 <-  grep(row2, df$MUN, fixed=T)

  #select the two rows of the data.frame that you want to sum
  #on basis of the entry in the MUN column
  #further only select the column with numbers for the sum operation
  #check if all entries in a single column are NA values
  #if yes then the ouput for this column is NA
  #if no calculate the column sum, if one entry is NA, ignore it
  sum <- ifelse(apply(is.na(df[c(index_row1, index_row2),2:ncol(df)]),2,all)
                      ,NA
                      ,colSums(df[c(index_row1, index_row2),2:ncol(df)],na.rm=TRUE)
               )

  #create a name entry for the new MUN column
  #paste0 is used to combine strings
  #in this case it might make sense to create a name 
  #that includes the indices of the rows that have been summed instad of only using X as name
  name <- paste0("Sum_R",index_row1,"_R" , index_row2)

  #add the row to the original data.frame
  df <-  cbind(MUN = c(as.character(df$MUN), name)
               ,rbind(df[, 2:ncol(df)], sum)
              )

  #return the data.frame from the function
  df

 

#sum two rows and replace your data.frame by the new result
data <- sum_rows(data, "Angra dos Reis (RJ)", "Areal (RJ)")

data <- sum_rows(data, "Armação dos Búzios (RJ)", "Areal (RJ)")

【讨论】:

感谢您的回答。你理解我的问题是对的,很好的代码,我理解了它的大部分。我只是不明白行名是如何解决的name &lt;- paste0("Sum_R", grep(row1, df$MUN, fixed=T),"_R" ,grep(row2, df$MUN, fixed=T))。我还需要 NA 值,因为它们与 0 不同,当我运行没有 data[ is.na(data)] &lt;- 0 部分的代码时,输​​出会出现错误。 我现在更新了我的答案,以满足您的所有需求(包括一些解释。我不知道您之前为什么会出错,在我的机器上代码没有产生错误。由于错误导致行现在消失了,这已经解决了。请注意,我同意@Gregor 强调的数据格式问题。我只是保留了data.frame 格式来演示它是如何工作的(或者它可能有多复杂)。还要注意@ @user 的 987654328@package highlightet 可能值得一看以编写优雅的代码。

以上是关于如何逐行求和?的主要内容,如果未能解决你的问题,请参考以下文章

如何逐行读取标准输入?

如何逐行读取大文件?

如何逐行读取txt文件

如何禁用 .onDelete- 或如何在列表中逐行使用 .deleteDisabled?

如何查看我的程序是如何逐行执行的[重复]

如何逐行执行bash脚本? [复制]