我需要在Python中计算组合(nCr),但无法在 math
, numpy
或 stat
库中找到执行此操作的函数 . 类似于类型函数的东西:
comb = calculate_combinations(n, r)
我需要可能组合的数量,而不是实际的组合,所以 itertools.combinations
对我不感兴趣 .
最后,我想避免使用阶乘,因为我将计算组合的数字会变得太大而且阶乘将变得非常可怕 .
这似乎是一个非常容易回答的问题,但是我被淹没在关于生成所有实际组合的问题中,这不是我想要的 . :)
非常感谢
14 回答
快速搜索谷歌代码给出(它使用@Mark Byers's answer中的公式):
如果你需要一个确切的答案,
choose()
比scipy.misc.comb()
快10倍(在所有0 <=(n,k)<1e3对上测试) .请参阅scipy.special.comb(旧版scipy中的scipy.misc.comb) . 当
exact
为False时,它使用gammaln函数获得良好的精度而不需要花费太多时间 . 在确切的情况下,它返回一个任意精度的整数,这可能需要很长时间才能计算出来 .如果您的程序的上限为
n
(比如n <= N
)并且需要重复计算nCr(最好是>>N
次),使用lru_cache可以为您带来巨大的性能提升:构造缓存(隐式完成)最多需要
O(N^2)
时间 . 对nCr
的任何后续调用都将在O(1)
中返回 .为什么不自己写呢?这是一个单行或类似的:
测试 - 打印Pascal的三角形:
PS . 编辑后将
int(round(reduce(mul, (float(n-i)/(i+1) for i in range(k)), 1)))
替换为int(reduce(mul, (Fraction(n-i, i+1) for i in range(k)), 1))
,这样就不会出现大N / K错误使用动态编程,时间复杂度为Θ(n * m)和空间复杂度Θ(m):
用同情的话很容易 .
这是另一种选择 . 这个最初是用C语言编写的,因此它可以被后向移植到C以获得有限精度的整数(例如__int64) . 优点是(1)它只涉及整数运算,(2)它通过连续的乘法和除法对避免膨胀整数值 . 我用Nas Banov的Pascal三角形测试了结果,得到了正确的答案:
基本原理:为了最小化乘法和除法的数量,我们将表达式重写为
为了尽可能避免乘法溢出,我们将按照以下STRICT顺序从左到右进行评估:
我们可以证明按此顺序操作的整数算术是精确的(即没有舍入误差) .
在很多情况下,数学定义的字面翻译是相当充分的(记住Python会自动使用大数字算术):
对于我测试的一些输入(例如n = 1000 r = 500),这比另一个(当前最高投票)答案中提出的一个衬管
reduce
快10倍以上 . 另一方面,它由@ J.F提供的snippit表示 . 塞巴斯蒂安 .仅使用随Python分发的标准库:
对于相当大的输入,这可能与纯python中的速度一样快:
您可以编写2个简单的函数,实际上比使用scipy.special.comb快5-8倍 . 实际上,您不需要导入任何额外的包,并且该功能非常容易阅读 . 诀窍是使用memoization存储以前计算的值,并使用nCr的定义
如果我们比较时间
当n大于20时,直接公式产生大整数 .
那么,还有另一个回应:
简短,快速,高效 .
如果你想要确切的结果 and 速度,请尝试gmpy -
gmpy.comb
应该完全按照你的要求做,而且速度非常快(当然,作为gmpy
的原作者,我有偏见;-) .如果您想要精确的结果,请使用sympy.binomial . 这似乎是最快的方法,请放手 .