1、数组简介
NumPy时一个python库,主要用于高效地处理多维数组和矩阵计算。它是科学计算领域中使用最广泛地一个库。在NumPy中,数组是最核心地概念,用于存储和操作数据。NumPy数组是一种多维对象,可以存储相同类型的元素,它支持高效的数学运算和线性代数操作。
1)数据类型
numpy数组要求其中的元素必须是同一个类型,虽然丧失了一些灵活性,却带来了性能的极大提升。numpy的数组中如果有字符串,那么所有的提升都变成字符类型。再进行数学运算时会报错,如下所示:
python
import numpy as np
arr=np.array([2,"hello",5.5])
arr+1
报错如下:
python
UFuncTypeError Traceback (most recent call last)
<ipython-input-5-6a2b42e30679> in <module>
2
3 arr=np.array([2,"hello",5.5])
----> 4 arr+1
UFuncTypeError: ufunc 'add' did not contain a loop with signature matching types (dtype('<U11'), dtype('<U11')) -> dtype('<U11')
numpy的标准数据类型主要是各类数值类型,毕竟这个库主要就是用来做数值运算的。numpy支持如:
- 整数:int8, int16, int32, int64
- 浮点数:float32,float64
- 复数:complex32, complex64
- numpy还支持一些特殊类型,如布尔型(bool), 无类型(void)
选择数据类型时,注意考虑数据类型的内存占用和计算效率,以选择最优的数据类型。
2)维、秩和轴
numpy数组的维度,秩和轴这三个概念经常使用。其中维度和轴是同样的,维度是编程中常用的说法,轴是线性代数中常用的说法。
numpy中维度或轴的信息是通过shape数学获取,比如:
python
import numpy as np
arr=np.array([[[4,5,6],[7,8,9]]])
print(arr.shape)
输出结果:
bash
(1, 2, 3)
这个数组有3个维度(轴),但是每个维度(轴)方向的长度不一样,分别是1,2,3。
秩是指轴的个数,也是维度的数目,比如上面的数组,秩是3.num中秩的信息是通过ndim属性来获取的,比如:
python
print(arr.ndim)
输出结果:
cpp
3
3) 创建方式
学习numpy的数组,最重要的目的就是掌握如何运用numpy的数组来进行数值计算。学习numpy数组的各类运算操作之前,掌握numpy提供的各种数组创建方法必不可少。numpy提供了多种数组创建方法,每种方式都有优点和意义。根据实际需求,选择合适的创建方式可以方便地创建具有特定形状和大小地数组,并为其分配内存空间,方便后续高效的学习各种数学运算和线性代数操作。
3.1)zeros
zeros方法可以创建指定维度和类型的数组,数组的每个元素都是0。
如下一维数组,类型分别未int和float的数组:
python
arr1=np.zeros(5, dtype=int)
print('arr1=', arr1)
arr2=np.zeros(5,dtype=float)
print('arr2=',arr2)
结果如下:
bash
arr1= [0 0 0 0 0]
arr2= [0. 0. 0. 0. 0.]
不同维度的数组:
python
arr1=np.zeros((2,4), dtype=int)
print(arr1, arr1.shape)
arr2=np.zeros((4,2),dtype=float)
print(arr2, arr2.shape)
运行结果:
bash
[[0 0 0 0]
[0 0 0 0]] (2, 4)
[[0. 0.]
[0. 0.]
[0. 0.]
[0. 0.]] (4, 2)
3.2) ones
ones方法可以创建指定维度和类型的数组,数组的每个元素都是1。
如下一维,类型分别为int和float的数组:
python
arr1=np.ones(6,dtype=int)
print('arr1=',arr1)
arr2=np.ones(6,dtype=float)
print('arr2=',arr2)
运行结果:
bash
arr1= [1 1 1 1 1 1]
arr2= [1. 1. 1. 1. 1. 1.]
不同维度的数组:
python
arr1=np.ones((2,4), dtype=int)
print(arr1, arr1.shape)
arr2=np.ones((4,2),dtype=float)
print(arr2,arr2.shape)
运行结果:
bash
[[1 1 1 1]
[1 1 1 1]] (2, 4)
[[1. 1.]
[1. 1.]
[1. 1.]
[1. 1.]] (4, 2)
3.3 linspace
linspace函数用来构建均匀分布的数组。
比如,创建一个均匀分布在-1-1之间的5个数值的数组。
python
arr=np.linspace(-1,1,5)
print(arr)
运行结果:
python
[-1. -0.5 0. 0.5 1. ]
linspace函数有个endpoint属性,用来控制是否包含最后一个元素。下面看看这个属性数值之后的区别:
python
arr=np.linspace(-1,1,5,endpoint=False)
print(arr)
运行结果:
python
[-1. -0.6 -0.2 0.2 0.6]
3.4 random
random函数是随机生成numpy数组,也是使用最多的函数。
随机生成值在-1-1之间的数组,可以指定任意维度:
python
arr=np.random.random((2,2))
print(arr)
运行结果如下:
python
[[0.47359842 0.04653416]
[0.48031469 0.81854343]]
随机生成在-50-50之间整体数组,可以指定任意维度,随机值的范围通过第一个和第二个参数指定。
python
arr=np.random.randint(-50,50,(3,3))
print(arr)
结果如下:
python
[[ -4 -39 6]
[ 41 -48 -30]
[ 41 -10 -49]]
随机生成一个均值为0,标准差为1的符合正态分布的数组,可以指定任意维度,均值和标准差通过第一个和第二个参数指定。
python
arr=np.random.normal(0,1,(3,3))
print(arr)
运行结果:
python
[[ 0.51650172 -1.51973535 0.46436314]
[-1.15680603 0.25093223 1.49028425]
[ 0.52343226 0.26129063 0.60616028]]
3.5 eye
eye函数是用来创建单位矩阵的。如果只有一个参数,创建的就是方阵。
python
arr=np.eye(3)
print(arr)
运行结果:
python
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
如果创建行列不一样的矩阵,那么,行和列哪个轴短,就以哪个为准生成方阵,其它值都是0.
python
arr1=np.eye(2,4)
print(arr1)
arr2=np.eye(4,2)
print(arr2)
运行结果:
python
[[1. 0. 0. 0.]
[0. 1. 0. 0.]]
[[1. 0.]
[0. 1.]
[0. 0.]
[0. 0.]]
4)总结
本文介绍了numpy中最重要的概念,数组的相关知识。包括数组的数据类型,以及各类常用的创建方式(zeros, ones, linspace, random,eye)。
2 基础操作
numpy作为一个强大的数值计算库,提供了对多维数组的很多便捷操作。此处第二部分主要介绍一些数组的基本操作。
1)子数组
首先介绍获取子数组的方法,提取已有数据的一部分来参与计算是比较常用的功能。
对于一维数组,提取子数组:
python
arr[start:stop:step]
- start:从哪个下标开始(下标从0开始)
- stop:到哪个下标结束(下标不包括stop这个值)
- step:间隔几个元素。
python
arr=np.array(range(10))
print(arr)
print(arr[::2])
print(arr[1::2])
print(arr[1:6:2])
print(arr[::-1])
运行结果:
python
[0 1 2 3 4 5 6 7 8 9]
[0 2 4 6 8]
[1 3 5 7 9]
[1 3 5]
[9 8 7 6 5 4 3 2 1 0]
对于多维数组,同样可以使用以上方式,数组有几维,就可以使用几次start:stop:step。比如以下二维数组:
python
arr=np.random.randint(0,20,(4,5))
print(arr)
print(arr[::2,::2])
运行结果:
python
[[ 5 8 12 19 5]
[19 2 11 0 2]
[10 8 16 17 6]
[ 0 9 15 3 10]]
[[ 5 12 5]
[10 16 6]]
也就是按取第1,3行,然后按列取第1,3,5列。
2)数组副本
当提取子数组后,如果对子数组进行修改,那么原始的数组会发生变化。这是因为数组是引用类型,当数组的数据量很大时,内存占用会比较低。比如:
python
arr=np.array(range(5))
print('arr=',arr)
arr2=arr[::2]
print('arr2=',arr2)
arr2[1]=100
print('arr=',arr)
运行结果如下:
python
arr= [0 1 2 3 4]
arr2= [0 2 4]
arr= [ 0 1 100 3 4]
子数组修改之后,原始数组也改变了。
如果要避免修改原始数组,就要建立子数组的副本,也就是copy方法。
python
arr=np.array(range(5))
print('arr=',arr)
arr2=arr[::2].copy()
print('arr2=',arr2)
arr2[1]=100
print('arr=',arr)
print('arr2=',arr2)
运行结果:
python
arr= [0 1 2 3 4]
arr2= [0 2 4]
arr= [0 1 2 3 4]
arr2= [ 0 100 4]
3)数组变行
进行数组分析时,我们常常得到的是线性的数据序列,也就是一维数组,在numpy中,从一维变成多维非常方便。
python
# list对象
arr=list(range(8))
print(arr)
# 通过numpy的array对象将list对象转成了numpy数组对象
arr=np.array(arr).reshape((2,4))
print(arr)
运行结果:
python
[0, 1, 2, 3, 4, 5, 6, 7]
[[0 1 2 3]
[4 5 6 7]]
注意:变换前后元素的总数量是相同,比如,上面的例子中,变换前有8个元素,变换成2*4的二维数组,也是8个元素。
除了二维数组,变换成3维数组也是一样的:
python
arr=np.array(range(30)).reshape((2,3,5))
print(arr)
运行结果:
python
[[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
[[15 16 17 18 19]
[20 21 22 23 24]
[25 26 27 28 29]]]
4)拼接和拆分
最后一个基本操作是拼接和拆分。
4.1 拼接
拼接有两个方向,水平拼接和垂直拼接,拼接的数组个数不限。比如,下面的示例是三个数组拼接在一起。
python
arr1=np.array([range(1,4),range(1,4),range(1,4)])
arr2=np.array([range(4,7),range(4,7),range(4,7)])
arr3=np.array([range(7,10),range(7,10),range(7,10)])
arr=np.concatenate([arr1,arr2,arr3])
print(arr)
arr=np.concatenate([arr1,arr2,arr3],axis=1)
print(arr)
运行结果:
python
[[1 2 3]
[1 2 3]
[1 2 3]
[4 5 6]
[4 5 6]
[4 5 6]
[7 8 9]
[7 8 9]
[7 8 9]]
[[1 2 3 4 5 6 7 8 9]
[1 2 3 4 5 6 7 8 9]
[1 2 3 4 5 6 7 8 9]]
concatenate函数用来拼接数组,默认是垂直方向拼接,设置axis=1,按照水平方向凭借。
如果觉得参数麻烦,记不住哪个是水平拼接,哪个是垂直拼接,还有两个专门拼接的函数,vstack(垂直拼接)和hstack(水平拼接)。
python
arr1=np.array([range(1,4),range(1,4),range(1,4)])
arr2=np.array([range(4,7),range(4,7),range(4,7)])
arr3=np.array([range(7,10),range(7,10),range(7,10)])
arr=np.vstack([arr1,arr2,arr3])
print(arr)
arr=np.hstack([arr1,arr2,arr3])
print(arr)
运行结果:
python
[[1 2 3]
[1 2 3]
[1 2 3]
[4 5 6]
[4 5 6]
[4 5 6]
[7 8 9]
[7 8 9]
[7 8 9]]
[[1 2 3 4 5 6 7 8 9]
[1 2 3 4 5 6 7 8 9]
[1 2 3 4 5 6 7 8 9]]
4.2 拆分
拆分数组时,通过设置拆分点的下标,可以将数组拆分成任意长度的多个数组,如:
python
arr=np.array(range(10))
arr1=np.split(arr,[1,5])
print(arr1)
运行结果:
python
[array([0]), array([1, 2, 3, 4]), array([5, 6, 7, 8, 9])]
上面的示例中,下标1对应的值是2,下标5对应的值是5,有两个拆分点,所以拆分成3个数组。
同样,数组的才分也有两个简便方法:
vsplit和hsplit。拆分多维数组时,可以按照垂直和水平两个方向拆。
python
arr=np.array(range(9)).reshape((3,3))
print(arr)
print(np.vsplit(arr,[1]))
print(np.hsplit(arr,[1]))
运行结果如下:
python
[[0 1 2]
[3 4 5]
[6 7 8]]
[array([[0, 1, 2]]), array([[3, 4, 5],
[6, 7, 8]])]
[array([[0],
[3],
[6]]), array([[1, 2],
[4, 5],
[7, 8]])]
垂直拆分时,拆分点是下标1的行,也就是从第二行开始拆分。水平拆分时,拆分点时下标1的列,也就是从第二列开始拆分。
5)总结
此处主要介绍的是numpy数组的基本操作。包括:
- 提取子数组。
- 创建数组副本
- 数组变形
- 拼接和拆分
3 通用计算
numpy提供了简单灵活的接口,用于优化数据数组的计算。通用计算最大的优势在于通过向量化操作。将循环推送到numpy之下的编译层,从而取得更快的执行效率。
numpy的通用计算让我们计算数组时就像计算单独一个变量一样,不用写循环去遍历数组中各个元素。比如,对于一般的python二维数组。我们要给数组中每个值加1:
python
l=[[1,2],[3,4]]
print(l)
for i in range(len(l)):
for j in range(len(l[i])):
l[i][j] += 1
print(l)
运行结果如下:
python
[[1, 2], [3, 4]]
[[2, 3], [4, 5]]
如果用numpy的通用计算的话:
python
l=[[1,2],[3,4]]
print(l)
# 将一般二维数组转成numpy二维数组
arr=np.array(l)
print(arr)
arr = arr+1
print(arr)
运行结果:
python
[[1, 2], [3, 4]]
[[1 2]
[3 4]]
[[2 3]
[4 5]]
1)算术计算
算术计算是最基本的,numpy数组支持直接用运算符或者通用函数来进行运算。
|------|-----------------|------|
| 运算符 | 通用函数 | 说明 |
| + | np.add | 加法 |
| - | np.subtract | 减法 |
| * | np.multiply | 乘法 |
| / | np.divide | 触发 |
| // | np.floor_divide | 向下整除 |
| ** | np.power | 指数运算 |
| % | np.mod | 模运算 |
需要注意,当numpy数组和单一数值运算时,数组中每个元素都单独和此数字进行运算。
python
arr=np.array(range(1,9)).reshape((2,4))
print(arr)
print(arr*2)
arr*2相当于arr中每个元素都乘以2。
当numpy数组和另一个数组运算时,是两个数组对应位置的元素进行运算。这就要求两个数组的shape要一样,否则会出错。
python
arr1=np.array(range(1,5)).reshape((2,2))
print(arr1)
arr2=np.array(range(6,10)).reshape((2,2))
print(arr2)
print(arr1*arr2)
运行结果:
python
[[1 2]
[3 4]]
[[6 7]
[8 9]]
[[ 6 14]
[24 36]]
结果对应元素相乘。
2)三角函数
2.1 三角函数
python
arr=np.array([0,np.pi/6,np.pi/4,np.pi/2])
print("sin(arr) = ",np.sin(arr))
print("cos(arr) = ",np.cos(arr))
print("tan(arr) = ",np.tan(arr))
运行结果:
python
sin(arr) = [0. 0.5 0.70710678 1. ]
cos(arr) = [1.00000000e+00 8.66025404e-01 7.07106781e-01 6.12323400e-17]
tan(arr) = [0.00000000e+00 5.77350269e-01 1.00000000e+00 1.63312394e+16]
2.2 反三角函数
python
arr=np.array([-1,0,1])
print("arcsin(arr) = ",np.arcsin(arr))
print("arccos(arr) = ",np.arccos(arr))
print("arctan(arr) = ",np.arctan(arr))
运行结果:
python
arcsin(arr) = [-1.57079633 0. 1.57079633]
arccos(arr) = [3.14159265 1.57079633 0. ]
arctan(arr) = [-0.78539816 0. 0.78539816]
3) 指数和对数
3.1 指数
python
x=np.array([1,2,3,10])
print("e^2 = ",np.exp(x))
print("2^x = ",np.exp2(x))
print("3^x = ", np.power(3,x))
运行结果:
python
e^2 = [2.71828183e+00 7.38905610e+00 2.00855369e+01 2.20264658e+04]
2^x = [ 2. 4. 8. 1024.]
3^x = [ 3 9 27 59049]
3.2 对数
python
x=np.array([1,2,3,10])
print("ln(x) = ",np.log(x))
print("log2(x) = ",np.log2(x))
print("log10(x) = ",np.log10(x))
运行结果:
python
ln(x) = [0. 0.69314718 1.09861229 2.30258509]
log2(x) = [0. 1. 1.5849625 3.32192809]
log10(x) = [0. 0.30103 0.47712125 1. ]
4) 通用特性
除了通用的计算方法,还有一些也很有用。下面介绍两个常用的,一个可以节约内存,提高程序的运行效率;另一个可以简化编码,提供程序的编程效率。
4.1 指定输出位置
进行两个数组的计算时,比如x数组和y数组,计算的结果常常要用新的数组(比如z数组)来保存。
如果计算之后x数组或y数组不再需要的话,我们可以把运算结果保存在x数组或y数组中,这些就不用申请新的内容。
python
x=np.random.randint(1,10,(2,3))
y=np.random.randint(1,10,(2,3))
print(x)
print(y)
np.multiply(x,y,out=x)
print(x)
运行结果:
python
[[3 7 8]
[2 5 5]]
[[5 1 6]
[6 3 4]]
[[15 7 48]
[12 15 20]]
设置参数out=y,可以看到计算结果保存在x数组中了。
4.2 简单的聚合
对于任何一个数组,按行或列聚合合计值时:
python
x=np.random.randint(1,10,(2,4))
print(x)
# 每列的合计值
print(np.add.reduce(x))
# 每列的合计值
print(np.add.reduce(x,axis=1))
运行结果:
python
[[2 3 2 5]
[1 7 5 9]]
[ 3 10 7 14]
[12 22]
上面是用np.add来聚合,也可以使用np.multiply, np.divide等等前面介绍的各种算术计算。
除了聚合合计值,numpy还提供了一个可以计算合计过程中每步计算结果的方法accumulate。
python
x=np.random.randint(1,10,5)
print(x)
print(np.add.accumulate(x))
print(np.multiply.accumulate(x))
运行结果:
python
[5 8 3 9 8]
[ 5 13 16 25 33]
[ 5 40 120 1080 8640]
5)总结回顾
本篇主要介绍了numpy数组的通用计算方法,通用计算把数组元素循环的复杂度封装起来。
4 聚合计算
上篇介绍的通用计算是关于多个numpy数组的计算,本篇介绍的聚合计算一般是针对单个数据集的各种统计结果,同样,使用聚合函数,也可以避免繁琐的循环语句的编写。
1)元素的和
数组中的元素求和也就是合计值。
1.1 调用方式
聚合计算有两种调用方式,一种是面向对象的方式,作为numpy数组对象的方式来调用:
python
arr=np.random.randint(1,10,(2,4))
print(arr)
print(arr.sum())
运行结果:
python
[[7 4 2 7]
[8 5 6 1]]
40
另一种是函数式调用的方式:
python
arr=np.random.randint(1,10,(2,4))
print(arr)
print(np.sum(arr))
运行结果:
python
[[8 4 8 3]
[3 8 5 9]]
48
下面演示各种聚合计算的方法时,都采用函数式调用的方法。
1.2 整体统计
整体统计就是统计数组所有值的和。
python
arr=np.random.randint(1,10,(2,4))
print(arr)
np.sum(arr)
运行结果:
python
[[3 1 7 1]
[6 7 9 2]]
36
1.3 按维度统计
比如上面的二维数组,按维度统计就是按行或列来统计,而不是把所有值加在一起。
python
arr=np.random.randint(1,10,(2,4))
print(arr)
# 统每列的合计值
print(np.sum(arr, axis=0))
# 统计每行的合计值
print(np.sum(arr, axis=1))
运行结果:
python
[[7 6 4 7]
[9 1 5 2]]
[16 7 9 9]
[24 17]
2) 元素的积
元素的积的聚合统计就是各个元素相乘的结果,对应的函数是:np.prod
2.1 按整体计算
python
arr=np.random.randint(1,5,(2,4))
print(arr)
print(np.prod(arr))
运行结果:
python
[[4 4 4 2]
[3 4 2 4]]
12288
2.2 按维度计算
python
arr=np.random.randint(1,5,(2,4))
print(arr)
# 按列聚合,就是列号相同,所有不同行号的元素相乘
print(np.prod(arr, axis=0))
# 按行聚合,就是行号相同,所有不同列号的元素相乘
print(np.prod(arr, axis=1))
运行结果:
python
[[1 1 3 1]
[1 3 2 3]]
[1 3 6 3]
[ 3 18]
3)元素的平均值和中位值
平均值对应的函数是:np.mean, 中位数对应的函数是:np.median。
3.1 整体统计
python
arr=np.random.randint(1,5,(2,4))
print(arr)
print(np.mean(arr))
print(np.median(arr))
运算结果:
python
[[2 4 3 4]
[2 3 3 4]]
3.125
3.0
3.2 按维度统计
python
arr=np.random.randint(1,5,(2,4))
print(arr)
print(np.mean(arr, axis=0))
print(np.mean(arr, axis=1))
print(np.median(arr, axis=0))
print(np.median(arr, axis=1))
运行结果:
python
[[1 1 1 4]
[2 4 3 4]]
[1.5 2.5 2. 4. ]
[1.75 3.25]
[1.5 2.5 2. 4. ]
[1. 3.5]
4) 元素的标准差和方差
标准差对应的函数是:np.std,方差对应的函数是np.var
4.1 整体统计
python
arr=np.random.randint(1,5,(2,4))
print(arr)
print(np.std(arr))
print(np.var(arr))
运算结果:
python
[[2 3 2 3]
[1 1 3 4]]
0.9921567416492215
0.984375
4.2 按维度统计
python
arr=np.random.randint(1,5,(2,4))
print(arr)
# 按列统计标准差
print(np.std(arr, axis=0))
# 按列统计方差
print(np.std(arr, axis=1))
# 按行统计标准差
print(np.var(arr, axis=0))
# 按行统计方差
print(np.var(arr, axis=1))
运行结果:
python
[[3 4 4 3]
[3 2 4 2]]
[0. 1. 0. 0.5]
[0.5 0.8291562]
[0. 1. 0. 0.25]
[0.25 0.6875]
5) 最大值和最小值
最大值对应的函数是:np.max,最小值对应的函数是:np.min。
5.1 整体统计
python
arr=np.random.randint(1,10,(2,4))
print(arr)
print(np.max(arr))
print(np.min(arr))
运行结果:
python
[[7 2 7 1]
[7 4 1 1]]
5.2 按维度统计
python
arr=np.random.randint(1,10,(2,4))
print(arr)
# 统计每列的最大值
print(np.max(arr, axis=0))
# 统计每行的最大值
print(np.max(arr, axis=1))
# 统计每列的最小值
print(np.min(arr, axis=0))
# 统计每行的最小值
print(np.min(arr, axis=1))
运行结果:
python
[[7 7 8 7]
[9 3 6 9]]
[9 7 8 9]
[8 9]
[7 3 6 7]
[7 3]
6) 累积和和累积积
数组中逐元素累加和累积
python
arr=np.random.randint(1,10,(2,2))
print(arr)
# 逐元素累加和
print(np.cumsum(arr))
# 逐元素累积积
print(np.cumprod(arr))
7)最大值下标和最小值下标
python
arr=np.random.randint(1,10,(2,2))
print(arr)
print(np.argmax(arr))
print(np.argmin(arr))
运行结果:
python
[[5 9]
[3 8]]
1
2
8) 总结回顾
本片介绍最常用的聚合计算;集合计算通常用于数据进行处理和分析,以及实现高级的数据分析算法。
5 广播计算
numpy的广播计算是指在多维数组上进行的一种高效计算方法。它可以将计算任务分配到每个维度上,并且可以在计算过程中进行数据共享和同步,从而提高计算效率。
广播计算在数值计算,科学计算,机器学习等领域都有广泛的应用。例如,在数值计算中,广播计算可以用于求解大规模的非线性方程组;在科学计算中,广播计算可以用于模拟和预测自然现象;在机器学习中,广播可以用于分布式训练和推离等场景。
numpy中广播计算遵循3个严格的规则:
1)如果两个数组的维度数不同,小维度数组的形状将会在最左边补1。
2)如果两个数组的形状在任何一个维度上都不匹配,那么数组的形状沿着维度为1的维度扩展以匹配另一个数组的形状。
3)如果两个数组的形状在任何一个维度上都不匹配并且没有任何一个维度等于1,那么会引发异常。
1) 广播规则1
二维数组和一个数值的运算:
python
arr=np.random.randint(1,10,(2,3))
print(arr)
print(arr+1)
print(arr*2)
运行结果:
python
[[4 1 1]
[1 9 1]]
[[ 5 2 2]
[ 2 10 2]]
[[ 8 2 2]
[ 2 18 2]]
arr+1时,1被自动扩充为全1的2*3矩阵,和arr一样结构的数组。arr*2时,同样,2被自动扩充为全2的2*3矩阵,和arr一样结构的数组。
二维数组和一维数组运算:
python
arr1=np.random.randint(1,10,(2,3))
print(arr1)
arr2=np.random.randint(1,10,3)
print(arr2)
print(arr1+arr2)
运行结果:
python
[[7 7 8]
[8 1 8]]
[9 6 9]
[[16 13 17]
[17 7 17]]
这种情况下,arr2和arr1都是3列,只是行数不一样,所以arr2被自动扩展成:
python
[[9 6 9]
[9 6 9]]
然后再和arr1对应的位置进行加法运算。
2) 广播规则2
每个数组每个维度上的数组都不一样,但另一个维度为1,比如以下两个数组的运算:
python
arr1=np.random.randint(1,10,(1,3))
print(arr1)
arr2=np.random.randint(1,10,(2,1))
print(arr2)
print(arr1+arr2)
运行结果:
python
[[8 5 2]]
[[8]
[3]]
[[16 13 10]
[11 8 5]]
arr1是1行3列的数组,所以arr1自动扩展了行,保持和arr2一致:
python
[[[8 5 2]]
[[8 5 2]]]
arr2是2行1列的数组,所以arr2自动扩充了列,保持与arr1一致:
python
[[8 8 8]
[3 3 3]]
3) 广播规则3
两个维度不一样的数组,在另一个维度上,数目也不为1。
python
arr1=np.random.randint(1,10,(2,3))
print(arr1)
arr2=np.random.randint(1,10,(3,1))
print(arr2)
print(arr1+arr2)
运行结果:
python
[[4 4 3]
[7 4 8]]
[[6]
[4]
[1]]
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-147-c8ba268f1ba5> in <module>
4 print(arr2)
5
----> 6 print(arr1+arr2)
ValueError: operands could not be broadcast together with shapes (2,3) (3,1)
arr1是2行3列的数组,arr2是3行1列的数组。运算时,arr2可以扩充成3列,但arr1无法扩充成3行,因为arr1行的维度和arr2不一样也不等于1。
4) 总结回顾
numpy的广播计算虽然简单,但对数据分析却很有意义:
1)提高计算效率,广播计算可以将计算任务分配到每个维度上,从而减少计算时间,提高计算效率。
2)减少内存占用:广播计算可以在多个维度上同时进行计算,从而减少需要存储的数据量,减少内存占用。
3)支持并行计算:numpy的广播计算可以支持多线程和多GPU并行计算,从而提高计算速度。
4)易于并发编程:numpy的广播计算提供了一个并发编程的方式,可以方便实现多线程和多GPU并行计算。