【问题标题】:Session generation from log file analysis with pandas使用 pandas 从日志文件分析生成会话
【发布时间】:2013-07-07 00:15:02
【问题描述】:

我正在分析一个 Apache 日志文件,并将其导入到 pandas 数据框中。

'65.55.52.118 - - [30/May/2013:06:58:52 -0600] "GET /detailedAddVen.php?refId=7954&uId=2802 HTTP/1.1" 200 4514 "-" "Mozilla/5.0 (兼容;bingbot/2.​​0;+http://www.bing.com/bingbot.htm)"'

我的数据框:



我想根据 IP、代理和时差将其分组到会话中(如果持续时间大于 30 分钟,则应该是新会话)。

通过IP和Agent对数据帧进行分组很容易,但是如何检查这个时间差?希望问题清楚。

sessions = df.groupby(['IP', 'Agent']).size()

更新:df.index 如下:

<class 'pandas.tseries.index.DatetimeIndex'>
[2013-05-30 06:00:41, ..., 2013-05-30 22:29:14]
Length: 31975, Freq: None, Timezone: None

【问题讨论】:

    标签: python pandas timedelta dataframe


    【解决方案1】:

    我会使用shiftcumsum 来执行此操作(这是一个简单的示例,使用数字而不是时间 - 但它们的工作方式完全相同):

    In [11]: s = pd.Series([1., 1.1, 1.2, 2.7, 3.2, 3.8, 3.9])
    
    In [12]: (s - s.shift(1) > 0.5).fillna(0).cumsum(skipna=False)  # *
    Out[12]:
    0    0
    1    0
    2    0
    3    1
    4    1
    5    2
    6    2
    dtype: int64
    

    * skipna=False 的需求似乎是一个错误。

    然后你可以在groupby apply中使用它:

    In [21]: df = pd.DataFrame([[1.1, 1.7, 2.5, 2.6, 2.7, 3.4], list('AAABBB')]).T
    
    In [22]: df.columns = ['time', 'ip']
    
    In [23]: df
    Out[23]:
      time ip
    0  1.1  A
    1  1.7  A
    2  2.5  A
    3  2.6  B
    4  2.7  B
    5  3.4  B
    
    In [24]: g = df.groupby('ip')
    
    In [25]: df['session_number'] = g['time'].apply(lambda s: (s - s.shift(1) > 0.5).fillna(0).cumsum(skipna=False))
    
    In [26]: df
    Out[26]:
      time ip  session_number
    0  1.1  A               0
    1  1.7  A               1
    2  2.5  A               2
    3  2.6  B               0
    4  2.7  B               0
    5  3.4  B               1
    

    现在您可以按 'ip''session_number' 分组(并分析每个会话)。

    【讨论】:

    • 谢谢安迪!很长一段时间后我得到了答案:),但是为什么我会收到这个错误? AttributeError: 'Timestamp' 对象没有属性 'shift'
    • @NilaniAlgiriyage 看起来您已尝试将移位应用于时间戳而不是列/系列(但不确定您是如何做到的)。
    • df['tval'] = df.index df['delta'] = (df['tval']-df['tval'].shift(1) > 30).fillna( 0).cumsum(skipna=False)
    • 以上代码是否正确?但它给出了另一种类型错误?
    • 上面的代码对我有用......你的代码看起来不错,虽然我认为你应该使用pd.offsets.Minute(30).nanos而不是30。你能确认type(df['tval'])的结果吗?和你的熊猫版本(适用于 0.11)。
    【解决方案2】:

    Andy Hayden 的回答简洁明了,但如果您有大量用户/IP 地址要分组,它会变得非常慢。这是另一种更丑但也更快的方法。

    import pandas as pd
    import numpy as np
    
    sample = lambda x: np.random.choice(x, size=10000)
    df = pd.DataFrame({'ip': sample(range(500)), 
                       'time': sample([1., 1.1, 1.2, 2.7, 3.2, 3.8, 3.9])})
    max_diff = 0.5 # Max time difference
    
    def method_1(df):
        df = df.sort_values('time')
        g = df.groupby('ip')
        df['session'] = g['time'].apply(
            lambda s: (s - s.shift(1) > max_diff).fillna(0).cumsum(skipna=False)
            )
        return df['session']
    
    
    def method_2(df):
        # Sort by ip then time 
        df = df.sort_values(['ip', 'time'])
    
        # Get locations where the ip changes 
        ip_change = df.ip != df.ip.shift()
        time_or_ip_change = (df.time - df.time.shift() > max_diff) | ip_change
        df['session'] = time_or_ip_change.cumsum()
    
        # The cumsum operated over the whole series, so subtract out the first 
        # value for each IP
        df['tmp'] = 0
        df.loc[ip_change, 'tmp'] = df.loc[ip_change, 'session']
        df['tmp'] = np.maximum.accumulate(df.tmp)
        df['session'] = df.session - df.tmp
    
        # Delete the temporary column
        del df['tmp']
        return df['session']
    
    r1 = method_1(df)
    r2 = method_2(df)
    
    assert (r1.sort_index() == r2.sort_index()).all()
    
    %timeit method_1(df)
    %timeit method_2(df)
    
    400 ms ± 195 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    11.6 ms ± 2.04 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-01-31
      • 2022-01-25
      • 1970-01-01
      • 2022-01-16
      • 2021-11-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多