Numpy数组---Array
Numpy的主要对象是多维数组。它是一个由元素(通常是数字)构成的表,所有元素的类型相同。维度的数量称为数组的阶(rank),数组的大小是一个由整型数构成的元组,可以描述数组不同维度上的大小。
Numpy的数组类叫做ndarray
,别名是array
。先来举一个例子,涉及的具体函数后面我们都会讲到。
import numpy as np
a = np.array([0, 1, 2, 3]) # 创建一个一维数组
print(type(a)) # 打印 "<class 'numpy.ndarray'>"
数组的属性
ndarray.ndim
:数组的维度数ndarray.shape
:数组每个维度的大小ndarray.size
:数组中元素的总个数ndarray.dtype
: 数组中元素的类型ndarray.itemsize
: 数组中每个元素所占的字节数ndarray.data
: 包含真实数组元素的缓冲区
再举一个例子。
import numpy as np
a = np.array([[0., 1., 2.],
[3., 4., 5.]]) # 创建一个2维数组
print(a) # 打印 "[[ 0. 1. 2.]
# [ 3. 4. 5.]]"
print(a.ndim) # 打印 "2"
print(a.shape) # 打印 "(2, 3)"
print(a.size) # 打印 "6"
print(a.dtype) # 打印 "float64"
print(a.itemsize) # 打印 "8" (64/8=8)
print(a.data) # 打印 "<memory at 0x7f18400ae3a8>"
创建数组
手动创建数组
可以利用array
函数从python的列表或元组创建一个数组。
- 1维数组
import numpy as np # 导入Numpy的推荐方式
a = np.array([0, 1, 2, 3]) # 创建一维数组
print(a) # 打印 "[1 2 3 4]"
print(a.ndim) # 打印 "1"
print(a.shape) # 打印 "(4,)"
print(len(a)) # 打印 "4"
- 2维及多维数组
import numpy as np
b = np.array([[0, 1, 2], [3, 4, 5]]) # 创建2维数组
print(b) # 打印 "[[0 1 2]
# [3 4 5]]"
print(b.ndim) # 打印 "2"
print(b.shape) # 打印 "(2, 3)"
print(b.shape[0], b.shape[1]) # 打印 “2 3”
print(len(b)) # 打印 "2"
c = np.array([[[1], [2]], [[3], [4]]]) # 创建3维数组
print(c) # 打印 "[[[1]
# [2]]
# (注意,打印时这里有一个空行)
# [[3]
# [4]]]"
print(c.shape) # 打印 "(2, 2, 1)"
注意:当你打印数组时,Numpy和嵌套列表以相似的方式显示,但是具有结构:
- 最后一维从左到右打印
- 倒数第二维从上到下打印
- 其余的维度也是从上到下打印,每一项之间都会有一个空行。
用函数创建数组
Numpy还提供了很多用函数创建数组的方法:
- arange:等间距分布的数组
import numpy as np
a = np.arange(10) # 0,1,..n-1
print(a) # 打印 "[0 1 2 3 4 5 6 7 8 9]"
b = np.arange(1, 9, 2) # start, end(不包含),step
print(b) # 打印 "[1 3 5 7]"
c = np.arange(0, 2.5, 0.4) # 参数可以是浮点数
print(c) # 打印 "[ 0. 0.4 0.8 1.2 1.6 2. 2.4]"
- linspace:指定数量(长度)的数组:
import numpy as np
d = np.linspace(0, 1, 6) # start,end, num-points
print(d) # 打印 "[ 0. 0.2 0.4 0.6 0.8 1. ]"
e = np.linspace(0, 1, 5, endpoint=False) # 可以显示的指定不包括最后一个点
print(d)
- 常用数组
import numpy as np
a = np.ones((1,2)) # 创建元素全为1的数组
print(a) # 打印 "[[ 1. 1.]]"
b = np.zeros((2,2)) # 创建元素全为0的数组
print(b) # 打印 "[[ 0. 0.]
# [ 0. 0.]]"
c = np.full((2,2), 7) # 创建一个用固定值填充的数组
print(c) # 打印 "[[ 7. 7.]
# [ 7. 7.]]"
d = np.eye(2) # 创建对角线为1,其它元素为0的2维数组
print(d) # 打印 "[[ 1. 0.]
# [ 0. 1.]]"
e = np.diag(np.array([1,2,3])) # 从2维数组提取对角线,或从一维数组构建对角线矩阵
print(e) # 打印 "[[1 0 0]
# [0 2 0]
# [0 0 3]]"
f = np.empty((2,2)) # 创建随机初始的数组
print(f) # 打印 "[[ 4.94065646e-324 9.88131292e-324]
# [ 1.48219694e-323 1.97626258e-323]]"
- np.random: 随机数数组
import numpy as np
a = np.random.rand(3) # [0, 1)均匀分布随机值
print(a) # 可能打印 "[ 0.14662351 0.9235998 0.80878827]"
b = np.random.randn(2,2) # 标准正态分布随机值
print(b) # 可能打印 "[[ 1.03371837 0.26109287]
# [ 1.33813718 -0.85320254]]"
np.random.seed(1234) # 设定随机数种子,产生可重复的结果
基本数据类型
你可能注意到,某些数组元素后面会跟着一个小数点 (比如 2. vs 2)。这是由于不同的数据类型所致。Numpy可以从输入自动推导出结果的数据类型:
import numpy as np
a = np.array([1, 2, 3, 4])
print(a.dtype) # 打印 "int64"
b = np.array([1., 2., 3., 4.]) # 打印 "float64"
print(b.dtype)
你也可以显式的指定你想得到的数据类型:
c = np.array([1, 2, 3], dtype=float)
print(c.dtype) # 打印 "float64"
d = np.array([1.,2.,3.]).astype('int64')
print(d.dtype) # 打印 "int64"
默认的数据类型是浮点数
e = np.ones((3, 3))
print(e.dtype) # 打印 "float64"
Numpy还有一些其它的数据类型
e = np.array([1+2j, 3+4j, 5+6j]) # 复数
print(e.dtype) # 打印 "complex128"
f = np.array([True, False, False, True]) # 布尔值
print(f.dtype) # 打印 "bool"
g = np.array(['Bonjour', 'Hello', 'Hallo']) # 字符串
print(g.dtype) # 打印 "<U7"
索引、切片和迭代
索引
数组中的每一项可以像python的序列类型(如list)一样被访问和赋值
import numpy as np
# 创建一个一维数组 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
a = np.arange(10)
print(a[0], a[2], a[-1]) # 打印:0 2 9
print(a[::-1]) # 打印 [9 8 7 6 5 4 3 2 1 0] (python中逆转序列依旧适用)
# 创建一个二维数组
# [[1 2 3]
# [4 5 6]
# [7 8 9]]
b = np.arange(1,10).reshape(3,3)
print(b[1,1], b[2,1]) # 打印 "5 8"
# 当提供的索引数小于维度数时,缺失的索引表示全部切片
print(b[1]) # 打印 "[4 5 6]"
print(b[1][2]) # 打印 "6"
切片
和Python列表类似,numpy数组可以使用切片语法。因为数组可以是多维的,所以你必须为每个维度指定好切片。
import numpy as np
a = np.arange(10) # 创建数组 [0 1 2 3 4 5 6 7 8 9]
print(a[2:9:3]) # 打印 [2 5 8]
print(a[1:4]) # 打印 [1 2 3] (不包括最后一个索引)
# 切片的三个参数都不是必须的,start默认是0,end默认是最后,step默认是1
print(a[::2]) # 打印 [0 2 4 6 8]
print(a[3:]) # 打印 [3 4 5 6 7 8 9]
# 创建如下二维数组,shape=(3, 4)
# [[ 1 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
b = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
# 使用切片操作得到一个由a的前两行和列1和列2组成的子数组c
# 数组c如下所示,shape=(2, 2)
# [[2 3]
# [6 7]]
c = b[:2, 1:3]
# 数组的一个切片是相同数据上的一个视图,共享内存内存地址,
# 因此修改切片数组会改变原始数组
print(b[0, 1]) # 打印 "2"
c[0, 0] = 77 # b[0, 0]与a[0, 1]代表同一个数据
print(b[0, 1]) # 打印 "77"
# 这种行为看起来很奇怪,但是可以帮助节省内存和时间开销。
你可以同时使用整型和切片语法来访问数组。但是,这样做会产生一个比原数组低阶的新数组。需要注意的是,这里和MATLAB中的情况是不同的:
import numpy as np
# 创建一个二维数组,shape=(3, 4)
# [[ 1 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
# 访问数组中间行数据的两种方式
# 混合使用整数索引和切片产生一个低阶的数组
# 只使用切片产生和原始数组相同阶的数组
row_r1 = a[1, :] # a第二行的1维视图
row_r2 = a[1:2, :] # a第二行的2维视图
print(row_r1, row_r1.shape) # 打印 "[5 6 7 8] (4,)"
print(row_r2, row_r2.shape) # 打印 "[[5 6 7 8]] (1, 4)"
# 当访问数组的列时也会产生同样的差别
col_r1 = a[:, 1]
col_r2 = a[:, 1:2]
print(col_r1, col_r1.shape) # 打印 "[ 2 6 10] (3,)"
print(col_r2, col_r2.shape) # 打印 "[[ 2]
# [ 6]
# [10]] (3, 1)"
下图是一个切片和索引操作的图解。
你也可以将赋值和切片结合起来
import numpy as np
a = np.arange(10) # 创建数组 [0 1 2 3 4 5 6 7 8 9]
a[5:] = 10
print(a) # 打印 "[ 0 1 2 3 4 10 10 10 10 10]"
b = np.arange(5) # 创建数组 [0 1 2 3 4]
a[5:] = b[::-1]
print(a) # 打印 "[0 1 2 3 4 4 3 2 1 0]"
Fancy indexing
Numpy提供了比常规python序列更多的索引方式。除了可以使用整数和切片索引,也可以使用布尔数组或者整数数组索引,这种方法叫做fancy indexing。它创建拷贝而不是视图。
整型数组访问:当我们使用切片语法访问数组时,得到的总是原数组的一个子集。整型数组访问允许我们利用其它数组的数据构建一个新的数组。当一个新数组是由整数数组索引创建的,新数组与这个整数数组的shape相同。
- 被索引数组是一维数组
import numpy as np
a = np.arange(0, 100, 10) # 创建一维数组 [0 10 20 30 40 50 60 70 80 90]
# 索引是一维数组,返回的数组shape=(5,),与索引数组i相同
i = np.array([1,1,3,8,5]) # 同一个索引值可以重复多次
print(a[i]) # 打印 "[10 10 30 80 50]"
# 索引也可以是列表
print(a[[1,1,3,8,5]]) # 打印 "[10 10 30 80 50]"
# 索引是二维数组。返回数组的shape=(2, 2),与索引数组j的shape相同。
j = np.array([ [ 3, 4], [ 9, 7 ] ]) # shape = (2, 2)
print(a[j]) # 打印 "[[30 40]
[90 70]]"
- 被索引数组是多维数组
import numpy as np
# 创建二维数组,shape=(3, 2)
# [[1 2]
# [3 4]
# [5 6]]
a = np.array([[1,2], [3, 4], [5, 6]])
# 当被索引数组是多维的时,单独的一个索引数组代表源数组的第一个维度
idx = np.array([0,1])
print(a[idx]) # 打印 "[[1 2]
[3 4]]"
# 我们可以给定多于一个索引数组
# 为每一维指定的索引数组的shape要相同
print(a[[0, 1, 2], [0, 1, 0]]) # 打印 "[1 4 5]"
# 上面整数数组的索引的例子与下面等价:
print(np.array([a[0, 0], a[1, 1], a[2, 0]])) # 打印 "[1 4 5]"
idx1 = np.array([[0,1],[1,2]])
idx2 = np.array([[1,0],[0,1]])
print(a[idx1,idx2]) # 打印 "[[2 3]
# [3 6]]"
整型数组访问语法还有个有用的技巧,可以用来选择或者更改矩阵中每行中的一个元素:
import numpy as np
a = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
print(a) # prints "array([[ 1, 2, 3],
# [ 4, 5, 6],
# [ 7, 8, 9],
# [10, 11, 12]])"
# 创建整数数组索引
b = np.array([0, 2, 0, 1])
# 使用b中的索引值从每一列中选择一个元素
print(a[np.arange(4), b]) # Prints "[ 1 6 7 11]"
# 索引b从每行中选择的元素都加上10
a[np.arange(4), b] += 10
print(a) # 打印 "array([[11, 2, 3],
# [ 4, 5, 16],
# [17, 8, 9],
# [10, 21, 12]])
布尔型数组访问:
布尔型数组访问可以让你选择数组中任意元素。
import numpy as np
#******************Example 1*****************************
#通常,这种访问方式用于选取数组中满足某些条件的元素:
a = np.array([[1,2], [3, 4], [5, 6]])
bool_idx = (a > 2) # 找到比2大的所有元素;
# 这会返回一个与a形状相同的布尔数组;
# 每一个位置的布尔值代表原数组中该位置的元素是否大于2
print(bool_idx) # 打印 "[[False False]
# [ True True]
# [ True True]]"
# 我们可以使用布尔数组索引构建一个1维数组,包含bool_idx中True对应的元素。
print(a[bool_idx]) # 打印 "[3 4 5 6]"
# 我们可以使用一条简明的语句完成以上所有操作
print(a[a > 2]) # 打印 "[3 4 5 6]"
# 我们也可以使用布尔数组索引对bool_idx中True对应的元素赋值
a[a>2] = 2
print(a) # 打印 "[[1 2]
[2 2]
[2 2]]"
#**********************Example 2************************
#创建一个2维数组,shape=(3, 4)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
a = np.arange(12).reshape(3,4)
b1 = np.array([True, True, False]) # 第一维的选择
b2 = np.array([True, False, True, False]) # 第二维的选择
print(a[b1, :]) # 打印 "[[0 1 2 3]
# [4 5 6 7]]"
print(a[:, b2]) # 打印 "[[ 0 2]
# [ 4 6]
# [ 8 10]]"
print(a[b1, b2]) # 打印 "[0 6]"
为了教程的简介,有很多数组访问的细节我们没有详细说明,可以查看文档。
拷贝和视图
当操作数组时,有时它们的数据会拷贝到一个新的数组,有时则不会。主要有以下几种情况
没有拷贝
简单的赋值操作不会对数组对象或者它们的数据产生拷贝:
import numpy as np
a = np.arange(12)
b = a # 一个新的对象被创建
# a和b是同一个ndarray对象的2个名字
print(b is a) # 打印 "True"
# 改变a的shape, b的shape自然也会改变
b.shape = 3,4
print(a.shape) # 打印 "(3, 4)"
视图或者浅拷贝
不同的array对象可以共享相同的数据。view
方法创建了一个共享相同数据的新数组对象。
c = a.view() # 用view方法创建数组c
print(c is a) # 打印 "False"
print(c.base is a) # 打印 "True"
print(c.flags.owndata) # 打印 "False"
c.shape = 2,6 # a的shape不改变
print(a.shape) # 打印 "(3, 4)"
c[0,4] = 1234 # a的数据会改变
print(a) # 打印 "[[ 0 1 2 3]
# [1234 5 6 7]
# [ 8 9 10 11]]"
深拷贝
d = a.copy() # 创建一个拥有新数据的新数组,d和a不共享任何东西
print(d is a) # 打印 "False"
print(d.base is a) # 打印 "False"
d[0,0] = 9999 # a的数据不会改变
print(a) # 打印 "[[ 0 1 2 3]
[1234 5 6 7]
[ 8 9 10 11]]"
基本运算
基本数学计算函数会对数组中元素逐个进行计算,既可以利用操作符重载,也可以使用函数方式:
import numpy as np
x = np.array([[1,2],[3,4]], dtype=np.float64)
y = np.array([[5,6],[7,8]], dtype=np.float64)
# 逐元素加法;都产生以下数组
# [[ 6.0 8.0]
# [10.0 12.0]]
print(x + y)
print(np.add(x, y))
# 逐元素减法;都产生以下数组
# [[-4.0 -4.0]
# [-4.0 -4.0]]
print(x - y)
print(np.subtract(x, y))
# 逐元素乘法;都产生以下数组
# [[ 5.0 12.0]
# [21.0 32.0]]
print(x * y)
print(np.multiply(x, y))
# 逐元素除法;都产生以下数组
# [[ 0.2 0.33333333]
# [ 0.42857143 0.5 ]]
print(x / y)
print(np.divide(x, y))
# 逐元素求平方根;产生以下数组
# [[ 1. 1.41421356]
# [ 1.73205081 2. ]]
print(np.sqrt(x))
# 逻辑运算
a = np.array([1, 1, 0, 0], dtype=bool)
b = np.array([1, 0, 1, 0], dtype=bool)
# 逐元素求逻辑与;都产生以下数组
# [ True False False False]
print(a & b)
print(np.logical_and(a,b))
# 逐元素求逻辑或;都产生以下数组
# [ True True True False]
print(a | b)
print(np.logical_or(a, b))
注意:*
是数组乘法并非矩阵乘法。在Numpy中使用dot
来进行矩阵乘法:
import numpy as np
x = np.array([[1,2],[3,4]])
y = np.array([[5,6],[7,8]])
v = np.array([9,10])
w = np.array([11, 12])
# 向量的内积;结果都是219
print(v.dot(w))
print(np.dot(v, w))
# 矩阵和向量的矩阵乘法;结果都是是1维数组[29 67]
print(x.dot(v))
print(np.dot(x, v))
# 矩阵和矩阵的矩阵乘法;结果是2维数组
# [[19 22]
# [43 50]]
print(x.dot(y))
print(np.dot(x, y))
一些操作,如+=
和*=
,会原地更改一个已经存在的数组而不会创建一个新的数组。
一些操作,如+=
和*=
,会原地更改一个已经存在的数组而不会创建一个新的数组。
import numpy as np
a = np.ones((2,3), dtype=int)
a *= 3 # 原地操作
print(a) # 打印 "[[3 3 3]
# [3 3 3]]"
操作不同数据类型的数组时,结果数组的类型会与更精确的数组的类型一致。
import numpy as np
a = np.ones(3, dtype=np.int32) # dtype = int32
b = np.linspace(0,3,3)
print(b.dtype) # float64
c = a + b
print(c.dtype) # float64
超越函数
import numpy as np
x = np.array([[1,2],[3,4]], dtype=np.float64)
# 逐元素求对数;产生以下数组
# [[ 0. 0.69314718]
# [ 1.09861229 1.38629436]]
print(np.log(x))
# 逐元素求指数;产生以下数组
# [[ 2.71828183 7.3890561 ]
# [ 20.08553692 54.59815003]]
print(np.exp(x))
# 逐元素求sin;产生以下数组
# [[ 0.84147098 0.90929743]
[ 0.14112001 -0.7568025 ]]
print(np.sin(x))
比较操作
import numpy as np
a = np.array([1, 2 ,3, 4])
b = np.array([4, 2 ,2, 4])
c = np.array([1, 2, 3, 4])
# 逐元素比较
print(a == b) # 打印 "[False True False True]"
print(a > b) # 打印 "[False False True False]"
# 数组整体比较
print(np.array_equal(a, b)) # 打印 "False"
print(np.array_equal(a, c)) # 打印 "True"
Basic reductions
默认情况下,这些操作会忽略数组的shape,将数组看做一个整体。然而,我们可以指定axis
参数,你可以指定某个axis执行一个操作。
求和、求平均
import numpy as np
x = np.array([[1,2],[3,4]])
# 计算所有元素的和; 结果都是 "10"
print(np.sum(x))
print(x.sum())
# 计算每一列的和; 结果都是 "[4 6]"
print(np.sum(x, axis=0))
print(x.sum(axis=0))
# 计算每一行的和; 结果都是
# " [[3]
# [7]]"
print(np.sum(x, axis=1,keepdims=True))
print(x.sum(axis=1,keepdims=True))
# mean的用法和sum类似
# 计算整个数组平均值;结果是 "2.5"
print(x.mean())
求极值
格式与求和运算类似
import numpy as np
x = np.array([[1,2],[3,4]])
print(x.max()) # 计算所有元素的最大值;结果是"4"
print(x.min()) # 计算所有元素的最小值;结果是"1"
print(x.argmax()) # 返回最大值索引;结果是"3"
print(x.argmin()) # 返回最小值索引;结果是"0"
逻辑运算
import numpy as np
print(np.all([True, True, False])) # 打印 "False"
print(np.any([True, True, False])) # 打印 "True"
截断操作
import numpy as np
a = np.arange(1,13).reshape(3,4)
# 将数组a中元素都截断在[2,9]的范围内
# "[2 2 3 4]
# [5 6 7 8]
# [9 9 9 9]]
print(np.clip(a,2,9))
广播
NumPy 数组的基本操作(比如加法)都是逐元素的(elementwise)。这当然要求进行运算的两个数组大小(shape)相同。然而 ,不同大小(shape)的数组之间也可能进行运算。广播是一种强有力的机制,它让Numpy可以让不同大小的矩阵在一起进行数学计算
最简单的一种情况是一个数组和一个标量的操作
import numpy as np
# 两个shape相同的数组相乘
a = np.array([1.0, 2.0, 3.0])
b = np.array([2.0, 2.0, 2.0])
print(a * b) # 打印 "[ 2. 4. 6.]"
# 一个数组和一个标量相乘
a = np.array([1., 2., 3.])
b = 2.0
print(a*b) # 打印 "[ 2. 4. 6.]"
'''
这个结果和前面b是数组的例子的结果相同。我们可以认为b在运算中被扩展成了和a尺寸相同的数组,
b中新元素就是原来元素的拷贝。当然这个关于扩展的类别只是概念上的。Numpy是非常智能的,
可以只使用一个标量而不用拷贝来完成这个操作。所以广播操作的内存和计算效率都是很高的。
第二个例子比第一个例子更高效,因为广播在进行乘法操作时移动更少的内存。
'''
一般的广播规则
- 如果数组的秩不同,使用1来将秩较小的数组进行扩展,直到两个数组的尺寸的长度都一样。
- 如果两个数组在某个维度上的长度是一样的,或者其中一个数组在该维度上长度为1,那么我们就说这两个数组在该维度上是相容的。
- 如果两个数组在所有维度上都是相容的,他们就能使用广播。
- 如果两个输入数组的尺寸不同,那么注意其中较大的那个尺寸。因为广播之后,两个数组的尺寸将和那个较大的尺寸一样。
- 在任何一个维度上,如果一个数组的长度为1,另一个数组长度大于1,那么在该维度上,就好像是对第一个数组进行了复制。
如果上述解释看不明白,可以读一读文档。
import numpy as np
# 计算向量外积
v = np.array([1,2,3]) # v的shape= (3,)
w = np.array([4,5]) # w的shape= (2,)
# 为了计算外积,我们先把v变成(3,1)的列向量;
# 结果如下
# [[ 4 5]
# [ 8 10]
# [12 15]]
print np.reshape(v, (3, 1)) * w
# 把向量加到矩阵的每一行
x = np.array([[1,2,3], [4,5,6]])
print x + v # 打印 "[[2 4 6]
# [5 7 9]]"
数组形状操作
Flattening
import numpy as np
a = np.array([[1,2,3],[4,5,6]])
# 以下两个函数都将多维数组变成一维数组
# 区别是 ravel 返回视图;flatten 返回拷贝。
# 结果都是 "[1 2 3 4 5 6]"
print(a.ravel())
print(a.flatten())
Reshaping
import numpy as np
a = np.array([1,2,3,4,5,6])
print(b.reshape(2,3)) # 打印 "[[1 2 3]
# [4 5 6]]"
添加维度
使用np.newaxis对象允许我们为数组添加一个维度
import numpy as np
z = np.array([1, 2, 3])
# 数组 shape= (3, 1)
# 结果 "[[1]
# [2]
# [3]]"
print(z[:,np.newaxis])
# 数组 shape = (1, 3)
# 结果 " [[1 2 3]]"
pirnt(z[np.newaxis,:])
Dimension shuffling
import numpy as np
a = np.arange(4*3*2).reshape(4,3,2)
print(a.shape) # 打印 "(4, 3, 2)"
# 将数组a的维度次序改变得到b
# 后两个维度移到前两个维度,第一个维度移到最后
b = a.transpose(1,2,0) # transpose得到的数组b是数组a的视图
print(b.shape) # 打印 "(3, 2, 4)"
print(a[0,2,1] == b[2,1,0]) # 打印 "True"
合并
import numpy as np
A = np.array([1,1,1])
B = np.array([2,2,2])
# 在竖直方向上叠加数组A,B
# 结果如下
# [[1 1 1]
# [2 2 2]]
print(np.vstack((A,B)))
# 在水平方向上叠加数组A,B
# 结果如下
# [1 1 1 2 2 2]
print(np.hstack((A,B)))
# 在不存在的维度上组合数组
print(np.stack((A,B),axis=0)) # shape = (2, 3)
# [[1 1 1]
# [2 2 2]]
print(np.stack((A,B),axis=1)) # shape = (3, 2)
# [[1 2]
# [1 2]
# [1 2]]
# 在存在的维度上组合数组
A = A[np.newaxis,:] # shape = (1,3)
B = B[np.newaxis,:] # shape = (1,3)
print(np.concatenate((A,B),axis=0)) # shape = (2, 3)
# [[1 1 1]
# [2 2 2]]
print(np.concatenate((A,B),axis=1)) # shape = (1, 6)
# [[1 1 1 2 2 2]]
分割
split的第二个参数可以是整数或者一维数组。
- 如果是整数。数组将被分为N个相等的数组。如果无法分成相等的数组,将会报错。
- 如果是一维数组。数组的每一个元素表明了在哪个位置分割数组。举个例子:
[2, 3]
,当axis=0时,结果为:
- ary[:2]
- ary[2:3]
- ary[3:]
import numpy as np
# 创建数组,shape = (3, 4)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
A = np.arange(12).reshape((3, 4))
# 纵向分割
# 结果如下
# [array([[0, 1],
# [4, 5],
# [8, 9]]), array([[ 2, 3],
# [ 6, 7],
# [10, 11]])]
print(np.split(A,2,axis=1))
# 横向分割
# 结果如下
# [array([[0, 1, 2, 3]]), array([[4, 5, 6, 7]]), array([[ 8, 9, 10, 11]])]
print(np.split(A,3,axis=0))
# split不均等分割
# 结果如下
# [array([[0, 1, 2, 3]]), array([[4, 5, 6, 7]]), array([[ 8, 9, 10, 11]])]
print(np.split(A,[1,2],axis=0))
# array_split进行不等量分割
# array_split和split唯一的区别是:
# array_split允许indices_or_sections是一个将数组不等分的整数
# 结果如下
# [array([[0, 1, 2, 3],
# [4, 5, 6, 7]]), array([[ 8, 9, 10, 11]])]
print(np.array_split(A, 2, axis=0))
数据排序
import numpy as np
# 创建2维数组,shape = (2, 3)
# [[4 3 5]
# [1 2 1]]
a = np.array([[4, 3, 5], [1, 2, 1]])
# 可以在数组的某一维排序
# 结果如下
# [[3 4 5]
# [1 1 2]]
print(np.sort(a, axis=1))
# 原地(in-place)排序
# a本身会被排序,打印a结果如下
# [[3 4 5]
# [1 1 2]]
a.sort(axis=1)
print(a)
# 排序与数组索引技巧结合:
b = np.array([4, 3, 1, 2])
j = np.argsort(a)
print(j) # 打印 "[2 3 1 0]" 对应排序后元素原来的索引
print(b[j]) # 打印 "[1 2 3 4]" 用数组j索引得到排序后的数组
# 找出极大、极小值对应的元素索引
c = np.array([3, 4, 1, 2])
j_max = np.argmax(b)
j_min = np.argmin(b)
print(j_max) # 最大值索引 "1"
print(j_min) # 最小值索引 "2"
Numpy文档
这篇教程涉及了你需要了解的numpy中的一些重要内容,但是numpy远不止如此。可以查阅官方文档来学习更多。