阶乘的定义和例子
阶乘函数 ,计算一个集合中的排列数。n!
假设你想对三支足球队曼联队、巴塞罗那队和拜仁慕尼黑队进行排名--存在多少种可能的排名?
答案是3! = 3 x 2 x 1 = 6 。
实际例子。假设,英格兰超级联赛有20支足球队。每支球队都有可能在赛季结束后达到20个排名中的任何一个。在20支固定球队的情况下,英超联赛存在多少种可能的排名?

图。英格兰超级联赛中的足球队的三种可能排名的例子。
一般来说,要计算阶乘 n! ,你需要将所有小于或等于n 的正整数相乘。
例如,如果你有5支足球队,就有5! = 5 x 4 x 3 x 2 x 1 = 120 个不同的配对。
在Python中,有许多不同的方法可以轻松计算阶乘函数,请看下面的替代方法。
在你阅读文章时,请随时观看我的解释视频。
如何在NumPy中计算阶乘?
NumPy的数学模块包含基本数学函数的有效实现,如阶乘函数numpy.math.factorial(n) 。
下面是一个如何用NumPy计算阶乘的例子3! 。
>>> import numpy as np
>>> np.math.factorial(3)
6
NumPy中的阶乘函数只有一个整数参数n 。如果参数是负数或者不是整数,Python将引发一个值错误。
下面是用Python计算3队的方法。
练习。修改代码以计算20个队的排名数!
如何在Scipy中计算阶乘?
流行的 [scipy](https://blog.finxter.com/best-10-scipy-cheat-sheets/)库是一个帮助你进行科学计算的库和模块的集合。
Scipy包含一个强大的功能集合--建立在NumPy库之上。因此,SciPy的阶乘函数scipy.math.factorial() 实际上是对NumPy的阶乘函数numpy.math.factorial() 的引用,这并不奇怪。
事实上,如果你用关键字 is 来比较它们的内存地址,就会发现两者都是指代同一个函数对象。
>>> import scipy, numpy
>>> scipy.math.factorial(3)
6
>>> numpy.math.factorial(3)
6
>>> scipy.math.factorial is numpy.math.factorial
True
所以你可以同时使用scipy.math.factorial(3) 和numpy.math.factorial(3) 来计算阶乘函数3! 。
由于这两个函数都指向同一个对象,其性能特征也是一样的--一个并不比另一个快。
让我们来看看math.factorial() --所有阶乘函数之母。
如何在Python的数学库中计算阶乘?
事实证明,不仅NumPy和Scipy带有阶乘函数的打包 "实现",而且Python的强大数学库也有。
你可以用 [math.factorial(n)](https://blog.finxter.com/python-math-factorial-2/)函数来计算阶乘n! 。
这里有一个例子。
>>> import math
>>> math.factorial(3)
6
3的阶乘是6--这里没有什么新东西。
让我们检查一下这是否真的与NumPy和Scipy的阶乘函数的实现相同。
>>> import scipy, numpy, math
>>> scipy.math.factorial is math.factorial
True
>>> numpy.math.factorial is math.factorial
True
哈!NumPy和Scipy两个库都依赖于数学库的同一个阶乘函数。
注意:因此,为了节省 你代码中的宝贵空间 ,如果你已经导入了 库,请使用 阶乘函数。如果没有,就使用NumPy或Scipy的阶乘函数别名。math math
所以到现在为止,我们已经在三个不同的瓶子里看到了同样的老酒。NumPy、Scipy和数学库都提到了同一个阶乘函数的实现。
如何在 Python 中计算阶乘?
自己实现一个函数通常是个好主意。这将帮助你更好地理解底层细节,并给你带来信心和专业知识。
因此,让我们在Python中实现阶乘函数!
要计算一个给定的n 元素集合的排列数,你可以使用阶乘函数n! 。阶乘的定义如下。
n!= n × (n - 1) × ( n - 2) × ... × 1
比如说
- 1! = 1
- 3!= 3 × 2 × 1 = 6
- 10!= 10 × 9 × 8 × 7 × 6 × 5 × 4 × 3 × 2 × 1 = 3,628,800
- 20! = 20 × 19 × 18 × . . . × 3 × 2 × 1 = 2,432,902,008,176,640,000
递归地,阶乘函数也可以定义如下。
n!= n × (n - 1)!
递归基例的定义如图所示。
1! = 0! = 1
这些基例背后的直觉是,一个有一个元素的集合有一个包络,一个有零个元素的集合有一个包络(有一种方法是将零个元素分配给零个桶)。
现在,我们可以使用这个递归定义,以递归的方式计算阶乘函数。
>>> factorial = lambda n: n * factorial(n-1) if n > 1 else 1
>>> factorial(3)
6
自己试试吧。在我们的交互式代码外壳中运行这个单行程序。
练习一下。输出是什么?
lambda 关键字被用来在一行中定义一个匿名函数。
你创建了一个有一个参数的lambda函数n ,并将这个lambda函数赋值为名称factorial 。最后,你调用命名的函数factorial(n-1) 来计算函数调用的结果factorial(n) 。
粗略地说,你可以使用factorial(n-1) 的较简单的解决方案来构建较难的问题factorial(n) 的解决方案,将前者与输入参数n 相乘。
一旦你到达递归基例n <= 1 ,你只需返回硬编码的解决方案factorial(1) = factorial(0) = 1 。
另一种方法是像这样使用迭代计算。
def factorial(n):
fac = n
for i in range(1, n):
fac *= i
return fac
print(factorial(3))
# 6
print(factorial(5))
# 120
在函数factorial(n) 中,我们将变量fac 初始化为值n 。然后,我们遍历1到n-1(包括)之间的所有数值i ,并将其与当前存储在变量fac 中的数值相乘。其结果是整数值n 的阶乘。
速度比较
让我们比较一下三种不同的阶乘函数计算方式的速度。
请注意,NumPy、Scipy和数学阶乘函数引用的是同一个函数对象--它们具有相同的速度属性。
因此,我们只将math.factorial() 函数与我们在Python中的两种实现方式(递归和迭代)进行比较。
想先猜一猜吗?
我使用我自己的笔记本电脑(四核,英特尔酷睿i7,第八代)和Python 3.7,使用以下代码为每种方法运行900次阶乘计算。
import time
num_runs = 900
speed = []
## SPEED TEST MATH.FACTORIAL ##
import math
start = time.time()
for i in range(num_runs):
math.factorial(i)
stop = time.time()
speed.append(stop-start)
## SPEED TEST RECURSIVE ##
factorial = lambda n: n * factorial(n-1) if n > 1 else 1
start = time.time()
for i in range(num_runs):
factorial(i)
stop = time.time()
speed.append(stop-start)
## SPEED TEST ITERATIVE ##
def factorial(n):
fac = n
for i in range(1, n):
fac *= i
return fac
start = time.time()
for i in range(num_runs):
factorial(i)
stop = time.time()
speed.append(stop-start)
## RESULT
print(speed)
# [0.011027336120605469, 0.10074210166931152, 0.0559844970703125]
import matplotlib.pyplot as plt
plt.bar(["Math", "Recursive", "Iterative"], height=speed)
plt.show()

哇--明显的赢家是math 模块!一个明显的迹象是,你应该总是倾向于使用库的代码而不是自己的实现!
math 库的实现几乎比迭代的实现快600%,比递归的实现快1000%。
| 方法 | math.factorial | 递归 | 迭代法 |
| 秒数 | 0.01 | 0.10 | 0.05 |
自己试试吧。你可以在交互式代码外壳中自己进行这个速度比较。
练习。你在你的浏览器中收到类似的结果吗?运行shell来看看吧!
今后的发展方向
三个库的实现numpy.math.factorial(),scipy.math.factorial(), 和math.factorial() 指向内存中的同一个函数对象--它们是相同的,所以使用它们中的任何一个。
在更高的层次上,你已经了解到流行的库如NumPy的库实现是非常快速和高效的。帮你自己一个忙,尽可能地使用库的实现。
NumPy库是一个很好的开始,它是Python中许多高级数据科学和机器学习库的基础,如matplotlib、pandas、tensorflow和scikit-learn。学习NumPy将为你建立你的Python事业奠定基础。
程序员的幽默
Q: How do you tell an introverted computer scientist from an extroverted computer scientist?
A: An extroverted computer scientist looks at your shoes when he talks to you.