现在是第三章,数组和矩阵,先列举本章的概述内容:
1.创建矩阵
2.矩阵运算
3.调用矩阵的行和列
4.增加或删除行和列
5.矩阵VS向量
6.案例1:生成协方差矩阵
7.案例2:寻找异常值
8.案例3:找到图中距离最近的一对端点
一、创建矩阵
使用matrix()函数创建矩阵,nrow指定行数,ncol指定列数
> y<-matrix(c(1,2,3,4),nrow=2,ncol=2)
> y
[,1] [,2]
[1,] 1 3
[2,] 2 4
二、矩阵运算
矩阵支持线性运算,可以两个矩阵相乘,也可以指定某个值乘以矩阵中每个元素
> y%*%y
[,1] [,2]
[1,] 7 15
[2,] 10 22
> 3*y
[,1] [,2]
[1,] 3 9
[2,] 6 12
三、调用矩阵的行和列
利用索引可以对矩阵进行操作,利用[ ]调用行或者列:
> y[,2]
[1] 3 4
> y[1,]
[1] 1 3
> y[c(1,2),]<-matrix(c(1,1,3,4),nrow=2)
> y
[,1] [,2]
[1,] 1 3
[2,] 1 4
四、增加或删除行和列
1、利用rbind()或者cbind()函数,给矩阵增加行或者列
> z<-matrix(c(1,2,3,4,1,1,0,0,1,0,1,0),nrow=4,ncol=3)
> z
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 2 1 0
[3,] 3 0 1
[4,] 4 0 0
> a<-c(1,1,1,1)
> z<-cbind(z,a)
> z
a
[1,] 1 1 1 1
[2,] 2 1 0 1
[3,] 3 0 1 1
[4,] 4 0 0 1
2.利用向量索引,删除矩阵的行或者列
> z
a a
[1,] 1 1 1 1 1
[2,] 2 1 0 1 1
[3,] 3 0 1 1 1
[4,] 4 0 0 1 1
> z<-z[,-1]
> z
a a
[1,] 1 1 1 1
[2,] 1 0 1 1
[3,] 0 1 1 1
[4,] 0 0 1 1
五、矩阵VS向量
矩阵就是一个向量,只是矩阵多了两个属性:行数和列数。用nrow和ncol定义矩阵行数和列数。
六、案例1:生成协方差矩阵
协方差矩阵概念:
协方差的定义上我们也可以看出一些显而易见的性质,如:
3.两个变量间的协方差就为两个变量间的相差系数
从协方差矩阵可以直观看出各个变量间相关关系,正相关、负相关还是无相关关系。
假设处理一个n元正态分布,它的协方差矩阵有n行n列,n个随机变量方差都为1,若n=3,每两个变量间的相关性rho=0.2时,如何用代码去生成矩阵呢?
因为n个随机变量方差都为1,所以对角线上的元素的都为1,每两个变量间的协方差均为0.2,基于这个前提去编程实现生成矩阵就简单多了,保证对角线元素是1,其余元素都是rho,这里可以利用矩阵索引去实现,如果行和列的索引值一样,对应的值就是1,反之就是rho,具体代码如下:
> makecov<-function(rho,n){
+ m<-matrix(nrow=n,ncol=n)
+ m<-ifelse(row(m)==col(m),1,rho)
+ return(m)
+ }
> makecov(0.2,3)
[,1] [,2] [,3]
[1,] 1.0 0.2 0.2
[2,] 0.2 1.0 0.2
[3,] 0.2 0.2 1.0
七、案例2:寻找异常值
所谓异常值,就是离群点,一堆数据中离大多数值最远的那些值。假如矩阵rs用来存储零售业销售数据,每行对应一家商店,一行里的观测值对应每天的销售数据,用非常简单的方法识别出每家商店数据中偏离最远的观测值,也就是与中位数差别最大的观测值(注意:这里是定义异常值是与中位数相差最大的值,实际统计学中对异常值定义是一组测定值中与平均值的偏差超过两倍标准差的测定值)
findols<-function(x){
findol<-function(xrow){
mdn<-median(xrow)
devs<-abs(xrow-mdn)
return(which.max(devs))
}
return(apply(x,1,findol))
}
八、案例3:找到图中距离最近的一对端点
假设第i行第j列代表城市i和城市j间的距离,通过设计一个函数,输入城市距离矩阵,输出城市间最短的距离,以及对应的两个城市。基于这个需求,完成函数设计:
#定义一个函数mind()
mind<-function(d){
n<-nrow(d)#n指向矩阵行数
dd<-cbind(d,1:n)#给矩阵增加最后一列,值全部为行数值
wmins<-apply(dd[-n,],1,imin)#去掉矩阵dd的最后一行,对矩阵的每一行,应用函数imin,最后会生成一个2行矩阵,第一行是最小值所在列,第二行就是最小值以及最小行
i<-which.min(wmins[2,])#从第二行值中找到最小那个对应的的下标,就是最小值所在行数
j<-wmins[1,i]#最小值所在行数下标,在第一行对应位置的值就是最小值所在列数
return(c(d[i,j],i,j))#返回最小值,最小值对应行数和列数
}
#定义函数imin()
imin<-function(x){#注意联系前面,一行一行的应用
lx<-length(x)#lx代表每一行包含元素的个数
i<-x[lx]#i指向这一行最后一个元素,也就是具体行数!
j<-which.min(x[(i+1):(lx-1)])#第一行从第二个元素开始遍历,到倒数第二个,返回最小值的下标,同理第二行从第三个开始
k<-i+j#行数+which返回的最小值下标=这一行最小值真正下标
return(c(k,x[k]))#生成向量,2个值,一个值是这一行最小值对应真正下标,另一个值就是这一行的最小值
}
因为这段代码比较复杂理解起来有点难度,为了帮助大家理解,我拿一个实例矩阵进行按步骤讲解,实际上我自己在理解的时候也是把每一步用实例矩阵还原,这样很容易就知道代码表达的具体意思,然后会惊叹,这段代码真的很牛!想法巧妙
> q<-matrix(c(0,12,13,8,20,12,0,15,28,88,13,15,0,6,9,8,28,6,0,33,20,88,9,33,0),nrow=5,ncol=5)
> q
[,1] [,2] [,3] [,4] [,5]
[1,] 0 12 13 8 20
[2,] 12 0 15 28 88
[3,] 13 15 0 6 9
[4,] 8 28 6 0 33
[5,] 20 88 9 33 0
> n<-nrow(q)
> n
[1] 5
> dd<-cbind(q,1:n)
> dd
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 0 12 13 8 20 1
[2,] 12 0 15 28 88 2
[3,] 13 15 0 6 9 3
[4,] 8 28 6 0 33 4
[5,] 20 88 9 33 0 5
> dd[-n,]
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 0 12 13 8 20 1
[2,] 12 0 15 28 88 2
[3,] 13 15 0 6 9 3
[4,] 8 28 6 0 33 4
给大家还原了mind()函数在应用imin()函数前的每一步,大家可以很直观看到,在应用imin()函数的时候,实际的矩阵已经从原本的矩阵q变成了上面的4行6列的矩阵,因为imin()函数是用在每一行的,所以首先,对第一行(0,12,13,8,20,1)应用函数,很明显第一行最小值是8,在第4列,那么imin()函数要实现这个目的
> x<-c(0,12,13,8,20,1)
> lx<-length(x)
> lx
[1] 6
> i<-x[lx]
> i
[1] 1
> j<-which.min(x[(i+1):(lx-1)])
> j
[1] 3
k<-i+j
> c(k,x[k])
[1] 4 8
这里可以直观看到,对第一行元素应用imin()函数,j值为3,因为x[(i+1):(lx-1)对应12 13 8 20,8刚好在第三个,所以返回j值是3,又因为i=1,刚好i+j=第一行实际值对应列所在位置,这里是巧妙运用i+j=实际位置
> wmins<-apply(dd[-n,],1,imin)
> wmins
[,1] [,2] [,3] [,4]
[1,] 4 3 4 5
[2,] 8 15 6 33
> mind(q)
[1] 6 3 4
其他3行同样思路,最终得到矩阵wmins如上所示,接下来从第二行值中找到最小那个对应的的下标,就是最小值所在行数,最小值在第3行,在第一行中对应的值就是最小值所在列数,由此锁定最小值所在行和列,也就锁定了最小值,思路就是这样,最终发现最小值为6,在第3行,第4列,大家好好体会下,会提升编程能力很有帮助。
好了,第三章的分享到此为此,写这章花了好久时间,终于坚持写完了,希望能对部分人理解R语言编程思想有帮助,辛苦也就值得了~~~下章再见!