基于两个数据框计算不同组合均值的R语言实现问题
问题解决:匹配多ID的时间序列数据并计算均值
需求明确
- 你有两个DataFrame:
df1:包含列v1、v2、v3(存储需要匹配的ID值)df2:包含列ID、Days、Hours、BT,每个ID对应7天,每天24小时的BT数据
- 目标:对
df1的每一行,匹配df2中相同Days、Hours组合下v1、v2、v3对应的BT值,计算这三个值的均值,最终生成包含v1、v2、v3、Days、Hours、Mean_BT的结果表
测试数据生成
先给出可复现的测试数据代码:
import pandas as pd import numpy as np # 生成df2:每个ID覆盖7天×24小时的BT数据 ids = [101, 102, 103, 104, 105] days = range(1, 8) hours = range(0, 24) df2_data = [] for id_val in ids: for day in days: for hour in hours: df2_data.append({ 'ID': id_val, 'Days': day, 'Hours': hour, 'BT': np.random.uniform(36.0, 37.5) }) df2 = pd.DataFrame(df2_data) # 生成df1:随机生成v1/v2/v3的ID组合 np.random.seed(42) df1 = pd.DataFrame({ 'v1': np.random.choice(ids, 10), 'v2': np.random.choice(ids, 10), 'v3': np.random.choice(ids, 10) })
常见循环错误原因
你之前的循环代码出错,大概率是以下问题:
- 没有给
df1的每一行匹配所有Days、Hours组合,只处理了单一时间点 - 匹配ID时没有同时锁定
Days和Hours条件,导致取错BT值 - 均值计算时没有正确聚合三个ID对应的BT值
正确实现方法
方法一:索引映射+交叉连接
利用索引快速查找BT值,结合交叉连接覆盖所有时间组合:
# 把df2转成多层索引,方便按Days/Hours/ID快速定位BT值 bt_lookup = df2.set_index(['Days', 'Hours', 'ID'])['BT'] # 生成Days和Hours的全组合,用于和df1做交叉连接 time_combinations = pd.MultiIndex.from_product([days, hours], names=['Days', 'Hours']).to_frame(index=False) # 交叉连接:让df1的每一行ID组合匹配所有时间点 df1_expanded = df1.merge(time_combinations, how='cross') # 定义函数计算单一行的均值 def get_mean_bt(row): # 分别获取三个ID在当前时间点的BT值 bt1 = bt_lookup.get((row['Days'], row['Hours'], row['v1']), np.nan) bt2 = bt_lookup.get((row['Days'], row['Hours'], row['v2']), np.nan) bt3 = bt_lookup.get((row['Days'], row['Hours'], row['v3']), np.nan) # 计算均值,自动忽略缺失值 return np.mean([bt1, bt2, bt3]) # 应用函数生成均值列 df1_expanded['Mean_BT'] = df1_expanded.apply(get_mean_bt, axis=1) # 提取最终结果 result = df1_expanded[['v1', 'v2', 'v3', 'Days', 'Hours', 'Mean_BT']] print(result.head())
方法二:宽表转换+合并计算
把df2转成宽表后直接匹配计算,代码更简洁:
# 将df2转换为宽表:Days/Hours为索引,ID为列,值为BT df2_wide = df2.pivot_table(index=['Days', 'Hours'], columns='ID', values='BT').reset_index() # 交叉连接df1和时间组合(同方法一) time_combinations = pd.MultiIndex.from_product([days, hours], names=['Days', 'Hours']).to_frame(index=False) df1_expanded = df1.merge(time_combinations, how='cross') # 合并宽表,获取每个ID对应的BT值 merged_df = df1_expanded.merge(df2_wide, on=['Days', 'Hours'], how='left') # 计算三个ID的BT均值 merged_df['Mean_BT'] = merged_df.apply(lambda row: np.mean([row[row['v1']], row[row['v2']], row[row['v3']]]), axis=1) # 提取结果 result = merged_df[['v1', 'v2', 'v3', 'Days', 'Hours', 'Mean_BT']] print(result.head())
关键注意事项
- 必须做交叉连接:因为每个ID对应所有7天24小时的数据,所以df1的每一行ID组合需要匹配所有时间点
- 匹配条件要完整:必须同时指定
Days、Hours、ID三个维度,避免取错数据 - 缺失值处理:如果某个ID在对应时间点没有数据,用
np.nan填充,np.mean会自动忽略缺失值(如果需要强制计算包含缺失值,改用np.nanmean)
内容的提问来源于stack exchange,提问作者Usman YousafZai
相关产品推荐
相关产品推荐

