大数据分析与应用实战:统计机器学习之数据导向编程
上QQ阅读APP看书,第一时间看更新

1.6 编程范式与面向对象概念

面向对象编程(object-oriented programming)是一种结构化程序的方式,使得个别对象的性质(属性)与行为(方法),得以封装成一个抽象的类别(class),以供反复利用。所谓相近对象(object)归为类,相近的意思正是同类对象有共同的性质与行为。举例来说,类别如果是人,名字、年龄与地址等就是应具有的属性,走路、说话、呼吸与跑步等就是人的行为或方法;电子邮件类别具有收件人列表、主题、内容主体等属性,而添加附件与发送等即为方法。对象是将抽象类中属性与方法具体实现后的结果,例如,张三与李四都是依照前述人的类别实例化(instantiate,有具体赋形之意)出来的实体对象,你打算通过电子邮件发送邀请函给张三与李四,则此封电子邮件对象的收件人列表包括张三与李四两人,且必有主题与内容主体等属性,并可在其中添加邀请函并发送出去。

从上面的说明可发现面向对象概念是对真实世界各种具体事物,及其之间的关系建模的一种方式,例如公司与员工、学生与老师等之间的关系。就数据驱动程序设计与大数据分析而言,面向对象概念将人类对真实世界的知识,视为软件中的对象,其下有属性数据,并可进行某些函数的运算。例如,如果时间序列(time series)为一类别,则开始时间、结束时间、采样频率等为该类别的属性,时间序列分解是该类别的方法;个人体重的历史记录则为时间序列类别实操出来的时间序列对象;数据科学工作者通常不太在乎时间序列对象的实际存储方式,关心的是这类数据对象的创建方法、所具有的属性与各种处理的方法。

泛函式编程(functional programming)是另一种重要的编程范式,它将计算机运算视为数学上的函数计算,也就是应用数学函数的输入(input)、处理(processing)与输出(output)的概念编写程序。泛函式编程支持且鼓励无副作用(side effects)的程序设计,因为副作用让程序变得复杂且容易产生错误。具体来说,泛函式编程倡导利用简单的执行区块,让程序计算结果不断渐进,逐层推导最终所需要的运算结果,而不是设计一个复杂的执行过程。

程序式编程(procedural programming)是历史悠久的编程范式,如同食谱一样,它提供完成一项任务的循序步骤,步骤内容的形式可能是处理函数或/及代码区块。代码区块依据任务所需,可以反复多次地执行某些指令语句的循环(loop),或者当某些条件满足时,才执行后续指令语句的流程控制(flow control),详见1.7节控制流程与自定义函数。

当代许多程序语言以混合范式(mixed paradigms)的方式进行编程,两种常用的数据分析脚本语言R与Python都结合了传统程序式编程、面向对象编程与泛函式编程等编程范式语法,以期有效完成数据处理与分析的任务。以Python为例,泛函式编程的写法是载入numpy套件并简记为np后,引用numpy套件中的std()函数,将类别为列表(list)的数据对象(data object)[1,2,3]传入函数中进行其标准偏差的计算。

另一种面向对象编程的方法是先创建numpy的数组(array)类对象a后,引用对象a下的方法(method)std(),以计算对象a本身的标准偏差。

Python语言向量化(vectorization)做法与1.5节所述相同,是将一运算施加在复杂对象一次,而非将其元素取出进行迭代式运用。例如,欲对前述ndarray的对象a中三个元素进行方根运算,仅须将其传入numpy的向量化函数sqrt()中,即可对各元素一一计算其方根值。

而Python隐式循环(implicit looping)要先将对象a从ndarray对象转为pandas套件Series序列类型,再引用序列类型的apply()方法,传入关键词为lambda的匿名函数(anonymous function),逐一取出a中元素(代号为x)进行加4处理,完成循环的重复性工作。

值得注意的是,面向对象编程使得程序代码更清楚易读,且提升程序代码的可复用性(reusability)。Python的面向对象较接近一般人熟知的面向对象语言,如C++与Java(参见1.6.2节Python语言面向对象),而R语言的面向对象虽然比较不正规,但表面上仍然实现了面向对象的诸多概念(Matloff,2011)。

简而言之,R与Python语言中面向对象的概念有:

· 两种语言中所见都是对象,从数字到字符串到矩阵到函数都是对象,因此程序员应常常关注环境中对象的类别。

· 面向对象提倡将个别但相关的数据项封装(encapsulation)成单一的类别实例,以追踪相关的变量,并强化程序代码的清晰度。

· 继承(inheritance)的概念可将某一类别延伸为更专门的类别,例如,猫头鹰继承鸟类的属性与方法,成为更特别的鸟类。

· 函数是多态的(polymorphic),即表面上看似相同的函数调用,其实会因传入对象的不同类别,进行不同的运算。例如R语言summary()、plot()、print()、predict()等泛型函数(generic functions),依据传入对象的类别,调用适合的具体方法对对象进行相应的计算与绘图,促进了程序代码的可复用性,可视为模块化设计的一种方式。Python也可以在自定义函数中根据传入的不同类别对象,进行相应的处理,这种一个函数有多重版本的概念也称为多重方法(multimethods) https://www.artima.com/weblogs/viewpost.jsp?thread=101605