2015-04-06 299 views
17

我有這樣的數據框(df1):比較Python的熊貓DataFrames用於匹配行的熊貓

df1 = pd.DataFrame(np.random.rand(10,4),columns=list('ABCD')) 
print df1 

     A   B   C   D 
0.860379 0.726956 0.394529 0.833217 
0.014180 0.813828 0.559891 0.339647 
0.782838 0.698993 0.551252 0.361034 
0.833370 0.982056 0.741821 0.006864 
0.855955 0.546562 0.270425 0.136006 
0.491538 0.445024 0.971603 0.690001 
0.911696 0.065338 0.796946 0.853456 
0.744923 0.545661 0.492739 0.337628 
0.576235 0.219831 0.946772 0.752403 
0.164873 0.454862 0.745890 0.437729 

我想檢查是否從另一個數據框(df2)的任何行(所有列)存在於df1。這是df2

df2 = df1.ix[4:8] 
df2.reset_index(drop=True,inplace=True) 
df2.loc[-1] = [2, 3, 4, 5] 
df2.loc[-2] = [14, 15, 16, 17] 
df2.reset_index(drop=True,inplace=True) 
print df2 

      A   B   C   D 
    0.855955 0.546562 0.270425 0.136006 
    0.491538 0.445024 0.971603 0.690001 
    0.911696 0.065338 0.796946 0.853456 
    0.744923 0.545661 0.492739 0.337628 
    0.576235 0.219831 0.946772 0.752403 
    2.000000 3.000000 4.000000 5.000000 
    14.000000 15.000000 16.000000 17.000000 

我試圖用df.lookup在一次搜索一行。我就是這麼做的:

list1 = df2.ix[0].tolist() 
cols = df1.columns.tolist() 
print df1.lookup(list1, cols) 

,但我得到這個錯誤信息:

File "C:\Users\test.py", line 19, in <module> 
    print df1.lookup(list1, cols) 
    File "C:\python27\lib\site-packages\pandas\core\frame.py", line 2217, in lookup 
    raise KeyError('One or more row labels was not found') 
KeyError: 'One or more row labels was not found' 

我也嘗試使用.all()

print (df2 == df1).all(1).any() 

,但我得到這個錯誤信息:

File "C:\Users\test.py", line 12, in <module> 
    print (df2 == df1).all(1).any() 
    File "C:\python27\lib\site-packages\pandas\core\ops.py", line 884, in f 
    return self._compare_frame(other, func, str_rep) 
    File "C:\python27\lib\site-packages\pandas\core\frame.py", line 3010, in _compare_frame 
    raise ValueError('Can only compare identically-labeled ' 
ValueError: Can only compare identically-labeled DataFrame objects 

我也是trie d isin()這樣的:

print df2.isin(df1) 

,但我得到False無處不在,這是不正確的:

A  B  C  D 
False False False False 
False False False False 
False False False False 
False False False False 
False False False False 
False False False False 
False False False False 
False False False False 
False False False False 
False False False False 

是否可以搜索在數據幀一組行,通過比較其他數據幀的行?

編輯: 如果這些行也存在於df1中,是否可以刪除df2行?

回答

24

您的問題的一種可能的解決方案是使用merge。檢查df1中是否存在來自另一個數據幀(df2)的任何行(所有列)等價於確定這兩個數據幀的交集。

pd.merge(df1, df2, on=['A', 'B', 'C', 'D'], how='inner') 

例如,如果DF1是

A   B   C   D 
0 0.403846 0.312230 0.209882 0.397923 
1 0.934957 0.731730 0.484712 0.734747 
2 0.588245 0.961589 0.910292 0.382072 
3 0.534226 0.276908 0.323282 0.629398 
4 0.259533 0.277465 0.043652 0.925743 
5 0.667415 0.051182 0.928655 0.737673 
6 0.217923 0.665446 0.224268 0.772592 
7 0.023578 0.561884 0.615515 0.362084 
8 0.346373 0.375366 0.083003 0.663622 
9 0.352584 0.103263 0.661686 0.246862 

和DF2被定義爲:這可以通過使用下面的函數來完成

 A   B   C   D 
0 0.259533 0.277465 0.043652 0.925743 
1 0.667415 0.051182 0.928655 0.737673 
2 0.217923 0.665446 0.224268 0.772592 
3 0.023578 0.561884 0.615515 0.362084 
4 0.346373 0.375366 0.083003 0.663622 
5 2.000000 3.000000 4.000000 5.000000 
6 14.000000 15.000000 16.000000 17.000000 

功能pd.merge(df1, df2, on=['A', 'B', 'C', 'D'], how='inner')生產:

 A   B   C   D 
0 0.259533 0.277465 0.043652 0.925743 
1 0.667415 0.051182 0.928655 0.737673 
2 0.217923 0.665446 0.224268 0.772592 
3 0.023578 0.561884 0.615515 0.362084 
4 0.346373 0.375366 0.083003 0.663622 

結果是都在df1和df2中的所有行(所有列)。

如果df1和df2中的列不同,並且只比較列的子集中相同的行值,我們也可以修改此示例。如果我們修改了原來的例子:

df1 = pd.DataFrame(np.random.rand(10,4),columns=list('ABCD')) 
df2 = df1.ix[4:8] 
df2.reset_index(drop=True,inplace=True) 
df2.loc[-1] = [2, 3, 4, 5] 
df2.loc[-2] = [14, 15, 16, 17] 
df2.reset_index(drop=True,inplace=True) 
df2 = df2[['A', 'B', 'C']] # df2 has only columns A B C 

那麼我們可以看看使用兩個dataframes之間common_cols = list(set(df1.columns) & set(df2.columns))公用列然後合併:

pd.merge(df1, df2, on=common_cols, how='inner') 

編輯:新的問題(評論),已經鑑定來自df2的行也出現在第一個數據幀(df1)中,是否有可能取得pd.merge()的結果,然後從df2中刪除同樣出現在df1中的行,其中I也存在於df1中不知道一個簡單的方法來完成從df2中刪除df1中的行的任務。這就是說,你可以使用以下命令:

ds1 = set(tuple(line) for line in df1.values) 
ds2 = set(tuple(line) for line in df2.values) 
df = pd.DataFrame(list(ds2.difference(ds1)), columns=df2.columns) 

有可能存在更好的方法來完成這項任務,但我不知道這樣的方法/函數。

編輯2:如何從df2中刪除也出現在df1中的行,如@WR答案中所示。

提供的方法df2[~df2['A'].isin(df12['A'])]沒有考慮所有類型的情況。考慮以下DataFrames:

DF1:

A B C D 
0 6 4 1 6 
1 7 6 6 8 
2 1 6 2 7 
3 8 0 4 1 
4 1 0 2 3 
5 8 4 7 5 
6 4 7 1 1 
7 3 7 3 4 
8 5 2 8 8 
9 3 2 8 4 

DF2:

A B C D 
0 1 0 2 3 
1 8 4 7 5 
2 4 7 1 1 
3 3 7 3 4 
4 5 2 8 8 
5 1 1 1 1 
6 2 2 2 2 

DF12:

A B C D 
0 1 0 2 3 
1 8 4 7 5 
2 4 7 1 1 
3 3 7 3 4 
4 5 2 8 8 

使用與來自DF2加入行的目標,上述DataFrames也出現在df1中會導致以下結果:

A B C D 
0 1 1 1 1 
1 2 2 2 2 

行(1,1,1,1)和(2,2,2,2)在df2中而不在df1中。不幸的是,使用所提供的方法(df2[~df2['A'].isin(df12['A'])])導致:

A B C D 
6 2 2 2 2 

這種情況發生時,因爲1在列A的值在兩個交叉點數據幀(即,(1,0,2,3))和DF2發現並因此去除(1,0,2,3)和(1,1,1,1)兩者。這是無意的,因爲行(1,1,1,1)不在df1中,因此不應刪除。

我認爲以下將提供一個解決方案。它創建稍後使用數據幀進行子集到所期望的結果虛擬列:

df12['key'] = 'x' 
temp_df = pd.merge(df2, df12, on=df2.columns.tolist(), how='left') 
temp_df[temp_df['key'].isnull()].drop('key', axis=1) 
+0

哦當然!一個SQL'INNER JOIN'。這逃脫了我。一個問題是,我從來沒有使用'JOIN'ing'ON'多列。如果要檢查所有數據框的列,可以用'on = df1.columns'來代替'on = ['A','B','C','D']'嗎? – 2015-04-06 02:37:01

+1

您可以使用'on = list(df1.columns)'或等效的'on = list(df2.columns)'。如果要檢查行是否相同(所有列),則df1和df2中的列必須相同。 – Andrew 2015-04-06 02:55:19

+0

安德魯,最後一個問題(我也將它添加到原始文章中) - 確定了來自'df2'的行也存在於第一個數據框('df1')中,是否有可能將「pd .merge()'然後從'df2'中刪除同樣出現在'df1'中的行? – 2015-04-06 20:40:51

6

@Andrew:我相信我找到了一種方法來丟棄已經存在於另外一個數據幀的行(即回答我的編輯),而不使用循環 - 讓我知道如果你不同意和/或如果我的OP + EDIT沒有明確說明這一點:

這個作品

兩個dataframes列總是相同的 - AB,CD。考慮到這一點,很大程度上基於安德魯的方法,這裏是如何下降,由df2這也存在於df1行:

common_cols = df1.columns.tolist()       #generate list of column names 
df12 = pd.merge(df1, df2, on=common_cols, how='inner')  #extract common rows with merge 
df2 = df2[~df2['A'].isin(df12['A'])] 

3號線執行以下操作:僅

  • 提取行df2中不df1匹配行:
  • 爲了2行是不同的,一個列中的任何一個列必須
    一定是不同的是,對應另一列 列。
  • 在這裏,我拿起列A,使這個比較 - 這是
    可以使用任何列名,但所有的
    列名。

注意:此方法本質上等效於SQL NOT IN()

+0

你無法想象我浪費了多少時間嘗試使用循環來完成此操作 – 2015-04-10 21:55:41

+1

我認爲您的邏輯可能存在問題(儘管我可能會誤解您的預期結果)我已經更新了我的答案 – Andrew 2015-04-11 06:39:16

+0

您是對的,您的問題是更好的解決方案。向我指出這一點。 – 2015-04-12 17:56:35