前言
机器学习,深度学习必备知识。不懂简直懵逼,这里列举了常用的以自己复习和入门。
安装
pip安装
pip install numpy
anaconda
傻瓜安装自带numpy
https://www.anaconda.com/download/#macos
自行选择。(备注:python将于2020年停止python 2的更新,建议选择学习py3)
由来
numpy的诞生就是为了更好做矩阵和数组的相关计算。“更好” 就说明python 的List 可能不是太好。
python LIst的特点
python List支持表达式生成列表(这也是python的建议方式)
L=[i for i in range(10)]
print(L)
python的列表是支持多类型元素的,这与C语言和 Java不同。在C语言和Java的数组中只允许一种类型的元素。而python允许不同类型的元素存在一个数组中。
这可以说是一个优点也可以是一个缺点。这增大了python 数组的多样性,但是在遍历的时候就会出大问题。python的团队不是傻子,就创造了另外一个array的包。只需要impory array即可使用。
import array
arr=array.array('i',[i for i in range(10)]) #指定了数组的类型“i”为整型
arr
输出
array('i', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
不要看这个数组长的奇怪,它与我们普通数组一样访问,一样遍历。
arr[5]
out: 5
但是现在就不能改变这个数组的类型了。
arr[7]=‘d’
----------------------------------------
TypeErrorTraceback (most recent call last)
in ()
----> 1 arr[7]='d'
TypeError: an integer is required (got type str)
这样真是好不容易解决了冲突问题,但是实用性还是很差,学过线性代数的都知道矩阵有很多计算,然而这个array并没有提供很多。于是一个重量级的numpy.array闪亮登场。
numpy登场
numpy是一个非常强大的包,因为强大里面的东西也很多,很难记忆。这里简单分了个累把常用的列举出来。
初见
numpy自带类型转换。
跟array包里面一样,生成一个numpy的array只需要调用numpy.array即可。
import numpy as np
nparr=np.array([i for i in range(10)])
nparr
out: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
可以查看一下nparr的类型
nparr.dtype
out: dtype('int64')
可以看出这是一个整型的数组。说明numpy自动帮我们识别了元素的类型。
再试试
nparr2=np.array([1,2,3.0])
nparr2.dtype
dtype('float64')
numpy自动识别了数组中有float型的,于是由变量的隐式转换规则,把整个数组变成了float数组。是不是很酷。
容错性
如果我们是一个整数数组,改变其中的元素为其他类型会怎么样呢?
import numpy as np
nparr=np.array([i for i in range(10)])
nparr
out: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
nparr[5]='3'
nparr
out : array([0, 1, 2, 3, 4, 3, 6, 7, 8, 9])
我们发现它可以把字符类型的数字直接转换为int,这一切都是自动的。不需要手动的进行ch-'0'这种操作。
nparr[5]=3.4
nparr
out: array([0, 1, 2, 3, 4, 3, 6, 7, 8, 9])
numpy自动完成了float->int的强制转换(就是把小数截断了)。
其实这所做的一切都是为了保证一个array中只有一个类型,跟array.array一样的。如果我们把其中一个元素变成一个字符串,就会报错。
nparr[5]='dd'
nparr
----------------------------------------
ValueErrorTraceback (most recent call last)
in ()
----> 1 nparr[5]='dd'
2 nparr
ValueError: invalid literal for int() with base 10: 'dd'
numpy.array的各种初始化
全0
np.zero
#zeros(shape, dtype=float, order='C')
#Return a new array of given shape and type, filled with zeros.
由文档可以看出zeros有三个参数shape 就是形状。dtype是类型可选参数,默认为float类型,order是一个可选参数,一般不用管它。‘C’的意思就是按照行优先。
np.zeros(10)
array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
最简单的创造全0数组的方式,只需要指定形状就可以了。类型和排列方式都系统自定了。
注意这里默认是float类型的。
如果要为别的类型需要强制指定。(备注:实际中大多数使用float型)
np.zeros(10,dtype=int)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
形状可以通过元祖或者列表直接指定。[行,列] 或者 (行,列)。
a=np.zeros(shape=(3,4),dtype='float')
a
array([[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.]])
单位阵(全1)
np.ones
跟全零是一个样的。不赘述了。
np.ones(shape=(2,3))
array([[ 1., 1., 1.],
[ 1., 1., 1.]])
填充阵(全‘X’)
要不就是全0 要不就是全1很没意思,那要指定填充物呢,也是可以的。
np.full(shape=(3,4),fill_value=666,dtype='float64')
array([[ 666., 666., 666., 666.],
[ 666., 666., 666., 666.],
[ 666., 666., 666., 666.]])
arange
arange可以指定起点、终点、步长进行数组的创建。
**注意 前包后不包 **
例如:
np.arange(0,20,step=2)
array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18])
前包后不包的意思就是包括起始的位置,终点不包括。步长是2.
当然步长可以是整数,也可以是小数。
linspace
这个直接指定开始、结束,然后个数进行创建。
注意 前包后也包
np.linspace(start=0,stop=20,num=10) #终点默认是包含的
array([ 0. , 2.22222222, 4.44444444, 6.66666667,
8.88888889, 11.11111111, 13.33333333, 15.55555556,
17.77777778, 20. ])
也可以让终点不包含
np.linspace(start=0,stop=20,num=10,endpoint=False)
array([ 0., 2., 4., 6., 8., 10., 12., 14., 16., 18.])
random
np.random是一个包,这个包里面有很多方法。
randint
产生随机数,范围是(low,high)
randint(low, high=None, size=None, dtype='l')
Return random integers from `low` (inclusive) to `high` (exclusive).
Return random integers from the "discrete uniform" distribution of
the specified dtype in the "half-open" interval [`low`, `high`). If
`high` is None (the default), then results are from [0, `low`).
这里说的是,high是可选参数,如果没有的话就产生(0,low)的随机数。如果有high的话就产生(low,high)的随机数。size是个数。dtype只能指定是int8,int16 还是int64 .(l就是int64)
我们知道随机数是通过随机种子计算出来的。
如果我们每次想产生想同的随机数只需要种下一样的种子就可以了。
np.random.seed(666)
random
这是random模块的一个函数random。产生0到1的随机数(不包含1)/
random_sample(size=None)
Return random floats in the half-open interval [0.0, 1.0).
np.random.random()
0.2811684913927954
np.random.random(10)
array([ 0.46284169, 0.23340091, 0.76706421, 0.81995656, 0.39747625,
0.31644109, 0.15551206, 0.73460987, 0.73159555, 0.8578588 ])
normal
这个比较重要,产生服从高斯分布的随机数,一般用户深度学习权重向量的初始化。
normal(loc=0.0, scale=1.0, size=None)
Draw random samples from a normal (Gaussian) distribution.
loc是均值。
scale是方差
np.random.normal(10,100,size=10)
array([ 92.1013692 , 46.7125916 , 175.39958581, 23.94647258,
-111.71535503, -89.49473667, -146.44858645, -152.87900441,
133.17486561, -81.36003361])
numpy.array的基本操作
查看属性
因为跟矩阵挂钩,查看属性也很有必要。np.array这个类提供两个基本属性查看。
import numpy as np
X=np.arange(15).reshape(3,5)
X
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
X.ndim #查看维度个数
2
X.shape #查看形状
(3, 5)
数据访问
numpy中的array跟python中的array访问是一样的。
可以通过下标的方式去访问X[1]
也可以X[1][1]这样去访问,但是不建议。直接X[1,1]就可以了。
这是普通的访问,当然也支持python的切片。
切片
切片其实很简单。
首先看一维的:
x=np.arange(10)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
x[0:5]
#产生一个前闭后闭的数组
array([0, 1, 2, 3, 4])
x[::2] #以2为步长对数组进行切分
array([0, 2, 4, 6, 8])
多维的也很简单,我们用逗号隔开每个维度,在每个维度上面会有不同的操作。
X[:2,:3]
array([[0, 1, 2],
[5, 6, 7]])
取子序列
这个用 切片就可以,
subX=X[:2,:3]
subX
array([[0, 1, 2],
[5, 6, 7]])
这是最简单的取子序列。但是numpy中为了效率 这个subX只是X 的引用。这意味着subX 中的值改变了。X的值也改变了。
subX[0,0]=100
X
array([[100, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[ 10, 11, 12, 13, 14]])
只需要使用array这个类带的copy()函数即可。
subX=X[:2,:3].copy()
改变形状
使用的是numpy中array类函数reshape
a.reshape(shape, order='C')
Returns an array containing the same data with a new shape.
意思就是返回一个值相同但是形状不一样的新数组。
x.reshape(2,5)
array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
这是我们知道形状,但是有时候知道一个维度的大小。另外一个维度,我们希望系统能够帮我们计算出来。这也是可以的。
x
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
x.reshape(2,-1)
array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
数组合并
预备
x=np.array([1,2,3])
y=np.array([3,2,1])
z=np.array([666,666,666])
array([666, 666, 666])
A = np.array([[1,2,3],[4,5,6]])
array([[1, 2, 3],
[4, 5, 6]])
concatenate
concatenate((a1, a2, ...), axis=0)
Join a sequence of arrays along an existing axis.
这个函数可以把数组拼接起来,默认是沿着第一个维度 (axis就是指定维度,0就是行)
np.concatenate([A,A])
array([[1, 2, 3],
[4, 5, 6],
[1, 2, 3],
[4, 5, 6]])
np.concatenate([A,A],axis=1)
array([[1, 2, 3, 1, 2, 3],
[4, 5, 6, 4, 5, 6]])
这个方法看起来很完善,行也可以列也可以,但是也存在一个很大的麻烦。
我们看
z=np.array([666,666,666])
array([666, 666, 666])
A = np.array([[1,2,3],[4,5,6]])
array([[1, 2, 3],
[4, 5, 6]])
这里直接
np.concatenate([A,z])
----------------------------------------
ValueErrorTraceback (most recent call last)
in ()
----> 1 np.concatenate([A,z])
ValueError: all the input arrays must have same number of dimensions
因为维度不一样,A是一个二维的矩阵,z是一个一维的向量。虽然看起来“列”都一样,但是不能想当然的去合并,那么我们只能把z变成一个二维的。
np.concatenate([A,z.reshape(1,-1)])
array([[ 1, 2, 3],
[ 4, 5, 6],
[666, 666, 666]])
如果遇到这种情况就很烦了,还要考虑维度,还要手动的进行升维。能不能再傻瓜一点呢?答案是ok的。
vstack
在垂直方向进行堆叠
np.vstack([A,z])
array([[ 1, 2, 3],
[ 4, 5, 6],
[666, 666, 666]])
这就很奇怪,为啥维度不一样还能进行堆叠?答案是很神奇。猜测就是只要水平维度相同就能堆叠。
B=np.full((2,2),100)
array([[100, 100],
[100, 100]])
np.hstack([A,B])
array([[ 1, 2, 3, 100, 100],
[ 4, 5, 6, 100, 100]])
分割
x=np.arange(10)
x
np.split
Signature: np.split(ary, indices_or_sections, axis=0)
Docstring:
Split an array into multiple sub-arrays.
这里说了这里的返回值是多个子数组。
>>> x = np.arange(9.0)
>>> np.split(x, 3)
[array([ 0., 1., 2.]), array([ 3., 4., 5.]), array([ 6., 7., 8.])]
这里也可以切分二维数组
vsplit
A=np.arange(16).reshape((4,4))
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
upper,lower=np.vsplit(A,[2])
upper
array([[0, 1, 2, 3],
[4, 5, 6, 7]])
lower
lower
lower
Out[81]:
array([[ 8, 9, 10, 11],
[12, 13, 14, 15]])
hsplit
left,right=np.hsplit(A,[2])
array([[ 0, 1],
[ 4, 5],
[ 8, 9],
[12, 13]])