欢迎光临散文网 会员登陆 & 注册

【Tidyverse优雅编程】优雅数据编程思维(实例阐述)

2023-05-03 20:35 作者:张敬信老师  | 我要投稿

编程思想的重要性:

  • 编程语法是散落在各处的知识碎片,编程思想将它们串在一起形成清晰脉络;

    • 编程知识碎片,学的死知识,用的时候不知道选哪片,只能是瞎套用;

  • 融入编程思想的编程语法,能够

    • 引领你更快地、真正地理解和学会编程语法;

    • 让你遇到问题知道从哪里开始思考,往哪个方向去思考;

我首创提出的 tidyverse优雅数据编程思想:

张敬信:数据编程思维


下面分别加以介绍,先设置数据文件根路径、加载包。

1. 向量化

  • 向量化,就是同时操作一个向量/矩阵的所有数据,对每个元素同时做相同操作

  • 关键是要用整体考量的思维来思考、来表示运算

比如考虑 n 元一次线性方程组:

若从整体的角度来考量,引入矩阵和向量:

则可以向量化表示为:


例1 实现归一化算法

归一化,是将数值向量线性放缩到[0,1], 一般还同时考虑指标一致化,将正向指标(值越大越好)和负向指标(值越小越好)都变成正向。

正向指标:

负向指标:

借助简单实例 x=[4,1,5,8], 问题已足够简单不需分解。

  • 若是正向指标,按第 1 个公式,按编程语法翻译成代码(要有意识地摒弃for i in 1:4的逐元素迭代想法):

这里用到两种常用的向量化计算:

  • min(x): 函数作用在向量上(几乎所有自带R函数都是这么设计的)

  • x - min(x): 向量减去标量(向量的每个元素都减去该标量)

另外,还有一种常用,比如:x * y(每个元素分别做乘法)
还有,若是负向指标,需要分支结构:

2. 自定义函数

  • 要做一件事,拿一个简单实例,调试通过;再改写成一个函数,就可以一步到位、反复用、批量用、给别人用。


  • R中函数一般形式为:

  • 你只要把输入给它,它就能在内部进行相应处理,把你想要的返回值给你。


  • 定义函数就好比创造一个模具,调用函数就好比用模具批量生成产品。

例2 将归一化封装为函数


3. 泛函式循环迭代

循环迭代,就是依次对序列的每个元素,重复做同样的事情,并保存结果。

做一件事情,就是一个代码段,封装起来就是自定义一个函数

循环迭代,本质上就是将一个函数依次应用(映射)到序列的每一个元素上,表示出来即map(x, f)

两点说明:

  • 序列:由一系列可以根据位置索引的元素构成,元素可以很复杂和不同类型;向量、列表、数据框都是序列

  • x作为第一个参数,是便于使用管道

purrr泛函式编程解决循环迭代问题的逻辑:

  • 针对序列每个单独的元素,怎么处理它得到正确的结果,将之定义为函数,再map到序列中的每一个元素,将得到的多个结果(每个元素作用后返回一个结果)打包到一起返回,并且可以根据想让结果返回什么类型选用 map 后缀。

循环迭代返回类型的控制:

  • map_chr, map_lgl, map_dbl, map_int: 返回相应类型向量

  • map_dfr, map_dfc: 返回数据框列表,再按行、按列合并为一个数据框

purrr风格公式(匿名函数):函数参数.f的一种简写;只需要写清楚它是如何操作序列参数.x(代表一个元素)的

  • 一元函数序列参数为.x, 例如

  • 表示为.f = ~ .x ^ 2 + 1

注: 这也是分解的思维,循环迭代要依次对序列中每个元素做某操作,只需要把对一个元素做的操作写清楚(即.f),剩下的交给map_*()就行了。

map_*(.x, .f, ...): 依次应用一元函数.f到一个序列.x的每个元素,...可设置.f的其它参数



例3 在外面对数据框各列做归一化

  • 数据框是序列,第1个元素是第1列df[[1]], 第2个元素是第2列df[[2]], ......

这是都当成正向指标,若+, -, -, +怎么办?


例4 批量读取数据并按行合并

  • 获取文件路径

  • 循环迭代读取,同时合并结果


4. 管道

管道运算符%>%magrittr包)或|>(R 4.1以来),通过管道将数据依次向前传递(从一个函数传给另一个函数),从而依次变换你的数据:

表示依次对数据进行若干操作:先对数据x进行f操作, 接着对结果数据进行g操作

使用管道的好处:

  • 避免使用过多的中间变量

  • 程序可读性大大增强:对数据集依次进行一系列操作

数据默认传递给下一个函数的第一参数,否则需用.代替数据

5. 数据思维I: 操作数据框的思维

将向量化和函数式(自定义函数+泛函式循环迭代)编程思维,纳入到数据框中来:

  • 向量化编程同时操作一个向量的数据,变成在数据框中操作一列的数据,或者同时操作数据框的多列,甚至分别操作数据框每个分组的多列;

  • 函数式编程变成为想做的操作自定义函数(或现成函数),再依次应用到数据框的多个列上,以修改列或做汇总

记住:每次至少操作一列数据!

例5 在数据框中做归一化

同时操作多列across()同时操作多列,只需要选择要操作的列,对(每)一列上要做的操作,写成函数

6. 数据思维II: 操作分解的思维

复杂数据操作都可以分解为若干简单的基本数据操作:

  • 数据连接

  • 数据重塑(变成整洁数据:长宽转换、拆分/合并列等)

  • 筛选行

  • 排序行

  • 选择列

  • 修改列

  • 分组汇总

一旦完成问题的梳理和分解,又熟悉每个基本数据操作,用“管道”流依次对数据做操作即可

例6 管道分解操作



问题:查询平均成绩≥60分的学生学号、姓名和平均成绩。

分解问题:

  • 先按学号分组汇总计算平均成绩

  • 然后根据判断条件筛选行

  • 再根据学号连接学生信息

  • 最后选择想要的列


7. 数据思维III: 数据分解的思维

分组操作:汇总/修改/筛选:想对数据框进行分组,分别对每组数据做操作,整体来想这是不容易想透的复杂事情,实际上只需做group_by()分组,然后把你要对一组数据做的操作实现

  • group_by + summarise: 分组汇总,结果是“有几个分组就有几个观测

  • group_by + mutate: 分组修改,结果是“原来几个样本还是几个观测

  • group_by + filter/slice: 分组筛选/切片,结果是“分别对每组取子集合一起

例7 分组修改数据

问题:分别计算每支股票的收盘价与前一天的差价。

  • 分解的逻辑:只要对Stock分组,对一组数据(一支股票)怎么计算收盘价与前一天的差价,就怎么写代码


例8 分组t检验

8. 批量建模/计算

对数据做分组,批量地对每个分组建立同样模型/做同样计算,并提取和使用批量的模型/计算结果,这就是批量建模/计算
“笨方法”手动分割数据、写for循环实现,再提取、合并结果也能实现。
数据思维做法更简洁优雅,仍是纳入到数据框中来做,用到嵌套数据框(列表列)+ mutate修改列 + map迭代
你只需要解决:一个数据上的建模/计算。

例9 批量线性回归建模

  • 分组嵌套,到嵌套数据框

  • 查看每一个数据, 经常取出来调试用

  • 调试在一个数据上做的事情:

  • 放到数据框里面去做:

  • 展开嵌套


总结一下贯穿始终的分解思维:

  • 解决无从下手的复杂问题:分解为若干可上手的简单问题

  • 循环迭代:分解为把解决一个元素的过程写成函数,再map到一系列的元素

  • 复杂的数据操作:分解为若干简单数据操作,再用管道连接

  • 操作多组数据:分解为group_by分组+操作明白一组数据

  • 修改多列:分解为across选择列+操作明白一列数据

  • 批量建模/计算:分组嵌套数据或重抽样嵌套数据+调试明白对一个数据如何建模/计算

更多来自实际问题的案例:https://zhuanlan.zhihu.com/p/467134727

关于base Rtidyverse

我的观点:

  • 没有必要先学习base R, 强烈建议直接从tidyverse入门R语言编程,没有base R基础效果更佳!我的R书很少涉及base R, 照样涵盖所有基本编程语法,不影响解决各种各样的R编程问题。

  • base R当作是一个R包来看待,其中的某些好用函数,完全可以使用。

  • 没有必要搞base Rtidyverse对立,Python用户从来都是热烈拥抱numpy, pandas, matplotlib, sklearn, 更易学、易用干嘛要排斥。

  • 近年来,国内不思进取、墨守成规的坚守base R, 已经严重阻碍了国内R语言的发展,越来越小众化、边缘化,我希望更多的人特别是高校教师,能够加入使用和推广以tidyverse为代表的R新技术的行列!

附免费学习资源:

我的R新书完整课件,免费可在线运行版(和鲸网)

  • 第一部分 - R基础语法与tidyverse优雅数据编程:

    https://www.heywhale.com/mw/project/641dc0d4feb4fe02b2ce72f7


  • 第二部分 - R应用统计与探索性数据分析:

    https://www.heywhale.com/mw/project/6434d65f381d60467de08121


【Tidyverse优雅编程】优雅数据编程思维(实例阐述)的评论 (共 条)

分享到微博请遵守国家法律