Add row to a data frame with total sum for each column

Do you need the Language column in your data, or is it more appropriate to think of that column as the row.names? That would change your data.frame from 4 observations of 3 variables to 4 observations of 2 variables (Files & LOC).

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
       Files   LOC
C++     4009 15328
Java     210   876
Python    35   200
Total   4254 16404

Here's a way that gets you what you want, but there may very well be a more elegant solution.

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

For the record, I prefer Chase's answer if you don't absolutely need the Language column.


A tidyverse way to do this would be to use bind_rows (or eventually add_row) and summarise to compute the sums. Here the issue is that we want sums for all but one, so a trick would be:

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

In one line:

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

Edit with dplyr >=1.0

One can also use across(), which is slightly more verbose in this case:

x %>%
  bind_rows(summarise(.,
                      across(where(is.numeric), sum),
                      across(where(is.character), ~"Total")))

See adorn_totals() from the janitor package:

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

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

The numeric columns remain of class numeric.

Disclaimer: I created this package, including adorn_totals() which is made for precisely this task.

Tags:

R

Dataframe