R 将行添加到数据框中,每列的总和为
我有一个数据框,我想在其中添加一个额外的行,该行汇总每个列的值。例如,假设我有以下数据:R 将行添加到数据框中,每列的总和为,r,dataframe,R,Dataframe,我有一个数据框,我想在其中添加一个额外的行,该行汇总每个列的值。例如,假设我有以下数据: x <- data.frame(Language=c("C++", "Java", "Python"), Files=c(4009, 210, 35), LOC=c(15328,876, 200), stringsAsFactors=FALSE) 我的本能是这样做: y <- rbin
x <- data.frame(Language=c("C++", "Java", "Python"),
Files=c(4009, 210, 35),
LOC=c(15328,876, 200),
stringsAsFactors=FALSE)
我的本能是这样做:
y <- rbind(x, c("Total", colSums(x[,2:3])))
问题是文件和LOC列都已转换为字符串:
> y$LOC
[1] "15328" "876" "200" "16404"
我知道这是因为我创建了一个向量c(“Total”,colSums(x[,2:3])
,输入是数字和字符串,它将所有元素转换为一个公共类型,这样所有向量元素都是相同的。然后,相同的事情发生在文件和LOC列上
有什么更好的方法可以做到这一点?您的数据中是否需要Language列,或者将该列视为将data.frame从3个变量的4个观察值更改为2个变量的4个观察值(Files&LOC)的
行名称更合适
x这里有一种方法可以满足您的需求,但很可能有一种更优雅的解决方案
rbind(x, data.frame(Language = "Total", t(colSums(x[, -1]))))
为了记录在案,如果你不绝对需要语言列,我更喜欢蔡斯的答案。如果(1)我们不需要第一列的“语言”
标题,那么我们可以使用行名来表示它,如果(2)可以将最后一行标记为“Sum”
,而不是“Total”
然后我们可以像这样使用addmargins
:
Language Files LOC
1 C++ 4009 15328
2 Java 210 876
3 Python 35 200
rownames(x) <- x$Language
addmargins(as.table(as.matrix(x[-1])), 1)
如果我们确实希望第一列标记为“Language”
,总行标记为“total”
,那么它会稍微长一点:
rownames(x) <- x$Language
Total <- sum
xa <- addmargins(as.table(as.matrix(x[-1])), 1, FUN = Total)
data.frame(Language = rownames(xa), as.matrix(xa[]), row.names = NULL)
您确定要在数据框中包含列总计吗?对我来说,数据框的解释现在取决于行。例如
- 第1行-(n-1):有多少文件与特定的语言关联
- 第n行:有多少文件与所有语言关联
如果您开始对数据进行子集,这会变得更加混乱。例如,假设您想知道哪些语言的文件超过100个:
> x = data.frame(Files=c(4009, 210, 35),
LOC=c(15328,876, 200),
row.names=c("C++", "Java", "Python"),
stringsAsFactors=FALSE)
> x["Total" ,] = colSums(x)
> x[x$Files > 100,]
Files LOC
C++ 4009 15328
Java 210 876
Total 4254 16404#But this refers to all languages!
Total
行现在是错误的
就我个人而言,我会计算出列和,并将它们存储在一个单独的向量中。如果将列强制为数字,您的原始直觉就会起作用:
y$LOC <- as.numeric(y$LOC)
y$Files <- as.numeric(y$Files)
y$LOC由于您提到这是导出以供演示之前的最后一步,为了清晰起见,您可能会有包含空格的列名(即“总计”)。如果是这样,以下内容将确保创建的data.frame将返回到原始数据集,而不会因列名不匹配而导致错误:
dfTotals <- data.frame(Language="Total",t(colSums(x[,-1]))))
colnames(dfTotals) <- names(x)
rbind(x, dfTotals)
dfTotals试试这个
y[4,] = c("Total", colSums(y[,2:3]))
library(tibble)
x %>% add_row( Language="Total",Files = sum(.$Files),LOC = sum(.$LOC) )
请参阅看门人软件包中的装饰总计()
:
library(janitor)
x %>%
adorn_totals("row")
#> Language Files LOC
#> C++ 4009 15328
#> Java 210 876
#> Python 35 200
#> Total 4254 16404
数值列仍然属于numeric类
免责声明:我创建了这个软件包,包括专门为这个任务设计的adorn_totals()
。一个tidyverse
方法是使用bind_rows
(或者最终add_row
)和
总结
来计算总和。这里的问题是,除了一个,我们需要所有的总和,所以一个技巧是:
summarise_all(x, ~if(is.numeric(.)) sum(.) else "Total")
一行:
x %>%
bind_rows(summarise_all(., ~if(is.numeric(.)) sum(.) else "Total"))
使用dplyr>=1.0进行编辑
还可以使用cross()
x %>%
bind_rows(summarise(.,
across(where(is.numeric), sum),
across(where(is.character), ~"Total")))
试试这个
y[4,] = c("Total", colSums(y[,2:3]))
library(tibble)
x %>% add_row( Language="Total",Files = sum(.$Files),LOC = sum(.$LOC) )
扩展的答案,如果你有更多的列,你可以使用
x %>% add_row(Language = "Total", summarise(., across(where(is.numeric), sum)))
就个人而言,我不建议将数据存储在行名中——这就是变量的用途!一般来说,我同意。我也倾向于遵循@csgillespie的建议,不要在同一个对象中混合原始数据和汇总统计数据。然而,正如OP所指出的,在这种情况下,这并不是一个真正的问题,因为问题围绕着dat的表示a、 没有任何进一步的分析。tidyverse等价物是什么?通常我不会这样做是为了分析,但这是为了演示。这是使用Swave在LaTeX文档中生成表之前的最后一步。谢谢,你是对的:我的解决方案不是必需的答案。你的答案是正确的。我投票支持你并删除了我的条目。很好,我很感激将其保存在tidyverse
中,仅为此加载另一个包似乎很愚蠢。回答很好,为什么只对特定数量的列求和,因为其他列可能不需要求和,而是求平均值。我担心,如果要在不同的列上使用不同的函数,则需要手动运行summaryse(var1=mean(var1),var2=sum(var2),var=“Total”)
sure@SashaPoda,done!这是一个很好的解决方案,但您必须删除第一列,然后将其传递给map_dbl。一种方法是使用[]运算符。x%>%bind_行(x[,-1]>%map_dbl(,sum))
library(tibble)
x %>% add_row( Language="Total",Files = sum(.$Files),LOC = sum(.$LOC) )
df %>% bind_rows(purrr::map_dbl(.,sum))
x %>% add_row(Language = "Total", summarise(., across(where(is.numeric), sum)))