Python函数式编程-map()、zip()、filter()、reduce()、lambda()

三个函数比较类似,都是应用于序列的内置函数。常见的序列包括list、tuple、str


map函数


map函数会根据提供的函数对指定序列做映射。

map函数的定义:

map(function, sequence[, sequence, ...]) -> list

map()函数接收两个参数,一个是函数,一个是序列,map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回。


1、当seq只有一个时,将函数func作用于这个seq的每个元素上,并得到一个新的seq。
让我们来看一下只有一个seq的时候,map()函数是如何工作的。

这里写图片描述

示例一

比如要对一个序列中的每个元素进行平方运算:

map(lambda x: x ** 2, [1, 2, 3, 4, 5])

返回结果为:

[1, 4, 9, 16, 25]

或者

>>> def f(x):
...   return x * x
...
>>> map(f, [1, 2, 3, 4, 5])
[1, 4, 9, 16, 25]

map()传入的第一个参数是f,即函数对象本身。

注意:map()函数不改变原有的 list,而是返回一个新的 list。

不需要map()函数,写一个循环,也可以计算出结果

L = []
for n in [1, 2, 3, 4, 5]:L.append(f(n))
print L

把f(x)作用在list的每一个元素并把结果生成一个新的list。

示例二

#使用lambda
>>> print map(lambda x: x % 2, range(7))
[0, 1, 0, 1, 0, 1, 0]
#使用列表解析
>>> print [x % 2 for x in range(7)]
[0, 1, 0, 1, 0, 1, 0]

2、当seq多于一个时,map可以并行(注意是并行)地对每个seq执行如下图所示的过程

这里写图片描述

在参数存在多个序列时,会依次以每个序列中相同位置的元素做参数调用function函数。

示例

比如要对两个序列中的元素依次求和。

map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])

map返回的list中第一个元素为,参数序列1的第一个元素加参数序列2中的第一个元素(1 + 2),
list中的第二个元素为,参数序列1中的第二个元素加参数序列2中的第二个元素(3 + 4),
依次类推,最后的返回结果为:

[3, 7, 11, 15, 19]

要注意function函数的参数数量,要和map中提供的集合数量相匹配。
如果集合长度不相等,会以最小长度对所有集合进行截取。


当函数为None时,操作和zip相似

map(None, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])

返回结果为:

[(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]


map()作为高阶函数,事实上它把运算规则抽象了,因此,我们不但可以计算简单的f(x)=x2,还可以计算任意复杂的函数,比如,把这个list所有数字转为字符串

>>> map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9])
['1', '2', '3', '4', '5', '6', '7', '8', '9']

由于list包含的元素可以是任何类型,因此,map() 不仅仅可以处理只包含数值的 list,事实上它可以处理包含任意类型的 list,只要传入的函数f可以处理这种数据类型。

比如假设用户输入的英文名字不规范,没有按照首字母大写,后续字母小写的规则,请利用map()函数,把一个list(包含若干不规范的英文名字)变成一个包含规范英文名字的list:
输入:[‘adam’, ‘LISA’, ‘barT’]
输出:[‘Adam’, ‘Lisa’, ‘Bart’]

def format_name(s):s1=s[0:1].upper()+s[1:].lower();return s1;print map(format_name, ['adam', 'LISA', 'barT'])
***将元组转换成list***
>>> map(int, (1,2,3))
[1, 2, 3]
***将字符串转换成list***
>>> map(int, '1234')
[1, 2, 3, 4]
***提取字典的key,并将结果存放在一个list中***
>>> map(int, {1:2,2:3,3:4})
[1, 2, 3]
***字符串转换成元组,并将结果以列表的形式返回***
>>> map(tuple, 'agdf')
[('a',), ('g',), ('d',), ('f',)]
#将小写转成大写
def u_to_l (s):return s.upper()
print map(u_to_l,'asdfd')

zip函数


Python函数式编程之zip()
zip()函数具体的工作机制是,将每个列表中同一位置的元素取出来组成一个元组,存放到一个列表中,然后返回这个列表。

>>> x = [1,2,3]
>>> y = ['a','b','c']
>>> z = [4,5,6]
>>> zip_xyz = zip(x, y, z)
>>> print zip_xyz
[(1, 'a', 4), (2, 'b', 5), (3, 'c', 6)]

对于长度不同的seq,zip()函数又怎么处理呢?

>>> a = [1,2,3]
>>> b = [4,5,6,7]
>>> zip_ab = zip(a, b)
>>> print zip_ab
[(1, 4), (2, 5), (3, 6)]

从上面的例子可以看出,当seq的长度不一致时,zip()会以最短的那个seq为主,进行处理,然后将多余的舍弃掉。

zip()对只有一个seq的处理:

>>> c = ['a', 'b', 'c']
>>> zip_c = zip(c)
>>> print zip_c
[('a',), ('b',), ('c',)]

unzip

>>> a = [1, 2, 3]
>>> b = ['a', 'b', 'c']
>>> zip_ab = zip(a,b)
>>> un_zip = zip(*zip_ab)
>>> print un_zip
[(1, 2, 3), ('a', 'b', 'c')]

一般认为这是一个unzip过程,工作原理如下:
在运行zip(*zip_ab)之前,zip_ab的值是:[(1, ‘a’), (2, ‘b’), (3, ‘c’)]
而zip(*zip_ab)就等价于zip((1, ‘a’), (2, ‘b’), (3, ‘c’))
所以得出结果:[(1, 2, 3), (‘a’, ‘b’, ‘c’)]

>>> x = [1,'a','b']
>>> zip_rx = zip(* [x] * 3)
>>> print zip_rx
[(1, 1, 1), ('a', 'a', 'a'), ('b', 'b', 'b')]

首先 [x]生成一个列表的列表:[[1, ‘a’, ‘b’]],这个列表中只有一个元素[1,’a’,’b’]
其次[x] * 3,表示将列表中的元素打印三次,即生成了含有三个元素的列表:
[[1, ‘a’, ‘b’], [1, ‘a’, ‘b’], [1, ‘a’, ‘b’]]
最后是zip(* [x] * 3)就等价于
zip([1, ‘a’, ‘b’], [1, ‘a’, ‘b’], [1, ‘a’, ‘b’])


filter函数


filter函数会对指定序列执行过滤操作。
filter函数的定义:

filter(function or None, sequence) -> list, tuple, or string

filter函数会对序列参数sequence中的每个元素调用function函数,最后返回的结果包含调用结果为True的元素序列。返回值的类型和参数sequence的类型相同. func函数是一个布尔函数,filter()函数调用这个函数一次作用于seq中的每一个元素,筛选出符合条件的元素,并以列表的形式返回。

示例一

比如返回序列中的所有偶数:

def is_even(x):
return x & 1 != 0filter(is_even, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

返回结果为:
[1, 3, 5, 7, 9]
如果function参数为None,返回结果和sequence参数相同。

示例二

假如有个列表,列表中有几个数字,现在我想从这些数字中,选出即能被2整除又能被3整除的数。

nums = [2,3,6,12,15,18]
def nums_res (x):return x % 2 == 0 and x % 3 == 0
print filter(nums_res, nums)
执行结果:[6, 12, 18]

如果使用普通方法的话,就需要使用for循环去挨个挨个遍历list中的元素。当然我们也可以使用列表解析法:

>>> print [x for x in nums if x % 2 == 0 and x % 3 == 0]
[6, 12, 18]

reduce函数


reduce函数,即为化简函数,reduce函数会对参数序列中元素进行累积。
reduce函数的定义:

reduce(function, sequence[, initial]) -> value

function参数是一个有两个参数的函数,reduce依次从sequence中取一个元素,和上一次调用function的结果做参数再次调用function。
第一次调用function时,如果提供initial参数,会以sequence中的第一个元素和initial作为参数调用function,否则会以序列sequence中的前两个元素做参数调用function。

reduce()函数的执行过程如下图所示

这里写图片描述

reduce把一个函数作用在一个序列[x1, x2, x3…]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

示例一

比方说对一个序列求和,就可以用reduce实现

>>> def add(x, y):
...   return x + y
...
>>> reduce(add, [1, 3, 5, 7, 9])
25

或者

reduce(lambda x, y: x + y, [1, 3, 5, 7, 9])

结果为25

或者

reduce(lambda x, y: x + y, [3, 5, 7, 9], 1)

结果为25( ((((1+3)+5)+7)+9) )

当然求和运算可以直接用Python内建函数sum(),没必要动用reduce。

示例二

从reduce函数的执行过程,很容易联想到求一个数的阶乘,而python中并没有给出一个求阶乘的内置函数,正好就拿这个例子来说明reduce函数。

#未指定init的情况
>>> n = 6
>>> print reduce(lambda x, y: x * y, range(1, n))
120

上面的例子中range(1,6)函数生成的是一个[1, 2, 3, 4, 5]这样的列表,这里我们给它个名叫seq1吧,reduce()函数执行时,由于没有指定init参数,所以将取seq1中的第一个元素1,作为第一个元素,由于前面的lambda有2个变量,所以需要两个实参,于是就取seq1中的第2个元素2,与第一个元素1一起传入lambda中去执行,并将返回结果2,并同下一个元素3再一起传入lambda中执行,再次返回的结果,作为下一次执行的第一个元素,依次类推,就得出结果5! = 120。

如果我们希望得到阶乘的结果再多增加几倍,可以启用init这个可选项。如:

>>> print reduce(lambda x, y: x * y, range(1, n),2)
240

这个时候,就会将init作为第一个元素,和seq1中的第一个元素1一起传入lambda函数中去执行,返回结果再作为下一次的第一个元素。


但是如果要把序列[1, 3, 5, 7, 9]变换成整数13579,reduce就可以派上用场

>>> def fn(x, y):
...   return x * 10 + y
...
>>> reduce(fn, [1, 3, 5, 7, 9])
13579

这个例子本身没多大用处,但是,如果考虑到字符串str也是一个序列,对上面的例子稍加改动,配合map(),我们就可以写出把str转换为int的函数:

>>> def fn(x, y):
...   return x * 10 + y
...
>>> def char2num(s):
...   return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
...
>>> reduce(fn, map(char2num, '13579'))
13579

整理成一个str2int的函数就是:

def str2int(s):def fn(x, y):return x * 10 + ydef char2num(s):return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]return reduce(fn, map(char2num, s))

还可以用lambda函数进一步简化成

def char2num(s):return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
def str2int(s):return reduce(lambda x,y: x*10+y, map(char2num, s))

也就是说,假设Python没有提供int()函数,你完全可以自己写一个把字符串转化为整数的函数,而且只需要几行代码

注意function函数不能为None。


lambda函数


Python中,lambda函数也叫匿名函数,及即没有具体名称的函数,它允许快速定义单行函数,类似于C语言的宏,可以用在任何需要函数的地方。这区别于def定义的函数。
lambda与def的区别:

1)def创建的方法是有名称的,而lambda没有。
2)lambda会返回一个函数对象,但这个对象不会赋给一个标识符,而def则会把函数对象赋值给一个变量(函数名)。
3)lambda只是一个表达式,而def则是一个语句。
4)lambda表达式” : “后面,只能有一个表达式,def则可以有多个。
5)像if或for或print等语句不能用于lambda中,def可以。
6)lambda一般用来定义简单的函数,而def可以定义复杂的函数。
6)lambda函数不能共享给别的程序调用,def可以。

lambda语法格式:
lambda 变量 : 要执行的语句

lambda [arg1 [, agr2,…..argn]] : expression

1、单个参数的:
>>> g = lambda x : x ** 2
>>> print g(3)
9
2、多个参数的:
>>> g = lambda x, y, z : (x + y) ** z
>>> print g(1,2,2)
9

lambda表达式会返回一个函数对象,如果没有变量接受这个返回值的话,它很快就会被丢弃。也正是由于lambda只是一个表达式,所以它可以直接作为list和dict的成员。如:

>>> list_a = [lambda a: a**3, lambda b: b**3]
>>> list_a[0]
<function <lambda> at 0x0259B8B0>
>>> g = list_a[0]
>>> g(2)
8

lambda表达式中,冒号前面是参数,可以有多个,用逗号分隔,冒号右边是返回值。


参考文献


python中的map、filter、reduce函数

python map函数

Python map()函数的用法

Python reduce()函数的用法

Python filter()函数的用法

Python lambda函数的用法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/246806.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Kaggle : Using a Convolutional Neural Network for classifying Cats vs Dogs

数据下载 https://www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition/data Part 1 - Preprocessing #Package Requirements #!/usr/bin/python2 # -*- coding: UTF-8 -*- import cv2 # working with, mainly resizing, images import numpy as np …

李宏毅机器学习课程1~~~Introduction Regression

机器学习介绍 机器学习就是要找一个函数。 机器学习的三大要素框架&#xff1a;训练集&#xff0c;函数集&#xff08;模型集&#xff09;&#xff0c;损失函数集。 机器学习图谱 AI训练师的成长之路。 1. 梯度下降法的理解Gradient Descent 参数变化的方向就是损失函数减少的方…

李宏毅机器学习课程2~~~误差从哪里来?

Stanford机器学习—第六讲. 怎样选择机器学习方法、系统 误差来源 误差主要来自于偏差和方差。 数学上定义&#xff1a; 通过covariate X 预测 Y &#xff0c;我们假设存在如下关系&#xff1a; Y f(X) ϵ 满足正态分布均值为0 方差σϵ 模型预测错误定义为&#xff1a; …

李宏毅机器学习课程3~~~梯度下降法

梯度下降法描述 梯度下降法是为了找到最优的目标函数&#xff0c;寻找的过程就是沿着损失函数下降的方向来确定参数变化的方向。参数更新的过程就是一个不断迭代的过程&#xff0c;每次更新参数学到的函数都会使得误差损失越来越小&#xff0c;也就是说学习到的参数函数越来越逼…

李宏毅机器学习课程4~~~分类:概率生成模型

分类问题用回归来解决&#xff1f; 当有右图所示的点时&#xff0c;这些点会大幅改变分类线的位置。这时候就会导致整体的回归结果变差。当把多分类当成回归问题&#xff0c;类别分别为1&#xff0c;2,3,4……&#xff0c;因为回归的问题是预测具体的值&#xff0c;这样定义类别…

李宏毅机器学习课程5~~~分类:逻辑回归

Function Set 不同的w&#xff0c;b来确定不同的函数&#xff0c;这样就组成了函数集合&#xff0c;不同的w&#xff0c;b可以来表达不同的分布函数。 Good of a Function 变换表达形式 两个Bernoulli distribution的交叉熵。所谓交叉熵&#xff0c;是用来刻画两个分布的相似性…

李宏毅机器学习课程6~~~深度学习入门

深度学习历史 深度学习经典步骤 神经网络的符合标记含义 Wij 代表的是从神经元&#xff4a;到神经元&#xff49;&#xff0c;这样写的目的是便于表达&#xff0c;否则最后的表达式子就是Wij的转置&#xff0c;细节见下面。 每个神经元的偏执值组成一个向量&#xff42; 单个神…

李宏毅机器学习课程7~~~反向传播

到底为什么基于反向传播的纯监督学习在过去表现不佳&#xff1f;Geoffrey Hinton总结了目前发现的四个方面问题&#xff1a; 带标签的数据集很小&#xff0c;只有现在的千分之一. 计算性能很慢&#xff0c;只有现在的百万分之一. 权重的初始化方式笨拙. 使用了错误的非线性模型…

李宏毅机器学习课程8~~~keras

keras keras示例 确定网络结构 确定损失函数 确定训练网络参数 batchsize与运算时间&#xff0c;平行运算&#xff0c;可以缩简运算时间。batchsize不能太大&#xff0c;这是由于内存的关系。此外&#xff0c;batchsize太大容易陷入局部极值点或者鞍点。batchsize&#xff1d;&…

李宏毅机器学习课程9~~~深度学习技巧

Recipe of Deep Learning Overfitting overfitting的判断是要训练误差与测试误差做比较。这个56-layer的网络在训练集上都没有训练好&#xff0c;说白了就是有点欠拟合。所以仅仅依靠测试集上的结果来判断56-layer比20-layer overfitting是不合理的。 更多理解见 Overfitting…

Liner(分段线性插值)

第一次写微博&#xff0c;记录自己的学习历程~~~~欢迎大家一起探讨~~~~ 分段线性插值故名思议就是说把给定样本点的区间分成多个不同区间&#xff0c;记为[xi,xi1]&#xff0c;在每个区间上的一次线性方程为&#xff1a; 关于其证明&#xff1a; 分段线性插值在速度和误差取得…

在linux设置回收站 - 防止失误操作造成数据清空,并定期清理

安装trash sudo apt-get install trash-chi 原理 执行trash命令后&#xff0c;是将文件移动了用户的回收站&#xff0c;每个用户的回收站路径为$HOME/.local/share/Trash&#xff0c;比如用户asin的回收站位于/home/asin/.local/share/Trash&#xff0c;用户root的回收站位于…

Spline(三次样条插值)

关于三次样条插值&#xff0c;计算方法比较复杂&#xff0c;但是静下心来仔细研究也是可以理解的。 本文借鉴文章来源&#xff1a;http://www.cnki.com.cn/Article/CJFDTotal-BGZD200611035.htm 定义&#xff1a; 简单来说就是给定了一些在区间[a,b]的数据点{x1,x2,x3.....xn…

李宏毅机器学习课程10~~~卷积神经网络

卷积的意义 数字图像是一个二维的离散信号&#xff0c;对数字图像做卷积操作其实就是利用卷积核&#xff08;卷积模板&#xff09;在图像上滑动&#xff0c;将图像点上的像素灰度值与对应的卷积核上的数值相乘&#xff0c;然后将所有相乘后的值相加作为卷积核中间像素对应的图像…

matlab自带的插值函数interp1的四种插值方法

x0:2*pi; ysin(x); xx0:0.5:2*pi;%interp1对sin函数进行分段线性插值&#xff0c;调用interp1的时候&#xff0c;默认的是分段线性插值 y1interp1(x,y,xx); figure plot(x,y,o,xx,y1,r) title(分段线性插值)%临近插值 y2interp1(x,y,xx,nearest); figure plot(x,y,o,xx,y2,r); …

拉格朗日插值法(Lagrange)

拉格朗日插值法是基于基函数的插值方法&#xff0c;插值多项式可以表示为&#xff1a; 其中称为 i 次基函数 Matlab中拉格朗日插值法函数为:Language 功能&#xff1a;求已知点数据点的拉格朗日多项式 调用格式&#xff1a;fLagrange(x,y) 或者 f ’Lagrange(x,y,x0) 其中&a…

当你在应用机器学习时你应该想什么

如今, 机器学习变得十分诱人, 它已在网页搜索, 商品推荐, 垃圾邮件检测, 语音识别, 图像识别, 自然语言处理等诸多领域发挥重要作用. 和以往我们显式地通过编程告诉计算机如何进行计算不同, 机器学习是一种数据驱动方法(data-driven approach). 然而, 有时候机器学习像是一种”…

利用均差的牛顿插值法(Newton)

函数f的零阶均差定义为 &#xff0c;一阶定义均差为&#xff1a; 一般地&#xff0c;函数f 的k阶均差定义为&#xff1a; 或者上面这个式子求的k1阶均差 利用均差的牛顿插值法多项式为&#xff1a; 简单计算的时候可以观看下面的差商&#xff08;均差&#xff09;表&#xff1a…

深度学习(Deep Learning)读书思考三:正则化

概述 正则化是机器学习中非常重要并且非常有效的减少泛华误差的技术&#xff0c;特别是在深度学习模型中&#xff0c;由于其模型参数非常多非常容易产生过拟合。因此研究者也提出很多有效的技术防止过拟合&#xff0c;比较常用的技术包括&#xff1a; 参数添加约束&#xff0c;…

利用差分的牛顿插值法(Newton)

差分牛顿插值法要求是等距的。 先来看三个概念 差分与均差的关系如下&#xff1a; 牛顿(Newton)插值的基本公式为&#xff1a; 由于差分插值是等距的&#xff0c;所以可以设xx0nh 对于上式 再由差分和均差的关系&#xff0c;可以将上面的黄色部分也就是牛顿插值基本公式转换…