R-数据结构-矩阵和数组

矩阵和数组都是特殊的向量,矩阵是特殊的数组。

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维数组,以此类推。
数组最常用的场合是表的计算。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值