2017-12-12 2 views
2

Ich möchte einen Datenrahmen durch eine Reihe von benutzerdefinierten Spalten und Werte filtern.Datenrahmen dynamische Filterung

Beispieldaten: test

col1 col2 col3 
1 1 a 4 
2 2 b 5 
3 3 c 6 
4 3 c 7 

Wenn der Benutzer angegeben c("col1", "col2") verwenden Wert zu filtern c(3, "c") ich die zurückgegebenen Ergebnisse erwarten die letzten beiden Zeilen sein.

test[test[c("col1", "col2")]==c(3,"c"),] 

aber es folgende Ergebnisse gibt:

Ich habe folgendes versucht

col1 col2 col3 
3 3 c 6 
NA NA NA NA 

Jede Idee, warum die letzte Zeile ist alles NA? Und wie kann ich das beheben?

Antwort

4

Wir müssen den Rowindex richtig bekommen. Es könnte entweder ein vector von logical oder numeric Index sein. Im Vergleich (es ist besser, list anstelle von c zu verwenden, da wir keine Klassen mischen wollen) erhalten wir eine logische matrix, die auf einen Vektor reduziert werden muss. Eine Option ist rowSums und prüfen, ob die Summe jeder Zeile 2, dh die Anzahl der Spalten gleich ist zum Vergleich herangezogen und Teilmenge der Zeilen

test[rowSums(test[c("col1", "col2")] == list(3, 'c'))==2,] 
# col1 col2 col3 
#3 3 c 6 
#4 3 c 7 

Nun schauen wir uns den Unterschied in der Herangehensweise mit c und list

test[c("col1", "col2")]==c(3,"c") 
# col1 col2 
#1 FALSE FALSE 
#2 FALSE FALSE 
#3 TRUE FALSE 
#4 FALSE TRUE 

Hier wird Elemente durch Rückführung der Elemente einer nach dem anderen, dh für ‚spalte1‘ zu vergleichen, wird 1 mit 3 verglichen, dann 2 mit ‚C‘, gefolgt von der Rückführung des Vektors, dh 3 mit 3 und wieder die nächsten 3 wit h 'c'. Es folgt der gleiche Weg mit der nächsten Spalte.

test[c("col1", "col2")]== list(3,"c") 
# col1 col2 
#1 FALSE FALSE 
#2 FALSE FALSE 
#3 TRUE TRUE #note the change 
#4 TRUE TRUE 

Während hier, vergleicht er die ersten Spaltenelemente mit dem ersten Elemente der list dh das list Element repliziert wird oder anschließend recycelt, indem die zweite Säule, die mit zweiten list Elemente Vergleich

anzumerken, dass es 8 ist Elemente, dh 4 pro Spalte.Es kommt also vor, dass es im ersten Fall 2 TRUE-Elemente gibt und im zweiten Fall 4 TRUE und es gibt 8 Elemente, aber wir haben nur 4 Zeilen. Wenn also die zweite Spalte der logischen Matrix keine Zeilen enthält, wird sie erstellt die NA Zeile für den wahren Wert

test[test[c("col1", "col2")]==c(3,"c"),] 
# col1 col2 col3 
#3  3 c 6 
#NA NA <NA> NA 

Ebenso gibt es 2 TRUE in jeder Spalte, wodurch wiederum die Anzahl der NA Zeilen verdoppelt

test[test[c("col1", "col2")]==list(3,"c"),] 
# col1 col2 col3 
#3  3 c 6 
#4  3 c 7 
#NA  NA <NA> NA 
#NA.1 NA <NA> NA 

Angenommen, wir vergleiche auch die 3. Spalte, dann gibt wird eine zusätzliche NA Zeile sein

test[test==list(3,"c", 5),] 
#  col1 col2 col3 
#3  3 c 6 
#4  3 c 7 
#NA  NA <NA> NA 
#NA.1 NA <NA> NA 
#NA.2 NA <NA> NA 
Hier
+1

Danke für die ausführliche Erklärung. – noname

0

meine dplyr Lösung:

library(dplyr) 
test %>% 
    rowwise() %>% 
    mutate(con = if_else(col1 %in% 3 & col2 %in% "c",TRUE, FALSE)) %>% 
    filter(con == TRUE) %>% 
    select(-con) %>% 
    ungroup 
0

Eine weitere dplyr Version mit tidyeval

library(dplyr) 
column_equals <- function(df, ...) { 
    conditions <- quos(...) 
    df %>% 
    filter(!!!conditions) 
} 

test %>% 
    column_equals(col1 == 3 & col2 == "c") 
0

Dies ist akrun answer zu einem realen Welt Beispiel auszudehnen, in denen Daten in den Spalten gesucht NA enthalten. In diesem Fall erhält man "NA" -Zeilen in der Endausgabe, was unordentlich ist und die Downstream-Analyse verwirren kann. In diesem Beispiel habe ich die Spalten num und col2 mit den Werten NA gespickt. Nur die NA in col2 hat Wirkung, weil sie in der Suche verwendet wird. Die Wurzel dieses Problems ist etwas, das funktioniert mit NA gibt NA (z NA == 1 = NA), mit Ausnahme is.na

mydf <- data.frame(num = c(1:3, NA, 5, 6), col1 = c('a', 'b', 'a', 'b', 'c', 'd'), col2 = c('A', 'b', 'A', 'B', NA, 'D'), col3 = as.character(letters)[1:6]) 
getrows = mydf[c("col2", "col1")] == list("A", "a") # Mixing up column orders for fun 
getrows = rowSums(getrows) == 2 
getrows 
mydf[getrows, ] # This gives undesired NA rows 
# Use which to get exact row number 
which(getrows) 
mydf[which(getrows),] 

den Ausgang unten vergleichen:

> mydf <- data.frame(num = c(1:3, NA, 5, 6), col1 = c('a', 'b', 'a', 'b', 'c', 'd'), col2 = c('A', 'b', 'A', 'B', NA, 'D'), col3 = as.character(letters)[1:6]) 
> getrows = mydf[c("col2", "col1")] == list("A", "a") # Mixing up column orders for fun 
> getrows = rowSums(getrows) == 2 
> getrows 
[1] TRUE FALSE TRUE FALSE NA FALSE 
> mydf[getrows, ] # This gives undesired NA rows 
    num col1 col2 col3 
1 1 a A a 
3 3 a A c 
NA NA <NA> <NA> <NA> 
> # Use which to get exact row number 
> which(getrows) 
[1] 1 3 
> mydf[which(getrows),] 
    num col1 col2 col3 
1 1 a A a 
3 3 a A c 
Verwandte Themen