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

Python 3.x中基于概率直方图高效计算大量变量概率的方法

优化概率区间查找的时间复杂度

问题背景

我有两个无重叠的概率直方图:一个对应机器正常工作状态,另一个对应异常状态。每个直方图包含M个区间,用两个列表表示:一个存储区间概率,一个存储升序排列的区间边界。现在要处理N个数值,找到每个值所属区间对应的概率,原始实现的时间复杂度是O(N*M),需要优化。

原始代码示例:

normal_histogram = [0.5, 0.5]
normal_edges_of_histogram = [0,1.5,3]

abnormal_hist = [0.6, 0.4]
abnormal_edges = [5,7,9]

values = [5,1,78,2,6,8,2,9,0]

# 时间复杂度O(N*M)的实现
for x in values:
  l_edge = 0
  r_edge = l_edge+1
  prob = 0
  while r_edge <= len(normal_edges_of_histogram)-1:
    if normal_edges_of_histogram[l_edge] <= x <= normal_edges_of_histogram[r_edge]:
      prob = normal_histogram[l_edge]
      break
    elif abnormal_edges[l_edge] <= x <= abnormal_edges[r_edge]:
      prob = abnormal_hist[l_edge]
      break
    l_edge += 1
    r_edge += 1
  print(prob)

预期输出:

answer = [0.6, 0.5, 0, 0.5, 0.6, 0.4, 0.5, 0.4, 0.5]

优化方案

方案1:二分查找(时间复杂度O(N*logM))

因为两个直方图的区间边界都是升序排列且无重叠,我们可以先判断数值落在哪个直方图的范围里,再用二分查找快速定位区间索引:

import bisect

normal_histogram = [0.5, 0.5]
normal_edges = [0, 1.5, 3]
abnormal_hist = [0.6, 0.4]
abnormal_edges = [5, 7, 9]

values = [5,1,78,2,6,8,2,9,0]
result = []

for x in values:
    prob = 0
    # 检查是否在正常区间范围内
    if normal_edges[0] <= x <= normal_edges[-1]:
        # 用bisect_right找到插入位置,减1就是对应区间的索引
        idx = bisect.bisect_right(normal_edges, x) - 1
        prob = normal_histogram[idx]
    # 检查是否在异常区间范围内
    elif abnormal_edges[0] <= x <= abnormal_edges[-1]:
        idx = bisect.bisect_right(abnormal_edges, x) - 1
        prob = abnormal_hist[idx]
    result.append(prob)

print(result)  # 输出: [0.6, 0.5, 0, 0.5, 0.6, 0.4, 0.5, 0.4, 0.5]

方案2:预处理合并所有有效区间(时间复杂度O(M + N*logM))

把正常和异常的区间合并成一个有序的区间-概率映射表,之后每个数值只需要一次二分查找:

import bisect

normal_histogram = [0.5, 0.5]
normal_edges = [0, 1.5, 3]
abnormal_hist = [0.6, 0.4]
abnormal_edges = [5, 7, 9]

# 预处理:整理所有区间的(左边界, 右边界, 概率)并排序
all_intervals = []
# 添加正常区间
for i in range(len(normal_histogram)):
    all_intervals.append((normal_edges[i], normal_edges[i+1], normal_histogram[i]))
# 添加异常区间
for i in range(len(abnormal_hist)):
    all_intervals.append((abnormal_edges[i], abnormal_edges[i+1], abnormal_hist[i]))
# 按左边界排序(原区间无重叠,也可直接拼接)
all_intervals.sort()
# 提取单独的右边界列表用于二分查找
right_edges = [edge[1] for edge in all_intervals]

values = [5,1,78,2,6,8,2,9,0]
result = []

for x in values:
    prob = 0
    # 找到第一个大于x的右边界索引
    idx = bisect.bisect_right(right_edges, x)
    if idx > 0:
        left, _, p = all_intervals[idx-1]
        if left <= x:
            prob = p
    result.append(prob)

print(result)  # 输出: [0.6, 0.5, 0, 0.5, 0.6, 0.4, 0.5, 0.4, 0.5]

方案说明

  • 二分查找方案代码简洁直观,适合两个直方图区间范围差异明显的场景,每个数值最多两次二分查找,时间复杂度为O(N*logM)。
  • 合并区间方案适合直方图数量较多的场景,预处理一次后每个数值仅需一次二分查找,整体效率更优。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 03:17:14