如何在Pandas DataFrame中计算列对的共同非空行数?
问题描述
我有一个包含约500列的DataFrame,可通过df.corr()轻松计算相关矩阵,但还想获取每对列的共同非空行数——也就是计算相关系数时所使用的记录数量。这个DataFrame较为稀疏,部分相关系数仅基于少量数据计算,部分则基于数千条有效数据。
示例输入DataFrame:
| 索引 | 特征1 | 特征2 | 特征3 |
|---|---|---|---|
| a | 2 | 3 | |
| b | 7 | 2 | |
| c | 1 | ||
| d | 3 | 1 | 9 |
期望输出:
| ---- | 特征1 | 特征2 | 特征3 |
|---|---|---|---|
| 特征1 | 3 | 1 (*) | 2 |
| 特征2 | 1 (*) | 2 | 2 (**) |
| 特征3 | 2 | 2 (**) | 3 |
注:输出中,特征1与特征2仅1行(*)同时非空,特征2与特征3有2行(**)同时非空。我试过用df.melt和df.pivot组合但没找到正确方法,不想用迭代方式,因为500+列时速度极慢。
解决方案
高效向量化实现(无迭代)
利用矩阵乘法可以快速计算出每对列的共同非空行数,完全适配大列数场景:
- 生成非空值布尔矩阵
将原DataFrame转换为布尔矩阵,非空值标记为True,空值为False:
mask = df.notna()
- 计算共同非空行数矩阵
通过布尔矩阵与其转置的矩阵乘法,直接得到所有列对的共同非空行数:
count_matrix = mask.T @ mask
这个操作是底层优化的向量运算,速度远快于循环迭代,500列的场景也能轻松处理。
- 添加自定义标记(可选)
如果需要像示例那样给低行数的单元格添加标记,比如行数≤1加(*)、行数≤2加(**),可以用applymap批量处理:
def format_cell(x): if x <= 1: return f"{x} (*)" elif x <= 2: return f"{x} (**)" return str(x) result_df = count_matrix.applymap(format_cell)
执行后就能得到和期望一致的输出结果。
内容的提问来源于stack exchange,提问作者Mike Tomaino
相关产品推荐
相关产品推荐

