
本文介绍在使用 pd.json_normalize() 扁平化多列字典数据时,如何将关联的 time_published 时间列正确广播到每个展开后的记录行中,避免信息丢失。
在新闻舆情分析等场景中,常遇到类似结构:一个 DataFrame 的每行代表一篇报道,多个列(如 0–41)存储了可变数量的股票情绪字典(可能为空或为 null),而最后一列(如 time_published)记录该报道的发布时间。当使用循环 + pd.json_normalize() 展开这些字典时,若未显式关联时间字段,最终结果将丢失关键的时间上下文——因为原始的 time_published 是按“行”对齐的,而扁平化后变成了按“字典条目”对齐。
解决核心在于:在每次 json_normalize 后,将对应行的 time_published 值广播(broadcast)为一列,并与当前批次的扁平化数据横向拼接。注意,不能直接使用 df['time_published'](返回 Series 全量),而应取与当前处理列 i 对应的原始行索引位置的值;但更稳妥且高效的做法是——利用 pandas 的自动对齐机制,在 concat 时将长度匹配的 time_published Series 与 json_normalize 结果合并。
由于 df_flat_ticker[i] 是一个包含字典(或 None/NaN)的 Series,其索引与原始 DataFrame 行索引一致。因此,df['time_published'] 这个 Series 的索引也完全匹配,可直接按索引对齐拼接:
df_final = pd.DataFrame()
for i in range(42): # 注意:range(42) 覆盖列索引 0–41
temp_dict_series = df_flat_ticker[i] # 取第 i 列(Series)
temp_flat = pd.json_normalize(temp_dict_series) # 展开为 DataFrame,索引保持不变
# 将 time_published 按索引对齐广播为新列
temp_with_time = pd.concat([temp_flat, df['time_published']], axis=1)
df_final = pd.concat([df_final, temp_with_time], ignore_index=False)
df_final = df_final.dropna(subset=['ticker']).reset_index(drop=True)更简洁、推荐的方式是使用 assign() 方法,语义清晰且避免嵌套 concat:
df_final = pd.DataFrame()
for i in range(42):
temp_flat = pd.json_normalize(df_flat_ticker[i])
# assign 自动按索引对齐,将整个 time_published Series 复制为新列
temp_with_time = temp_flat.assign(time_published=df['time_published'])
df_final = pd.concat([df_final, temp_with_time], ignore_index=True)
df_final = df_final.dropna(subset=['ticker']).reset_index(drop=True)✅ 关键要点总结:
- pd.json_normalize() 会保留输入 Series 的原始索引,这是实现时间列对齐的基础;
- df['time_published'] 是同长度、同索引的 Series,assign() 或 concat(axis=1) 会自动按索引对齐,无需手动 iloc 或 map;
- 使用 ignore_index=True 在最终 concat 中重置索引,提升可读性;
- dropna(subset=['ticker']) 比全局 dropna() 更安全,仅过滤掉 ticker 为空的无效记录(因字典可能为 None 或空);
- 若原始数据含大量空列(如全 null),可先用 df_flat_ticker.iloc[:, :42].apply(lambda s: s.dropna().tolist(), axis=0) 预处理,但本方案已兼容稀疏结构。
最终输出的 df_final 每行即为一条「股票+情绪指标+发布时间」三元组,完美支持后续按时间窗口聚合、多 ticker 关联分析等任务。










