比较Python Pandas DataFrames以匹配行

时间:2015-04-06 01:30:50

标签: python pandas rows matching

我在Pandas中有这个DataFrame(df1):

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

我也试过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

是否可以通过将数据框与其他数据框的行进行比较来搜索DataFrame中的一组行?

编辑: 如果这些行也出现在df2

中,是否可以删除df1

2 个答案:

答案 0 :(得分:36)

问题的一个可能解决方案是使用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

然后我们可以在两个数据帧之间使用common_cols = list(set(df1.columns) & set(df2.columns))查看公共列,然后合并:

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

编辑:新问题(评论),确定了df2中也存在于第一个数据框(df1)中的行,是否可以获取pd.merge()的结果然后从df2中删除也存在于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'])]并未考虑所有类型的情况。请考虑以下DataFrame:

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

使用上面的DataFrames,目标是从df2中删除也存在于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

这是因为A列中的值1在交叉点DataFrame(即(1,0,2,3))和df2中都找到,因此同时删除了(1,0,2,3)和(1) ,1,1,1)。这是无意的,因为行(1,1,1,1)不在df1中,不应删除。

我认为以下内容将提供解决方案。它创建了一个虚拟列,稍后用于将DataFrame子集化为所需的结果:

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)

答案 1 :(得分:8)