2013-01-16 9 views
12

Mam duży R data.table z kluczem z wieloma kolumnami, gdzie niektóre kolumny wartości zawierają pewne NA. Chciałbym usunąć grupy, które są całkowicie NA w jednej lub wielu kolumnach wartości, ale zachowują całą grupę w inny sposób. Powtarzam to dla każdej kolumny klucza.Jak powinienem usunąć bloki NA z danych R.table

Aby dać przykład uproszczony:

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 

więc proszę spadać:

  • Seria A, D, E, H, L
  • Ids: 4, 10, 11 i 12

Prawidłowy wynik powinien wyglądać następująco:

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 

Co udało mi się do tej pory:

znajdę Series, które są NA dla Wartość1 tak:

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

I mógłbym nawet zrobić

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

Ale teraz kończę z V1 pojawiającym się w finałowym stole.

+2

dlaczego nie po prostu 'na.omit (DT)'? – Justin

+0

'na.omit' usuwa wszystkie NA. Chcę usunąć tylko wtedy, gdy cały "blok" jest NA. Więc w tym przykładzie nie ma wartości m lub z, więc powinny one zostać usunięte, ale nie chcę upuszczać dwóch NA w serii b – Corone

+0

Wtedy @Arun ma twoją odpowiedź, ale nie powinieneś potrzebować 'as .logical'. – Justin

Odpowiedz

9

Można to zrobić, aby te wpisy, gdzie nie wszystkie ValueNA: potrzebne są wokół !all

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

parens aby uniknąć nie dołącz składni, która przyjrzy się Matthew (patrz komentarze). Tak samo jak to:

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

Opierając się na tym, by odebrać nowe sprecyzować pytanie:

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 

To zmienia kolejność, choć. Więc nie jest to dokładnie oczekiwany rezultat. Następująca zachowuje kolejność i powinna być również szybsza.

# 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

Z jakiegoś powodu ".SD [! All (is.na (Value))]" nie działa. – Arun

+0

+1 '!' = Nie dołączaj, ale nie jestem pewien, dlaczego to nie zadziałałoby (nie powinno to mieć znaczenia dla logiki, może być prawdopodobnie nie dołączać w połączeniu z recyklingiem, być może) –

+1

OK, teraz Rozumiem. '.SD [(! All (is.na (Value)))]' (z parantezą) działa! – Arun

10

Co z wykorzystaniem funkcji complete.cases?

DT[complete.cases(DT),] 

będzie spadać wiersze, które mają wartość kolumny z 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

Fajna funkcja, przydatna do poznania, ale chcę funkcji "notempty.cases" - Opuść tylko te przypadki, które są całkowicie puste dla jednej kolumny, i pozostaw pozostałe NA. – Corone

+4

ok, wtedy powinieneś zmienić przykład zestawu danych, ponieważ wszystkie zmienne, które mają wartości NA, mają wartości NA dla 3 wierszy tej samej litery (zarówno w wartości 1, jak i wartości 2) –

+0

Dobrze, dodałem dwie dodatkowe NA, aby to pokazać – Corone

Powiązane problemy