Numpy技巧与实战案例分享:轻松实现数组操作 – wiki基地


NumPy 技巧与实战案例分享:轻松实现数组操作

NumPy(Numerical Python)是 Python 中用于科学计算的基础软件包。它提供了一个强大的多维数组对象 ndarray,以及用于处理这些数组的各种派生对象(例如,屏蔽数组和矩阵)。此外,NumPy 还包含了用于执行各种数学运算(如线性代数、傅里叶变换和随机数生成)的函数,这些运算通常比纯 Python 实现更高效。

NumPy 的核心优势在于其矢量化操作。这意味着你可以对整个数组执行操作,而无需编写显式的循环。这不仅使代码更简洁、更易读,而且由于 NumPy 在底层使用经过优化的 C 代码,因此执行速度也更快。

本文将深入探讨 NumPy 的各种实用技巧,并通过具体的实战案例来展示如何利用这些技巧轻松实现数组操作,从而提高你的数据处理和分析效率。

1. NumPy 基础:数组创建与属性

1.1 数组创建

NumPy 提供了多种创建数组的方法:

  • array() 函数: 从 Python 列表或元组创建数组。

    “`python
    import numpy as np

    从列表创建

    arr1 = np.array([1, 2, 3, 4, 5])
    print(arr1) # 输出: [1 2 3 4 5]

    从元组创建

    arr2 = np.array((6, 7, 8, 9, 10))
    print(arr2) # 输出: [ 6 7 8 9 10]

    创建多维数组

    arr3 = np.array([[1, 2, 3], [4, 5, 6]])
    print(arr3)

    输出:

    [[1 2 3]

    [4 5 6]]

    “`

  • zeros() 函数: 创建一个全零数组。

    “`python
    arr_zeros = np.zeros((3, 4)) # 创建一个 3×4 的全零数组
    print(arr_zeros)

    输出:

    [[0. 0. 0. 0.]

    [0. 0. 0. 0.]

    [0. 0. 0. 0.]]

    “`

  • ones() 函数: 创建一个全一数组。

    “`python
    arr_ones = np.ones((2, 5)) # 创建一个 2×5 的全一数组
    print(arr_ones)

    输出:

    [[1. 1. 1. 1. 1.]

    [1. 1. 1. 1. 1.]]

    “`

  • empty() 函数: 创建一个未初始化的数组(内容是随机的)。

    python
    arr_empty = np.empty((4, 2)) # 创建一个 4x2 的未初始化数组
    print(arr_empty) # 输出内容是随机的

  • arange() 函数: 创建一个等差数列数组。

    python
    arr_arange = np.arange(10, 30, 5) # 创建一个从 10 到 30(不包括 30),步长为 5 的数组
    print(arr_arange) # 输出: [10 15 20 25]

  • linspace() 函数: 创建一个等间隔数列数组。

    python
    arr_linspace = np.linspace(0, 1, 5) # 创建一个从 0 到 1(包括 1),包含 5 个元素的数组
    print(arr_linspace) # 输出: [0. 0.25 0.5 0.75 1. ]

  • random 模块: 创建随机数组。

“`python
# 创建一个形状为 (2, 3) 的随机数组,元素值在 [0, 1) 之间
random_arr = np.random.rand(2, 3)
print(random_arr)

# 创建一个形状为 (3, 3) 的随机整数数组,元素值在 [1, 10) 之间
random_int_arr = np.random.randint(1, 10, size=(3, 3))
print(random_int_arr)

“`

1.2 数组属性

NumPy 数组具有以下常用属性:

  • ndim: 数组的维度(秩)。
  • shape: 数组的形状(每个维度的大小)。
  • size: 数组中元素的总数。
  • dtype: 数组中元素的数据类型。
  • itemsize: 数组中每个元素占用的字节数。
  • nbytes: 整个数组占用的总字节数。

“`python
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 (或 int32,取决于系统)
print(“每个元素字节数:”, arr.itemsize) # 输出: 每个元素字节数: 8 (或 4,取决于系统)
print(“总字节数:”, arr.nbytes) # 输出: 总字节数: 48 (或 24,取决于系统)
“`

2. NumPy 核心:数组索引、切片与迭代

2.1 数组索引

NumPy 数组的索引方式与 Python 列表类似,但功能更强大:

  • 单个元素索引: 使用方括号 [] 和元素的索引位置(从 0 开始)。

    python
    arr = np.array([10, 20, 30, 40, 50])
    print(arr[0]) # 输出: 10
    print(arr[3]) # 输出: 40
    print(arr[-1]) # 输出: 50 (负数索引表示从末尾开始)

  • 多维数组索引: 使用逗号分隔的多个索引值。

    python
    arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    print(arr[0, 0]) # 输出: 1 (第一行第一列)
    print(arr[1, 2]) # 输出: 6 (第二行第三列)
    print(arr[2, -1]) # 输出: 9 (第三行最后一列)

2.2 数组切片

切片用于提取数组的子集:

  • 一维数组切片: 类似于 Python 列表的切片。

    python
    arr = np.array([10, 20, 30, 40, 50])
    print(arr[1:4]) # 输出: [20 30 40] (从索引 1 到索引 4 之前)
    print(arr[:3]) # 输出: [10 20 30] (从开头到索引 3 之前)
    print(arr[2:]) # 输出: [30 40 50] (从索引 2 到末尾)
    print(arr[::2]) # 输出: [10 30 50] (从开头到末尾,步长为 2)

  • 多维数组切片: 使用逗号分隔每个维度的切片。

    “`python
    arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    print(arr[0:2, 1:3])

    输出:

    [[2 3]

    [5 6]] (第一行到第二行之前,第二列到第三列之前)

    print(arr[:, 1]) # 输出: [2 5 8] (所有行的第二列)
    print(arr[1, :]) # 输出: [4 5 6] (第二行的所有列)
    “`

2.3 布尔索引

布尔索引是一种强大的技术,它允许你使用布尔数组(True/False 数组)来选择数组中的元素。

“`python
arr = np.array([1, 2, 3, 4, 5, 6])
bool_index = arr > 3 # 创建一个布尔数组,指示哪些元素大于 3
print(bool_index) # 输出: [False False False True True True]
print(arr[bool_index]) # 输出: [4 5 6] (选择布尔数组中为 True 的元素)

更简洁的写法:

print(arr[arr > 3]) # 输出: [4 5 6]
“`
2.4 花式索引
花式索引使用整数数组进行索引。

“`python
arr = np.array([10, 20, 30, 40, 50, 60])
indices = np.array([1, 3, 5]) # 要选择的元素的索引
print(arr[indices]) # 输出: [20 40 60]

多维数组

arr = np.arange(12).reshape((3, 4))
print(arr)

[[ 0 1 2 3]

[ 4 5 6 7]

[ 8 9 10 11]]

row = np.array([0, 1, 2])
col = np.array([1, 2, 3])
print(arr[row, col]) # 输出: [ 1 6 11]
“`

2.5 数组迭代

  • for 循环: 可以直接使用 for 循环遍历数组的元素。

    “`python
    arr = np.array([1, 2, 3])
    for x in arr:
    print(x)

    输出:

    1

    2

    3

    “`

  • nditer() 函数: nditer() 函数提供了一种更灵活的迭代方式,可以控制迭代顺序和访问元素的方式。

    “`python
    arr = np.array([[1, 2], [3, 4]])
    for x in np.nditer(arr):
    print(x)

    输出:

    1

    2

    3

    4

    # 使用 order=’F’ 参数按列优先顺序迭代 (Fortran-style order)
    for x in np.nditer(arr, order=’F’):
    print(x)

    #使用 op_flags 参数修改元素值
    for x in np.nditer(arr, op_flags=[‘readwrite’]):
    x[…] = 2 * x
    print(arr) #输出[[2,4],[6,8]]
    “`

3. NumPy 进阶:数组操作与通用函数

3.1 数组形状操作

  • reshape() 函数: 改变数组的形状(不改变元素)。

    “`python
    arr = np.arange(12) # 创建一个包含 0-11 的一维数组
    arr_reshaped = arr.reshape(3, 4) # 将数组重塑为 3×4 的二维数组
    print(arr_reshaped)

    输出:

    [[ 0 1 2 3]

    [ 4 5 6 7]

    [ 8 9 10 11]]

    arr_reshaped_again = arr.reshape(2, 2, 3) #重塑为三维数组
    “`

  • ravel() 函数: 将多维数组展平为一维数组。

    python
    arr = np.array([[1, 2, 3], [4, 5, 6]])
    arr_flattened = arr.ravel()
    print(arr_flattened) # 输出: [1 2 3 4 5 6]

    flatten()的功能与ravel()相同,不过flatten返回的是拷贝,而ravel返回的是视图(view).

  • transpose() 函数 / T 属性: 转置数组(交换行和列)。

    “`python
    arr = np.array([[1, 2, 3], [4, 5, 6]])
    arr_transposed = arr.transpose()
    print(arr_transposed)

    输出:

    [[1 4]

    [2 5]

    [3 6]]

    print(arr.T) # 与 arr.transpose() 效果相同
    “`

3.2 数组拼接与拆分

  • concatenate() 函数: 沿指定轴连接多个数组。

    “`python
    arr1 = np.array([[1, 2], [3, 4]])
    arr2 = np.array([[5, 6]])
    arr_concatenated = np.concatenate((arr1, arr2), axis=0) # 沿行方向(axis=0)连接
    print(arr_concatenated)

    输出:

    [[1 2]

    [3 4]

    [5 6]]

    arr3 = np.array([[7],[8]])
    arr_concatenated_axis1 = np.concatenate((arr1,arr3), axis=1) #沿列方向
    print(arr_concatenated_axis1)
    “`

  • vstack() 函数: 垂直堆叠数组(沿行方向)。

    “`python
    arr1 = np.array([1, 2, 3])
    arr2 = np.array([4, 5, 6])
    arr_stacked = np.vstack((arr1, arr2))
    print(arr_stacked)

    输出:

    [[1 2 3]

    [4 5 6]]

    “`

  • hstack() 函数: 水平堆叠数组(沿列方向)。

    python
    arr1 = np.array([1, 2, 3])
    arr2 = np.array([4, 5, 6])
    arr_stacked = np.hstack((arr1, arr2))
    print(arr_stacked) # 输出: [1 2 3 4 5 6]

  • split() 函数: 将数组拆分为多个子数组。

    “`python
    arr = np.arange(9)
    arr_split = np.split(arr, 3) # 将数组拆分为 3 个大小相等的子数组
    print(arr_split) # 输出: [array([0, 1, 2]), array([3, 4, 5]), array([6, 7, 8])]

    arr = np.arange(12).reshape(3,4)
    arr_split_axis1 = np.split(arr, 2, axis=1) #沿着列方向拆分
    “`

  • hsplit()vsplit(): 分别沿水平和垂直方向拆分数组,相当于split()axis分别设置为10

3.3 通用函数 (ufunc)

通用函数(universal functions,简称 ufunc)是对数组进行逐元素运算的函数。NumPy 提供了大量的 ufunc,涵盖了各种数学、三角、逻辑、位运算等操作。

  • 算术运算: +, -, *, /, ** (幂), // (整除), % (取模)。

    “`python
    arr1 = np.array([1, 2, 3])
    arr2 = np.array([4, 5, 6])

    print(arr1 + arr2) # 输出: [5 7 9] (逐元素相加)
    print(arr1 * arr2) # 输出: [ 4 10 18] (逐元素相乘)
    print(arr1 ** 2) # 输出: [1 4 9] (逐元素求平方)
    “`

  • 比较运算: ==, !=, >, <, >=, <=.

    “`python
    arr1 = np.array([1, 2, 3])
    arr2 = np.array([2, 2, 4])

    print(arr1 == arr2) # 输出: [False True False] (逐元素比较)
    print(arr1 < arr2) # 输出: [ True False True]
    “`

  • 数学函数: np.sin(), np.cos(), np.tan(), np.exp(), np.log(), np.sqrt(), np.abs(), 等。

    python
    arr = np.array([0, np.pi/2, np.pi])
    print(np.sin(arr)) # 输出: [0.0000000e+00 1.0000000e+00 1.2246468e-16] (逐元素计算正弦值)
    print(np.sqrt(arr)) # 逐元素计算平方根

  • 聚合函数: np.sum(), np.mean(), np.min(), np.max(), np.std(), np.var(), np.median(), 等。

    “`python
    arr = np.array([1, 2, 3, 4, 5])

    print(np.sum(arr)) # 输出: 15 (求和)
    print(np.mean(arr)) # 输出: 3.0 (求平均值)
    print(np.max(arr)) # 输出: 5 (求最大值)
    print(np.std(arr)) # 求标准差
    print(np.argmin(arr)) # 返回最小值的索引
    “`

  • 广播 (Broadcasting): 广播是一种强大的机制,它允许 NumPy 在不同形状的数组之间执行算术运算。广播遵循一组规则,NumPy 会自动扩展较小数组的形状,使其与较大数组的形状兼容。

    “`python
    arr1 = np.array([[1, 2, 3], [4, 5, 6]])
    arr2 = np.array([10, 20, 30]) # arr2 会被广播到与 arr1 相同的形状

    print(arr1 + arr2)

    输出:

    [[11 22 33]

    [14 25 36]]

    “`

4. 实战案例

4.1 图像处理:灰度化

假设你有一张彩色图像,你可以使用 NumPy 将其转换为灰度图像。

“`python
from PIL import Image

加载图像

img = Image.open(“color_image.jpg”) # 替换为你的图像文件名
img_array = np.array(img)

提取 RGB 通道

r = img_array[:, :, 0]
g = img_array[:, :, 1]
b = img_array[:, :, 2]

使用 NTSC 亮度公式计算灰度值

gray_array = 0.299 * r + 0.587 * g + 0.114 * b

将灰度值转换为 8 位无符号整数 (0-255)

gray_array = gray_array.astype(np.uint8)

创建灰度图像

gray_img = Image.fromarray(gray_array)
gray_img.save(“gray_image.jpg”) # 保存灰度图像
“`

4.2 数据分析:标准化

在数据分析中,经常需要对数据进行标准化(使数据的均值为 0,标准差为 1)。

“`python
data = np.array([10, 12, 15, 18, 20, 22, 25])

计算均值和标准差

mean = np.mean(data)
std = np.std(data)

标准化

standardized_data = (data – mean) / std

print(standardized_data)
“`

4.3 线性代数:矩阵乘法

“`python

创建两个矩阵

A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])

矩阵乘法

C = np.dot(A, B) # 或者使用 A @ B (Python 3.5+)
print(C)

输出:

[[19 22]

[43 50]]

求解线性方程组

2x + y = 5

x – y = 1

a = np.array([[2, 1], [1, -1]])
b = np.array([5, 1])
x = np.linalg.solve(a, b)
print(x) # [2. 1.]
“`

4.4 统计分析:计算相关系数
“`python

创建两组数据

x = np.array([1, 2, 3, 4, 5])
y = np.array([2, 3, 1, 5, 4])

计算相关系数

correlation_coefficient = np.corrcoef(x, y)[0, 1]
print(correlation_coefficient)
“`

5. 总结

NumPy 是 Python 数据科学生态系统中的基石。通过掌握 NumPy 的数组操作技巧和通用函数,你可以高效地处理和分析各种类型的数据。本文介绍了 NumPy 的基础知识、核心概念(如索引、切片、迭代、形状操作、数组拼接与拆分)以及通用函数(包括算术运算、比较运算、数学函数、聚合函数和广播)。

此外,本文还通过几个实战案例展示了 NumPy 在图像处理、数据分析和线性代数等领域的应用。希望这些案例能够帮助你更好地理解 NumPy 的实际应用,并启发你在自己的项目中灵活运用 NumPy。

NumPy 的功能非常丰富,本文只是介绍了其中的一部分。要更深入地学习 NumPy,建议你参考 NumPy 的官方文档和教程,并进行大量的实践练习。 随着你对 NumPy 的熟练程度不断提高,你会发现它是一个无比强大的工具,可以大大提升你的数据处理和分析效率。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部