当前课程知识点:R语言数据分析 > 中部:执具 > 第6章 基础编程——用别人的包和函数讲述自己的故事 > 6.4 控制流
大家好
欢迎来到《R语言数据分析》课程
今天和大家交流的主题是《控制流》
也就如何写一套自己的算法逻辑
在我们前面的课程里面讲到
R编代码的第一法则是
用别人的包和函数 讲述你自己的故事
当然前半句话
我们在前面课程里面已经做了简要的交代
如何从这1万多个包里面
找到我们自己想要的那一个
并且使用其中的函数
今天我们主要讲述后半句话
就是讲述你自己的故事
也就是如何针对你自己的问题
写一套自己的逻辑过程
顺序 分支 循环
其实也是结构化编程的三种最基本的结构
无论是R 还是其他任何一个编程语言
基本上都由这么三种最基本的结构来组成
咱们现在看一看
R里面如何实现这三种最基本的结构
首先我们看一下这个顺序的结构
这里面我们列出一些R的代码
在讲述这个顺序结构之前
我们先说一说这个代码
在PPT里面怎么排版的
我们这个代码用不同的颜色代表了
这个R里面不同的组成部分
比如说我用这个深蓝色代表注释
所有以#号开头的都是注释
然后绝大部分代码我们都用这个黑色表示
然后对其中的的函数
比如这个c()这是一个函数
一个combine一个函数
都是用这个红色来表示
然后对于其中的一些常数
无论是这个数值
还是这个逻辑值
比如说TRUE FALSE
都用这个橘红色表示
下面这种
对于某个控制台的输出
它和我们注释有点区别
我们在这个PPT里面用#号
后面接一个大于号 #>
表示这是控制台的输出
以区别于我们前面这个注释
这是我们后面在PPT里面排版
这个R代码的时候
我们都遵循这个原则
有利于大家来读我们这个代码
我们还是回到我们主题
这个顺序结构
所谓顺序结构其实就是针对我的问题
把这个代码
把逻辑分成一步一步
第一条代码 第二条代码 逐行执行
比如说我现在拿到了六个同学
语文yw 数学sx 外语wy
他三门课的成绩
然后我对这六位同学的成绩进行一个简单的分析
首先我们定义
我们创建一个yw这么一个向量
然后再创建sx wy
总共加这三个向量
分别是用来存储
我这个六个同学的语文 数学 外语三门课的成绩
通过c()这个函数
把六位同学的成绩放(捏)在一起
变成一个向量
创建完之后 可以怎么样
我来看看这六个同学三门课它的总分是多少
这个时候可以怎么样
yw + sx + wy
大家注意一下
这里面我们和以前学的C(语言)编程可能有点不一样
因为以前学的时候可能是说第一个元素相加
第二个因素相加
第三个元素相加
这样做一个循环
可能循环六次了
但我们这边是个向量化的编程
就是yw + sx + wy
它其实相当于是
第一个同学的语文成绩加第一个同学数学成绩
加他的外语成绩
作为我们最后结果的
比如说这个ysw语数外这么一个新的向量
它的第一个元素
同样也是就对每一个同学的
他三门课的成绩都分别相加
所以我们所谓向量化操作是
就相当于对这个每一个元素并行开展某个操作
比如这里面就是一个相加的操作
我们在控制台里面
敲入ysw这个变量名称 然后一回车
就可以看得出来
这六个同学三门课的总分
它其实还是长度为6的一个向量
这其实我们可以看得出来
其实所谓的R代码就是
第一行 第二行 第三行
一行一行往下执行
这其实就是一个顺序结构
当然比如说
我们举个例子
比如说我们这个语文yw成绩
因为这个试卷里面有一个题没有打印清楚
这个两分的题没有打印清楚怎么办
我对每个同学都加两分
这时候可以怎么做
yw+2
就是它每一个元素都都加二
加二之再重新赋值给语文yw成绩
这里面其实我们可以看得出来
R里面对象是不需要定义的
直接创建就可以
然后在修改的时候怎么办
重新赋值就可以
我们其实还可以做进一步的操作
比如说
拿到这三门课的成绩之后
六个同学的三门课的成绩
我来看一看
比如说我先看看
分析一下语文成绩
可以看看它的平均分是多少
这六个同学的
调用mean()这个函数
将刚才这个语文成绩交给mean()这个函数
就得到平均分
一看平均分多少 92.16
所以这六个同学的语文成绩相对还是
平均分还是比较高的
平均分一般来讲是代表集中的趋势
就大部分水平在哪
我们可以看看它分散的程度
分散程度一个比较典型的
用来量化这个分散程度
一个典型统计量是标准差
我们可以调用这个sd()这个函数
来求它的标准差
当然我们也可以写自己代码来实现它
标准差的公式我们可以看一下
这大家都比较熟了
每一个同学的成绩减掉平均分
括符 平方 相加
括符 平方 相加
除以n-1
因为它是样本标准差
所以这面是n-1
然后再开根号
这是我们标准差一个计算公式
我们对照一下R代码
这里面其实是什么 6减1
1/(6-1)
这毫无疑问就是
前面的1/(n-1)
然后乘以多少
每个同学的语文成绩减掉平均分
它的平方
求和
然后再乘以前面1/(n-1)
然后再括符之后怎么样
0.5次方
其实就是开根号了
我们一对照就发现
R代码是非常直观的
和我们数学公式对照的话
发现它非常直观
这时候我们可以看得出来
语文的标准差是3.43
同样我们也可以求数学和外语
分别把它标准差求出来
这时候我们可以看得出来
数学的标准差相对大一点的
其实无论是针对我们这六位同学
还是我们以后拿到更多的数据
我们发现
对于这个语文数学外语来讲
其实数学成绩它的偏差是相对比较大一点的
也就是说
数学可能是一个容易拉分的一个科目
当然我们还可以做进一步的操作
比如说
拿到这个平均分和这个标准差之后
我可以算算它的标准得分
标准得分
标准得分计算公式比较简单
就是xi减掉一个平均分
再除以标准差
同样在R里面代码怎么实现
就是语文成绩减掉平均分
括符
除以标准差
这就得出来了
同样这还是个向量化的运算
大家注意到没有
大家注意到没有
就是语文
每一个同学的语文成绩都减掉平均分
然后再除以标准差
所以它最后得到结果是
还是一个长度为6的
一个标准得分
一个数值向量
这就是我们顺序结构一个最基本的一个过程
当然这里面我们用的都是一些四则运算
包括一个求平方求开方
我们还可以再看看
一些逻辑运算
比如说我们可以判断语文成绩
六个同学语文成绩哪些同学是优秀的
六个同学语文成绩哪些同学是优秀的
这个时候我可以和什么相比
假如说我定义五分制成绩的话
优 良 中 及格 不及格
大于等于90分我认为都是优秀
这个就看看语文成绩是否大于等于90
也可以做一个判断
这个时候它返回结果
是一个逻辑向量也是长度为六的
还是一个向量化的操作
我们看比如这里面我们将语文成绩显示完之后
96 89 94 93 87 94
这里面89和这个87所相应位置上的元素
应该就是FALSE
其他位置是TRUE
这里面其实是一个逻辑运算
当然也可以做“逻辑与”的运算
就是看看
所有这六个同学
是不是语文大于等于85
并且他数学也大于等于85
这个时候我们也返回的也是一个
长度为6的一个逻辑向量
我们前面通过简单几行代码
向大家展示了一下
就是针对我这个语数外三门课的成绩
我做一个简单的分析
其实就是一个顺序结构来展示
就是第一条 第二条 第三条代码
逐行执行
这是一个顺序执行的过程
但其实应该来讲
任何一个R代码
顺序结构都是它的主体
顺序结构应该是最基本的结构
看完顺序结构之后
我们再看一看这个分支结构
所谓分支结构是
满足某个条件的情况之下
执行某个代码
就是通过这个if这个语句
if后面跟一个条件判断
它返回结构是TRUE还是FALSE
假如为真的时候 就执行它
否则的话就不执行
这是一个最基本的语法过程
当然这个if语句
它后面可能是单条的语句
也可能是一个语句块
就执行单个语句也可能执行多条语句
但我们都强烈建议大家
就是无论你单条语句还是多条语句
都用花括符把它括起来
当然还有一个情况
就是当它满足这个条件时候执行某条语句
就是当它满足这个条件时候执行某条语句
不满足执行另外一些语句块
不满足执行另外一些语句块
这个时候就是if再加上else
我们需要说明
假如这种情况的话
这个else是这个语句
必须紧跟着花括符后面
必须在同一行
否则的话它就会认为
这里面语法上是有错误的
所以这个时候我们有两个点要注意
第一是这个条件判断它应该是一个标量
一个逻辑返回值是TRUE还是FALSE
另外就是这个else这个子句
它应该紧接着前面的这个花括符的后面
咱们还是以这个成绩的分析为例
我们来看一看这个分支结构是如何实现的
比如说我现在想判断一下
六个同学的语文成绩
它为优还是为良的情况
我可以先算一算
把最低成绩先求出来
我先把这个最低成绩我赋值给min_score
假如这个最低的成绩都已经大于等于90的话
那我就输出
所有的同学 语文成绩全部都为优
否则的话我判断一下
它是不是都大于等于80
虽然说前面这个不满足
第二个条件是不是满足的
假如最低成绩不是大于等于90
但是它满足大于等于80的话
我要输出一条
就语文成绩至少是为良的这六位同学
否则的话就是并非所有同学语文成绩都为优良
它这个逻辑过程可以用旁边
这个示意图来表示
就首先判断一下
是不是大于等于90
是的话就输出
语文成绩全部都为优
否则的话我判断一下
它是否大于等于80
假如是的话我输出一个
语文成绩至少为良
否则的话怎么样
并非所有同学他的语文成绩都为优良
我们一看
咱们针对目前我们这六个同学的成绩来讲
语文成绩应该至少为良
因为我们是判断六个同学
其实这里面还可以还用另外一种方式来表达它
我们在R里面
这个逻辑判断里面用的非常多的两个函数
一个是all() 一个是any()
all()什么意思
我们说语文大于等于90这是一个逻辑判断
前面看了它是长度为6的一个逻辑向量
假如所有同学语文成绩都大于等于90的话
这个时候返回结果为TRUE
否则的话只要有一个同学
它不是大于等于90的
那返回的结果是就是FALSE
所以我们可以改写一下前面这个语句
前面代码
就是if所有同学语文成绩都大于等于90的话
输出语文成绩全部为优
否则的话
如果满足这个所有同学成绩
至少是大于等于80
那怎么样
我这个输出一个消息就是语文成绩至少为良
这两都不满足 那怎么样
就最后只能说并非所有同学成绩都为优良
当然all()这个函数的一个用法
就是它接受一个逻辑向量
假如逻辑向量里面每一个取值都为TRUE的话
我返回一个TRUE
否则的话返回FALSE
当然和它相对应的就是另外一个了
就是any()
any()是什么呢
它也是接收一个逻辑向量为这个输入
只要由其中一个为真
只要有其中一个为TRUE
那好 返回的结果就为真
否则的话
就所有都为FALSE的时候
才返回什么
才返回什么
返回这个FALSE
我们可以看一下
比如说我们判断一下
是不是有同学有不及格的现象
就是有any有任何一个同学他语文是小于60
假如有的话
输出有同学语文成绩挂科了
否则的话
是所有同学都考试顺利通过
当然对于我们这个数据来讲
它应该是输出后面这个
所有同学语文成绩都顺利通过了
咱们再看一下下面这几条代码
看一下这个代码
这个代码其实和我们前面代码一看没什么区别
几乎没什么区别
唯一的区别是什么呢
大家看一下
这个时候这个else这个语句
它其实和}不在同一行
因为R代码它是个脚本语言
它不需要提前编译之类的 它不是这样
我只是看当前这个代码
假如已经完整了我就执行它
然后再接下来是下一条语句
那好
大家看一下这个输出是什么
这个输出并不是说语文成绩至少为良
而是什么呢
这里面会输出四个错误
并且输出语文成绩至少为良
同时输出
并非所有同学成绩均为优良
这时候我们一看跟我们想要的逻辑是不一样的
它问题在哪
问题是这样的
问题在于
else这个子句没有紧跟上面一个
花括符
花括符
就导致你前面这个执行完了
然后突然来一个
莫名其妙来一个else子句
这么一个语句
它这里面这一行就会出一个错
然后出完错之后
我接着执行下面这一行
这一行代码是对的
我就输出来一个语文成绩至少为良
然后输出到下面时候有个花括符又出一个错误
因为花括符是莫名其妙来了
然后下面又来一个else这个子句
这个时候又出一个错误
这个时候还是会输出这个
这个message也是没有问题的
最后到这个花括符的时候又出个错误
所以我们真正的输出后面是有
1-2-3-4
4个错误
同时输出两个消息
这是我们前面讲到的
在我们R里面这个
条件分支结构的时候一定得注意
假如我们有这个else这个子句的话
一定得紧跟着前面的这个花括符 }
我们再看一下
我们前面讲这个顺序结构的时候
提到了我们的所谓的向量化的操作
我们再看看
假如我这个分支结构里面
是不是也有相应的向量化操作
比如说我们说语文是大于90的
语文大于等于90
可以做一个判断
它是返回一个这个逻辑向量
假如我将这个逻辑向量交给这个
交给这个if语句的话
它结果是什么呢
它的结果是不是说所有同学均为优
这个是错的
因为按理说我们是
第一个为TRUE 第二个就为FALSE
第五还为FALSE
毫无疑问
这并不是所有同学的语文都为优
那好 按理说这个if这个条件是不满足的
这个message应该不会执行
但是假如我们是这样写代码的话
它其实还是为输出的
它会输出所有同学语文成绩均为优
但是同时会输出一个警告信息
输出一条警告的消息
是什么呢
我们这里面交给它的if
这个条件判断
交给if的是什么呢
它不是单个的长度为1的一个标量
而是一个向量
那这个时候它会说我只用了
第一个
这个向量的第一个元素
因为你第一个元素是TRUE
毫无疑问 我就执行了
这其实不是我们想要的
所以我们得注意了
在R里面
虽然说它是一个向量化的一个语言
但是 对if这个分支结构来讲
我只能接受什么
只能接受这个标量
有没有这个向量化的操作
比如说我是优的时候
大于等于90的时候我说输出一个优
我说输出一个优否则的话我就输一个良
也有 在R里面
但是不是这个if
不是if这种结构
而是这么一种方式
ifelse()这么一个函数
这个函数接受三个参数
第一个参数是
第一个参数是
条件判断
比如说我们这里面
yw >= 90
它得到一个长度为六的逻辑向量
第二个参数是一个取值参数
第三个也是
那好 假如我前面这个满足的话
比如说我长度为6的
这里面有一些部分为TRUE
有些部分为FALSE
那好
这个为真的部分
为TRUE的部分
我都取优
否则的话取非优
这种ifelse这个语句其实还可以嵌套
比如说 大于等于90的时候我输出一个优
否则的话我看你是不是大于等于80
假如是80的话
可以输出一个良或者说非优良
或者大于等于88的时候
我输出一个较好
否则的话我就输出一般
这种结构也可以
这个时候我们可以看一下
它是不是向旁边这么一个结构
先是判断一下
是不是大于等于90
是的话输出一个
否则我再判断一下
是不是大于等于88
是的话输出一个
否则的话输出另外一个
是不是这样
当我们看这个ifelse这个语句的时候
这个函数的时候
我们可以通过另外一个角度来看它
条理会更清楚一点
否则的话你这样层层嵌套
很多时候我们很难理清楚这个逻辑过程
其实这个ifelse() 它是接受三个参数的
首先是第一个参数是一个逻辑判断
一个逻辑判断
第二个和第三个参数都是什么
都是它的一个取值的向量
比如说我们刚才这条语句
现在给他换一种方式
语文大于等于90
它毫无疑问是一个什么
它返回结果是什么
一个长度为6的逻辑向量
然后第二个
优
它其实是一个取值向量
因为它的长度不足够与像前面一样长
它是长度为6
这边长度只为1
那怎么办
它循环补齐
一直补成长度为多少呢
为6的一个
一个取值向量
一个字符向量
同样第三条语句也是一样
这里面我们可以将这条语句先执行
执行完之后它结果是什么
它执行结果这样的
较好 较好 较好 较好 一般 较好
也是一个取值向量
所以大家注意了
我们在看ifelse这个语句的时候
我们是
先把里面先执行完
然后我们再来看
逻辑判断
后面两个都是取值
取值向量
然后当我这个逻辑判断为TRUE的时候
怎么样
在第二个取值向量内能取相应的值
当为FALSE的时候
怎么样
我在第三个
第三个参数
这个取值向量取相应的值
毫无疑问 这个时候就是
优 较好 优 优 一般 优
这就是我们想要的结果了
这是我们对R里面分支结构的一个简要的介绍
要么就是if这么一种方式
另外一种就是ifelse()这么一个函数
来执行我们所谓的
分支这么一种结构
这么一种控制流
咱们再看第三种
第三种是循环结构
在R里面循环结构的话有三种实现方式
for while repeat
三种方式
for循环的话它是一个枚举型
就是我这个控制变量
要枚举一个向量里面每一个数值
对于每个数值我都循环
执行一次
然后这个while是
带条件的
当条件满足的时候 一直执行它
直到条件不满足
这个repeat是无条件循环
一直循环 一直循环
当然既然是无条件循环的话
毫无疑问 得有一个终止条件
也就涉及到我们后面要说的这个
有两个语句用于控制这个循环的问题
第一个是什么呢 就是break
假如我们通过这个repeat的来实现这个循环的话
毫无疑问 里面必须有个什么
循环体里面必须有个break语句
在满足某个条件之下
我就跳出循环
否则的话就死循环
还有另外一种就是next
break相当于终止循环
next什么意思
就是next之后的语句不再执行了
我直接执行下一轮循环
这就是next
我们通过一个具体的例子
通过斐波那契数列
我们来看一看
在R里面如何实现这么三种循环
斐波那契数列
大家都比较熟悉
就是
在很多自然现象里面
都符合这么一个斐波那契数列
这么一种模式
它是什么呢
就是1-1-2-3-5-8-13-21
一直往下生长
从第三个数开始
都是
它前两个数的和
比如说2是 1 1 的和
3呢 1 2的和
3是1、2的和
5呢 2 3 的和
8呢 3 5 的和
对吧
好
既然我们知道这个斐波那契数列
是这么一种生长机制的话
从前往后这么生长
其实我是可以通过循环的方式来实现它
比如说我现在想
我想求出斐波那契数列前十六个数
那这个怎么生长呢
那我可以通过一个for循环来实现它
我首先
先定义一个
这个变量n_fib
表示斐波那契数列的长度
然后呢
我创建一个长度为16的
一个斐波那契数列
这个时候是numeric
创建它
这时候默认值都是多少
都是0
就长度为16的0-0-……-0-0 这么一个
数值向量
然后我将前两个斐波那契数列前两个值
赋为1和1
因为斐波那契数列第三个数开始
就是它前两个数之和
好 第三个数开始
其实我可以自动生长了
不用再人工来赋值了
通过for循环就可以
怎么做呢
这里边有一个控制变量是i
从第三一直到十六就是
3-4-5-6-7-……-15-16
这么多的一个
需要枚举的
这么多数我都需要枚举
具体来讲这个循环体里面就是
它第i个位置上的元素
它相当于它前一个元素再加上它
前两位的元素之和
加起来之后
就变成
第i个位置的元素了
就相当于我刚开始有有第一个和第二个元素
然后第二次
我再做循环的时候
第一轮循环是
我先把第三个元素求出来
第二轮循环求第四个元素
一直往下生长就可以
其实就是我这个菲波拉契数列
一直循环到第十六个元素
一直循环到第十六个元素
循环完之后
我们调用这个fib
将fib这个变量
可以输出一下
我们看看它结果
就是1-1-2-3-……
一直到987
一直到987
当然我们在循环体里面
不能说直接我把这个fib放在这
然后它就显示出来
假如在循环体里面怎么办
我show()一下
把当前的fib的值给先求出来
看一下
这是通过for循环来
实现这个斐波那契数列
这是我们知道了我们要有多少个数
前十六个数我来枚举它
通过for循环来枚举
来实现这个斐波那契数列
再比如说我们另外一种情形
我要求1000以内的斐波那契数列
这个时候其实我没有办法说
这个控制变量是多少
这个循环的控制变量
来枚举有多少多少个数
这是没有办法的 怎么办呢
我现在只知道这个条件
就满足这个条件的时候
我就一直循环一直生长
假如不满足的话我就终止它
这个时候用到
这个while这个循环
我们这个时候可以这样
我先定义一个向量fib
先把它首先赋值
为1 1
赋值为1 1
从第三个元素开始
我是前两个元素之和
那这个时候我可以这样求
当我这个最后菲波拉契数列
当前菲波拉契数列最后两个元素之和
小于1000的话
我就一直生长
每循环一次增加一位
直到当前斐波那契数列最后两位之和大于(等于)1000
就我就终止循环
大家看这个时候交给这个while
我们可以写这么一个循环
来实现这个斐波那契数列的生长了
大家看一下
这当前的斐波那契数列
然后tail(fib,2)表什么意思
它尾部的tail
表示它的尾部的意思
就是最后
最后几个最后两个
然后最后两个元素之和就是sum
把最后两个元素之和求出来
我判断一下它是否小于1000
假如是的话执行这个循环体里面的语句
循环体里的语句其实是一个生长的过程
就是fib 就是当前的
斐波那契数列
然后呢
将它最后两位
就是tail(fib, 2)
最后两位求和
并且combine一下
就将最两位求和之后
放在这个fib最后
也就实现了增加一位的功能
也就是逐步往下生长
每循环一次增加一位
直到不满足这个条件
这就所谓的while这个循环
毫无疑问我们可以看一下这个fib
这个生成的这个向量
其实和我们前面的for循环是一样的
它长度正好也是16
这是有条件的循环
还有一种就是
就是无条件的循环
R里面通过
通过repeat这么一种方式来实现
我们同样也是先定义这个fib
这么一个斐波那契数列
这么一个数列
repeat后面就没有括符了
因为它是无条件的
就是要执行某个语句块
这个时候这个语句块我们用花括符
把它给括起来
因为这是repeat循环
它是无条件循环
这个时候我们得定义一个终止条件
就当我斐波那契数列的最后两位之和
它大于等于1000的话
我就break
我就跳出这个循环
否则的话我再执行后面的
执行这个循环体
一直执行这个循环体
这个时候和我们前面语句是一样的
就在当前的斐波那契数列的基础之上增加一位
就是把当前斐波那契数列最后两位之和求出来
放到它最后面去
这也实现了我们斐波那契数列逐渐生长
它得到的结果也是一样的
和我们前面这个while语句执行结果是一样的
其实我们比较一下之后就会发现
其实我们这个repeat它相当于什么呢
相当于这么一个过程
就是while(TRUE)
这门其实等价于这个repeat
就是因为我这个条件始终都永远为真
和这个repeat效果是完全一样的
它就是无条件循环
当然这个时候
我也得在里面加一个终止的判断过程
什么条件之下我就break
这是我们关于这个循环里面的repeat
我们可以再举个例子
比如说我们说举这么一个例子
叫幸运52
这个例子是这种
就是我从1到100里面抽取一个数
假如这个数正好是52的话
我就终止循环
否则的话我就继续抽
我看我究竟要抽多少次
所以我们称之为幸运52
当然这不是以前的一个节目
以前有个电视节目叫幸运52
这里面含义不一样
我们来看看这实现过程
也是用这个repeat这么个方式来实现它
我首先从1到100里面抽取一个数
也通过sample()这个函数
第一个参数是100
就表示从1到100里面抽
抽取几个呢 抽取一个
交给my_number
当然我们可以计算一下次数
就是刚开始我可以定义赋值
将这个time_count赋值为0
每执行一次的时候我就增加1
每抽取一次我就增加1
假如我这次抽取的数据正好等于52的话
我就抽到它
并且我把抽了多少次
这个次数我给列出来
否则的话 怎么样呢
我目前还没有抽到
我只是把当前这个抽到的数给显示一下
我们来看一下这个结果
当然我们这边抽到多少
是第22次就抽到了
当然这里面因为是一个随机抽取的过程
所以同学们在执行这个代码的时候
虽然代码相同但可能抽取的次数是不一样的
这就是简单的我们讲解了一下这个
R里面循环的三种方式
一个for循环 一个while 一个repeat
枚举型的 带条件的和无条件循环
我们前面讲这个顺序结构也好分支结构也好
都说到向量化的问题
这里面我们在学完了这个循环结构之后
我们需要说一下
尽量向量化
千万不要滥用这个循环
虽然我们已经学会了这个显式循环了
我们可以举个例子
比如说我现在有
两个向量
第一个向量
1到1亿
这里面是科学计数法
相当于1乘以10的8次方
一亿
然后第二个向量
二到一亿零一
所以它长度都是为1亿的一个数值向量
我们再定义一个向量z
它也是长度为1亿的一个向量
假如我是向量化操作的话
其实就是
x加y直接赋给z就可以
我通过这个system.time我来计算一下
我要执行这个代码它花多长时间
我们一看这个时候总的时间多少
0.45
不到半秒
假如我们现在改用显式循环来做的话
而不用并行的这个向量化操作
我用显示循环
其实我可以用这个for循环
类似于我们以前学过的
比如说for我通过这个控制变量
它枚举1到1亿
每一个数值就是x相应的位置元素
加上y相应位置元素赋给z
这应该是非常符合我们以前学过的c
Java等等它里面逻辑过程
这是一个循环的过程
好
虽然我们实现的结果是完全一样
但是我们发现这时候耗时多长时间
11.7秒
那边不到半秒
这边是11.7秒
二三十倍的差别
所以通过这个简单例子
我们可以看得出来
在R里面
虽然我们有这么一个循环的控制过程
但是假如能向量化的话 能并行的话尽量并行
这是我们一个最基本的原则
我们再重新强调一下
只要串行不是必须的
就一般来讲我们就用并行的结构
避免显式循环
所谓不是必须的是什么意思
就我这一轮循环不受上一轮循环的影响
我就可以并行进行了
这并行作业的话它效率
我们这个效率我们刚才已经对比了差别非常大
当然假如我本轮循环受上一轮循环的影响
比如我们前面通过这个生长的方式
来生成这个斐波那契数列的话
你当前这一轮是受上一轮的影响
上一轮不执行你这一轮也执行不了
这里面其实就需要用到串行的过程
除了这个情况之外其他情况一律用
并行的方式
当然其实即便是对这个斐波那契数列
其实它也可以通过并行的方式来执行它
我可以用这个apply方式来执行
它其实也不用通过这个从第三个元素开始
每个元素都是逐渐生长
也不用这样
可套用这个公式
当我这个n等于1的时候
它为1
n等于2的时候为1
n等于3的时候为2
n等于4的时候为3
可以套用这么一个公式来算
当然这个公式
大家可以看一下这个代码
就对照一下这个公式和这个代码
就是看看R里面
比如说
开方 开根号
然后这里面n次方 这里面x
可以对照它的公式其实都非常直观
这里面其实是类似于这种并行的方式
也就是比如说还是求16个元素的话
从1到16的话
这个n取每一个值我都调用这个函数
我得到相应的结果
通过这个sapply这个函数来执行它
同样我得到结果是
也还是一个长度为16的一个斐波那契数列
当然这个apply这个函数族
它本质上也不是并行的
但至少我们从形式上看它确实并行的
在R里面其实有很多并行作业
我们说向量化就是一个并行作业
就是向量的每一个元素我都采用同样的操作
这是一个向量化的一个过程
比如说我们求
开根号sqrt() sin()
round() 这个四舍五入
转换成数值等等
其实都是一个向量化的过程
包括我们前面看到的很多二元操作符
加减乘除等等
都是向量化的过程
另外一种并行作业
比如说有这个split-apply-combine
这么一种数据处理的模式
我先将数据分组
split分完组之后
对每一组作用于某个函数采取某个操作
然后再对操作的结果
每一组的结果combine变成一个整体
这里面我们经常会用到
这个先分组再作用某个函数
做某个操作 最后合并
split-apply-combine
这种方式以后经常会用
就是apply这个函数族我们需要关注一下
当然后面我们也会讲tidyverse
这么一个扩展包套装
这里面也有很多分组统计的一些函数
另外这个对于这个并行来讲
其实这个TASK VIEWS里面
我们R这个任务视图里面其实也有
也专门有这个相应的主题
感兴趣同学可以看一看
以上我们就将
我们R里面的三种最基本的控制的结构
顺序的
分支的
循环的做一个简要讲解
同时将我们这个向量化操作
以及这个并行作业做了一个简单的介绍
本次课到此结束
谢谢大家
-第1章 气象万千、数以等观
--第1章 作业
-第2章 所谓学习、归类而已
--第2章 作业
-第3章 格言联璧话学习
--第3章 作业
-第4章 源于数学、归于工程
--第4章 作业
-讨论题
-第5章 工欲善其事、必先利其器
--第5章 作业
-第6章 基础编程——用别人的包和函数讲述自己的故事
--6.1 编程环境
--6.4 控制流
--第6章 作业
-第7章 数据对象——面向数据对象学习R语言
--第7章 作业
-第8章 人人都爱tidyverse
--第8章 作业
-第9章 最美不过数据框
--第9章 作业
-第10章 观数以形
--第10章 作业
-第11章 相随相伴、谓之关联
--11.1 导引
--第11章 作业
-第12章 既是世间法、自当有分别
--12.1 导引
--第12章 作业
-第13章 方以类聚、物以群分
--13.1 导引
--第13章 作业
-第14章 庐山烟雨浙江潮
--第14章 作业