一、NumPy库简介

NumPy(Numerical Python)是 Python 语言的一个扩展程序库。其中提供了许多向量和矩阵操作,能让用户轻松完成最优化、线性代数、积分、插值、特殊函数、傅里叶变换、信号处理和图像处理、常微分方程求解以及其他科学与工程中常用的计算,不仅方便易用而且效率更高。
NumPy 是一个开源的Python科学计算基础库,是SciPy、Pandas等数据处理或科学计算库的基础。包含:

  • 拥有一个类似于列表的、强大的N维数组对象ndarray,它描述了相同类型的元素的集合。并且它还是一个具有矢量运算和复杂广播能力的快速且节省空间的多维数组
  • 对整组数据进行快速运算的标准数学函数库,无需编写循环,即内置并行运算功能,当系统进行某种计算时,并且有多个核心时,NumPy会自动做并行计算。
  • NumPy底层用C语言编写,内部解除了GIL(全局解释性锁),其对数组的操作速度不受python解释器的限制,处理速度快,效率远高于纯python代码。
  • 具有实用的线性代数、傅里叶变换和随机生成函数的功能。
  • 可以直接完成数组和矩阵运算,无需循环。

二、NumPy库入门

1.数据的维度

  • 一个数据表达一个含义;一组数据表达一个或多个含义。维度是一组数据的组织形式。
    一个数据

  • 一维数据由对等关系的有序或无需数据构成,采用线性方式组织,对应列表、数组和集合等概念。其中,列表和数组都是一维数据的有序结构。列表:数据类型可以不同;数组:数据类型可以相同。
    一维数组

  • 二维数据由多个一维数据构成,是一维数据的组合形式,表格是典型的二维数据。(数据表)
    二维数组

  • 三维数据由一维或二维数据在新维度上扩展形成。(数据立方体)
    三维数组

  • 高维数据仅利用最基本的二元关系展示数据间的复杂结构。
    四维数组(数据柱)
    四维数组
    五维数组(数据墙)
    五维数组
    对于数据维度的Python表示,一维数据可以用列表或集合类型表示;二维或多维可以用列表类型表示;高维数据可以用字典或数据表示格式表示。目前,国际公认的数据表示格式有三种,分别是JSON、XML和YMAL格式。

数组的形状(Shape):描述数组的维度,用一个元组来表示,以及各个维度内部的元素个数。
( n 0 n_0 n0, n 1 n_1 n1…, n i n_i ni,… n m n_m nm)
数组的长度(Length):某个维度中的元素个数
数组的形状

2.安装NumPy

Anaconda:安装了anaconda之后,NumPy就已经被安装好了
pip:pip installnumpy

3.导入NumPy库

import numpy as np

三、NumPy的数组对象:ndarray

1 为什么要引入ndarry呢?

我们先来看一个例子:计算A的平方+B的三次方,其中,A和B是一维数组。
传统写法:

def pySum():
    a = [0,1,2,3,4]
    b = [9,8,7,6,5]
    c = []
    for i in range(len(a)):
        c.append(a[i]**2 + b[i]**3)
    return c

print(pySum())
# [729, 513, 347, 225, 141]

使用NumPy写法:

def npSum():
    a = np.array([0,1,2,3,4])
    b = np.array([9,8,7,6,5])
    c = a**2 + b**3
    return c

print(npSum())
# [729 513 347 225 141]

从中可以看出,①数组对象可以去掉元素运算所需的循环,使一维向量更像单个数据;②由于NumPy的底层是由c语言实现的,所以设置专门的数组对象,经过优化,可以提升这类应用的运算速度;通过观察,在科学计算中,一个维度所有数据的类型往往相同。③数组对象采用相同的数据类型,有助于节省运算和存储空间。

2. ndarray是一个多维数组对象

2.1 定义

NumPy中定义的最重要的对象是称为ndarray的N维数组对象(矩阵),它描述相同类型的元素集合。ndarray对象由计算机内存中的一维连续区域组成,ndarray中的每个元素在内存中使用相同大小的块。

ndarray由两部分构成:①实际的数据;②描述这些数据的元数据(数据维度、数据类型等)。
np.array()生成一个ndarray数组:
在这里插入图片描述

  • ndarray数组一般要求所有元素类型相同(同质),数组下标从0开始。
  • ndarray在程序中的别名是:array。
  • np.array()输出成[]形式,元素由空格分割。
  • ndarray有两个基本的概念:①轴(axis):保存数据的维度;②秩(rank):轴的数量,即这个数组有多少个维度。

2.2 内存中的存储形式

从ndarray对象提取的任何元素(通过切片)由一个数组标量类型的 Python 对象表示。 下图显示了ndarray,数据类型对象(dtype)和数组标量类型之间的关系。
在这里插入图片描述

  • 列表包含三个属性:列表的类型:列表类;列表的长度:元素个数;列表中的元素地址:指向元素对象的存储位置。每个元素对象包含:类型:该元素的类型;元素:该元素的值。
    列表可以存储多个数据类型。
    在这里插入图片描述
  • 数组包含四个属性:类型:表示元素的属性,即,每个元素应为同一数据类型;数据:按顺序排列着每个元素的值,便于广播;维度和步幅。
    在这里插入图片描述

综上可以看出,数组的存储结构使其性能大大提高,优于使用列表。

2.3 ndarray对象的属性

属性说明
.shapendarray对象维度的元组
.ndimndarray对象的维度
.sizendarray对象中元素总数,相当于.shape中n*m的值
.dtypendarray对象的元素类型
.itemsizendarray对象中每个元素的大小,以字节为单位
.flags这个函数返回了它们的当前值
a = np.array([[0,1,2,3,4],
              [9,8,7,6,5]])
a.ndim
Out[15]: 2 #一共有2个维度

a.shape
Out[16]: (2, 5) #第一个维度有两个方向,第二个维度有5个元素

a.size
Out[17]: 10 #一共有10个元素

a.dtype
Out[18]: dtype('int32') #这是一个32位的整数类型

a.itemsize
Out[19]: 4 #每个元素由4个字节构成
 
a.flags
Out[20]:
C_CONTIGUOUS : True #(C)  数组位于单一的、C 风格的连续区段内
F_CONTIGUOUS : True #(F) 数组位于单一的、Fortran 风格的连续区段内
OWNDATA : True # (O) 数组的内存从其它对象处借用
WRITEABLE : True # (W) 数据区域可写入。 将它设置为flase会锁定数据,使其只读
ALIGNED : True # (A) 数据和任何元素会为硬件适当对齐
UPDATEIFCOPY : False # (U) 这个数组是另一数组的副本。当这个数组释放时,源数组会由这个数组中的元素更新

2.4 ndarray数组的元素类型

类型类型代码说明
int8, uint8i1, u1有符号和无符号的8位(1个字节)整型
int16, uint16i2, u2有符号和无符号的16位(2个字节)整型
int32, uint32i4, u4有符号和无符号的32位(4个字节)整型
int64, uint64i8, u8有符号和无符号的64位(8个字节)整型
float16f2半精度浮点数
float32f4 或 f标准的单精度浮点数。与C的float兼容
float64f8 或 d标准的双精度浮点数。与C语言的double和python的float对象兼容
float128f16 或 g扩展精度浮点数
complex64, complex128, complex256c8, c16, c32分别用两个32位,64位,128位浮点数表示的复数
bool?存储True和False值的布尔类型
objectOpython对象类型
string_S固定长度的字符串类型(每个字符一个字节)。例如:要创建一个长度为10的字符串,应使用S10
unicode_U固定长度的Unicode类型(字节数由平台决定)跟字符串的定义方式一样

ndarray为什么要支持这么多种元素类型?
对比:Python语法仅支持整数、浮点数和复数3种类型。

  • 科学计算涉及数据较多,对存储和性能都有较高要求。
  • 对元素类型精细定义,有助于NumPy合理使用存储空间并优化性能。
  • 对元素类型精细定义,有助于程序员对程序规模有合理评估。

3. ndarray对象的创建方法

  • 从Python中的列表、元组等类型创建ndarray数组。
  • 使用NumPy中函数创建ndarray数组,如:arange,ones,zeros等。
  • 从字节流(raw bytes)中创建ndarray数组。
  • 从文件中读取特定格式,创建ndarray数组。

3.1 array()函数 - 自由创建

基本的ndarray是使用NumPy中的数组函数创建的,它接收一切序列型的对象,比如:列表元组可迭代对象等等,当然也包括它自己。
如下所示:

numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)

上面的构造器接受以下参数:

参数描述
object一切序列型的对象,比如:列表元组可迭代对象等等
dtype数组的所需数据类型,可选。
copy默认为true,对象是否被复制,可选
orderC(按行)、F(按列)或A(任意,默认
subok默认情况下,返回的数组被强制为基类数组。 如果为true,则返回子类。
ndmin指定返回数组的最小维数。

当np. array()不指定dtype时,NumPy将根据数据情况关联一个dtype类型。
下面我们看一些简单例子:

# 二维数组
import numpy
array = numpy.array([[1,2,3],[4,5,6]])
print(array)
# [[1 2 3]
#  [4 5 6]]
# dtype为复数
import numpy
array = numpy.array([1,2,3],dtype=complex)
print(array)
# [1.+0.j 2.+0.j 3.+0.j]
x = np.array([0,1,2,3]) #从列表类型创建
print(x)
[0 1 2 3]

x = np.array((4,5,6,7)) #从元组类型创建
print(x)
[4 5 6 7]

x = np.array([[1,2],[9,8],(0.1,0.2)]) #从列表和元组混合类型创建
print(x)
[[1.  2. ]
 [9.  8. ]
 [0.1 0.2]]

3.2 arange()函数 - 范围创建

这个函数返回ndarray对象,包含给定范围内的等间隔值。

a = numpy.arange(start, stop, step, dtype)

相关参数说明如下:

参数说明
start范围的起始值,默认为0
stop范围的终止值(不包含)
step步长,默认为1
dtype指定填充值的数据类型,如果没有提供,则会使用输入数据的类型
import numpy as np
# 设置了 dtype
x = np.arange(5, dtype=float)  
print x
# [0. 1. 2. 3. 4.]
# 设置了起始值和终止值参数  
import numpy as np
x = np.arange(10,20,2)  
print(X)
# [10  12  14  16  18]

3.3 empty() - 内存创建

该函数值分配数组大小内存,而不产生实际值。具有相同效果的还有有empty_like()函数。

np.empty(shape, dtype=None, order='C')

相关参数说明如下:

参数说明
shape列表或元祖表现的多维数组
orderC或者F,是否将多维数组以C或者Fortrain的形式存在内存中。默认为C
dtype指定填充值的数据类型,如果没有提供,则会使用输入数据的类型
a = np.empty((3,3))
print(a)
print(a[0]) # 值为0

# 打印
[[0.00000000e+000 0.00000000e+000 0.00000000e+000]
 [0.00000000e+000 0.00000000e+000 2.41104035e-321]
 [1.37962320e-306 1.29060870e-306 2.22518251e-306]]
[0. 0. 0.]

认为empty()和empty_like()结果的值为0是不正确的,因为很多情况下,它返回的是未初始化的垃圾值

3.4 ones()、zeros() - 自动填充创建

ones():返回特定大小,以1填充的新数组。

numpy.ones(shape, dtype = None, order = 'C')

相关参数说明如下:

参数说明
start范围的起始值,默认为0
stop范围的终止值(不包含)
step两个值的间隔,默认为1
dtype指定填充值的数据类型,如果没有提供,则会使用输入数据的类型
import numpy
x = numpy.ones([2,2], dtype = int)
print(x)
# [[1 1]
#  [1 1]]

zeros():返回特定大小,以0填充的新数组。

numpy.zeros(shape, dtype = None, order = 'C')

相关参数说明如下:

参数说明
start范围的起始值,默认为0
stop范围的终止值(不包含)
step两个值的间隔,默认为1
dtype指定填充值的数据类型,如果没有提供,则会使用输入数据的类型
# 含有5个0的数组,默认类型为float  
import numpy
x = numpy.zeros(5)  
print(x)
# [0. 0. 0. 0. 0.]

3.5 full()函数 - 填充创建

指定输出的形状,再指定一个数填充入该结构中,输出该结果。

np.full(shape, fill_value, dtype=None, order='C')

相关参数说明如下:

参数说明
shape列表或元祖表现的多维数组
fill_value填充值
dtype指定填充值的数据类型,如果没有提供,则会使用输入数据的类型
orderC或者F,是否将多维数组以C或者Fortrain的形式存在内存中。默认为C
np.full((2, 2), np.inf)

# 结果
array([[ inf,  inf],
       [ inf,  inf]])

3.6 eye() - 对角创建

创建一个类单位矩阵,即对角线上为1,其余为0的数组。指定形状即可创建。

np.eye(N, M=None, k=0, dtype=float, order='C')

相关参数说明如下:

参数说明
N输出的行数
M输出的列数。如果为空,默认大小等于N
k设定对角线索引位置。默认为主对角线,即0。正值,是上对角线;负值是下对角线。
dtype指定填充值的数据类型,如果没有提供,则会使用输入数据的类型
orderC或者F,是否将多维数组以C或者Fortrain的形式存在内存中。默认为C
a = np.eye(5, k=-2)
b = np.eye(5, k=2)
print(a) # 右移两格
print(b) # 左移两格

# 打印
[[0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]
 [1. 0. 0. 0. 0.]
 [0. 1. 0. 0. 0.]
 [0. 0. 1. 0. 0.]]
 
[[0. 0. 1. 0. 0.]
 [0. 0. 0. 1. 0.]
 [0. 0. 0. 0. 1.]
 [0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]]

3.7 repeat()函数 - 复制创建

将输入值的整体或某部分,在原来的基础上,进行指定次数的复制,从而创建新的输出值。

np.repeat(a, repeats, axis=None)

相关参数说明如下:

参数说明
aarray-like
repeats重复次数
axis执行方向
x = np.array([[1,2],[3,4]])
np.repeat(x, [1, 2], axis=0)

# 结果
array([[1, 2],
       [3, 4],
       [3, 4]])

3.8 random模块 - 随机创建

使用NumPy包中的random模块,它包含很多函数可以创建基于随机的数组。
具体函数可以参考:np.random模块的使用

np.random.randint(start, end, size)

相关参数说明如下:

参数说明
start随机范围的下边界
end随机范围的上边界
size随机结果的形态
n1 = np.random.randint(5, 15, size=(4, 4))

# 输出:
array([[12, 11, 14,  6],
       [ 5,  6, 13, 13],
       [ 8, 14, 13, 12],
       [ 8, 11, 10,  6]])

3.9 linspace()-等差数组创建

此函数类似于arange()函数。 在此函数中,指定了范围之间的均匀间隔数量,而不是步长

numpy.linspace(start, stop, num, endpoint, retstep, dtype)

相关参数说明如下:

参数说明
start序列的起始值
end序列的终止值
num要生成的等间隔样例数量,默认为50
endpoint如果为true,终止值包含在输出数组当中
retstep如果为true,返回样例,以及连续数字之间的步长
dtype输出数组的数据类型,如果没有提供,则取决于其它参数
a = np.linspace(10,20,5)  
print(a)
# [10.   12.5   15.   17.5  20.]

x = np.linspace(1,2,5, retstep =  True)
print(x)
#(array([ 1.  ,  1.25,  1.5 ,  1.75,  2.  ]), 0.25)

3.10 logspace()-等比数组创建

此函数返回一个ndarray对象,其中包含在对数刻度上均匀分布的数字。 刻度的开始和结束端点是某个底数的幂,通常为 10。

numpy.logscale(start, stop, num, endpoint, base, dtype)

相关参数说明如下:

参数说明
start起始值是base的start次幂
end终止值是base的stop次幂
num范围内的数值数量,默认为50
endpoint如果为true,终止值包含在输出数组当中
base对数空间的底数,默认为10
dtype输出数组的数据类型,如果没有提供,则取决于其它参数
# 默认底数是 10
a = np.logspace(1, 5, num=5, base=2)
print(a) 
# [ 2.  4.  8. 16. 32.]

3.11 asarray()-自由创建

此函数类似于numpy.array,这个例程对于将Python序列转换为ndarray非常有用。
基本功能和array()一样

numpy.asarray(a, dtype = None, order = None)

相关参数说明如下:

参数说明
a任意形式的输入参数,比如列表、列表的元组、元组、元组的元组、元组的列表。
dtype通常,输入数据的类型会应用到返回的ndarray。
order'C’为按行的C风格数组,'F’为按列的Fortran风格数组。

例子1:

list1 = [[1, 1, 1], [1, 1, 1], [1, 1, 1]]
arr1 = np.array(list1)
arr2 = np.asarray(list1)
list1[0][0] = 3
print(list1)
print(arr1)
print(arr2)
[[3, 1, 1], [1, 1, 1], [1, 1, 1]]
[[1 1 1]
 [1 1 1]
 [1 1 1]]
[[1 1 1]
 [1 1 1]
 [1 1 1]]

array()和asarray()都是对列表进行了深复制,所以列表改变,数组对象不变
例子2:

arr1 = np.ones((3, 3))
arr2 = np.array(arr1)
arr3 = np.asarray(arr1)
arr1[0][0] = 3
print(arr1)
print(arr2)
print(arr3)
"""
[[3. 1. 1.]
 [1. 1. 1.]
 [1. 1. 1.]]
[[1. 1. 1.]
 [1. 1. 1.]
 [1. 1. 1.]]
[[3. 1. 1.]
 [1. 1. 1.]
 [1. 1. 1.]]
"""

可见,arr2没有发生改变,而arr3发生了改变。
当数据源本身已经是一个ndarray对象时,array()仍然会复制出一个副本,asarray()则直接引用了原来的数组。这是和array()的区别

3.12 ones_like()-根据数组的形状创建

ones_like(a):根据数组a的形状生成一个全1的数组
zeros_like(a):根据数组a的形状生成一个全0的数组
full_like(a,val):根据数组a的形状生成一个数组,每个元素值都是val

x.shape
# (2, 3, 4)

np.ones_like(x)
"""
array([[[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]],

       [[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]]])
"""
np.zeros_like(x)
"""
array([[[0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.]],

       [[0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.]]])
"""
np.full_like(x,3)
"""
array([[[3., 3., 3., 3.],
        [3., 3., 3., 3.],
        [3., 3., 3., 3.]],

       [[3., 3., 3., 3.],
        [3., 3., 3., 3.],
        [3., 3., 3., 3.]]])
"""

3.13 frombuffer()-根据缓冲区创建

此函数将缓冲区解释为一维数组。 暴露缓冲区接口的任何对象都用作参数来返回ndarray。

numpy.frombuffer(buffer, dtype=float, count=-1, offset=0)

参数说明如下:

参数说明
buffer任何暴露缓冲区借口的对象。
dtype通常,输入数据的类型会应用到返回的ndarray。
count需要读取的数据数量,默认为-1,读取所有数据。
offset需要读取的起始位置,默认为0。

例子

s =  'Hello World' 
a = np.frombuffer(s, dtype =  'S1')  
print(a)
# ['H'  'e'  'l'  'l'  'o'  ' '  'W'  'o'  'r'  'l'  'd']

3.14 fromiter()-根据可迭代对象创建

此函数从任何可迭代对象构建一个ndarray对象,返回一个新的一维数组。

numpy.fromiter(iterable, dtype, count = -1)

参数说明如下:

参数说明
iterable任何可迭代对象。
dtype通常,输入数据的类型会应用到返回的ndarray。
count需要读取的数据数量,默认为-1,读取所有数据。

例子

# 从列表中获得迭代器  
list1 = range(5) 
it = iter(list1)  
# 使用迭代器创建 ndarray 
x = np.fromiter(it, dtype=float)  
print(x)
# [0.   1.   2.   3.   4.]

四、ndarray数组的形状变换

对于创建后的ndarray数组,可以对其进行维度变换和元素类型变换。

1. ndarray数组的维度变换

方法说明
.reshape(shape)不改变数组元素,返回一个shape形状的数组,原数组不变
.resize(shape)与.reshape()功能一样,但修改原数组
.swapaxes(ax1, ax2)将数组n个维度中两个维度进行调换
.flatten()对数组进行降维,返回折叠后的一维数组,原数组不变,深拷贝
.ravel()对数组进行降维,返回折叠后的一维数组,原数组改变,浅拷贝
b = np.arange(12)
print(b)
# [ 0  1  2  3  4  5  6  7  8  9 10 11]
c = b.reshape(3, 4)
print(c)
"""
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
"""
b.resize(3, 4)
print(b)
"""
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
"""

当改变形状时,应该考虑到数组中的元素的个数,确保改变前后,元素总个数相等

b = np.arange(12)
c = b.reshape(2, 5)
print(c)

在这里插入图片描述
快速创建数组并且改变数组形状

b = np.arange(12).reshape(3, 4)
print(b)
"""
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
"""

reshape(shape)还可以根据数组中元素的总个数、以及其他维度的取值,来自动计算出这个维度的取值。通过-1来实现

b = np.arange(12).reshape(-1, 6)
print(b)
"""
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]]
"""
# 只有一个参数表示一维数组,-1表示长度不知道,由numpy自动计算
b = np.arange(12).reshape(-1)
print(b)
# [ 0  1  2  3  4  5  6  7  8  9 10 11]

flatten方法和ravel方法

import numpy as np
n1 = np.random.randint(10,size=(4,4))
n1
# 结果
array([[8, 6, 0, 6],
       [5, 1, 2, 4],
       [9, 5, 9, 2],
       [9, 5, 4, 1]])

(1) flatten方法

n1.flatten()
# 结果
array([8, 6, 0, 6, 5, 1, 2, 4, 9, 5, 9, 2, 9, 5, 4, 1])

再次打印n1:

n1
array([[8, 6, 0, 6],
       [5, 1, 2, 4],
       [9, 5, 9, 2],
       [9, 5, 4, 1]])

(2) ravel属性

n1.ravel()
# 结果 同上
array([8, 6, 0, 6, 5, 1, 2, 4, 9, 5, 9, 2, 9, 5, 4, 1])

再次打印n1,同上:

n1
array([[8, 6, 0, 6],
       [5, 1, 2, 4],
       [9, 5, 9, 2],
       [9, 5, 4, 1]])

区别:

n1.flatten()[0] = 100
n1
# 不改变原数组的值,重新拷贝一份
array([[8, 6, 0, 6],
       [5, 1, 2, 4],
       [9, 5, 9, 2],
       [9, 5, 4, 1]])
n1.ravel()[0] = 100
n1
# 改变原数组的值,浅拷贝
array([[100, 6, 0, 6],
       [5, 1, 2, 4],
       [9, 5, 9, 2],
       [9, 5, 4, 1]])

flatten和ravel都有返回值,ravel是浅拷贝,它的地址还是指向原来的数组,改变任意一方,都会受影响;flatten是深拷贝,它已经被分配了新的地址,所以改变自身的值,原值不受影响。

2. ndarray数组的类型变换

astype()方法一定会创建新的数组,即使两个类型一致(原始数据的一个拷贝)。

new_a = a.astype(new dtype)
a = np.ones((2, 3), dtype=np.int) #np.int表示整数类型这一类
print(a)
"""
[[1 1 1]
 [1 1 1]]
"""
b = a.astype(np.float)
print(b)
"""
[[1. 1. 1.]
 [1. 1. 1.]]
"""

3. ndarry数组向列表的转换

ls = a.tolist()
a = np.full((2, 3), 25, dtype=np.int32)
print(a)

a.tolist()
print(a)
"""
[[25 25 25]
 [25 25 25]]
[[25 25 25]
 [25 25 25]]
"""

4. ndarray数组的转置和轴对换

数组的转置/轴对换只会返回源数据的一个视图,不会对源数据进行修改。

print('ndarray数组的转置和轴对换')
k = np.arange(9) #[0,1,....8]
m = k.reshape((3,3)) # 改变数组的shape复制生成2维的,每个维度长度为3的数组
print(k) # [0 1 2 3 4 5 6 7 8]
print(m)
"""
[[0 1 2]
 [3 4 5]
 [6 7 8]]
"""
# 转置(矩阵)数组:T属性 : mT[x][y] = m[y][x]
print(m.T)
"""
[[0 3 6]
 [1 4 7]
 [2 5 8]]
"""
# 高维数组的轴对象
k = np.arange(8).reshape((2, 2, 2))
print(k)
"""
[[[0 1]
  [2 3]]

 [[4 5]
  [6 7]]]
"""
print(k[1][0][0]) # 4
# 轴变换 transpose 参数:由轴编号组成的元组
m = k.transpose((1,0,2)) # m[y][x][z] = k[x][y][z] (0:x, 1:y, 2:z)
print(m)
"""
[[[0 1]
  [4 5]]

 [[2 3]
  [6 7]]]
"""
# 轴交换 swapaxes (axes:轴),参数:一对轴编号
m = k.swapaxes(0,1) # 将第一个轴和第二个轴交换 m[y][x][z] = k[x][y][z]
print(m)
"""
[[[0 1]
  [4 5]]

 [[2 3]
  [6 7]]]
"""
# 使用轴交换进行数组矩阵转置
m = np.arange(9).reshape((3,3))
print(m)
"""
[[0 1 2]
 [3 4 5]
 [6 7 8]]
"""
print(m.swapaxes(1,0))
"""
[[0 3 6]
 [1 4 7]
 [2 5 8]]
"""

5. nadarry数组的拼接

(1). vstack:垂直堆叠

v是vertical的英文单词缩写,是垂直的意思,所以是进行上下垂直方向上的堆叠,即:垂直堆叠。按照轴的标准看,则是axis=0,即按行拼接,将每一个水平行都堆叠在一起。那么列数必须相等。(注意理解,这并不矛盾)

import numpy as np

n1 = np.random.randint(10, size=(4, 4))
n2 = np.random.randint(10, size=(1, 4))
display(n1, n2)

# 结果
array([[5, 4, 7, 2],
       [7, 6, 4, 3],
       [7, 2, 5, 7],
       [0, 6, 9, 3]])
array([[0, 8, 4, 1]])
np.vstack([n1, n2])
# 结果
array([[5, 4, 7, 2],
       [7, 6, 4, 3],
       [7, 2, 5, 7],
       [0, 6, 9, 3],
       [0, 8, 4, 1]])
(2) hstack:水平堆叠

h是horizontal的英文缩写,表示垂直的意思,所以是进行水平方向上的堆叠:即水平堆叠。按照轴的标准看,则是axis=1,即按列拼接,将每一个垂直列都堆叠在一起。那么
行数必须相等。

import numpy as np

n1 = np.random.randint(10, size=(4, 4))
n2 = np.random.randint(10, size=(4, 1))
display(n1, n2)
# 结果
array([[1, 4, 7, 8],
       [2, 6, 7, 3],
       [9, 0, 1, 4],
       [1, 3, 3, 7]])
array([[4],
       [4],
       [6],
       [4]])
np.hstack([n1, n2])
# 结果
array([[1, 4, 7, 8, 4],
       [2, 6, 7, 3, 4],
       [9, 0, 1, 4, 6],
       [1, 3, 3, 7, 4]])
(3). concatenate([], axis)
import numpy as np
n1 = np.random.randint(10, size=(4, 4))
n2 = np.random.randint(10, size=(4, 4))
display(n1, n2)
# 结果
array([[3, 5, 4, 6],
       [8, 4, 1, 5],
       [8, 7, 6, 9],
       [5, 3, 7, 6]])
array([[6, 7, 9, 1],
       [4, 1, 9, 7],
       [6, 4, 0, 6],
       [9, 9, 7, 9]])
np.concatenate([n1, n2])
# 结果 默认axis=0, 从第一层内容对应开始拼接(np.concatenate([n1, n2], axis=0))
array([[3, 5, 4, 6],
       [8, 4, 1, 5],
       [8, 7, 6, 9],
       [5, 3, 7, 6],
       [6, 7, 9, 1],
       [4, 1, 9, 7],
       [6, 4, 0, 6],
       [9, 9, 7, 9]])
np.concatenate([n1, n2], axis=1)
# 结果 从第二层内容对应开始拼接
array([[3, 5, 4, 6, 6, 7, 9, 1],
       [8, 4, 1, 5, 4, 1, 9, 7],
       [8, 7, 6, 9, 6, 4, 0, 6],
       [5, 3, 7, 6, 9, 9, 7, 9]])
(4). np.c_[a ,b]
a = np.arange(10).reshape(2, -1)
b = np.repeat(1, 10).reshape(2, -1)
# 打印a,b
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])
array([[1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1]])

np.c_[a,b]
# 结果
array([[0, 1, 2, 3, 4, 1, 1, 1, 1, 1],
       [5, 6, 7, 8, 9, 1, 1, 1, 1, 1]])

6. nadarry数组的分割

创建一个 6 * 6 的二维数组:

import numpy as np

n1 = np.random.randint(10, size=(6, 6))
n1
# 结果
array([[9, 1, 9, 5, 7, 9],
       [8, 9, 0, 6, 8, 1],
       [5, 1, 5, 6, 4, 9],
       [3, 2, 1, 9, 8, 8],
       [3, 1, 5, 2, 2, 0],
       [0, 3, 1, 4, 0, 3]])
(1). hsplit:水平方向分成多个水平子数组

注意:split理解为分离的意思,而不是切割的意思,否则,后面的结果会理解相反。
要想实现水平方向的分离,则需要从列方向进行切割。

  • hsplit(ndarray, x), x指定:均匀分成几部分,不可均分则报错
np.hsplit(n1, 2)
# 输出
[array([[9, 1, 9],
        [8, 9, 0],
        [5, 1, 5],
        [3, 2, 1],
        [3, 1, 5],
        [0, 3, 1]]), array([[5, 7, 9],
        [6, 8, 1],
        [6, 4, 9],
        [9, 8, 8],
        [2, 2, 0],
        [4, 0, 3]])]
  • hsplit(ndarray, [x, y]), 用列表代表分割的索引,不一定要均分
np.hsplit(n1, [2, 4])
# 结果
[array([[9, 1],
        [8, 9],
        [5, 1],
        [3, 2],
        [3, 1],
        [0, 3]]), array([[9, 5],
        [0, 6],
        [5, 6],
        [1, 9],
        [5, 2],
        [1, 4]]), array([[7, 9],
        [8, 1],
        [4, 9],
        [8, 8],
        [2, 0],
        [0, 3]])]
(2). vsplit:分成多个垂直子数组
  • vsplit(ndarray, x), x指定:均匀分成几部分,不可均分则报错
np.vsplit(n1, 2)
# 输出
[array([[9, 1, 9, 5, 7, 9],
        [8, 9, 0, 6, 8, 1],
        [5, 1, 5, 6, 4, 9]]), array([[3, 2, 1, 9, 8, 8],
        [3, 1, 5, 2, 2, 0],
        [0, 3, 1, 4, 0, 3]])]
  • vsplit(ndarray, [x, y]), 用列表代表分割的索引
np.vsplit(n1, [2, 4])
# 结果
[array([[9, 1, 9, 5, 7, 9],
        [8, 9, 0, 6, 8, 1]]), array([[5, 1, 5, 6, 4, 9],
        [3, 2, 1, 9, 8, 8]]), array([[3, 1, 5, 2, 2, 0],
        [0, 3, 1, 4, 0, 3]])]
(3). split / array_split(array, indicate_or_sections, axis)

axis指定按照哪一层进行切割,默认从axis=0、第0层为标准进行切割, 即vsplit方法,将垂直方向分成多个垂直子数组

np.array_split(n1, [1, 4])
# 结果  9, (8, 5, 3), (3, 0)   或(np.arrat_split(n1, [1, 4], axis=0))
[array([[9, 1, 9, 5, 7, 9]]), array([[8, 9, 0, 6, 8, 1],
        [5, 1, 5, 6, 4, 9],
        [3, 2, 1, 9, 8, 8]]), array([[3, 1, 5, 2, 2, 0],
        [0, 3, 1, 4, 0, 3]])]
np.arrat_split(n1, [1, 4], axis=1)
# 结果 9, (1,9,5), (7, 9)
[array([[9],
        [8],
        [5],
        [3],
        [3],
        [0]]), array([[1, 9, 5],
        [9, 0, 6],
        [1, 5, 6],
        [2, 1, 9],
        [1, 5, 2],
        [3, 1, 4]]), array([[7, 9],
        [8, 1],
        [4, 9],
        [8, 8],
        [2, 0],
        [0, 3]])]

五、nadarry数组的索引

nadarry数组的操作包括数组的索引和切片。①索引:获取数组中特定位置元素的过程;②切片:获取数组元素子集的过程。

1. 一维数组的索引和切片

与Python的列表类似

a = np.array([9,8,7,6,5])
print(a[2])	# 7
print(a[1:4:2]) #起始编号:终止编号(不含):步长
# [8 6]

2. 多维数组的索引

a = np.arange(24).reshape((2, 3, 4))
print(a)
print(a[1, 2, 3])  #每个维度一个索引值,逗号分割
print(a[-1, 2, -2])
"""
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
"""
"""
23
22
"""

3. 多维数组的切片

一维数组

a = np.array([0, 1, 2, 3])
print(a[0:3])	# [0 1 2]
print(a[:3])	# [0 1 2]
print(a[0:])	# [0 1 2 3]

二维数组

a = np.array([[0, 1, 2], [4, 5, 6]])
print(a[0])
# [0 1 2]
print(a[0:2])
"""
[[0 1 2]
 [4 5 6]]
"""
print(a[:2])
"""
[[0 1 2]
 [4 5 6]]
"""
print(a[0:2, 0:2])
"""
[[0 1]
 [4 5]]
"""
print(a[0:2, 1:3])
"""
[[1 2]
 [5 6]]
"""
print(a[:, 0])
"""
[0 4]
"""

三维数组

a = np.array([[[0, 1, 2], [3, 4, 5]], [[6, 7, 8], [9, 10, 11]]])
print(a[:, :, 0])
"""
[[0 3]
 [6 9]]
"""
print(a[:, :, 0:2:2]) # print(a[:, :, ::2])
"""
[[ 2  5]
 [ 8 11]]
"""

切片还可以包括省略号(…),来使选择元组的长度与数组的维度相同。 如果在行位置使用省略号,它将返回包含行中元素的ndarray。

a = np.array([[1, 2, 3], [3, 4, 5], [4, 5, 6]])
print(a)
"""
[[1 2 3]
 [3 4 5]
 [4 5 6]]
"""
# 这会返回第二列元素的数组:
print(a[..., 1])
"""
[2 4 5]
"""
# 现在我们从第二行切片所有元素:
print(a[1, ...])
"""
[3 4 5]
"""
# 现在我们从第二列向后切片所有元素:
print(a[..., 1:])
"""
[[2 3]
 [4 5]
 [5 6]]
"""

4. 花式索引

选出方形索引区域,使用ix_()函数
索引的数量与维度对应,并且,每个索引列表内都是一维的。

np.ix_([索引1],[索引2],[索引3])

例子:

arr1 = np.array([[8, 2, 3, 4],
       [3, 5, 3, 9],
       [3, 9, 9, 9],
       [3, 2, 5, 5]])
print(arr1[np.ix_([0,2],[1,3])])
# 打印
"""
[[2 4]
 [9 9]]
"""

5. 布尔索引

布尔索引:使用布尔数组作为索引。arr[condition],condition为一个条件/多个条件组成的布尔数组。

示例:

x = np.array([3, 2, 3, 1, 3, 0])
# 布尔型数组的长度必须跟被索引的轴长度一致
y = np.array([True, False, True, False, True, False])
print(x[y])  # [3,3,3]
print(x[y == False])  # [2,1,0]
print(x >= 3)  # [ True False  True False  True  False]
print(x[~(x >= 3)])  # [2,1,0]
print((x == 2) | (x == 1))  # [False  True False  True False False]
print(x[(x == 2) | (x == 1)])  # [2 1]
x[(x == 2) | (x == 1)] = 0
print(x)  # [3 0 3 0 3 0]

参考:
NumPy库的介绍与使用教程
Python之Numpy详细教程
NumPy — 从零到入门

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐