2011-06-05 16 views
35

Chciałbym podzbioru (filtr) ramkę danych, określając, które wiersze są przechowywane w nowej ramce danych. Oto uproszczony przykład dataframe:Podzbiór obrazu według wielu warunków logicznych wierszy, aby usunąć

data 
v1 v2 v3 v4 
a v d c 
a v d d 
b n p g 
b d d h  
c k d c  
c r p g 
d v d x 
d v d c 
e v d b 
e v d c 

Na przykład, jeżeli rząd kolumnowej v1 ma „B”, „D”, lub „e”, chcę, aby pozbyć się tego wiersza obserwacji, produkujących następująca ramka danych:

v1 v2 v3 v4 
a v d c 
a v d d 
c k d c  
c r p g 

Udało mi się wykonać podzbiór na podstawie jednego warunku na raz. Na przykład, tutaj mogę usunąć wiersze gdzie V1 zawiera „B”:

sub.data <- data[data[ , 1] != "b", ] 

Mam jednak wiele, wiele takich warunkach, że robi to po jednym na raz nie jest pożądane. Nie udało się wpisem:

sub.data <- data[data[ , 1] != c("b", "d", "e") 

lub

sub.data <- subset(data, data[ , 1] != c("b", "d", "e")) 

Próbowałem kilka innych rzeczy, a także, jak !%in%, ale to nie wydaje się istnieć. Jakieś pomysły?

Odpowiedz

37

! powinny być po zewnętrznej stronie oświadczenie:

data[!(data$v1 %in% c("b", "d", "e")), ] 

    v1 v2 v3 v4 
1 a v d c 
2 a v d d 
5 c k d c 
6 c r p g 
44

Spróbuj

subset(data, !(v1 %in% c("b","d","e"))) 
+0

Ładne i proste, dzięki. Nie jestem pewien, które rozwiązanie bardziej mi się podoba, to czy to dostarczone przez Andrie. Oba są łatwe i skuteczne. Wszystkie trzy rozwiązania działają dla mnie i nigdy wcześniej nie używałem 'which()'. Tak więc miło było zostać wprowadzonym w tę funkcję. – Jota

+9

Jeśli pomaga ci zdecydować, czy użyć 'podzbioru' lub' [', spójrz na ostrzeżenie w pomocy dla' 'podzbioru': *" Jest to wygodna funkcja przeznaczona do interaktywnego użytku. Do programowania lepiej używać standardowych funkcji podsekcji takich jak [, aw szczególności nietypowa ocena podzbioru argumentów może mieć nieprzewidziane konsekwencje. "* – Andrie

+0

@Andrie Dzięki za dodanie wyjaśnienia. – chl

3
my.df <- read.table(textConnection(" 
v1 v2 v3 v4 
a v d c 
a v d d 
b n p g 
b d d h  
c k d c  
c r p g 
d v d x 
d v d c 
e v d b 
e v d c"), header = TRUE) 

my.df[which(my.df$v1 != "b" & my.df$v1 != "d" & my.df$v1 != "e"), ] 

    v1 v2 v3 v4 
1 a v d c 
2 a v d d 
5 c k d c 
6 c r p g 
4

Ta odpowiedź jest bardziej przeznaczona do wyjaśnienia, dlaczego nie jak. Operator '==' w R jest wektoryzowany w ten sam sposób co operator '+'. Dopasowuje elementy tego, co znajduje się po lewej stronie, do elementów tego, co znajduje się po prawej stronie, na element. Np

> 1:3 == 1:3 
[1] TRUE TRUE TRUE 

Tutaj Pierwszy test jest 1==1 co ma miejsce, drugi i trzeci 2==23==3. Zauważ, że ta zwraca FALSE w pierwszym i drugim elementem, ponieważ kolejność jest źle:

> 3:1 == 1:3 
[1] FALSE TRUE FALSE 

Teraz, gdy jeden obiekt jest mniejszy niż w innych obiektów to mniejszy obiekt jest powtarzany tyle, ile trzeba, aby dopasować powiększenie obiekt. Jeśli rozmiar większego obiektu nie jest mnożeniem wielkości mniejszego obiektu, pojawia się ostrzeżenie, że nie wszystkie elementy są powtarzane. Np

> 1:2 == 1:3 
[1] TRUE TRUE FALSE 
Warning message: 
In 1:2 == 1:3 : 
    longer object length is not a multiple of shorter object length 

Oto pierwsze dopasowanie 1==1, następnie 2==2 i wreszcie 1==3 (NIE), ponieważ po lewej stronie jest mniejsza. Jeżeli jeden z boków jest tylko jeden element wówczas powtarza:

> 1:3 == 1 
[1] TRUE FALSE FALSE 

Prawidłowe operatorowi sprawdzenia, czy element jest w wektorze jest rzeczywiście '%in%' który wektorowy tylko do lewego elementu (dla każdego elementu lewy wektor jest testowany, jeśli jest częścią dowolnego obiektu w prawym elemencie).

Alternatywnie można użyć kombinacji '&', aby połączyć dwie instrukcje logiczne. '&' trwa dwa elementy i sprawdza elementwise jeśli oba są prawdziwe:

> 1:3 == 1 & 1:3 != 2 
[1] TRUE FALSE FALSE 
10

można również osiągnąć poprzez łamanie rzeczy w jednostkowym sprawozdaniu logicznych o tym & oddzielić oświadczenia.

subset(my.df, my.df$v1 != "b" & my.df$v1 != "d" & my.df$v1 != "e") 

To nie jest eleganckie i wymaga więcej kodu, ale może być bardziej czytelne dla nowszych użytkowników. Jak wskazano w powyższym komentarzu, subset jest funkcją "wygody", która najlepiej sprawdza się podczas interaktywnej pracy.

+1

czy nie powinny to być '|', a nie '&'? –

+0

@BenBolker Jeśli zmienisz na '|', otrzymasz te same dane, które zostały wprowadzone. – Jota

+1

@Frank Czy możesz wyjaśnić logikę '&' powiązaną z '! =' Tutaj? Podobnie jak Ben, wydaje się, że powinno się użyć '|', ale masz rację, że nie powinno. Jestem szczególnie zdezorientowany, jeśli chodzi o dzielenie wielu kolumn w ten sposób. Na przykład, korzystając z przykładowych danych Hermana powyżej, aby usunąć wszystkie przypadki "b" z v1 i wszystkich "n" z v2, myślę, że 'my.df [my.df $ v1! =" B "i moje. df $ v2! = "n",] "usuwałoby tylko przypadki, które spełniłyby oba te kryteria (tj. tylko wiersz 3), a nie którekolwiek z tych kryteriów (tj. zarówno wiersz 3, jak i wiersz 4). W rzeczywistości użycie '' 'z'! = 'Robi to, czego oczekuję' & ', ale nie rozumiem dlaczego. – coip

5
data <- data[-which(data[,1] %in% c("b","d","e")),] 
+3

'' 'który jest zły i przyniesie nieoczekiwane wyniki w przypadkach, gdy żadna z wartości w wektorze nie pasuje do wektora źródłowego. – A5C1D2H2I1M1N2O1R2T1

0
sub.data<-data[ data[,1] != "b" & data[,1] != "d" & data[,1] != "e" , ] 

Większe ale proste do zrozumienia (chyba) i może być stosowany z wieloma kolumnami, nawet z !is.na(data[,1]).

1

A także

library(dplyr) 
data %>% filter(!v1 %in% c("b", "d", "e")) 

lub

data %>% filter(v1 != "b" & v1 != "d" & v1 != "e") 

lub

data %>% filter(v1 != "b", v1 != "d", v1 != "e") 

ponieważ operator & jest regulowane przecinku.