Generación de sesiones a partir del análisis de archivos de registro con pandas.

Estoy analizando un archivo de registro de Apache y lo he importado a un dataframe de 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 (compatible; bingbot /2.0; + http://www.bing.com/bingbot.htm ) “‘

Mi dataframe:

introduzca la descripción de la imagen aquí

Quiero agrupar esto en sesiones basadas en IP, agente y diferencia horaria (si la duración es superior a 30 minutos, debería ser una nueva sesión).

Es fácil agrupar el dataframe por IP y agente, pero ¿cómo verificar esta diferencia de tiempo? Espero que el problema esté claro.

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

ACTUALIZACIÓN: df.index es como sigue:

  [2013-05-30 06:00:41, ..., 2013-05-30 22:29:14] Length: 31975, Freq: None, Timezone: None 

Haría esto usando un shift y una cumsum (aquí hay un ejemplo simple, con números en lugar de veces, pero funcionarían exactamente igual):

 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 

* la necesidad de skipna = False parece ser un error.

Entonces puedes usar esto en un grupo 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 

Ahora puede agrupar por 'ip' y 'session_number' (y analizar cada sesión).

La respuesta de Andy Hayden es encantadora y concisa, pero se vuelve muy lenta si tiene un gran número de usuarios / direcciones IP para agrupar. Aquí hay otro método que es mucho más feo pero también mucho más rápido.

 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)