机器学习系列(三)——Numpy数组与矩阵
Numpy.array基本操作
生成一个数组
import numpy as np
x=np.arange(10)
x
#out:array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
生成一个矩阵
y=np.arange(15).reshape(3,5)
y
#out:
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
基本属性
x.ndim
查看x数据维度out:1
x.shape
返回一个元组,查看具体大小out:(10,)
x.size
返回x中数据个数out:10
y.ndim
查看y数据维度out:2
y.shape
返回一个元组,查看具体大小out:(3,5)
y.size
返回y中数据个数out:15
array数据访问
方括号索引:x[2]
out:2
参数为负数表示倒着数:x[-1]
out9
若是矩阵只指定一个维度输出是行向量:
y[2]
out:array([10, 11, 12, 13, 14])
若访问第0行第2个元素:
y[0][2]
out:2
但是这种方式不建议。
//或
y[0,2]
out:2
这种方式是numpy提供的方式,可加圆括号(0,2)。
两个方括号在索引切片时存在问题。
切片:x[1:5]
out:array([1, 2, 3, 4])
不包含切片终端点元素。
x[:4]
#out:array([0, 1, 2, 3])
x[6:]
#out:array([6, 7, 8, 9])
第三个参数是切片步长:
x[ : : 2]
out:array([0, 2, 4, 6, 8])
x[ : : -1]
out:array([9, 8, 7, 6, 5, 4, 3, 2, 1, 0])
二维数组切片:
y[ : 2,: 3]
取前两行的前三列out:
array([[0, 1, 2]
,[5, 6, 7]])
但是用两个方括号的切片就会出错:
y[:2][:3]
#out:array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
因为首先解析切片y[:2],取了前两行,(y[:2])[:3]本意是取前三列,但是这里实际是取y[:2]的前三行。
组合切片
访问前两行从头到尾间隔为2元素:
y[ :2,: : 2]
#out:array([[0, 2, 4],
[5, 7, 9]])
行倒着数,列也倒着数:
y[ : : -1,: : -1]
#out:array([[14, 13, 12, 11, 10],
[ 9, 8, 7, 6, 5],
[ 4, 3, 2, 1, 0]])
y[0]等价于y[0,:]取行,取列则不行,建议使用numpy方式。
与python中切片的不同:
suby=y[:2,:3]
suby
#out:array([[0, 1, 2],
[5, 6, 7]])
suby[0,0]=100
suby
#out:array([[100, 1, 2],
[ 5, 6, 7]])
y
#out:array([[100, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[ 10, 11, 12, 13, 14]])
可以看到对切片后子矩阵的元素做修改,切片被修改后,原矩阵也被修改。而python中list的切片是创建了一个全新的矩阵,修改不影响原矩阵。因为numpy优先考虑效率,取子矩阵得到的是原矩阵的一个引用。
如果要创建与原矩阵不相关的子矩阵,要使用copy方法:
suby=y[:2,:3].copy()
suby
#out:array([[0, 1, 2],
[5, 6, 7]])
此时修改suby,y是没有被改变的。
reshape
reshape参数是元组,不过括号可以省略。这里x是有10个元素的一维向量。
x.reshape(2,5)
#out:array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
reshape不改变原数组或矩阵。
二维数组与一维数组区别:
x#一维数组
#out:array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
x.reshape(1,10)#二维数组
#out:array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])
我们可以让计算机帮助我们智能确定,比如:
x.reshape(2,-1)
#我只想要两行,至于每行几个元素我不关心
#out:array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
x.reshape(-1,2)
#我只想要两列,至于每列几个元素我不关心
#out:array([[0, 1],
[2, 3],
[4, 5],
[6, 7],
[8, 9]])
但是无论是自动确定还是指定reshape必须保证整除关系。
合并操作
对数组的合并
x=np.array([1,2,3])
y=np.array([4,5,6])
#让x与y合并,获得一个1×6向量
np.concatenate([x,y])
#out:array([1, 2, 3, 4, 5, 6])
z=np.array([6,6,6])
np.concatenate([x,y,z])#支持多个参数
#out:array([1, 2, 3, 4, 5, 6, 6, 6, 6])
也可以对矩阵进行合并
A=np.array([[1,2,3],[4,5,6]])
np.concatenate([A,A])#会按行进行拼接
#out:array([[1, 2, 3],
[4, 5, 6],
[1, 2, 3],
[4, 5, 6]])
可以理解为样本数量的增加。另一种是特征的增加:
A=np.array([[1,2,3],[4,5,6]])
np.concatenate([A,A],axis=1)
#out:array([[1, 2, 3, 1, 2, 3],
[4, 5, 6, 4, 5, 6]])
axis默认为0,意思是沿着第一维度行方向进行操作,为1,则沿着第二维度方向拼接。
向量与矩阵的拼接:
concatenate只能处理同维数的矩阵拼接,比如拼接z和A
np.concatenate([A,z])
会报错,当然可以将z整理形状后拼接:
np.concatenate([A,z.reshape(1,3)])
#out:array([[1, 2, 3],
[4, 5, 6],
[6, 6, 6]])
不过numpy中有更好的方法vstack和hstack:
np.vstack([A,z])
#out:array([[1, 2, 3],
[4, 5, 6],
[6, 6, 6]])
B=np.array([[1,2],[2,3]])
np.hstack([A,B])
#out:array([[1, 2, 3, 1, 2],
[4, 5, 6, 2, 3]])
水平堆叠和竖直堆叠虽然能智能处理,但传入的也必须合法,否则会报错。
分割操作
split传入待分割数组和分割点列表
x=np.arange(10)
x
#out:array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
np.split(x,[3,7])
#out:[array([0, 1, 2]), array([3, 4, 5, 6]), array([7, 8, 9])]
同样可以对矩阵进行分割,此时,axis默认为0,按行分割。
A=np.arange(16).reshape((4,4))
A
#out:array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
A1,A2=np.split(A,[2])#分为两个部分
A1
out:array([[0, 1, 2, 3],
[4, 5, 6, 7]])
A3,A4=np.split(A,[2],axis=1)#按列
A3
#out:array([[ 0, 1],
[ 4, 5],
[ 8, 9],
[12, 13]])
同样,对于分割,numpy也提供了更简单的方式vsplit和hsplit:
upper,lower=np.vsplit(A,[2])
upper
#out:array([[0, 1, 2, 3],
[4, 5, 6, 7]])
数据分割对机器学习数据处理非常重要,比如一般数据格式是特征和分类label,特征要参与计算,需要把特征和label分开。
data=np.arange(16).reshape((4,4))
x,y=np.hsplit(data,[-1])#x是4×3矩阵
y
#out:array([[ 3],
[ 7],
[11],
[15]])
y[:,0]#把提取到的label变成向量
out:array([ 3, 7, 11, 15])
实际处理矩阵数据时要随机应变。