基于DataFrame如何编写循环统计出生群1年内同群个体数及均值
实现方案
1 基础单日群规模统计
无需编写显式循环,通过分组统计+表连接即可实现,性能远高于逐行遍历,运行结果与示例输出完全一致:
import pandas as pd # 先统计df2中每个日期、每个群的当日在场个体总数 daily_pack_count = df2.groupby(['date', 'pack'])['indiv'].count().reset_index(name='count') # 将统计结果匹配到df1的对应行,无匹配记录默认填充空值,需要填0可追加.fillna(0) df1 = df1.merge(daily_pack_count, on=['date', 'pack'], how='left')
上述代码执行后,示例中出生日期100天、属1号群的个体count值均为3,出生日期101天、属1号群的个体count值为2,完全匹配预期输出。
2 扩展:出生后365天平均群规模计算
核心逻辑:对每个个体划定时间窗口为出生日期当天至出生后第364天(共365天),逐日统计该时段内出生群的在场个体数,当日无该群观测记录则计数为0,最终计算365天的群规模平均值。
2.1 逐行for循环实现(逻辑透明易调试)
适合数据量较小(十万行以内)的场景,每一步逻辑可直接断点验证:
# 预计算所有日期-群的个体数映射,避免循环内重复统计 daily_count_map = df2.groupby(['date', 'pack'])['indiv'].count().to_dict() # 初始化均值存储列 df1['avg_pack_size_1y'] = 0.0 # 逐一遍历df1中的个体 for idx, row in df1.iterrows(): birth_date = row['date'] birth_pack = row['pack'] # 生成365天的时间窗口序列 time_window = range(birth_date, birth_date + 365) daily_size_list = [] # 逐日统计群规模 for day in time_window: day_size = daily_count_map.get((day, birth_pack), 0) daily_size_list.append(day_size) # 计算均值写入对应行 df1.loc[idx, 'avg_pack_size_1y'] = sum(daily_size_list) / 365
2.2 向量化优化实现(大数据集适用)
如果df1行数较多,逐行循环速度较慢,可通过条件连接跳过逐行遍历,性能提升10~100倍:
# 为每个个体生成365天窗口的结束日期 df1['window_end'] = df1['date'] + 364 # 生成每日群规模统计底表 daily_count_df = df2.groupby(['date', 'pack'])['indiv'].count().reset_index(name='daily_size') # 匹配所有符合:群一致、日期落在个体365天窗口内的记录 match_record = df1.merge( daily_count_df, on='pack', how='left' ).query('date_y >= date_x and date_y <= window_end') # 按个体分组计算365天平均规模 avg_res = match_record.groupby(['date_x', 'indiv', 'pack'])['daily_size'].sum() / 365 avg_res = avg_res.reset_index(name='avg_pack_size_1y') # 结果合并回原df1 df1 = df1.merge( avg_res, left_on=['date', 'indiv', 'pack'], right_on=['date_x', 'indiv', 'pack'], how='left' ).drop(columns=['date_x', 'window_end']).fillna({'avg_pack_size_1y': 0})
注意:如果你的
date字段是datetime时间格式,生成365天窗口时不要直接加整数,需替换为birth_date + pd.Timedelta(days=365)计算时间差。
内容的提问来源于stack exchange,提问作者Ananth Jason
相关产品推荐
相关产品推荐

