如何逐行求和?
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.table
或dplyr
“按组”处理它。
使用这些数据:
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 <- paste0("Sum_R", grep(row1, df$MUN, fixed=T),"_R" ,grep(row2, df$MUN, fixed=T))
。我还需要 NA 值,因为它们与 0 不同,当我运行没有 data[ is.na(data)] <- 0
部分的代码时,输出会出现错误。
我现在更新了我的答案,以满足您的所有需求(包括一些解释。我不知道您之前为什么会出错,在我的机器上代码没有产生错误。由于错误导致行现在消失了,这已经解决了。请注意,我同意@Gregor 强调的数据格式问题。我只是保留了data.frame
格式来演示它是如何工作的(或者它可能有多复杂)。还要注意@ @user 的 987654328@package highlightet 可能值得一看以编写优雅的代码。以上是关于如何逐行求和?的主要内容,如果未能解决你的问题,请参考以下文章