如何向具有总计的数据框添加行?

时间:2011-02-09 15:26:23

标签: r dataframe

我有一个数据框,我想添加一个额外的行,总计列的值。例如,假设我有这些数据:

x <- data.frame(Language=c("C++", "Java", "Python"), 
                Files=c(4009, 210, 35), 
                LOC=c(15328,876, 200), 
                stringsAsFactors=FALSE)    

数据如下所示:

  Language Files   LOC
1      C++  4009 15328
2     Java   210   876
3   Python    35   200

我的直觉是这样做:

y <- rbind(x, c("Total", colSums(x[,2:3])))

这样可行,它计算总数:

> y
  Language Files   LOC
1      C++  4009 15328
2     Java   210   876
3   Python    35   200
4    Total  4254 16404

问题是Files和LOC列都已转换为字符串:

> y$LOC
[1] "15328" "876"   "200"   "16404"

我理解这种情况正在发生,因为我创建了一个带有数字和字符串输入的向量c("Total", colSums(x[,2:3]),并且它将所有元素转换为通用类型,以便所有向量元素都相同。然后在Files和LOC列中发生同样的事情。

有什么更好的方法可以做到这一点?

13 个答案:

答案 0 :(得分:23)

这是一种可以满足您需求的方式,但可能会有一个更优雅的解决方案。

rbind(x, data.frame(Language="Total",t(colSums(x[,-1]))))

如果您不完全需要Language列,我更喜欢Chase的回答。

答案 1 :(得分:21)

请参阅janitor包中的adorn_totals()

library(janitor)
x %>%
  adorn_totals("row")

#>  Language Files   LOC
#>       C++  4009 15328
#>      Java   210   876
#>    Python    35   200
#>     Total  4254 16404

数字列仍为数字类。

免责声明:我创建了这个软件包,包括adorn_totals(),它是为了完成这项任务而制作的。

答案 2 :(得分:20)

您是否需要数据中的语言列,或者将该列视为row.names更合适?这会将您的data.frame从3个变量的4个观察变为2个变量的4个观察值(Files&amp; LOC)。

x <- data.frame(Files=c(4009, 210, 35), LOC=c(15328,876, 200), row.names=c("C++", "Java", "Python"), stringsAsFactors=F)    
x["Total" ,] <- colSums(x)


> x
       Files   LOC
C++     4009 15328
Java     210   876
Python    35   200
Total   4254 16404

答案 3 :(得分:14)

执行此操作的tidyverse方法是使用bind_rows(或最终add_rows)和summarise来计算总和。这里的问题是我们想要除了一个以外的所有总和,所以一个技巧就是:

summarise_all(x, funs(if(is.numeric(.)) sum(.) else "Total"))

在一行中:

x %>%
  bind_rows(summarise_all(., funs(if(is.numeric(.)) sum(.) else "Total")))

答案 4 :(得分:9)

试试这个

y[4,] = c("Total", colSums(y[,2:3]))

答案 5 :(得分:5)

如果(1)我们在第一列上不需要"Language"标题,那么我们可以使用行名表示它,如果(2)可以将最后一行标记为"Sum"而不是"Total",我们可以像这样使用addmargins

rownames(x) <- x$Language
addmargins(as.table(as.matrix(x[-1])), 1)

,并提供:

       Files   LOC
C++     4009 15328
Java     210   876
Python    35   200
Sum     4254 16404

如果我们确实希望标记为"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)

,并提供:

  Language Files   LOC
1      C++  4009 15328
2     Java   210   876
3   Python    35   200
4    Total  4254 16404

答案 6 :(得分:1)

您确定要确保数据框中的列总数吗?对我来说,数据框的解释现在取决于行。例如,

  • 第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行现在错了!

我个人会计算列总和并将它们存储在一个单独的向量中。

答案 7 :(得分:1)

由于您提到这是导出演示文稿之前的最后一步,因此为了清晰起见,您可能会在列名中包含空格(即“Grand Total”)。如果是这样,以下内容将确保创建的data.frame将绑定到原始数​​据集,而不会由不匹配的列名称导致错误:

dfTotals <- data.frame(Language="Total",t(colSums(x[,-1]))))

colnames(dfTotals) <- names(x)  

rbind(x, dfTotals)

答案 8 :(得分:1)

尝试一下

library(tibble)
x %>% add_row( Language="Total",Files = sum(.$Files),LOC = sum(.$LOC) )

答案 9 :(得分:1)

df %>% bind_rows(purrr::map_dbl(.,sum))

答案 10 :(得分:1)

扩展Nicolas Ratto的答案,如果你有更多的列,你可以使用

x %>% add_row(Language = "Total", summarise(., across(where(is.numeric), sum)))

答案 11 :(得分:0)

如果您将列强制为数字,原始本能就会起作用:

y$LOC <- as.numeric(y$LOC)
y$Files <- as.numeric(y$Files)

然后应用colSums()和rbind()。

答案 12 :(得分:0)

您可以使用申请每个总和

  

申请(df [ - 你不想要的总和],2,总和)

然后你可以

  

rbind

你df中的数据