Eu preciso calcular combinatorials (nCr) em Python, mas não consegue encontrar a função de fazer isso em math
, numpy
ou stat
bibliotecas. Algo como uma função do tipo:
comb = calculate_combinations(n, r)
Preciso do número de combinações possíveis, não das combinações reais, por itertools.combinations
isso não me interessa.
Por fim, quero evitar o uso de fatoriais, pois os números para os quais vou calcular as combinações podem ficar muito grandes e os fatoriais serão monstruosos.
Parece uma pergunta REALMENTE fácil de responder, no entanto, estou sendo afogado em perguntas sobre como gerar todas as combinações reais, o que não é o que eu quero.
fonte
scipy.misc.comb
foi descontinuado em favor dascipy.special.comb
versão desde0.10.0
.Por que não escrever você mesmo? É uma linha ou algo assim:
Teste - impressão do triângulo de Pascal:
PS. editado para substituir
int(round(reduce(mul, (float(n-i)/(i+1) for i in range(k)), 1)))
comint(reduce(mul, (Fraction(n-i, i+1) for i in range(k)), 1))
isso, não será err para grande N / Kfonte
from functools import reduce
.Uma rápida pesquisa no código do google fornece (ele usa a fórmula da resposta de @Mark Byers ):
choose()
é 10 vezes mais rápido (testado em todos os pares 0 <= (n, k) <1e3) do quescipy.misc.comb()
se você precisar de uma resposta exata.fonte
choose
função deve ter muito mais votos positivos! O Python 3.8 tem math.comb, mas eu tive que usar o Python 3.6 para um desafio e nenhuma implementação deu resultados exatos para números inteiros muito grandes. Este faz e faz rápido!Se você deseja resultados e velocidade exatos , tente o gmpy -
gmpy.comb
faça exatamente o que você pede e é muito rápido (é claro, comogmpy
autor original do site, sou tendencioso ;-).fonte
gmpy2.comb()
é 10 vezes mais rápido do quechoose()
de minha resposta para o código:for k, n in itertools.combinations(range(1000), 2): f(n,k)
ondef()
é ougmpy2.comb()
ouchoose()
sobre Python 3.Se você deseja um resultado exato, use
sympy.binomial
. Parece ser o método mais rápido, sem dúvida.fonte
Uma tradução literal da definição matemática é bastante adequada em muitos casos (lembrando que o Python usará automaticamente a aritmética de grandes números):
Para algumas entradas que testei (por exemplo, n = 1000 r = 500), isso foi mais de 10 vezes mais rápido do que o liner
reduce
sugerido em outra resposta (atualmente com o maior voto). Por outro lado, é superado pelo snippit fornecido por @JF Sebastian.fonte
Começando
Python 3.8
, a biblioteca padrão agora inclui amath.comb
função para calcular o coeficiente binomial:qual é o número de maneiras de escolher k itens de n itens sem repetição
n! / (k! (n - k)!)
:fonte
Aqui está outra alternativa. Este foi originalmente escrito em C ++, para que possa ser portado em C ++ para um número inteiro de precisão finita (por exemplo, __int64). A vantagem é (1) envolver apenas operações com números inteiros e (2) evitar inchar o valor inteiro, fazendo pares sucessivos de multiplicação e divisão. Testei o resultado com o triângulo Pascal de Nas Banov, ele obtém a resposta correta:
Fundamentação da petição: Para minimizar o número de multiplicações e divisões, reescrevemos a expressão como
Para evitar o excesso de multiplicação, tanto quanto possível, avaliaremos na seguinte ordem STRICT, da esquerda para a direita:
Podemos mostrar que a aritmética inteira operada nesta ordem é exata (ou seja, nenhum erro de arredondamento).
fonte
Usando programação dinâmica, a complexidade do tempo é Θ (n * m) e a complexidade do espaço Θ (m):
fonte
Se o seu programa tiver um limite superior para
n
(digamosn <= N
) e precisar calcular repetidamente a nCr (de preferência por >>N
vezes), o uso do lru_cache poderá oferecer um enorme aumento de desempenho:Construir o cache (que é feito implicitamente) leva
O(N^2)
tempo. Quaisquer chamadas subseqüentesnCr
retornarãoO(1)
.fonte
Você pode escrever duas funções simples que, na verdade, são cerca de 5 a 8 vezes mais rápidas do que usar scipy.special.comb . De fato, você não precisa importar nenhum pacote extra, e a função é facilmente legível. O truque é usar a memorização para armazenar valores previamente calculados e usar a definição de nCr
Se compararmos os tempos
fonte
É bem fácil com o sympy.
fonte
Usando apenas biblioteca padrão distribuída com Python :
fonte
A fórmula direta produz grandes números inteiros quando n é maior que 20.
Então, mais uma resposta:
curto, preciso e eficiente, porque isso evita inteiros grandes em python, permanecendo com longs.
É mais preciso e mais rápido quando comparado ao scipy.special.comb:
fonte
range(n-r+1, n+1)
vez derange(n-r,n+1)
.Este é o código @ killerT2333 usando o decorador de memorização incorporado.
fonte
Aqui está um algoritmo eficiente para você
Por exemplo, nCr (30,7) = fato (30) / (fato (7) * fato (23)) = (30 * 29 * 28 * 27 * 26 * 25 * 24) / (1 * 2 * 3 * 4 * 5 * 6 * 7)
Portanto, basta executar o loop de 1 a r para obter o resultado.
fonte
Provavelmente é o mais rápido que você pode fazer em python puro para entradas razoavelmente grandes:
fonte
Esta função é muito otimizada.
fonte