Necesito calcular combinatorias (nCr) en Python, pero no puedo encontrar la función de hacer eso en math
, numpy
o stat
bibliotecas. Algo así como una función del tipo:
comb = calculate_combinations(n, r)
Necesito el número de combinaciones posibles, no las combinaciones reales, por lo itertools.combinations
que no me interesa.
Finalmente, quiero evitar el uso de factoriales, ya que los números para los que calcularé las combinaciones pueden ser demasiado grandes y los factoriales serán monstruosos.
Esto parece una pregunta REALMENTE fácil de responder, sin embargo, me estoy ahogando en preguntas sobre la generación de todas las combinaciones reales, que no es lo que quiero.
fuente
scipy.misc.comb
está en desuso a favor descipy.special.comb
desde la versión0.10.0
.¿Por qué no lo escribes tú mismo? Es de una sola línea o tal:
Prueba - imprimir el triángulo de Pascal:
PD. editado para reemplazar
int(round(reduce(mul, (float(n-i)/(i+1) for i in range(k)), 1)))
conint(reduce(mul, (Fraction(n-i, i+1) for i in range(k)), 1))
lo que no lo hará err de gran N / Kfuente
from functools import reduce
.Una búsqueda rápida en el código de google da (usa la fórmula de la respuesta de @Mark Byers ):
choose()
es 10 veces más rápido (probado en todos los pares 0 <= (n, k) <1e3) quescipy.misc.comb()
si necesita una respuesta exacta.fuente
choose
función debería tener muchos más votos positivos! Python 3.8 tiene math.comb, pero tuve que usar Python 3.6 para un desafío y ninguna implementación dio resultados exactos para enteros muy grandes. Este lo hace y lo hace rápido!Si quieres resultados exactos y velocidad, prueba gmpy :
gmpy.comb
debe hacer exactamente lo que pides y es bastante rápido (por supuesto, comogmpy
autor original, soy parcial ;-).fuente
gmpy2.comb()
es 10 veces más rápido quechoose()
mi respuesta para el código: ¿for k, n in itertools.combinations(range(1000), 2): f(n,k)
dóndef()
estágmpy2.comb()
ochoose()
en Python 3.Si quieres un resultado exacto, úsalo
sympy.binomial
. Parece ser el método más rápido, sin duda.fuente
Una traducción literal de la definición matemática es bastante adecuada en muchos casos (recordando que Python usará automáticamente aritmética de números grandes):
Para algunas entradas que probé (p. Ej., N = 1000 r = 500), esto fue más de 10 veces más rápido que el revestimiento
reduce
sugerido en otra respuesta (actualmente más votada). Por otro lado, es superado por el fragmento proporcionado por @JF Sebastian.fuente
Comenzando
Python 3.8
, la biblioteca estándar ahora incluye lamath.comb
función para calcular el coeficiente binomial:cuál es la cantidad de formas de elegir k elementos de n elementos sin repetición
n! / (k! (n - k)!)
:fuente
Aquí hay otra alternativa. Este se escribió originalmente en C ++, por lo que se puede transferir a C ++ para un entero de precisión finita (por ejemplo, __int64). La ventaja es que (1) involucra solo operaciones enteras y (2) evita hinchar el valor entero haciendo pares sucesivos de multiplicación y división. He probado el resultado con el triángulo Pascal de Nas Banov, obtiene la respuesta correcta:
Justificación: para minimizar el número de multiplicaciones y divisiones, reescribimos la expresión como
Para evitar el desbordamiento de multiplicación tanto como sea posible, evaluaremos en el siguiente orden ESTRICTO, de izquierda a derecha:
Podemos mostrar que la aritmética de enteros operada en este orden es exacta (es decir, sin error de redondeo).
fuente
Mediante la programación dinámica, la complejidad del tiempo es Θ (n * m) y la complejidad del espacio Θ (m):
fuente
Si su programa tiene un límite superior para
n
(digamosn <= N
) y necesita calcular repetidamente nCr (preferiblemente por >>N
veces), el uso de lru_cache puede brindarle un gran aumento de rendimiento:La construcción de la memoria caché (que se hace implícitamente) lleva
O(N^2)
tiempo. Cualquier llamada posterior anCr
regresaráO(1)
.fuente
Puede escribir 2 funciones simples que en realidad resultan ser aproximadamente 5-8 veces más rápidas que usar scipy.special.comb . De hecho, no necesita importar ningún paquete adicional, y la función es bastante fácil de leer. El truco consiste en utilizar la memorización para almacenar valores calculados previamente y utilizar la definición de nCr
Si comparamos tiempos
fuente
Es bastante fácil con sympy.
fuente
Usando solo la biblioteca estándar distribuida con Python :
fuente
La fórmula directa produce enteros grandes cuando n es mayor que 20.
Entonces, otra respuesta más:
corto, preciso y eficiente porque esto evita los grandes enteros de Python al quedarse con largos.
Es más preciso y más rápido cuando se compara con scipy.special.comb:
fuente
range(n-r+1, n+1)
lugar derange(n-r,n+1)
.Este es el código @ killerT2333 que usa el decorador de memoria incorporado.
fuente
Aquí hay un algoritmo eficiente para ti
Por ejemplo nCr (30,7) = fact (30) / (fact (7) * fact (23)) = (30 * 29 * 28 * 27 * 26 * 25 * 24) / (1 * 2 * 3 * 4 * 5 * 6 * 7)
Entonces, simplemente ejecute el ciclo de 1 a r puede obtener el resultado.
fuente
Probablemente sea lo más rápido que pueda hacerlo en Python puro para entradas razonablemente grandes:
fuente
Esta función está muy optimizada.
fuente