Мне нужно вычислить combinatorials (NCR) в Python , но не может найти функцию , чтобы сделать это в math
, numpy
или stat
библиотеках. Что-то вроде функции типа:
comb = calculate_combinations(n, r)
Мне нужно количество возможных комбинаций, а не фактические комбинации, поэтому itertools.combinations
меня это не интересует.
Наконец, я хочу избежать использования факториалов, так как числа, для которых я буду вычислять комбинации, могут стать слишком большими, а факториалы будут чудовищными.
На этот вопрос кажется ДЕЙСТВИТЕЛЬНО легко ответить, однако меня тонут вопросы о генерации всех фактических комбинаций, чего я не хочу.
источник
scipy.misc.comb
устарел и замененscipy.special.comb
версией с0.10.0
.Почему бы не написать самому? Это однострочный или такой:
Тест - печать треугольника Паскаля:
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источник
from functools import reduce
.Быстрый поиск по коду Google дает (он использует формулу из ответа @Mark Byers ):
choose()
в 10 раз быстрее (проверено на всех парах 0 <= (n, k) <1e3), чемscipy.misc.comb()
если вам нужен точный ответ.источник
choose
функции должно быть больше голосов! В Python 3.8 есть math.comb, но мне пришлось использовать Python 3.6 для решения задачи, и ни одна реализация не дала точных результатов для очень больших целых чисел. Этот делает и делает это быстро!Если вы хотите точные результаты и скорость, попробуйте gmpy -
gmpy.comb
должны делать то , что вы просите, и это довольно быстро (конечно, какgmpy
«s оригинальный автор, я имею в смещена ;-).источник
gmpy2.comb()
это в 10 раз быстрее, чемchoose()
из моего ответа на код:for k, n in itertools.combinations(range(1000), 2): f(n,k)
гдеf()
либо,gmpy2.comb()
либоchoose()
на Python 3.Если хотите точного результата, используйте
sympy.binomial
. Похоже, это самый быстрый метод.источник
Дословный перевод математического определения вполне адекватен во многих случаях (учитывая, что Python автоматически использует арифметику с большими числами):
Для некоторых входных данных, которые я тестировал (например, n = 1000 r = 500), это было более чем в 10 раз быстрее, чем один лайнер,
reduce
предложенный в другом (в настоящее время наибольшее количество голосов) ответ. С другой стороны, он превосходит фрагмент, предоставленный @JF Sebastian.источник
Начиная
Python 3.8
, стандартная библиотека теперь включаетmath.comb
функцию для вычисления биномиального коэффициента:что является количеством способов выбрать k элементов из n элементов без повторения
n! / (k! (n - k)!)
:источник
Вот еще одна альтернатива. Первоначально он был написан на C ++, поэтому его можно перенести на C ++ для целого числа конечной точности (например, __int64). Преимущество состоит в том, что (1) он включает только целочисленные операции и (2) позволяет избежать раздувания целочисленного значения путем последовательного выполнения пар умножения и деления. Я проверил результат с треугольником Паскаля Наса Банова, он дает правильный ответ:
Обоснование: чтобы минимизировать количество умножений и делений, мы переписываем выражение как
Чтобы максимально избежать переполнения при умножении, мы будем выполнять вычисления в следующем СТРОГОМ порядке слева направо:
Мы можем показать, что целочисленные арифметические операции в этом порядке точны (т.е. нет ошибки округления).
источник
При динамическом программировании временная сложность равна Θ (n * m), а пространственная сложность Θ (m):
источник
Если ваша программа имеет верхнюю границу
n
(скажемn <= N
) и ей необходимо многократно вычислять nCr (желательно >>N
раз), использование lru_cache может дать вам огромный прирост производительности:Создание кеша (которое выполняется неявно) требует
O(N^2)
времени. Любые последующие вызовыnCr
будут возвращеныO(1)
.источник
Вы можете написать 2 простые функции, которые на самом деле примерно в 5-8 раз быстрее, чем при использовании scipy.special.comb . Фактически, вам не нужно импортировать какие-либо дополнительные пакеты, и функция довольно легко читается. Хитрость заключается в том, чтобы использовать мемоизацию для хранения ранее вычисленных значений и использовать определение nCr
Если мы сравним время
источник
С sympy это довольно просто.
источник
Использование только стандартной библиотеки, поставляемой с Python :
источник
Прямая формула дает большие целые числа, когда n больше 20.
Итак, еще один ответ:
короткий, точный и эффективный, потому что это позволяет избежать использования больших целых чисел Python за счет использования long.
Это точнее и быстрее по сравнению с scipy.special.comb:
источник
range(n-r+1, n+1)
вместоrange(n-r,n+1)
.Это код @ killerT2333, использующий встроенный декоратор мемоизации.
источник
Вот эффективный алгоритм для вас
Например, nCr (30,7) = fact (30) / (fact (7) * fact (23)) = (30 * 29 * 28 * 27 * 26 * 25 * 24) / (1 * 2 * 3 * 4 * 5 * 6 * 7)
Так что просто запустите цикл от 1 до r и получите результат.
источник
Это, вероятно, так быстро, как вы можете сделать это на чистом питоне для достаточно больших входных данных:
источник
Эта функция очень оптимизирована.
источник