Numpy的使用

目录

  • 1.创建数组
    • 1.1普通创建
    • 1.2创建含初始占位符的数组
  • 2.矢量化运算
    • 2.1矢量化
    • 2.2广播机制
  • 3.索引和切片
    • 3.1索引
    • 3.2切片
  • 4.数组运算
    • 4.1数组部分
    • 4.2 矩阵部分
  • 5.常用函数
  • 6.读写文件
    • 6.1loadtxt()
    • 6.2 savetxt()

1.创建数组

Numpy是在Python中涉及科学计算时肯定会用到的,该库提供多维数组。虽然python含有array数组,但是对于大量数据进行高级数学和其他类型的操作时,使用Numpy数组比使用array更加有效率,更加简单。为什么Numpy这么快,一个很重要的原因就是矢量化,用近C的速度去做一些运算。(摘自官方文档)

1.1普通创建

a=np.array([1,2,3])
b=np.array([(1,2,3),(4,5,6)],dtype='float64')
c=np.array([[1,2,3],[4,5,6]])
#注意下面第一种复数矩阵的创建结果中j全部为0
d=np.array([[1,2],[3,4]],dtype=complex)
e=np.array([1+2j,2+3j])

结果:

[1 2 3]

[[1. 2. 3.]
 [4. 5. 6.]]

[[1 2 3]
 [4 5 6]]

[[1.+0.j 2.+0.j]
 [3.+0.j 4.+0.j]]

[1.+2.j 2.+3.j]

1.2创建含初始占位符的数组

a=np.zeros((2,3))#全0
b=np.ones((2,3))#全1
c=np.empty((2,3))#全垃圾值
d=np.eye(2)#对角矩阵
e=np.full((2,2),6)#全为6
f=np.diag([1,2,3,4])#创建对角线为[1,2,3,4]的二维数组
运行结果:
[[0. 0. 0.]
 [0. 0. 0.]]
--------------------------
[[1. 1. 1.]
 [1. 1. 1.]]
--------------------------
[[1. 1. 1.]
 [1. 1. 1.]]
--------------------------
[[1. 0.]
 [0. 1.]]
--------------------------
[[6 6]
 [6 6]]
--------------------------
[[1 0 0 0]
 [0 2 0 0]
 [0 0 3 0]
 [0 0 0 4]]
a=np.random.random((2,2))#2x2的随机数组,取值范围在[0.0,1.0)
#random与rand相同,randn()函数取值范围是标准正态分布
b=np.random.randint(4,15,size=(2,2))#取值范围[4,15)的整数数组
c=np.random.normal(0,0.1,size=(3,3))#均值为0,标准差为0.1的正态分布中随机抽取3x3的数组
结果:
[[0.98271693 0.30466724]
 [0.13086    0.72070177]]
--------------------------
[[10 11]
 [13  5]]
--------------------------
[[-0.02855388 -0.0367391   0.07517827]
 [-0.03310269  0.08124156 -0.16556125]
 [-0.04000652  0.00365722 -0.03634599]]
a=np.arange(4,10)#[4,5,6,7,8,9]
b=np.arange(4,10,3)#[4,7]
c=np.linspace(0,10,6)#创建[0,10]之间含6个元素的array,各个元素的间隔相等,为(10-0)/(6-1)
d=np.linspace(0,10,6,endpoint=False)#创建[0,10)之间含6个元素的array,各个元素的间隔相等,为(10-0)/6
f=np.linspace(0,5)#默认是50个数据
e=np.logspace(0,2,20)#和linspace类似,创建的是等比数列,生成10^0-10^2的20个元素的等比数列

2.矢量化运算

2.1矢量化

描述了代码中没有任何显示的循环索引等,应用在元素级(即应用与对应元素间的运算)
Numpy中的+-*/都是指的矢量化运算,就是对应位置的元素做加减乘除操作,便不再赘述。

2.2广播机制

用于描述操作的隐式逐元素行为的术语,描述了如何在算数运算期间处理不同形状的数组,较小的数组在较大的数组上广播,以便他们具有兼容的形状,广播提供了一种矢量化数组操作的办法。
一般广播的规则:
从尾尺寸开始,向前发展,当两个数组的shape满足:1.从尾部开始具有的轴都相同 2.当对应轴不同但其中的一个轴为1这两个条件只要满足其中的一个即可,否则会抛出异常:operands could not be broadcast together
最后的结果数组的大小是沿输入的每个轴不是1的大小。
例如:

a   shape:(2x4x3)
b         (    3,)   a与b是可以广播的
c         (8x4x3)
d         (  2x1)    c和d是不可以广播的
因为倒数第二维既不相同,也不满足其中一个为1.(4和2)

3.索引和切片

3.1索引

基本索引:
对于数组有几个维度,就相当于有几个轴,最外层对应轴axis=0,axis往后递增,以此类推。
2维数据中 axis=0表示行,axis=1表示列
3维数据中 axis=0表示组,axis=1表示行,axis=2表示列
对于1维数组其索引和list相同,不再赘述。

对于2维:
a=np.array([[1,2,3],[4,5,6]])
a[0]代表[1,2,3],即第一行数据
a[0][1]与a[0,1]均代表2,但是二者有些区别:
[0][1]先找到a[0]再找[1],a[0,1]则是直接定位
对于3维:
a=np.array([[[1,2,3],[4,5,6]],[[4,5,6],[7,8,9]]])
即:
[[[1 2 3]
  [4 5 6]]

 [[4 5 6]
  [7 8 9]]]
-----------------
a[0]=
[[1 2 3]
 [4 5 6]]
a[0,0]=[1 2 3]
a[0,0,1]=1

花式索引:

a[[0,1,2]] 一个花式索引,获取最外层索引(axis=0)为0,1,2的数据

a[[1,3],[1,2]] 使用两个花式索引操作数组时,会将第一个花式索引作为最外面的索引(axis=0),第二个花式索引(axis=1),以此类推.例子是获取索引为[1,1]和[3,2]的元素。

a[[1,3],[[1],[2]]] 对于两个花式索引,当第二个花式索引为二维数组时,此时获取的是[[a[1,1],a[1,2]],[a[3,1],a[3,2]]相当于行与列的组合。对于当对数组的矩形部分的元素整体赋值时用得到。

布尔索引:

a=np.array([1,2,3])
print(a==1)  #打印结果为:[ True False False],即为一个布尔类型的数组
将布尔类型的数组作为索引会返回布尔值为Ture对应位置的数据
a[a==1]  #其值为[1]
当a为二维数组时,如果想对其中一行,或者一列利用布尔索引
a=np.array([[1,2,3],[4,5,6],[7,8,9]])
print(a[[True,False,True],1])
print(a[0,[True,False,True]])
结果:
[2 8]
[1 3]
注意,布尔索引的长度要和二维数组列的元素个数和行的元素个数相同

3.2切片

切片的形式:i:j:k
i代表初始位置,j代表终止位置,k代表步长。
j是负数时被解释为n+j(n为切片维度中元素的数量)
未给出的部分 | k>0 | k<0
-------- | ----- |----
没有给出 i | 默认为0 | 默认n-1
没有给出 j |默认为n|默认-n-1
没有给出 k ,K默认为1。

对于二维数组
a[:,:-1]输出前n-1列所有行
a[:,-1]获取最后一列(结果是一维数组)
a[:,n-1:]获取最后一列(结果是二维数组)
a=np.array([[1,2,3,4],[5,6,7,8]])
print(a[1:4:3,1:4:2])
结果:[[6 8]]

4.数组运算

4.1数组部分

对于矩阵运算这部分,因为Numpy官方推荐使用数组,以后会把矩阵给删除,所以就使用数组做矩阵运算。
数组作矩阵乘积运算时,可以使用@操作符,也可以使用dot函数。
数组可以进行转置操作,可以采用T或者transpose函数转置。
一维数组的转置就是它本身。
T与transpose()的区别:
对于一维和二维是没有区别的,对于多维而言当使用T和 transpose()时,你会发现结果时一样的,3维的转置默认是将维度由axis(0,1,2)变为(2,1,0),所以默认二者相同。但是有时我们需要对三维数组仅仅两个轴进行变换,所以此时只能用transpose,而不能使用T。

#乘积:
A@B
A.dot(B)
np.dot(A,B)
三者都是指A矩阵与B矩阵相乘

#转置:
A.transpose(1,0,2)
将其axis=0的轴与axis=1的轴进行变换,可输出其shape进行观察。

#求逆矩阵
np.linalg.inv(x)
#求x的逆矩阵

dot运算需要注意的地方:
1.一维数组和一维数组
一维数组和一维数组的dot运算得到的是一个标量,即是线性代数中的内积。

vec1 = np.array([1, 2, 3])
vec2 = np.array([1, 1, 1])
print(vec1.dot(vec2))
print(vec1*vec2)
结果:
6
[1 2 3]

2.二维数组和一维数组的点积
例如shape(2,3)二维数组dot一维数组shape(3,),会得到一维行向量, 相当于(2,3) * (3,) = (2,)

vec1 = np.array([1, 2, 3])
vec2 = np.array([[1, 1, 1],[1,1,2]])
vec2.dot(vec1)
结果:
[6 9]

变换数组形态
1.reshape()改变数组的shape
2.使用ravel,flatten函数展平数组
二者都可以展平数组,flatten可以选择横向或者纵向展平。

a= np.array([[1, 1, 1],[1,1,2]])
a.ravel() #横向展平
结果:
[1, 1, 1, 1, 1, 2]
a.flatten() #横向展平
结果:
[1, 1, 1, 1, 1, 2]
a=np.array([[1,2,3],[4,5,6]])
a.flatten('F')#纵向展平
结果:
[1 4 2 5 3 6]

遇到的其他方法:

np.arange(20)[:,np.newaxis]  #指将一维数组变为列向量

3.将数组进行组合
使用hstack函数可以实现数组的横向组合,vstack可以实现数组的纵向组合,concatenate函数可以实现数组的横向和纵向组合,其中参数axis=1按照横向组合,axis=0按照纵向组合。
注意组合的两个数组需要满足的条件:除了连接轴之外的所有输入数组维度必须完全匹配。(意思就是如果按照横向组合,需要纵向的长度是相同的,但是连接轴(横向不需要长度相同))

一维数组:
e=np.array([1,2,3])
d=np.array([1,2,3])
print(np.vstack((d,e)))
print(np.hstack((d,e)))
结果:
[[1 2 3]
 [1 2 3]]
[1 2 3 1 2 3]
二维数组:
a=np.array([[1,2],[4,5]])
b=np.array([[7,8,9],[10,11,12]])
print(np.hstack((a,b))) 等同print(np.concatenate((a,b),axis=1))
a和b按横向组合时,要求其纵向长度相同都为2,但是其横向(连接轴)不需要长度相同,a横向为2,b横向为3
结果:
[[ 1  2  7  8  9]
 [ 4  5 10 11 12]]
a=np.array([[1,2,3],[4,5,6]])
b=np.array([[7,8,9],[10,11,12]])
print(np.vstack((a,b)))  也就等同print(np.concatenate((a,b),axis=0))
结果:
[[ 1  2  3]
 [ 4  5  6]
 [ 7  8  9]
 [10 11 12]]

np.c_和np.r_
np.r_是按列连接两个矩阵,就是把两矩阵上下相加,要求列数相等。
np.c_是按行连接两个矩阵,就是把两矩阵左右相加,要求行数相等。
hstack和vstack以及concatenate的参数都是tuple,而np.c_和np.r_的调用方式是np.c_[a,b]。
注意:
对于一维数组的连接:结果与二维数组的结果效果不同

一维数组:
e=np.array([1,2,3])
d=np.array([1,2,3])
print(np.vstack((d,e)))
print(np.r_[d,e])
结果:
[[1 2 3]
 [1 2 3]]
[1 2 3 1 2 3]
print(np.hstack((d,e)))
print(np.c_[d,e])
结果:
[1 2 3 1 2 3]
[[1 1]
 [2 2]
 [3 3]]
二维数组:
a=np.array([[1,2,3],[4,5,6]])
b=np.array([[7,8,9],[10,11,12]])
print(np.c_[a,b])
print(np.r_[a,b])
结果:
[[ 1  2  3  7  8  9]
 [ 4  5  6 10 11 12]]
[[ 1  2  3]
 [ 4  5  6]
 [ 7  8  9]
 [10 11 12]]

4.将数组进行分割
使用hsplit函数实现横向分割,使用vsplit函数实现纵向分割,使用split函数可以通过设置axis来进行横向和纵向分割(axis=1实现横向分割)。

b=np.array([[7,8,9],[10,11,12]])
横向分割:
np.hsplit(b,3) 等同np.split(b,3,axis=1)
结果:
[array([[ 7],
        [10]]), array([[ 8],
        [11]]), array([[ 9],
        [12]])]
        
纵向分割:        
np.vsplit(b,2) 等同np.split(b,2,axis=0)
结果:
[array([[7, 8, 9]]), array([[10, 11, 12]])]

4.2 矩阵部分

矩阵是ndarry的子类,矩阵是继承Numpy数组对象的二维数组对象。
创建矩阵:

np.mat('1,2;3,4')
np.matrix([[1,2],[3,4]])
结果:
[[1 2]
 [3 4]]

将二维数组变为矩阵:
np.mat(A)
注:A为二维数组
==注意:==
对于矩阵和二维数组是有区别的,矩阵有一些特殊的属性,H求共轭转置,I求逆矩阵。****对于矩阵而言,求两个矩阵对应元素的乘积只能使用multiply,代表的时矩阵乘积***。

5.常用函数

1.常用的一些数学函数:
一元:调用形式:np.___(A)
exp():求各元素的指数e^x^ 例如np.exp(A) 会将对应位置变为e^x,x指的是对应位置的元素大小
log10 log2 log1p
log1p指的是log(1+x)
二元:调用形式:np.___(A,B)
maximum minimum 求两个数组,对应位置的最大,最小元素。
还有add subtract multiply divide
例如:

a=np.array([0,1,4,2])
b=np.array([1,2,6,1])
np.maximum(a,b)
结果:[1, 2, 6, 2]

2.数组统计运算:
调用形式:arr.___()
min max sum mean求数组中的最小元素,最大元素,所有的和,平均值
注意:keepdims表示的确保最后返回的数组的维度为(n,1)防止返回一维数组。
例如:

   >>> np.sum([[0, 1], [0, 5]], axis=0)
    array([0, 6])

   >>> np.sum([[0, 1], [0, 5]], axis=0,keepdims=True)
    array([[0, 6]])

argmin argmax 求最小值的索引,求最大值的索引
cumsum 计算元素的累计和(当前位置前面所有元素的和,包括当前位置的元素,类似fibinacci数列)
cumprod 计算元素的累计积,和cumsum的方式类似。

a=np.arange(10) 
print(a.cumsum())
结果:[ 0  1  3  6 10 15 21 28 36 45]
b=np.array([1,2,0,1])
print(b.cumprod())
结果:[1, 2, 0, 0]

另外可以在此基础上加上条件表达去达到统计的功能:
例如:

np.mean(pred == Y)*100
计算预测正确率,pred==Y去判断是否相等,bool数组,1代表相等,0代表不相等

3.数组比较运算
返回结果为一个bool型的数组。

a=np.array([1,4,3])
b=np.array([1,3,3])
print(a>b)
结果:
[False  True False]

4.数组数据处理的相关函数
np.around()函数用于返回五舍六入后的值,可指定精度。
i=np.floor(x)函数用于以元素方式返回输入的下限,取整操作,i<=x。
i=np.ceil(x)函数用于以元素方式返回输入的上限,返回的数值i>=x。
np.where()函数根据 条件从 x 和 y 中选择元素,当为 True 时,选 x,否则选 y。

np.around(round和around相同)
np.around(a, decimals=0, out=None)

对于正好在舍入小数值之间的值,NumPy舍入到最接近的偶数值。当超过5时候(不包含5),才会进位!因此,1.5和2.5轮到2.0,-0.5和0.5轮到0.0等。由于IEEE浮点标准[1]中的小数部分的不精确表示以及当以10的幂进行缩放时引入的误差,结果也可能是令人惊讶的。

参数:

  • a : array_like。输入数据。

  • decimals : int,可选。要舍入的小数位数(默认值:0)。如果小数为负数,则指定小数点左侧的位置数。

  • out : ndarray,可选。替代输出数组,用于放置结果。它必须具有与预期输出相同的形状,但如果需要,将输出输出值的类型。

返回:
rounded_array : ndarray。与a相同类型的数组,包含舍入值。除非指定了out,否则将创建一个新数组。返回对结果的引用。复数的实部和虚部分别舍入。舍入浮点数的结果是浮点数。
例子1:

>>> np.around([0.37, 1.64])
array([ 0.,  2.])
>>> np.around([0.37, 1.64], decimals=1)
array([ 0.4,  1.6])
>>> np.around([.5, 1.5, 2.5, 3.5, 4.5]) # rounds to nearest even value
array([ 0.,  2.,  2.,  4.,  4.])
>>> np.around([1,2,3,11], decimals=1) # ndarray of ints is returned
array([ 1,  2,  3, 11])
>>> np.around([1,2,3,11], decimals=-1)
array([ 0,  0,  0, 10])

常用的用法:

np.round(x).astype(int) 将x四舍五入变为整数

np.floor()

>>> a = np.array([-2.5, -1.7, -1.5, -0.2, 0.2, 1.5, 1.7, 2.0])
>>> np.floor(a)
array([-3., -2., -2., -1.,  0.,  1.,  1.,  2.])

np.ceil()

>>> a = np.array([-1.7, -1.5, -0.2, 0.2, 1.5, 1.7, 2.0])
>>> np.ceil(a)
array([-1., -1., -0.,  1.,  2.,  2.,  2.])

np.where()
np.where(condition, x, y)
如果只给出条件,则返回condition.nonzero()。

参数:

  • condition:array_like,bool。如果为True,则产生x,否则产生y。

  • x,y:array_like,可选。要从中选择的值。x,y和条件需要可以广播broadcastable到某种形状。

返回:
out:ndarray或ndarray元组。如果同时指定了x和y,则输出数组包含x的元素,其中condition为True,其他元素来自 y。如果只给出条件,则返回元组condition.nonzero(),条件为True 的索引。

如果给出x和y并且输入数组是1-D,where则相当于:
[xv if c else yv for (c,xv,yv) in zip(condition,x,y)]

常用的例子:

a=np.array([[1,2,3],[4,5,6],[7,8,9]])
b=np.where(a==6) #返回元素为6的行标和列表,返回值为一个元组,第一个为行标,第二个为列标
print(b)
print(b[0])
print(b[1])
c=np.where(a[1,:]==5)  #在行标为1的条件下,去选择5,返回值为列标的索引
print(c)
print(c[0]) #c[0]是一个一维数组
print(c[0][0]) #第一个为5的下标索引
d=np.where(a[1:]==5) #从索引为1的行开始去寻找,此时的行标基于1为0
print(d)

结果:
(array([1], dtype=int64), array([2], dtype=int64))
[1]
[2]
(array([1], dtype=int64),)
[1]
1
(array([0], dtype=int64), array([1], dtype=int64))

其他例子:

>>> np.where([[True, False], [True, True]],
...          [[1, 2], [3, 4]],
...          [[9, 8], [7, 6]])
array([[1, 8],
       [3, 4]])
>>> np.where([[0, 1], [1, 0]])
(array([0, 1], dtype=int64), array([1, 0], dtype=int64))
>>> x = np.arange(9.).reshape(3, 3)
>>> print(x)
[[0. 1. 2.]
 [3. 4. 5.]
 [6. 7. 8.]]

>>> np.where( x > 5 )
(array([2, 2, 2]), array([0, 1, 2])) 元组第一个元素为行标,第二个为列标
>>> x[np.where( x > 3.0 )]               # Note: result is 1D.
array([ 4.,  5.,  6.,  7.,  8.])
>>> np.where(x < 5, x, -1)               # Note: broadcasting.
array([[ 0.,  1.,  2.],
       [ 3.,  4., -1.],
       [-1., -1., -1.]])
       
>>> goodvalues = [3, 4, 7]
>>> ix = np.isin(x, goodvalues)
>>> ix
array([[False, False, False],
       [ True,  True, False],
       [False,  True, False]])
>>> np.where(ix)
(array([1, 1, 2]), array([0, 1, 1]))

6.读写文件

对于二进制文件的读写利用load和save,savaz函数.注意对于load读取文件时不能省略扩展名,sava是可以的。save和savez的区别是savez可以存多个数组。

arr=load('data.txt')
save('data',arr)
savez('data',arr1,arr2) #写进data二进制文件中两个数组
arr=np.load('data.npz')
print(arr.files) # 查看各个数组名称
print(arr['arr_0']) #输出第一个数组的内容

下面主要是对文本文件的读写。

6.1loadtxt()

从文本文件加载数据到二维数组。
常用的参数:
loadtxt(fname,dtype=,
delimiter=None,usecols=None,unpack=False)
delimiter :间隔符,一般为‘,’
usecols :是一个元组,使用该元组中的元素对应的列。如(0,3)则利用第一列和第四列的数据。
unpack:当是False时,会返回一个数组,当为True时,将该读取的cols的每列分开,返回多个变量,需要多个变量接收。

dataset=np.loadtxt('data1.txt',delimiter=',',usecols=(0,1))
#将第一列和第二列数据加载到dataset数组中

6.2 savetxt()

可以将数组写到以某种分隔符隔开的文本文件中。

numpy.savetxt(fname, X, fmt='%.18e', delimiter=' ', newline='\n', header='', footer='', comments='# ', encoding=None)
例如:
a=np.array([[1,4,3],[2,3,4]])
np.savetxt('data2.txt',a,fmt='%.2f',delimiter=',') 
将数组保存到文件中,同时数组元素保留2位小数。如果数组为1维,则会以列的形式保存到文本文件中。

结果:
存储结果
==注意==:
1.数组进行运算时,结果数组类型遵循向上转换的行为
2.数组太大时,Numpy会自动跳过数组中心部分并仅打印角点,若想打印全部,需要更改打印选项np.set_printoptions(threshold=sys.maxsize)

import sys
a=np.arange(10000).reshape(5000,2)
print(a)
np.set_printoptions(threshold=sys.maxsize)
print(a)

但是虽然官方写的是这样,但是用jupyter是不需要更改,显示的是全部数据,用Pycharm需要更改打印选项。
3.‘*’号在Numpy中指的是矢量化运算(按对于元素进行运算),矩阵乘积可以使用@运算符或者是dot()函数
4.在编程的过程中尽量不使用一维数组防止出错,把一维数组变成行向量和列向量进行处理,对于测试时可以加入assert断言语句。

assert(a.shape==(2,3))
#断言会执行,出错会跳出异常

你可能感兴趣的:(Numpy的使用)