`
datamachine
  • 浏览: 163987 次
社区版块
存档分类
最新评论

集算器与R语言的循环函数对比

阅读更多

  循环函数可以遍历数组或集合中的每个成员,可以将结构复杂的循环语句用简单的函数形式表达出来,可以减少代码量并提高可读性。集算器和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))

  总结:在进行多层循环或跨行组的计算时,集算器循环函数的运算性能更高,代码更易书写。

  • 大小: 34.5 KB
  • 大小: 35.8 KB
  • 大小: 40.6 KB
  • 大小: 22.8 KB
  • 大小: 15.1 KB
  • 大小: 26.9 KB
0
2
分享到:
评论

相关推荐

    R语言笔记:数据分析与绘图的编程环境

    #### 一、R语言概述与基础 **1.1 R语言环境** R语言是一种专为统计计算而设计的编程语言,它提供了丰富的图形展示和数据分析工具。R语言拥有强大的社区支持,这使得其在学术研究、数据分析等领域得到了广泛的应用...

    7. R语言patchwork拼图教程汇总.pdf

    这表明该教程汇总与R语言和ggplot2包紧密相关,因为patchwork包是在ggplot2的基础上开发的,用于处理ggplot2对象的组合。换句话说,patchwork是ggplot2可视化工具的一个扩展,它让ggplot2用户能够更容易地将多个图形...

    R语言简介

    - **入门训练**:为了快速上手R语言,建议先从简单的例子入手,逐步掌握基本语法和常用函数。 #### 简单操作;数值与向量 - **向量与赋值**:在R中,向量是最基本的数据结构之一。可以使用`c()`函数将多个元素组合...

    R语言入门必备

    在国际地球信息科学与地球观测学院(ITC),R语言作为一种重要的工具被广泛应用于教学和研究中。学生可以通过ITC提供的网络服务访问R语言。此外,教师和研究人员也会使用R来处理地理空间数据,进行模型构建和结果...

    R语言简介,PDF格式的

    - **R与统计**:R语言最初是为统计分析而设计的,因此它内置了大量的统计函数和方法,如线性回归、非线性回归、时间序列分析等。 - **R与视窗系统**:R在Windows平台上提供了良好的支持,包括图形界面安装程序和图形...

    Quantitative Trading with R

    12. R语言编程:包括函数式编程、编写自定义函数、使用分支和循环结构以及遵循推荐的编码风格指南。 13. 相关性和相关性分析:文档中提到了使用R语言进行配对相关性分析的例子,这是量化分析中衡量不同金融产品、...

    179种分类算法比较测评

    实验结果表明,随机森林(Random Forests,简称RF)版本的分类器表现最佳,其中随机森林的某个版本(通过R语言的Caret包实现并访问)在94.1%的最大准确率上超越了90%的数据集,并且有84.3%的数据集其准确率超过了...

    Intel汇编语言程序设计(第五版)(作者Kip R.Irvine)

    《Intel汇编语言程序设计(第五版)》是由Kip R.Irvine编著的一本经典教材,深入浅出地介绍了Intel架构下的汇编语言编程。这本书涵盖了从基础的指令系统到高级的编程技术,旨在帮助读者理解计算机底层运作原理,并...

    installMissingRPackages:R函数安装缺少的R软件包

    `installMissingRPackages` 是一个R语言中的自定义函数,其主要目的是自动化处理R脚本运行时遇到的缺失软件包问题。在R编程环境中,我们经常需要安装各种软件包来扩展R的功能,如数据分析、可视化或机器学习等。手动...

    R软件中文版教程

    - **循环与向量化**:对比了传统循环与向量化的优劣,并推荐了高效的编程习惯。 - **程序编写**:介绍了如何在R中编写程序的基本框架。 - **自定义函数**:教授了如何编写自己的函数以增强R的功能。 #### 七、相关...

    QSPpaper:与我的QSP论文相关的R函数

    在本项目中,"QSPpaper:与我的QSP论文相关的R函数" 是一个与定量系统药理学(Quantitative Systems Pharmacology, QSP)研究相关的R编程资源。QSP是一种综合方法,它结合了生物学、药理学、数学和计算科学,用于理解...

    谭浩强经典C语言书籍

    6.7 几种循环的比较:对比了while、do-while和for循环的特点和适用情况。 6.8 break和continue语句:介绍了break和continue在循环控制中的作用和使用时机。 6.9 程序举例:通过实例演示了循环结构程序设计。 7. ...

    c期中试卷(1).rar

    - 文件打开与关闭:学习fopen和fclose函数,理解文件操作模式(如"r", "w", "a")。 - 文件读写:掌握fread和fwrite函数进行二进制数据读写,fgets和fprintf进行文本数据处理。 - 文件定位:了解fseek和ftell函数...

    R软件中文版教程(初学者用)

    - **编写程序**:介绍了如何使用R语言编写程序,包括如何组织代码结构。 - **自定义函数**:详细说明了如何编写自己的函数来实现特定的功能,以及如何调试这些函数。 #### 七、相关文献 - **参考资料**:推荐了...

    Concepts of Programming Languages - Robert W. Sebesta

    - **编译器与解释器**:两种不同的语言执行器及其优缺点对比分析。 10. **现代编程语言趋势** - **函数式编程**:强调函数应用而非命令式控制流的语言风格。 - **泛型编程**:通过模板或泛型来实现代码复用的...

    单片机汇编与C语言对照

    例如,"MOV A, R0"这条汇编指令就是将寄存器R0的内容移动到累加器A中,这在C语言中可能需要多行代码来实现。 C语言是一种中级语言,它提供了更高级别的抽象,使得程序员可以更专注于逻辑而非硬件细节。C语言在...

Global site tag (gtag.js) - Google Analytics