Je dois calculer combinatoires (nCr) en Python mais ne peut pas trouver la fonction de le faire dans math
, numpy
ou les stat
bibliothèques. Quelque chose comme une fonction du type:
comb = calculate_combinations(n, r)
J'ai besoin du nombre de combinaisons possibles, pas des combinaisons réelles, donc itertools.combinations
cela ne m'intéresse pas.
Enfin, je veux éviter d'utiliser des factorielles, car les nombres pour lesquels je vais calculer les combinaisons peuvent devenir trop gros et les factorielles vont être monstrueuses.
Cela semble être une question VRAIMENT facile à répondre, mais je suis noyé dans des questions sur la génération de toutes les combinaisons réelles, ce qui n'est pas ce que je veux.
la source
scipy.misc.comb
est obsolète au profit de lascipy.special.comb
version depuis0.10.0
.Pourquoi ne pas l'écrire vous-même? C'est un one-liner ou tel:
Test - impression du triangle de Pascal:
PS. modifié pour remplacer
int(round(reduce(mul, (float(n-i)/(i+1) for i in range(k)), 1)))
parint(reduce(mul, (Fraction(n-i, i+1) for i in range(k)), 1))
afin qu'il ne se trompe pas pour le grand N / Kla source
from functools import reduce
.Une recherche rapide sur le code google donne (elle utilise la formule de la réponse de @Mark Byers ):
choose()
est 10 fois plus rapide (testé sur toutes les paires 0 <= (n, k) <1e3) quescipy.misc.comb()
si vous avez besoin d'une réponse exacte.la source
choose
fonction devrait avoir beaucoup plus de votes positifs! Python 3.8 a math.comb, mais j'ai dû utiliser Python 3.6 pour un défi et aucune implémentation n'a donné de résultats exacts pour de très grands entiers. Celui-ci le fait et le fait vite!Si vous voulez des résultats et une vitesse exacts , essayez gmpy -
gmpy.comb
devrait faire exactement ce que vous demandez, et c'est assez rapide (bien sûr, en tantgmpy
qu'auteur original, je suis partial ;-).la source
gmpy2.comb()
c'est 10 fois plus rapide que d'choose()
après ma réponse pour le code:for k, n in itertools.combinations(range(1000), 2): f(n,k)
oùf()
est l'ungmpy2.comb()
ou l' autre ouchoose()
sur Python 3.Si vous voulez un résultat exact, utilisez
sympy.binomial
. Cela semble être la méthode la plus rapide, haut la main.la source
Une traduction littérale de la définition mathématique est tout à fait adéquate dans de nombreux cas (en se rappelant que Python utilisera automatiquement l'arithmétique des grands nombres):
Pour certaines entrées que j'ai testées (par exemple n = 1000 r = 500), c'était plus de 10 fois plus rapide que la ligne
reduce
suggérée dans une autre réponse (actuellement la plus votée). En revanche, il est surpassé par l'extrait de code fourni par @JF Sebastian.la source
Au départ
Python 3.8
, la bibliothèque standard comprend désormais lamath.comb
fonction de calcul du coefficient binomial:qui est le nombre de façons de choisir k éléments parmi n éléments sans répétition
n! / (k! (n - k)!)
:la source
Voici une autre alternative. Celui-ci a été écrit à l'origine en C ++, il peut donc être rétroporté en C ++ pour un entier de précision finie (par exemple __int64). L'avantage est (1) qu'il n'implique que des opérations entières, et (2) il évite de gonfler la valeur entière en faisant des paires successives de multiplication et de division. J'ai testé le résultat avec le triangle Pascal de Nas Banov, il obtient la bonne réponse:
Justification: pour minimiser le nombre de multiplications et de divisions, nous réécrivons l'expression comme
Pour éviter autant que possible le débordement de multiplication, nous évaluerons dans l'ordre STRICT suivant, de gauche à droite:
Nous pouvons montrer que l'arithmatique entière opérée dans cet ordre est exacte (c'est-à-dire pas d'erreur d'arrondi).
la source
En utilisant la programmation dynamique, la complexité temporelle est Θ (n * m) et la complexité spatiale Θ (m):
la source
Si votre programme a une limite supérieure à
n
(par exemplen <= N
) et doit calculer à plusieurs reprises nCr (de préférence pour >>N
fois), l'utilisation de lru_cache peut vous donner un énorme gain de performances:La construction du cache (ce qui est fait implicitement) prend du
O(N^2)
temps. Tous les appels ultérieurs ànCr
retournerontO(1)
.la source
Vous pouvez écrire 2 fonctions simples qui s'avèrent être environ 5 à 8 fois plus rapides qu'en utilisant scipy.special.comb . En fait, vous n'avez pas besoin d'importer de packages supplémentaires et la fonction est assez facilement lisible. L'astuce consiste à utiliser la mémorisation pour stocker les valeurs précédemment calculées et à utiliser la définition de nCr
Si nous comparons les temps
la source
C'est assez facile avec sympy.
la source
En utilisant uniquement la bibliothèque standard distribuée avec Python :
la source
La formule directe produit de grands entiers lorsque n est supérieur à 20.
Alors, encore une autre réponse:
court, précis et efficace car cela évite les grands entiers python en s'en tenant aux longs.
Il est plus précis et plus rapide par rapport à scipy.special.comb:
la source
range(n-r+1, n+1)
au lieu derange(n-r,n+1)
.Il s'agit du code @ killerT2333 utilisant le décorateur de mémorisation intégré.
la source
Voici un algorithme efficace pour vous
Par exemple nCr (30,7) = fact (30) / (fact (7) * fact (23)) = (30 * 29 * 28 * 27 * 26 * 25 * 24) / (1 * 2 * 3 * 4 * 5 * 6 * 7)
Donc, exécutez simplement la boucle de 1 à r pour obtenir le résultat.
la source
C'est probablement aussi rapide que vous pouvez le faire en python pur pour des entrées raisonnablement volumineuses:
la source
Cette fonction est très optimisée.
la source