查看原文
其他

手撕numpy(三):切片和索引详解

黄伟呢 凹凸数据 2021-08-09
↑ 关注 + 星标 ~ 有趣的不像个技术号每晚九点,我们准时相约  


大家好,我是黄同学


手撕numpy系列持续更新中~


《手撕numpy(一):简单说明和创建数组的不同方式》


1、切片


1)numpy中数组切片与原生python切片的不同点


数组切片返回的是原始数组的视图,原生python切片返回的是原始数组的浅拷贝。


操作如下:

list1 = [1,2,3]
display(list1)
list2 = list1[1:]
display(list2)
# 此时,修改list2中某一个元素,查看原始列表的元素是否发生变化?
list2[0] = 666
display(list2)
display(list1)

array1 = np.array([1,3,5,2,4])
display(array1)
array2 = array1[2:]
display(array2)
# 此时,修改array2中某一个元素,查看原始数组的元素是否发生变化?
array2[0] = 888
display(array2)
display(array1)

结果如下:


① 使用数组对象的copy方法,实现底层数据的复制,而不是返回底层数据的视图;

array3 = np.array([1,2,3,4,5,6])
display(array3)
array4 = array3.copy()
display(array4)

array4[2] = 666
display(array4)
display(array3)

结果如下:


2)numpy中切片的使用


① 使用切片需要注意的知识点


② 一张图帮你理解数组切片


③ 常用切片操作如下

a = np.arange(10)
display(a) # array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

print(a[:3]) # 0 1 2
print(a[3:6]) # 3 4 5
print(a[6:]) # 6 7 8 9
print(a[::]) # 0 1 2 3 4 5 6 7 8 9
print(a[:]) # 0 1 2 3 4 5 6 7 8 9
print(a[::3]) # 0 3 6 9
print(a[1::3]) # 1 4 7
print(a[2::3]) # 2 5 8

# 当start、stop、step为负数的时候,理解起来就稍微难一点;
print(a[::-1]) # 9 8 7 6 5 4 3 2 1 0
print(a[:-4:-1]) # 9 8 7
print(a[-4:-7:-1]) # 6 5 4
print(a[-7::-1]) # 3 2 1 0

结果如下:


④ 当你理解了那幅图,可以做一下如下几道题目,检验一下自己;

a = np.arange(10)
display(a)

print(a[-8:-2:1])
print(a[7:1:-1])

注意:上述两个切片是否存在问题,假如不存在,结果又是什么?如果你能回答正确这两个问题,python切片,就没有问题了。


3)当数组是多维数组时,可以使用array[高维, 低维]的方式,按维度进行索引或切片。


如果中括号[]中只写了一个维度的时候,就代表最高维;

对每一个维度,都可以使用上述的切片功能;


① 直接举例说明

b = np.arange(20).reshape(4,5)
display(b)

display(b[2,3])
display(b[1])
display(b[-1])
# -----------------------------------------------
display(b[1:3,2:4])
display(b[2,1:4])
display(b[0:3,1])
# -----------------------------------------------
display(b[1:3,:])
display(b[:,1])
display(b[::])

结果如下:


② 怎么把一个二维数组的所有元素全部倒序过来?

c = np.arange(12).reshape(3,4)
display(c)
# ------------你可分步考虑一下---------------
display(c[::-1,:])
display(c[:,::-1])
display(c[::-1,::-1])

结果如下:


2、索引


1)普通索引

a = np.arange(1,13,1).reshape(3,4)
display(a)

# 获取某一个元素:如下两种方式
display(a[1][2])
display(a[1,2])
# 获取某一行元素:如下两种方式
display(a[1])
display(a[1,:])
# 获取某一列元素
display(a[:,1])

结果如下:


2)通过整数数组进行索引(☆☆☆)


当要选取的元素不连续时,可以提供一个索引数组来选择(或修改)对应索引位置

的元素。


通过整数数组索引,【返回的是原数组的拷贝,而不是视图】。


可以提供多个一维数组索引,此时会将每个数组的对应位置元素作为索引,返回对应的元素。


① 通过整数数组索引,获取数组中的元素(这个用的多一点);

a = np.arange(1,21,1).reshape(5,4)
display(a)
# 选取数组a中的第2、第4、第5行数据;
display(a[[1,3,4]])

结果如下:


② 提供多个一维数组索引,获取数组中的元素(这种方式很特别,了解一下);

a = np.arange(1,21,1).reshape(5,4)
display(a)
# 下面这个代码获取的是对应位置组成的坐标的元素
# [1,2],[4,3],[4,2]
display(a[[1,4,4],[2,3,2]])

结果如下:


③ 通过整数数组索引,【返回的是原数组的拷贝,而不是视图】;

a = np.arange(1,21,1).reshape(5,4)
display(a)

b = a[[1,3]]
display(b)

b[1,2] = 888
display(b)
display(a)

结果如下:


注意:当返回的是原数组的拷贝的时候,相当于将原始数组复制了一份,在内存中重新开辟了一块儿空间,存储起来了。因此,当我修改任何一个数组,相互之间没有任何影响。


3)通过布尔数组进行索引


含义:我们可以提供一个布尔类型的数组(A),然后通过该数组(A)来对另外一个数组(B)进行索引(元素选取)。索引的原则为:如果为True,则选取对应位置的元素,否则不选取。


作用:通过布尔类型的数组进行索引是常见且实用的操作,我们通常用来进行元素选择(或过滤)操作。


① 通过布尔数组取一维数组中的元素

a = np.array([17,19,32,13,27,10,40])

a1 = a[[True,True,False,True,False,False,True]]
display(a1)

bool_index = a > 15
display(bool_index)
a2 = a[bool_index]
display(a2)

结果如下:


② 通过布尔数组取二维数组中的元素

b = np.arange(10,30).reshape(5,4)
display(b)
# 这个表示选取第1,2,4行;
b1 = b[[True,True,False,True,False]]
display(b1)

bool_index = b > 20
display(bool_index)
b2 = b[bool_index]
display(b2)

结果如下:


③ 构造布尔数组的几种常用的运算符


操作如下

c = np.arange([15,18,19,23,24,28,30,35,37,40,41,45])
display(c)

c1 = c[c>25]
display(c1)

c2 = c[(c>20) & (c<35)]
display(c2)

c3 = c[(c<20) | (c>40)]
display(c3)

c4 = c[~(c>40)]
display(c4)

结果如下


④ 取出两个数组中相同的元素

a = np.array([1, 3, 9, 10])
b = np.array([1, 8, 6, 10])
# 对应位置的元素,会进行比较;
display(a[a == b])

结果如下







近期文章,点击图片即可查看






后台回复关键词「进群」,即刻加入读者交流群~


先撕numpy,再撕pandas!

朱小五

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存