0
votes

I would like to calculate sums by cut values for several columns. I know how to do this manually for each column, but I am struggling finding a decent way to automate the function for all columns. Usually I would use my function with lapply, but I chose to do it with data.table and I could not figure out how to use char values.

I was hoping for a list of data.tables with the sums for each category or a matrix/data.table with a first column for each column variable and the following columns as the categories, like

data.table(col.name=c("v1","v2"), low=c( 1185.3074,1175.7261 ), high=c( 1175.726,350.3937 ))

MWE

rm(list=ls())
if(!require(data.table)) { install.packages("data.table"); require(data.table)}
set.seed(123)
DT<-data.table(v1=runif(50,10,50),v2=runif(50,10,50))

DT[,sum(v1, na.rm = T), by=cut(DT[,v1], breaks=c(0,25,50), labels = c("low", "high"))]
DT[,sum(v2, na.rm = T), by=cut(DT[,v2], breaks=c(0,25,50), labels = c("low", "high"))]
4

4 Answers

3
votes

I guess one standard way would be to reshape twice:

dcast(
  melt(DT), 
  variable ~ cut(value, c(0,25,50), c("low","high")), 
  fun = sum
)

#    variable      low     high
# 1:       v1 323.2453 1216.937
# 2:       v2 331.0626 1122.991

melt reshapes to "long"; while dcast reverts to "wide."

1
votes

You can try something like this, not exactly what you want though but the result is close and it automates the summary process(essentially it is still a loop through all the columns of the data table and summarize each individually):

DT[, c(lapply(.SD, function(col) tapply(col, cut(col, breaks = c(0, 25, 50)), FUN=sum)), 
       list(category = c('low', 'high')))]

#          v1        v2 category
#1:  323.2453  331.0626      low
#2: 1216.9367 1122.9914     high
1
votes

A base R solution for fun:

do.call(rbind, lapply(DT, function(x) tapply(x, cut(x, 0:2*25), sum)))

#        (0,25]     (25,50]
#v1 323.2452605 1216.936685
#v2 331.0626328 1122.991399
0
votes

I started with data table, but I think tidyr and dplyr are more suitable for my later purposes. I it seems easier to summarise using several functions at the same time while keeping control of the naming. Anyhow, it is always good to have a second solution to the same problem and I needed the nudge to just reshape my data.

if(!require(dplyr)) { install.packages("dplyr"); require(dplyr)}
if(!require(tidyr)) { install.packages("tidyr"); require(tidyr)}
DT %>% 
    gather(variable, value) %>%
    mutate(segment = cut(value, c(0,25,50), c("low","high"))) %>%
    group_by(variable,segment) %>%
    summarise(sum=sum(value)) %>%
    spread(segment, sum)