Pandas高效实现:将DataFrame数值追加到另一DataFrame列表列对应行
问题描述
现有两个通过如下代码创建的DataFrame:
df1 Fecha Vals 0 2001-01-01 [] 1 2001-01-02 [] 2 2001-01-03 [] 3 2001-01-04 [] 4 2001-01-05 [] 5 2001-01-06 [] 6 2001-01-07 [] 7 2001-01-08 [] 8 2001-01-09 [] df2 Fecha Vals 0 2001-01-01 0.0 1 2001-01-03 1.0 2 2001-01-05 2.0 3 2001-01-07 3.0 4 2001-01-09 4.0
需要将df2中的Vals值追加到df1中对应Fecha行的Vals列表里,得到如下结果:
df1 Fecha Vals 0 2001-01-01 [0.0] 1 2001-01-02 [] 2 2001-01-03 [1.0] 3 2001-01-04 [] 4 2001-01-05 [2.0] 5 2001-01-06 [] 6 2001-01-07 [3.0] 7 2001-01-08 [] 8 2001-01-09 [4.0]
尝试用for循环实现,但面对大型DataFrame时速度极慢,希望找到无需循环的高效实现方式。目前已能用df1['Fecha'].isin(df2['Fecha'].values)筛选df1中的对应行。
补充说明
- 后续需重复此操作,将df3等DataFrame的数值追加到df1的其他行中,且不希望去重。例如df3 = pd.DataFrame({'Fecha': ['2001-01-02', '2001-01-05', '2001-01-08'], 'Vals': [0.0, 1.0, 2.0]})。
- df2中的间隔仅为示例构造情况。
- 完成追加操作后,需为每行创建均值列和标准差列。
- 创建DataFrame的完整代码:
import datetime import pandas as pd yy = 2001 date_list = ['{:4d}-{:02d}-{:02d}'.format(yy, mm, dd) for mm in range(1, 2) for dd in range(1, 10)] fechas1 = [datetime.datetime.strptime(date_base, '%Y-%m-%d') for date_base in date_list] nf1 = len(fechas1) vals1 = [[] for _ in range(nf1)] dic1 = { 'Fecha': fechas1, 'Vals': vals1 } df1 = pd.DataFrame(dic1) fechas2 = [datetime.datetime.strptime(date_list[idx], '%Y-%m-%d') for idx in range(0, nf1, 2)] nf2 = len(fechas2) vals2 = [float(idx) for idx in range(nf2)] dic2 = { 'Fecha': fechas2, 'Vals': vals2 } df2 = pd.DataFrame(dic2)
高效实现方案
1. 单次追加(df2到df1)
利用字典查询+批量更新的方式,避免逐行循环:
# 将df2转为日期到值的映射字典 date_to_val = df2.set_index('Fecha')['Vals'].to_dict() # 批量更新df1的Vals列:匹配到日期则追加值,否则保留原列表 df1['Vals'] = df1.apply( lambda row: row['Vals'] + [date_to_val[row['Fecha']]] if row['Fecha'] in date_to_val else row['Vals'], axis=1 )
字典查询为O(1)操作,apply基于向量化逻辑执行,效率远高于for循环。
2. 多次追加(支持df3、df4等)
封装成函数,方便重复调用:
def append_vals_to_df1(df_target, df_source): date_to_val = df_source.set_index('Fecha')['Vals'].to_dict() df_target['Vals'] = df_target.apply( lambda row: row['Vals'] + [date_to_val[row['Fecha']]] if row['Fecha'] in date_to_val else row['Vals'], axis=1 ) return df_target # 示例:追加df2 df1 = append_vals_to_df1(df1, df2) # 追加df3 df3 = pd.DataFrame({'Fecha': ['2001-01-02', '2001-01-05', '2001-01-08'], 'Vals': [0.0, 1.0, 2.0]}) df1 = append_vals_to_df1(df1, df3)
执行后df1中2001-01-05行的Vals会变为[2.0, 1.0],满足不重复追加的需求。
3. 计算均值和标准差列
对每行的Vals列表计算统计值,空列表或单元素列表返回NaN:
import numpy as np df1['Mean'] = df1['Vals'].apply(lambda x: np.mean(x) if x else np.nan) # 样本标准差(ddof=1),至少2个值才计算 df1['Std'] = df1['Vals'].apply(lambda x: np.std(x, ddof=1) if len(x)>=2 else np.nan)
若需计算总体标准差,去掉ddof=1参数即可。
超大型DataFrame性能优化
如果数据量达到百万级以上,可采用完全向量化的合并方式,进一步提升性能:
# 将df2的单个值转为列表格式,方便合并 df2_list = df2.assign(Vals=df2['Vals'].apply(lambda x: [x])) # 合并df1与df2,空值用原列表填充 merged = df1.merge(df2_list, on='Fecha', how='left', suffixes=('', '_new')) df1['Vals'] = merged['Vals_new'].combine_first(merged['Vals']).apply(lambda x: x if isinstance(x, list) else [])
内容的提问来源于stack exchange,提问作者sancho.s ReinstateMonicaCellio
相关产品推荐
相关产品推荐

