2016-02-19 4 views
6

È possibile che .SDcols vari con la variabile di raggruppamento by? Ho la seguente situazione, in cui vorrei cambiare .SDcols in colonne diverse per ogni anno. I valori per .SDcols si trovano in un file data.table, mentre sto cercando di applicare una funzione allo .SD in un'altra tabella utilizzando questi valori.Consentire .SDcols di variare con la variabile di raggruppamento in data.table

Molto probabilmente mi manca l'approccio più ovvio e facendo questo torto, ma questo è quello che stavo cercando,

## Contains the .SDcols applicable to each year 
dat1 <- data.table(
    year = 1:4, 
    vals = lapply(1:4, function(i) letters[1:i]) 
) 

## Make the sample data (with NAs) 
set.seed(1775) 
dat2 <- data.table(year = sample(1:4, 10, TRUE)) 
dat2[, letters[1:4] := replicate(4, sample(c(NA, 1:5), 10, TRUE), simplify=FALSE)] 

## Goal: Sum up the columns in the corresponding .SDcols for each year 
## Attempt, doesn't work -- I think b/c .SDcols must be fixed? 
dat2[, SUM := rowSums(.SD, na.rm=TRUE), by=year, 
    .SDcols=unlist(dat1[year == .BY[[1]], vals])] 

## Desired result, by simply iterating through each possible year 
for (i in 1:4) { 
    dat2[year==i, SUM := rowSums(.SD, na.rm=TRUE), 
    .SDcols=unlist(dat1[year == i, vals])] 
} 

dat2[] 
#  year a b c d SUM 
# 1: 1 3 1 5 1 3 
# 2: 2 1 3 3 1 4 
# 3: 1 5 4 3 NA 5 
# 4: 4 1 NA 4 5 10 
# 5: 2 2 2 2 NA 4 
# 6: 2 NA 3 3 NA 3 
# 7: 4 2 3 2 NA 7 
# 8: 1 2 NA 5 4 2 
# 9: 2 3 3 5 1 6 
# 10: 3 NA 4 2 NA 6 

risposta

6

Mi sembra che si sta solo in cerca di un semplice join durante l'aggiornamento dei valori (per riferimento) per ogni valore in dat1 (by = .EACHI). In entrambi i casi, rowSums è il collo di bottiglia in questa soluzione e il tuo tentativo (a causa della conversione della matrice). Se fossi in te, vorrei convertire tutti gli NA s a zero ed eseguire Reduce(`+`,...) invece (non sono sicuro se si desidera modificare i valori nei dati originali)

dat2[dat1, 
     SUM := rowSums(.SD[, unlist(i.vals), with = FALSE], na.rm = TRUE), 
     on = "year", 
    by = .EACHI] 
dat2 
#  year a b c d SUM 
# 1: 1 3 1 5 1 3 
# 2: 2 1 3 3 1 4 
# 3: 1 5 4 3 NA 5 
# 4: 4 1 NA 4 5 10 
# 5: 2 2 2 2 NA 4 
# 6: 2 NA 3 3 NA 3 
# 7: 4 2 3 2 NA 7 
# 8: 1 2 NA 5 4 2 
# 9: 2 3 3 5 1 6 
# 10: 3 NA 4 2 NA 6 

Anche se fossi in te, come detto, vorrei convertire le NA s di zeri e utilizzare Reduce invece

for(j in 2:ncol(dat2)) set(dat2, i = which(is.na(dat2[[j]])), j = j, value = 0L) 
dat2[dat1, 
     SUM := Reduce(`+`, .SD[, unlist(i.vals), with = FALSE]), 
     on = "year", 
    by = .EACHI] 
dat2 
#  year a b c d SUM 
# 1: 1 3 1 5 1 3 
# 2: 2 1 3 3 1 4 
# 3: 1 5 4 3 0 5 
# 4: 4 1 0 4 5 10 
# 5: 2 2 2 2 0 4 
# 6: 2 0 3 3 0 3 
# 7: 4 2 3 2 0 7 
# 8: 1 2 0 5 4 2 
# 9: 2 3 3 5 1 6 
# 10: 3 0 4 2 0 6 
+0

Le escludere dall'elenco (i.vals) '' era quello che mi aveva messo in difficoltà . Ero sicuro che si trattasse di un problema ".EACHI". +1 – A5C1D2H2I1M1N2O1R2T1

+0

@AnandaMahto funzionerebbe senza "i" anche io, lo uso sempre per sicurezza (nel caso ci sia una colonna simile anche nell'altro set di dati), o ti stavi solo riferendo a 'by =. Parte EACHI? –

Problemi correlati