矩阵和数组都是特殊的向量,矩阵是特殊的数组。
1.矩阵
矩阵与向量的区别在于:矩阵是有行、列这两个维度。矩阵和向量一样,有模式的概念(矩阵中的元素必须是同一类型的数据)
1.1 创建矩阵
矩阵的下标都是从1开始的,R默认按列存储数据。
创建方法:
####1.创建矩阵的方法
> A<-matrix(1:16,4,4);A
[,1] [,2] [,3] [,4]
[1,] 1 5 9 13
[2,] 2 6 10 14
[3,] 3 7 11 15
[4,] 4 8 12 16
> y<-matrix(c(1,2,3,4),nrow = 2,ncol = 2)
> y
[,1] [,2]
[1,] 1 3
[2,] 2 4
> B<-matrix(1:16,4,4,byrow = TRUE);B#####按行生成矩阵
[,1] [,2] [,3] [,4]
[1,] 1 2 3 4
[2,] 5 6 7 8
[3,] 9 10 11 12
[4,] 13 14 15 16
> A<-matrix(1:16,2);A
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 1 3 5 7 9 11 13 15
[2,] 2 4 6 8 10 12 14 16
###2.先声明y是矩阵,然后为其赋值
> y<-matrix(nrow = 2,ncol = 2)
> y[1,1]<-1
> y[1,2]<-2
> y[2,1]<-3
> y[2,2]<-4
> y
[,1] [,2]
[1,] 1 2
[2,] 3 4
####3.通过设置维数来创建矩阵
x<-1:20
dim(x)<-c(4,5);x
1.2 矩阵的运算(重点)
1.2.1 线性代数运算
包括矩阵乘法、数乘、加法、减法、求逆等
colSums(A)###求列的所有元素之和
rowSums(A)
colMeans(A)
A * B ######矩阵的内积,对应位置相乘
A %*% B ######矩阵的外积(矩阵的乘法)
diag(A) ###求对角线元素
t(A) ###转置
##求解线性方程组AX=b
a<-matrix(c(1:8,10),3,3,byrow = TRUE)
b<-rep(1,3)
round(solve(a,b),2)
##求逆
round(solve(a),2)
A<-solve(a)
A%*%b
1.2.2 矩阵的索引
x<-1:20
dim(x)<-c(4,5);x ###创建矩阵
x[1,2]###矩阵的一行2列
x[1,c(2,3,4)]
x[c(1,2),c(2,3,4)]
####对矩阵的子阵进行赋值
> x[c(1,3),]<-matrix(1:10,nrow = 2)
> x
[,1] [,2] [,3] [,4] [,5]
[1,] 1 3 5 7 9
[2,] 2 6 10 14 18
[3,] 2 4 6 8 10
[4,] 4 8 12 16 20
####删除某列
> x[,-5]
[,1] [,2] [,3] [,4]
[1,] 1 3 5 7
[2,] 2 6 10 14
[3,] 2 4 6 8
[4,] 4 8 12 16
1.2.3一个例子:图像操作
图像文件本质上是矩阵,像素点是按照行和列进行排列的。一张灰度图像会把一个像素点的亮度存储为矩阵的一个元素。如:图像中位于第3行,第5列的像素点的灰度值就存储在矩阵的第三行、第五列。
1.2.4 矩阵元素筛选
> x[x[,2]>6,]###筛选矩阵的第二列大于6的元素所在的
[,1] [,2] [,3] [,4] [,5]
[1,] 3 7 11 15 19
[2,] 4 8 12 16 20
> z<-c(5,12,13,13)
> x[z %% 2 == 1,]####筛选矩阵x中满足z的元素为奇数的条件的行
[,1] [,2] [,3] [,4] [,5]
[1,] 1 5 9 13 17
[2,] 3 7 11 15 19
[3,] 4 8 12 16 20
它的逻辑是:先判断z %% 2 == 1,结果是(T,F,T,T), 然后再用(T,F,T,T)判断矩阵x为T的行
1.2.5 生成协方差阵(row() 、col())
row() 、col()的参数是矩阵,row() 返回行号,col()返回列号
####生成协方差阵
makecov<-function(rho,n){
m<-matrix(nrow = n,ncol=n)
m<-ifelse(row(m) == col(m),1,rho)
return(m)
}
1.3 对矩阵的行和列调用函数
1.3.1 apply()函数
apply(m,dimcode,function,fargs)
m ##是一个矩阵
dimcode ##维度编号,取为1表示对每一行应用函数,取为2表示对列应用函数。
function ###应用在行和列上的函数
fargs ###可选参数集
> z<-matrix(1:6,nrow = 3,ncol=2)
> apply(z,2,mean)
[1] 2 5
> z
[,1] [,2]
[1,] 1 4
[2,] 2 5
[3,] 3 6
> f<-function(x){
+ x/c(2,8)
+ }
> apply(z, 1, f)##apply()默认输出的第一列是其操作对象的第一行
[,1] [,2] [,3]
[1,] 0.5 1.000 1.50
[2,] 0.5 0.625 0.75
> t(apply(z, 1, f))
[,1] [,2]
[1,] 0.5 0.500
[2,] 1.0 0.625
[3,] 1.5 0.750
在用apply()时,待调用函数至少需要一个参数。如果待调用函数有多个参数,用apply()调用这类函数时,需要把额外的参数列举到函数名字后面,用逗号隔开。
例子1:如果有一个矩阵是由0,1组成,想要生成如下向量:矩阵的每行的1如果较多,那么向量的元素取为1;反之,取为0.
copymaj<-function(rw,d){
d<-length(rw)
maj<-sum(rw[1:d])/d
if(maj >= 1/2){
rate<-1
}else{
rate<-0
}
return(rate)
}
x<-matrix(nrow = 4,ncol = 5)
x[1,]<-c(1,0,1,1,0)
x[2,]<-c(0,1,1,0,1)
x[3,]<-c(1,0,1,1,1)
x[4,]<-c(0,1,0,0,1)
apply(x,1,copymaj)
apply(x,1,copymaj,4)####4表示取矩阵每行的前4个元素,即d的取值。
例子2:寻找异常值
###异常值是距离大多数观测值很远的少数点。
如:找离中位数差别最大的值。
findols<-function(x){
findol<-function(xr){
mdn<-median(xr)
devs<-abs(xr-mdn)
return(which.max(devs))
}
return(apply(x,1,findol))
}
x<-matrix(nrow = 4,ncol = 4)
x[1,]<-c(5,7,8,20)
x[2,]<-c(1,12,3,4)
x[3,]<-c(4,5,56,3)
x[4,]<-c(7,6,9,0)
findols(x)
[1] 4 2 3 4
1.4 增删矩阵的行和列
rbind() ##按行组合
cbind() ##按列组合
> x<-c(1,2,3,4)
> y<-c(4,5,6,7)
> z<-cbind(x,y) ###按列组合
> z
x y
[1,] 1 4
[2,] 2 5
[3,] 3 6
[4,] 4 7
> z<-rbind(x,y) ###按行组合
> z
[,1] [,2] [,3] [,4]
x 1 2 3 4
y 4 5 6 7
例子1:找到图中距离最近的一对端点
如:计算城市之间的距离
x<-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)
dim(x)<-c(5,5)
###寻找行向量的最小元素及所在索引
imin<-function(z){
m<-length(z) ##向量Z的长度
i<-z[m] ##向量Z的最后一个元素赋值给i
j<-which.min(z[(i+1):(m-1)]) ##倒着遍历向量z,寻找最小值所在索引(超出向量下标的元素为NA)
k<-i+j
return(c(k,z[k]))
}
mind<-function(x){
n<-nrow(x) ###返回矩阵x的行数
dd<-cbind(x,1:n) ###将x的行号与矩阵x组合
wmins<-apply(dd[-n,],1,imin) ###寻找每行最小值和对应的索引(矩阵的列号)
i<-which.min(wmins[2,]) ###在每行最小值中,找到最终的最小值的索引(矩阵的行号)
j<-wmins[1,i] ###提取最终最小值的列号
return(c(x[i,j],i,j)) ###返回最小值及对应的行号、列号
}
mind(x)
1.5 避免意外降维
> x<-matrix(1:16,4,4)
> x[2,] ##提取矩阵x的第二行向量,结果是向量
[1] 2 6 10 14
> attributes(x) ###提取矩阵x的维度
$dim
[1] 4 4
> attributes(x[2,])
NULL
> str(x) ##矩阵x的行索引区间是1:4,列1:4
int [1:4, 1:4] 1 2 3 4 5 6 7 8 9 10 ...
> str(x[2,]) ###而矩阵第二行向量的索引区间是1:4
int [1:4] 2 6 10 14
也就是说,从矩阵中提取子矩阵时,如果子矩阵只有一行,R会将其当成向量来处理。这会导致程序不通过。
在R中,可以用drop参数来避免矩阵自动减少维度。
> r<-x[2,,drop=FALSE]
> r
[,1] [,2] [,3] [,4]
[1,] 2 6 10 14
> attributes(r)
$dim
[1] 1 4
as.matrix()函数将向量转化为矩阵
> u<-1:3
> attributes(u)
NULL
> v<-as.matrix(u)
> v
[,1]
[1,] 1
[2,] 2
[3,] 3
> attributes(v)
$dim
[1] 3 1
矩阵行、列的命名
> colnames(v)<-c("A")
> v
A
[1,] 1
[2,] 2
[3,] 3
> rownames(v)<-c("A","B","C")
> v
A
A 1
B 2
C 3
2.数组
在R中,一般矩阵的行用来表示样本(不同的观测),列表示变量。所以矩阵式二维数组。但是如果样本来自不同的时间,那么时间就是第三个维度。那么此时的数据是三维数组。
数组的创建
y<-1:20
dim(y)<-c(2,2,5);y ######3维数组
dim1<-c("A1","A2")
dim2<-c("B1","B2","B3")
dim3<-c("C1","C2","C3","c4")
z<-array(1:24,c(2,3,4),dimnames=list(dim1,dim2,dim3))
###将firsttest和sencondtest合并到一个数据结构中,firsttest在第一层,sencondtest在第二层。dim=c(3,2,2)表明数据共有2层,每层的数据是3行2列。那么,此时tests的每个元素都有三个下标。
> firsttest<-c(46,21,50,30,25,50)
> dim(firsttest)<-c(3,2)
> firsttest
[,1] [,2]
[1,] 46 30
[2,] 21 25
[3,] 50 50
> sencondtest<-c(46,41,50,43,35,50)
> dim(sencondtest)<-c(3,2)
> sencondtest
[,1] [,2]
[1,] 46 43
[2,] 41 35
[3,] 50 50
> tests<-array(data=c(firsttest,sencondtest),dim=c(3,2,2))
> tests
, , 1
[,1] [,2]
[1,] 46 30
[2,] 21 25
[3,] 50 50
, , 2
[,1] [,2]
[1,] 46 43
[2,] 41 35
[3,] 50 50
> tests[3,2,1] ##3行2列1部分的元素
[1] 50
当然,我们也可以将两个或者三个数组组成4维数组,以此类推。
数组最常用的场合是表的计算。