numpy中索引和切片详解


Posted in Python onDecember 15, 2017

索引和切片

一维数组

一维数组很简单,基本和列表一致。

它们的区别在于数组切片是原始数组视图(这就意味着,如果做任何修改,原始都会跟着更改)。

这也意味着,如果不想更改原始数组,我们需要进行显式的复制,从而得到它的副本(.copy())。

import numpy as np #导入numpy
arr = np.arange(10) #类似于list的range()
arr
Out[3]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
arr[4] #索引(注意是从0开始的)
Out[4]: 4
arr[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] = 33
arr #可以发现将标量赋值给一个切片时,该值可以传播到整个选区
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]])

想到了什么?咱们当做一个平面直角坐标系。

numpy中索引和切片详解

相当于arr1[x,y],x相当于行数,y相当于列数(必须声明,图中x和y标反了,但不影响理解)。

多维数组

先说明下reshape()更改形状:

np.reshape(a,newshape,order='C')

a:array_like以一个数组为参数。

newshape:intortupleofints。整数或者元组

顺便说明下,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 * 列中列

numpy中索引和切片详解

那么:

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] #设置步长为2
Out[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 != 1
Out[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] = 10

arr5
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))# 创建新数组,只分配内存空间,不填充值

for i in 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]])

通过,这些试验,还可发现,花式索引将数据复制到了一个新的数组中。

总结

以上就是本文关于numpy中索引和切片详解的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:

如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

Python 相关文章推荐
浅谈python字典多键值及重复键值的使用
Nov 04 Python
python实现下载文件的三种方法
Feb 09 Python
Python基于回溯法子集树模板解决m着色问题示例
Sep 07 Python
python 读入多行数据的实例
Apr 19 Python
python: 自动安装缺失库文件的方法
Oct 22 Python
django框架F&Q 聚合与分组操作示例
Dec 12 Python
用pytorch的nn.Module构造简单全链接层实例
Jan 14 Python
python3连接MySQL8.0的两种方式
Feb 17 Python
python使用pandas抽样训练数据中某个类别实例
Feb 28 Python
Python中的整除和取模实例
Jun 03 Python
pytorch实现手写数字图片识别
May 20 Python
Python实现老照片修复之上色小技巧
Oct 16 Python
Python实现简单网页图片抓取完整代码实例
Dec 15 #Python
利用numpy实现一、二维数组的拼接简单代码示例
Dec 15 #Python
神经网络python源码分享
Dec 15 #Python
神经网络理论基础及Python实现详解
Dec 15 #Python
浅谈机器学习需要的了解的十大算法
Dec 15 #Python
python实现协同过滤推荐算法完整代码示例
Dec 15 #Python
python3大文件解压和基本操作
Dec 15 #Python
You might like
PHP中用正则表达式清除字符串的空白
2011/01/17 PHP
PHP中实现crontab代码分享
2015/03/26 PHP
PHP根据图片色界在不同位置加水印的方法
2015/07/01 PHP
Fleaphp常见函数功能与用法示例
2016/11/15 PHP
PHP连接MYSQL数据库的3种常用方法
2017/02/27 PHP
php实现登录页面的简单实例
2019/09/29 PHP
借用Google的Javascript API Loader来加速你的网站
2009/01/28 Javascript
jQuery AJAX实现调用页面后台方法和web服务定义的方法分享
2012/03/01 Javascript
JavaScript中valueOf函数与toString方法深入理解
2012/12/02 Javascript
jquery入门—数据删除与隔行变色以及图片预览
2013/01/07 Javascript
JS实现在线统计一个页面内鼠标点击次数的方法
2015/02/28 Javascript
JavaScript动态改变div属性的实现方法
2015/07/22 Javascript
每天一篇javascript学习小结(Boolean对象)
2015/11/12 Javascript
jQuery实现checkbox列表的全选、反选功能
2016/11/24 Javascript
官方推荐react-navigation的具体使用详解
2018/05/08 Javascript
JS实现Cookie读、写、删除操作工具类示例
2018/08/28 Javascript
JS实现时间校验的代码
2020/05/25 Javascript
解决父组件将子组件作为弹窗调用只执行一次created的问题
2020/07/24 Javascript
跟老齐学Python之一个免费的实验室
2014/09/14 Python
python使用chardet判断字符串编码的方法
2015/03/13 Python
分享一下Python 开发者节省时间的10个方法
2015/10/02 Python
Python的Tornado框架的异步任务与AsyncHTTPClient
2016/06/27 Python
Python字符串格式化%s%d%f详解
2018/02/02 Python
78行Python代码实现现微信撤回消息功能
2018/07/26 Python
Python实现多线程的两种方式分析
2018/08/29 Python
python爬取酷狗音乐排行榜
2019/02/20 Python
Django url,从一个页面调到另个页面的方法
2019/08/21 Python
Python树莓派学习笔记之UDP传输视频帧操作详解
2019/11/15 Python
Keras:Unet网络实现多类语义分割方式
2020/06/11 Python
Python调用系统命令os.system()和os.popen()的实现
2020/12/31 Python
英国美发和美容产品商城:HQhair
2019/02/08 全球购物
制药工程专业应届生求职信
2013/09/24 职场文书
正风肃纪剖析材料
2014/09/30 职场文书
意外死亡赔偿协议书
2014/10/14 职场文书
自主招生自荐信怎么写
2015/03/24 职场文书
数据分析数据库ClickHouse在大数据领域应用实践
2022/04/03 MySQL