You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Numpy中沿指定轴寻找最频实数(非整数)的高效实现方法

优化高维数组各维度最频繁元素的计算效率

我们有一个400万行、4列的标准正态分布随机数组:

import numpy as np
x = np.random.randn(4000000, 4)

需求是对每一列(沿axis=0)找出其中最频繁出现的元素。原实现通过循环调用np.histogram逐个维度处理,效率很低——不仅没有利用NumPy的向量化优势,np.histogram本身也有不少额外开销。下面是几种高效优化方案:

原低效实现回顾

# 循环构建每个维度的直方图
hist = [np.histogram(x[:, i], bins=200) for i in range(x.shape[-1])]
# 拆分频次和分箱边界
freq, val = (np.array([o[0] for o in hist]).T, np.array([o[1] for o in hist]).T)
# 找最大频次的分箱索引
most_freq = np.argmax(freq, axis=0)
# 提取对应分箱的近似值
result = np.diagonal(val[most_freq])

结果近似为[0., 0., 0., 0.](符合正态分布的峰值特性),但速度远未达标。


优化方案1:全向量化分箱与统计

通过一次性对所有列做离散化和频次统计,替代循环调用np.histogram:

# 1. 获取所有列的极值,生成等宽分箱
col_mins = x.min(axis=0)
col_maxs = x.max(axis=0)
bins = np.linspace(col_mins, col_maxs, 201).T  # shape: (4, 201)

# 2. 向量化离散化所有列,得到每个元素的分箱索引
bin_indices = np.digitize(x, bins, right=True)
# 修正边界值(避免超出分箱范围)
bin_indices[bin_indices == 200] = 199

# 3. 对每列统计分箱频次
freqs = np.array([np.bincount(col, minlength=200) for col in bin_indices.T])

# 4. 找到最大频次的分箱,计算对应中点值
most_freq_idx = np.argmax(freqs, axis=1)
bin_midpoints = (bins[:, :-1] + bins[:, 1:]) / 2
result = bin_midpoints[np.arange(4), most_freq_idx]

np.digitize支持对每列使用独立分箱,一次性完成所有列的离散化;np.bincount比np.histogram更轻量,统计效率更高。

优化方案2:Numba并行加速循环

如果需要更极致的性能,用Numba对循环做JIT编译,利用多核并行处理:

import numba

@numba.jit(nopython=True, parallel=True)
def compute_most_freq(x, num_bins=200):
    n_cols = x.shape[1]
    result = np.zeros(n_cols)
    # 并行遍历每一列
    for i in numba.prange(n_cols):
        col = x[:, i]
        col_min = col.min()
        col_max = col.max()
        bin_width = (col_max - col_min) / num_bins
        
        # 计算分箱索引并修正边界
        bin_indices = ((col - col_min) / bin_width).astype(np.int64)
        bin_indices[bin_indices == num_bins] = num_bins - 1
        
        # 统计频次并找峰值分箱
        freq = np.bincount(bin_indices, minlength=num_bins)
        max_idx = np.argmax(freq)
        
        # 计算峰值对应的近似值
        result[i] = col_min + (max_idx + 0.5) * bin_width
    return result

# 调用函数
result = compute_most_freq(x)

Numba的parallel=True会自动将循环分配到多个CPU核心,相比纯Python循环速度提升10倍以上,同时避免了np.histogram的不必要开销。

优化方案3:利用数据特性预先设定分箱

因为数据是标准正态分布,99.9%的样本集中在[-4, 4]区间,我们可以直接预先设定分箱范围,省去计算每列极值的时间:

# 预先针对正态分布设定分箱
bins = np.linspace(-4, 4, 201)
# 离散化所有列
bin_indices = np.digitize(x, bins, right=True)
# 修正超出范围的少数样本
bin_indices[bin_indices < 0] = 0
bin_indices[bin_indices >= 200] = 199

# 统计频次并计算结果
freqs = np.array([np.bincount(col, minlength=200) for col in bin_indices.T])
most_freq_idx = np.argmax(freqs, axis=1)
bin_midpoints = (bins[:-1] + bins[1:]) / 2
result = bin_midpoints[most_freq_idx]

这种方案省去了全局极值计算的步骤,对于已知分布的数据效率最优。


内容的提问来源于stack exchange,提问作者Daniel Wiczew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 23:10:25