文章目录
1 迭代数组
【1 迭代数组】一整节介绍nditer。
NumPy迭代器对象numpy.nditer提供了一种灵活访问一个或者多个数组元素的方式,该迭代器最基本的任务是完成对数组元素的访问。下面用arange()函数创建一个2×3数组,并使用nditer对它进行迭代。
import numpy as np
a=np.arange(6).reshape(2,3)
print('原始数组:')
print(a)
print('-----')
print('迭代输出元素:')
for x in np.nditer(a):
print(x,end=',')
输出:
原始数组:
[[0 1 2]
[3 4 5]]
-----
迭代输出元素:
0,1,2,3,4,5,
以上实例不是使用标准C或者Fortran顺序,选择的顺序是和数组内存布局一致的,这样做是为了提升访问的效率,默认是行序优先(row-major order,或者说是C-order),这反映了默认情况下只需访问每个元素,而无需考虑其特定顺序。可以通过迭代上述数组的转置来看到这一点,并与以C顺序访问数组转置的copy方式做对比,如下实例:
import numpy as np
a=np.arange(6).reshape(2,3)
print('原始数组:')
print(a)
print('-----')
print('迭代输出元素:')
for x in np.nditer(a.T):
print(x,end=',')
print('\n-----')
for x in np.nditer(a.T.copy(order='C')):
print(x,end=',')
输出:
原始数组:
[[0 1 2]
[3 4 5]]
-----
迭代输出元素:
0,1,2,3,4,5,
-----
0,3,1,4,2,5,
可以看出,a和a.T的遍历顺序是一样的,也就是他们在内存中的存储顺序也是一样的,但是a.T.copy(order=‘C’)的遍历结果是不同的,那是因为它和前两种的存储方式是不一样的,默认是按行访问。
1.1 控制遍历顺序
1、for x in np.nditer(a, order=‘F’)——Fortran order,即是列序优先;
2、for x in np.nditer(a.T, order=‘C’)——C order,即是行序优先;
import numpy as np
a=np.arange(0,60,5).reshape(3,4)
print('原始数组:')
print(a)
print('-----')
b=a.T
print('原始数组的转置是:')
print(b)
print('-----')
c=b.copy(order='C')
print('以C风格顺序排序')
print(c)
for x in np.nditer(c):
print(x,end=',')
print('\n-----')
c=b.copy(order='F')
print('以F风格顺序排序')
print(c)
for x in np.nditer(c):
print(x,end=',')
输出:
原始数组:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
-----
原始数组的转置是:
[[ 0 20 40]
[ 5 25 45]
[10 30 50]
[15 35 55]]
-----
以C风格顺序排序
[[ 0 20 40]
[ 5 25 45]
[10 30 50]
[15 35 55]]
0,20,40,5,25,45,10,30,50,15,35,55,
-----
以F风格顺序排序
[[ 0 20 40]
[ 5 25 45]
[10 30 50]
[15 35 55]]
0,5,10,15,20,25,30,35,40,45,50,55,
以上输出我比较疑惑的是:以C风格顺序排序与以F风格顺序排序后输出数组居然一模一样,然后使用nditer后确实不一样…
可以通过显式设置,来强制nditer对象使用某种顺序:
import numpy as np
a=np.arange(0,60,5).reshape(3,4)
print('原始数组:')
print(a)
print('-----')
print('以C风格顺序排序')
for x in np.nditer(a,order='C'):
print(x,end=',')
print('\n-----')
print('以F风格顺序排序')
for x in np.nditer(a,order='F'):
print(x,end=',')
输出:
原始数组:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
-----
以C风格顺序排序
0,5,10,15,20,25,30,35,40,45,50,55,
-----
以F风格顺序排序
0,20,40,5,25,45,10,30,50,15,35,55,
1.2 修改数组中元素的值
nditer对象有一个可选参数op_flags。默认情况下,nditer将视待迭代遍历的数组为只读对象(read-only),为了在遍历数组的同时,实现对数组元素值的修改,必须指定op_flags为read-write或者write-only。
import numpy as np
a=np.arange(0,60,5).reshape(3,4)
print('原始数组:')
print(a)
print('-----')
for x in np.nditer(a,op_flags=['readwrite']):
x[...]=2*x
print('修改后的数组是:')
print(a)
输出:
原始数组:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
-----
修改后的数组是:
[[ 0 10 20 30]
[ 40 50 60 70]
[ 80 90 100 110]]
1.3 使用外部循环
nditer类的构造器拥有flags参数,它可以接受下列值:
参数 | 描述 |
---|---|
c_index | 可以跟踪C顺序的索引 |
f_index | 可以跟踪Fortran顺序的索引 |
multi-index | 每次迭代可以跟踪一种索引类型 |
external_loop | 给出的值是具有多个值的一维数组,而不是零维数组 |
在下面的实例中,迭代器遍历对应于每列,并组合为一维数组。
import numpy as np
a=np.arange(0,60,5).reshape(3,4)
print('原始数组:')
print(a)
print('-----')
print('修改后的数组是:')
for x in np.nditer(a,flags=['external_loop'],order='F'):
print(x,end=',')
输出:
原始数组:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
-----
修改后的数组是:
[ 0 20 40],[ 5 25 45],[10 30 50],[15 35 55],
1.4 广播迭代
如果两个数组是可广播的,nditer组合对象能够同时迭代它们。假设数组a的维度为3×4,数组b的维度为1×4,则使用以下迭代器(数组b被广播到a的大小)。
import numpy as np
a=np.arange(0,60,5).reshape(3,4)
print('第一个数组:')
print(a)
b=np.array([1,2,3,4],dtype=int)
print('第二个数组:')
print(b)
print('-----')
print('修改后的数组是:')
for x,y in np.nditer([a,b]):
print("%d:%d" % (x,y),end=',')
输出:
第一个数组:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
第二个数组:
[1 2 3 4]
-----
修改后的数组是:
0:1,5:2,10:3,15:4,20:1,25:2,30:3,35:4,40:1,45:2,50:3,55:4,
2 数组操作
Numpy中包含了一些函数用于处理数组,大概可分为以下6类:
2.1 修改数组形状
函数 | 描述 |
---|---|
reshape | 不改变数据的条件下修改形状 |
flat | 数组元素迭代器 |
flatten | 返回一份数组拷贝,对拷贝所做的修改不会影响原始数组 |
ravel | 返回展开数组 |
下面详细介绍这四个函数。
numpy.reshape函数可以在不改变数据的条件下修改形状,格式如下:
numpy.reshape(arr,newshape,order='C')
1、arr:要修改形状的数组
2、newshape:整数或者整数数组,新的形状应当兼容原有形状
3、order:‘C’–按行,‘F’–按列,‘A’–原顺序,‘k’–元素在内存中的出现顺序。
import numpy as np
a = np.arange(0,60,5)
print ('原始数组是:')
print (a)
print ('\n')
print ('修改后的数组是:')
a = a.reshape(3,4)
print(a)
输出:
原始数组是:
[ 0 5 10 15 20 25 30 35 40 45 50 55]
修改后的数组是:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
numpy.ndarray.flat是一个数组元素迭代器,实例如下:
import numpy as np
a=np.arange(0,60,5).reshape(3,4)
print('第一个数组为:')
for row in a:
print(row)
print('------')
print('迭代后的数组为:')
# 对数组中每个元素都进行处理,可以使用flat属性,该属性是一个数组元素迭代器
for element in a.flat:
print(element)
输出:
第一个数组为:
[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]
------
迭代后的数组为:
0
5
10
15
20
25
30
35
40
45
50
55
numpy.ndarray.flatten返回一份数组拷贝,对拷贝所做的修改不会影响原始数组,格式如下:
ndarray.flatten(order='C')
参数order:‘C’–按行,‘F’–按列,‘A’–原顺序,‘K’–元素在内存中的出现顺序。
import numpy as np
a = np.arange(0,60,5).reshape(3,4)
print ('原始数组是:')
print (a)
print ('\n')
print('展开的数组为:')
print(a.flatten())
print ('\n-----')
print('以F风格顺序展开的数组:')
print(a.flatten(order='F'))
输出:
原始数组是:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
展开的数组为:
[ 0 5 10 15 20 25 30 35 40 45 50 55]
-----
以F风格顺序展开的数组:
[ 0 20 40 5 25 45 10 30 50 15 35 55]
numpy.ravel()展平的数组元素,顺序通常是"C风格",返回的是数组视图,修改会影响原始数组。该函数接收两个参数:
numpy.ravel(a,order='C')
参数order:‘C’–按行,‘F’–按列,‘A’–原顺序,‘K’–元素在内存中的出现顺序。
import numpy as np
a = np.arange(0,60,5).reshape(3,4)
print ('原始数组是:')
print (a)
print ('\n')
print('调用ravel后:')
print(a.ravel())
print ('\n-----')
print('以F风格顺序调用ravel后:')
print(a.ravel(order='F'))
输出:
原始数组是:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
调用ravel后:
[ 0 5 10 15 20 25 30 35 40 45 50 55]
-----
以F风格顺序调用ravel后:
[ 0 20 40 5 25 45 10 30 50 15 35 55]
2.2 翻转数组
函数 | 描述 |
---|---|
transpose | 对换数组的维度,即转置 |
ndarray.T | 和self.transpose()相同 |
rollaxis | 向后滚动指定的轴 |
swapaxes | 对换数组的两个轴 |
numpy.transpose函数用于对换数组的维度,格式如下:
numpy.transpose(arr,axes)
参数说明:
1、arr:要操作的数组
2、axes:整数列表,对应维度,通常所有维度都会对换。
import numpy as np
a = np.arange(0,60,5).reshape(3,4)
print ('原始数组是:')
print (a)
print ('\n')
print('转置后:')
print(np.transpose(a))
输出:
原始数组是:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
转置后:
[[ 0 20 40]
[ 5 25 45]
[10 30 50]
[15 35 55]]
numpy.ndarray.T类似numpy.transpose:
import numpy as np
a = np.arange(0,60,5).reshape(3,4)
print ('原始数组是:')
print (a)
print ('\n')
print('转置后:')
print(a.T)
输出:
原始数组是:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
转置后:
[[ 0 20 40]
[ 5 25 45]
[10 30 50]
[15 35 55]]
numpy.rollaxis函数向后滚动特定的轴到一个特定位置,格式如下:
numpy.rollaxis(arr,axis,start)
参数说明:
1、arr:数组
2、axis:要向后滚动的轴,其它轴的相对位置不会改变
3、start:默认为零,表示完整的滚动,否则会滚动到特定位置。
我认为示例代码过于复杂,且以后用到的可能性较小,因此不整理该内容,以后用到再说。
numpy.swapaxes函数用于交换数组的两个轴,格式如下:
numpy.swapaxes(arr,axis1,axis2)
参数说明:
1、arr:输入的数组
2、axis1:对应第一个轴的整数
3、axis2:对应第二个轴的整数
import numpy as np
a = np.arange(8).reshape(2,4)
print ('原始数组是:')
print (a)
print ('-------')
print('调用swapaxes函数后的数组:')
b=np.swapaxes(a,0,1) #这里与转置效果相同
print(b)
输出:
原始数组是:
[[0 1 2 3]
[4 5 6 7]]
-------
调用swapaxes函数后的数组:
[[0 4]
[1 5]
[2 6]
[3 7]]
2.3 修改数组维度
维度 | 描述 |
---|---|
broadcast | 产生模仿广播的对象 |
broadcast_to | 将数组广播到新形状 |
expand_dims | 扩展数组的形状 |
squeeze | 从数组的形状中删除一维条目 |
下面只介绍squeeze,其他看这里。
numpy.squeeze函数从给定数组的形状中删除一维的条目,函数格式如下:
numpy.squeeze(arr,axis)
参数说明:
1、arr:输入数组
2、axis:整数或整数元组,用于选择形状中一维条目的子集
import numpy as np
x=np.arange(9).reshape(1,3,3)
print('数组x:')
print(x)
y=np.squeeze(x)
print('\n数组y:')
print(y)
print('\n数组x、y的形状分别为:')
print(x.shape,y.shape)
输出:
数组x:
[[[0 1 2]
[3 4 5]
[6 7 8]]]
数组y:
[[0 1 2]
[3 4 5]
[6 7 8]]
数组x、y的形状分别为:
(1, 3, 3) (3, 3)
2.4 连接数组
函数 | 描述 |
---|---|
concatenate | 连接沿现有轴的数组序列 |
stack | 沿着新的轴加入一系列数组。 |
hstack | 水平堆叠序列中的数组(列方向) |
vstack | 竖直堆叠序列中的数组(行方向) |
numpy.concatenate函数用于沿指定轴连接相同形状的两个或多个数组,格式如下:
numpy.concatenate((a1,a2,...),axis)
参数说明:
1、a1,a2,…:相同类型的数组
2、axis:沿着它连接数组的轴,默认为0
import numpy as np
a=np.array([[1,2],[3,4]])
print('第一个数组:')
print(a)
print('------')
b=np.array([[5,6],[7,8]])
print('第二个数组:')
print(b)
print('------')
print('沿轴0连接两个数组:')
print(np.concatenate((a,b)))
print('------')
print('沿轴1连接两个数组:')
print(np.concatenate((a,b),axis=1))
输出:
第一个数组:
[[1 2]
[3 4]]
------
第二个数组:
[[5 6]
[7 8]]
------
沿轴0连接两个数组:
[[1 2]
[3 4]
[5 6]
[7 8]]
------
沿轴1连接两个数组:
[[1 2 5 6]
[3 4 7 8]]
只介绍concatenate,其他看这里。
2.5 分割数组
函数 | 数组及操作 |
---|---|
split | 将一个数组分割为多个子数组 |
hsplit | 将一个数组水平分割为多个子数组(按列) |
vsplit | 将一个数组垂直分割为多个子数组(按行) |
numpy.split函数沿特定的轴将数组分割为子数组,格式如下:
numpy.split(ary,indices_or_sections,axis)
参数说明:
1、ary:被分割的数组
2、indices_or_sections:如果是一个整数,就用该数平均切分,如果是一个数组,为沿轴切分的位置(左开右闭)
3、axis:设置沿着哪个方向进行切分,默认为0,横向切分,即水平方向。为1时,纵向切分,即竖直方向。
a=np.arange(9)
print('第一个数组:')
print(a)
print('---------')
b=np.split(a,3)
print('将数组分为三个大小相同的子数组:')
print(b)
print('---------')
b=np.split(a,[2,4,7])
print('将数组在一维数组中表明的位置分割:')
print(b)
输出:
第一个数组:
[0 1 2 3 4 5 6 7 8]
---------
将数组分为三个大小相同的子数组:
[array([0, 1, 2]), array([3, 4, 5]), array([6, 7, 8])]
---------
将数组在一维数组中表明的位置分割:
[array([0, 1]), array([2, 3]), array([4, 5, 6]), array([7, 8])]
axis为0时在水平方向分割,axis为1时在垂直方向分割:
a=np.arange(16).reshape(4,4)
print('第一个数组:')
print(a)
print('---------')
b=np.split(a,2)
print('默认分割,即按0轴/水平方向分割:')
print(b)
print('---------')
c=np.split(a,2,1)
print('沿垂直方向分割:')
print(c)
print('---------')
d=np.split(a,2,0)
print('沿水平方向分割:')
print(d)
输出:
第一个数组:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]]
---------
默认分割,即按0轴/水平方向分割:
[array([[0, 1, 2, 3],
[4, 5, 6, 7]]), array([[ 8, 9, 10, 11],
[12, 13, 14, 15]])]
---------
沿垂直方向分割:
[array([[ 0, 1],
[ 4, 5],
[ 8, 9],
[12, 13]]), array([[ 2, 3],
[ 6, 7],
[10, 11],
[14, 15]])]
---------
沿水平方向分割:
[array([[0, 1, 2, 3],
[4, 5, 6, 7]]), array([[ 8, 9, 10, 11],
[12, 13, 14, 15]])]
numpy.hsplit函数用于水平分割数组,通过指定要返回的相同形状的数组数量来拆分原数组。
import numpy as np
harr=np.floor(10*np.random.random((2,6)))
print('原array:')
print(harr)
print('\n\n拆分后:')
print(np.hsplit(harr,3))
输出:
原array:
[[5. 9. 4. 4. 7. 8.]
[1. 2. 9. 4. 2. 0.]]
拆分后:
[array([[5., 9.],
[1., 2.]]), array([[4., 4.],
[9., 4.]]), array([[7., 8.],
[2., 0.]])]
numpy.vsplit沿着垂直轴分割,其分割方式与hsplit用法相同。
import numpy as np
harr=np.floor(10*np.random.random((4,6)))
print('原array:')
print(harr)
print('\n\n拆分后:')
print(np.vsplit(harr,2))
输出:
原array:
[[3. 0. 4. 4. 2. 8.]
[1. 0. 2. 0. 8. 5.]
[5. 9. 7. 2. 4. 5.]
[3. 1. 5. 3. 9. 5.]]
拆分后:
[array([[3., 0., 4., 4., 2., 8.],
[1., 0., 2., 0., 8., 5.]]), array([[5., 9., 7., 2., 4., 5.],
[3., 1., 5., 3., 9., 5.]])]
2.6 数组元素的添加与删除
函数 | 元素及描述 |
---|---|
resize | 返回指定形状的新数组 |
append | 将值添加到数组末尾 |
insert | 沿指定轴将值插入到指定下标之前 |
delete | 删掉某个轴的子数组,并返回删除后的新数组 |
unique | 查找数组内的唯一元素 |
numpy.resize函数返回指定大小的新数组。如果新数组大小大于原始大小,则包含原始数组中的元素的副本。
numpy.resize(arr,shape)
参数说明:
1、arr:要修改大小的数组
2、shape:返回数组的新形状
a=np.array([[1,2,3],[4,5,6]])
print('第一个数组:')
print(a)
print('-----')
print('第一个数组的形状:')
print(a.shape)
print('-----')
b=np.resize(a,(3,2))
print('第二个数组:')
print(b)
print('-----')
print('第二个数组的形状:')
print(b.shape)
print('-----')
b=np.resize(a,(3,3))
print('修改第二个数组的形状后:')
print(b) #注意在输出中,a的第一行在b中重复出现,因为尺寸变大了
输出:
第一个数组:
[[1 2 3]
[4 5 6]]
-----
第一个数组的形状:
(2, 3)
-----
第二个数组:
[[1 2]
[3 4]
[5 6]]
-----
第二个数组的形状:
(3, 2)
-----
修改第二个数组的形状后:
[[1 2 3]
[4 5 6]
[1 2 3]]
numpy.append函数在数组的末尾添加值。追加操作会分配整个数组,并把原来的数组复制到新数组中。此外,输入数组的维度必须匹配,否则将生成ValueError。
numpy.append(arr,values,axis=None)
参数说明:
1、arr:输入数组
2、values:要向arr添加的值,需要和arr形状相同(除了要添加的轴)
3、axis:默认为None,此时默认是横向追加,返回【总是为一维数组】;当axis为0时,数组是加在下边(列数要相同);当axis为1时,数组是加在右边(行数要相同)。
a=np.array([[1,2,3],[4,5,6]])
print('第一个数组:')
print(a)
print('\n\n向数组添加元素:')
print(np.append(a,[7,8,9]))
print('\n\n沿轴0添加元素:')
print(np.append(a,[[7,8,9]],axis=0))
print('\n\n沿轴1添加元素:')
print(np.append(a,[[5,5,5],[7,8,9]],axis=1))
输出:
第一个数组:
[[1 2 3]
[4 5 6]]
向数组添加元素:
[1 2 3 4 5 6 7 8 9]
沿轴0添加元素:
[[1 2 3]
[4 5 6]
[7 8 9]]
沿轴1添加元素:
[[1 2 3 5 5 5]
[4 5 6 7 8 9]]
numpy.insert函数在给定索引之前,沿给定轴在输入数组中插入值;如果未提供轴,则输入数组会被展开。
numpy.insert(arr,obj,values,axis)
参数说明:
1、arr:输入数组
2、obj:在其之前插入值的索引
3、values:要插入的值
4、axis:沿着它插入的轴,如果未提供,则输入数组会被展开
a=np.array([[1,2],[3,4],[5,6]])
print('第一个数组:')
print(a)
print('\n未传递Axis参数。在插入之前输入数组会被展开')
print(np.insert(a,3,[11,12]))
print('\n传递了Axis参数。会广播值数组来分配输入数组')
print('\n沿轴0广播')
print(np.insert(a,1,[11],axis=0))
print('\n沿轴1广播')
print(np.insert(a,1,11,axis=1))
输出:
第一个数组:
[[1 2]
[3 4]
[5 6]]
未传递Axis参数。在插入之前输入数组会被展开
[ 1 2 3 11 12 4 5 6]
传递了Axis参数。会广播值数组来分配输入数组
沿轴0广播
[[ 1 2]
[11 11]
[ 3 4]
[ 5 6]]
沿轴1广播
[[ 1 11 2]
[ 3 11 4]
[ 5 11 6]]
numpy.delete函数返回从输入数组中删除指定子数组后的新数组。如果未提供轴参数,则输入数组将展开。
np.delete(arr,obj,axis)
参数说明:
1、arr:输入数组
2、obj:可以是切片,整数或者整数数组,表明要从输入数组删除的子数组
3、axis:沿着它删除给定子数组的轴,如果未提供,则输入数组会被展开
a=np.arange(12).reshape(3,4)
print('第一个数组:')
print(a)
print('\n未传递Axis参数。在删除之前输入数组会被展开')
print(np.delete(a,5))
print('\n删除第二列')
print(np.delete(a,1,axis=1))
print('\n包含从数组中删除的替代值的切片')
a=np.arange(1,11)
print(np.delete(a,np.s_[::2])) #s_是切片slice
输出:
第一个数组:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
未传递Axis参数。在删除之前输入数组会被展开
[ 0 1 2 3 4 6 7 8 9 10 11]
删除第二列
[[ 0 2 3]
[ 4 6 7]
[ 8 10 11]]
包含从数组中删除的替代值的切片
[ 2 4 6 8 10]
numpy.unique函数用于去除数组中的重复元素。
np.unique(arr,return_index,return_inverse,return_counts)
1、arr:输入数组,如果不是一维数组则会展开,还会从小到大排序
2、return_index:如果为true,返回新列表元素在旧列表中的位置(下标),并以列表形式储
3、return_inverse:如果为true,返回旧列表元素在新列表中的位置(下标),并以列表形式储
4、return_counts:如果为true,返回去重数组中的元素在原数组中的出现次数
import numpy as np
a=np.array([5,2,6,2,7,5,6,8,2,9])
print('第一个数组:')
print(a)
print('\n第一个数组去掉重复值后:')
u=np.unique(a)
print(u)
print('\n去重得到的数组的索引数组:')
u,indices=np.unique(a,return_index=True)
print(indices)
print('\n每个和原数组下标对应的数值:')
print(a)
print('\n去重数组的下标:')
u,indices=np.unique(a,return_inverse=True)
print(u)
print('\n下标为:')
print(indices)
print('\n使用下标重构原数组:')
print(u[indices])
print('\n返回去重元素的重复数量:')
u,indices=np.unique(a,return_counts=True)
print(u)
print(indices)
输出:
第一个数组:
[5 2 6 2 7 5 6 8 2 9]
第一个数组去掉重复值后:
[2 5 6 7 8 9]
去重得到的数组的索引数组:
[1 0 2 4 7 9]
每个和原数组下标对应的数值:
[5 2 6 2 7 5 6 8 2 9]
去重数组的下标:
[2 5 6 7 8 9]
下标为:
[1 0 2 0 3 1 2 4 0 5]
使用下标重构原数组:
[5 2 6 2 7 5 6 8 2 9]
返回去重元素的重复数量:
[2 5 6 7 8 9]
[3 2 2 1 1 1]
END