python pandas - 处理嵌套 groupby 的最佳方法
Posted
技术标签:
【中文标题】python pandas - 处理嵌套 groupby 的最佳方法【英文标题】:python pandas - optimal way to handle nested groupby 【发布时间】:2021-12-10 09:46:23 【问题描述】:我目前正在尝试使用 python 和 pandas 库处理一些日志文件。日志包含有关发送到服务器的请求的简单信息,我想从中提取有关会话的信息。这里的会话定义为同一用户在特定时间段内发出的一组请求(例如30分钟,从第一次请求到最后一次请求的时间计算,此时间段之后的请求应视为新会话的一部分)
要做到这一点,目前我正在执行嵌套分组:首先我使用 groupby 获取每个用户的请求,然后按 30 分钟间隔对每个用户请求进行分组,最后遍历这些间隔并选择那些实际包含数据的间隔:
# example log entry:
# id,host,time,method,url,response,bytes
# 303372,XXX.XXX.XXX.XXX,1995-07-11 12:17:09,GET,/htbin/wais.com?IMAX,200,6923
by_host = logs.groupby('host', sort=False)
for host, frame in by_host:
by_frame = frame.groupby(pd.Grouper(key='time', freq='30min', origin='start'))
for date, logs in by_frame:
if not logs.empty and logs.shape[0] > 1:
session_calculations()
这当然是非常低效的,并且使计算需要相当长的时间。有没有办法优化这个过程?我无法想出任何成功的东西。
编辑:
host time method url response bytes
0 ***.novo.dk 1995-07-11 12:17:09 GET /ksc.html 200 7067
1 ***.novo.dk 1995-07-11 12:17:48 GET /shuttle/missions/missions.html 200 8678
2 ***.novo.dk 1995-07-11 12:23:10 GET /shuttle/resources/orbiters/columbia.html 200 6922
3 ***.novo.dk 1995-08-09 12:48:48 GET /shuttle/missions/sts-69/mission-sts-69.html 200 11264
4 ***.novo.dk 1995-08-09 12:49:48 GET /shuttle/countdown/liftoff.html 200 4665
预期结果是从请求中提取的会话列表:
host session_time
0 ***.novo.dk 00:06:01
1 ***.novo.dk 00:01:00
请注意,这里的 session_time 是输入的第一个请求和最后一个请求之间的时间差,将它们分组在 30 分钟的时间窗口中。
【问题讨论】:
您能否提供一个包含输入数据和预期输出的最小示例? 嗨,我提供了示例输入和预期输出 【参考方案1】:要为每个用户定义本地时间窗口,即将原点视为每个用户第一次请求的时间,您可以先按“主机”分组。然后使用GroupBy.apply
对每个用户的DataFrame 应用一个函数,该函数处理时间分组并计算用户会话的持续时间。
def session_duration_by_host(by_host):
time_grouper = pd.Grouper(key='time', freq='30min', origin='start')
duration = lambda time: time.max() - time.min()
return (
by_host.groupby(time_grouper)
.agg(session_time = ('time', duration))
)
res = (
logs.groupby("host")
.apply(session_duration_by_host)
.reset_index()
.drop(columns="time")
)
【讨论】:
这个方法的问题是Grouper现在会全局设置时间窗口,这意味着它们将不再在特定用户第一次请求时正确开始。 @Etahel 我现在才明白你的意思。你说的对。我已经用考虑到这一点的新解决方案更新了我的帖子。它应该按预期工作。【参考方案2】:# You have to write idiomatic Pandas code, so rather then processing something -> saving into variable -> using that variable (only once) to something -> .... you have to chain your process. Also pandas `apply` is much faster than normal `for` in most situations.
logs.groupby('host', sort=False).apply(
lambda by_frame:by_frame.groupby(
pd.Grouper(key='time', freq='30min', origin='start')
).apply(lambda logs: session_calculations() if (not logs.empty) and (logs.shape[0] > 1) else None)
)
【讨论】:
强烈建议不要使用纯代码的答案。请include an explanation 说明如何以及为何解决问题。这将有助于未来的读者更好地理解您的解决方案。 - From Review以上是关于python pandas - 处理嵌套 groupby 的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章
Python Flatten 用 Pandas 将嵌套字典 JSON 相乘
来自 Python 嵌套字典的 Pandas Dataframe