代码之家  ›  专栏  ›  技术社区  ›  Georg Heiler

pandas获得contigus值的第一个元素以执行会话化,即获得会话开始事件

  •  0
  • Georg Heiler  · 技术社区  · 5 年前

    我如何找到一个会话(针对每个组)的第一个元素,该元素开始一系列新的连续值?

    import pandas as pd
    df = pd.DataFrame({'group':[1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,], 'value':[
        1,2,3,4,5,10,11, 15, 16,17,18,19,20, # 13
        21, 22,23,24,26,27.28,
        4,5,6, 8,9,10,11,12, 13,14
    ]})
    display(df)
    

    到目前为止,我被困在这里:

    df['shifted_value'] = df['value'].shift(-1)
    df['difference_nect'] = df['shifted_value'] - df['value']
    
    # this is obviously not yet correct - how can I get the first element (elemnt of 0 for each of the starting sessions)
    df['session_element_index'] = df.groupby(['group']).cumcount()
    df.head()
    

    在SQL中,我会使用窗口函数并比较前一个/下一个元素,以确定会话是否开始/结束。有没有更好的熊猫原生方式——如何以矢量化的方式做到这一点?

    2 回复  |  直到 5 年前
        1
  •  1
  •   jezrael    5 年前

    使用 DataFrameGroupBy.diff 比较不相等 1 并过滤 boolean indexing :

    df1 = df[df.groupby('group')['value'].diff().ne(1)]
    print (df1)
        group  value
    0       1   1.00
    5       1  10.00
    7       1  15.00
    17      1  26.00
    18      1  27.28
    19      2   4.00
    22      2   8.00
    

    如果需要计数器列:

    g = df.groupby('group')['value'].apply(lambda x: x.diff().ne(1).cumsum())
    df['session_element_index'] = df.groupby(g).cumcount()
    print (df.head(10))
       group  value  session_element_index
    0      1    1.0                      0
    1      1    2.0                      1
    2      1    3.0                      2
    3      1    4.0                      3
    4      1    5.0                      4
    5      1   10.0                      0
    6      1   11.0                      1
    7      1   15.0                      0
    8      1   16.0                      1
    9      1   17.0                      2
    
        2
  •  0
  •   Corralien    5 年前

    作为第一种方法:

    out = df.groupby("group", as_index=False).value \
            .apply(lambda s: ((s - s.shift()) != 1.0).cumsum() \
            .drop_duplicates())
    
    >>> out
    0  0     1
       5     2
       7     3
       17    4
       18    5
    1  19    1
       22    2
    Name: value, dtype: int64
    
    >>> out.index.get_level_values(1)
    Int64Index([0, 5, 7, 17, 18, 19, 22], dtype='int64')