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

1.7.2 自定义函数

如同数学上的函数一样,动态程序语言R与Python的函数对象都是依据输入的对象参数(objects as arguments)进行计算与转换后再传出输出对象。以R语言为例,它运用function关键词创建函数的语法如下(Python自定义函数请参见1.6.2节Python语言面向对象):

function(arguments) {body}

其中参数值(arguments)是一个(或以上)对象名称(a set of symbol names),可用等号运算符给予对象参数默认值,传入函数主体内执行指令语句后,用return关键词传回最后一行语句,但return关键词常被省略。

与函数相关的另一个名词是参数(parameter),它是函数内程序转换或运算所需要的固有性质(intrinsic property),须包含在函数的定义中;参数值(argument)是当调用函数时,实际传入函数程序中的值,R语言用args()函数显示函数的参数名与对应的默认值。为了方便说明,本书后续不刻意区分参数与参数值。

大部分情况下,需将关键词function定义的函数对象用用户自定义的名称存储起来,方便后续使用。但是也有不具名函数嵌套在其他函数中结合运用的情况,此时不具名函数被称为匿名函数(anonymous function),Python语言称之为Lambda函数。

上例说明R语言如何自定义函数,函数corplot有三个参数,其中参数plotit已有默认的参数值FALSE。下面调用corplot()时,根据使用者传入的参数值u、v和真假值(最后一个可传可不传,因为已经有默认值FALSE了),计算相关系数,并进行逻辑语句判断,决定是否绘制散点图。

plotit为真的散点图如图1.12所示。

图1.12 corplot()函数的参数plotit设定为真时绘制的散点图

在数据处理与分析实战时,经常将重复性的工作定义为函数,便于精简代码、模块化工作流程。下例先读入新生数据集,有入学学年、学院、系所、班级、性别与毕业学校等字符串字段。

除了字段学号(识别变量通常不转为因子)外,先将newbie所有字段转换为因子向量,并查看各字段摘要报表。其中可以发现性别字段有异常值,故将其再转回字符串类型,并用gsub()函数将男女异常值替换为正常值。

查看清理后的性别值频率分布,确定正常后再将其转为因子向量。

使用lapply()隐式循环函数,对部别、学制、系所、学院与性别等类别字段,成批产生频率分布表,了解其类别数据分布状况。

所谓文不如表,表不如排序后的表。因此,进一步使用lapply()隐式循环函数,结合前述匿名函数概念,将各个字段(即匿名函数中的参数u,读者请自行思考其为几维的数据对象?)依序产生频率分布表后再进行排序。

校方需要统计各系科(dept)各学制(acasys)下生源排名前三与后三的学校,因此定义下面deptByAcaSys()的函数。函数在传入科系与学制名后,先用逻辑值索引(logical indexing)挑选子表tbl,接着对子表中的毕业学校一栏产生排序后的频率分布表top3与bottom3,最后组织成数据集df后传出。

以下是调用deptByAcaSys()自定义函数的两个例子,我们还须思考是否有可以改进之处。其实deptByAcaSys()缺乏输入参数的合理性检查(sanity check),好的用户自定义函数应该能够避免不当参数的输入,例如,dept是否在该校9个系所名单内,避免造成意料之外的错误。限于篇幅,请读者自行举一反三。

最后,无论是内置函数、各套件中的函数,还是自行定义的函数,读者应注意引用函数时其默认的参数值与可能的参数选项,才能善用函数模块化数据处理与分析的工作流程。