Pandas实现双列联合分箱计数的简洁方法

使用 `pd.cut` 对两列分别分箱,再通过 `pd.crosstab` 一键生成交叉频数表,可替代冗长的手动布尔索引计数逻辑,代码从数十行压缩为2行,兼具可读性与可维护性。

在数据分析中,常需根据多个数值列的组合条件对样本进行分类统计(例如:按 Age1 的区间 × Age2 的区间 统计频数)。原始方法依赖嵌套布尔索引和重复调用 len(),不仅代码冗长、易出错(如边界不一致、漏写括号),而且难以扩展或复用。

推荐采用 向量化分箱 + 交叉制表 的标准范式:

import pandas as pd
import numpy as np

data = pd.DataFrame({
    'Age1': [45, 48, 52, 51, 48, 45, 62, 47, 65, 50], 
    'Age2': [37, 68, 71, 54, 67, 59, 95, 56, 41, 42]
})

# 定义统一区间:(-∞, 40], (40, 50], (50, 60], (60, ∞)
bins = [-np.inf, 40, 50, 60, np.inf]

# 一步生成二维频数表
result = pd.crosstab(
    pd.cut(data['Age1'], bins=bins, right=True),   # Age1 分箱(右闭区间)
    pd.cut(data['Age2'], bins=bins, right=True)    # Age2 分箱(右闭区间)
)

print(result)

输出结果为清晰的交叉频数矩阵:

Age2          (-inf, 40.0]  (40.0, 50.0]  (50.0, 60.0]  (60.0, inf]
Age1                                                               
(40.0, 50.0]             1             1             2            2
(50.0, 60.0]             0             0             1            1
(60.0, inf]              0             1             0            1

优势说明

  • pd.cut 自动处理边界逻辑(right=True 表示右闭,默认行为),避免手动写 >=/
  • pd.crosstab 天然支持分类型索引,结果直接可读、可导出、可可视化;
  • 若需自定义行列标签(如 "40-50" 替代 (40.0, 50.0]),可在 pd.cut 中添加 labels 参数;
  • 支持进一步聚合,如 .apply(lambda x: x / x.sum(), axis=1) 计算行百分比。

⚠️ 注意事项

  • 确保 bins 在两列中完全一致,以保证语义对齐;
  • 若数据含缺失值(NaN),pd.cut 默认将其归为 NaN 类别,crosstab 会自动忽略(如需保留,设置 dropna=False);
  • 如需严格匹配原题中的分类名称(60),可后续用 result.rename_axis 和 result.rename 重命名索引。

该方法是 Pandas 生态中处理“双维度区间计数”问题的标准、高效且可扩展的解决方案。