您的位置:首页 > 其它

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

2015-12-27 23:15 204 查看



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


伦理片 http://www.dotdy.com/

比较:
(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最大的三条记录。

(3)R语言有时用下标来计算,比如过滤;有时用函数来计算,比如求记录序号;有时是“数据集+函数+数据集”的形式,比如排序;有时是“函数+数据集+函数”的形式,比如Top N。这种多变的写法看似灵活,但会让程序员产生严重的混乱。相比之下,集算器总是“数据集+函数+函数……”这种对象式的访问形式,结构简单统一,更易于程序员掌握。

比如,进行连续计算,先过滤再求TopN,集算器的算法如下:

R语言的算法如下:

Mid<-sales[as.POSIXlt(sales$lt("2010-01-01") &sales$AMOUNT>2000,]

head(Mid [order(Mid$AMOUNT),],n=3)

可以看到,集算器更擅长表达多步骤的连续计算。

总结:在本案例中,集算器在语法一致性和连续计算方面有一定的优势,对初学者更友好。


3、分组汇总

对记录分组汇总时也常会用到循环函数,比如:按CLIENT和SELLERID分组,分组后对AMOUNT求和并求最大值。

集算器:sales.groupsCLIEmax(AMOUNT))

部分结果如下:

(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))

比较:

影音先锋电影 http://www.iskdy.com/
(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表达式理论上更强大,但理解起来稍显困难,集算器的写法相对好理解。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: