副本与视图
在 Numpy 中,返回结果是 副本 或者 视图。
-
赋值运算:不会为数组和数组中的任何元素创建副本。(是同一个,故同时变化)
-
numpy.ndarray.copy()
函数创建一个副本。 对副本数据进行修改,不会影响到原始数据。 -
数组切片操作返回的对象只是原数组的视图。
import numpy as np
x = np.array([[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]])
y = x
y[::2, :3:2] = -1
print(x)
# [[-1 12 -1 14 15]
# [16 17 18 19 20]
# [-1 22 -1 24 25]
# [26 27 28 29 30]
# [-1 32 -1 34 35]]
print(y)
# [[-1 12 -1 14 15]
# [16 17 18 19 20]
# [-1 22 -1 24 25]
# [26 27 28 29 30]
# [-1 32 -1 34 35]]
x = np.array([[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]])
y = x.copy()
y[::2, :3:2] = -1
print(x)
# [[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]]
print(y)
# [[-1 12 -1 14 15]
# [16 17 18 19 20]
# [-1 22 -1 24 25]
# [26 27 28 29 30]
# [-1 32 -1 34 35]]
索引与切片
数组索引机制指的是用方括号([])加序号的形式引用单个数组元素,它的用处很多,比如抽取元素,选取数组的几个元素,甚至为其赋一个新值。
切片索引:
- 对 python 列表进行切片操作得到的数组是原数组的副本,而对 Numpy 数据进行切片操作得到的数组则是指向相同缓冲区的视图。
- x[i];
x[i][j]等价于 x[i,j]) - x[
start:stop:step,start:stop:step
]切片索引,逗号前是行,后面是列;下表从0开始,省去表示默认从第0个数字开始;为左开右闭;-1表示最后一个元素。
#利用负数下标翻转数组
print(x[::-1]) # [8 7 6 5 4 3 2 1]
dots 索引
用...
表示足够多的冒号来构建完整的索引列表。
比如,如果 x
是 5 维数组:
x[1,2,...]
等于x[1,2,:,:,:]
x[...,3]
等于x[:,:,:,:,3]
x[4,...,5,:]
等于x[4,:,:,5,:]
import numpy as np
x = np.random.randint(1, 100, [2, 2, 3])
print(x)
# [[[ 5 64 75]
# [57 27 31]]
#
# [[68 85 3]
# [93 26 25]]]
print(x[1, ...])
# [[68 85 3]
# [93 26 25]]
print(x[..., 2])
# [[75 31]
# [ 3 25]]
整数数组索引
注意!
-
x[r, c]:r和c都是数组,表示行和列,表示的是对应坐标(r和c是一一对应)
-
x[r]:r若为高维数组,表示的是这个输出的数组形状,但是r仍然只表示行。
-
numpy. take(a, indices, axis=None, out=None, mode='raise')
Take elements from an array along an axis. axis=0按行取 -
np.take(x, [r, c],axis=0/1) 存疑
-
应注意:使用切片索引(视图),生成的数组视图将始终是原始数组的子数组,
但是整数数组索引(副本),不是其子数组,是形成新的数组
。
x = np.array([[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]])
r = [0, 1, 2]
c = [2, 3, 4]
y = x[r, c]
print(y)
# [13 19 25]
x = np.array([[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]])
r = np.array([[0, 1], [3, 4]])
print(x[r])
#等价于print(np.take(x, r, axis=0))
# [[[11 12 13 14 15]
# [16 17 18 19 20]]
#
# [[26 27 28 29 30]
# [31 32 33 34 35]]]
# 获取了 5X5 数组中的四个角的元素。
# 行索引是 [0,0] 和 [4,4],而列索引是 [0,4] 和 [0,4]。
r = np.array([[0, 0], [4, 4]])
c = np.array([[0, 4], [4, 0]])
y = x[r, c]
print(y)
# [[11 15]
# [35 31]]
#????????????????????????????????????好奇怪啊 咋来的
x = np.array([[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]])
r = [0, 1, 2]
c = [2, 3, 4]
y = np.take(x, [r, c])
print(y)
# [[11 12 13]
# [13 14 15]]
#副本和视图问题:
#切片索引与整数数组索引
import numpy as np
a=np.array([[1,2],[3,4],[5,6]])
b=a[0:1,0:1]
b[0,0]=2
print(a[0,0]==b)
#[[True]]
b=a[0,0]
b=2
print(a[0,0]==b)
#False
布尔索引:
通过一个布尔数组来索引目标数组。
- x[x>5]:取出大于5的数(x>5的返回布尔数组,x[布尔数组]将布尔数组中的True的位置的值返回
- logical_not(布尔数组):非运算,True改为False
- np.logical_and(express1, express2) #逻辑与:同时成立
x = np.array([np.nan, 1, 2, np.nan, 3, 4, 5])
y = np.logical_not(np.isnan(x))
print(x[y])
# [1. 2. 3. 4. 5.]
import matplotlib.pyplot as plt
x = np.linspace(0, 2 * np.pi, 50)
y = np.sin(x) #都是数组
# print(len(x)) # 50
plt.plot(x, y)
mask = y >= 0 #返回一个布尔数组
'''
[ True True True True True True True True True True True True
True True True True True True True True True True True True
True False False False False False False False False False False False
False False False False False False False False False False False False
False False]
'''
# print(len(x[mask])) #x[mask]取出布尔数组中为True的值 25
plt.plot(x[mask], y[mask], 'bo')
mask = np.logical_and(y >= 0, x <= np.pi / 2) #逻辑与:同时成立
'''
[ True True True True True True True True True True True True
True False False False False False False False False False False False
False False False False False False False False False False False False
False False False False False False False False False False False False
False False]
'''
plt.plot(x[mask], y[mask], 'go')
plt.show()
数组迭代
除了for循环,Numpy 还提供另外一种更为优雅的遍历方法。
apply_along_axis(func1d, axis, arr)
Apply a function to 1-D slices along the given axis.- axis=0沿着列计算,axis=1沿着行计算
x = np.array([[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]])
y = np.apply_along_axis(np.sum, 0, x) #沿着列计算
print(y) # [105 110 115 120 125]
def my_func(x):
return (x[0] + x[-1]) * 0.5
y = np.apply_along_axis(my_func, 1, x)
print(y) #[13. 18. 23. 28. 33.]
交换(反转)二维数组中的两列(行)
#索引和切片
arr = np.arange(9).reshape(3, 3)
x = arr[:, [2, 1, 0]]
print(x)
# [[2 1 0]
# [5 4 3]
# [8 7 6]]
x = arr[::-1, :]
print(x)
# [[6 7 8]
# [3 4 5]
# [0 1 2]]