#!/usr/bin/env python # coding: utf-8 # # Numpy 数组及其索引 # 先导入numpy: # In[1]: from numpy import * # ## 产生数组 # 从列表产生数组: # In[2]: lst = [0, 1, 2, 3] a = array(lst) a # 或者直接将列表传入: # In[3]: a = array([1, 2, 3, 4]) a # ## 数组属性 # 查看类型: # In[4]: type(a) # 查看数组中的数据类型: # In[5]: # 32比特的整数 a.dtype # 查看每个元素所占的字节: # In[6]: a.itemsize # 查看形状,会返回一个元组,每个元素代表这一维的元素数目: # In[7]: # 1维数组,返回一个元组 a.shape # 或者使用: # In[8]: shape(a) # `shape` 的使用历史要比 `a.shape` 久,而且还可以作用于别的类型: # In[9]: lst = [1,2,3,4] shape(lst) # 查看元素数目: # In[10]: a.size # In[11]: size(a) # 查看所有元素所占的空间: # In[12]: a.nbytes # 但事实上,数组所占的存储空间要比这个数字大,因为要用一个header来保存shape,dtype这样的信息。 # # 查看数组维数: # In[13]: a.ndim # ## 使用fill方法设定初始值 # 可以使用 `fill` 方法将数组设为指定值: # In[14]: a.fill(-4.8) a # 但是与列表不同,数组中要求所有元素的 `dtype` 是一样的,如果传入参数的类型与数组类型不一样,需要按照已有的类型进行转换。 # ## 索引与切片 # 和列表相似,数组也支持索引和切片操作。 # # 索引第一个元素: # In[15]: a = array([0, 1, 2, 3]) a[0] # 修改第一个元素的值: # In[16]: a[0] = 10 a # 切片,支持负索引: # In[17]: a = array([11,12,13,14,15]) a[1:3] # In[18]: a[1:-2] # In[19]: a[-4:3] # 省略参数: # In[20]: a[::2] # In[21]: a[-2:] # 假设我们记录一辆汽车表盘上每天显示的里程数: # In[22]: od = array([21000, 21180, 21240, 22100, 22400]) # 可以这样计算每天的旅程: # In[23]: dist = od[1:] - od[:-1] dist # 在本质上,**Python**会将array的各种计算转换为类似这样的**C**代码: # # ```c # int compute_sum(int *arr, int N) { # int sum = 0; # int i; # for (i = 0; i < N; i++) { # sum += arr[i]; # } # return sum; # } # ``` # ## 多维数组及其属性 # `array` 还可以用来生成多维数组: # In[24]: a = array([[ 0, 1, 2, 3], [10,11,12,13]]) a # 事实上我们传入的是一个以列表为元素的列表,最终得到一个二维数组。 # # 甚至可以扩展到3D或者4D的情景。 # # 查看形状: # In[25]: a.shape # 这里2代表行数,4代表列数。 # 查看总的元素个数: # In[26]: # 2 * 4 = 8 a.size # 查看维数: # In[27]: a.ndim # ## 多维数组索引 # 对于二维数组,可以传入两个数字来索引: # In[28]: a[1, 3] # 其中,1是行索引,3是列索引,中间用逗号隔开,事实上,**Python**会将它们看成一个元组(1,3),然后按照顺序进行对应。 # # 可以利用索引给它赋值: # In[29]: a[1, 3] = -1 a # 事实上,我们还可以使用单个索引来索引一整行内容: # In[30]: # 返回第二行元组组成的array a[1] # **Python**会将这单个元组当成对第一维的索引,然后返回对应的内容。 # ## 多维数组切片 # 多维数组,也支持切片操作: # In[31]: a = array([[ 0, 1, 2, 3, 4, 5], [10,11,12,13,14,15], [20,21,22,23,24,25], [30,31,32,33,34,35], [40,41,42,43,44,45], [50,51,52,53,54,55]]) a # 想得到第一行的第 4 和第 5 两个元素: # In[32]: a[0, 3:5] # 得到最后两行的最后两列: # In[33]: a[4:, 4:] # 得到第三列: # In[34]: a[:, 2] # 每一维都支持切片的规则,包括负索引,省略: # [lower:upper:step] # 例如,取出3,5行的奇数列: # In[35]: a[2::2, ::2] # ## 切片是引用 # 切片在内存中使用的是引用机制。 # In[36]: a = array([0,1,2,3,4]) b = a[2:4] print b # 引用机制意味着,**Python**并没有为 `b` 分配新的空间来存储它的值,而是让 `b` 指向了 `a` 所分配的内存空间,因此,改变 `b` 会改变 `a` 的值: # In[37]: b[0] = 10 a # 而这种现象在列表中并不会出现: # In[38]: a = [1,2,3,4,5] b = a[2:3] b[0] = 13234 print a # 这样做的好处在于,对于很大的数组,不用大量复制多余的值,节约了空间。 # # 缺点在于,可能出现改变一个值改变另一个值的情况。 # # 一个解决方法是使用copy()方法产生一个复制,这个复制会申请新的内存: # In[39]: a = array([0,1,2,3,4]) b = a[2:4].copy() b[0] = 10 a # ## 花式索引 # 切片只能支持连续或者等间隔的切片操作,要想实现任意位置的操作,需要使用花式索引 `fancy slicing` 。 # ### 一维花式索引 # 与 range 函数类似,我们可以使用 arange 函数来产生等差数组。 # In[40]: a = arange(0, 80, 10) a # 花式索引需要指定索引位置: # In[41]: indices = [1, 2, -3] y = a[indices] print y # 还可以使用布尔数组来花式索引: # In[42]: mask = array([0,1,1,0,0,1,0,0], dtype=bool) # In[43]: a[mask] # 或者用布尔表达式生成 `mask`,选出了所有大于0.5的值: # In[44]: from numpy.random import rand a = rand(10) a # In[45]: mask = a > 0.5 a[mask] # mask 必须是布尔数组。 # ### 二维花式索引 # In[46]: a = array([[ 0, 1, 2, 3, 4, 5], [10,11,12,13,14,15], [20,21,22,23,24,25], [30,31,32,33,34,35], [40,41,42,43,44,45], [50,51,52,53,54,55]]) a # 对于二维花式索引,我们需要给定 `row` 和 `col` 的值: # In[47]: a[(0,1,2,3,4), (1,2,3,4,5)] # 返回的是一条次对角线上的5个值。 # In[48]: a[3:, [0,2,5]] # 返回的是最后三行的第1,3,5列。 # 也可以使用mask进行索引: # In[49]: mask = array([1,0,1,0,0,1], dtype=bool) a[mask, 2] # 与切片不同,花式索引返回的是原对象的一个复制而不是引用。 # ### “不完全”索引 # 只给定行索引的时候,返回整行: # In[50]: y = a[:3] y # 这时候也可以使用花式索引取出第2,3,5行: # In[51]: condition = array([0,1,1,0,1], dtype=bool) a[condition] # ### 三维花式索引 # In[52]: a = arange(64) a.shape = 4,4,4 a # In[53]: y = a[:,:,[2, -1]] y # ## where语句 # where(array) # `where` 函数会返回所有非零元素的索引。 # ### 一维数组 # 先看一维的例子: # In[54]: a = array([0, 12, 5, 20]) # 判断数组中的元素是不是大于10: # In[55]: a > 10 # 数组中所有大于10的元素的索引位置: # In[56]: where(a > 10) # 注意到 `where` 的返回值是一个元组。 # # 使用元组是由于 where 可以对多维数组使用,此时返回值就是多维的。 # # 在使用的时候,我们可以这样: # In[57]: indices = where(a > 10) indices = indices[0] indices # 或者: # In[58]: indices = where(a>10)[0] indices # 可以直接用 `where` 的返回值进行索引: # In[59]: loc = where(a > 10) a[loc] # ### 多维数组 # 考虑二维数组: # In[60]: a = array([[0, 12, 5, 20], [1, 2, 11, 15]]) loc = where(a > 10) # 返回结果是一个二维的元组,每一维代表这一维的索引值: # In[61]: loc # 也可以直接用来索引a: # In[62]: a[loc] # 或者可以这样: # In[63]: rows, cols = where(a>10) # In[64]: rows # In[65]: cols # In[66]: a[rows, cols] # 再看另一个例子: # In[67]: a = arange(25) a.shape = 5,5 a # In[68]: a > 12 # In[69]: where(a > 12)