Menu

Filtrowanie danych w R (subset, [ ], filter z dplyr)

Wszystkie sposoby na zostawienie potrzebnych wierszy i kolumn: maski logiczne w nawiasach, jednolinijkowe subset(), %in%, pułapki z NA oraz filter() i select() z dplyr.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Filtrowanie wierszy: maska logiczna

Żeby przefiltrować ramkę danych w R, wstaw warunek na pozycję wierszy w nawiasach: df[condition, ]. Warunek daje wektor TRUE/FALSE, po jednej wartości na wiersz, a R zostawia wiersze z TRUE:

Czytaj scores[scores$score > 80, ] od środka: scores$score > 80 daje TRUE FALSE TRUE TRUE FALSE, a nawiasy zostawiają wiersze 1, 3 i 4. Końcowy przecinek nie jest opcjonalny. Nawiasy na ramce danych przyjmują [rows, columns]; puste miejsce na kolumny oznacza "wszystkie kolumny". Zapomnij o przecinku, a zamiast wierszy zaczniesz indeksować kolumny. To jeden z najczęstszych błędów początkujących w R.

Zwróć uwagę, że wypisane numery wierszy to 1 3 4, a nie 1 2 3: filtrowanie zachowuje oryginalne etykiety wierszy. Nieszkodliwe, ale zaskakuje.

Wiele warunków: & i | (nie &&)

Łącz warunki przez & (AND) i | (OR). Każdy warunek dostaje własne, pełne porównanie:

Pułapka: R ma też && i ||, a tutaj nie są one wymienne z & i |. Formy podwójne działają na pojedynczych wartościach (istnieją dla warunków if); gdy dostaną całe kolumny, współczesny R (4.3+) zatrzymuje się z błędem w rodzaju 'length = 5' in coercion to 'logical(1)', a starszy R po cichu porównywał tylko pierwszy wiersz, co jest chyba jeszcze gorsze. W nawiasach zawsze używaj pojedynczych & i |. Pełne omówienie tej różnicy znajdziesz w artykule o operatorach.

%in%: dopasowanie do zbioru wartości

Gdy kolumna ma pasować do dowolnej z kilku wartości, nie łącz == przez |, tylko użyj %in%:

x %in% set zwraca TRUE wszędzie tam, gdzie x jest jedną z wartości w set. Czyta się to lepiej niż status == "pending" | status == "shipped", działa dla dowolnej liczby wartości i łatwo to zanegować: !(orders$status %in% c("refunded")).

Wybieranie kolumn

Miejsce na kolumny w nawiasach przyjmuje nazwy lub pozycje:

Dwie uwagi. Wybór po nazwie przetrwa zmianę kolejności kolumn; wybór po pozycji (scores[, c(1, 3)]) psuje się w dniu, w którym ktoś wstawi nową kolumnę. A prośba o jedną kolumnę zwraca zwykły wektor, a nie ramkę danych, dlatego drugie print() pokazuje 91 88 bez otaczającej tabeli. Gdy chcesz zachować kształt ramki danych, dodaj drop = FALSE: scores[, "score", drop = FALSE].

subset(): przyjazna jednolinijkowa funkcja bazowego R

Bazowy R ma funkcję opakowującą, która obsługuje wiersze i kolumny jednym czytelnym wywołaniem, bez $ i bez pilnowania przecinków:

Wewnątrz subset() piszesz gołe nazwy kolumn (score, nie scores$score), a funkcja obliczy je na ramce danych. To tak zwana niestandardowa ewaluacja (non-standard evaluation) i ma udokumentowane zastrzeżenie: rozwiązuje nazwy w czasie wykonania w sposób, który źle działa wewnątrz własnych funkcji (zmienna score w twojej funkcji może zostać przesłonięta przez kolumnę score). Zasada wprost z ?subset: świetne w konsoli, unikaj w programowaniu i tam używaj indeksowania nawiasami.

Pułapka z NA

Porównanie z NA daje NA, a nie FALSE, a filtrowanie nawiasami zamienia wiersze z NA w masce na wiersze pełne NA:

Pierwszy wynik zawiera śmieciowy wiersz z NA, bo warunek dla wiersza 2 nie był ani TRUE, ani FALSE. Rozwiązaniem jest jawne wymaganie !is.na(). subset() i filter() z dplyr po cichu usuwają wiersze z warunkiem NA. To wygodne, ale warto wiedzieć, że tak się dzieje. Dlaczego NA tak się rozprzestrzenia, wyjaśnia artykuł o brakujących wartościach.

Sposób dplyr: filter() i select()

Pakiet dplyr dzieli zadanie na dwa czasowniki, filter() dla wierszy i select() dla kolumn, z gołymi nazwami kolumn i bez powtarzania df$ (statycznie, bo piaskownica uruchamia tylko bazowy R):

library(dplyr)

scores |> filter(score > 80)
scores |> filter(score > 80, team == "red")     # comma = AND
scores |> filter(status %in% c("pending", "shipped"))
scores |> select(name, score)
scores |> filter(team == "red") |> select(name, score)

filter() automatycznie usuwa wiersze z warunkiem NA i zawsze zwraca ramkę danych (nigdy goły wektor), co usuwa obie pułapki bazowego R opisane wyżej. Ceną jest zależność od pakietu i te same zastrzeżenia dotyczące niestandardowej ewaluacji co przy subset(). Pełny przegląd czasowników znajdziesz we wprowadzeniu do dplyr.

Co warto zapamiętać

  • df[condition, ] to podstawowy idiom, a przecinek jest obowiązkowy.
  • Łącz warunki pojedynczymi & i |; && zgłasza błąd na wektorach.
  • %in% wygrywa z łańcuchem == przy dopasowywaniu zbioru wartości.
  • Wybieraj kolumny po nazwie i pamiętaj, że pojedyncze kolumny spadają do wektorów, chyba że użyjesz drop = FALSE.
  • subset() to wygodna jednolinijkowa funkcja do konsoli; nawiasy to wersja do programowania.
  • Porównania z NA tworzą w nawiasach wiersze widma; zabezpiecz się przez !is.na().

Dalej: dodawanie i przekształcanie kolumn, czyli df$new <- ..., ifelse() i mutate() z dplyr.

Najczęściej zadawane pytania

Jak przefiltrować wiersze ramki danych w R?

Wstaw warunek logiczny na pozycję wierszy w nawiasach: df[df$score > 80, ]. Warunek daje wektor TRUE/FALSE, a R zostawia wiersze z TRUE. Przecinek jest ważny: oddziela filtr wierszy od (pustego) filtra kolumn. subset(df, score > 80) robi to samo przy mniejszej ilości pisania.

Jak filtrować z wieloma warunkami w R?

Łącz warunki przez & (AND) i | (OR): df[df$score > 80 & df$team == "red", ]. Używaj pojedynczego &, nie &&: podwójna forma działa tylko na pojedynczych wartościach i we współczesnym R zgłasza błąd na wektorach.

Czym różni się subset() od filtrowania nawiasami w R?

Zostawiają te same wiersze, z dwiema różnicami: subset() po cichu usuwa wiersze, w których warunek daje NA (nawiasy zachowują je jako wiersze wypełnione NA), a subset() korzysta z niestandardowej ewaluacji: piszesz gołe nazwy kolumn, co jest wygodne w konsoli, ale zawodne wewnątrz własnych funkcji.

Jak przefiltrować wiersze, w których kolumna pasuje do listy wartości?

Użyj %in%: df[df$team %in% c("red", "blue"), ] zostawia wiersze, w których team to dowolna z wymienionych wartości. Zastępuje łańcuch porównań == połączonych przez | i w przeciwieństwie do == nigdy nie zwraca NA.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ