如何快速生成含.describe()及扩展统计量的DataFrame?
高效计算大DataFrame的行级统计量(含自定义指标)
问题背景
我有一个20000行、1600列的DataFrame,每行代表一个观测对象,每列对应一个日期。示例数据如下:
import pandas as pd import numpy as np df2 = pd.DataFrame( np.array([ [1, 2, 3, 4, 5], [6, np.NaN, np.NaN, np.NaN, 10], [np.NaN, np.NaN, 14, 13, 15], [16, 17, 18, 19, 20], [21, 22, 23, 24, 25] ]), columns=['2016-01-01', '2016-01-02', '2016-01-03', '2016-01-04', '2016-01-05'], index=[1, 2, 3, 4, 5] )
需要生成一个新的DataFrame,包含.describe()输出的核心统计量(count、mean、std、min、max),以及三个自定义统计量:
first_v:每行的首个有效值last_v:每行的最后一个有效值density:观测数 / 首次观测后的日期总数(即总列数减去首个有效值所在列的索引)
原有的逐行循环方法(如下)运行速度极慢,需要更高效的解决方案:
for i in df2.index: df[i] = df2.T[i].describe()
预期输出结果:
count mean std min max first_v last_v density 1 5.0 3.0 1.581139 1.0 5.0 1.0 5.0 1.0 2 2.0 8.0 2.828427 6.0 10.0 6.0 10.0 0.4 3 3.0 14.0 1.000000 13.0 15.0 14.0 15.0 1.0 4 5.0 18.0 1.581139 16.0 20.0 16.0 20.0 1.0 5 5.0 23.0 1.581139 21.0 25.0 21.0 25.0 1.0
高效解决方案
利用Pandas和NumPy的向量化运算替代逐行循环,充分利用底层优化,大幅提升处理速度:
# 1. 计算默认核心统计量 desc_stats = df2.describe(axis=1)[['count', 'mean', 'std', 'min', 'max']] # 2. 生成非空值掩码 mask = df2.notna() # 3. 计算首个有效值及其索引 first_idx = mask.argmax(axis=1) # 每行第一个非空值的列索引(0-based) first_v = df2.values[np.arange(len(df2)), first_idx] # 4. 计算最后一个有效值 # 反转列后找第一个非空值,再转换为原列索引 last_idx = mask.shape[1] - 1 - mask.iloc[:, ::-1].argmax(axis=1) last_v = df2.values[np.arange(len(df2)), last_idx] # 5. 计算density指标 density = desc_stats['count'] / (mask.shape[1] - first_idx) # 6. 合并所有结果并调整列顺序 result = desc_stats.join(pd.DataFrame({ 'first_v': first_v, 'last_v': last_v, 'density': density }, index=desc_stats.index)) result = result[['count', 'mean', 'std', 'min', 'max', 'first_v', 'last_v', 'density']] # 查看结果(保留6位小数) print(result.round(6))
方案说明
- 向量化运算:避免了逐行循环的Python级开销,利用C语言实现的底层函数处理数据,速度提升显著
- 掩码操作:通过
notna()生成掩码矩阵,快速定位有效值位置 - 索引计算:用
argmax()高效找到每行首个/最后一个有效值的位置,再通过NumPy索引直接取值 - 结果合并:用
join()快速合并统计结果,保证索引对齐
内容的提问来源于stack exchange,提问作者Rodion Molchanov
相关产品推荐
相关产品推荐

