2015-01-29 22 views
5

Ho un data.table pieno di alcuni prodotti di consumo. Ho creato qualche distinzione per i prodotti come 'low', 'high' o 'unknown' qualità. I dati sono serie temporali e sono interessato a livellare la stagionalità dei dati. Se la classificazione grezza di un prodotto (la classificazione sfornata dall'algoritmo che ho usato per determinare la qualità) è la qualità 'low' nel periodo X, ma la sua classificazione grezza era la qualità 'high' nel periodo X-1, sto riclassificando quel prodotto come 'high' qualità per periodo X. Questo processo è fatto all'interno di una sorta di distinzione di gruppo di prodotti.Comportamento ifelse in data.table (R)

Per fare questo, ho qualcosa di simile al seguente:

require(data.table) 

# lag takes a column and lags it by one period, 
# padding with NA 

lag <- function(var) { 
    lagged <- c(NA, 
       var[1:(length(var)-1)]) 
    return(lagged) 
} 

set.seed(120) 

foo <- data.table(group = c('A', rep(c('B', 'C', 'D'), 5)), 
        period = c(1:16), 
        quality = c('unknown', sample(c('high', 'low', 'unknown'), 15, replace = TRUE))) 

foo[, quality_lag := lag(quality), by = group] 

foo[, quality_1 := ifelse(quality == 'low' & quality_lag == 'high', 
          'high', 
          quality)] 

Dando uno sguardo al foo:

group period quality quality_lag quality_1 
1:  A  1 unknown   NA unknown 
2:  B  2  low   NA  NA 
3:  C  3 high   NA  high 
4:  D  4  low   NA  NA 
5:  B  5 unknown   low unknown 
6:  C  6 high  high  high 
7:  D  7  low   low  low 
8:  B  8 unknown  unknown unknown 
9:  C  9 high  high  high 
10:  D  10 unknown   low unknown 
11:  B  11 unknown  unknown unknown 
12:  C  12  low  high  high 
13:  D  13 unknown  unknown unknown 
14:  B  14 high  unknown  high 
15:  C  15 high   low  high 
16:  D  16 unknown  unknown unknown 

Quindi, quality_1 è in gran parte quello che voglio. Se il periodo X è 'low' e il periodo X-1 è 'high', si verifica la riclassificazione a 'high' e tutto è rimasto per lo più intatto da quality. Tuttavia, quando quality_lag è NA, 'low' viene riclassificato in NA in quality_1. Questo non è un problema con 'high' o 'unknown'.

Vale a dire, le prime quattro file di foodovrebbero simile a questa:

group period quality quality_lag quality_1 
1:  A  1 unknown   NA unknown 
2:  B  2  low   NA  low 
3:  C  3 high   NA  high 
4:  D  4  low   NA  low 

Dei pensieri su che cosa sta causando questo?

+7

Per i principianti, non è necessario reinventare la ruota. 'data.table' v> = 1.9.5 ha già la funzione' lag' chiamata 'shift', quindi potresti semplicemente fare' foo [, quality_lag: = shift (quality), by = group] ' –

+6

Secondariamente,' ifelse' è veramente una funzione awefull e cerco sempre di evitarlo. Il mio consiglio sarebbe semplicemente di fare qualcosa come 'foo [, quality_1: = quality] [quality == 'low' e quality_lag == 'high', quality_1: =" high "]' –

+1

@DavidArenburg ha il punto morto. Inoltre, vedi http://stackoverflow.com/q/16275149/1492421 per maggiori informazioni su ifelse –

risposta

6

Per cominciare, il Development version on GitHub ha già una funzione di ritardo efficiente chiamato shift che può essere utilizzato sia come lag o piombo (e ha alcune funzionalità aggiuntive troppo, vedi ?shift).

anche dare un'occhiata here in quanto v'è una serie di altre nuove funzioni che sono oggi presenti in v> = 1.9.5

Così in v> = 1.9.5 potremmo semplicemente fare

foo[, quality_lag := shift(quality), by = group] 

Anche se in v < 1.9.5 si potrebbe fare un uso di .N invece di creare questa funzione, nel modo seguente

foo[, quality_lag2 := c(NA, quality[-.N]), by = group] 

Per quanto riguarda la seconda domanda, mi sento di raccomandare di evitare ifelse tutti insieme per molti motivi specificati here

Una possibile alternativa potrebbe essere , solo per usare un semplice indicizzazione come in

foo[, quality_1 := quality][quality == 'low' & quality_lag == 'high', quality_1 := "high"] 

Questa soluzione ha un po 'alto, di chiamare [.data.table due volte, ma sarà ancora molto più efficiente/sicuro rispetto alla soluzione ifelse.

-3

Il tuo problema è che ifelse(NA, 1, 2) == NA e quando lo fai NA == 'low' il risultato è NA. Una soluzione semplice è rappresentata da NA come stringhe nella funzione di ritardo. Qui è la versione del codice di lavoro:

require(data.table) 

# lag takes a column and lags it by one period, 
# padding with NA 

lag <- function(var) { 
    lagged <- c("NA", 
       var[1:(length(var)-1)]) 
    return(lagged) 
} 

set.seed(120) 

foo <- data.table(group = c('A', rep(c('B', 'C', 'D'), 5)), 
        period = c(1:16), 
        quality = c('unknown', sample(c('high', 'low', 'unknown'), 15, replace = TRUE))) 

foo[, quality_lag := lag(quality), by = group] 

foo[, quality_1 := ifelse(quality == 'low' & quality_lag == 'high', 
          'high', 
          quality)] 
+4

Dovresti ** mai ** rappresentare NA come carattere principalmente perché 'is.na (" NA ") # [1] FALSE' –