#!/usr/bin/env python # coding: utf-8 # 向量化的数组运算比纯python同等程度的运算要快很多。 # # 一个简单的例子,假设我们想要评价函数`sqrt(x^2 + y^2)`。`np.meshgrid`函数取两个1维的数组,产生一个2维的矩阵,对应于所有两个数组中(x, y)的组合: # In[7]: 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)。 # In[18]: m, n = (5, 3) x = np.linspace(0, 1, m) y = np.linspace(0, 1, n) X, Y = np.meshgrid(x, y) x # In[19]: y # In[20]: X # In[21]: Y # 可以看到X和Y的shape都是3x5,用图的话更好理解: # # [](../MarkdownPhotos/chp04/v2-a7f1c996c371d1167a0fb7b5273c6d01_r.jpg) # # ![](http://oydgk2hgw.bkt.clouddn.com/pydata-book/jaa76.jpg) # # # 把X和Y画出来后,就可以看到网格了: # # # In[23]: import matplotlib.pyplot as plt get_ipython().run_line_magic('matplotlib', 'inline') plt.style.use('ggplot') plt.plot(X, Y, marker='.', color='blue', linestyle='none') # 可以用zip得到网格平面上坐标点的数据: # In[24]: z = [i for i in zip(X.flat, Y.flat)] z # 好了,下面继续进入书中的内容 # In[3]: points = np.arange(-5, 5, 0.01) # 1000 equally spaced points xs, ys = np.meshgrid(points, points) # xs和ys是一样的 ys # In[25]: z = np.sqrt(xs ** 2 + ys ** 2) z # 这里我们用matplotlib把图画出来: # In[27]: plt.imshow(z, cmap=plt.cm.gray); plt.colorbar() plt.title("Image plot of $\sqrt{x^2 + y^2}$ for a grid of values") # # 1 Expressing Conditional Logic as Array Operations (像数组操作一样表示逻辑条件) # # `numpy.where`函数是一个向量版的三相表达式,`x if condition else y`。假设我们有一个布尔数组和两个数组: # In[28]: 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中的值。列表表达式的话会这么写: # In[29]: result = [(x if c else y) for x, y, c in zip(xarr, yarr, cond)] result # 这么做的话会有很多问题。首先,对于很大的数组,会比较慢。第二,对于多维数组不起作用。但`np.where`能让我们写得更简洁: # In[30]: result = np.where(cond, xarr, yarr) result # `np.where`中第二个和第三个参数不用必须是数组。where在数据分析中一个典型的用法是基于一个数组,产生一个新的数组值。假设我们有一个随机数字生成的矩阵,我们想要把所有的正数变为2,所有的负数变为-2。用where的话会非常简单: # In[31]: arr = np.random.randn(4, 4) arr # In[32]: arr > 0 # In[33]: np.where(arr > 0, 2, -2) # 我们可以结合标量和数组。比如只把整数变为2,其他仍未原来的数字: # In[34]: np.where(arr > 0, 2, arr) # set only positive value to 2 # # 2 Mathematical and Statistical Methods (数学和统计方法) # # 一些能计算统计值的数学函数能基于整个数组,或者沿着一个axis(轴)。可以使用aggregations(often called reductions,汇总,或被叫做降维),比如sum, mean, and std(标准差). # # 下面是一些aggregate statistics(汇总统计): # # In[35]: arr = np.random.randn(5, 4) arr # In[36]: arr.mean() # In[37]: np.mean(arr) # In[38]: arr.sum() # mean, sum这样的函数能接受axis作为参数来计算统计数字,返回的结果维度更少: # In[39]: arr.mean(axis=1) # In[40]: arr.sum(axis=0) # 这里`arr.mean(1)`表示,compute mean acros the columns(计算各列之间的平均值)。`arr.sum(0)`表示,compute sum down the rows(计算各行总和)。 # # 其他一些方法,像cumsum和cumprod不做汇总,而是产生一个中间结果的数组: # In[41]: arr = np.array([0, 1, 2, 3, 4, 5, 6, 7]) arr.cumsum() # 上面的计算是一个累加的结果,`0+1=1,1+2=3,3+3=6`以此类推。 # In[44]: get_ipython().run_line_magic('pinfo', 'np.cumsum') # 对于多维数组,accumulation functions(累积函数)比如cumsum,返回的是同样大小的数组,但是部分聚合会沿着指示的轴向较低维度进行切片: # In[45]: arr = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]) arr # In[46]: arr.cumsum(axis=0) # 沿着行加法 # In[47]: arr.cumprod(axis=1) # 沿着列乘法 # 这里有一些基本的统计计算方法: # ![](http://oydgk2hgw.bkt.clouddn.com/pydata-book/9mzrp.png) # # # 3 Methods for Boolean Arrays(布尔数组的方法) # # sum是用来计算布尔数组中有多少个true的: # In[48]: arr = np.random.randn(100) (arr > 0).sum() # Number of positive values # 有两个其他方法,any和all,对于布尔数组特别有用。any检测数组中只要有一个ture返回就是true,而all检测数组中都是true才会返回true。 # In[49]: bools = np.array([False, False, True, False]) # In[50]: bools.any() # In[51]: bools.all() # # 4 Sorting(排序) # # numpy中也有sort方法: # In[53]: get_ipython().run_line_magic('pinfo', 'np.random.randn') # 返回符合正态分布的数值 # In[54]: arr = np.random.randn(6) arr # In[55]: arr.sort() # In[56]: arr # 如果是多维数组,还可以按axis来排序: # In[57]: arr = np.random.randn(5, 3) arr # In[58]: arr.sort(1) # In[59]: arr # 上面是直接调用数组的sort方法,会改变原有数组的顺序。但如果使用`np.sort()`函数的话,会生成一个新的排序后的结果。 # # 一个计算分位数的快捷方法是先给数组排序,然后选择某个排名的值: # In[60]: large_arr = np.random.randn(1000) large_arr.sort() # In[61]: large_arr[int(0.05 * len(large_arr))] # 5% quantile # # 5 Unique and Other Set Logic (单一性和其他集合逻辑) # # Numpy也有一些基本的集合操作用于一维数组。`np.unique`,能返回排好序且不重复的值: # In[62]: names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe']) np.unique(names) # In[63]: ints = np.array([3, 3, 3, 2, 2, 1, 1, 4, 4]) # In[64]: np.unique(ints) # 如果用纯python代码来实现的话,要这么写: # In[65]: sorted(set(names)) # `np.in1d`, 测试一个数组的值是否在另一个数组里,返回一个布尔数组: # In[66]: values = np.array([6, 0, 0, 3, 2, 5, 6]) # In[67]: np.in1d(values, [2, 3, 6]) # 这里是一些数组的集合操作: # ![](http://oydgk2hgw.bkt.clouddn.com/pydata-book/du91n.png) # In[ ]: