Statistics: combinations in Python

前端 未结 18 1402
南旧
南旧 2020-11-27 10:14

I need to compute combinatorials (nCr) in Python but cannot find the function to do that in math, numpy or stat libraries. Something

相关标签:
18条回答
  • 2020-11-27 10:49

    If your program has an upper bound to n (say n <= N) and needs to repeatedly compute nCr (preferably for >>N times), using lru_cache can give you a huge performance boost:

    from functools import lru_cache
    
    @lru_cache(maxsize=None)
    def nCr(n, r):
        return 1 if r == 0 or r == n else nCr(n - 1, r - 1) + nCr(n - 1, r)
    

    Constructing the cache (which is done implicitly) takes up to O(N^2) time. Any subsequent calls to nCr will return in O(1).

    0 讨论(0)
  • 2020-11-27 10:50

    A quick search on google code gives (it uses formula from @Mark Byers's answer):

    def choose(n, k):
        """
        A fast way to calculate binomial coefficients by Andrew Dalke (contrib).
        """
        if 0 <= k <= n:
            ntok = 1
            ktok = 1
            for t in xrange(1, min(k, n - k) + 1):
                ntok *= n
                ktok *= t
                n -= 1
            return ntok // ktok
        else:
            return 0
    

    choose() is 10 times faster (tested on all 0 <= (n,k) < 1e3 pairs) than scipy.misc.comb() if you need an exact answer.

    def comb(N,k): # from scipy.comb(), but MODIFIED!
        if (k > N) or (N < 0) or (k < 0):
            return 0L
        N,k = map(long,(N,k))
        top = N
        val = 1L
        while (top > (N-k)):
            val *= top
            top -= 1
        n = 1L
        while (n < k+1L):
            val /= n
            n += 1
        return val
    
    0 讨论(0)
  • 2020-11-27 10:52

    Here is an efficient algorithm for you

    for i = 1.....r
    
       p = p * ( n - i ) / i
    
    print(p)
    

    For example nCr(30,7) = fact(30) / ( fact(7) * fact(23)) = ( 30 * 29 * 28 * 27 * 26 * 25 * 24 ) / (1 * 2 * 3 * 4 * 5 * 6 * 7)

    So just run the loop from 1 to r can get the result.

    0 讨论(0)
  • 2020-11-27 10:55

    Using only standard library distributed with Python:

    import itertools
    
    def nCk(n, k):
        return len(list(itertools.combinations(range(n), k)))
    
    0 讨论(0)
  • 2020-11-27 10:55

    That's probably as fast as you can do it in pure python for reasonably large inputs:

    def choose(n, k):
        if k == n: return 1
        if k > n: return 0
        d, q = max(k, n-k), min(k, n-k)
        num =  1
        for n in xrange(d+1, n+1): num *= n
        denom = 1
        for d in xrange(1, q+1): denom *= d
        return num / denom
    
    0 讨论(0)
  • 2020-11-27 10:55

    This is @killerT2333 code using the builtin memoization decorator.

    from functools import lru_cache
    
    @lru_cache()
    def factorial(n):
        """
        Calculate the factorial of an input using memoization
        :param n: int
        :rtype value: int
        """
        return 1 if n in (1, 0) else n * factorial(n-1)
    
    @lru_cache()
    def ncr(n, k):
        """
        Choose k elements from a set of n elements,
        n must be greater than or equal to k.
        :param n: int
        :param k: int
        :rtype: int
        """
        return factorial(n) / (factorial(k) * factorial(n - k))
    
    print(ncr(6, 3))
    
    0 讨论(0)
提交回复
热议问题