2013-04-22 15 views
14

Ho 2 frame di dati df1 e df2.meno funzionamento dei frame di dati

df1 <- data.frame(c1=c("a","b","c","d"),c2=c(1,2,3,4)) 
df2 <- data.frame(c1=c("c","d","e","f"),c2=c(3,4,5,6)) 
> df1 
    c1 c2 
1 a 1 
2 b 2 
3 c 3 
4 d 4 
> df2 
    c1 c2 
1 c 3 
2 d 4 
3 e 5 
4 f 6 

Ho bisogno di eseguire il funzionamento impostato di questi 2 frame di dati. Ho utilizzato il metodo merge(df1,df2,all=TRUE) e merge(df1,df2,all=FALSE) per ottenere l'unione e l'intersezione di questi frame di dati e ottenuto l'output richiesto. Qual è la funzione per ottenere il meno di questi frame di dati, cioè tutte le posizioni esistenti su un frame di dati ma non l'altro? Ho bisogno del seguente risultato.

c1 c2 
1 a 1 
2 b 2 
+1

Do you vuoi ottenere le linee in df1 che non sono in df2 ** e ** in df2 che non sono in df1? – juba

+0

@juba, credo che questo sia più di 'setdiff' ma per' data.frame's – Arun

+0

Sì, questo è quello che pensavo, ma il risultato dato non è un 'setdiff'. Ecco perché chiedo la domanda :) – juba

risposta

24

Ricordo di aver ricevuto questo numero esatto alcuni mesi fa. Riuscito a setacciare i miei one-liner Evernote.

Nota: Questo è non la mia soluzione. Il merito va a chiunque l'abbia scritto (che non riesco a trovare al momento).

Se non ti preoccupare rownames allora si può fare:

df1[!duplicated(rbind(df2, df1))[-seq_len(nrow(df2))], ] 
# c1 c2 
# 1 a 1 
# 2 b 2 

Edit: A data.table soluzione:

dt1 <- data.table(df1, key="c1") 
dt2 <- data.table(df2) 
dt1[!dt2] 

o meglio one-liner (da v1 .9.6+):

setDT(df1)[!df2, on="c1"] 

Restituisce tutte le righe in df1 dove df2$c1 non corrisponde a df1$c1.

+0

funziona perfettamente. Grazie –

+2

Questa soluzione 'data.table' è molto più veloce di una ricerca' setdiff' o '% in %', grazie! – daroczig

4

È possibile creare columnas identificatore poi sottoinsieme:

esempio

df1 <- data.frame(c1=c("a","b","c","d"),c2=c(1,2,3,4), indf1 = rep("Y",4)) 
df2 <- data.frame(c1=c("c","d","e","f"),c2=c(3,4,5,6),indf2 = rep("Y",4)) 
merge(df1,df2) 
# c1 c2 indf1 indf2 
#1 c 3  Y  Y 
#2 d 4  Y  Y 

bigdf <- merge(df1,df2,all=TRUE) 
# c1 c2 indf1 indf2 
#1 a 1  Y <NA> 
#2 b 2  Y <NA> 
#3 c 3  Y  Y 
#4 d 4  Y  Y 
#5 e 5 <NA>  Y 
#6 f 6 <NA>  Y 

Poi in subset come si desidera:

bigdf[is.na(bigdf$indf1) ,] 
# c1 c2 indf1 indf2 
#5 e 5 <NA>  Y 
#6 f 6 <NA>  Y 

bigdf[is.na(bigdf$indf2) ,] #<- output you requested those not in df2 
# c1 c2 indf1 indf2 
#1 a 1  Y <NA> 
#2 b 2  Y <NA> 
+0

questo non è possibile..bcoz i dati dati sono solo un esempio di dataframes.the effettivo i frame di dati contengono un'enorme quantità di righe. quindi la dimensione dell'oggetto può diventare molto grande con questo metodo. –

+1

@DinoopNair Quindi si può fare unire con 'all.x = TRUE' e sottoinsieme su' indf2'? – juba

1

Se non avete intenzione di utilizzare uno qualsiasi dei dati effettivi in ​​d2, allora non è necessario merge affatto:

df1[!(df1$c1 %in% df2$c1), ] 
+0

ho bisogno di controllare i valori in entrambe le colonne. –

7

Preferisco sqldf pacchetto:

require(sqldf) 
sqldf("select * from df1 except select * from df2") 

## c1 c2 
## 1 a 1 
## 2 b 2 
1

È possibile verificare i valori in entrambe le colonne e dal sottoinsieme simili (semplicemente aggiungendo un'altra soluzione):

na.omit(df1[ sapply(1:ncol(df1) , function(x) ! df1[,x] %in% df2[,x]) , ]) 
# c1 c2 
#1 a 1 
#2 b 2 
0

Un problema con https://stackoverflow.com/a/16144262/2055486 è assume né frame di dati righe già ha duplicato. La seguente funzione rimuove questa limitazione e funziona anche con colonne definite dall'utente arbitrarie in x o y.

L'implementazione utilizza un'idea simile all'implementazione di duplicated.data.frame nel concatenare le colonne con un separatore.duplicated.data.frame utilizza "\r", che può causare conflitti se le voci hanno incorporato i caratteri "\r". Questo utilizza lo"\30" che avrà una probabilità molto minore di apparire nei dati di input.

setdiff.data.frame <- function(x, y, 
    by = intersect(names(x), names(y)), 
    by.x = by, by.y = by) { 
    stopifnot(
    is.data.frame(x), 
    is.data.frame(y), 
    length(by.x) == length(by.y)) 

    !do.call(paste, c(x[by.x], sep = "\30")) %in% do.call(paste, c(y[by.y], sep = "\30")) 
} 

# Example usage 
# remove all 4 or 6 cylinder 4 gear cars or 8 cylinder 3 gear rows 
to_remove <- data.frame(cyl = c(4, 6, 8), gear = c(4, 4, 3)) 
mtcars[setdiff.data.frame(mtcars, to_remove), ] 
#>     mpg cyl disp hp drat wt qsec vs am gear carb 
#> Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1 
#> Valiant  18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1 
#> Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1 
#> Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2 
#> Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2 
#> Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4 
#> Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6 
#> Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8 

# with differing column names 
to_remove2 <- data.frame(a = c(4, 6, 8), b = c(4, 4, 3)) 
mtcars[setdiff.data.frame(mtcars, to_remove2, by.x = c("cyl", "gear"), by.y = c("a", "b")), ] 
#>     mpg cyl disp hp drat wt qsec vs am gear carb 
#> Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1 
#> Valiant  18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1 
#> Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1 
#> Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2 
#> Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2 
#> Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4 
#> Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6 
#> Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8 
0

Questo è quello che ho cercato: ho 2 dati cornici DF2 e df_name

DF2
età nome2
b 10
c 20
d 30

df_name
nome età hobby
un 10 ballo
b 20 cantare
c 30 gioco

Per trovare df_name MENO DF2:

1.Merge i 2 dataframes.
dfmerge < - merge (x = df_name, y = DF2, by.x = c ("nome"), by.y = c ("nome2"), tutti = TRUE)

dfmerge

nome age.x passatempo age.y
1 a 10 di danza NA
2 b 20 cantare 10
3 c 30 gioco 20
4 d NA 30

.210

dfmerge [is.na (dfmerge $ age.y),]

nome age.x passatempo age.y
1 a 10 di danza NA

Problemi correlati