【问题标题】:Comparing previous row values in Pandas DataFrame比较 Pandas DataFrame 中的前一行值
【发布时间】:2017-05-14 22:47:32
【问题描述】:
import pandas as pd
data={'col1':[1,3,3,1,2,3,2,2]}
df=pd.DataFrame(data,columns=['col1'])
print df


         col1  
    0     1          
    1     3          
    2     3          
    3     1          
    4     2          
    5     3          
    6     2          
    7     2          

我有以下 Pandas DataFrame,我想创建另一列来比较 col1 的前一行,看看它们是否相等。最好的方法是什么?它就像下面的 DataFrame。谢谢

    col1  match  
0     1   False     
1     3   False     
2     3   True     
3     1   False     
4     2   False     
5     3   False     
6     2   False     
7     2   True     

【问题讨论】:

    标签: python pandas numpy boolean shift


    【解决方案1】:

    你需要eqshift

    df['match'] = df.col1.eq(df.col1.shift())
    print (df)
       col1  match
    0     1  False
    1     3  False
    2     3   True
    3     1  False
    4     2  False
    5     3  False
    6     2  False
    7     2   True
    

    或者eq使用==,但是在大DataFrame中会慢一些:

    df['match'] = df.col1 == df.col1.shift()
    print (df)
       col1  match
    0     1  False
    1     3  False
    2     3   True
    3     1  False
    4     2  False
    5     3  False
    6     2  False
    7     2   True
    

    时间安排

    import pandas as pd
    data={'col1':[1,3,3,1,2,3,2,2]}
    df=pd.DataFrame(data,columns=['col1'])
    print (df)
    #[80000 rows x 1 columns]
    df = pd.concat([df]*10000).reset_index(drop=True)
    
    df['match'] = df.col1 == df.col1.shift()
    df['match1'] = df.col1.eq(df.col1.shift())
    print (df)
    
    In [208]: %timeit df.col1.eq(df.col1.shift())
    The slowest run took 4.83 times longer than the fastest. This could mean that an intermediate result is being cached.
    1000 loops, best of 3: 933 µs per loop
    
    In [209]: %timeit df.col1 == df.col1.shift()
    1000 loops, best of 3: 1 ms per loop
    

    【讨论】:

    • 你可以做df = pd.concat([df]*10000, ignore_index=True)
    • == 通常不会比使用 eq 慢(例如,当我测试它们时,我得到的结果与您相反)。
    • @ajcr - 感谢您的评论。我在 Windows 下测试了更多次,如果与标量比较,时间是相同的,但如果比较 2 系列,eqnelt... 比 ==!=,@987654338 更快@ 在较大的 df 中。您在较大的df 中的时间安排是什么?
    • 多么了不起的方法!所以shift 默认是向下移动,我明白了。为什么 .eq 上的 pandas 文档没有包含实际使用 .eq 的示例?诡异的。但我猜它的工作原理与== 相同,除了计算时间。
    • @jezrael 如果我们之间有空值,我可以知道如何处理。
    【解决方案2】:

    1) pandas 方法: 使用diff

    df['match'] = df['col1'].diff().eq(0)
    

    2) numpy 方法: 使用np.ediff1d

    df['match'] = np.ediff1d(df['col1'].values, to_begin=np.NaN) == 0
    

    两者都产生:

    时间安排:(与@jezrael 使用的DF 相同)

    %timeit df.col1.eq(df.col1.shift())
    1000 loops, best of 3: 731 µs per loop
    
    %timeit df['col1'].diff().eq(0)
    1000 loops, best of 3: 405 µs per loop
    

    【讨论】:

    • 我尝试了 pandas 和 numpy 方法,但它不适用于字符串。 pandas 分别产生了unsupported operand type(s) for -: 'str' and 'str'cannot convert 'to_begin' to array with dtype 'dtype('O')' as required for input ary
    【解决方案3】:

    这是一个使用 slicing 的基于 NumPy 数组的方法,它允许我们将视图用于输入数组以提高效率 -

    def comp_prev(a):
        return np.concatenate(([False],a[1:] == a[:-1]))
    
    df['match'] = comp_prev(df.col1.values)
    

    示例运行 -

    In [48]: df['match'] = comp_prev(df.col1.values)
    
    In [49]: df
    Out[49]: 
       col1  match
    0     1  False
    1     3  False
    2     3   True
    3     1  False
    4     2  False
    5     3  False
    6     2  False
    7     2   True
    

    运行时测试-

    In [56]: data={'col1':[1,3,3,1,2,3,2,2]}
        ...: df0=pd.DataFrame(data,columns=['col1'])
        ...: 
    
    #@jezrael's soln1
    In [57]: df = pd.concat([df0]*10000).reset_index(drop=True)
    
    In [58]: %timeit df['match'] = df.col1 == df.col1.shift() 
    1000 loops, best of 3: 1.53 ms per loop
    
    #@jezrael's soln2
    In [59]: df = pd.concat([df0]*10000).reset_index(drop=True)
    
    In [60]: %timeit df['match'] = df.col1.eq(df.col1.shift())
    1000 loops, best of 3: 1.49 ms per loop
    
    #@Nickil Maveli's soln1   
    In [61]: df = pd.concat([df0]*10000).reset_index(drop=True)
    
    In [64]: %timeit df['match'] = df['col1'].diff().eq(0) 
    1000 loops, best of 3: 1.02 ms per loop
    
    #@Nickil Maveli's soln2
    In [65]: df = pd.concat([df0]*10000).reset_index(drop=True)
    
    In [66]: %timeit df['match'] = np.ediff1d(df['col1'].values, to_begin=np.NaN) == 0
    1000 loops, best of 3: 1.52 ms per loop
    
    # Posted approach in this post
    In [67]: df = pd.concat([df0]*10000).reset_index(drop=True)
    
    In [68]: %timeit df['match'] = comp_prev(df.col1.values)
    1000 loops, best of 3: 376 µs per loop
    

    【讨论】:

      【解决方案4】:

      我很惊讶这里没有人提到 rolling 方法。 rolling 可以很容易地用于验证 n-previous 值是否都相同或执行任何自定义操作。这当然不如使用 diff 或 shift 快,但它可以轻松适应更大的窗口:

      df['match'] = df['col1'].rolling(2).apply(lambda x: len(set(x)) != len(x),raw= True).replace({0 : False, 1: True})
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-02-17
        • 1970-01-01
        • 2023-01-11
        • 2016-05-02
        • 1970-01-01
        • 2021-09-19
        • 1970-01-01
        相关资源
        最近更新 更多