2013-01-16 3 views
12

J'ai un grand R data.table avec une clé multi-colonne, où certaines colonnes de valeur contiennent des NA. Je voudrais supprimer les groupes qui sont entièrement NA dans une ou plusieurs colonnes de valeur, mais conserver le groupe entier dans le cas contraire. Répétez ceci pour chaque colonne de la clé.Comment faire pour supprimer des blocs de NA à partir d'un R data.table

Pour donner un exemple simplifié:

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 

Je voudrais donc laisser tomber:

  • Série: a, d, e, h et l
  • Ids: 4, 10, 11 et 12

résultat correct devrait ressembler à:

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 

Ce que je réussi à ce jour:

je peux trouver la série qui sont NA pour Valeur1 comme ceci:

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

Et je pourrais même faire

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

Mais maintenant je me retrouve avec V1 apparaissant dans la table finale.

+2

pourquoi pas seulement 'na.omit (DT)'? – Justin

+0

'na.omit' ne fait que supprimer toutes les NA. Je veux seulement enlever quand le "bloc" entier est NA. Donc dans l'exemple, il n'y a pas de valeur pour m ou z, donc ils devraient être supprimés, mais je ne veux pas laisser tomber les deux NA en série b – Corone

+0

Puis @Arun a votre réponse, mais vous ne devriez pas avoir besoin de 'comme .logical'. – Justin

Répondre

9

Vous pouvez le faire pour obtenir les entrées dans lesquelles tous Value sont NA:

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

Les parens autour !all sont nécessaires pour éviter la syntaxe non-join que Matthieu examinera (voir les commentaires). Même chose que ceci:

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

partir de là pour répondre à la nouvelle question clarifiée:

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 

qui change l'ordre, cependant. Ce n'est donc pas précisément le résultat demandé. Ce qui suit garde la commande et devrait être plus rapide aussi.

# 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

Pour une raison quelconque, '.SD [! All (is.na (Value))]' ne fonctionne pas. – Arun

+0

+1 '!' = Ne pas joindre, mais je ne sais pas pourquoi cela ne fonctionnerait pas (ne devrait pas faire de différence pour logique, peut-être un problème de ne pas se joindre au recyclage, peut-être) –

+1

Okay, maintenant Je comprends. '.SD [(! All (is.na (Valeur)))]' (avec la parenthèse) fonctionne! – Arun

10

Qu'en est-il de l'utilisation de la fonction complete.cases?

DT[complete.cases(DT),] 

Il baissera les lignes qui ont une valeur de colonne avec 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

Belle fonction, utile à savoir, mais je veux une fonction "notempty.cases" - Ne laisser tomber que les cas qui sont complètement vides pour une colonne, et laisser les autres NA dans. – Corone

+4

ok, alors vous devriez peut-être changer l'exemple de jeu de données, parce que toutes les variables qui ont des valeurs NA, ont des valeurs NA pour les 3 lignes de la même lettre (dans Value1 et value2) –

+0

Bon point, j'ai inclus deux NA supplémentaires pour montrer cela – Corone

Questions connexes