一维数组很简单,基本和列表一致。 它们的区别在于数组切片是原始数组视图(这就意味着,如果做任何修改,原始都会跟着更改)。 这也意味着,如果不想更改原始数组,我们需要进行显式的复制,从而得到它的副本(
)。
- .copy()
- importnumpyasnp#导入numpyarr=np.arange(10)#类似于list的range()arr
- Out[3]: array([0,1,2,3,4,5,6,7,8,9])
- arr[4]#索引(注意是从0开始的)Out[4]:4arr[3:6]#切片Out[6]: array([3,4,5])
- arr_old=arr.copy()#先复制一个副本arr_old
- Out[8]: array([0,1,2,3,4,5,6,7,8,9])
- arr[3:6]= 33arr#可以发现将标量赋值给一个切片时,该值可以传播到整个选区Out[10]: array([0,1,2,33,33,33,6,7,8,9])
- arr_old
- Out[11]: array([0,1,2,3,4,5,6,7,8,9])
二维数组中,各索引位置上的元素不再是标量,而是一维数组(好像很难理解哈)。
- arr1=np.array([[1,2,3],[4,5,6],[7,8,9]])
- arr1[0]
- Out[13]: array([1,2,3])
- arr1[1,2]
- Out[14]:6
好像很难理解,是吧。
那这样看:
- array([[1,2,3],
- [4,5,6],
- [7,8,9]])
想到了什么?咱们当做一个平面直角坐标系。
相当于
, x 相当于行数,y 相当于列数(必须声明,图中 x 和 y 标反了,但不影响理解)。
- arr1[x,y]
先说明下
更改形状:
- reshape()
- np.reshape(a, newshape, order='C')
a :array_like 以一个数组为参数。 newshape : int or tuple of ints。整数或者元组
顺便说明下,
不更改原数组形状(会生成一个副本)。
- np.reshape()
- arr1=np.arange(12)
- arr2=arr1.reshape(2,2,3)#将arr1变为2×2×3数组arr2
- Out[9]:
- array([[[0,1,2],
- [3,4,5]],
- [[6,7,8],
- [9,10,11]]])
其实多维数组就相当于:
row * col * 列中列
那么:
- arr2[0]
- Out[10]:
- array([[0,1,2],
- [3,4,5]])
- arr2[1]
- Out[11]:
- array([[6,7,8],
- [9,10,11]])
- arr2[0,1]
- Out[12]: array([3,4,5])
- arr2[0]= 23 #赋值arr2
- Out[15]:
- array([[[23,23,23],
- [23,23,23]],
- [[6,7,8],
- [9,10,11]]])
那么这样也就很容易的就可以理解下面这种索引了。
切片索引把每一行每一列当做一个列表就可以很容易的理解。 返回的都是数组。
再复杂一点:
我们想要获得下面这个数组第一行的第 2,3 个数值。
- arr1=np.arange(36)#创建一个一维数组。arr2=arr1.reshape(6,6)#更改数组形状。Out[20]:
- array([[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],
- [30,31,32,33,34,35]])
为了得到第 2,3 个数,我们可以:
- arr2[0,2:4]
- Out[29]: array([2,3])
可以发现 ndarray 的切片其实与列表的切片是差不太多的。
我们还可以这样:
- arr2[1]#取得第2行Out[37]: array([6,7,8,9,10,11])
- arr2[:,3]#取得第3列, 只有:代表选取整列(也就是整个轴)Out[38]: array([3,9,15,21,27,33])
- arr2[1:4,2:4]# 取得一个二维数组Out[40]:
- array([[8,9],
- [14,15],
- [20,21]])
- arr2[::2,::2]#设置步长为2Out[41]:
- array([[0,2,4],
- [12,14,16],
- [24,26,28]])
- arr3=arr2.reshape(4,3,3)
- arr3[2:,:1]= 22 #对切片表达式赋值arr3
- Out[25]:
- array([[0,1,2,3,4,5],
- [6,7,8,9,10,11],
- [22,13,14,15,16,17],
- [22,19,20,21,22,23],
- [22,25,26,27,28,29],
- arr3=(np.arange(36)).reshape(6,6)#生成6*6的数组arr3
- Out[35]:
- array([[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],
- [30,31,32,33,34,35]])
- x=np.array([0,1,2,1,4,5])
- x== 1#通过比较运算得到一个布尔数组Out[42]: array([False,True,False,True,False,False], dtype=bool)
- arr3[x== 1]#布尔索引Out[43]:
- array([[6,7,8,9,10,11],
- [18,19,20,21,22,23]])
从结果上看,布尔索引取出了布尔值为 True 的行。 布尔型数组的长度和索引的数组的行数(轴长度)必须一致。 布尔型数组可与切片,整数(整数序列)一起使用。
- arr3[x == 1,2:]#切片
- Out[44]:
- array([[ 8, 9, 10, 11],
- [20, 21, 22, 23]])
- arr3[x == 1,-3:]#切片
- Out[47]:
- array([[ 9, 10, 11],
- [21, 22, 23]])
- arr3[x == 1,3]#整数
- Out[48]: array([ 9, 21])
!= 不等于符号。 ~ 负号可以对条件进行否定。logical_not() 函数也可以。
- x!= 1Out[49]: array([True,False,True,False,True,True], dtype=bool)
- arr3[~(x== 1)]#实际类似于取反Out[51]:
- array([[0,1,2,3,4,5],
- [12,13,14,15,16,17],
- [24,25,26,27,28,29],
- [30,31,32,33,34,35]])
- arr3[np.logical_not(x== 1)]#作用于 ~ 相同Out[53]:
- array([[0,1,2,3,4,5],
- [12,13,14,15,16,17],
- [24,25,26,27,28,29],
- [30,31,32,33,34,35]])
组合多个条件,使用布尔运算符
(和),
- &
(或)
- |
- (x== 1)&(x== 4)#和Out[67]: array([False,False,False,False,False,False], dtype=bool)
- (x==1)|(x==4)#或Out[68]: array([False,True,False,True,True,False], dtype=bool)
- arr3[(x==1)|(x==4)]#布尔索引Out[71]:
- array([[6,7,8,9,10,11],
- [18,19,20,21,22,23],
- [24,25,26,27,28,29]])
通过以上的代码实验,我们也可以发现,布尔索引不更改原数组,创建的都是原数组的副本。
那这个东西能做什么呢?其他索引能做的,他基本也都可以。
比如有这样一个数组:
- arr5=np.random.randn(4,4)#randn返回一个服从标准正态分布的数组。arr5
- Out[77]:
- array([[-0.64670829,1.53428435,0.20585387,0.42680995],
- [-0.63504514,0.54542881,-0.82163028,-0.89835051],
- [-0.66770299,0.22617913,0.16358189,-0.75074314],
- [-0.25439447,-0.96135628,-0.10552532,-1.06962358]])
我们要将 arr5 大于 0 的数值变为 10:
- arr5[arr5> 0]= 10arr5
- Out[80]:
- array([[-0.64670829,10. ,10. ,10. ],
- [-0.63504514,10. ,-0.82163028,-0.89835051],
- [-0.66770299,10. ,10. ,-0.75074314],
当然,布尔索引也可以结合上面的运算符来进行操作。
花式索引(Fancy indexing),指的是利用整数数组进行索引。
第一次看到这个解释,我是一脸懵的。
试验后,我才理解。
- arr6=np.empty((8,4))# 创建新数组,只分配内存空间,不填充值
- foriin range(8):#给每一行赋值arr6[i]=i
- arr6
- Out[5]:
- array([[0.,0.,0.,0.],
- [1.,1.,1.,1.],
- [2.,2.,2.,2.],
- [3.,3.,3.,3.],
- [4.,4.,4.,4.],
- [5.,5.,5.,5.],
- [6.,6.,6.,6.],
- [7.,7.,7.,7.]])
- arr6[[2,6,1,7]]#花式索引Out[14]:
- array([[2.,2.,2.,2.],
- [6.,6.,6.,6.],
- [1.,1.,1.,1.],
- [7.,7.,7.,7.]])
我们可以看到花式索引的结果,以一个特定的顺序排列。 而这个顺序,就是我们所传入的整数列表或者 ndarray。 这也为我们以特定的顺序来选取数组子集,提供了思路。
- arr6[2]
- Out[15]: array([2.,2.,2.,2.])
- arr6[6]
- Out[17]: array([6.,6.,6.,6.])
- arr6[1]
- Out[18]: array([1.,1.,1.,1.])
可以看到,花式索引的结果与普通索引是一致的。只不过,花式索引简化了索引过程,而且还实现了按一定的顺序排列。
还可以使用负数(其实类似于列表)进行索引。
- arr6[[-2,-6,-1]]
- Out[21]:
- array([[6.,6.,6.,6.],
- [2.,2.,2.,2.],
- [7.,7.,7.,7.]])
一次传入多个索引数组,会返回一个一维数组,其中的元素对应各个索引元组。
有点懵。
- arr7=np.arange(35).reshape(5,7)#生成一个5*7的数组arr7
- Out[24]:
- array([[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,30,31,32,33,34]])
- arr7[[1,3,2,4],[2,0,6,5]]
- Out[27]: array([9,21,20,33])
经过对比可以发现,返回的一维数组中的元素,分别对应(1,2)、(3,0)....
这一样一下子就清晰了,我们传入来两个索引数组,相当于传入了一组平面坐标,从而进行了定位。
此处,照我这样理解的话,那么一个 N 维数组,我传入 N 个索引数组的话,是不是相当于我传入了一个 N 维坐标。
我试验了下三维,是这样的,但是以后的不知道了。谁知道求告诉。
- ar=np.arange(27).reshape(3,3,3)
- ar
- Out[31]:
- array([[[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]]])
- ar[[1,2],[0,1],[2,2]]
- Out[32]: array([11,23])
那么应该如何得到一个矩形区域呢。可以这样做:
- arr7[[1,3,2,4]][:,[2,0,6,5]]
- Out[33]:
- array([[9,7,13,12],
- [23,21,27,26],
- [16,14,20,19],
- [30,28,34,33]])
必须明白,
等价于
- arr7[2][3]
- arr7[2,3]
那么上面这种得到矩形区域的方法,就相当于行与列去了交集。
此外还可用
函数,它的作用与上面的方法类似,只不过是将两个一维的数组转换为了一个可以选择矩形区域的索引器。
- np.ix_
- arr7[np.ix_([1,3,2,4],[2,0,6,5])]
- Out[34]:
- array([[9,7,13,12],
- [23,21,27,26],
- [16,14,20,19],
- [30,28,34,33]])
通过,这些试验,还可发现,花式索引将数据复制到了一个新的数组中。
来源: http://www.cnblogs.com/sunshinewang/p/6882031.html