learning R

初学R

R语言的定位是统计分析、绘图,刚好缺一门这样趁手的语言,当然了Python也是可以的,这里就不对两个语言作比较了:)

安装

根据自己的操作系统到R官网可以找到安装文档对于windows有安装包,对于linux来说直接使用系统的包管理工具进行r的安装就可以啦

运行

在这一点上和python有点相似,R既可以交互式执行也可以执行脚本,在shell当中执行R就可以进入交互式语言环境,注意大写的R

划重点

R的数组的下标是从1而不是从0开始的!这一点需要注意,我猜可能是为了方便各种科研人员使用和理解吧

R的基础数据结构

向量

R因为会涉及到很多的矩阵运算、向量运算、表的连接之类的操作,所以R当中的基础类型包含了向量,并且支持加减乘除等基本操作,在R中使用c()来进行向量的创建,如下:

1
2
3
4
5
6
7
> v <- c(T,F,NA,TRUE)
> v
[1] TRUE FALSE NA TRUE
> v <- c(4,7,23,5,76.2,80)
> x <- sqrt(v)
> x
[1] 2.000000 2.645751 4.795832 2.236068 8.729261 8.944272

所以你看R简直就是为了线代而生的!也怪不得学统计学以及数学专业的同学大学期间会有R的相关课程啦

因子

因子提供了一种简单而又紧凑的形式来处理分类数据。因子用水平(level)来标示所有可能的取值,如果数据集有取值个数固定的名义变量,因子就会特别有用,下面接着贴代码:

1
2
3
4
5
> g <- c("f","m","m","m","f","m","f","m","f","f")
> g <- factor(g) #这里使用factor来将向量转化为一个因子
> g # 对其进行输出我们可以看到在原有向量的基础上多了一个Levels的属性
[1] f m m m f m f m f f
Levels: f m

需要说明的是在R的底层实现中对于因子的存储实际上是数据类型1,2而在使用和展示的时候会进行相应的转化,这里对用户来说是完全透明的,因为int类型不管是运算还是比较其速度都是比其他类型要快的

还是考虑向量转因子这个操作,如果说这个向量当中只有一个维度,但是我想要创建一个两个维度的怎么办?这个时候只要在factor当中传入第二个参数就可以了,如下:

1
2
3
4
5
6
7
8
> other.g <- factor(c("m","m","m","m","m"))
> other.g
[1] m m m m m
Levels: m #我们不加参数创建出来的因子只有一个Level
> other.g <- factor(c("m","m","m","m","m"),levels = c("f","m"))
> other.g
[1] m m m m m
Levels: f m #我们加上levels参数,这就ok了

利用因子类型数据,我们可以做的事情之一就是计算每个可能值的发生次数,例如

1
2
3
4
5
6
7
8
> table(g)
g
f m
5 5
> table(other.g)
other.g
f m
0 5

table还可以用来获取多个因子的交叉表,假设我们还有一个向量a存储了10个人所属的年龄,那么我们可以得到两个向量的交叉表:

1
2
3
4
5
6
7
8
9
10
11
> a <- factor(c('adult','adult','juvenile','juvenile','adult','adult','adult','juvenile','adult','juvenile'))
> table(g,a)
a
g adult juvenile
f 4 1
m 2 3
> table(a,g)
g
a f m
adult 4 2
juvenile 1 3

我们使用table将两个因子进行运算结果为一个交叉表,这个交叉表可以理解为根据两个向量进行了一次统计,在例子中就是对于1~10的元素,既是adult又是f的有4个,既是adult又是m的有2个,以此类推,所以table(a,g)和table(g,a)的区别仅仅是做了一次rotation,这个需要好好理解一下哈。

相应的R还提供了对于table交叉表结果的运算支持,例如我们想要获得列连表的边际和相对频率,使用margin.table参数第一个为表,第二个参数为想要查询的维度:

1
2
3
4
5
6
7
8
9
> t <- table(a,g)
> margin.table(t,1)
a
adult juvenile
6 4
> margin.table(t,2)
g
f m
5 5

同时还能计算相对频率

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
> prop.table(t,1)
g
a f m
adult 0.6666667 0.3333333
juvenile 0.2500000 0.7500000
> prop.table(t,2)
g
a f m
adult 0.8 0.4
juvenile 0.2 0.6
> prop.table(t)
g
a f m
adult 0.4 0.2
juvenile 0.1 0.3

Tips

在python当中可以使用dir查看当前已经创建的变量&对象,在R当中同样有objects()来查看已经创建的对象,也可以使用ls(),并且使用rm进行删除来释放内存

1
2
> objects()
[1] "a" "b" "g" "other.g" "t" "v" "x"

生成序列

由于向量在R中为基础数据类型,因此其在生成序列的时候也提供了多种方法,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
> x <- 1:10 # 表示从1到10的向量
> x
[1] 1 2 3 4 5 6 7 8 9 10
> 10:15 - 1 # 这里注意:的优先级比运算符要高
[1] 9 10 11 12 13 14
> 5:0 # 递减的数组
[1] 5 4 3 2 1 0
> seq(-4,1,0.5) # seq应该是sequence的缩写,根据给定的参数生成指定类型的数组
[1] -4.0 -3.5 -3.0 -2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0
> seq(form = 1,to = 5,legth = 4)
[1] 1 2 3 4 5
> seq(from = 1,to = 5,legth = 4)
[1] 1 2 3 4 5
Warning message:
In seq.default(from = 1, to = 5, legth = 4) :
extra argument ‘legth’ will be disregarded
> seq(from = 1,to = 5,length = 4)
[1] 1.000000 2.333333 3.666667 5.000000
> seq(from = 1,to = 5,length = 2)
[1] 1 5
> seq(length = 10,from = -2,by = 0.2)
[1] -2.0 -1.8 -1.6 -1.4 -1.2 -1.0 -0.8 -0.6 -0.4 -0.2
> rep(5,10) # repeat表示重复,可以对数组进行复制操作
[1] 5 5 5 5 5 5 5 5 5 5
> rep("hi",3)
[1] "hi" "hi" "hi"
> rep(1:2,3)
[1] 1 2 1 2 1 2
> rep(1:2,each = 3)
[1] 1 1 1 2 2 2

相应的还有生成因子序列的函数gl,第一个参数表示因子的个数,第二个参数表示重复次数,可以跟第三个参数跟因子的种类

1
2
3
4
5
6
7
8
> gl(3,5)
[1] 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3
Levels: 1 2 3
> gl(2,5,labels = c("female","male"))
[1] female female female female female male male male male male
Levels: female male
> gl(2,5,labels = c("female","male","t"))
[1] female female female female female male male male male male

同时R还提供了各种随机函数形式为rfunc(n,part1,part2…)例如:

1
2
3
4
5
6
7
> rnorm(10) #生成10个服从均值为0标准差为1的正态分布的随机数值
[1] -1.27810332 -0.34985527 0.91900558 -0.39174789 -0.09393429 0.60651344
[7] 0.51054821 0.55335663 0.25080796 0.40683237
> rnorm(4,mean = 10,sd = 3)# 生成4个均值为0 标准差为3的正态分布的随机数值
[1] 10.963400 6.480760 13.697037 8.714443
> rt(5,df = 10) #生成5个服从自由度为10的t分布的随机数值
[1] 0.06394753 0.46390402 0.49374847 -0.19909417 -1.04752838

数据子集

这一节主要讲R对于向量的各种索引操作,十分妖娆,包括普通的逻辑运算以及R特有的使用向量索引向量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
> x <- c(0,-3,4,-1,45,90,-5)# 这里我们生成一个向量赋值给x
> x > 0 # 向量与数字进行逻辑运算生成一个包含每个元素与数字进行逻辑运算结果的向量
[1] FALSE FALSE TRUE FALSE TRUE TRUE FALSE
> x[x>0] # 最妖娆的地方在这里,使用上述结果的逻辑值向量进行索引,我们获取到了该逻辑值为true的位置的向量
[1] 4 45 90
> x[c(4,6)] # 使用下标直接进行索引
[1] -1 90
> x[c(4,TRUE,6,T)]
[1] -1 0 90 0
> x[-1] # R中可以使用负数下标索引表示排除该位置的元素
[1] -3 4 -1 45 90 -5
> x
[1] 0 -3 4 -1 45 90 -5
> x[-c(4,6)]
[1] 0 -3 4 45 -5
> x[-(1:3)]
[1] -1 45 90 -5
> x
[1] 0 -3 4 -1 45 90 -5
> pH <- c(4.5,7,7.3,8.2,6.3) # 下面这段有点类似于字典数据类型了,给向量的值增加上key
> names(pH) <- c("area1","area2","mud","dam","middle")
> pH
area1 area2 mud dam middle
4.5 7.0 7.3 8.2 6.3
> pH['area1']
area1
4.5
> pH <- c(area1 = 4.5,area2 = 7,mud = 7.3,dam = 8.2,middle = 6.3) # 对于从开始就知道key对应关系的可以这样来进行创建
> pH
area1 area2 mud dam middle
4.5 7.0 7.3 8.2 6.3
> pH['area1']
area1
4.5

给向量复制两种方法的比较vec <- 0和vec <- 0

1
2
3
4
5
6
7
8
9
10
> x <- 1:5
> x
[1] 1 2 3 4 5
> x <- 0
> x
[1] 0
> x <- 1:5
> x[] <- 0
> x
[1] 0 0 0 0 0

矩阵和数组

在R当中矩阵和数组都是带有维度这个属性的向量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
> m <- c(45,23,66,77,33,44,56,12,78,23)
> m
[1] 45 23 66 77 33 44 56 12 78 23
> dim(m) <- c(2,5)
> m
[,1] [,2] [,3] [,4] [,5]
[1,] 45 66 33 56 78
[2,] 23 77 44 12 23
> m <- matrix(c(45 ,23 ,66, 77, 33, 44, 56, 12, 78, 23),2,5)
> m
[,1] [,2] [,3] [,4] [,5]
[1,] 45 66 33 56 78
[2,] 23 77 44 12 23
> m <- matrix(c(45 ,23 ,66, 77, 33, 44, 56, 12, 78, 23),2,5,byrow = T)
> m
[,1] [,2] [,3] [,4] [,5]
[1,] 45 23 66 77 33
[2,] 44 56 12 78 23

在矩阵运算中有rbing以及cbind两个用以将两个或两个以上的向量或者矩阵合并到一起的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
> m1 <- matrix(c(45,23,66,77,33,44,56,12,78,23),2,5)
> m1
[,1] [,2] [,3] [,4] [,5]
[1,] 45 66 33 56 78
[2,] 23 77 44 12 23
> cbind(c(4,76),m1[,4])
[,1] [,2]
[1,] 4 56
[2,] 76 12
> m2 <- matrix(rep(10,20),4,5)
> m2
[,1] [,2] [,3] [,4] [,5]
[1,] 10 10 10 10 10
[2,] 10 10 10 10 10
[3,] 10 10 10 10 10
[4,] 10 10 10 10 10
> m3 <- rbind(m1[1,],m2[3,])
> m3
[,1] [,2] [,3] [,4] [,5]
[1,] 45 66 33 56 78
[2,] 10 10 10 10 10

R还支持给矩阵的行、列命名

1
2
3
4
5
6
7
8
9
10
11
12
13
> results <- matrix(c(10,30,40,50,43,56,21,30),2,4,byrow = T)
> colnames(results) <- c('1qrt','2qrt','3qrt','4qrt')
> rownames(results) <- c('store1','store2')
> results
1qrt 2qrt 3qrt 4qrt
store1 10 30 40 50
store2 43 56 21 30
> results['store1',]
1qrt 2qrt 3qrt 4qrt
10 30 40 50
> results['store2',c('1qrt','4qrt')]
1qrt 4qrt
43 30

在R中数组是matrix的拓展,支持两个以上的维度因此需要两个维度以上的索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
> a <- array(1:24,dim = c(4,3,2))
> a
, , 1
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
, , 2
[,1] [,2] [,3]
[1,] 13 17 21
[2,] 14 18 22
[3,] 15 19 23
[4,] 16 20 24
> a[1,3,2]
[1] 21
> a[1,,2]
[1] 13 17 21
> a[4,3] # 最后一维度的索引可以空,但是逗号不能省
Error in a[4, 3] : incorrect number of dimensions
> a[4,3,]
[1] 12 24
> a[c(2,3),,-2]
[,1] [,2] [,3]
[1,] 2 6 10
[2,] 3 7 11

列表

R当中的列表是以其他对象为成分的有序集合,她和向量不同他的元素不一定是同一种数据类型、模式、或者是相同长度,列表的成分总是标号并且有一个名称属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
> my.lst <- list(stud.id = 34453,stud.name = "John",stud.marks = c(14.3,12,15,19))
> my.lst
$stud.id
[1] 34453
$stud.name
[1] "John"
$stud.marks
[1] 14.3 12.0 15.0 19.0
> my.lst[[1]]
[1] 34453
> my.lst[[3]]
[1] 14.3 12.0 15.0 19.0
> my.lst[1]
$stud.id
[1] 34453
> mode(my.lst[1])# 我们可以理解stud.id是列表的第一个元素
[1] "list"
> mode(my.lst[[1]]) # 34453是列表的第一个元素的第一个元素
[1] "numeric"
> my.lst$stud.id #可以通过这种方式来取值
[1] 34453
> names(my.lst) # 有点类似于字典
[1] "stud.id" "stud.name" "stud.marks"
> length(my.lst)
[1] 3
> other <- list(age = 19,sex = 'male')
> other
$age
[1] 19
$sex
[1] "male"
> lst <- c(my.lst,other) #合并列表
> lst
$stud.id
[1] 34453
$stud.name
[1] "John"
$stud.marks
[1] 14.3 12.0 15.0 19.0
$age
[1] 19
$sex
[1] "male"
> unlist(my.lst) #使用unlist将list转化为向量元素
stud.id stud.name stud.marks1 stud.marks2 stud.marks3 stud.marks4
"34453" "John" "14.3" "12" "15" "19"

dataset

dataset同样是R中一种基本的数据结构,它的结构与二维矩阵类似,然而不同的是,dataset的每列可以有不同的数据类型的数据,在这个意义上,数据框和列表更相似,实际上在R当中dataset是一种特殊的列表。

可以把数据框的每一行行为作为一个观测值(或称为个案),他有一组变量来表述。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
> my.dataset <- data.frame(site = c('A','B','A','A','B'),season = c('Winter','Summer','Summer','Spring','Fall'),pH = c(7.4,6.3,8.6,7.2,8.9))
> my.dataset
site season pH
1 A Winter 7.4
2 B Summer 6.3
3 A Summer 8.6
4 A Spring 7.2
5 B Fall 8.9
> my.dataset[3,2] # 因为第二列season是string因此在R中被转换为了因子数据类型,类似的site也是
[1] Summer
Levels: Fall Spring Summer Winter
> my.dataset$pH
[1] 7.4 6.3 8.6 7.2 8.9
> my.dataset[my.dataset$pH > 7,]
site season pH
1 A Winter 7.4
3 A Summer 8.6
4 A Spring 7.2
5 B Fall 8.9
> my.dataset[my.dataset$season == 'Summer',]# 这里表示匹配season为summer的所有的数据
site season pH
2 B Summer 6.3
3 A Summer 8.6
> my.dataset[my.dataset$season == 'Summer']# 但是在这里由于没有逗号表示这是一个一维的查找会先将dataset的season这一个维度做一个逻辑运算最终结果为FALSE TRUE TRUE FALSE FALSE,所以你看第一列就丢掉了
season pH
1 Winter 7.4
2 Summer 6.3
3 Summer 8.6
4 Spring 7.2
5 Fall 8.9
> my.dataset[my.dataset$season == 'Summer',c('site','pH')]
site pH
2 B 6.3
3 A 8.6

可以把attach函数应用到dataset上,attach可以直接访问dataset的列而无需添加相应的数据列名称

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
> attach(my.dataset)
The following object is masked _by_ .GlobalEnv:
pH
> my.dataset[site=='B',]
site season pH
2 B Summer 6.3
5 B Fall 8.9
> my.dataset[site=='B']
Error in `[.data.frame`(my.dataset, site == "B") :
undefined columns selected
> season #感觉attach把my.dataset应用到了整个命名空间一样
[1] Winter Summer Summer Spring Fall
Levels: Fall Spring Summer Winter
> detach(my.dataset)
> season
Error: object 'season' not found
> subset(my.dataset,pH > 8)
site season pH
3 A Summer 8.6
5 B Fall 8.9
> subset(my.dataset,season == 'Summer',season:pH)
season pH
2 Summer 6.3
3 Summer 8.6
> season:pH
> my.dataset[my.dataset$season=='Summer','pH'] <- my.dataset[my.dataset$season=='Summer','pH'] + 1 # 对于某些数据进行运算操作
> my.dataset
site season pH
1 A Winter 7.4
2 B Summer 7.3
3 A Summer 9.6
4 A Spring 7.2
5 B Fall 8.9
> my.dataset$NO3 <- c(234.5,256.6,654.1,356.7,776.4) #增加新列
> my.dataset
site season pH NO3
1 A Winter 7.4 234.5
2 B Summer 7.3 256.6
3 A Summer 9.6 654.1
4 A Spring 7.2 356.7
5 B Fall 8.9 776.4

对于增加新列的唯一要求就是新列需要和原来的数据拥有同样的行数,我们可以用如下两个函数分别获得dataset的行数和列数

nrow/ncol

在数据挖掘任务重通常很少需要用到上面提到的data.frame来进行手动的输入数据,一般是把来源与文件或者数据库的数据读入dataset,因此建议浏览一下R的数据导入和导出手册

R还可以来编辑一个已存在的dataset、或者创建一个新的dataset

1
2
3
4
5
6
7
8
9
10
11
my.dataset <- edit(my.dataset) # 会直接进入vim的编辑模式以文本形式编辑my.dataset很方便!!!
> names(my.dataset)
[1] "site" "season" "pH" "NO3"
> names(my.dataset) <- c('area','season','pH','NO3')
> my.dataset
area season pH NO3
1 A Winter 7.4 234.5
2 B Summer 7.3 256.6
3 A Summer 9.6 654.1
4 A Spring 7.2 356.7
5 B Fall 8.9 776.4

我们可以通过执行data()来查看当前提供支持的数据结构通过调用data(USArrests)来创建一个叫做USArrests的dataset

自定义函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
> se <- function(x){
+ v <- var(x)
+ n <- length(x)
+ return (sqrt(v/n))
+ }
>
# 带有默认参数的函数
> basic.stats <- function(x,more = F){
+ stats <- list()
+ clean.x <- x[!is.na(x)]
+
+ stats$n <- length(x)
+ stats$nNAs <- stats$n - length(clean.x)
+
+ stats$mean <- mean(clean.x)
+ stats$std <- sd(clean.x)
+ stats$med <- median(clean.x)
+ if (more){
+ stats$skew <- sum(((clean.x-stats$mean)/stats$std)^3) / length(clean.x)
+ stats$kurt <- sum(((clean.x-stats$mean)/stats$std)^4) / length(clean.x) - 3
+ }
+ unlist(stats)
+ }
> basic.stats(c(45,2,4,46,43,65,NA,6,-213,-3,-45))
n nNAs mean std med
11.00000 1.00000 -5.00000 79.87768 5.00000
# 喜闻乐见的for循环
> f <- function(x){
+ for (i in 1:10){
+ res <- x*i
+ cat(x,'*',i,'=',res,'\n')
+ }
+ }
> f(4)
4 * 1 = 4
4 * 2 = 8
4 * 3 = 12
4 * 4 = 16
4 * 5 = 20
4 * 6 = 24
4 * 7 = 28
4 * 8 = 32
4 * 9 = 36
4 * 10 = 40

R的一些理念

R所有东西都是对象,并且支持继承之类的操作,并且其基础类型都会包含plot方法的支持用以对用户透明的绘制图形,这也是R的优点所在,其他的像面向对象啊之类这些都和其他语言是类似的不再赘述。

值得一提的是当退出R的交互模式的时候他会询问是否保存当前工作,如果选择是哪么就会在当前目录生成一个Rplots.pdf,好神奇有没有,这个文件是可以直接打开查看图形的!对于第一次接触R的我来说,讲真,真是太人性化了。

或者在R当中也可以自己手动执行保存操作。

save.image()

load(‘filename’)

棒呆!

hello http://just4fun.im/2018/03/31/learning R/ bye