Menu

Daten filtern und subsetten in R (subset, [ ], dplyr filter)

Alle Wege, um genau die Zeilen und Spalten zu behalten, die du willst: logische Masken mit Klammern, der subset()-Einzeiler, %in%, NA-Fallen und dplyr's filter() und select().

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

Zeilen filtern: die logische Maske

Um einen Data Frame in R zu filtern, setzt man eine Bedingung an die Zeilenposition der Klammern: df[bedingung, ]. Die Bedingung ergibt einen Vektor aus TRUE/FALSE, einen pro Zeile, und R behält die TRUE-Zeilen:

Lies scores[scores$score > 80, ] von innen nach außen: scores$score > 80 erzeugt TRUE FALSE TRUE TRUE FALSE, und die Klammern behalten die Zeilen 1, 3 und 4. Das abschließende Komma ist nicht optional. Klammern auf einem Data Frame nehmen [zeilen, spalten]; den Spalten-Slot leer zu lassen bedeutet "alle Spalten". Vergisst man das Komma, indexiert man stattdessen Spalten - einer der häufigsten Anfängerfehler in R.

Beachte, dass die ausgegebenen Zeilennummern 1 3 4 sind, nicht 1 2 3 - das Filtern behält die ursprünglichen Zeilenlabels. Harmlos, aber es überrascht viele.

Mehrere Bedingungen: & und | (nicht &&)

Kombiniere Bedingungen mit & (UND) und | (ODER). Jede Bedingung bekommt ihren eigenen vollständigen Vergleich:

Die Falle: R hat auch && und ||, und die sind hier nicht mit & und | austauschbar. Die doppelten Formen arbeiten auf Einzelwerten (sie existieren für if-Bedingungen); bekommen sie ganze Spalten, bricht modernes R (4.3+) mit einem Fehler wie 'length = 5' in coercion to 'logical(1)' ab, und älteres R verglich stillschweigend nur die erste Zeile - was wohl noch schlimmer ist. Innerhalb von Klammern immer das einfache & und |. Die Operatoren-Doku behandelt den Unterschied vollständig.

%in%: gegen eine Menge von Werten abgleichen

Wenn eine Spalte einem von mehreren Werten entsprechen soll, kette nicht == mit | - verwende %in%:

x %in% set gibt überall dort TRUE zurück, wo x einer der Werte in set ist. Es liest sich besser als status == "pending" | status == "shipped", skaliert auf beliebig viele Werte und lässt sich sauber negieren: !(orders$status %in% c("refunded")).

Spalten auswählen

Der Spalten-Slot der Klammern nimmt Namen oder Positionen:

Zwei Anmerkungen. Auswahl nach Name übersteht eine Umsortierung der Spalten; Auswahl nach Position (scores[, c(1, 3)]) geht an dem Tag kaputt, an dem jemand eine Spalte einfügt. Und die Abfrage einer einzelnen Spalte gibt einen einfachen Vektor zurück, keinen Data Frame - deshalb zeigt das zweite print() 91 88 ohne Tabelle drumherum. Wenn du die Data-Frame-Form behalten musst, ergänze drop = FALSE: scores[, "score", drop = FALSE].

subset(): der freundliche Base-Einzeiler

Base R liefert einen Wrapper mit, der Zeilen und Spalten in einem lesbaren Aufruf erledigt - ohne $, ohne Komma-Buchhaltung:

Innerhalb von subset() schreibt man nackte Spaltennamen (score, nicht scores$score) - sie werden gegen den Data Frame ausgewertet. Das nennt sich Non-Standard Evaluation, und es kommt mit einem dokumentierten Vorbehalt: Namen werden zur Laufzeit auf eine Weise aufgelöst, die sich in eigenen Funktionen fehlverhält (eine Variable namens score in deiner Funktion kann von einer Spalte namens score verdeckt werden). Die Faustregel, direkt aus ?subset: interaktiv großartig, beim Programmieren vermeiden - dort Klammer-Indexierung verwenden.

Die NA-Falle

Ein Vergleich mit NA ergibt NA, nicht FALSE - und Klammer-Filterung behält Zeilen mit NA-Maske als Zeilen voller NA:

Das erste Ergebnis enthält eine Müllzeile aus NAs, weil die Bedingung von Zeile 2 weder TRUE noch FALSE war. Die Lösung ist, !is.na() explizit zu verlangen. subset() und dplyr's filter() verwerfen Zeilen mit NA-Bedingung beide stillschweigend - bequem, aber man sollte wissen, dass es passiert. Die Doku zu fehlenden Werten erklärt, warum sich NA so ausbreitet.

Der dplyr-Weg: filter() und select()

Das dplyr-Paket teilt die Aufgabe in zwei Verben - filter() für Zeilen, select() für Spalten - mit nackten Spaltennamen und ohne df$-Wiederholung (statisch; die Sandbox führt nur Base R aus):

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() verwirft Zeilen mit NA-Bedingung automatisch und gibt immer einen Data Frame zurück (nie einen nackten Vektor), was beide Base-Stolperfallen von oben beseitigt. Der Preis ist eine Paketabhängigkeit und dieselben Non-Standard-Evaluation-Vorbehalte wie bei subset() - siehe die dplyr-Einführung für die vollständige Verben-Tour.

Was du mitnimmst

  • df[bedingung, ] ist das grundlegende Idiom - und das Komma ist Pflicht.
  • Bedingungen mit einfachem & und | kombinieren; && wirft bei Vektoren einen Fehler.
  • %in% schlägt verkettete == beim Abgleich gegen eine Wertemenge.
  • Spalten nach Name auswählen, und daran denken: Einzelspalten fallen auf Vektoren zurück, außer mit drop = FALSE.
  • subset() ist der angenehme interaktive Einzeiler; Klammern sind der programmierbare.
  • Vergleiche mit NA erzeugen in Klammern Geisterzeilen - mit !is.na() absichern.

Als Nächstes: Spalten hinzufügen und transformieren - df$new <- ..., ifelse() und dplyr's mutate().

Häufig gestellte Fragen

Wie filtere ich Zeilen eines Data Frames in R?

Setze eine logische Bedingung an die Zeilenposition der Klammern: df[df$score > 80, ]. Die Bedingung erzeugt einen TRUE/FALSE-Vektor, und R behält die TRUE-Zeilen. Das Komma ist wichtig - es trennt den Zeilenfilter vom (leeren) Spaltenfilter. subset(df, score > 80) tut dasselbe mit weniger Tipparbeit.

Wie filtere ich mit mehreren Bedingungen in R?

Kombiniere Bedingungen mit & (UND) und | (ODER): df[df$score > 80 & df$team == "red", ]. Verwende das einfache &, nicht && - die doppelte Form funktioniert nur auf Einzelwerten und wirft in modernem R bei Vektoren einen Fehler.

Was ist der Unterschied zwischen subset() und Klammer-Filterung in R?

Sie behalten dieselben Zeilen, mit zwei Unterschieden: subset() verwirft stillschweigend Zeilen, bei denen die Bedingung NA ist (Klammern behalten sie als NA-gefüllte Zeilen), und subset() nutzt Non-Standard Evaluation - man schreibt nackte Spaltennamen, was interaktiv bequem, aber in eigenen Funktionen unzuverlässig ist.

Wie filtere ich Zeilen, in denen eine Spalte einer Liste von Werten entspricht?

Verwende %in%: df[df$team %in% c("red", "blue"), ] behält Zeilen, deren team einer der aufgeführten Werte ist. Es ersetzt eine Kette von ==-Vergleichen, die mit | verbunden sind, und gibt anders als == nie NA zurück.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S