Python 使用reduce()归约数据集,可以将sum()
、len()
、max()
和min()
函数看作reduce()
函数的特殊形式。reduce()
函数是高阶函数,能将可迭代对象中相邻的两个值通过指定函数结合在一起。
现有如下序列对象:
d = [2, 4, 4, 4, 5, 5, 7, 9]
reduce()
函数对它应用+
运算符后效果如下:
2 + 4 + 4 + 4 + 5 + 5 + 7 + 9
为了更好地说明计算过程,给上面的表达式加上括号。
((((((2 + 4) + 4) + 4) + 5) +5 ) + 7) + 9
Python对表达式的标准解释方式是从左到右求值,所以与左卷积(fold-left)是同一个意思。有些函数式语言提供了右卷积(fold-right)函数,当与递归组合使用时,这些函数会进行优化处理。不过在Python中,归约都是从左到右进行的,所以不存在优化问题。
可以给归约提供一个初始值,如下所示:
reduce(lambda x, y: x + y ** 2, iterable, 0)
如果不提供,则将序列的第一个值用作初始值。设置初始值的方式对于map()
函数和reduce()
函数都非常重要。下面通过设置初始值为0得到正确的计算结果:
0 + 2**2 + 4**2 + 4**2 + 4**2 + 5**2 + 5**2 + 7**2 + 9**2
如果不设置初始值,reduce()
函数使用序列的第一个值作为初始值,这个值就不会传递给卷积函数,导致计算错误。没有初始值的reduce()
函数的计算过程如下所示:
2 + 4**2 + 4**2 + 4**2 + 5**2 + 5**2 + 7**2 + 9**2
这样的错误告诉我们使用reduce()
函数时务必小心。
下面通过reduce()
高阶函数定义一些内置的归约函数。
sum2 = lambda data: reduce(lambda x, y: x + y ** 2, data, 0)
sum = lambda data: reduce(lambda x, y: x + y, data, 0)
count = lambda data: reduce(lambda x, y: x + 1, data, 0)
min = lambda data: reduce(lambda x, y: x if x < y else y, data)
max = lambda data: reduce(lambda x, y: x if x > y else y, data)
其中sum2()
归约函数计算序列的平方和,在求样本集的标准差时很有用。sum()
归约函数模仿内置的sum()
函数的功能。count()
归约函数与len()
函数的功能类似,不过前者可以接收可迭代对象作为参数,而后者只能处理实例化的集合对象。
min()
函数和max()
函数模仿内置同名函数的功能。这里将序列第一个值作为初始值以保证计算结果正确。如果对reduce()
函数指定了额外的初始值,则会由于提供了一个序列中不存在的值而得到错误的结果。