numpy_数组操作
概要
本文对数组操作进行知识梳理,重点掌握切片和索引。
array的分解和组合
切片和索引——依照「某种方法」切出一块内容
在做数组运算或数组操作时,返回结果不是数组的副本就是** 视图**。
所有赋值运算不会为数组和数组中的任何元素创建副本。
numpy.ndarray.copy() 函数创建一个副本。 对副本数据进行修改,不会影响到原始数据。
对 python 列表进行切片操作得到的数组是原数组的副本,而对** Numpy 数据进行切片操作得到的数组则是指向相同缓冲区的视图**。
start:stop:step
rng = np.random.default_rng(42)
arr = rng.random((5, 4))
arr
array([[0.77395605, 0.43887844, 0.85859792, 0.69736803],
[0.09417735, 0.97562235, 0.7611397 , 0.78606431],
[0.12811363, 0.45038594, 0.37079802, 0.92676499],
[0.64386512, 0.82276161, 0.4434142 , 0.22723872],
[0.55458479, 0.06381726, 0.82763117, 0.6316644 ]])
# 最简单的索引,取第 0 行
arr[0] array([0.77395605, 0.43887844, 0.85859792, 0.69736803])
# 最简单的切片,取第 0 行第 1 列
arr[0, 1] 0.4388784397520523
# 带点范围 第 1-2 行
arr[1:3]
# 离散也可以:第 1,3 行
arr[[1, 3]]
# 加上维度:第 1-2 行,第 1 列
arr[1:3, 1] array([0.97562235, 0.45038594])
# 离散也是一样:第 1,3 行,第 0 列
arr[[1,3], [0]]
# 简写:到最后或到开始。如第 3 行到最后一行
arr[3:]
# 开始到第 3 行(不包括第3行),第 1-3 列(不包括第3列)
arr[:3, 1:3]
# 跳跃,步长:start:stop:step,第 1 行到第 4 行,间隔为 2,即第 1、3 行
arr[1: 4: 2]
# 加上列,第 1、3 行,第 0、2 列
arr[1:4:2, 0:3:2]
# 第一列的值,其实是所有其他维度第 1 维的值
arr[...,1] 或者 arr[:,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 = np.array([[0, 1], [3, 4]])
print(x[r])
# [[[11 12 13 14 15]
# [16 17 18 19 20]]
#
# [[26 27 28 29 30]
# [31 32 33 34 35]]]
dots索引
使用…表示足够多的冒号来构建完整的索引列表。
比如,如果 x 是 5 维数组:
x[1,2,...] 等于 x[1,2,:,:,:]
x[...,3] 等于 x[:,:,:,:,3]
x[4,...,5,:] 等于 x[4,:,:,5,:]
take 索引
numpy. take(a, indices, axis=None, out=None, mode=‘raise’)
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]
print(np.take(x, r, axis=0))
# [[11 12 13 14 15]
# [16 17 18 19 20]
# [21 22 23 24 25]]
bool 索引
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.]
数组遍历 apply_along_axis(func1d, axis, arr)
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 = np.apply_along_axis(np.sum, 0, x)
print(y) # [105 110 115 120 125]
y = np.apply_along_axis(np.sum, 1, x)
print(y) # [ 65 90 115 140 165]
拼接、堆叠
np.concatenate 和 np.stack,前者是拼接,后者是堆叠(会增加一个维度),都可以指定维度
(array([[0.77395605, 0.43887844, 0.85859792],
[0.69736803, 0.09417735, 0.97562235]]),
array([[0.7611397 , 0.78606431, 0.12811363],
[0.45038594, 0.37079802, 0.92676499]]))
拼接
# 默认沿axis=0(列)连接
np.concatenate((arr1, arr2))
# 或:(维度大于1时)
# 竖直按行顺序拼接
# 注:vstack 看起来像 stack,但它是 concatenate,建议只使用 `np.concatenate`
np.vstack((arr1, arr2))
array([[0.77395605, 0.43887844, 0.85859792],
[0.69736803, 0.09417735, 0.97562235],
[0.7611397 , 0.78606431, 0.12811363],
[0.45038594, 0.37079802, 0.92676499]])
# 沿 axis=1(行)连接
np.concatenate((arr1, arr2), axis=1)
# 或:(维度大于1时)
# 水平按列顺序拼接
# 道理和 vstack 一样,建议使用 `np.concatenate` axis=1
np.hstack((arr1, arr2))
array([[0.77395605, 0.43887844, 0.85859792, 0.7611397 , 0.78606431,0.12811363],
[0.69736803, 0.09417735, 0.97562235, 0.45038594, 0.37079802, 0.92676499]])
堆叠(增加维度的拼接)
# 堆叠,默认根据 axis=0 进行
np.stack((arr1, arr2))
array([[[0.77395605, 0.43887844, 0.85859792],
[0.69736803, 0.09417735, 0.97562235]],
[[0.7611397 , 0.78606431, 0.12811363],
[0.45038594, 0.37079802, 0.92676499]]])
# shape为(2,2,3)
# 堆叠,根据 axis=2
np.stack((arr1, arr2), axis=2)
# 或:
# 纵深按 axis=2 堆叠,不管它就行,我们认准 `stack`
np.dstack((arr1, arr2))
array([[[0.77395605, 0.7611397 ],
[0.43887844, 0.78606431],
[0.85859792, 0.12811363]],
[[0.69736803, 0.45038594],
[0.09417735, 0.37079802],
[0.97562235, 0.92676499]]])
# shape为(2,3,2)
样例(注意)
import numpy as np
x = np.array([1, 2, 3])
y = np.array([7, 8, 9])
z = np.stack([x, y])
print(z.shape) # (2, 3)
print(z)
# [[1 2 3]
# [7 8 9]]
z = np.stack([x, y], axis=1)
print(z.shape) # (3, 2)
print(z)
# [[1 7]
# [2 8]
# [3 9]]
import numpy as np
x = np.array([1, 2, 3]).reshape(1, 3)
y = np.array([7, 8, 9]).reshape(1, 3)
z = np.stack([x, y])
print(z.shape) # (2, 1, 3)
print(z)
# [[[1 2 3]]
#
# [[7 8 9]]]
z = np.stack([x, y], axis=1)
print(z.shape) # (1, 2, 3)
print(z)
# [[[1 2 3]
# [7 8 9]]]
z = np.stack([x, y], axis=2)
print(z.shape) # (1, 3, 2)
print(z)
# [[[1 7]
# [2 8]
# [3 9]]]
import numpy as np
x = np.array([[1, 2, 3], [4, 5, 6]])
y = np.array([[7, 8, 9], [10, 11, 12]])
z = np.stack([x, y])
print(z.shape) # (2, 2, 3)
print(z)
# [[[ 1 2 3]
# [ 4 5 6]]
#
# [[ 7 8 9]
# [10 11 12]]]
z = np.stack([x, y], axis=1)
print(z.shape) # (2, 2, 3)
print(z)
# [[[ 1 2 3]
# [ 7 8 9]]
#
# [[ 4 5 6]
# [10 11 12]]]
z = np.stack([x, y], axis=2)
print(z.shape) # (2, 3, 2)
print(z)
# [[[ 1 7]
# [ 2 8]
# [ 3 9]]
#
# [[ 4 10]
# [ 5 11]
# [ 6 12]]]
重复
numpy.tile(A, reps)
numpy.repeat(a, repeats, axis=None)
axis=0,沿着y轴复制,实际上增加了行数。
axis=1,沿着x轴复制,实际上增加了列数。
axis=None,会flatten当前矩阵,实际上就是变成了一个行向量。
repeats,可以为一个数,也可以为一个矩阵。
array([[0, 7, 6, 4],
[4, 8, 0, 6],
[2, 0, 5, 9]])
import numpy as np
x = np.repeat(3, 4)
print(x) # [3 3 3 3]
x = np.array([[1, 2], [3, 4]])
y = np.repeat(x, 2)
print(y)
# [1 1 2 2 3 3 4 4]
y = np.repeat(x, 2, axis=0)
print(y)
# [[1 2]
# [1 2]
# [3 4]
# [3 4]]
y = np.repeat(x, 2, axis=1)
print(y)
# [[1 1 2 2]
# [3 3 4 4]]
y = np.repeat(x, [2, 3], axis=0)
print(y)
# [[1 2]
# [1 2]
# [3 4]
# [3 4]
# [3 4]]
y = np.repeat(x, [2, 3], axis=1)
print(y)
# [[1 1 2 2 2]
# [3 3 4 4 4]]
分拆
记住 np.split 即可,其他是快捷方式。
array([[ 9, 77, 65, 44],
[43, 86, 9, 70],
[20, 10, 53, 97],
[73, 76, 72, 78],
[51, 13, 84, 45],
[50, 37, 19, 92]])
# 默认切分列(axis=0),切成 3 份
np.split(arr, 3)
# 或:
np.vsplit(arr, 3) # v-vertically (垂直,按照高速)
[array([[ 9, 77, 65, 44],
[43, 86, 9, 70]]),
array([[20, 10, 53, 97],
[73, 76, 72, 78]]),
array([[51, 13, 84, 45],
[50, 37, 19, 92]])]
#(axis=1)切分行
np.split(arr, 2, axis=1)
# 或:
np.hsplit(arr, 2) # h-horizontally(水平,按照宽度)
[array([[ 9, 77],
[43, 86],
[20, 10],
[73, 76],
[51, 13],
[50, 37]]),
array([[65, 44],
[ 9, 70],
[53, 97],
[72, 78],
[84, 45],
[19, 92]])]
一些练习补充
验证两随机数组是否相等
例题:给定两个随机数组A和B,验证它们是否相等。
A = np.random.randint(0,2,5) B = np.random.randint(0,2,5)
#Assuming identical shape of the arrays and a tolerance for the comparison of values
equal = np.allclose(A,B)
print(equal)
#Checking both the shape and the element values, no tolerance (values have to be exactly equal)
equal = np.array_equal(A,B)
print(equal)
知识点总结:
numpy.allclose()函数: 比较两个数组在一个公差内按元素方向是否相等。
numpy.allclose(a, b, rtol=1e-05, atol=1e-08, equal_nan=False)
参数
a, b:要比较的输入数组。
rtol:浮动,相对公差参数。
atol:浮动,绝对公差参数。
equal_nan:是否将Nan的值比较为相等——在同一个地方,如果 equal_nan=True ,若inf在两个数组中位于同一位置且符号相同,则将它们视为相等。
返回布尔值:如果两个数组在给定的公差内相等,则返回“真”;否则返回“假”。
numpy.array_equal(arr1,arr2):此逻辑函数检查两个数组是否具有相同的形状和元素。
数组去重——如何在numpy数组中找到重复值?
例题:
在给定的numpy数组中找到重复的条目(第二次出现以后),并将它们标记为True。第一次出现应为False。
a = np.random.randint(0, 5, 10)
import numpy as np
np.random.seed(100)
a = np.random.randint(0, 5, 10)
print(a)
# [0 0 3 0 2 4 2 2 2 2]
b = np.full(10, True)
vals, counts = np.unique(a, return_index=True)
b[counts] = False
print(b)
# [False True False True False False True True True True]
知识点总结:
numpy.unique(ar, return_index=False, return_inverse=False, return_counts=False, axis=None)[source]
一维数组
对一维数组或列表,unique()函数去除其中重复元素,并按元素大小返回一个新的无重复元组或列表。
import numpy as np
A = [1, 2, 2, 5,3, 4, 3]
a = np.unique(A)
print(a)
# [1 2 3 4 5]
C= ['fgfh','asd','fgfh','asdfds','wrh']
c= np.unique(C)
print(c)
# ['asd' 'asdfds' 'fgfh' 'wrh']
return_index = True表示:返回新列表元素在旧列表中的位置,并以列表形式储存在s中。
a, s= np.unique(A, return_index=True)
print(a)
print(s)
# [1 2 3 4 5]
# [0 1 4 5 3]
return_inverse = True表示:返回旧列表元素在新列表中的位置,并以列表形式储存在p中。
a,s,p = np.unique(A, return_index=True, return_inverse=True)
print(a)
print(s)
print(p)
# [1 2 3 4 5]
# [0 1 4 5 3]
# [0 1 1 4 2 3 2]
二维数组
import numpy
c=np.array(((1,2),(3,4),(5,6),(7,8),(7,8),(3,4),(1,2)))
x=c[:,0]+c[:,1]*1j
print('转化为虚数:',x)
print('虚数去重后:',np.unique(x))
print(np.unique(x,return_index=True)) # return_index:输出的元素索引值
idx=np.unique(x,return_index=True)[1]
print('二维数组去重:\n',c[idx])
#转化为虚数: [ 1.+2.j 3.+4.j 5.+6.j 7.+8.j 7.+8.j 3.+4.j 1.+2.j]
#虚数去重后: [ 1.+2.j 3.+4.j 5.+6.j 7.+8.j]
#(array([ 1.+2.j, 3.+4.j, 5.+6.j, 7.+8.j]), array([0, 1, 2, 3], dtype=int64))
#二维数组去重:
#[[1 2]
#[3 4]
#[5 6]
#[7 8]]
print('去重方案2:\n',np.array(list(set([tuple(t) for t in c]))))
#去重方案2:
#[[1 2]
#[3 4]
#[5 6]
#[7 8]]