01 numpy广播(broadcast)
广播(Broadcast)是 numpy 对不同形状(shape)的数组进行数值计算的方式。
如果两个数组 a 和 b 形状相同,即满足 a.shape == b.shape,那么 a*b 的结果就是 a 与 b 数组对应位相乘。这要求维数相同,且各维度的长度相同。
实例为:
import numpy as np
a = np.array([1,2,3,4])
b = np.array([10,20,30,40])
c = a * b
print (c) #输出结果为:[ 10 40 90 160]
当运算中的 2 个数组的形状不同时,numpy 将自动触发广播机制,扩充到相同的形状,再进行计算,实例:
import numpy as np
a = np.array([[ 0, 0, 0],
[10,10,10],
[20,20,20],
[30,30,30]])
b = np.array([0,1,2])
print(a + b)
输出为:
[[ 0 1 2]
[10 11 12]
[20 21 22]
[30 31 32]]
下面图片可简单理解运算过程:
广播的规则:
- 让所有输入数组都向其中形状最长的数组看齐,形状中不足的部分都通过在前面加 1 补齐。
- 输出数组的形状是输入数组形状的各个维度上的最大值。
- 当输入数组的某个维度的长度为 1 时,沿着此维度运算时都用此维度上的第一组值。
02 迭代数组
迭代器最基本的任务的可以完成对数组元素的访问。
2.1 numpy.nditer()
numpy.nditer 提供了一种灵活访问一个或者多个数组元素的方式。
一个简单的例子:
import numpy as np
a = np.arange(6).reshape(2,3)
print ('原始数组是:')
print (a)
print ('\n')
print ('迭代输出元素:')
for x in np.nditer(a):
print (x, end=", " )
print ('\n')
输出结果为:
原始数组是:
[[0 1 2]
[3 4 5]]
迭代输出元素:
0, 1, 2, 3, 4, 5,
选择的顺序是和数组内存布局一致的。
再来一个对比的实例:
import numpy as np
a = np.arange(6).reshape(2,3)
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=", " )
print ('\n')
输出结果为:
0, 1, 2, 3, 4, 5,
0, 3, 1, 4, 2, 5,
从上述例子可以看出,a 和 a.T 的遍历顺序是一样的,也就是他们在内存中的存储顺序也是一样的。但是 a.T.copy(order = ‘C’) 的遍历结果是不同的,那是因为它和前两种的存储方式是不一样的,
控制遍历顺序:
- for x in np.nditer(a, order=‘F’):Fortran order,即是列序优先;
- for x in np.nditer(a.T, order=‘C’):C order,即是行序优先;
实例为:
import numpy as np
a = np.arange(0,60,5)
a = a.reshape(3,4)
print ('原始数组是:')
print (a)
print ('\n')
print ('原始数组的转置是:')
b = a.T
print (b)
print ('\n')
print ('以 C 风格顺序排序:')
c = b.copy(order='C')
print (c)
for x in np.nditer(c):
print (x, end=", " )
print ('\n')
print ('以 F 风格顺序排序:')
c = b.copy(order='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,
2.2 广播迭代
如果两个数组是可广播的,nditer 组合对象能够同时迭代它们。
实例:
# 假设数组 a 的维度为 3X4,数组 b 的维度为 1X4 ,则使用以下迭代器(数组 b 被广播到 a 的大小)
import numpy as np
a = np.arange(0,60,5)
a = a.reshape(3,4)
print ('第一个数组为:')
print (a)
print ('\n')
print ('第二个数组为:')
b = np.array([1, 2, 3, 4], dtype = int)
print (b)
print ('\n')
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,
03 numpy数组操作
3.1 numpy.reshape()
numpy.reshape 函数可以在不改变数据的条件下修改形状,格式为:
numpy.reshape(arr, newshape, order='C')
参数解释:
arr:要修改形状的数组
newshape:整数或者整数数组,新的形状应当兼容原有形状
order:'C' -- 按行,'F' -- 按列,'A' -- 原顺序,'k' -- 元素在内存中的出现顺序。
实例:
import numpy as np
a = np.arange(8)
print ('原始数组:')
print (a)
print ('\n')
b = a.reshape(4,2)
print ('修改后的数组:')
print (b)
输出结果为:
原始数组:
[0 1 2 3 4 5 6 7]
修改后的数组:
[[0 1]
[2 3]
[4 5]
[6 7]]
3.2 numpy.ndarray.flat()
numpy.ndarray.flat 是一个数组元素迭代器,相当于把每个元素单独成行。
实例:
import numpy as np
a = np.arange(9).reshape(3,3)
print ('原始数组:')
for row in a:
print (row)
#对数组中每个元素都进行处理,可以使用flat属性,该属性是一个数组元素迭代器:
print ('迭代后的数组:')
for element in a.flat:
print (element)
输出结果为:
原始数组:
[0 1 2]
[3 4 5]
[6 7 8]
迭代后的数组:
0
1
2
3
4
5
6
7
8
3.3 numpy.ndarray.flatten()
numpy.ndarray.flatten 返回一份数组拷贝,对拷贝所做的修改不会影响原始数组,格式为:
ndarray.flatten(order='C')
其中,order:‘C’ – 按行,‘F’ – 按列,‘A’ – 原顺序,‘K’ – 元素在内存中的出现顺序。
实例为:
import numpy as np
a = np.arange(8).reshape(2,4)
print ('原数组:')
print (a)
print ('\n')
# 默认按行
print ('展开的数组:')
print (a.flatten()) #按行展开为一行
print ('\n')
print ('以 F 风格顺序展开的数组:')
print (a.flatten(order = 'F')) #按列展开为一行
输出结果为:
原数组:
[[0 1 2 3]
[4 5 6 7]]
展开的数组:
[0 1 2 3 4 5 6 7]
以 F 风格顺序展开的数组:
[0 4 1 5 2 6 3 7]
3.4 numpy.ravel()
numpy.ravel() 展平的数组元素,顺序通常是"C风格",修改会影响原始数组(与flatten的区别)。
3.5 numpy.transpose()
numpy.transpose 函数用于对换数组的维度(类似于numpy.ndarray.T),格式为:
numpy.transpose(arr, axes)
#arr:要操作的数组
#axes:整数列表,对应维度,通常所有维度都会对换。
实例为:
import numpy as np
a = np.arange(12).reshape(3,4)
print ('原数组:')
print (a )
print ('\n')
print ('对换数组:')
print (np.transpose(a))
输出结果为:
原数组:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
对换数组:
[[ 0 4 8]
[ 1 5 9]
[ 2 6 10]
[ 3 7 11]]
3.6 numpy.rollaxis()
numpy.rollaxis 函数向后滚动特定的轴到一个特定位置,格式为:
numpy.rollaxis(arr, axis, start)
# arr:数组
# axis:要向后滚动的轴,其它轴的相对位置不会改变
# start:默认为零,表示完整的滚动。会滚动到特定位置。
3.7 numpy.swapaxes()
numpy.swapaxes 函数用于交换数组的两个轴,格式为:
numpy.swapaxes(arr, axis1, axis2)
# arr:输入的数组
# axis1:对应第一个轴的整数
# axis2:对应第二个轴的整数
3.8 numpy.broadcast()
numpy.broadcast 用于模仿广播的对象,它返回一个对象,该对象封装了将一个数组广播到另一个数组的结果。
3.9 numpy.broadcast_to()
numpy.broadcast_to 函数将数组广播到新形状。实例为:
import numpy as np
a = np.arange(4).reshape(1,4)
print ('原数组:')
print (a)
print ('\n')
print ('调用 broadcast_to 函数之后:')
print (np.broadcast_to(a,(4,4)))
输出结果为:
[[0 1 2 3]]
调用 broadcast_to 函数之后:
[[0 1 2 3]
[0 1 2 3]
[0 1 2 3]
[0 1 2 3]]
3.10 其他
numpy.expand_dims 函数通过在指定位置插入新的轴来扩展数组形状。
numpy.squeeze 函数从给定数组的形状中删除一维的条目。
格式:
numpy.expand_dims(arr, axis)
# arr:输入数组
# axis:新轴插入的位置
numpy.squeeze(arr, axis)
# axis:整数或整数元组,用于选择形状中一维条目的子集
连接数组的函数:
分割数组的函数:
实例为:
import numpy as np
a = np.arange(9)
print ('第一个数组:')
print (a)
print ('\n')
print ('将数组分为三个大小相等的子数组:')
b = np.split(a,3)
print (b)
print ('\n') #输出为:[array([0, 1, 2]), array([3, 4, 5]), array([6, 7, 8])]
print ('将数组在一维数组中表明的位置分割:')
b = np.split(a,[4,7])
print (b) #输出为:[array([0, 1, 2, 3]), array([4, 5, 6]), array([7, 8])]
数组元素的添加与删除函数:
数组元素的函数较多,大概了解有什么操作,需要的时候再搜索即可。
3.11 位运算
除去数组运算,numpy还有位运算。
位运算是一种在二进制数字的位级别上进行操作的一类运算,是直接操作二进制数字的各个位,而不考虑数字的整体值。
NumPy bitwise_ 开头的函数是位运算函数。
一些常用函数:
也可以使用操作符进行计算:
- & 与运算
- | 或运算
- ^ 异或运算
- ~ 取反运算
- << 左移运算
- >>右移运算