【问题标题】:Compare rows of two data-frames with unequal lengths比较长度不等的两个数据帧的行
【发布时间】:2017-10-08 19:58:34
【问题描述】:

我对 pandas 还很陌生,希望获得一些关于如何以最佳方式解决问题的反馈。我正在尝试从两个长度不等的数据框中评估两列的值以找到两种情况:

  1. data_set_2 中的 id1 在 data_set_1 中不存在。
  2. data_set_2 中的(id1, id2) 组合在data_set_1 中不存在。

复杂之处在于我想避免使用应用或循环方法。这些数据集可能会变得非常大(下面的示例是有意简化的),我的理解是可以有更多有条不紊的方法来处理这个问题。

data_set_1 = pd.DataFrame({"id1": ["A", "B", "C", "D"], "id2": ["1", "2", "2", "1"]})
data_set_2 = pd.DataFrame({"id1": ["A", "B", "F", "C", "D", "E"], "id2": ["1", "1", "2", "1", "1", "2"],"id3": ["1","2","3","4","5","6"]})

我期望返回的内容:

1. E, F

2.
(B, 1)
(F, 2)
(C, 1)
(E, 2)

到目前为止我尝试过的如下:

获取data_set_1中不存在的产品:

data_set_2.loc[~(data_set_2.id1.isin(data_set_1.id1))] 

(这是我不确定这是否是最好的方法的地方)- 获取 data_set_1 中不存在的 id1、id2 组合:

我尝试了一个 isin 语句,似乎两个数据帧的长度似乎是一个问题,因为 pandas 将评估两个数据帧之间的相同索引行,并且它独立地评估每一列。

我发现我可以像这样索引多个列值:

data_set_2.set_index(["id1", "id2"], inplace=True,drop=False)
data_set_1.set_index(["id1", "id2"], inplace=True,drop=False)

让我这样做:

~data_set_2[["id1","id2"]].isin(data_set_1)
A   1    False  False
B   1     True   True
F   2     True   True
C   1     True   True
D   1    False  False
E   2     True   True

虽然这给了我想要的东西,但我无法在 loc 选择操作中选择评估为 True 的行:

data_set_2.loc[~data_set_2[["id1","id2"]].isin(data_set_1)]
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/usr/local/bfm/lib/python/pandas/0.20.2-cp35/pandas/core/indexing.py", line 1328, in __getitem__
    return self._getitem_axis(key, axis=0)
  File "/usr/local/bfm/lib/python/pandas/0.20.2-cp35/pandas/core/indexing.py", line 1539, in _getitem_axis
    raise ValueError('Cannot index with multidimensional key')
ValueError: Cannot index with multidimensional key

让我觉得这不是解决问题的正确方法。关于如何最好地实现这一点的任何想法?

【问题讨论】:

    标签: python python-3.x pandas


    【解决方案1】:

    对于您的第一种情况,您可以使用np.setdiff1d:

    vals = np.setdiff1d(data_set_2.id1, data_set_1.id1)
    print(vals)
    array(['E', 'F'], dtype=object)
    

    对于第二种情况,setdiff1d 不起作用,但简单的设置差异应该足够好。

    vals = set(data_set_2.iloc[:, :2].apply(tuple, 1)) \
                           -  set(data_set_1.apply(tuple, 1))
    print(vals)
    {('B', '1'), ('C', '1'), ('E', '2'), ('F', '2')}
    

    或者,为了改进您现有的方法,您可以按照以下方式做一些事情:

    m = ~data_set_2[["id1","id2"]].isin(data_set_1)
    
    print(m[m.all(1)])
              id1   id2
    id1 id2
    B   1    True  True
    F   2    True  True
    C   1    True  True
    E   2    True  True
    
    vals = m[m.all(1)].index.tolist()
    
    print(vals)
    [('B', '1'), ('F', '2'), ('C', '1'), ('E', '2')]
    

    【讨论】:

    • 给我一些时间@COLDSPEED,试图弄清楚所有设置如何在这里发挥作用 - 会回复你
    • @user3166881 你目前的方法很快,我敢说合并很有竞争力。
    • @user3166881 如果您的问题得到解答,请告诉我。
    • 抱歉耽搁了,分心了。对于大型数据集,您的方法实际上要快得多。直到现在才真正理解“all”方法的应用,这让我有了一些漂亮的说法。谢谢!
    【解决方案2】:

    你可以尝试使用anti-join来获取你想要的数据。

    import pandas as pd
    data_set_1 = pd.DataFrame({"id1": ["A", "B", "C", "D"], "id2": ["1", "2", "2", "1"]})
    data_set_2 = pd.DataFrame({"id1": ["A", "B", "F", "C", "D", "E"], "id2": ["1", "1", "2", "1", "1", "2"],"id3": ["1","2","3","4","5","6"]})
    
    # Merging two data frame on id1, then filtering base on indicator
    data_result_1 = data_set_2.merge(data_set_1.loc[:, ["id1"]], on="id1", how="outer", indicator=True)
    data_result_1 = data_result_1[data_result_1['_merge'] == 'left_only']
    
    # Merging two data frame on id1 and id2, then filtering base on indicator
    data_result_2 = data_set_2.merge(data_set_1.loc[:, ["id1", "id2"]], on=["id1", "id2"], how="outer", indicator=True)
    data_result_2 = data_result_2[data_result_2['_merge'] == 'left_only']
    
    
    print([tuple(x) for x in data_result_1.loc[:, ["id1"]].values])
    print([tuple(x) for x in data_result_2.loc[:, ["id1", "id2"]].values])
    

    【讨论】:

    • 合并是一种干净的方法!没想到要使用指标
    猜你喜欢
    • 2016-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多