说白了就是复合函数(比如f(g(x+y))),再说高阶函数之前,你首先要明白,函数是可以作为一个变量进行赋值的,在Python里面,所有变量和函数都是一个object,都是一个类型,下面看实例代码吧:
这个过程中,你应该时刻明白,Python中不管你是什么,你都是一个object,都可以作为参数进行传递,多个函数相互组合在一起,自然就形成了高阶函数
python 使用 lambda 来创建匿名函数。
- lambda只是一个表达式,函数体比def简单很多。
- lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
- lambda函数拥有自己的命名空间,且不能访问自有参数列表之外或全局命名空间里的参数。
- 虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。
- 最重要的一点,Lambda表达式可以体现你的逼格。华尔街和伦敦银行高街最逼的一群人都是自诩用且只用函数式编程的。什么是函数式编程?就是类似于全篇程序都用python中lambda这样的一行代码来解决问题。为什么他们逼?因为数学家们学编程的时候,脑子还在数学公式这条线上;他们不会写面对对象编程,只会死想出一条条公式来解决问题;其实这是智商堪忧的体现;但是因为投行基金们很倾向于聘用这群数学家转型的半吊子程序员;他们的使用习惯于是成了圈内高逼的体现;恩,葡萄就是这么酸。:P。
Lambda函数的语法只包含一个语句,如下:
比如,我写个相加函数:
楼上这个,实际上就是一个函数:
除了Lambda本身,Python还提供了其他几个辅助工具,让你的函数式代码块更加牛逼:
reduce
Python中的reduce内建函数是一个二元操作函数,他用来将一个数据集合(列表,元组等)中的所有数据进行如下操作:传给reduce中的函数func() (必须是一个二元操作函数)先对集合中的第1,2个数据进行操作,得到的结果再与第三个数据用func()函数运算,最后得到一个结果。
顾名思义,reduce就是要把一个list给缩成一个值。所以你必须用二元操作函数。
map
map函数应用于每一个可迭代的项,返回的是一个结果list。如果有其他的可迭代参数传进来,map函数则会把每一个参数都以相应的处理函数进行迭代处理。map()函数接收两个参数,一个是函数,一个是序列,map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回。
格式:map(func, seq1[, seq2...] )
Python函数式编程中的map()函数是将func作用于seq中的每一个元素,并用一个列表给出返回值。
map可以使用任何的lambda函数操作,本质上是把原有的list根据lambda法则变成另外一个list
filter()函数可以对序列做过滤处理,就是说可以使用一个自定的函数过滤一个序列,把序列的每一项传到自定义的过滤函数里处理,并返回结果做过滤。最终一次性返回过滤后的结果。 和map()类似,filter()也接收一个函数和一个序列。和map()不同的时,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
语法
filter(func, seq)
熟练运用以上三个玩意儿,你就可以一行写出几乎所有的复杂计算了。
3、装饰器
装饰器就是函数的『包装』:
我们来看一个代码:
输出:
你可以看到如下的东西:
1)函数foo前面有个@hello的“注解”,hello就是我们前面定义的函数hello
2)在hello函数中,其需要一个fn的参数(这就用来做回调的函数)
3)hello函数中返回了一个inner函数wrapper,这个wrapper函数回调了传进来的fn,并在回调前后加了两条语句。
所以,本质上来讲,用@decorator来装饰某个函数时,其实是做了下面这件事儿:
变成 =====》
再简单点说,就是把一个函数传到另外一个函数中,再调回给自己。
所以:
hello(foo)返回了wrapper()函数,所以,foo其实变成了wrapper的一个变量,而后面的foo()执行其实变成了wrapper()
同理,我们也可以搞多个decorator:
相当于:
你还可以给这个decorator带个参数:
相当于:
好了,讲这么多比较复杂,我们来看个网页编程的case:
在上面这个例子中,我们可以看到:makeHtmlTag有两个参数。所以,为了让 hello = makeHtmlTag(arg1, arg2)(hello) 成功,makeHtmlTag 必需返回一个decorator(这就是为什么我们在makeHtmlTag中加入了real_decorator()的原因),这样一来,我们就可以进入到 decorator 的逻辑中去了—— decorator得返回一个wrapper,wrapper里回调hello。
Decorator这个东西,也可以写成class样式:
输出:
这个class样式的看起来比函数样式看着清楚点儿,这样我们再把刚刚的网页编程那段改一下,就得到:
输出:
装饰器的副作用:
因为decorator的因素,我们原本的函数其实已经变成了一个叫wrapper函数。
比如,你再调用的时候,他会告诉你,这是 wrapper, 而不是 foo 或者 hello。
当然,虽然功能效果不变,但是有些处女座的童鞋会觉得很不爽。
所以,Python的functool包中提供了一个叫wrap的decorator来消除这样的副作用:
输出:
来个经典例子:
斐波那契额数列递归法:
我们知道,这个递归是相当没有效率的,因为会重复调用。比如:我们要计算fib(5),于是其分解成fib(4) + fib(3),而fib(4)分解成fib(3)+fib(2),fib(3)又分解成fib(2)+fib(1)…… 你可看到,基本上来说,fib(3), fib(2), fib(1)在整个递归过程中被调用了两次。
而我们用decorator,在调用函数前查询一下缓存,如果没有才调用了,有了就从缓存中返回值。一下子,这个递归从二叉树式的递归成了线性的递归。
Python的functools模块提供了很多有用的功能,其中一个就是偏函数(Partial function)。
偏函数又可以翻译成部分函数,大概意思就是说,只设置一部分参数。
举个例子,我们知道int()可以把字符串变成十进制数字:
但int()函数还提供额外的base参数,默认值为10。如果传入base参数,就可以做N进制的转换:
假设要转换大量的二进制字符串,每次都传入int(x, base=2)非常麻烦,于是,我们想到,可以定义一个int2()的函数,默认把base=2传进去:
这样,我们转换二进制就非常方便了:
functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义int2(),可以直接使用下面的代码创建一个新的函数int2:
所以,简单总结functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。
注意到上面的新的int2函数,仅仅是把base参数重新设定默认值为2,但也可以在函数调用时传入其他值:
最后,创建偏函数时,实际上可以接收函数对象、这3个参数,当传入:
实际上固定了int()函数的关键字参数base。
同理:我们刚刚说的可以当成一个dict带入
继续同理,我们可以用把一个list塞进来
相当于:
注意,10在最左边。
5、实战
今天的课程实践会结合上节课给你们的代码内容。
上节课我们讲了如果写个Dataset类来帮我们下载和处理数据。
这节课我们学习了文本的读入,那我们就来做做更加复杂的内容:
本节课的压缩包里有一个数据文件,是我们今天实战的数据。
这是美国亚利桑那州Pima印第安女人患有糖尿病状况的数据集(因为他们的得病率很高)。
这个数据是一个txt文件(其实是个csv),每一行就是一个数据条,长这样:
其中,前面N-1个数据,分别是一些身体的指标,比如:血压,血糖,身高,是否怀孕等等。 最后第N个数据点是记录她是否患有糖尿病,它只有0或者1两种可能。这也就是我们说的数据标签。
所以,这里我们脑海中应该浮现的数据结构如下:
所以,这是一个二元分类问题。
参照上一堂课的内容,我们要做如下的修改:
- Dataset这个类中的download_data函数要被修改,改成我们从外部读入数据的过程。并且要把我们的x和y分开储存,并返回。
- 我们这次依旧是以0.7的比率分开训练集和测试集。当我们得到区分开的 以后,我们把这些个数据分别用Json或者Pickle的方法序列化在我们文件夹内。然后我们新建一个程序,从中反序列化我们处理好的数据。并进行之后的Machine Learning过程。
- 当我们把一个model训练好以后,我们代入全部的x_test数据,并得到我们预测出来的分类值y_preds。我们把这个值(list)与我们的y_test相互比较,用一些正确率统计的方法计算我们model的准确率,并用lambda函数来实现
预测数据的直接准确率怎么计算?
准确率 = (对的数据数 / 全部数据数) * 100%
高级一点,
我们可以再实现一点其他准确率计算方式:
AUC,MSE,...
详情可见附录的cheat sheet,或者自行百度。
OK!
自己动手尝试一下吧!
好吧,这一节写的有点偷懒(主要是暂时用不到,以后用到可能会再整理一下),2小节以后直接粘贴复制的
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ri-ji/72736.html