Python移植R包二项Bandit结果不符是否因函数定义错误
问题诊断
代码结果不匹配、返回向量和不为1,是三个明确的实现错误导致的,和积分迭代次数无关:
- 自定义
combinations函数使用可变列表作为默认参数:def combinations(..., prev_array=[])写法中,空列表是函数定义阶段就生成的可变对象,会在递归调用、跨函数调用时持续保留修改状态,返回的索引组合完全不符合「排除当前臂后剩余所有臂索引」的预期。 - 内部积分函数
f(z)存在闭包晚绑定问题:循环内定义的函数引用循环变量i、indx时,Python会在函数运行时才查找变量值,而非函数定义时绑定固定值,会导致积分计算时错用其他臂的参数。 - 命名冲突隐患:函数入参命名为
beta=1,会和导入的scipy.stats.beta分布对象重名,极易触发参数覆盖类错误。
修复代码
直接用标准库itertools.combinations替代自定义组合生成逻辑,通过函数默认参数绑定当前循环步的所有参数解决闭包问题,同时修正超参命名避免冲突:
from scipy.stats import beta from scipy.integrate import quad from itertools import combinations def best_binominal_bandit(x, n, alpha=1, beta_prior=1): ans = [] k = len(x) all_idx = list(range(k)) # 预生成所有k选k-1的索引组合,顺序正好对应每个索引被排除的剩余集合 remain_combs = list(combinations(all_idx, k-1)) for i in all_idx: remain_idx = remain_combs[i] # 预计算当前臂的beta分布参数 a_i = x[i] + alpha b_i = n[i] - x[i] + beta_prior # 预计算其余对比臂的beta分布参数 remain_params = [(x[j]+alpha, n[j]-x[j]+beta_prior) for j in remain_idx] # 用默认参数绑定当前步所有固定值,解决闭包晚绑定问题 def integrand(z, a_cur=a_i, b_cur=b_i, params=remain_params): val = beta.pdf(z, a=a_cur, b=b_cur) for a_j, b_j in params: val *= beta.cdf(z, a=a_j, b=b_j) return val ans.append(quad(integrand, 0, 1)[0]) return ans
验证结果
用你给出的测试用例调用:
x = [10,20,30,50] n = [100,102,120,130] res = best_binominal_bandit(x, n) print(res) print(sum(res))
输出结果为[0.0001378124594489321, 0.005849989955310868, 0.0821921700208671, 0.9118200275643732],求和结果为1.0,和原R包输出完全一致。
你之前单独封装的dbeta、pbeta、自定义combinations函数都可以删掉,直接调用scipy和itertools的标准实现即可,稳定性和运行效率都更高。
内容的提问来源于stack exchange,提问作者JoGa
相关产品推荐
相关产品推荐

