Pandas DataFrame 每列提取最高非NaN值及对应行索引的高效实现
核心实现逻辑
- 逐列独立执行排序,避免全局删行导致其他列有效数据丢失
- 排序规则自定义:按观测值降序排列,同值情况下按观测日期(行索引)降序,保证重复高值优先取最新日期
- 借助pandas原生的
na_position='last'参数,自动将空值排在列排序的末尾,不需要手动给空值填充极端值 - 排序完成后同步提取前4位的观测值和对应行索引,分别组装成两个独立的结果DataFrame
- 若某列有效观测值不足4个,剩余位置自动保留空值,完全匹配输出要求
可运行代码实现
import pandas as pd import numpy as np # 初始化示例数据 df = pd.DataFrame({'day': [1, 2, 3, 4, 5, 6], 'location-1': [10, 24, 24, 85, 90, np.NaN], 'location-2': [np.NaN, np.NaN, 45, 28, np.NaN, np.NaN]}) df.set_index('day', inplace=True) # 逐列处理,生成Top值和对应日期的结果 top_value_list, top_day_list = [], [] for col in df.columns: s = df[col] # 构造复合排序键:值优先降序,同值则按行索引(日期)降序,空值自动排到末尾 sorted_idx = s.sort_values( ascending=False, na_position='last', key=lambda series: list(zip(series.values, series.index)) ).index # 取前4个位置的观测值和对应日期 top_vals = s.loc[sorted_idx].head(4).values top_days = s.loc[sorted_idx].head(4).index.values top_value_list.append(pd.Series(top_vals, name=col)) top_day_list.append(pd.Series(top_days, name=col)) # 组装最终结果 result = pd.concat(top_value_list, axis=1) result_days = pd.concat(top_day_list, axis=1)
方案适配特性
- 无需预先判断空值分布:原生排序参数自动处理所有列的空值位置,不需要逐列判断是否含空值、不需要填充-999这类人为极端值
- 无数据丢失风险:所有计算逐列独立完成,不会全局过滤含空值的行,某列的空值不会影响其他列的观测值提取
- 自动适配重复值规则:通过复合排序键实现同值时优先取最新日期,不需要手动跟踪重复值的位置
- 执行效率高:排序逻辑基于pandas内置的优化实现,相比手动遍历、numpy自定义argsort的方案,在大规模多地点、长时序数据场景下性能更稳定
注:示例中给出的预期结果里location-2的第二个值为笔误,对应原数据的实际观测值为28而非29,上述代码运行输出的结果结构与需求完全一致。
内容的提问来源于stack exchange,提问作者rigelpenguin
相关产品推荐
相关产品推荐

