- 4.1 The NumPy ndarray 多维数组对象
- 4.2 Universal Functions 通用函数
- 4.3 Array-Oriented Programming with Arrays 数组导向编程
- 5.1 Introduction to pandas Data Structures pandas 的数据结构
- 5.2 Essential Functionality 主要功能
- 5.3 Summarizing and Computing Descriptive Statistics 汇总和描述性统计
- 7.1 Handling Missing Data 处理缺失数据
- 7.2 Data Transformation 数据变换
- 7.3 String Manipulation 字符串处理
- 11.1 Date and Time Data Types and Tools 日期和时间数据类型及其工具
- 11.2 Time Series Basics 时间序列基础
- 11.3 Date Ranges, Frequencies, and Shifting 日期范围,频度,和位移
- 12.1 Categorical Data 类别数据
- 14.1 USA.gov Data from Bitly USA.gov 数据集
- 14.2 MovieLens 1M Dataset MovieLens 1M 数据集
- 14.3 US Baby Names 1880–2010 1880年至2010年美国婴儿姓名
4.3 Array-Oriented Programming with Arrays 数组导向编程
向量化的数组运算比纯 python 同等程度的运算要快很多。
一个简单的例子,假设我们想要评价函数 sqrt(x^2 + y^2)
。 np.meshgrid
函数取两个 1 维的数组,产生一个 2 维的矩阵,对应于所有两个数组中(x, y)的组合:
import numpy as np
在进行书中的内容之前,先举个例子说明 meshgrid 的效果。meshgrid 函数用两个坐标轴上的点在平面上画网格。用法:
[X,Y]=meshgrid(x,y)
[X,Y]=meshgrid(x)
与[X,Y]=meshgrid(x,x)
是等同的[X,Y,Z]=meshgrid(x,y,z)
生成三维数组,可用来计算三变量的函数和绘制三维立体图
这里,主要以 [X,Y]=meshgrid(x,y)
为例,来对该函数进行介绍。
[X,Y] = meshgrid(x,y)
将向量 x 和 y 定义的区域转换成矩阵 X 和 Y,其中矩阵 X 的行向量是向量 x 的简单复制,而矩阵 Y 的列向量是向量 y 的简单复制(注:下面代码中 X 和 Y 均是数组,在文中统一称为矩阵了)。
假设 x 是长度为 m 的向量,y 是长度为 n 的向量,则最终生成的矩阵 X 和 Y 的维度都是 nm (注意不是 mn)。
m, n = (5, 3) x = np.linspace(0, 1, m) y = np.linspace(0, 1, n) X, Y = np.meshgrid(x, y) x
array([ 0. , 0.25, 0.5 , 0.75, 1. ])
y
array([ 0. , 0.5, 1. ])
X
array([[ 0. , 0.25, 0.5 , 0.75, 1. ], [ 0. , 0.25, 0.5 , 0.75, 1. ], [ 0. , 0.25, 0.5 , 0.75, 1. ]])
Y
array([[ 0. , 0. , 0. , 0. , 0. ], [ 0.5, 0.5, 0.5, 0.5, 0.5], [ 1. , 1. , 1. , 1. , 1. ]])
可以看到 X 和 Y 的 shape 都是 3x5,把 X 和 Y 画出来后,就可以看到网格了:
import matplotlib.pyplot as plt %matplotlib inline plt.style.use('ggplot') plt.plot(X, Y, marker='.', color='blue', linestyle='none')
[<matplotlib.lines.Line2D at 0x107cddd30>, <matplotlib.lines.Line2D at 0x107cddeb8>, <matplotlib.lines.Line2D at 0x107ce5198>, <matplotlib.lines.Line2D at 0x107ce5358>, <matplotlib.lines.Line2D at 0x107ce5518>]
可以用 zip 得到网格平面上坐标点的数据:
z = [i for i in zip(X.flat, Y.flat)] z
[(0.0, 0.0), (0.25, 0.0), (0.5, 0.0), (0.75, 0.0), (1.0, 0.0), (0.0, 0.5), (0.25, 0.5), (0.5, 0.5), (0.75, 0.5), (1.0, 0.5), (0.0, 1.0), (0.25, 1.0), (0.5, 1.0), (0.75, 1.0), (1.0, 1.0)]
好了,下面继续进入书中的内容
points = np.arange(-5, 5, 0.01) # 1000 equally spaced points xs, ys = np.meshgrid(points, points) # xs 和 ys 是一样的 ys
array([[-5. , -5. , -5. , ..., -5. , -5. , -5. ], [-4.99, -4.99, -4.99, ..., -4.99, -4.99, -4.99], [-4.98, -4.98, -4.98, ..., -4.98, -4.98, -4.98], ..., [ 4.97, 4.97, 4.97, ..., 4.97, 4.97, 4.97], [ 4.98, 4.98, 4.98, ..., 4.98, 4.98, 4.98], [ 4.99, 4.99, 4.99, ..., 4.99, 4.99, 4.99]])
z = np.sqrt(xs ** 2 + ys ** 2) z
array([[ 7.07106781, 7.06400028, 7.05693985, ..., 7.04988652, 7.05693985, 7.06400028], [ 7.06400028, 7.05692568, 7.04985815, ..., 7.04279774, 7.04985815, 7.05692568], [ 7.05693985, 7.04985815, 7.04278354, ..., 7.03571603, 7.04278354, 7.04985815], ..., [ 7.04988652, 7.04279774, 7.03571603, ..., 7.0286414 , 7.03571603, 7.04279774], [ 7.05693985, 7.04985815, 7.04278354, ..., 7.03571603, 7.04278354, 7.04985815], [ 7.06400028, 7.05692568, 7.04985815, ..., 7.04279774, 7.04985815, 7.05692568]])
这里我们用 matplotlib 把图画出来:
plt.imshow(z, cmap=plt.cm.gray); plt.colorbar() plt.title("Image plot of $\sqrt{x^2 + y^2}$ for a grid of values")
<matplotlib.text.Text at 0x10dca7c18>
1 Expressing Conditional Logic as Array Operations (像数组操作一样表示逻辑条件)
numpy.where
函数是一个向量版的三相表达式, x if condition else y
。假设我们有一个布尔数组和两个数组:
xarr = np.array([1.1, 1.2, 1.3, 1.4, 1.5]) yarr = np.array([2.1, 2.2, 2.3, 2.4, 2.5]) cond = np.array([True, False, True, True, False])
假设如果 cond 中为 true,我们去 xarr 中对应的值,否则就取 yarr 中的值。列表表达式的话会这么写:
result = [(x if c else y) for x, y, c in zip(xarr, yarr, cond)] result
[1.1000000000000001, 2.2000000000000002, 1.3, 1.3999999999999999, 2.5]
这么做的话会有很多问题。首先,对于很大的数组,会比较慢。第二,对于多维数组不起作用。但 np.where
能让我们写得更简洁:
result = np.where(cond, xarr, yarr) result
array([ 1.1, 2.2, 1.3, 1.4, 2.5])
np.where
中第二个和第三个参数不用必须是数组。where 在数据分析中一个典型的用法是基于一个数组,产生一个新的数组值。假设我们有一个随机数字生成的矩阵,我们想要把所有的正数变为 2,所有的负数变为-2。用 where 的话会非常简单:
arr = np.random.randn(4, 4) arr
array([[ 2.18194474, 0.15001978, -0.77191684, 0.18716397], [ 1.2083149 , -0.22911585, 1.30880201, 0.14197253], [ 0.65639111, -1.28394185, 0.65706167, 1.14277598], [-0.32639966, -0.26880881, -0.10225964, 0.4739671 ]])
arr > 0
array([[ True, True, False, True], [ True, False, True, True], [ True, False, True, True], [False, False, False, True]], dtype=bool)
np.where(arr > 0, 2, -2)
array([[ 2, 2, -2, 2], [ 2, -2, 2, 2], [ 2, -2, 2, 2], [-2, -2, -2, 2]])
我们可以结合标量和数组。比如只把整数变为 2,其他仍未原来的数字:
np.where(arr > 0, 2, arr) # set only positive value to 2
array([[ 2. , 2. , -0.77191684, 2. ], [ 2. , -0.22911585, 2. , 2. ], [ 2. , -1.28394185, 2. , 2. ], [-0.32639966, -0.26880881, -0.10225964, 2. ]])
2 Mathematical and Statistical Methods (数学和统计方法)
一些能计算统计值的数学函数能基于整个数组,或者沿着一个 axis(轴)。可以使用 aggregations(often called reductions,汇总,或被叫做降维),比如 sum, mean, and std(标准差).
下面是一些 aggregate statistics(汇总统计):
arr = np.random.randn(5, 4) arr
array([[-1.53575656, -1.39268394, -1.02284353, -1.03165049], [ 0.53301867, 0.50258973, -0.49389656, 0.24610963], [ 0.95377174, -1.57268184, 0.42969986, 1.22912566], [ 0.73686692, -2.82328155, 0.48018497, -1.38046692], [ 0.94164808, 0.19599722, -0.88779738, -0.87556277]])
arr.mean()
-0.33838045197794597
np.mean(arr)
-0.33838045197794597
arr.sum()
-6.767609039558919
mean, sum 这样的函数能接受 axis 作为参数来计算统计数字,返回的结果维度更少:
arr.mean(axis=1)
array([-1.24573363, 0.19695537, 0.25997886, -0.74667415, -0.15642871])
arr.sum(axis=0)
array([ 1.62954886, -5.09006038, -1.49465263, -1.81244489])
这里 arr.mean(1)
表示,compute mean acros the columns(计算各列之间的平均值)。 arr.sum(0)
表示,compute sum down the rows(计算各行总和)。
其他一些方法,像 cumsum 和 cumprod 不做汇总,而是产生一个中间结果的数组:
arr = np.array([0, 1, 2, 3, 4, 5, 6, 7]) arr.cumsum()
array([ 0, 1, 3, 6, 10, 15, 21, 28])
上面的计算是一个累加的结果, 0+1=1,1+2=3,3+3=6
以此类推。
np.cumsum?
对于多维数组,accumulation functions(累积函数)比如 cumsum,返回的是同样大小的数组,但是部分聚合会沿着指示的轴向较低维度进行切片:
arr = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]) arr
array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
arr.cumsum(axis=0) # 沿着行加法
array([[ 0, 1, 2], [ 3, 5, 7], [ 9, 12, 15]])
arr.cumprod(axis=1) # 沿着列乘法
array([[ 0, 0, 0], [ 3, 12, 60], [ 6, 42, 336]])
这里有一些基本的统计计算方法:
3 Methods for Boolean Arrays(布尔数组的方法)
sum 是用来计算布尔数组中有多少个 true 的:
arr = np.random.randn(100) (arr > 0).sum() # Number of positive values
46
有两个其他方法,any 和 all,对于布尔数组特别有用。any 检测数组中只要有一个 ture 返回就是 true,而 all 检测数组中都是 true 才会返回 true。
bools = np.array([False, False, True, False])
bools.any()
True
bools.all()
False
4 Sorting(排序)
numpy 中也有 sort 方法:
np.random.randn? # 返回符合正态分布的数值
arr = np.random.randn(6) arr
array([ 1.93663555, -1.29810982, 0.83366006, 0.51674613, 2.32879117, 1.07342758])
arr.sort()
arr
array([-1.29810982, 0.51674613, 0.83366006, 1.07342758, 1.93663555, 2.32879117])
如果是多维数组,还可以按 axis 来排序:
arr = np.random.randn(5, 3) arr
array([[-0.76658562, -1.00222899, 0.39039437], [ 0.23100317, -1.0581081 , 1.69177329], [ 1.0239365 , 0.84698669, -0.97911915], [ 0.76255951, 0.27828523, 0.41807172], [ 0.40792019, -1.19514714, -1.41666804]])
arr.sort(1)
arr
array([[-1.00222899, -0.76658562, 0.39039437], [-1.0581081 , 0.23100317, 1.69177329], [-0.97911915, 0.84698669, 1.0239365 ], [ 0.27828523, 0.41807172, 0.76255951], [-1.41666804, -1.19514714, 0.40792019]])
上面是直接调用数组的 sort 方法,会改变原有数组的顺序。但如果使用 np.sort()
函数的话,会生成一个新的排序后的结果。
一个计算分位数的快捷方法是先给数组排序,然后选择某个排名的值:
large_arr = np.random.randn(1000) large_arr.sort()
large_arr[int(0.05 * len(large_arr))] # 5% quantile
-1.6908607973872243
5 Unique and Other Set Logic (单一性和其他集合逻辑)
Numpy 也有一些基本的集合操作用于一维数组。 np.unique
,能返回排好序且不重复的值:
names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe']) np.unique(names)
array(['Bob', 'Joe', 'Will'], dtype='<U4')
ints = np.array([3, 3, 3, 2, 2, 1, 1, 4, 4])
np.unique(ints)
array([1, 2, 3, 4])
如果用纯 python 代码来实现的话,要这么写:
sorted(set(names))
['Bob', 'Joe', 'Will']
np.in1d
, 测试一个数组的值是否在另一个数组里,返回一个布尔数组:
values = np.array([6, 0, 0, 3, 2, 5, 6])
np.in1d(values, [2, 3, 6])
array([ True, False, False, True, True, False, True], dtype=bool)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论