You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

统计指定时间范围内活动出现次数:多索引DataFrame函数开发需求

我来帮你实现这个函数,结合Pandas的特性,我们可以分步骤完成需求,同时考虑不同数据规模下的效率问题给出两种方案:

实现思路

核心需求是:针对每个活动a的实例,统计同一用户(name)在该实例时间的±nhr小时范围内,出现的其他活动(排除当前a实例本身)的次数。

基础实现方案(适合中小数据集)

这个方案逻辑直观,用apply遍历每个目标活动实例,针对性筛选统计:

import pandas as pd
from datetime import timedelta

def find_close_activities(df, a, nhr):
    # 把多索引结构转为普通列,方便后续操作
    df_flat = df.reset_index()
    
    # 筛选出所有活动为a的记录,作为我们的统计基准
    target_records = df_flat[df_flat['activity'] == a].copy()
    
    # 定义辅助函数:计算单条记录对应的周边活动次数
    def count_nearby(row):
        # 先锁定同一用户的所有记录
        same_user = df_flat[df_flat['name'] == row['name']]
        # 计算时间范围:当前时间 ± nhr小时
        time_start = row['time'] - timedelta(hours=nhr)
        time_end = row['time'] + timedelta(hours=nhr)
        # 筛选符合时间范围且不是当前活动a的记录(排除自身)
        valid_activities = same_user[(same_user['time'] >= time_start) & 
                                     (same_user['time'] <= time_end) & 
                                     (same_user['activity'] != a)]
        return len(valid_activities)
    
    # 对每个目标记录计算次数
    target_records['close_activities_count'] = target_records.apply(count_nearby, axis=1)
    
    # 恢复原有的多索引格式并返回
    return target_records.set_index(['name', 'time']).drop(columns=['activity'])

测试示例

用你提供的示例数据调用:

# 构造示例DataFrame
data = [
    ('Bill', '2013-10-09 05:27:00', 'run'),
    ('Bill', '2013-10-09 07:23:00', 'play'),
    ('Bill', '2013-10-09 07:25:00', 'hw'),
    ('Bill', '2013-10-09 08:25:00', 'swim'),
    ('Rick', '2014-11-07 06:27:00', 'eat'),
    ('Rick', '2014-11-07 07:25:00', 'swim'),
    ('Rick', '2014-11-07 08:25:00', 'hw'),
    ('Rick', '2014-11-07 10:30:00', 'play')
]
df = pd.DataFrame(data, columns=['name', 'time', 'activity'])
df['time'] = pd.to_datetime(df['time'])
df = df.set_index(['name', 'time'])

# 调用函数,统计swim实例2小时内的其他活动次数
result = find_close_activities(df, 'swim', 2)
print(result)

输出结果:

close_activities_count
name  time                                 
Bill  2013-10-09 08:25:00                  2
Rick  2014-11-07 07:25:00                  2

高效优化方案(适合大数据集)

如果你的数据量很大,apply的遍历效率会很低,我们可以用merge_asof实现高效的时间范围连接,避免逐行遍历:

import pandas as pd
from datetime import timedelta

def find_close_activities(df, a, nhr):
    df_flat = df.reset_index()
    target_records = df_flat[df_flat['activity'] == a].copy()
    
    # 按name和time排序,merge_asof要求输入已排序
    df_sorted = df_flat.sort_values(['name', 'time'])
    target_sorted = target_records.sort_values(['name', 'time'])
    
    # 为每个目标记录计算时间上下限
    target_sorted['time_low'] = target_sorted['time'] - timedelta(hours=nhr)
    target_sorted['time_high'] = target_sorted['time'] + timedelta(hours=nhr)
    
    # 用merge_asof做时间范围连接,匹配同用户、时间在范围内的记录
    merged = pd.merge_asof(
        target_sorted, df_sorted,
        on='time', by='name',
        left_bound='time_low', right_bound='time_high',
        direction='nearest'
    )
    
    # 排除自身记录(当匹配到的活动是a且时间完全相同时)
    merged = merged[(merged['activity_y'] != a) | (merged['time_x'] != merged['time_y'])]
    
    # 按原目标记录分组统计数量
    count_result = merged.groupby(['name', 'time_x']).size().reset_index(name='close_activities_count')
    
    # 恢复多索引格式
    return count_result.set_index(['name', 'time_x']).rename_axis(index={'time_x': 'time'})

这个方案利用Pandas的向量化操作,效率比apply高一个数量级,适合处理十万级以上的数据集。

内容的提问来源于stack exchange,提问作者LogCapy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:48:57