numpy初步掌握

发布于:2025-04-14 ⋅ 阅读:(16) ⋅ 点赞:(0)

一、前言

官方文档:https://numpy.org/learn/

参考资料:https://www.runoob.com/numpy/numpy-tutorial.html

二、概述

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数组都有一些限制:

  1. 数组所有元素必须属于同一类型
  2. 创建后,数组大小无法改变
  3. 每一行必须有相同的列数

三、数组

3.1 数组创建

3.1.1 从已有数据创建

🦊array方法从列表/元组创建数组,格式为numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)

  1. object:数组或嵌套数列
  2. dtype:数据类型
  3. copy:对象是否需要复制
  4. order:创建数组的样式,C为行方向,F为列方向,A为任意方向(默认)
  5. subok:默认返回一个与基类类型一致的数组
  6. 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')

  1. shape:数组形状
  2. dtype:数据类型
  3. 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:终止值,如果endpointtrue,该值则包含在数列中

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:终止值,如果endpointtrue,该值则包含在数列中

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),对于int8int16int32int64可以使用字符串i1i2i4i8来代替

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返回数组内存布局的详细信息,关键标志有:

  1. C_CONTIGUOUS:C风格连续内存
  2. F_CONTIGUOUS:Fortran风格连续内存
  3. OWNDATA:数组是否拥有数据副本
  4. 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]

但也存在着区别:

  1. 列表切片会创建新的列表副本
  2. 数组切片返回的是视图,修改视图会影响原始数组
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

  1. op:迭代的数组
  2. flags:控制迭代器行为,有multi_index多索引、external_loop外部循环优化
  3. op_flags:操作模式,有readonly默认、readwrite可修改
  4. op_dtypes:强制转换数据类型
  5. 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. 维度相等两个数组的对应维度长度相同
  2. 维度为1其中一个数组的维度长度为1,可自动扩展为另一数组的维度长度
  3. 维度缺失其中一个数组的维度更少,可在其形状前补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