R语言和集算器吸引人的地方之一在于,它们的代码风格都比较敏捷,用简短的代码就可以实现丰富的功能。比如都可以写出”Vector Computing”表达式,对判断语句都进行了简化,都可以把基础函数扩展成高级函数,都支持泛型。其中向量化计算的特点是用函数和运算符处理批量数据,避免循环语句。这将带来2个优点:使程序员可以轻松掌握,降低学习成本;方便实现计算,提高性能。
下面用几个例子来比较一下R和集算器在向量计算方面的细微区别。
我们先看看最基本的Vector取值,赋值。比如:取出Vetor中下标在5-10的5个值,替换成另5个值。
R解法:
01 A1<-c(51,52,53,54,55,56,57,58,59,60)
02 A2<-A1[6:10]
03 A1[6:10]<-seq(1,5)
集算器解法:
A1 =[51,52,53,54,55,56,57,58,59,60]
A2 =A1(to(6,10))
A3 >A1(to(6,10))=to(1,5)
点评:2者都可以方便地实现向量的取值赋值,用法也几乎一样。不过看起来R用”:”来表示区间范围的写法更直观顺眼。
接着看一下Vector的数学运算
R解法:
04 A4<-c(1,2,3)
05 A5<-c(2,4,6)
06 A4*A5 #向量乘法,结果是: [1] 2 8 18
07 A4+2 #向量与常数相加,结果是: [1] 3 45
08 ifelse(A4>1,A4+2,A4-2) #条件计算,结果是: [1]-1 4 5
09 sum(A4) #聚合,向量成员求和,结果是:6
10 sort(A4,decreasing = TRUE) #逆序排序,结果是:3 2 1
集算器解法:
A4 =[1,2,3]
A5 =[2,4,6]
A6 =A4**A5 ‘向量乘法,结果是:2 4 18
A7 =A4.(~+2) ‘向量与常数相加,结果是:3 4 5
A8 =A4.(if(~>1,~+2,~-2)) ‘条件计算,结果是:-1 4 5
A9 =A4.sum() ‘聚合,向量成员求和,结果是:6
A10 =A4.sort(~:-1) ‘逆序排序,结果是:3 2 1
点评:可以看到,不论是Vector的四则运算,聚合运算,还是排序运算,2者都可以很好的实现,语法也非常相近。需要注意的是,虽然集算器的代码看起来更加”面向对象”,但底层来说R才是真正的”面向对象”。前者更利于在普通商业领域使用;后者更利于程序员自己编写扩展的package,在科学专业领域更易被接受。
下面看看针对结构化数据的向量运算。比如,以Northwind数据库的Orders table为基础进行以下计算:
1. 查询运货费在200和300之间
2. 查询订单日期在1997年的数据。
3. 求上述集合的交集:既是运货费在200和300之间的,同时订单日期在1997年的数据。
4. 对上一步的结果按EmployeeID分组,计算每个员工的平均运货费。
R解法:
02 A2<-result[result$Freight>=200& result$Freight<=300,]
03 A3<- result[format(result$OrderDate,'%Y')=="1997",]
04 A4<-result[result$Freight>=200& result$Freight<=300 &format(result$OrderDate,'%Y')=="1997",]
05 A5<-tapply(A2$Freight,INDEX=A2$EmployeeID,FUN=mean)
集算器解法:
A2 =A1.select(Freight>=200 &&Freight<=300 && year(OrderDate)==1997)
A3 =A1.select(year(OrderDate)==1997)
A4 =A3^A4
A5 =A4.group(EmployeeID;~.avg(Freight))
点评:R在查询和分组统计时表现不错,但集合运算时不如集算器,实际上,在这个例子中R并没有进行集合运算,而是用查询的方法间接实现的。
R是能够对简单的向量进行集合运算的,比如:intersect(A2$Orderid,A3$Orderid),但对于data.frame这种结构化数据则不能直接进行集合运算。
当然这并不是说R的向量化计算不够强大,实事上,如果进行矩阵相关的运算,R就要比集算器更好用。比如求矩阵A的eigen value,R可以简单的表达为:eigen(A),而集算器则没有直接的函数可以表示。这也从另一个侧面说明集算器更适合商业计算,R则可以应用于科学计算。
总结一下,向量化运算中,两者均在基本运算方面表现优秀,其中R在矩阵运算方面更好;集算器在结构化数据方面表现更好。