Search code examples
rdata.tableconditional-statementssubtraction

r - Conditionally subtract two data tables


I have two data.tables showing temperatures for multiple locations (identified by geocode).

I would like to create a third one based on a subtraction of them. Here they are:

library(data.table)

# Generate random data:
geocode <- paste0("N", 1:10)
dates <- seq(as.Date("2000-01-01"), as.Date("2004-12-31"), by="month")
models <- c("A", "B", "C", "D", "E")
temp <- runif(length(geocode)*length(dates)*length(models), min=0, max=30)
dt1 <- data.table(expand.grid(Location=geocode,Date=dates,Model=models),Temperature=temp)


ref <- runif(length(geocode), min=0, max=30)
dt2 <- data.table(expand.grid(Location=geocode), Temperature=ref)

I would like to conditionally subtract dt2 from dt1. By each location (geocode), I would like to subtract temperature in dt2 from temperature in dt1, preserving the other columns (Date and Model).

How to achieve this? I would know how to do if it was a single data table, but I've never tried to do algebra on two different data tables like this before.


Solution

  • I think this works:

    dt1[dt2, on=.(Location), td := x.Temperature - i.Temperature, by=.EACHI]
    
          Location       Date Model Temperature          td
       1:       N1 2000-01-01     A    3.949276 -19.2110455
       2:       N2 2000-01-01     A    2.811684 -11.6405195
       3:       N3 2000-01-01     A   24.069659  13.6159779
       4:       N4 2000-01-01     A   25.809426  -1.8793405
       5:       N5 2000-01-01     A   25.193624  19.6812965
      ---                                                  
    2996:       N6 2004-12-01     E   24.298463   4.0218859
    2997:       N7 2004-12-01     E    1.488011 -26.4472283
    2998:       N8 2004-12-01     E   27.489108   5.6525076
    2999:       N9 2004-12-01     E    3.487664  -5.9926003
    3000:      N10 2004-12-01     E    8.523718  -0.7559126
    

    Checking by eye...

    dt2[dt1[1:5], on=.(Location), .(Location, t1 = i.Temperature, t2 = x.Temperature)]
    
       Location        t1        t2
    1:       N1  3.949276 23.160321
    2:       N2  2.811684 14.452204
    3:       N3 24.069659 10.453681
    4:       N4 25.809426 27.688766
    5:       N5 25.193624  5.512328
    

    Looks right to me.


    How it works

    The syntax for an update join is x[i, v := expr, by=.EACHI]. Inside the expression, prefixes i.* and x.* can be used to clarify where columns are being taken from.

    The by=.EACHI might not be needed, but I usually use it for this.