文章目录
一、前言
二、概述
2.1 安装
Numpy是一个运行速度非常快的数学库,主要用于数组计算。
Numpy可以采用pip来安装:pip install numpy
,安装成功后,可以使用np.__version__
来验证是否安装成功。
导入numpy包的常用方式
import numpy as np
2.2 基础
维度是描述数组结构的核心属性,表示数据的层次和方向,常见的有一维数组、二维数组、多维数组等。
轴是维度的具体方向,用axis=0,1,2……
表示,例如一维数组仅有axis=0
;二维数组有axis=0
行方向、axis=1
列方向。
大多数numpy数组都有一些限制:
- 数组所有元素必须属于同一类型
- 创建后,数组大小无法改变
- 每一行必须有相同的列数
三、数组
3.1 数组创建
3.1.1 从已有数据创建
🦊array
方法从列表/元组创建数组,格式为numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)
object
:数组或嵌套数列dtype
:数据类型copy
:对象是否需要复制order
:创建数组的样式,C为行方向,F为列方向,A为任意方向(默认)subok
:默认返回一个与基类类型一致的数组ndmin
:指定生成数组的最小维度
import numpy as np
a = np.array([1, 2, 3, 4, 5], ndmin = 2)
print (a) # [[1 2 3 4 5]]
🦊asarray
方法将输入转换为数组,格式numpy.asarray(a, dtype = None, order = None)
import numpy as np
x = [1,2,3]
a = np.asarray(x)
print (a) # [1 2 3]
🦊frombuffer
方法实现动态数组,格式numpy.frombuffer(buffer, dtype = float, count = -1, offset = 0)
buffer
:可以是任意对象,以流的形式传入
count
:读取的数据数量,默认为-1,读取所有数据
offset
:读取的初始位置,默认为0
import numpy as np
s = b'Hello World'
a = np.frombuffer(s, dtype = 'S1')
print (a)
# [b'H' b'e' b'l' b'l' b'o' b' ' b'W' b'o' b'r' b'l' b'd']
🦊fromiter
方法将可迭代对象转换为一维数组,格式numpy.fromiter(iterable, dtype, count=-1)
import numpy as np
# 使用 range 函数创建列表对象
list=range(5)
it=iter(list)
# 使用迭代器创建 ndarray
x=np.fromiter(it, dtype=float)
print(x)
# [0. 1. 2. 3. 4.]
3.1.2 创建特殊值数组
🦊empty
方法来创建指定形状、数据类型且未初始化的数组,格式为numpy.empty(shape, dtype = float, order = 'C')
shape
:数组形状dtype
:数据类型order
:有C行优先和F列优先选项,表示在内存中存储元素的顺序
注意,由于数组未初始化,元素为随机值
import numpy as np
x = np.empty([3,2], dtype = int)
print (x)
"""值为:
[[ 1 0]
[1970749584 32762]
[1970628064 32762]]
"""
🦊zeros
方法创建指定大小的数组,数组元素为0,格式numpy.zeros(shape, dtype = float, order = 'C')
order
:‘C’ 用于 C 的行数组,或者 ‘F’ 用于 FORTRAN 的列数组
🦊ones
方法创建指定大小的数组,数组元素为1,格式numpy.ones(shape, dtype = None, order = 'C')
order
:‘C’ 用于 C 的行数组,或者 ‘F’ 用于 FORTRAN 的列数组
🦊zeros_like
用于创建一个与给定数组具有相同形状的数组,元素为0;格式numpy.zeros_like(a, dtype=None, order='K', subok=True, shape=None)
a
:给定要创建相同形状的数组
shape
:默认为a数组的形状
subok
:是否允许返回子类,true返回子类对象,否则返回与数组a相似的数组
🦊ones_like
也是创建一个与给定数组相同形状的数组,以1填充,格式numpy.ones_like(a, dtype=None, order='K', subok=True, shape=None)
3.1.3 创建数值范围数组
🦊arange
方法创建等差数组,格式numpy.arange(start, stop, step, dtype)
start
:起始值,默认为0
stop
:终止值,不包括
step
:步长,默认为1
类似于python中range的使用
import numpy as np
x = np.arange(5)
print (x)
# [0 1 2 3 4]
🦊linspace
方法创建等差数组,格式np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
start
:起始值,默认为0
stop
:终止值,如果endpoint
为true
,该值则包含在数列中
num
:要生成的数量,默认为50
endpoint
:为true
时数列中包含stop值
retstep
:为true
时生成的数组会显示间距
import numpy as np
x = np.linspace(5,10,10,"false","true")
print (x)
# (array([ 5. , 5.55555556, 6.11111111, 6.66666667, 7.22222222,
# 7.77777778, 8.33333333, 8.88888889, 9.44444444, 10. ]), 0.5555555555555556)
🦊logspace
方法创建等比数列,格式np.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None)
start
:起始值,默认为0
stop
:终止值,如果endpoint
为true
,该值则包含在数列中
num
:要生成的数量,默认为50
endpoint
:为true
时数列中包含stop值
base
:对数的底,默认为10
import numpy as np
a = np.logspace(1.0, 2.0, num = 10)
print (a)
# [ 10. 12.91549665 16.68100537 21.5443469 27.82559402
# 35.93813664 46.41588834 59.94842503 77.42636827 100. ]
3.1.4 随机数组生成
3.1.5 其他
复制或重组现有数组
结构化数组创建
从文件或缓冲区加载
特殊数组生成器
3.2 数组属性
数组属性一览:
🦊shape
表示数组的维度,返回类似(行数,列数,……)
的结构
import numpy as np
a = np.array([[1,2,3],[4,5,6]])
print (a.shape) # (2,3)
除此之外,可以通过reshape
方法调整数组形状:
b = a.reshape(3,2)
# [[1 2][3 4][5 6]]
🦊dtype
用于定义数组中元素的类型,numpy支持的数据类型和c的相似,常用的有:
dtype语法为
numpy.dtype(object,align,copy)
,对于int8
,int16
,int32
,int64
可以使用字符串i1
,i2
,i4
,i8
来代替
object
:要转换为的数据类型对象
align
:如果为true,填充字段使其类似C的结构体
copy
:复制dtype对象,如果为false,则是对内置数据类型对象的引用
结构化类型的情况下,规定了字段的名称、每个字段的数据类型和所取的内存块部分
import numpy as np
# 结构化数据类型的使用
dt = np.dtype([('age',np.int8)])
print(dt) # [('age', 'i1')]
a = np.array([(10,),(20,),(30,)], dtype = dt)
print(a) # [(10,) (20,) (30,)]
print(a["age"]) # [10 20 30]
🦊ndim
返回数组的维度数量(轴数),举个栗子,一维数组轴数为一,二维数组轴数为二……
arr_1d = np.array([1, 2, 3])
print(arr_1d.ndim) # 输出 1
arr_2d = np.array([[1, 2], [3, 4]])
print(arr_2d.ndim) # 输出 2
🦊size
返回数组的元素总数量
arr = np.zeros((3, 4))
print(arr.size) # 输出 12(3×4)
🦊itemsize
返回数组中每个元素的字节大小
arr_int = np.array([1, 2], dtype=np.int32)
print(arr_int.itemsize) # 输出 4(每个int32占4字节)
arr_float = np.array([1.0, 2.0], dtype=np.float64)
print(arr_float.itemsize) # 输出 8(每个float64占8字节)
🦊nbytes
返回数组所有元素占用的总字节数
arr = np.ones((2, 3), dtype=np.float32)
print(arr.nbytes) # 输出 24(2×3×4字节)
🦊strides
返回遍历数组时在每个维度上需要跨过的字节数(内存布局信息),例如下面例子中,行维度需要跨越12字节($ 3\times 4 $),列维度上每列间隔4字节。
arr = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.int32)
print(arr.strides) # 输出 (12, 4)
🦊flags
返回数组内存布局的详细信息,关键标志有:
C_CONTIGUOUS
:C风格连续内存F_CONTIGUOUS
:Fortran风格连续内存OWNDATA
:数组是否拥有数据副本WRITEABLE
:数据是否可修改
arr = np.array([[1, 2], [3, 4]])
print(arr.flags)
# 输出:
# C_CONTIGUOUS : True
# F_CONTIGUOUS : False
# OWNDATA : True
# WRITEABLE : True
# ALIGNED : True
# WRITEBACKIFCOPY : False
🦊T
返回数组的转置视图
arr = np.array([[1, 2], [3, 4]])
print(arr.T)
# 输出:
# [[1 3]
# [2 4]]
四、数组操作
4.1 索引/切片
numpy数组的索引与切片类似于Python列表
a = np.array([1,2,3,4,5])
print(a) # [1 2 3 4 5]
print(a[0]) # 1
print(a[:3]) #[1 2 3]
但也存在着区别:
- 列表切片会创建新的列表副本
- 数组切片返回的是视图,修改视图会影响原始数组
a = np.array([1,2,3,4,5])
b = [1,2,3,4,5]
temp = a[:3]
temp[0] = 10
print(a) # [10,2,3,4,5]
temp = b[:3]
temp[0] = 10
print(b) # [1,2,3,4,5]
除此之外,numpy也提供了更多的索引方式
🦊整数数组索引:使用一个数组来访问另一个数组的元素,这个数组的元素都是目标数组某个维度上的索引值,格式arr[行,列]
import numpy as np
# 获取(0,0),(1,1) 和 (2,0) 位置处的元素
x = np.array([[1, 2], [3, 4], [5, 6]])
y = x[[0,1,2], [0,1,0]]
print (y) # [1 4 5]
🦊布尔索引:通过布尔数组来索引
# 一维
arr = np.array([3, 1, 4, 1, 5])
mask = arr > 2
print(arr[mask]) # 输出 [3 4 5](筛选大于2的元素)
# 多维
arr_2d = np.array([[1, 2], [3, 4], [5, 6]])
mask = arr_2d > 3
print(arr_2d[mask]) # 输出 [4 5 6](展平后符合条件的元素)
# 多条件: 与、或、非
mask = (arr > 2) & (arr < 5)
print(arr[mask]) # 输出 [3 4]
🦊花式索引:利用整数数组进行索引
# 一维 :对应位置的元素
arr = np.array([10, 20, 30, 40, 50])
indices = [0, 2, 4]
print(arr[indices]) # 输出 [10 30 50]
# 二维 : 对应下标的行
arr_2d = np.array([[1, 2], [3, 4], [5, 6]])
rows = [0, 2]
cols = [1, 0]
print(arr_2d[rows, cols]) # 输出 [2, 5](取(0,1)和(2,0)的元素)
np.ix_
生成网格索引,即输入的两个数组进行笛卡尔积
arr_2d = np.array([[1, 2], [3, 4], [5, 6]])
rows = [0, 2]
cols = [1]
print(arr_2d[np.ix_(rows, cols)]) # 输出 [[2], [6]]
总结一下:
4.2 数组遍历
使用nditer方法来迭代数组,格式nditer(op, flags=None, op_flags=None, op_dtypes=None, order='K', casting='safe', op_axes=None, itershape=None, buffersize=0)
,详细见https://numpy.org/doc/stable/reference/generated/numpy.nditer.html
op
:迭代的数组flags
:控制迭代器行为,有multi_index
多索引、external_loop
外部循环优化op_flags
:操作模式,有readonly
默认、readwrite
可修改op_dtypes
:强制转换数据类型order
:迭代顺序,'C'
行优先,'F'
列优先
控制迭代顺序:
import numpy as np
a = np.array([[ 0, 1, 2],
[10,11,12],
[20,21,22],
[30,31,32]])
print("列优先遍历:")
for x in np.nditer(a, order='F'):
print(x)
print("行优先遍历:")
for x in np.nditer(a.T, order='C'):
print(x)
多数组同时迭代:
a = np.array([1, 2, 3])
b = np.array([[10], [20]])
it = np.nditer((a, b), flags=['external_loop'])
for x, y in it:
print(f"x={x}, y={y}")
# 输出:
# x=[1 2 3], y=[10 10 10] # 广播后的结果
# x=[1 2 3], y=[20 20 20]
4.3 修改形状
reshape(arr,newshape,order='C')
import numpy as np
a = np.array([[1,2,3],[4,5,6]])
print (a.shape) # (2,3)
b = a.reshape(3,2)
# [[1 2][3 4][5 6]]
flat
方法是数组元素迭代器
import numpy as np
a = np.arange(9).reshape(3,3)
print ('原始数组:')
for row in a:
print (row)
#对数组中每个元素都进行处理,可以使用flat属性,该属性是一个数组元素迭代器:
print ('迭代后的数组:')
for element in a.flat:
print (element)
flatten
返回一份数组拷贝,格式ndarray.flatten(order='C')
order
:'C'
按行;'F'
按列;'A'
原顺序;'K'
元素在内存中出现的顺序
ravel
返回数组试图,格式numpy.ravel(a, order='C')
4.4 更多
数组翻转
连接数组
分割数组
数组元素添加/删除
五、数组运算
5.1 常规运算
数组间可以进行加减乘除,但是需要相同形状或符合广播规则
import numpy as np
a = np.arange(9, dtype = np.float_).reshape(3,3)
b = np.array([10,10,10])
print ('两个数组相加:')
print (np.add(a,b))
print ('两个数组相减:')
print (np.subtract(a,b))
print ('两个数组相乘:')
print (np.multiply(a,b))
print ('两个数组相除:')
print (np.divide(a,b))
三角函数:sin、cos、tan、arcsin、arccos、arctan等
import numpy as np
a = np.array([0,30,45,60,90])
print ('不同角度的正弦值:')
# 通过乘 pi/180 转化为弧度
print (np.sin(a*np.pi/180))
print ('数组中角度的余弦值:')
print (np.cos(a*np.pi/180))
print ('数组中角度的正切值:')
print (np.tan(a*np.pi/180))
幂:power
import numpy as np
a = np.array([10,100,1000])
print ('调用 power 函数:')
print (np.power(a,2))
5.2 广播机制
广播是针对不同形状的数组进行数值计算的方式,广播的规则满足下述条件,则广播成功,否则抛出异常ValueError
- 维度相等:两个数组的对应维度长度相同
- 维度为1:其中一个数组的维度长度为1,可自动扩展为另一数组的维度长度
- 维度缺失:其中一个数组的维度更少,可在其形状前补1,直到维度数量一致
标量与数组运算:标量会自动扩展为目标数组相同形状
arr = np.array([[1, 2], [3, 4]])
result = arr + 5 # 等价于 arr + np.array([[5, 5], [5, 5]])
# 输出:
# [[ 6 7]
# [ 8 9]]
一维数组与二维数组:
a = np.array([[1, 2, 3], [4, 5, 6]]) # shape (2, 3)
b = np.array([10, 20, 30]) # shape (3,) → (1, 3)
result = a + b
# 输出:
# [[11 22 33]
# [14 25 36]]
无法广播:
a = np.zeros((3, 4))
b = np.zeros((2, 4))
# a + b 会报错:ValueError: operands could not be broadcast together
六、更多
6.1 数学函数
6.2 统计函数
6.3 线性代数
numpy提供了linalg库来执行线性代数所需要的功能
6.4 字符串函数
6.5 视图/副本
副本是一个数据的完整拷贝,对副本的修改不会影响原数据,但是视图是数据的一个别称或引用,对视图的修改会改变原数据。
可以通过base
属性来判定视图或副本:
arr = np.array([1,2,3,4,5])
view_slice=arr[1:4]
copy_arr=arr.copy()
print(view_slice.base is arr) # True(视图)
print(copy_arr.base is None) # True(副本)
也可以检查内存地址:
print(view_slice.__array_interface__['data'][0] == arr.__array_interface__['data'][0]) # True
print(copy_arr.__array_interface__['data'][0] == arr.__array_interface__['data'][0]) # False