R语言基础指令和并行算法初识(上篇)

来源:互联网 发布:2015 库里对火箭 数据 编辑:程序博客网 时间:2024/04/28 14:57

一.R语言背景介绍
二. R语言基础指令
三. R语言并行算法
四. 计划打算

一.R语言背景介绍
1.2、起源:R是统计领域广泛使用的诞生于1980年左右的S语言的一个分支。可以认为R是S语言的一种实现。而S语言是由AT&T贝尔实验室开发的一种用来进行数据探索、统计分析和作图的解释型语言。

1.3、功能:R是一套完整的数据处理、计算和制图软件系统。其功能包括:1)、数据存储和处理系统;2)、数组运算工具(其向量、矩阵运算方面功能尤其强大);3)、完整连贯的统计分析工具;4)、优秀的统计制图功能;5)、简便而强大的编程语言:6)、可操纵数据的输入和输出,可实现分支、循环,用户可自定义功能  贝尔实验室 。1.4、特点:1)、R是一个免费的自由软件,它有UNIX、LINUX、MacOS和WINDOWS版本,都是可以免费下载和使用的。在那儿可以下载到R的安装程序、各种外挂程序和文档。在R的安装程序中只包含了8个基础模块,其他外在模块可以通过CRAN获得。 2)、R的原代码可自由下载使用,亦有已编译的执行档版本可以下载,可在多种平台下运行,包括UNIX、Windows和MacOS。 R主要是以命令行操作,同时有人开发了几种图形用户界面。 3)、R内建多种统计学及数字分析功能。因为S的血缘,R比其他统计学或数学专用的编程语言有更强的物件导向(面向对象程序设计)功能。 4)、R的另一强项是绘图功能,制图具有印刷的素质,也可加入数学符号。 5)、虽然R主要用于统计分析或者开发统计相关的软体,但也有人用作矩阵计算。其分析速度可媲美GNU Octave甚至商业软件MATLAB。 6)、R的功能能够通过由用户撰写的套件(功能包)增强。

二. R语言基础指令
2.1、对象指令

   R语言是一种面向对象的语言,所有的对象都有两个内在属性:元素类型和长度。   元素类型是对象内元素的基本类型,包括:数值(numeric),字符型(character),复数型(complex)、逻辑型(logical)、函数(function)等。除了元素类型外,对象本身也有不同的“类型”,表示不同的数据结构。R中的对象类型主要包括:  向量(vector): 由一系列有序元素构成。  因子(factor):对同长的其他向量元素进行分类的向量对象。R 同时提供有序和无序因子。  数组(array):带有多个下标的类型相同的元素的集合  矩阵(matrix):矩阵仅仅是一个双下标的数组。R提供了一下函数专门处理二维数组(矩阵)。  数据框(data frame):和矩阵类似的一种结构。在数据框中,列可以是不同的对象。                                    列表(list):是一种泛化的向量。它没有要求所有元素是同一类型,许多时候就是向量和列表类型。列表为统计计算的结果返回提供了一种便利的方法。

向量(Vector):

例如一个从1到30的规则整数序列,可以这样产生:

x <- 1:30 这个结果向量x有30个元素。
函数seq可以生成如下的实数序列:
seq(1, 5, 0.5) [1] 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 其中第一个数字表示序列的起点,第二个表示终点,第三个是生成序列的步长。
也可以这样使用:
seq(length=9, from=1, to=5) [1] 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0
还可以用函数c直接输入数值:
c(1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5) [1] 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0
如果想用键盘输入一些数据也是可以的,只需要直接使用默认选项 的scan函数:
z <- scan()
1: 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0
10:
Read 9 items
z [1] 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0
数组(array):

一维数据是向量,二维数据是矩阵,数组是向量和矩阵的直接推广,是由三维或三维以上的数据构成的. 数组函数是array(),语法是:array(dadta, dim)其中data必须是同一类型的数据,dim是各维的长度组成的向量。 1、产生一个三维和四维数组。 例1:xx <- array(1:24, c(3, 4, 2)) #一个三维数组 例2:yy <- array(1:36, c(2, 3, 3, 2)) #一个四维数组  2、dim()函数可将向量转化成数组或矩阵。 例1:xx <- 1:24; dim(xx) <- c(3, 4, 2); xx #效果同array(1:24, c(3, 4, 2)) 例2:zz <- 1:10; dim(zz) <- c(2, 5); zz #效果同matrix(1:10, 2, 5)

因子(Factor) :

一个因子不仅包括分类变量本身还包括变量不同的可能水 平    因子函数factor用下面的选项创建一个因子:  factor(x, levels = sort(unique(x), na.last = TRUE),  labels = levels, exclude = NA, ordered = is.ordered(x))  levels 用来指定因子可能的水平(缺省值是向量x中互异的值);labels  用来指定水平的名字;exclude表示从向量x中剔除的水平值;ordered是  一个逻辑型选项用来指定因子的水平是否有次序。下面有一些例子:

factor(1:3)
[1] 1 2 3 19
Levels: 1 2 3

> factor(1:3, levels=1:5)  [1] 1 2 3  Levels: 1 2 3 4 5  > factor(1:3, labels=c("A", "B", "C"))  [1] A B C  Levels: A B C  > factor(1:5, exclude=4)  [1] 1 2 3 NA 5  Levels: 1 2 3 5

矩阵(Matrix) :
一个矩阵实际上是有一个附加属性(维数dim)的向量, 维数即为一个长度为2的向量,用来指定矩阵的行数和列数。
一个矩阵可以用函数matrix来创建:

matrix(data = NA, nrow = 1, ncol = 1, byrow = FALSE,  dimnames = NULL)  选项byrow表示数据给出的值是要按列填充(缺省值)还是按行填充  (如果为TRUE)。可以通过选项dimnames给行列命名。一些实例参考:> matrix(data=5, nr=2, nc=2)

[,1] [,2]

[1,] 5 5

[2,] 5 5

matrix(1:6, 2, 3)

[,1] [,2] [,3]

[1,] 1 3 5

[2,] 2 4 6

matrix(1:6, 2, 3, byrow=TRUE)

[,1] [,2] [,3]

[1,] 1 2 3

[2,] 4 5 6
数据框(Data frame):

用函数data.frame来创建。数据框中的向  量必须有相同的长度,如果其中有一个比其它的短,它将“循环”整数  次(以使得其长度与其它向量相同): > x <- 1:4; n <- 10; M <- c(10, 35); y <- 2:4  > data.frame(x, n)  x  n  

1 1 10
2 2 10
3 3 10
4 4 10

data.frame(x, M)
x m
1 1 10
2 2 35
3 3 10
4 4 35
要注意的一种情况是:
data.frame(x, y)

Error in data.frame(x, y) :

arguments imply differing number of rows: 4, 3

如果一个因子包含在一个数据框中,它必须和其中的向量有相同的长度。

列表(List) :
列表可以用list函数创建,方法与创建数据框类似。它对其中包含的对象没有什么限制。和data.frame()比较,缺省值没有给出对象的名称;用前面的向量x和y举例:

L1 <- list(x, y); L2 <- list(A=x, B=y)
L1
[[1]]
[1] 1 2 3 4
[[2]]
[1] 2 3 4
L2
A[1]1234B
[1] 2 3 4
names(L1)
NULL
names(L2)
[1] “A” “B”

2.2、数学指令

数学运算符:

+,-,*,/,^,%%。(加,减,乘,除,乘方,求余。)

比较运算符:

,<,>=,<=,==,!=。(大于,小于,大于等于,小于等于,等于,不等于。)

逻辑运算符:

&,|,!。(与,或,非。)
数学函数:
1、round() #四舍五入
2、signif() #取有效数字
3、trunc() #取整 floor() #向下取整 ceiling() #向上取整
4、logb(a, b) #以b为底的对数,省略b表示自然对数 log() #自然对数 log10() #以10为底的常用对数
5、sqrt() #平方根 exp() #指数
6、sin() #正弦 cos() #余弦 tan() #正切 asin() #反正弦 acos() #反余弦 atan() #反正切 sinh() #双曲正弦 tanh() #双曲正切
7、nchar() #字符长度 例:xx <- ‘China is a great country’ nchar(xx)
8、substring() #取子字符串 例:substring(xx, 1, 5)
9、paste() #连接字符 语法是:paste(…, sep = ” “, collapse = NULL)
2.3、结构指令

if: if语句 Looping: 循环控制 repeat: repeat语句 while: while语句 for: for语句 switch: switch语句 

if语句 :
if ( statement1 ) //判断是否符合判定条件statement1

     statement2  //符合statement1则执行statement2 else if ( statement3 )  //不符合statement1,则继续判断是否符合判定条件

statement3

     statement4  //符合statement3,则执行statement5 else if ( statement5 )  //不符合statement3,则继续判断是否符合判定条件statement5     statement6  //符合statement5,则执行statement6 else     statement8  //不符合statement5,则执行最后的statement8

repeat语句:

repeat 语句会重复对主体部分求值直到明确地要求退出。这就意味着你必须小心使用 repeat,因为可能导致死循环。 repeat 循环的语法如下  repeat statement

while语句 :

while 语句和 repeat 语句非常的类似。 while 循环的语法如下  while ( statement1 ) statement2其中statement1为循环条件,statement2为执行语句。

for语句 :

for 循环的语法如下  for ( name in vector )    statement1其中name处于向量vector中,是循环条件,处于循环条件中时,程序会依次执行statement1语句,直到当跳出循环后,即name超出vector的范围,for循环终止。

switch语句:
switch语句会根据判定结果的不同而执行不同的分支语句,首先执行statement,其返回值范围从1到list长度。switch执行list中包含的语句,并将结果返回。其语法形式如下:

 switch (statement, list) 

switch(x)
{
case 1:
case 2:
case 3: System.out.println(“haha”);
break;
case 4: System.out.println(“hehe”);
}
2.4、统计量指令:

平均值:mean(vec)
排序:sort(vec) 对向量vec从小到大进行排序。降序:sort(vec, decreasing = TRUE)。
获得按照大小排序后的元素的位置:order(vec) 获得向量vec第i大元素在向量中的位置。
获得按照大小排序后每个元素的位置:rank(x) 获得向量x每个元素大小位置。
中位数 :median(vec)
百分位数 (用99个数值或99个点,将按大小顺序排列的观测值划分为100个等分,则这99个数值或99个点就称为百分位数):quantile(vec)
分散程度的度量
方差:var(vec)
标准差:sd(vec)
协方差矩阵:cov(vec)
相关矩阵:cor(vec)
2.5、文件指令:

dir.create:新建一个文件夹
list.dirs:显示目录下的文件夹
list.files:显示目录下的文档
file.create:文档创建
file.exists:判断文档是否存在
file.remove:文档删除
file.rename:重命名
file.append:文档添加
file.copy:文档复制
file.symlink(from, to) file.show:显示文档内容
file.info:显示文档信息
file.edit:编辑文档
zip: 压缩文件
unzip: 解压缩文件
2.6、矩阵运算指令:

由于R的目的性和特殊性,我们会频繁接触图像的数字化和繁琐的处理加工,因此,矩阵运算作为其中的基础工作,就理所应当的去加强掌握!函数rbind()和cbind()分别用上下或左右的方式合并向量或矩阵:> m1 <- matrix(1, nr = 2, nc = 2)> m2 <- matrix(2, nr = 2, nc = 2)> rbind(m1, m2)[,1] [,2][1,] 1 1[2,] 1 1[3,] 2 2[4,] 2 2> cbind(m1, m2)[,1] [,2] [,3] [,4][1,] 1 1 2 2[2,] 1 1 2 2

两矩阵乘积的运算符是“%*%”,例如,对上面的矩阵m1和m2:

> rbind(m1, m2) %*% cbind(m1, m2)[,1] [,2] [,3] [,4][1,] 2 2 4 4[2,] 2 2 4 4[3,] 4 4 8 8[4,] 4 4 8 8> cbind(m1, m2) %*% rbind(m1, m2)[,1] [,2][1,] 10 10[2,] 10 10矩阵的转置由函数t完成;这个函数也可以作用于数据框。R中也有一些用于矩阵计算的专门的函数。我们可以使用solve求矩阵的

逆,用qr来分解矩阵,用eigen来计算特征值和特征向量,用svd来做奇异值
分解。

函数diag可以用来提取或修正一个矩阵的对角元,或者创建一个对角矩

阵。

diag(m1)
[1] 1 1
diag(rbind(m1, m2) %*% cbind(m1, m2))
[1] 2 2 8 8
diag(m1) <- 10
m1
[,1] [,2]
[1,] 10 1
[2,] 1 10
diag(3)
[,1] [,2] [,3]
[1,] 1 0 0
[2,] 0 1 0
[3,] 0 0 1
v <- c(10, 20, 30)
diag(v)
[,1] [,2] [,3]
[1,] 10 0 0
[2,] 0 20 0
[3,] 0 0 30
diag(2.1, nr = 3, nc = 5)
[,1] [,2] [,3] [,4] [,5]
[1,] 2.1 0.0 0.0 0 0
[2,] 0.0 2.1 0.0 0 0
[3,] 0.0 0.0 2.1 0 0

三. R语言并行算法
3.1、R中的高效批量处理函数(lapply sapply apply tapply mapply)

R语言提供了批量处理函数,可以循环遍历某个集合内的所有或部分元素,以简化操作。这些函数底层是通过C来实现的,所以效率也比手工遍历来的高效。批量处理函数有很重要的apply族函数:lapply sapply apply tapply mapply。   apply族函数是高效能计算的运算向量化(Vectorization)实现方法之一,比起传统的for,while常常能获得更好的性能。apply : 用于遍历数组中的行或列,并且使用指定函数来对其元素进行处理。lapply : 遍历列表向量内的每个元素,并且使用指定函数来对其元素进行处理。返回列表向量。

sapply : 与lapply基本相同,只是对返回结果进行了简化,返回的是普通的向量。
vapply :类似于 sapply ,但是提供了第三个参数 FUN.VALUE 用以指明返回值的形式
mapply: 支持传入两个以上的列表。
tapply: 接入参数INDEX,对数据分组进行运算,就和SQL中的by group一样。
通过对数组或者矩阵的一个维度使用函数生成值得列表或者数组、向量。
apply(X, MARGIN, FUN, …)
X 阵列,包括矩阵
MARGIN 1表示矩阵行,2表示矩阵列,也可以是c(1,2)
例:

xxx<-matrix(1:20,ncol=4) //创建矩阵
apply(xxx,1,mean) //获得矩阵中每一行的平均值
[1] 8.5 9.5 10.5 11.5 12.5
apply(xxx,2,mean) //获得矩阵中每一列的平均值
[1] 3 8 13 18
xxx //xxx为所创建的矩阵
[,1] [,2] [,3] [,4]
[1,] 1 6 11 16
[2,] 2 7 12 17
[3,] 3 8 13 18
[4,] 4 9 14 19
[5,] 5 10 15 20
通过对x的每一个元素运用函数,生成一个与元素个数相同的值列表
lapply(X, FUN, …)
X表示一个向量或者表达式对象,其余对象将被通过as.list强制转换为list

例:

x <- list(a = 1:10, beta = exp(-3:3), logic = c(TRUE,FALSE,FALSE,TRUE))
x //展示结果

a[1]12345678910//a110beta
[1] 0.04978707 0.13533528 0.36787944 1.00000000 2.71828183 7.38905610
[7] 20.08553692 //beta为自然常数e(2.71828)从-3到3的次方的结果
$logic
[1] TRUE FALSE FALSE TRUE //logic是一个逻辑序列

lapply(x,mean) //获取上述3个序列分别对应的平均值

a[1]5.5beta
[1] 4.535125
$logic
[1] 0.5
sapply(list, FUN, …, simplify, USE.NAME=TRUE)
比 lapply 多了一个 simplify 参数。如果 simplify=FALSE ,则等价于 lapply 。否则,在上一种情况的基础上,将 lapply 输出的list简化为vector或matrix。例:
lapply和sapply作对比:

lst <- list(a=c(1:5), b=c(6:10))
sapply(lst, mean) >lapply(lst,mean)
a b a38[1]3sapply(lst,fivenum)b
a b [1] 8
[1,] 1 6 > lapply(lst, fivenum)
[2,] 2 7 a[3,]38[1]12345[4,]49b
[5,] 5 10 [1] 6 7 8 9 10
//其中,fivenum返回返回五个数字摘要(最低,低铰链,中位数,上铰链,最大)的输入数据。
vapply(list, FUN, FUN.VALUE, …, USE.NAME=TRUE)

vapply 类似于 sapply ,但是提供了第三个参数 FUN.VALUE 用以指明返回值的形式,可以看作返回值的模板。例

lst <- list(a=c(1:5), b=c(6:10))
res <- vapply(lst, function(x) c(min(x), max(x)), c(min.=0, max.=0))
//function(x) c(min(x), max(x))是返回lst中的最大值和最小值;
//c(min.=0, max.=0)指明结果返回的模板;
res
a b
min. 1 6
max. 5 10
mapply(FUN, …,MoreArgs=NULL,SIMPLIFY=TRUE,USE.NAMES=TRUE)

mapply 是多变量版的 sapply ,参数(...)部分可以接收多个数据, mapply 将 FUN 应用于这些数据的第一个元素组成的数组,然后是第二个元素组成的数组,以此类推。要求多个数据的长度相同,或者是整数倍关系。返回值是vector或matrix,取决于 FUN 返回值是一个还是多个。

mapply(sum, list(a=1,b=2,c=3), list(a=10,b=20,d=30))
a b c
11 22 33
mapply(function(x,y) x^y, c(1:5), c(1:5))
[1] 1 4 27 256 3125
mapply(function(x,y) c(x+y, x^y), c(1:5), c(1:5))
//此时的function(x,y)有两个返回值,一个是两数之和,另一个是两数之积;
[,1] [,2] [,3] [,4] [,5]
[1,] 2 4 6 8 10
[2,] 1 4 27 256 3125

3.2、parallel包
众所周知,在大数据时代R语言有两个弱项,其中一个就是只能使用单线程计算。但是R在2.14版本之后,R就内置了parallel包,强化了R的并行计算能力。
parallel包实际上整合了之前已经比较成熟的snow包和multicore包,multicore无法在windows下运行。parallel包可以很容易的在计算集群上实施并行计算,在多个CPU核心的单机上,也能发挥并行计算的功能。我们今天就来探索一下parallel包在多核心单机上的使用。
parallel包的思路和lapply函数很相似,都是将输入数据分割、计算、整合结果。只不过并行计算是用到了不同的cpu来运算。

这样的计算过程可以使用如下方式来表述:1、启动M个附属进程,并初始化2、针对于任务,为每个附属进程分发所有的数据3、将任务粗略的分为M个块儿(chunks),并将这些块儿发送到附属进程(包含需要的R代码)4、等待所有的附属进程完成计算任务,并返回结果5、对于其他任务也同样重复2-46、关闭附属进程

在parallel包里,对应上述两种并行化方式有如下两个核心函数(针对于lapply函数的并行化,mclapply在windows上不能使用):
parLapply(cl, x, FUN, …)
mclapply(X, FUN, …, mc.cores)

下面将parallel包与传统lapply算法(前面提到过)作比较,体验parallel包对于提升效率的重要性:
案例1:直接使用lapply(隐式循环函数,它实际就是对不同的数据应用了相同的函数):
fun <- function(x){
return (x+1);
}
system.time({
res <- lapply(1:5000000, fun);
});
user system elapsed
21.42 1.74 25.70
//对于1到五百万中的每个数进行加一运算,得到完成运算所用的时间。
案例2:使用parallel包来加速
library(parallel) //载入parallel包,并且不返回任何信息
#打开四核,具体核数根据机器的核数决定
cl <- makeCluster(getOption(“cl.cores”, 4));
system.time({
res <- parLapply(cl, 1:5000000, fun)
});
user system elapsed
6.54 0.34 19.95

#关闭并行计算stopCluster(cl);看看单核机器跑出来的结果:user  system elapsed29.30    9.23   97.22

由上述实验数据可见,在应用parallel包以及其中的函数方法进行运算时应注意的是:

1)、并非核数越多越好,看机器配置。2)、首先要先用detectCores函数确定系统核心数目,对于Window系统下的Intel I5或I7 处理器,一般使用detectCores(logical = F)来获得实际的物理核心数量。3)、由于这个函数使用的是调用Rscript的方式,这个例子里,对象被复制了三份,因此内存会吃的很厉害,在大数据条件就要小心使用。

3.3、R语言中的遗传算法

背景介绍:遗传算法是一种解决最优化的搜索算法,是进化算法的一种。进化算法最初借鉴了达尔文的进化论和孟德尔的遗传学说,从生物进化的一些现象发展起来,这些现象包括遗传、基因突变、自然选择和杂交等。遗传算法通过模仿自然界生物进化机制,发展出了随机全局搜索和优化的方法。遗传算法其本质是一种高效、并行、全局搜索的方法,它能在搜索过程中自动获取和积累有关搜索空间的知识,并自适应的控制搜索过程,计算出全局最优解。算法步骤:1. 创建初始种群2. 循环:产生下一代3. 评价种群中的个体适应度4. 定义选择的适应度函数5. 改变该种群(交配和变异)6. 返回第二步7. 满足终止条件结束

这里写图片描述
目标:在遗传算法里,优化问题的解是被称为个体,它表示为一个变量序列,叫做染色体或者基因串。染色体一般被表达为简单的字符串或数字串,也有其他表示法,这一过程称为编码。首先要创建种群,算法随机生成一定数量的个体,有时候也可以人工干预这个过程进行,以提高初始种群的质量。
评价:在每一代中,每一个个体都被评价,并通过计算适应度函数得到一个适应度数值。种群中的个体被按照适应度排序,适应度高的在前面。
接下来,是产生下一代个体的种群,通过选择过程和繁殖过程完成。
选择:是根据新个体的适应度进行的,但同时并不意味着完全的以适应度高低作为导向,因为单纯选择适应度高的个体将可能导致算法快速收敛到局部最优解而非全局最优解,我们称之为早熟。
作为折中,遗传算法依据原则:适应度越高,被选择的机会越高,而适应度低的,被选择的机会就低。初始的数据可以通过这样的选择过程组成一个相对优化的群体。
繁殖:表示被选择的个体进入交配过程,包括交配(crossover)和突变(mutation),交配对应算法中的交叉操作。一般的遗传算法都有一个交配概率,范围一般是0.6~1,这个交配概率反映两个被选中的个体进行交配的概率。
突变:表示通过突变产生新的下一代个体。一般遗传算法都有一个固定的突变常数,又称为变异概率,通常是0.1或者更小,这代表变异发生的概率。根据这个概率,新个体的染色体随机的突变,通常就是改变染色体的一个字节(0变到1,或者1变到0)。

遗传算法实现将不断的重复这个过程:每个个体被评价,计算出适应度,两个个体交配,然后突变,产生下一代,直到终止条件满足为止。一般终止条件有以下几种:1)进化次数限制;2)计算耗费的资源限制,如计算时间、计算占用的CPU,内存等;3)个体已经满足最优值的条件,即最优值已经找到;4)当适应度已经达到饱和,继续进化不会产生适应度更好的个体;5)人为干预。

算法案例:

题目:设fx=(x1-5)^2 + (x2-55)^2 +(x3-555)^2 +(x4-5555)^2 +(x5-55555)^2,计算fx的最小值,其中x1,x2,x3,x4,x5为5个不同的变量。从直观上看,如果想得到fx的最小值,其实x1=5,x2=55,x3=555,x4=5555,x5=55555时,fx=0为最小值。如果使用穷举法,通过循环的方法找到这5个变量,估计会很费时的,我就不做测试了。下面我们看一下遗传算法的运行情况。

这里写图片描述
参数说明:

popsize,个体数量,即染色体数目
chsize,基因数量,限参数的数量
crossprob,交配概率,默认为1.0
mutateprob,突变概率,默认为0.01
elitism,精英数量,直接复制到下一代的染色体数目,默认为1
minval,随机生成初始种群的下边界值
maxval,随机生成初始种群的上边界值
maxiter,繁殖次数,即循环次数,默认为10
evalFunc,适应度函数,用于给个体进行评价
结论:
我们得到的最优化的结果:

x1=5.000317, x2=54.997099, x3=554.999873, x4=5555.003120, x5=55554.218695和我们预期的结果非常接近,而且耗时只有0.6秒。这个结果是非常令人满意地,不是么!如果按照单线程思想,使用穷举法去解决问题,时间复杂度将会达到O(n^5),估计没有5分钟肯定算不出来。

四. 计划打算

 对R语言的graphics,即画图功能进行学习和掌握,细致了解绘图函数和各种类型的绘图方法,最终能够使用R软件完成一些简单的绘图任务。
0 0
原创粉丝点击