在深度神经网络代码中经常用到numpy库的一些函数,很多看过之后很容易忘记,本文对经常使用的函数进行归纳总结。
np.arange
arange是numpy一个常用的函数,该函数主要用于创建等差数列。它的使用方法如下所示:
numpy.arange([start,] stop[, step])
参数说明:
- start:起始值,默认为0
- stop:结束值(不包含),左闭右开
- step:步长(可选,默认为1)
注意该函数返回值类型为“<class 'numpy.ndarray'>”
基础用法
import numpy as np
# 1. 只有一个参数(终点)
a = np.arange(5)
print(a) # [0 1 2 3 4]
print(type(a)) #<class 'numpy.ndarray'> 返回类型
# 2. 指定起点和终点
b = np.arange(2, 6)
print(b) # [2 3 4 5]
# 3. 指定起点、终点和步长
c = np.arange(0, 10, 2)
print(c) # [0 2 4 6 8]
# 4. 负步长
d = np.arange(5, -1, -1)
print(d) # [5 4 3 2 1 0]
另外arange也支持浮点数步长,请看下面的例子
import numpy as np
a = np.arange(1,2,0.2)
print(a) #[1.0,1.2,1.4,1.6,1.8]
np.array
这是numpy最基础也是最重要的数据结构。array函数创建序列需要从列表或者元组进行创建,这一点是与arange不相同的。
基础用法
import numpy as np
# 1. 从列表创建
arr1 = np.array([1, 2, 3, 4, 5])
print("一维数组:", arr1)
# 2. 从嵌套列表创建多维数组
arr2 = np.array([[1, 2, 3], [4, 5, 6]])
print("二维数组:\n", arr2)
# 3. 指定数据类型
arr3 = np.array([1, 2, 3], dtype=float)
print("浮点数数组:", arr3)
# 4. 从元组创建
arr4 = np.array((1, 2, 3))
print("从元组创建:", arr4)
数组属性
import numpy as np
def array_properties():
arr = np.array([[1, 2, 3], [4, 5, 6]])
print("维度:", arr.ndim) # 2
print("形状:", arr.shape) # (2, 3)
print("大小:", arr.size) # 6
print("数据类型:", arr.dtype) # int64
print("每个元素的字节数:", arr.itemsize)
print("总字节数:", arr.nbytes)
print("数据存储顺序:", arr.flags)
常见的数组操作
import numpy as np
# 1. 基本操作
def basic_operations():
arr = np.array([[1, 2, 3], [4, 5, 6]])
# 重塑
reshaped = arr.reshape(3, 2)
print("重塑后:\n", reshaped)
# 转置
transposed = arr.T
print("转置后:\n", transposed)
# 展平
flattened = arr.flatten()
print("展平后:", flattened)
# 2. 数组切片
def array_slicing():
arr = np.array([[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]])
# 基本切片
print("前两行:\n", arr[:2])
print("第二列:", arr[:, 1])
print("子矩阵:\n", arr[1:3, 1:3])
# 高级索引
indices = np.array([0, 2])
print("选择行:", arr[indices])
# 布尔索引
mask = arr > 5
print("大于5的元素:", arr[mask])
数组广播
import numpy as np
def broadcasting_examples():
# 1. 标量广播
arr = np.array([[1, 2, 3], [4, 5, 6]])
print("加标量:\n", arr + 1)
# 2. 数组广播
row = np.array([1, 2, 3])
print("加行向量:\n", arr + row)
col = np.array([[1], [2]])
print("加列向量:\n", arr + col)
# 3. 广播规则示例
a = np.array([[1, 2, 3], [4, 5, 6]]) # shape: (2, 3)
b = np.array([10, 20, 30]) # shape: (3,)
print("广播结果:\n", a + b)
broadcasting_examples()
#输出
加标量:
[[2 3 4]
[5 6 7]]
加行向量:
[[2 4 6]
[5 7 9]]
加列向量:
[[2 3 4]
[6 7 8]]
广播结果:
[[11 22 33]
[14 25 36]]
视图和副本
def views_and_copies():
arr = np.array([[1, 2, 3], [4, 5, 6]])
# 视图
view = arr.view()
view[0, 0] = 99
print("原数组被修改:\n", arr)
# 副本
copy = arr.copy()
copy[0, 0] = 88
print("原数组未被修改:\n", arr)
#输出
视图: [[1 2 3]
[4 5 6]]
原数组被修改:
[[99 2 3]
[ 4 5 6]]
原数组未被修改:
[[99 2 3]
[ 4 5 6]]
view() 创建一个数组视图,它与原数组共享相同的数据,但可以有不同的形状或数据类型。关键点是:
- 视图是共享数据的新数组对象
- 修改视图中的数据会影响原数组
- 视图的形状改变不影响原数组
看看下面的例子:
import numpy as np
def dtype_views():
# 1. 创建整数数组
arr = np.array([1, 2, 3, 4], dtype=np.int32)
# 2. 创建float类型的视图
view_float = arr.view(np.float32)
print("原数组:", arr)
print("原数组类型:", arr.dtype)
print("原数组id:",id(arr))
print("视图:", view_float)
print("视图类型:", view_float.dtype)
print("原数组id:",id(view_float))
dtype_views()
#输出
原数组: [1 2 3 4]
原数组类型: int32
原数组id: 136153673669328
视图: [1.e-45 3.e-45 4.e-45 6.e-45]
视图类型: float32
原数组id: 136153673387632
通过上面的结果可以看到,view方法返回的对象与原数组的对象id是不同的,但是他们的实际数据是存储在同一个位置的,所以修改view,原数组也会修改。这里就不在深入介绍了。
结论:
- 视图不复制数据,只创建新的数组对象
- 视图创建了新的数组对象,但指向相同的数据
实际应用场景
import numpy as np
# 1. 数据类型转换而不复制
def efficient_type_conversion():
# 创建大数组
arr = np.arange(1000000, dtype=np.int32)
# 使用视图转换类型(高效)
float_view = arr.view(np.float32)
# 对比复制方式
float_copy = arr.astype(np.float32)
print("视图是否共享内存:", np.shares_memory(arr, float_view))
print("副本是否共享内存:", np.shares_memory(arr, float_copy))
# 2. 图像处理中的应用
def image_processing():
# 创建模拟图像数据
img = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]], dtype=np.uint8)
# 创建展平视图进行处理
flat_view = img.view()
flat_view.shape = (-1,)
# 处理数据
flat_view += 10
print("处理后的图像:\n", img)
np.where
这是一个非常强大的函数,它的主要作用:
- 条件查找:返回满足条件的元素索引
- 条件选择:根据条件从两个数组中选择元素
条件查找
import numpy as np
def basic_where:
arr = np.array([1, 2, 3, 4, 5, 4, 3, 2, 1]) #array创建序列需要基于列表创建
#找出所有大于3的索引和对应的值
indices = np.where(arr > 3)
print(f'索引:{indices}')
print(f'对应的值:{arr[indices]}')
# 找出所有偶数的索引
even_indices = np.where(arr % 2 == 0)
print(f"偶数索引: {even_indices}")
print(f"偶数值: {arr[even_indices]}")
#多维数组示例
arr_2d = np.array([
[1,2,3],
[4,5,6],
[7,8,9]])
rows, cols= np.where(arr_2d > 5)
print("行索引:", rows) #行索引: [1 2 2 2]
print("列索引:", cols) #列索引: [2 0 1 2]
print("对应的值:", arr_2d[rows, cols]) #对应的值: [6 7 8 9]
result = np.where(arr_2d > 5)
print("结果:",result) #行索引: (array([1, 2, 2, 2]), array([2, 0, 1, 2]))
由此可见,np.where对于二维数组或多维数组进行条件检查,返回的是各个维度索引的组成的元组。
条件选择
import numpy as np
# 基本条件选择
def conditional_selection():
arr = np.array([1, 2, 3, 4, 5])
# 根据条件选择值:
# where(condition, x, y)
# 当condition为True时选择x,为False时选择y
result = np.where(arr > 3, arr, -1)
print(result) # [-1 -1 -1 4 5]
# 使用数组作为替换值
result2 = np.where(arr % 2 == 0, arr * 2, arr * 3)
print(result2) # [3 4 9 8 15]
# 多维数组条件选择
def multidim_conditional():
arr_2d = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
])
# 将大于5的元素替换为100
result = np.where(arr_2d > 5, 100, arr_2d)
print(result) #[[ 1 2 3]
# [ 4 5 100]
#[100 100 100]]