广播的实际应用
01.
数组的归一化
在前面的一节中,我们看到通用函数让
NumPy
用户免于写很慢的
Python
循环。广播进一步扩展了这个功能,一个常见的例子就是数
组数据的归一化。假设你有一个有
10
个观察值的数组,每个观察
值包含
3
个数值。
我们将用一个
10×3
的数组存放该数据:
X = np.random.random((10, 3))
X
array([[0.55264619, 0.0669091 , 0.30293985],
[0.91052963, 0.03485153, 0.74247044],
[0.50012938, 0.68384604, 0.12966619],
[0.11133564, 0.20995151, 0.41285416],
[0.72184877, 0.46878861, 0.67614857],
[0.00367248, 0.79193403, 0.7893964 ],
[0.03832598, 0.16219652, 0.98850594],
[0.09408313, 0.97329599, 0.15448008],
[0.76594461, 0.77699128, 0.88225423],
[0.17258578, 0.2612646 , 0.64148811]])
我们可以计算每个特征的均值,计算方法是利用
mean
函数沿着第
一个维度聚合:
Xmean = X.mean(0)
Xmean
array([0.38711016, 0.44300292, 0.5720204 ])
现在通过从 X 数组的元素中减去这个均值实现归一化(该操作是一 个广播操作):
为了进一步核对我们的处理是否正确,可以查看归一化的数组的均 值是否接近 0:
X_centered = X - Xmean
X_centered.mean(0)
array([-3.88578059e-17, -1.11022302e-17, 2.22044605e-17])
在机器精度范围内,该均值为
0
。
02.
画一个二维函数
广播另外一个非常有用的地方在于,它能基于二维函数显示图像。
我们希望定义一个函数
z
=
f
(
x
,
y
)
,可以用广播沿着数值区间计算
该函数
# x和y表示0~5区间50个步长的序列
x = np.linspace(0, 5, 50)
y = np.linspace(0, 5, 50)[:, np.newaxis]
z = np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x)
#我们将用 Matplotlib 来画出这个二维数组:
%matplotlib inline
import matplotlib.pyplot as plt
plt.imshow(z, origin='lower', extent=[0, 5, 0, 5], cmap='viridis')
plt.colorbar();
结果如图
2-5
所示,这是一个引人注目的二维函数可视化。
图
2-5
:一个二维数值的可视化
示例:统计下雨天数
假设你有一系列表示某城市一年内日降水量的数据,这里将用
Pandas后面会介绍
加载
2014
年西雅图市的日降水统计数
据:
import numpy as np
import pandas as pd # 利用Pandas抽取降雨量,放入一个NumPy数组
rainfall = pd.read_csv('C:\\Users\\Administrator\\Desktop\\shuju\\Seattle2014.csv')['PRCP'].values
inches = rainfall / 254 # 1/10mm -> inches
inches.shape
(365,)
这个数组包含
365
个值,给出了从
2014
年
1
月
1
日至
2014
年
12
月
31
日每天的降水量。这里降水量的单位是英寸。
首先做一个快速的可视化,用
Matplotlib
(将在后面章节学习)生成下雨天数的直方图,如图
2-6
所示:
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn; seaborn.set() # 设置绘图风格
plt.hist(inches, 40);
图
2-6
:
2014
年西雅图市降水量直方图
该直方图表明了这些数据的大意:尽管人们对西雅图市有刻板印象,但
是
2014
年它大多
数时间的降水量都是接近
0
的。但是这样做并没有很好地传递出我们希
望看到的某些信息,例如一年中有多少天在下雨,这些下雨天的平均降
水量是多少,有多少天的降水量超过了半英寸?
和通用函数类似的比较操作
2.3
节介绍了通用函数,并且特别关注了算术运算符。我们看到用
+
、
-
、
*
、
/
和其他一些运算符实现了数组的逐元素操作。
NumPy
还实
现了如
<
(小于)和
>
(大于)的逐元素比较的通用函数。这些比较运
算的结果是一个布尔数据类型的数组。一共有
6
种标准的比较操作:
x = np.array([1, 2, 3, 4, 5])
x < 3 # 小于
array([ True, True, False, False, False])
x > 3 # 大于
array([False, False, False, True, True])
另外,利用复合表达式实现对两个数组的逐元素比较也是可行的:
(2 * x) == (x ** 2)
array([False, True, False, False, False])
和算术运算符一样,比较运算操作在
NumPy
中也是借助通用函数来实
现的。例如当你写
x < 3
时,
NumPy
内部会使用
np.less(x, 3)。这些比较运算符和其对应的通用函数如下表所示。
和算术运算通用函数一样,这些比较运算通用函数也可以用于任意形
状、大小的数组。下面是一个二维数组的示例:
这样每次计算的结果都是布尔数组了。
NumPy
提供了一些简明的模式
来操作这些布尔结果。