NumPy 学习笔记系列(三):深入理解数组操作

NumPy 学习笔记系列(三):深入理解数组操作

在前两篇文章中,我们讨论了NumPy的基础知识以及广播机制的工作原理。在这一篇中,我们将进一步探讨NumPy中其他重要的数组操作。包括数组切片与索引、数组形状操作(如reshape、flatten、transpose)、统计函数、条件筛选与布尔索引。这些操作是日常数据处理不可或缺的工具,深入理解它们的原理和应用将显著提升你的数据分析能力。

1. 数组切片与索引(Slicing and Indexing)

切片(Slicing)和索引(Indexing) 是从数组中提取子数组或特定元素的基本操作。它们在处理多维数组时尤为重要,因为你经常需要对部分数据进行操作。

1.1 基本切片语法

切片的基本语法是start:stop:step,用于从数组中提取元素。start表示切片的起始位置(包含),stop表示结束位置(不包含),step表示步长。

1.1.1 基本切片

让我们从一维数组的基本切片操作开始:

import numpy as np

# 创建一个一维数组
arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

# 提取索引从2到6的元素(不包括6)
sub_arr1 = arr[2:6]
print("从索引2到6的切片结果:", sub_arr1)

# 提取每隔两个元素
sub_arr2 = arr[::2]
print("每隔两个元素的切片结果:", sub_arr2)

输出:

从索引2到6的切片结果: [2 3 4 5]
每隔两个元素的切片结果: [0 2 4 6 8]

arr[2:6]表示从数组arr中提取索引为2到5的元素(注意:切片是左闭右开区间,因此索引6处的元素不包含在结果中)。也就是说,它会提取arr[2]arr[5]的元素。

arr[::2]表示从头到尾每隔两个元素提取一次。::2中的第一个:表示从头到尾,2表示步长,即每隔2个元素提取一次。

1.1.2 反向切片

切片语法也支持负索引和负步长,允许你从数组末尾开始进行切片操作。

# 使用负索引和负步长进行反向切片
sub_arr3 = arr[-5:-1]
print("负索引的切片结果:", sub_arr3)

sub_arr4 = arr[::-1]
print("数组的反向结果:", sub_arr4)

输出:

负索引的切片结果: [5 6 7 8]
数组的反向结果: [9 8 7 6 5 4 3 2 1 0]

arr[-5:-1]使用负索引从数组的倒数第五个元素开始,提取到倒数第一个元素(不包含)。负索引从数组末尾计数,-1表示数组的最后一个元素。

arr[::-1]表示以步长-1从数组末尾向前反向提取元素。这意味着整个数组将被逆序。

1.2 多维数组切片

多维数组的切片操作和一维数组类似,但你需要为每个维度指定切片。

1.2.1 二维数组的切片
# 创建一个二维数组
arr2d = np.array([[0, 1, 2, 3],
                  [4, 5, 6, 7],
                  [8, 9, 10, 11],
                  [12, 13, 14, 15]])

# 提取前两行和后两列的子数组
sub_arr5 = arr2d[:2, 2:]
print("前两行和后两列的切片结果:\n", sub_arr5)

# 提取每行的第2列
sub_arr6 = arr2d[:, 1]
print("每行的第二列:", sub_arr6)

# 提取中间的2x2子数组
sub_arr7 = arr2d[1:3, 1:3]
print("中间2x2的子数组:\n", sub_arr7)

输出:

前两行和后两列的切片结果:
[[2 3]
 [6 7]]

每行的第二列: [ 1  5  9 13]

中间2x2的子数组:
[[ 5  6]
 [ 9 10]]

arr2d[:2, 2:]表示从二维数组arr2d中提取前两行(行索引0和1)和后两列(列索引2和3)的元素。
arr2d[:, 1]表示提取二维数组arr2d的每一行中的第二列元素。这里的:表示选择所有行,1表示选择列索引为1的那一列。
arr2d[1:3, 1:3]表示提取行索引为1到2的行和列索引为1到2的列(不包含3),形成一个2x2的子数组。

1.2.2 三维数组的切片

对于三维数组,切片操作同样可以扩展,适用于更多维度的数据。

# 创建一个三维数组
arr3d = np.array([[[0, 1, 2], [3, 4, 5]],
                  [[6, 7, 8], [9, 10, 11]],
                  [[12, 13, 14], [15, 16, 17]]])

# 提取第一层
sub_arr8 = arr3d[0]
print("第一层的切片结果:\n", sub_arr8)

# 提取每层的第二行
sub_arr9 = arr3d[:, 1, :]
print("每层的第二行:\n", sub_arr9)

# 提取从第一层第二行到第二层第一行的子数组
sub_arr10 = arr3d[0:2, 1, 1:]
print("复杂切片操作的结果:\n", sub_arr10)

输出:

第一层的切片结果:
[[0 1 2]
 [3 4 5]]

每层的第二行:
[[ 3  4  5]
 [ 9 10 11]
 [15 16 17]]

复杂切片操作的结果:
[[ 4  5]
 [10 11]]

arr3d[0]表示提取三维数组arr3d的第一层(索引为0)。这里的0是第一个维度的索引,即三维数组的第一个二维数组。
arr3d[:, 1, :]表示从每一层的第二行中提取所有列。这里的:表示选择所有层,1表示第二行,:表示选择所有列。
arr3d[0:2, 1, 1:]表示从第一层和第二层(索引为0和1)中提取第二行,并从第二行中提取索引为1到最后的列。

1.2.3 切片中的步长使用

步长不仅可以用于一维数组,在多维数组中同样适用,允许你以一定的间隔提取数据。

# 在二维数组中使用步长
sub_arr11 = arr2d[::2, ::2]
print("二维数组中步长为2的切片结果:\n", sub_arr11)

输出:

二维数组中步长为2的切片结果:
[[ 0  2]
 [ 8 10]]

arr2d[::2, ::2]表示从二维数组中每隔两行和两列提取一次元素。::2中的第一个:表示从头到尾选择所有行,但步长为2,第二个:表示选择所有列,步长同样为2。

1.3 视图与副本

需要注意的是,NumPy切片返回的是原数组的视图(view),而不是副本(copy)。这意味着对切片的修改会影响到原数组:

# 修改切片,观察原数组的变化
sub_arr2d[0, 0] = 99
print("修改后的原数组:\n", arr2d)

输出:

修改后的原数组:
[[ 1 99  3]
 [ 4  5  6]
 [ 7  8  9]]

要避免这种情况,可以使用copy()方法创建数组的副本。

# 创建副本
sub_arr2d_copy = arr2d[:2, 1:].copy()
sub_arr2d_copy[0, 0] = 77
print("修改副本后的原数组:\n", arr2d)

输出:

修改副本后的原数组:
[[ 1 99  3]
 [ 4  5  6]
 [ 7  8  9]]

2. 数组形状操作(Shape Operations)

NumPy数组的形状决定了数据的维度和结构。通过形状操作,你可以轻松地转换数据的结构以适应不同的分析需求。常用的形状操作包括reshapeflattentranspose

2.1 reshape:改变数组形状

reshape方法允许你在不改变数据的情况下重新安排数组的形状。这个操作非常有用,尤其是在你需要将一维数据转换为多维数据时。

# 创建一个一维数组
arr = np.arange(6)

# 将一维数组重塑为二维数组
reshaped_arr = arr.reshape(2, 3)
print("重塑后的数组:\n", reshaped_arr)

输出:

重塑后的数组:
[[0 1 2]
 [3 4 5]]

在使用reshape时,需要确保新形状的元素数量与原数组一致,否则会抛出错误。

2.2 flatten:展平数组

flatten方法将多维数组展平成一维数组。这在将数据输入机器学习模型或进行其他操作时非常有用。

# 展平数组
flattened_arr = reshaped_arr.flatten()
print("展平后的数组:", flattened_arr)

输出:展平后的数组:[0 1 2 3 4 5]

2.3 transpose:转置数组

transpose方法交换数组的维度,对于矩阵操作尤为重要。

# 创建一个二维数组
arr2d = np.array([[1, 2, 3], [4, 5, 6]])

# 转置数组
transposed_arr = arr2d.transpose()
print("转置后的数组:\n", transposed_arr)

输出:

转置后的数组:
[[1 4]
 [2 5]
 [3 6]]

transpose可以用于多维数组中,以灵活地调整数据的排列方式。

3. 统计函数(Statistical Functions)

NumPy提供了一系列的统计函数,帮助你快速计算数组的统计属性,如均值、标准差、最大值和最小值等。

####3.1 均值和中位数

# 创建一个随机数组
arr = np.random.randn(2, 3)

# 计算均值
mean_val = np.mean(arr)
print("均值:", mean_val)

# 计算中位数
median_val = np.median(arr)
print("中位数:", median_val)

输出:

均值:-0.268387
中位数:-0.133333

这些统计函数还可以沿特定轴进行计算,例如计算每列或每行的均值:

# 计算每列的均值
mean_col = np.mean(arr, axis=0)
print("每列的均值:", mean_col)

3.2 标准差和方差

标准差和方差是衡量数据分布的离散程度的两个重要指标。

# 计算标准差
std_val = np.std(arr)
print("标准差:", std_val)

# 计算方差
var_val = np.var(arr)
print("方差:", var_val)

输出:

标准差:0.823
方差:0.676

3.3 最大值和最小值

最大值和最小值函数可以帮助你快速找到数组中的极值。

# 计算最大值和最小值
max_val = np.max(arr)
min_val = np.min(arr)
print("最大值:", max_val, ",最小值:", min_val)

输出:最大值:0.975,最小值:-1.344

这些函数对于探索性数据分析(EDA)和初步了解数据分布非常有用。

4. 条件筛选与布尔索引(Conditional Selection and Boolean Indexing)

条件筛选和布尔索引允许你根据特定条件筛选数组中的元素,这是数据清洗和分析中的常用操作。

4.1 基本条件筛选

# 创建一个数组
arr = np.array([1, 2, 3, 4, 5, 6])

# 筛选出大于3的元素
filtered_arr = arr[arr > 3]
print("筛选结果:", filtered_arr)

输出:筛选结果:[4 5 6]

这种方式可以很方便地从数组中提取满足条件的子集。

4.2 组合条件筛选

你还可以组合多个条件进行复杂的筛选操作:

# 筛选出大于2且小于5的元素
filtered_arr = arr[(arr > 2) & (arr < 5)]
print("组合条件筛选结果:", filtered_arr)

输出:组合条件筛选结果:[3 4]

这种方法使你能够对数据进行更精确的操作和分析。

4.3 使用布尔索引进行赋值

布尔索引不仅可以用于条件筛选,还可以用于对数组中的特定元素进行赋值操作。这种技术在数据清洗和处理过程中非常有用,能够有效地修改数组中的数据。

通过布尔索引,你可以对满足特定条件的数组元素进行赋值。这种方式在数据预处理、异常值处理等场景下尤为实用。

# 创建一个数组
arr = np.array([1, 2, 3, 4, 5, 6])

# 将所有大于3的元素设为10
arr[arr > 3] = 10
print("赋值后的数组:", arr)

输出:赋值后的数组:[ 1 2 3 10 10 10]

在这个例子中,我们将数组中所有大于3的元素都设置为10。这种操作可以帮助你快速处理数据中的特定值,尤其是当你需要标准化数据或处理异常值时。

4.4 布尔数组的生成

有时,你可能需要生成一个布尔数组,用于后续的筛选或其他操作。你可以通过比较操作生成布尔数组:

# 生成布尔数组
bool_arr = arr > 2
print("布尔数组:", bool_arr)

输出:布尔数组:[False False True True True True]

这个布尔数组可以直接用于筛选、赋值或其他操作。

4.5 结合布尔索引与其他操作

布尔索引还可以与统计函数等其他操作结合使用,以实现更复杂的数据处理任务。

# 计算满足条件的元素的均值
mean_filtered = np.mean(arr[arr > 2])
print("筛选后元素的均值:", mean_filtered)

输出:筛选后元素的均值:10.0

这种方式允许你对筛选后的数据进一步进行统计分析,非常适合于数据清洗和预处理阶段。

总结

通过本文的学习,你现在应该对NumPy中的一些关键数组操作有了更深入的理解。我们详细探讨了数组切片与索引、数组形状操作(reshape、flatten、transpose)、统计函数以及条件筛选和布尔索引。掌握这些操作能够帮助你更加灵活、高效地处理数据,从而为后续的分析和建模打下坚实的基础。

在数据科学和机器学习的工作流程中,这些操作无处不在,是每个数据科学家和工程师都必须熟练掌握的技能。在接下来的文章中,我们将继续深入探讨NumPy的其他高级功能,如线性代数操作、随机数生成以及与其他库的整合等。

如果你有任何问题或建议,欢迎在评论区留言。继续加油,让我们一起探索NumPy的更多可能性!

  • 11
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值