循环函数可以遍历数组或集合中的每个成员,可以将结构复杂的循环语句用简单的函数形式表达出来,可以减少代码量并提高可读性。集算器和R语言都支持循环函数,下面将对比两者用法上的异同。
1、生成数据
生成1到10之间的奇数。
集算器:x=to(1,10).step(2)
代码中,to(1,10)生成了1到10之间的连续整数,step函数根据上一步计算结果间隔取数,最终结果是[1,3,4,5,7,9]。集算器的这种数据类型被称为序列。
这段代码还有更简单的写法:x=10.step(2)。
R语言:x<-seq(from=1,to=10,by=2)
这段代码直接从1开始间隔取数,直到10为止,计算结果是:c(1,3,4,5,9)。R语言的这种数据类型被称为向量。
这段代码还有更简单的写法,即:x<-seq(1,10,2)。
比较:
(1)两者都可以实现本例,但集算器要分两步计算,理论上性能较差。R语言只需一步,性能较高;
(2)集算器的写法是按照序号从集合取数,具有通用性。比如某个字符串序列:A1=["a", "bc", "def"……],要取出A1里奇数位置的字符串时,集算器的写法不必改变,仍然是x=A1.step(2)。
R语言是直接生成数据,所以性能更高。R语言也可以写出通用的表达式,比如同样的字符串向量:A1=c(“a”, “bc”, “def”……),要取出A1里奇数位置的字符串时,R语言的表达式可以是:x=A1[seq(1,length(A1),2)]。
(3)集算器的循环函数有个R语言所没有的特点:内置循环变量和运算符。其中,“~”代表循环变量,“#”代表循环计数,“[]”代表相对位置,“{}”代表相对区间。利用这些变量和运算符,集算器可以写出通用简洁的表达式,比如求集合A2=[2,3,4,5,6]各成员的平方:
A2.(~*~) /结果为[4,9,16,25,36],也可以表示为A2**A2,但后者不够直观通用。R语言则只能表示为A2*A2。
取前三个成员:
A2.select(#<=3) /结果为[2,3,4]
取每个成员的上一个成员,组成新集合:
A2.(~[-1]) /结果为[null,2,3,4,5]
增长率:
A2.((~ – ~[-1])/ ~[-1]) /结果为[null,0.5,0.33333333333,0.25,0.2]
移动平均值:
A2.(~{-1,1}.avg()) /结果为[2.5, 3.0, 4.0, 5.0, 5.5]
总结:本例中,R语言既可以直接生成数据,也可以写出通用的表达式,比集算器更灵活,占用内存可以更少。
2、过滤记录
循环函数的计算对象可以是成员为单值的数组或集合,也可以是成员为记录的二维结构化数据对象,事实上,后者才是循环函数的主要用途。比如:针对订单记录sales,过滤出2010年签订的金额大于2000的订单。
说明:sales来源于文本文件,其部分数据如下:
集算器:sales.select(ORDERDATE>=date(“2010-01-01″) && AMOUNT>2000)
部分结果如下:
R语言:sales[as.POSIXlt(sales$ORDERDATE)>=as.POSIXlt("2010-01-01") &sales$AMOUNT>2000,]
部分结果如下:
比较:
(1)集算器和R语言都可以实现本功能,所不同的是集算器使用了select循环函数,而R语言直接使用下标,两者的本质并无差别。另外,R语言还可以用attach函数进一步简化表达式:sales[as.POSIXlt(ORDERDATE)>=as.POSIXlt("2010-01-01") & AMOUNT>2000,]。如此一来,两者的相似度就更高了。
(2)除了查询,还有求序号、排序、排名、Top N、分组求和等。比如:求本案例中记录的序号。
sales.pselect@a(ORDERDATE>=date(“2010-01-01″) && AMOUNT>2000) /集算器
which(as.POSIXlt(sales$ORDERDATE)>=as.POSIXlt(“2010-01-01″) &sales$AMOUNT>2000) /R语言
比如:将记录按照SELLERID正排序,按照AMOUNT逆排序。
sales.sort(SELLERID,AMOUNT:-1) /集算器
sales[order(sales$SELLERID,-sales$AMOUNT),] /R语言
比如:求AMOUNT最大的三条记录。
sales.top(-AMOUNT;3) /集算器
head(sales[order(-sales$AMOUNT),],n=3) /R语言
(3)R语言有时用下标来计算,比如过滤;有时用函数来计算,比如求记录序号;有时是“数据集+函数+数据集”的形式,比如排序;有时是“函数+数据集+函数”的形式,比如Top N。这种多变的写法看似灵活,但会让程序员产生严重的混乱。相比之下,集算器总是“数据集+函数+函数……”这种对象式的访问形式,结构简单统一,更易于程序员掌握。
比如,进行连续计算,先过滤再求TopN,集算器的算法如下:sales.select(ORDERDATE>=date(“2010-01-01″) && AMOUNT>2000).top(AMOUNT;3)
R语言的算法如下:
Mid<-sales[as.POSIXlt(sales$ORDERDATE)>=as.POSIXlt("2010-01-01") &sales$AMOUNT>2000,]
head(Mid [order(Mid$AMOUNT),],n=3)
可以看到,集算器更擅长表达多步骤的连续计算。
总结:在本案例中,集算器在语法一致性和连续计算方面有一定的优势,对初学者更友好。
3、分组汇总
对记录分组汇总时也常会用到循环函数,比如:按CLIENT和SELLERID分组,分组后对AMOUNT求和并求最大值。
集算器:sales.groups(CLIENT,SELLERID;sum(AMOUNT),max(AMOUNT))
部分结果如下:
R语言:
result1<-aggregate(sales[,4],sales[c(3,2)],sum)
result2<-aggregate(sales[,4],sales[c(3,2)],max)
result<-cbind(result1,result2[,3])
部分结果如下:
比较:
(1)本案例要使用一种以上的汇总方法,集算器可直接实现本案例,但R语言内置的库函数不直接支持同时使用多种汇总方法,因此求和、求最大值要分为两步,最后再通过cbind拼合结果。另外,R语言在本案例中要占用更多的内存。
(2)注意一下R语言中反人类的设计:sales[c(3,2)],这里的顺序是先SELLERID再CLIENT,但业务逻辑中的分组顺序却是先CLIENT再SELLERID,完全相反,而结果又会显示为先SELLERID再CLEINT。总之,业务逻辑、代码、计算结果,这三者无法统一起来。
总结:本案例中,集算器在敏捷性、内存占用、统一性方面有优势。
4、求平方和
用循环函数求集合v=[2,3,4,5]的平方和。
注意:集算器和R语言都有现成函数可以求平方和,但这里我们用通用的循环函数来实现。
集算器:v.loops(~~+~*~;0)
R语言:Reduce(function(x,y) x+y*y, c(0,v))
比较:
(1)集算器和R语言都可以轻松实现本功能;
(2)集算器使用了loops函数,这表示以零为初始值,对v中的每个成员依次进行计算,并返回最后的结果。其中,“~”代表当前这一步的成员,“~~”代表上一步的计算结果。比如:第一步的算法是0+2*2,第二步的算法是4+3*3,依此类推。最后的结果是54。
R语言使用了Reduce函数,这表示对[0,2,3,4,5]中的成员依次计算,并将当次的计算结果代入下一次继续计算。第一步的算法是:0+2*2,第二步的算法是4+3*3,同集算器一样。
(3)R语言使用了lambda表达式来实现本算法。这种写法无需定义函数名就可以直接使用,是匿名函数的一种。本例中,function(x,y)是函数的声明部分,定义了两个参数;x+y*y是函数体,实现具体算法;c(0,v)将0和v拼在了一起,即[0,2,3,4,5],这个集合中的每个成员都会依次参与运算。由于可以传入完整的函数,因此这种写法非常灵活,可以实现功能复杂的算法。
集算器的写法可以理解为一种隐式的lambda表达式。这种写法本质和R语言的显式lambda表达式一样,但它只有表达式,既没有函数名,也无需声明函数,更不需要定义变量,因此结构更简单。本例中,“~”是内置的循环变量,无需定义;~~+~*~是表达式,用来实现具体算法;v是固定参数,参数中的每个成员都会依次参与运算。由于不能传入函数,因此理论上这种写法的灵活性和表达能力不如R语言。
(4)集算器的写法理论上不够灵活,但它有~、~~、#、[]、{}等便利的内置变量和运算符,实际表达能力反而更强。比如集算器可以用“~~”直接表示上一步的计算结果,但在R语言中这需要用reduce函数和额外的变量配合才能实现。集算器可以用“#”直接表达当前的循环序号,而R语言就很难实现该功能。集算器也可以用“[]”来表达相对位置,比如~[1]可以表示下一个成员的值,Close[-1]可以表示上一条记录中Close字段的值。
集算器还能用“{}”表示相对区间,比如{-1,1}可以表达前一位和后一位之间的三个成员,因此,用v.(~{-1,1}.avg())这种通用的表达式就可以计算移动平均值,而R语言需要用特定的函数来实现:filter(v/3, rep(1, 3),sides = 1),这里甚至没有“求平均值”这个函数,入门者很难理解。
总结:本案例中,R语言的lambda表达式理论上更强大,但理解起来稍显困难,集算器的写法相对好理解。
5、跨行组运算
这里有多支股票的日交易数据stock,请计算每支股票收盘价的日增长额。
部分原始数据如下:
集算器
A10=stock.group(Code)
A11=A10.(~.sort(Date))
A12=A11.(~.derive((Close-Close[-1]):INC))
R语言
A10<-split(stock, stock $Code)
for(I in 1:length(A10){
A10[[i]][order(as.numeric(A10[[i]]$Date)),] #sort by Date in each group
A10[[i]]$INC<-with(A10[[i]], Close-c(0,Close[- length (Close)])) #add a column, increased price
}
比较:
(1)集算器和R语言都可以实现本案例,但集算器只用到了循环函数,性能高效代码简洁,而R语言需要用for语句手工书写代码,性能和可读性都较差;
(2)本案例要进行两层循环:循环每一只股票,循环股票内的每一条记录。R语言的循环函数(包括lambda语法)没有内置的循环变量,只擅长表达最内层的循环,很难表达多层循环,即使能写也非常难懂。
集算器的循环函数可以用“~”表达循环变量,还能嵌套使用,因此很擅长表达多层循环。比如代码中的A10.(~.sort(Date)),这实际是A10.(~.sort(~.Date))的简写,前一个“~”代表当前股票,后一个“~”代表当前股票的当前记录。
(3)本案例是一个典型的有序算法,需要在每只股票里用当日收盘价减去上一日收盘价。集算器由于有#、[]、{}等便利的内置变量和运算符,因此很容易表达此类有序算法,比如:Close-Close[-1]就可以表达增长额。R语言也可以进行有序计算,但它缺乏循环序号、相对位置、相对区间等等便利功能,因此语法比较晦涩,比如增长额需要用Close-c(0,Close[- length (Close)])来表达。
本案例的有序算法还比较简单,复杂些的算法用R语言的循环函数就更难表达了,往往需要多层的for循环才能实现,比如计算股票的连续上涨天数:
A10<-split(stock, stock $Code)
for(I in 1:length(A10){
A10[[i]][order(as.numeric(A10[[i]]$Date)),] #sort by Date in each group
A10[[i]]$INC<-with(A10[[i]], Close-c(0,Close[- length (Close)])) #add a column, increased price
if(nrow(A10[[i]])>0){ #add a column, continuous increased days
A10 [[i]]$CID[[1]]<-1
for(j in 2:nrow(A3[[i]])){
if(A10 [[i]]$INC[[j]]>0 ){
A10 [[i]]$CID[[j]]<-A10 [[i]]$CID[[j-1]]+1
}else{
A10 [[i]]$CID[[j]]<-0
}
}
}
}
集算器的算法依然简单易懂:
A10=stock.group(Code)
A11=A10.(~.sort(Date))
A12=A11.(~.derive((Close-Close[-1]):INC), if(INC>0,CID=CID[-1]+1, 0):CID))
总结:在进行多层循环或跨行组的计算时,集算器循环函数的运算性能更高,代码更易书写。
相关推荐
#### 一、R语言概述与基础 **1.1 R语言环境** R语言是一种专为统计计算而设计的编程语言,它提供了丰富的图形展示和数据分析工具。R语言拥有强大的社区支持,这使得其在学术研究、数据分析等领域得到了广泛的应用...
这表明该教程汇总与R语言和ggplot2包紧密相关,因为patchwork包是在ggplot2的基础上开发的,用于处理ggplot2对象的组合。换句话说,patchwork是ggplot2可视化工具的一个扩展,它让ggplot2用户能够更容易地将多个图形...
- **入门训练**:为了快速上手R语言,建议先从简单的例子入手,逐步掌握基本语法和常用函数。 #### 简单操作;数值与向量 - **向量与赋值**:在R中,向量是最基本的数据结构之一。可以使用`c()`函数将多个元素组合...
在国际地球信息科学与地球观测学院(ITC),R语言作为一种重要的工具被广泛应用于教学和研究中。学生可以通过ITC提供的网络服务访问R语言。此外,教师和研究人员也会使用R来处理地理空间数据,进行模型构建和结果...
- **R与统计**:R语言最初是为统计分析而设计的,因此它内置了大量的统计函数和方法,如线性回归、非线性回归、时间序列分析等。 - **R与视窗系统**:R在Windows平台上提供了良好的支持,包括图形界面安装程序和图形...
12. R语言编程:包括函数式编程、编写自定义函数、使用分支和循环结构以及遵循推荐的编码风格指南。 13. 相关性和相关性分析:文档中提到了使用R语言进行配对相关性分析的例子,这是量化分析中衡量不同金融产品、...
实验结果表明,随机森林(Random Forests,简称RF)版本的分类器表现最佳,其中随机森林的某个版本(通过R语言的Caret包实现并访问)在94.1%的最大准确率上超越了90%的数据集,并且有84.3%的数据集其准确率超过了...
《Intel汇编语言程序设计(第五版)》是由Kip R.Irvine编著的一本经典教材,深入浅出地介绍了Intel架构下的汇编语言编程。这本书涵盖了从基础的指令系统到高级的编程技术,旨在帮助读者理解计算机底层运作原理,并...
`installMissingRPackages` 是一个R语言中的自定义函数,其主要目的是自动化处理R脚本运行时遇到的缺失软件包问题。在R编程环境中,我们经常需要安装各种软件包来扩展R的功能,如数据分析、可视化或机器学习等。手动...
在本项目中,"QSPpaper:与我的QSP论文相关的R函数" 是一个与定量系统药理学(Quantitative Systems Pharmacology, QSP)研究相关的R编程资源。QSP是一种综合方法,它结合了生物学、药理学、数学和计算科学,用于理解...
6.7 几种循环的比较:对比了while、do-while和for循环的特点和适用情况。 6.8 break和continue语句:介绍了break和continue在循环控制中的作用和使用时机。 6.9 程序举例:通过实例演示了循环结构程序设计。 7. ...
- 文件打开与关闭:学习fopen和fclose函数,理解文件操作模式(如"r", "w", "a")。 - 文件读写:掌握fread和fwrite函数进行二进制数据读写,fgets和fprintf进行文本数据处理。 - 文件定位:了解fseek和ftell函数...
- **编写程序**:介绍了如何使用R语言编写程序,包括如何组织代码结构。 - **自定义函数**:详细说明了如何编写自己的函数来实现特定的功能,以及如何调试这些函数。 #### 七、相关文献 - **参考资料**:推荐了...
- **编译器与解释器**:两种不同的语言执行器及其优缺点对比分析。 10. **现代编程语言趋势** - **函数式编程**:强调函数应用而非命令式控制流的语言风格。 - **泛型编程**:通过模板或泛型来实现代码复用的...
例如,"MOV A, R0"这条汇编指令就是将寄存器R0的内容移动到累加器A中,这在C语言中可能需要多行代码来实现。 C语言是一种中级语言,它提供了更高级别的抽象,使得程序员可以更专注于逻辑而非硬件细节。C语言在...