【问题标题】:Pandas: find matching rows in two dataframes (without using `merge`)Pandas:在两个数据框中查找匹配的行(不使用`merge`)
【发布时间】:2022-01-24 09:19:52
【问题描述】:

假设我有这两个列数相同但行数可能不同的数据框:

tmp = np.arange(0,12).reshape((4,3))
df = pd.DataFrame(data=tmp) 

tmp2 = {'a':[3,100,101], 'b':[4,4,100], 'c':[5,100,3]}
df2 = pd.DataFrame(data=tmp2)

print(df)
   0   1   2
0  0   1   2
1  3   4   5
2  6   7   8
3  9  10  11

print(df2)
     a    b    c
0    3    4    5
1  100    4  100
2  101  100    3

我想验证df2 的行是否与df 的任何行匹配,即我想获得一系列(或数组)给出此结果的布尔值:

0     True
1    False
2    False
dtype: bool

我认为类似isin 的方法应该可以工作,但是我得到了这个结果,它导致了一个数据框并且是错误的:

print(df2.isin(df))
       a      b      c
0  False  False  False
1  False  False  False
2  False  False  False

作为约束,我不希望使用merge 方法,因为我所做的实际上是在应用合并之前检查数据。 感谢您的帮助!

【问题讨论】:

    标签: python pandas dataframe matching isin


    【解决方案1】:

    可能有更有效的解决方案,但您可以附加两个数据框可以调用duplicated,例如:

    df.append(df2).duplicated().iloc[df.shape[0]:]
    

    这假设每个 DataFrame 中的所有行都是不同的。以下是一些基准:

    tmp1 = np.arange(0,12).reshape((4,3))
    df1 = pd.DataFrame(data=tmp1,  columns=["a", "b", "c"]) 
    
    tmp2 = {'a':[3,100,101], 'b':[4,4,100], 'c':[5,100,3]}
    df2 = pd.DataFrame(data=tmp2)
    
    df1 = pd.concat([df1] * 10_000).reset_index()
    df2 = pd.concat([df2] * 10_000).reset_index()
    
    %timeit df1.append(df2).duplicated().iloc[df1.shape[0]:]
    # 100 loops, best of 5: 4.16 ms per loop
    %timeit pd.Series([m.all() for m in np.isin(df2.values,df1.values)])
    # 10 loops, best of 5: 74.9 ms per loop
    %timeit df2.apply(frozenset, axis=1).isin(df1.apply(frozenset, axis=1))
    # 1 loop, best of 5: 443 ms per loop
    

    【讨论】:

      【解决方案2】:

      试试:

      df[~df.apply(tuple,1).isin(df2.apply(tuple,1))]
      

      这是我的结果:

      【讨论】:

        【解决方案3】:

        使用np.in1d:

        >>> df2.apply(lambda x: all(np.in1d(x, df)), axis=1)
        0     True
        1    False
        2    False
        dtype: bool
        

        另一种方式,使用frozenset

        >>> df2.apply(frozenset, axis=1).isin(df1.apply(frozenset, axis=1))
        0     True
        1    False
        2    False
        dtype: bool
        

        【讨论】:

          【解决方案4】:

          您可以使用 MultiIndex(昂贵的 IMO):

          pd.MultiIndex.from_frame(df2).isin(pd.MultiIndex.from_frame(df))
          Out[32]: array([ True, False, False])
          

          另一种选择是创建一个字典,然后运行isin

          df2.isin({key : array.array for key, (_, array) in zip(df2, df.items())}).all(1)
          Out[45]: 
          0     True
          1    False
          2    False
          dtype: bool
          

          【讨论】:

            【解决方案5】:

            您可以使用numpy.isin,它将比较数组中的所有元素,并为每个数组的每个元素返回TrueFalse

            然后在每个数组上使用all(),如果所有元素都为真,函数将返回True,将得到你想要的输出:

            >>> pd.Series([m.all() for m in np.isin(df2.values,df.values)])
            
            0     True
            1    False
            2    False
            dtype: bool
            

            正在发生的事情的细分:

            # np.isin
            >>> np.isin(df2.values,df.values)
            
            Out[139]: 
            array([[ True,  True,  True],
                   [False,  True, False],
                   [False, False,  True]])
            
            # all()
            >>> [m.all() for m in np.isin(df2.values,df.values)]
            
            Out[140]: [True, False, False]
            
            # pd.Series()
            >>> pd.Series([m.all() for m in np.isin(df2.values,df.values)])
            
            Out[141]: 
            0     True
            1    False
            2    False
            dtype: bool
            

            【讨论】:

            • 这听起来效率低下。它是 O(n^2),其中 n 是数据帧中的元素数。由于 OP 只想要匹配行,它应该在 O(n) 中是可行的。
            • 根据下面的答案,这不是最低效的方法,实际上比使用apply 好得多。我测试了其他答案,对我有用的是 Corralien 和 sammy 的答案,它们显然都是低效的。其他的对我不起作用。
            猜你喜欢
            • 2019-01-04
            • 2014-04-27
            • 2019-04-23
            • 1970-01-01
            • 2017-06-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多