R,不仅仅是一种语言 本文原载于《程序员》杂志2010年第8期,因篇幅所限,有所删减,这里刊登的是全文,希望对大家有帮助。
R是什么 工欲善其事,必先利其器,作为一个战斗在IT界第一线的工程师,C/C++、java、perl、python、ruby、php、javascript、erlang等等等等,你手中总有一把使用自如的刀,帮助你披荆斩棘。 应用场景决定知识的储备与工具的选择,反过来,无论你选择了什么样的工具,你一定会努力地把它改造成符合自己应用场景所需的那个样子。从这个道理来说,我选择了R[1]作为数据挖掘人员手中攻城陷池的那把云梯,并努力地把它改造成自己希望的那个样子。 关于R的一个比较准确的描述是:R是一门用于统计计算和作图的语言,它不单是一门语言,更是一个数据计算与分析的环境。统计计算领域有三大工具:SAS、SPSS、S,R正是受S语言和Scheme语言影响发展而来。其最主要的特点是免费、开源、各种各样的模块十分齐全,在R的综合档案网络CRAN中,提供了大量的第三方功能包,其内容涵盖了从统计计算到机器学习,从金融分析到生物信息,从社会网络分析到自然语言处理,从各种数据库各种语言接口到高性能计算模型,可以说无所不包,无所不容,这也是为什么R正在获得越来越多各行各业的从业人员喜爱的一个重要原因。 从R的普及来看,国外的普及度要明显好于国内,跟盗版windows的泛滥会影响linux在中国的普及一样的道理,破解的matlab与SPSS的存在也影响了R在中国的使用人群。但在国外高校的统计系,R几乎是一门必修的语言,具有统治性的地位。在工业界,作为互联网公司翘楚的google内部也有不少的工程使用R进行数据分析工作,这里[2]有一个google campus的讲课视频,内容就是用R作为工具来讲述数据挖掘的概念与算法。 随着近年来R使用者的增加,关于R的报道也屡有见于报端,如2009年初美国纽约时报就有一篇很好的报道:Data Analysts Captivated by R’s Power[3]。报道中述说了R的发展历史以及由于数据挖掘需求的增长而日益普及的现状,它虽源于S但其发展却远远地超过了S,已经成为高校毕业学生所选用的第二大工具语言,google与Pfizer的员工也介绍了R在自己公司中的应用。此外,报道中google首席经济学家Hal Varian说:R的最让人惊艳之处在于你可以通过修改它来做所有的事情,而你已经拥有大量可用的工具包,这无疑让你是站在巨人的肩膀上工作。 以下就R的几个主要应用场景以及我在实践中的经验对这个并不算主流的编程语言作一些介绍。 统计计算:R之最强项 R从它出生的第一天就是为了做统计计算的,那时它被定义为一个统计计算与作图的工具,虽然发展到现在它已经被赋予了越来越强大的功能,但现在R的开发人员里,还是以各个高校统计系的老师与学生为主,他们自然最了解自己最需要的是什么。 在统计计算中,我们常常需要根据样本数据作线性回归,得到一定的规律性,R中实现这个功能十分简单,以下是一个一元线性回归的例子: x <- 1:10 y <- x+rnorm(10, 0, 1) fit <- lm(y ~ x) summary(fit) 注明一下,R里的“<-”符号意义为赋值,大多数情况下它可以用“=”号来代替,但某些特殊的场合不可以,本文会遵循“<-”这种官方使用的写法。这个例子的前两行准备了两列数据:自变量x与因变量y,第三行的函数lm即根据提供的样本数据进行线性回归计算,得到的模型结果可以用第四行打印出来。函数lm除了可以做这种简单的一元线性回归,还可以做多元线性回归,同时返回模型的各种统计量。 做统计的往往免不了要做各种各样的图形,R的另一个基本特点就是对图形的强大支持,以下代码展示了一个箱线图的作法,代码来自boxplot函数的manual,该图显示了几列数据的分位数、中值、均值、奇异点等信息及其对比位置。更详细的关于R的作图功能可以参看[4]。 boxplot(mpg~cyl,data=mtcars, main=”Car Milage Data”, xlab=”Number of Cylinders”, ylab=”Miles Per Gallon”) 机器学习:让你的数据发挥它应有的作用 机器学习、数据挖掘领域面临着一些抽象自大量现实生活的问题,比如关联规则挖掘、聚类、分类这三大问题。作为一个完备的工程计算包,R毫无疑问对它们都提供了足够的支持。 关联规则问题源于“买了这件商品的顾客还买了什么”这个问题,现在已经广泛应用于客户行为分析以及互联网用户行为分析中。关联规则挖掘领域最经典的算法为apriori,R的第三方包arules[5],就是专门用于做关联规则挖掘的。以下例子需要你已经安装了arules包。 library(arules) data <- paste(“item1,item2″,”item1″,”item2,item3″, sep=”\n”) write(data, file = “demo_basket”) tr <- read.transactions(“demo_basket”, format = “basket”, sep=”,”) data(“Adult”) rules <- apriori(Adult, parameter = list(supp = 0.5, conf = 0.9, target = “rules”)) 最后一行的apriori函数接受一个transaction对象的输入,输出关联规则对象rules,为方便起见,这里用于计算的transaction对象Adult是通过第5行从arules包中现成载入进来的,第2~4行说明了怎么从一个文本文件中读入数据并生成一个transaction对象。 聚类算法使用最广泛的高效算法无疑是kmeans,R在其默认载入的stats包中就包含了这个函数,以下是一个来自kmean说明文档的例子: x <- rbind(matrix(rnorm(100, sd = 0.3), ncol = 2), matrix(rnorm(100, mean = 1, sd = 0.3), ncol = 2)) cl <- kmeans(x, 2) plot(x, col = cl$cluster) points(cl$centers, col = 1:2, pch = 8, cex=2) 代码第1行生成两组两维的正态分布的数据,第一组均值为0,第二组均值为1,两组数据方差都为0.3。第2行对该数据进行聚类,第3和第4行把聚类结果画出来。 分类器是模式识别领域的研究主题,也是人类认知活动的中心。多年来的学术研究积累下来很多种类型的分类器,而其中比较靠谱的分类器基本都能在R中找到对应的实现。诸多分类器中以svm最为著名,它也被一些人称为是单分类器的王道。以下是一个利用svm对著名的iris数据集进行分类的过程,运行该例子需要你已经安装了e1071这个包[6]。 library(e1071) data(iris) x <- subset(iris, select = -Species) y <- iris$Species model <- svm(x, y) summary(model) pred <- predict(model, x) table(pred, y) 第5行代码调用svm函数,计算由x作为特征y作为类别标签的分类器模型,第7行把模型应用于原数据进行预测。 以上例子的演示并非想让各位读者当场学会各个不同领域中这些功能函数的用法,而是一方面展示一些实际的R代码以及它解决问题的方式,另一方面说明了R在这些常见的机器学习领域的积累。在R帮助下去解决这些或许不是我们专业的问题,可以省去我们大量重复造轮子的精力,写出来的代码也足够的短小精悍,节省时间之余也让你对自己算法逻辑的全局一览无余。 高性能计算:向量化与并行/分布计算 作为现代数据挖掘人员从业者,可能第一个需要关心的是所使用工具的可伸缩性(scalability),具体来说就是在面对大数据量场景时的计算能力。 一个拥有高性能计算能力的计算包,首先它必须能充分利用历史上积累下来的那些著名的数值计算包,比如blas、lapack;另一方面,它必须具有良好的可扩展性,即它必须方便开发人员并行化自己的算法,很幸运这些特性R都具备了。 类似于R、scilab与matlab那样的工程计算包,通常都会以向量化计算(Vectorization)作为其基本的计算特点(即使python的numpy包也是如此),因为向量化的处理方式是现代大型计算机的基本特性,在计算机领域,无论硬件还是软件,都提供了对向量化的支持,硬件上如Intel的MMX, SSE等指令集都提供了对向量化的支持,更多可以看到wikipedia上的介绍[7]。软件上如blas等著名的计算包,天然地就可以对向量化的命令自动实施并行计算。 所谓向量化,是一种特殊的并行计算的方式,相比于一般程序在同一时间只执行一个操作的方式,它可以在同一时间执行多次操作,通常是对不同的数据执行同样的一个或一批指令,或者说把指令应用于一个数组/向量。以下列出R中经常使用几种向量化运算,都是十分稀松平常的操作,但它们本质上都是同时对一批数据应用相同的操作,所以都可以经过向量化处理方式的改造:
- 向量取值,如:V[1:10]
- 向量赋值,如:V[1:10] <- seq(1,10)
- lapply,类似于python里的map函数:lapply(A, mean)
- 矩阵运算:A + B;A %*% B