说明
《Python 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
Python reduce 将两个参数的 function 从左至右积累地应用到 iterable 的条目,以便将该可迭代对象缩减为单一的值。Python3.x reduce() 已经被移到 functools 模块里,如果我们要使用,需要引入 functools 模块来调用 reduce() 函数。Python 之父 Guido 专门撰文讨论过 reduce 在 Python 3 的去留问题(见参考)。
它的语法是:functools.reduce(function, iterable[, initializer])
。可以理解为 reduce 中的第一个参数 function 是一个函数,它有两个变量(function 的变量),iterable 是一个序列,function 第一次执行时,按顺序先取两个传入执行,得到一个结果,然后再将这个结果与 iterable 中的下一个值(还是两个变量)传入 function 执行,如此反复直到 iterable 里的值取完为止,最终就能得到一个终极的返回值。
由于在 Python 3.x 开始,它从内置函数中移除,使用时需要导入:
from functools import reduce
例如,reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) 是计算 ((((1+2)+3)+4)+5) 的值。 左边的参数 x 是积累值而右边的参数 y 则是来自 iterable 的更新值。
如果存在可选项 initializer,它会被放在参与计算的可迭代对象的条目之前,并在可迭代对象为空时作为默认值。 如果没有给出 initializer 并且 iterable 仅包含一个条目,则将返回第一项。
大致相当于:
def reduce(function, iterable, initializer=None):
it = iter(iterable)
if initializer is None:
value = next(it)
else:
value = initializer
for element in it:
value = function(value, element)
return value
另外,如果我们要计算累加,还是继续使用 sum(),不建议用 reduce():
reduce(lambda x, y: x+y, [1,2,3,4,5])
简单的逻辑可使用 lambda 匿名函数。
我们做一个累积相除的功能:
from functools import reduce
from operator import truediv
reduce(truediv, [4, 3, 2, 1])
reduce(lambda x,y: x/y, [4, 3, 2, 1])
# 0.6666666666666666
指定 initializer 参数时,第一次执行时,函数的第一个参数传入此值,第二个参数为序列的第一个值:
from functools import reduce
from operator import truediv
reduce(truediv, [10, 5, 2], 50)
# 0.5
当序列为空时,则返回就是 initializer 的值:
reduce(truediv, [], 50)
# 50
如果 initializer 没有指定,序列也会空,则会报错:
reduce(truediv, [])
# TypeError: reduce() of empty iterable with no initial value
如果没有指定 initializer 并且序列的值只有一个时,则直接返回这个仅有的一个序列值:
reduce(truediv, [10])
# 10
pandas 提供的 pd.merge() 只允许传入两个 DataFrame,但如果有一堆 DataFrame 需要合并,那么这时候就可以用 reduce() 了:
reduce(lambda a, b: pd.merge(a, b, on=['ID']), dflist)
Python的 reduce() 的性能可能非常差,因为它通过多次调用函数来工作。这会使您的代码变得缓慢和低效。当您将 reduce() 用于复杂的用户定义函数或 lambda 函数时,使用 reduce() 还会影响代码的可读性。
Python 提供了一系列工具,可以优雅地替换 reduce(),至少在其主要用例中是如此。主要有:
第二点和第三点是 Guido 自己的担忧,他说:
所以现在 reduce() 这实际上是我最讨厌的一个,因为除了一些涉及
+
或*
的示例外,几乎每次我看到带有非平凡函数参数的 reduce() 调用时,我都需要抓起纸笔来绘制实际输入到该函数中的内容,然后才能理解 reduce() 应该做什么。所以在我看来,reduce() 的适用性非常局限于关联运算符,在所有其他情况下,最好显式写出积累循环。(来源:https://www.artima.com/weblogs/viewpost.jsp?thread=98196)
以下是用内置函数与reduce() 方法的性能对比:
from timeit import timeit
timeit('sum(range(100))')
# 0.7738632510008756
timeit('reduce(lambda x,y: x+y, range(100))',
setup='from functools import reduce')
# 6.639591105020372
如果您打算使用 reduce() 来解决问题,那么与使用专用内置函数的代码相比,您的代码将慢得多,内置函数比如求和问题(sum)最具可读性和 python 风格的解决方案。
关于 reduce() 的使用方法的一些总结:
reduce(function, iterable[, initializer])
如果我不想得到最终值,想把每次计算结果保存起来,怎么办?
请参阅 itertools.accumulate() 它可以把 reduce 执行每次执行过程产生所有中间值形成一个迭代器,供迭代使用(而 reduce 会给一个最终值,就是迭代器的最后一个值)。
NumPy reduction function:https://numpy.org/doc/stable/reference/generated/numpy.ufunc.reduce.html
更新时间:2022-01-12 23:35:28 标签:pytho reduce 函数