设置数据框之间列的差异

时间:2014-03-01 02:30:19

标签: python pandas

注意:此问题的灵感来自其他帖子中讨论的想法:DataFrame algebra in Pandas

假设我有两个数据框AB,而对于某些列col_name,它们的值为:

A[col_name]   |  B[col_name]  
--------------| ------------
1             |  3
2             |  4
3             |  5
4             |  6

我想根据A计算Bcol_name之间的设置差异。此操作的结果应为:

A的行A[col_name]B[col_name]中的任何条目都不匹配。

以下是上述示例的结果(显示A的其他列):

A[col_name] | A[other_column_1] | A[other_column_2]  
------------+-------------------|------------------ 
1           |    'foo'          |  'xyz'            ....
2           |    'bar'          |  'abc'

请注意,A[col_name]B[col_name]中的某些条目可能包含值np.NaN。我想将这些条目视为未定义但不同,即设置差异应该返回

我怎么能在熊猫中做到这一点? (概括为多列的差异也很好)

2 个答案:

答案 0 :(得分:4)

一种方法是使用系列isin方法:

In [11]: df1 = pd.DataFrame([[1, 'foo'], [2, 'bar'], [3, 'meh'], [4, 'baz']], columns = ['A', 'B'])

In [12]: df2 = pd.DataFrame([[3, 'a'], [4, 'b']], columns = ['A', 'C'])

现在,您可以检查df1['A']中的每个项目是否属于df2['A']

In [13]: df1['A'].isin(df2['A'])
Out[13]:
0    False
1    False
2     True
3     True
Name: A, dtype: bool

In [14]: df1[~df1['A'].isin(df2['A'])]  # not in df2['A']
Out[14]:
   A    B
0  1  foo
1  2  bar

我认为这也符合您对NaN的要求:

In [21]: df1 = pd.DataFrame([[1, 'foo'], [np.nan, 'bar'], [3, 'meh'], [np.nan, 'baz']], columns = ['A', 'B'])

In [22]: df2 = pd.DataFrame([[3], [np.nan]], columns = ['A'])

In [23]: df1[~df1['A'].isin(df2['A'])]
Out[23]:
    A     B
0 1.0   foo
1 NaN   bar
3 NaN   baz

注意:对于大型帧,可能值得将这些列作为索引(以the other question中所述的方式执行连接)。

更一般地

在两个或多个列上合并的一种方法是使用虚拟列:

In [31]: df1 = pd.DataFrame([[1, 'foo'], [np.nan, 'bar'], [4, 'meh'], [np.nan, 'eurgh']], columns = ['A', 'B'])

In [32]: df2 = pd.DataFrame([[np.nan, 'bar'], [4, 'meh']], columns = ['A', 'B'])

In [33]: cols = ['A', 'B']

In [34]: df2['dummy'] = df2[cols].isnull().any(1)  # rows with NaNs in cols will be True

In [35]: merged = df1.merge(df2[cols + ['dummy']], how='left')

In [36]: merged
Out[36]:
    A      B  dummy
0   1    foo    NaN
1 NaN    bar   True
2   4    meh  False
3 NaN  eurgh    NaN

布尔值出现在df2中,True在其中一个合并列中有一个NaN。按照你的规范,我们应该删除那些错误的:

In [37]: merged.loc[merged.dummy != False, df1.columns]
Out[37]:
    A      B
0   1    foo
1 NaN    bar
3 NaN  eurgh

不雅。

答案 1 :(得分:0)

这是一个同样优雅的选项,因为它会将NaN值预先映射到其他值(0),以便它们可以用作指数:

def left_difference(L, R, L_on, R_on, NULL_VALUE):
  L[L_on] = L[L_on].fillna(NULL_VALUE)
  L.set_index(L_on, inplace=True)

  R[R_on] = R[R_on].fillna(NULL_VALUE)
  R.set_index(R_on, inplace=True)

  # MultiIndex difference:
  diff = L.ix[L.index - R.index]
  diff = diff.reset_index()

  return diff

为了使这项工作更加顺利,NULL_VALUE应该是L_onR_on未使用的值。