r library car_R语言代码模块化(3):程序控制

又是编程基础系列,本次主题是R的程序控制。掌握程序控制能力是学习系统性的构建程序的重要过程。在我看来,程序控制能力的体现在编程者能够掌握程序运行中的错误、识别低效率环节、监控程序状态、增强程序稳定性、关键点控制,这些能力跟程序本身的功能无关,但对提升工作效率及降低错误概率很有帮助。本次简单介绍一些R程序控制基础技能,以及一些我的看法。

写log

如果你的程序有非常多的循环,甚至是循环嵌套,那记录每次循环的程序状态就非常有必要,在R语言里tryCatch基本能满足这方面的需求。以我来说,一个tryCatch的结构我通常会写成这个样子:

> for(i in 1:10){
+   tryCatch({
+     fread(i)
+   },
+   warning = function(w) {write(paste(i,w), file = 'log', append = T)},
+   error = function(e) {write(paste(i,e), file = 'log', append = T)},
+   finally = {next})
+ }
> 
> readLines('log')
 [1] "1 Error in fread(i): input= must be a single character string containing a file name, a system command containing at least one space, a URL starting 'http[s]://', 'ftp[s]://' or 'file://', or, the input data itself containing at least one n or r" 
 [2] ""                                                                                                                                                                                                                                                          
 [3] "2 Error in fread(i): input= must be a single character string containing a file name, a system command containing at least one space, a URL starting 'http[s]://', 'ftp[s]://' or 'file://', or, the input data itself containing at least one n or r" 
 [4] ""        
......

工作原理很简单,就是将错误跟警告写入一个文本。可以理解为tryCatch会将程序的错误及警告分别存成对象w及e,可以用函数解析并输出对象。写log是个好习惯,试想一下你跑了好几天的程序突然出错,但却不知道错误在哪的那种恐惧......

循环及条件语句

各人觉得日常处理数据的话,熟练for循环、while循环、if else语句就能cover大部分需求。善用if els能增加程序的稳定性,例如:

> fun<-function(x){
+   x+10
+ }
> 
> input<-'A'
> 
> if(is.character(input)) {
+   print('输入是字符,无法计算')
+ } else {
+   fun(input)
+ }
[1] "输入是字符,无法计算"

这些函数用法过于基础,不再赘述。

检查低效率环节

基本都的方法就是用system.time包裹程序主体,例如:

> i<-1
> 
> system.time({
+   while(i < 10^7) {
+     i<-i+1
+   }
+ })
用户 系统 流逝 
1.50 0.01 1.55 

但如果程序很复杂,强烈推荐用profvis包,展示一个简单的例子:

> i<-1
> j<-1
> 
> profvis::profvis({
+   while(i < 10^7) {
+     i<-i+1
+   }
+   
+   while(j < 10^7) {
+     j<-j+10
+   }
+   
+ })

上面这段代码运行之后,在Rstudio的source界面(脚本界面)会展示一个profile:

53cfa1a018a660238239fb7e7cd94614.png

每一行代码的运行时间及内存消耗一目了然。

交互式程序控制

想象一个情景,你编写了一个程序,这个程序有一个步骤涉及到数据删除,但你不是很肯定会不会误删数据,这时候可以在关键点加一个if else及gWidgets包的ginput函数,例如:

> library(gWidgets)
> library(tcltk)
> library(gWidgetstcltk)
> 
> options(guiToolkit="tcltk")
> 
> dataname<-'毕业论文.docx'
> file.create(dataname)
[1] TRUE
> 
> file.exists(dataname)
[1] TRUE
> 
> remove_check<-function(dataname) {
+   Lock1<-ginput(message = paste('你要删除',dataname,'吗? (y/n)'),
+                 icon = 'warning')
+   
+   if(Lock1 == 'y') {
+     Lock2<-ginput(message = paste('再确认一次,你真的要删除',dataname,'吗? (y/n)'),
+                   icon = 'warning')
+   } else {
+     Lock2<-'n'
+   }
+   
+   if(Lock1 == 'y' & Lock2 == 'y') {
+     Lock3<-ginput(message = paste(dataname,'删除后将无法恢复,你真的要删除吗? (y/n)'),
+                   icon = 'warning')
+   } else {
+     Lock3<-'n'
+   }
+   
+   return(c(Lock1,Lock2,Lock3))
+ }
> 
> txt<-remove_check(dataname)
> 
> if('n' %in% txt) {
+   print('论文:感谢不杀之恩')
+ } else {
+   file.remove(dataname) 
+ }

运行txt<-remove_check的时候,会接连弹出窗口:

2bd9f84cfd194e5b820e8869f489e003.png

1be4aa19dcacbd1fa9404cf4ce62882b.png

aa57db2d2f52f2e916c17cfe82c2fb5b.png

需要注意的是,上面这个弹窗啥都不输入且点击OK,则会传回"";点击右上角x会传回字符串的FALSE;点击Cancel会传回NA。

这里我输入的顺序是yyn,接着程序才会继续运行后面的if else。

> if('n' %in% txt | 'FALSE' %in% txt) {
+   print('论文:感谢不杀之恩')
+ } else {
+   file.remove(dataname) 
+ }
[1] "论文:感谢不杀之恩"

写在后面

这个基础系列差不多就到这,这些是我过去日常编程中挑选出来我觉得比较实用的知识点。接下来会继续探索R的更多工具,感谢各位持续关注。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值