如何对有序列表做等宽分箱并直接获取各箱内的原始数据?
已排序列表等宽分桶提取原始值的实现方案
你原先基于bisect的实现思路是完全可行的,只是代码里有两个小瑕疵:一是把numpy的linspace误写为linespace,二是仅遍历list[:-1]最后手动补最大值的写法,遇到列表存在多个和最大值相等的重复元素时会漏数,调整后就能得到稳定正确的结果。
下面给两种场景下的简洁实现:
纯标准库实现(无第三方依赖)
不需要引入numpy计算分桶边界,直接通过步长计算边界即可,兼容所有Python3环境:
import bisect def split_equal_width_bins(sorted_list: list, bin_num: int) -> list[list]: if not sorted_list: return [[] for _ in range(bin_num)] min_val = sorted_list[0] max_val = sorted_list[-1] # 生成分桶边界,共bin_num+1个分割点 step = (max_val - min_val) / bin_num bin_edges = [min_val + i * step for i in range(bin_num + 1)] result = [[] for _ in range(bin_num)] for num in sorted_list: # 最大值统一放入最后一个桶,规避浮点计算误差导致的索引越界 if num == max_val: result[-1].append(num) continue # 二分查找当前值所属桶位置 bin_idx = bisect.bisect_right(bin_edges, num) - 1 result[bin_idx].append(num) return result # 测试示例 demo_list = [-1.8, -1.7, -1.3, 0.6, 2.7, 3.1, 3.2] print(split_equal_width_bins(demo_list, 5)) # 输出: [[-1.8, -1.7, -1.3], [], [0.6], [2.7], [3.1, 3.2]]
基于数据处理库的极简实现
如果你本身就在用numpy/pandas处理数据,可以直接用库内置的分桶函数,不需要手写二分逻辑:
numpy 版本
import numpy as np demo_arr = np.array([-1.8, -1.7, -1.3, 0.6, 2.7, 3.1, 3.2]) bin_num = 5 bin_edges = np.linspace(demo_arr.min(), demo_arr.max(), bin_num + 1) # 计算每个元素对应的桶索引 bin_indices = np.digitize(demo_arr, bin_edges, right=False) - 1 # 修正最大值的索引,避免浮点误差导致越界 bin_indices[bin_indices == bin_num] = bin_num - 1 # 按索引分组提取原始值 grouped_res = [demo_arr[bin_indices == i].tolist() for i in range(bin_num)]
pandas 版本
代码最短,直接用分桶+分组聚合即可:
import pandas as pd demo_ser = pd.Series([-1.8, -1.7, -1.3, 0.6, 2.7, 3.1, 3.2]) bin_num = 5 grouped_res = demo_ser.groupby( pd.cut(demo_ser, bins=bin_num, include_lowest=True) ).apply(list).tolist()
提示:以上所有实现默认输入是升序排列的列表,如果输入未排序,先调用
sorted()预处理即可。浮点计算存在精度误差,所有实现里把最大值统一归入最后一桶的处理,就是为了避免类似3.2被算到边界外的异常情况。
内容的提问来源于stack exchange,提问作者chapayev
相关产品推荐
相关产品推荐

