2013-04-22 70 views
14

我有2個數據幀df1df2減去數據幀的操作

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 

我需要執行這兩個數據幀的設置操作。我用merge(df1,df2,all=TRUE)merge(df1,df2,all=FALSE)方法得到這些數據幀的並集和交集並得到了所需的輸出。獲得這些數據幀減去的功能是什麼,即所有位置都存在於一個數據幀中,而不是另一個數據幀中。我需要以下輸出。

c1 c2 
1 a 1 
2 b 2 
+1

你想要在df1中獲取不在df2中的行和不在df1中的df2中的**行? – juba 2013-04-22 09:39:19

+0

@juba,我相信這是'setdiff'的更多,但'data.frame's – Arun 2013-04-22 09:43:07

+0

是的,這就是我的想法,但給出的結果不是'setdiff'。這就是爲什麼我問這個問題:) – juba 2013-04-22 09:44:02

回答

24

我記得幾個月前剛剛通過這個確切問題。管理通過我的Evernote單行進行篩選。

注意:這是而不是我的解決方案。信用是寫給誰寫的(我目前似乎找不到)。

如果您不擔心rownames那麼你可以做:

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

編輯:一個data.table解決方案:

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

或更好的一行(從V1 .9.6+):

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

這將返回df1中的所有行,其中df2$c1df1$c1不匹配。

+0

這是完美的工作。謝謝 – 2013-04-22 10:14:43

+2

這個'data.table'解決方案比''setdiff''或'%in%'查找要快得多,謝謝! – daroczig 2016-05-13 21:20:40

4

可以創建標識符columnas然後子集:

例如

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 

然後你子集多麼希望:

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

這是不可能的..bcoz給定的數據只是一個示例dataframes.the實際數據幀包含大量的行。所以用這種方法對象尺寸可能會變得很大。 – 2013-04-22 09:42:51

+1

@DinoopNair然後你可以用'all.x = TRUE'和'indf2'上的子集合並? – juba 2013-04-22 09:56:54

1

如果你不使用任何d2實際數據的計劃,那麼你不需要merge都:

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

我需要檢查兩列中的值。 – 2013-04-22 09:52:08

7

我更喜歡sqldf包:

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

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

您可以在兩列檢查值,子集是這樣的(只是添加另一種解決方案):

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

一個問題與https://stackoverflow.com/a/16144262/2055486是它假定沒有數據幀已經複製了行。以下函數刪除了該限制,並且還可以在x或y中使用任意用戶定義的列。

該實施方式使用類似的想法來實施duplicated.data.frame將列與分隔符連接在一起。duplicated.data.frame使用"\r",如果條目已嵌入"\r"字符,則可能導致衝突。這使用了輸入數據出現的機率較低的ASCII record separator"\30"

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

這是我的嘗試:我有2個數據幀DF2和df_name

DF2
NAME2年齡
b 10分配
-C 20
d 30

df_name
名稱年齡愛好
10舞蹈
B 20唱
C 30的遊戲

要找到df_name減號DF2:

1.Merge 2個dataframes。
dfmerge < - 合併(X = df_name,Y = DF2,by.x = C( 「名稱」),by.y = C( 「NAME2」),所有= TRUE)

dfmerge

名稱age.x嗜好age.y
1 10舞蹈NA
2 b 20 10唱
3 -C 30播放20
4 d NA 30

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

名age.x愛好age.y
1 10舞蹈NA