I have a big dataframe in R, and I want to make some new columns based on existing columns. However, for each row, the new value depends also on some other rows.
Here is some dummy data
colnames <- c('date', 'docnr', 'clientid', 'values')
docnr <- c(1,2,3,4,5,6)
dates <- c('2017-01-01', '2017-02-01', '2017-03-01', '2017-04-01','2017-01-05', '2017-02-05')
clients <- c(1,1,1,1,2,2)
values <- c(10,14,4,7,9,19)
df <- data.frame(cbind(dates, docnr, clients, values))
names(df) <- colnames
df$date <- as.Date(df$date, format = "%Y-%m-%d")
df
date docnr clientid values
1 2017-01-01 1 1 10
2 2017-02-01 2 1 14
3 2017-03-01 3 1 4
4 2017-04-01 4 1 7
5 2017-01-05 5 2 9
6 2017-02-05 6 2 19
What I want to do, is for every row (uniquely identified by docnr) to take the date and the client id, and find all of the other rows that have the same clientid, and an earlier date.
Then, I want to calculate some things from this subset. For example, I want the total number of rows in this subset, and the total of all values of this subset.
So for this example data, I would expect:
date docnr clientid values counts totals
1 2017-01-01 1 1 10 0 0
2 2017-02-01 2 1 14 1 10
3 2017-03-01 3 1 4 2 24
4 2017-04-01 4 1 7 3 28
5 2017-01-05 5 2 9 0 0
6 2017-02-05 6 2 19 1 9
At the moment, I use a for loop:
counts <- numeric(0)
totals <- numeric(0)
for (i in 1:nrow(df)) {
tmp <- df[df$date< df$date[i] & df$clientid== df$clientid[i],
c( "date", "docnr","value")]
cnt <- nrow(tmp)
tot <- sum(tmp$value)
counts[i] <- res
totals[i] <- tot
}
df$counts <- counts
df$totals <- totals
This loop is obviously very slow for a dataframe of 700k rows (have not run it to completion yet). A parallel implementation with doSNOW does not seem to scale much better.
I've tried using a sql query with sqldf, but subqueries can only return 1 value at a time, which would mean running the query all over for every new column I want to define (and I want to add many more derivative columns later).
I came across a solution with SQL objects (Is it possible to get multiple values from a subquery?), but objects didn't work in R's sqldf. Using joins doesn't work because the second query needs to have information from the first query.
I just started in R (and am also not very familiar with sql), so I would be much obliged if someone knew a more efficient way to do this.