1. NumPy简介
NumPy是Python中一个重要的库,用于科学计算和数据分析。它提供了一个强大的多维数组对象(ndarray
)和用于操作这些数组的函数。NumPy是许多其他Python科学计算库的基础,如Pandas、SciPy和Matplotlib。
NumPy的背景和目标
NumPy最初由Travis Olliphant于2005年创建,并且它是Numeric和Numarray两个库的继承者。NumPy的目标是为Python提供一种高效的数组处理方法,使得科学计算更加便捷和高效。
NumPy的主要特征和应用场景
NumPy的主要特征包括:
- 强大的多维数组对象:NumPy的核心是
ndarray
对象,它可以存储任意维度的同类型数据。这种数组对象非常适合进行数值计算和数据处理。 - 快速的数值运算:NumPy通过对数组的操作使用高效的C语言代码实现,因此在数值运算方面比纯Python代码更快速。
- 广播机制:NumPy引入了广播机制,使得不同形状的数组可以进行运算,这样可以简化代码并提高运算效率。
- 丰富的数学函数库:NumPy提供了大量的数学函数和线性代数操作,如三角函数、指数函数、统计函数、矩阵分解等,满足科学计算的需求。
- 与其他科学计算库的兼容性:NumPy与其他常用的科学计算库(如SciPy、Pandas、Matplotlib)紧密结合,可以方便地与这些库一起使用。
NumPy在以下应用场景中得到广泛应用:
- 数据分析和处理:NumPy的数组对象提供了高效的数据结构和操作,使得数据分析和处理变得更加便捷。它可以处理大量数据并进行快速的数值计算。
- 科学计算:NumPy提供了丰富的数学函数和线性代数操作,适用于科学计算中的各种任务,如信号处理、图像处理、统计分析等。
- 机器学习和人工智能:NumPy是许多机器学习和深度学习框架的基础。它提供了高效的数组操作和数学函数,可以加速算法的实现和运行。
NumPy与Python的关系
NumPy是用Python编写的,是Python科学计算生态系统中的核心组件之一。NumPy提供了高性能的数组对象和数组操作函数,使得Python在科学计算领域有了更强大的能力。
NumPy通过底层的C语言代码实现了数组操作的高效性,并通过Python的接口与用户进行交互。这使得NumPy既具有高性能的计算能力,又保持了Python的简洁和易用性。
NumPy还与Python的标准库和其他科学计算库紧密结合,使得用户可以方便地进行数据的读写、可视化和分析。通过NumPy,Python成为了一种强大的科学计算语言,受到了广泛的应用和开发者的喜爱。
2. NumPy数组
NumPy的核心是多维数组对象ndarray
,它提供了一种高效存储和操作大量数据的方式。在本节中,我们将学习如何创建NumPy数组,了解数组的属性和方法,并掌握基本的数组操作。
创建NumPy数组
NumPy数组可以通过多种方式创建,如以下示例所示:
通过Python列表创建数组
import numpy as np
# 创建一维数组
arr1 = np.array([1, 2, 3, 4, 5])
print(arr1)
# [1 2 3 4 5]
# 创建二维数组
arr2 = np.array([[1, 2, 3], [4, 5, 6]])
print(arr2)
# [[1 2 3]
# [4 5 6]]
使用NumPy函数创建特殊数组
# 创建全零数组
zeros = np.zeros((2, 3))
print(zeros)
# [[0. 0. 0.]
# [0. 0. 0.]]
# 创建全一数组
ones = np.ones((3, 2))
print(ones)
# [[1. 1.]
# [1. 1.]
# [1. 1.]]
# 创建指定范围的等间隔数组
range_arr = np.arange(0, 10, 2)
print(range_arr)
# [0 2 4 6 8]
# 创建指定大小的随机数组
random_arr = np.random.rand(2, 3)
print(random_arr)
# [[0.98409252 0.27752055 0.89984634]
# [0.00264179 0.62695002 0.77690454]]
数组的属性和方法
NumPy数组具有许多有用的属性和方法,可以帮助我们了解和操作数组。以下是一些常用的属性和方法:
数组的形状和维度
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr.shape) # 输出数组的形状
# (2, 3)
print(arr.ndim) # 输出数组的维度
# 2
数组的数据类型
arr = np.array([1, 2, 3])
print(arr.dtype) # 输出数组的数据类型
# int32
数组的大小和元素个数
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr.size) # 输出数组的大小,即元素的总个数
# 6
print(arr.itemsize) # 输出数组中每个元素的字节大小
# 4
操作数组的基本操作
数组的索引和切片
arr = np.array([1, 2, 3, 4, 5])
print(arr[0]) # 输出第一个元素
# 1
print(arr[2:4]) # 输出索引为2和3的元素
# [3 4]
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr[1, 2]) # 输出第二行第三列的元素
# 6
print(arr[:, 1]) # 输出所有行的第二列元素
# [2 5]
数组的变形
arr = np.array([1, 2, 3, 4, 5, 6])
# [1 2 3 4 5 6]
reshaped_arr = arr.reshape(2, 3) # 将一维数组变形为二维数组
print(reshaped_arr)
# [[1 2 3]
# [4 5 6]]
arr = np.array([[1, 2], [3, 4]])
# [[1 2]
# [3 4]]
flattened_arr = arr.flatten() # 将二维数组展平为一维数组
print(flattened_arr)
# [1 2 3 4]
数组的拼接
arr1 = np.array([1, 2, 3])
# [1 2 3]
arr2 = np.array([4, 5, 6])
# [4 5 6]
concatenated_arr = np.concatenate((arr1, arr2)) # 拼接两个数组
print(concatenated_arr)
# [1 2 3 4 5 6]
arr1 = np.array([[1, 2], [3, 4]])
# [[1 2]
# [3 4]]
arr2 = np.array([[5, 6]])
# [[5 6]]
concatenated_arr = np.concatenate((arr1, arr2), axis=0) # 沿行方向拼接
print(concatenated_arr)
# [[1 2]
# [3 4]
# [5 6]]
3. NumPy数据类型
NumPy提供了多种数据类型来存储和处理数组中的元素。在本节中,我们将学习常见的数据类型、数据类型转换以及如何自定义数据类型。
常见的数据类型
NumPy支持以下常见的数据类型:
-
bool
:布尔值(True或False) -
int
:整数类型,根据平台可能是int32或int64 -
float
:浮点数类型,根据平台可能是float32或float64 -
complex
:复数类型,由两个浮点数表示实部和虚部 -
str
:字符串类型 -
object
:Python对象类型 -
datetime
:日期时间类型 -
timedelta
:时间间隔类型 -
np.void
:Void类型,可以存储任意类型的数据
数据类型转换
在NumPy中,可以使用astype()
函数进行数据类型转换。以下是一些常见的数据类型转换示例:
arr = np.array([1, 2, 3])
# [1 2 3]
# 转换为浮点数类型
float_arr = arr.astype(float)
print(float_arr)
# [1. 2. 3.]
# 转换为字符串类型
str_arr = arr.astype(str)
print(str_arr)
# ['1' '2' '3']
# 转换为布尔类型
bool_arr = arr.astype(bool)
print(bool_arr)
# [ True True True]
自定义数据类型
NumPy还允许用户自定义数据类型,以满足特定的需求。可以使用np.dtype()
函数来定义自定义数据类型,并指定字段的名称和数据类型。以下是一个自定义数据类型的示例:
- 对于定义的自定义数据类型,其中的字符串字段需要指定字符串的最大长度
- 未指定字符串字段的最大长度,则默认为长度为0的空字符串,导致相关字段为空
-
'U10'
表示最大长度为10的Unicode字符串
# 定义自定义数据类型
person_dtype = np.dtype([('name', 'U10'), ('age', 'int'), ('height', 'float')])
# 创建一个数组并使用自定义数据类型
person_arr = np.array([('John', 25, 180.5), ('Alice', 30, 165.2)], dtype=person_dtype)
print(person_arr)
# [('John', 25, 180.5) ('Alice', 30, 165.2)]
print(person_arr[0]['name'])
# John
4. 数组计算
NumPy提供了丰富的数组计算方法、广播机制以及数学函数和线性代数操作,使得处理和操作数组变得更加便捷和高效。
数组的计算方法
使用NumPy,你可以对数组进行各种数学运算和统计计算。以下是一些常用的数组计算方法示例:
-
np.sum(arr)
:计算数组所有元素的总和。 -
np.mean(arr)
:计算数组所有元素的平均值。 -
np.std(arr)
:计算数组所有元素的标准差。 -
np.var(arr)
:计算数组所有元素的方差。 -
np.min(arr)
:找到数组中的最小值。 -
np.max(arr)
:找到数组中的最大值。 -
np.argmin(arr)
:找到数组中最小值的索引。 -
np.argmax(arr)
:找到数组中最大值的索引。
arr1 = np.array([1, 2, 3, 4, 5])
arr2 = np.array([6, 7, 8, 9, 10])
# 计算数组总和
sum_result = np.sum(arr1)
print("数组总和:", sum_result)
# 数组总和: 15
# 计算数组平均值
mean_result = np.mean(arr1)
print("数组平均值:", mean_result)
# 数组平均值: 3.0
# 计算数组标准差
std_result = np.std(arr1)
print("数组标准差:", std_result)
# 数组标准差: 1.4142135623730951
# 计算数组最大值
max_result = np.max(arr1)
print("数组最大值:", max_result)
# 数组最大值: 5
广播机制
广播机制(Broadcasting)是NumPy中一种强大且灵活的功能,它允许不同形状的数组在进行元素级别的运算
时自动调整形状,以满足运算的要求。广播机制可以简化代码并提高计算的效率。
广播机制的核心原则是在进行运算时,NumPy会自动调整数组的形状
,使其能够逐元素
地进行计算。具体来说,广播机制会按照以下规则进行数组的形状调整:
- 如果两个数组的维度数不同,那么在较小的维度上
添加长度为1的维度
,直到两个数组的维度数相同。
a. 维度数(number of dimensions)是指数组的维度或轴的数量。在NumPy中,数组的维度数可以通过ndim属性获取
b. 长度为1的维度指的是在数组的形状中,某个维度的长度(即元素个数)为1
# 创建示例数组
arr1 = np.array([1, 2, 3]) # 形状为 (3,)
# [1 2 3]
arr2 = np.array([[4], [5], [6]]) # 形状为 (3, 1)
# [[4]
# [5]
# [6]]
# 在较小维度上添加长度为1的维度,使维度数相同
broadcasted_arr1 = arr1[:, np.newaxis] # 添加维度后的形状为 (3, 1)
print("调整后的数组形状:")
print(broadcasted_arr1)
# [[1]
# [2]
# [3]]
print(arr2)
# [[4]
# [5]
# [6]]
- 如果两个数组的维度长度相同,或者其中一个数组在某个维度上的长度为1,那么这两个数组在该维度上是兼容的。
a. 二维数组中,第一维度:行数;第二维度:列数;
# 创建示例数组
arr1 = np.array([1, 2, 3]) # 形状为 (3,)
# [1 2 3]
arr2 = np.array([[4, 5, 6]]) # 形状为 (1, 3)
# [[4 5 6]]
# 在维度长度相同的情况下,数组在该维度上是兼容的
result = arr1 + arr2
print("运算结果:")
print(result)
# [[5 7 9]]
- 如果两个数组在所有维度上的长度都不相等,且其中没有一个数组的长度为1,则无法进行广播,会引发错误。
# 创建示例数组
arr1 = np.array([1, 2, 3]) # 形状为 (3,)
# [1 2 3]
arr2 = np.array([4, 5, 6, 7]) # 形状为 (4,)
# [4 5 6 7]
# 无法进行广播,会引发错误
result = arr1 + arr2
# 运行到此处时会抛出 ValueError: operands could not be broadcast together with shapes (3,) (4,) 错误
广播机制的应用场景包括:
- 对不同形状的数组进行元素级别的运算,如加法、乘法等。
# 广播示例1: 不同形状的数组相加
arr1 = np.array([1, 2, 3]) # 形状 (3, ) 维度 1
arr2 = np.array([[4, 5, 6], [7, 8, 9]]) # 形状 (2, 3) 维度 2
result2 = arr1 + arr2
# 为了使它们的维度数相同,arr1会在其形状中添加一个长度为1的维度,变为 (1, 3)
# [[1, 2, 3]]
print("不同形状的数组相加结果:")
print(result2)
# [[ 5 7 9]
# [ 8 10 12]]
- 在数组与标量之间进行运算,将标量广播到数组的每个元素。
# 广播示例2: 数组与标量的运算
scalar = 10
arr1 = np.array([1, 2, 3])
result1 = arr1 + scalar
print("数组与标量的运算结果:")
print(result1)
# [11 12 13]
- 在数组与更高维度的数组之间进行运算,使其形状兼容。
数学函数及线性代数操作
NumPy提供了广泛的数学函数和线性代数操作,可以对数组进行各种数学运算和矩阵操作。以下是一些常用的数学函数和线性代数操作示例:
-
np.sin(arr)
:计算数组中每个元素的正弦值。
# 使用数学函数
sin_result = np.sin(arr1)
print("正弦值:", sin_result)
-
np.cos(arr)
:计算数组中每个元素的余弦值。 -
np.exp(arr)
:计算数组中每个元素的指数值。 -
np.log(arr)
:计算数组中每个元素的自然对数。 -
np.dot(arr1, arr2)
:计算两个数组的点积。
# 进行矩阵乘法
matrix1 = np.array([[1, 2], [3, 4]])
# [[1 2]
# [3 4]]
matrix2 = np.array([[5, 6], [7, 8]])
# [[5 6]
# [7 8]]
dot_result = np.dot(matrix1, matrix2)
print("矩阵乘法结果:")
print(dot_result)
# [[19 22]
# [43 50]]
-
np.transpose(arr)
:计算数组的转置。
matrix1 = np.array([[1, 2], [3, 4]])
# [[1 2]
# [3 4]]
# 计算数组的转置
transpose_result = np.transpose(matrix1)
print("数组转置结果:")
print(transpose_result)
# [[1 3]
# [2 4]]
-
np.linalg.inv(arr)
:计算数组的逆矩阵。
matrix1 = np.array([[1, 2], [3, 4]])
# [[1 2]
# [3 4]]
# 计算数组的逆矩阵
inv_result = np.linalg.inv(matrix1)
print("逆矩阵结果:")
print(inv_result)
# [[-2. 1. ]
# [ 1.5 -0.5]]
5. 数组的读写存储
NumPy提供了方便的函数来读写和存储数组数据。在本节中,学习如何使用NumPy读取和写入数组数据。
读写数组
写入数组数据
使用NumPy的np.save()
函数。该函数将数组数据保存到二进制文件中,以便以后读取使用。
# 创建一个数组
arr = np.array([1, 2, 3, 4, 5])
# 写入数组数据
np.save('data.npy', arr)
读取数组数据
使用NumPy的np.load()
函数。该函数从存储的二进制文件
中加载数组,并返回一个包含数组数据的NumPy数组对象
。
# 读取数组数据
arr = np.load('data.npy')
# 打印数组
print(arr)
存储与加载数组
除了读写数组数据,NumPy还提供了更灵活的函数来存储和加载数组数据,如np.savez()和np.load()。
使用np.savez()
函数可以将多个数组
保存到一个压缩文件.npz
中。
# 创建两个数组
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
# 存储多个数组数据
np.savez('data.npz', array1=arr1, array2=arr2)
使用np.load()
函数加载.npz文件
时,它会返回一个类似于字典的对象,其中包含了被保存的数组数据。
# 加载多个数组数据
data = np.load('data.npz')
# 访问数组数据
arr1 = data['array1']
arr2 = data['array2']
# 打印数组
print(arr1)
print(arr2)
6. 数组的统计计算
在NumPy中,我们可以对数组进行各种统计计算。这些计算可以帮助我们了解数组中的数据分布、趋势和相关性等信息。
基本统计计算
平均值(mean):计算数组的平均值。
标准差(std):计算数组的标准差,衡量数据的离散程度。
方差(var):计算数组的方差,衡量数据的离散程度。
最小值(min):找到数组中的最小值。
最大值(max):找到数组中的最大值。
总和(sum):计算数组中所有元素的总和。
最小值索引(argmin):找到数组中最小值的索引。
最大值索引(argmax):找到数组中最大值的索引。
高级统计计算
百分位数(percentiles):计算数组中给定百分比的元素值。
arr = np.array([1, 2, 3, 4, 5])
# 计算50%的百分位数【计算50%的百分位数就是返回数组中的中位数】
percentile_value = np.percentile(arr, 50)
print(percentile_value)
# 3.0
# 找到一个值,使得10%的元素小于或等于这个值
percentile_value = np.percentile(arr, 10)
print(percentile_value)
# 1.4
中位数(median):计算数组的中位数。
arr = np.array([1, 2, 3, 4, 5])
median_value = np.median(arr)
print(median_value)
# 3.0
相关系数(corrcoef):计算数组的相关系数。
arr1 = np.array([1, 2, 3, 4, 5])
arr2 = np.array([5, 4, 3, 2, 1])
corrcoef_value = np.corrcoef(arr1, arr2)
print(corrcoef_value)
# [[ 1. -1.]
# [-1. 1.]]
协方差(cov):计算数组的协方差矩阵。
arr1 = np.array([1, 2, 3, 4, 5])
arr2 = np.array([5, 4, 3, 2, 1])
cov_matrix = np.cov(arr1, arr2)
print(cov_matrix)
# [[ 2.5 -2.5]
# [-2.5 2.5]]
直方图(histogram):计算数组的直方图。
直方图是一种用于可视化数据分布的图形表示方法。
它将数据划分为一系列称为“箱子”(或“柱”)的区间,并计算落入每个区间的数据点数量
。
直方图可以帮助我们了解数据的分布情况、数据的集中程度和数据的离散程度。
-
hist
是一个包含每个区间内数据点数量的数组 -
bins
是一个包含划分的区间边界值的数组
arr = np.array([1, 2, 3, 4, 5])
hist, bins = np.histogram(arr)
print(hist)
print(bins)
# [1 0 1 0 0 1 0 1 0 1]
# [1. 1.4 1.8 2.2 2.6 3. 3.4 3.8 4.2 4.6 5. ]
差分(diff):计算数组的差分值。
差分操作将计算相邻元素之间的差值
arr = np.array([1, 2, 3, 4, 5])
diff_arr = np.diff(arr)
print(diff_arr)
# [1 1 1 1]
梯度(gradient):计算数组的梯度。
数组的梯度是指数组中相邻元素之间的变化率或斜率
。
对于一维数组,梯度表示每个元素的变化幅度;
对于多维数组,梯度表示在每个维度上的变化幅度。
arr = np.array([1, 2, 3, 4, 5])
gradient_arr = np.gradient(arr)
print(gradient_arr)
# [1. 1. 1. 1. 1.]
7. 数组的复制和视图
在 NumPy 中,对数组进行复制和视图操作是常见的操作之一。理解复制和视图的概念及其区别对于正确处理数组非常重要。本教程将介绍深度复制、浅复制和视图的概念以及它们之间的区别。
深度复制
深度复制是指创建一个完全独立于原始数组的新数组,即在内存中生成一个完全相同的副本。对复制后的数组进行修改不会影响原始数组。
使用 copy()
方法可以进行深度复制。
arr = np.array([1, 2, 3, 4, 5])
arr_copy = arr.copy()
# 修改复制后的数组,不会影响原始数组
arr_copy[0] = 10
print("原始数组:", arr)
print("深度复制后的数组:", arr_copy)
# 原始数组: [1 2 3 4 5]
# 深度复制后的数组: [10 2 3 4 5]
浅复制
浅复制是指创建一个新的数组对象,但该对象与原始数组共享相同的数据内容。这意味着对浅复制后的数组进行修改会影响原始数组。
使用切片操作
或 view()
方法可以进行浅复制。
arr = np.array([1, 2, 3, 4, 5])
arr_shallow_copy = arr[:]
# 修改浅复制后的数组,会影响原始数组
arr_shallow_copy[0] = 10
print("原始数组:", arr)
print("浅复制后的数组:", arr_shallow_copy)
# 原始数组: [10 2 3 4 5]
# 浅复制后的数组: [10 2 3 4 5]
视图
视图是指创建一个新的数组对象,与原始数组共享相同的数据内容,但具有不同的维度大小或形状
。对视图进行修改会影响原始数组
,反之亦然。
使用view()
方法可以创建视图。
arr = np.array([1, 2, 3, 4, 5])
arr_view = arr.view()
# 修改视图的形状和大小
arr_view.shape = (5, 1)
arr_view[1] = 10
print("原始数组:", arr)
print("视图数组:", arr_view)
# 原始数组: [ 1 10 3 4 5]
# 视图数组: [[ 1]
# [10]
# [ 3]
# [ 4]
# [ 5]]