2013-01-16 5 views
12

Ho un grande R data.table con una chiave a più colonne, dove alcune colonne di valori contengono alcune NA. Mi piacerebbe rimuovere gruppi che sono interamente NA in una o più colonne di valori, ma mantenere l'intero gruppo in caso contrario. Ripetendo questo per ogni colonna della chiave.Come si devono rilasciare blocchi di NA da un dato R.table

Per fare un esempio semplificato:

library(data.table) 
DT = data.table(
    Series = rep(letters[1:12], each = 3), 
    Id = 1:12, 
    Value1 = c(1:3, NA, 5:9, rep(NA,3), 1:3, NA, 5:9, rep(NA,3), 1:3, NA, 5:9, rep(NA,3)), 
    Value2 = c(rep(NA,3), 1:4, NA, 6:9, rep(NA,3), 1:9, 1:9, rep(NA,3))) 
DT 
    Series Id Value1 Value2 
1:  a 1  1  NA 
2:  a 2  2  NA 
3:  a 3  3  NA 
4:  b 4  NA  1 
5:  b 5  5  2 
6:  b 6  6  3 
7:  c 7  7  4 
8:  c 8  8  NA 
9:  c 9  9  6 
10:  d 10  NA  7 
11:  d 11  NA  8 
12:  d 12  NA  9 
13:  e 1  1  NA 
14:  e 2  2  NA 
15:  e 3  3  NA 
16:  f 4  NA  1 
17:  f 5  5  2 
18:  f 6  6  3 
19:  g 7  7  4 
20:  g 8  8  5 
21:  g 9  9  6 
22:  h 10  NA  7 
23:  h 11  NA  8 
24:  h 12  NA  9 
25:  i 1  1  1 
26:  i 2  2  2 
27:  i 3  3  3 
28:  j 4  NA  4 
29:  j 5  5  5 
30:  j 6  6  6 
31:  k 7  7  7 
32:  k 8  8  8 
33:  k 9  9  9 
34:  l 10  NA  NA 
35:  l 11  NA  NA 
36:  l 12  NA  NA 
    Series Id Value1 Value2 

quindi vorrei far cadere:

  • Serie: A, D, E, H e L
  • Ids: 4, 10, 11 e 12

risultato corretto dovrebbe essere simile:

Series Id Value1 Value2 
1:  b 5  5  2 
2:  b 6  6  3 
3:  c 7  7  4 
4:  c 8  8  NA 
5:  c 9  9  6 
6:  f 5  5  2 
7:  f 6  6  3 
8:  g 7  7  4 
9:  g 8  8  5 
10:  g 9  9  6 
11:  i 1  1  1 
12:  i 2  2  2 
13:  i 3  3  3 
14:  j 5  5  5 
15:  j 6  6  6 
16:  k 7  7  7 
17:  k 8  8  8 
18:  k 9  9  9 
    Series Id Value1 Value2 

Quello che sono riuscito finora:

posso trovare la serie che sono NA per Value1 come questo:

DT[, sum(1-is.na(Value1)) == 0, by = Series][V1 == TRUE] 

e ho potuto anche fare

setkey(DT, Series) 
DT = DT[DT[, sum(1-is.na(Value)) == 0, by = Series][V1 != TRUE]] 

Ma ora finisco con V1 che appare nel tavolo finale.

+2

perché non solo 'na.omit (DT)'? – Justin

+0

'na.omit' sta semplicemente rimuovendo tutte le NA. Voglio solo rimuovere quando l'intero "blocco" è NA. Quindi nell'esempio, non ci sono valori per m o z, quindi dovrebbero essere eliminati, ma non voglio rilasciare i due NA nella serie b – Corone

+0

Quindi @Arun ha la tua risposta, ma non dovresti aver bisogno di 'come .logical'. – Justin

risposta

9

È possibile fare questo per ottenere tali voci alle quali non tutti sono ValueNA:

setkey(DT, "Series") 
DT[, .SD[(!all(is.na(Value)))], by=Series] 

Le parentesi intorno !all sono necessari per evitare di non-join sintassi che Matthew esaminerà (vedi commenti). Uguale a questo:

DT[, .SD[as.logical(!all(is.na(Value)))], by=Series] 

costruzione da quello di rispondere alla nuova domanda chiarito:

allNA = function(x) all(is.na(x))  # define helper function 
for (i in c("Id","Series")) 
    DT = DT[, if (!any(sapply(.SD,allNA))) .SD else NULL, by=i] 
DT 
    Series Id Value1 Value2 
1:  i 1  1  1 
2:  i 2  2  2 
3:  i 3  3  3 
4:  b 5  5  2 
5:  b 6  6  3 
6:  f 5  5  2 
7:  f 6  6  3 
8:  j 5  5  5 
9:  j 6  6  6 
10:  c 7  7  4 
11:  c 8  8  NA 
12:  c 9  9  6 
13:  g 7  7  4 
14:  g 8  8  5 
15:  g 9  9  6 
16:  k 7  7  7 
17:  k 8  8  8 
18:  k 9  9  9 

che cambia l'ordine, però. Quindi non è esattamente il risultato richiesto. Quanto segue mantiene l'ordine e dovrebbe essere anche più veloce.

# starting fresh from original DT in question again 
DT[,drop:=FALSE] 
for (i in c("Series","Id")) 
    DT[,drop:=drop|any(sapply(.SD,allNA)),by=i] 
DT[(!drop)][,drop:=NULL][] 
    Series Id Value1 Value2 
1:  b 5  5  2 
2:  b 6  6  3 
3:  c 7  7  4 
4:  c 8  8  NA 
5:  c 9  9  6 
6:  f 5  5  2 
7:  f 6  6  3 
8:  g 7  7  4 
9:  g 8  8  5 
10:  g 9  9  6 
11:  i 1  1  1 
12:  i 2  2  2 
13:  i 3  3  3 
14:  j 5  5  5 
15:  j 6  6  6 
16:  k 7  7  7 
17:  k 8  8  8 
18:  k 9  9  9 
+0

Per qualche motivo, '.SD [! All (is.na (Value))]' non funziona. – Arun

+0

+1 '!' = Non aderire, ma non sono sicuro del motivo per cui non funzionerebbe (non dovrebbe fare la differenza per logica, potrebbe essere un problema di non unirmi in combinazione con il riciclaggio, forse) –

+1

Ok, ora Capisco. '.SD [(! All (is.na (Value)))]' (con la parante) funziona! – Arun

10

Che dire della funzione complete.cases?

DT[complete.cases(DT),] 

Si scenderà le righe che hanno un valore di colonna con NA

> DT[complete.cases(DT),] 
    Series Id Value1 Value2 
1:  b 4  4  1 
2:  b 5  5  2 
3:  b 6  6  3 
4:  c 7  7  4 
5:  c 8  8  5 
6:  c 9  9  6 
7:  f 4  4  1 
8:  f 5  5  2 
9:  f 6  6  3 
10:  g 7  7  4 
11:  g 8  8  5 
12:  g 9  9  6 
13:  j 4  4  1 
14:  j 5  5  2 
15:  j 6  6  3 
16:  k 7  7  4 
17:  k 8  8  5 
18:  k 9  9  6 
+0

Funzione piacevole, utile da sapere, ma voglio una funzione "notempty.cases" - Lascia solo quei casi che sono completamente vuoti per una colonna e lascia gli altri NA in. – Corone

+4

ok, allora dovresti forse cambiare l'esempio del set di dati, poiché tutte le variabili che hanno valori NA, hanno valori NA per le 3 righe della stessa lettera (sia in Valore1 sia in valore2) –

+0

Buon punto, ho incluso due NA in più per mostrare questo – Corone

Problemi correlati