Python使用NumPy进行数组运算
1. NumPy简介
NumPy(Numerical Python)是Python中一个用于高效处理数值计算的库。它提供了高性能的多维数组对象 ndarray
,以及大量用于对这些数组进行操作的函数。NumPy的诞生极大地提高了Python在科学计算领域的效率,成为众多科学计算库(如 pandas
、matplotlib
、scikit - learn
等)的基础。
1.1 NumPy的优势
与Python原生的列表(list
)相比,ndarray
具有以下显著优势:
- 高效存储:
ndarray
在内存中以连续的方式存储数据,这使得它在存储和访问大量数据时效率更高。而Python列表是一种动态数组,每个元素都有独立的内存地址,存储相同数据量时占用内存更多。 - 快速计算:NumPy的底层代码是用C语言编写的,对数组的操作通过向量化计算实现,避免了Python中循环的开销,因此在执行数学运算时速度更快。
1.2 安装NumPy
在使用NumPy之前,需要先安装它。如果使用 pip
包管理器,可以在命令行中运行以下命令进行安装:
pip install numpy
如果使用 conda
,则可以运行:
conda install numpy
2. 创建NumPy数组
2.1 从Python列表创建
最常见的创建 ndarray
的方式是从Python列表转换。可以使用 numpy.array()
函数,例如:
import numpy as np
# 从一维列表创建一维数组
list1 = [1, 2, 3, 4]
arr1 = np.array(list1)
print(arr1)
# 从二维列表创建二维数组
list2d = [[1, 2, 3], [4, 5, 6]]
arr2d = np.array(list2d)
print(arr2d)
2.2 使用特定函数创建数组
numpy.zeros()
:创建一个全零的数组。可以指定数组的形状,例如:
# 创建一个长度为5的一维全零数组
zeros1d = np.zeros(5)
print(zeros1d)
# 创建一个3x3的二维全零数组
zeros2d = np.zeros((3, 3))
print(zeros2d)
numpy.ones()
:创建一个全一的数组,用法与numpy.zeros()
类似:
ones1d = np.ones(4)
print(ones1d)
ones2d = np.ones((2, 2))
print(ones2d)
numpy.arange()
:创建一个等差数组,类似于Python的range()
函数,但返回的是ndarray
。例如:
# 创建从0到9(不包括9),步长为1的数组
arr_range1 = np.arange(10)
print(arr_range1)
# 创建从2到10(不包括10),步长为2的数组
arr_range2 = np.arange(2, 10, 2)
print(arr_range2)
numpy.linspace()
:创建一个在指定范围内均匀分布的数组。需要指定起始值、结束值(包括)和元素数量。例如:
# 创建在0到1之间(包括0和1),均匀分布的5个元素的数组
arr_linspace = np.linspace(0, 1, 5)
print(arr_linspace)
3. NumPy数组的属性
3.1 形状(shape)
ndarray
的 shape
属性返回一个元组,描述数组在每个维度上的大小。例如:
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr.shape)
对于二维数组,shape
的第一个元素表示行数,第二个元素表示列数。
3.2 维度(ndim)
ndim
属性返回数组的维度数量。例如:
arr1d = np.array([1, 2, 3])
arr2d = np.array([[1, 2, 3], [4, 5, 6]])
print(arr1d.ndim)
print(arr2d.ndim)
3.3 元素数量(size)
size
属性返回数组中元素的总数。例如:
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr.size)
3.4 数据类型(dtype)
dtype
属性返回数组中元素的数据类型。NumPy支持多种数据类型,如 int32
、float64
等。例如:
arr = np.array([1, 2, 3], dtype=np.float64)
print(arr.dtype)
4. 基本的数组运算
4.1 算术运算
NumPy数组支持各种算术运算,这些运算都是按元素进行的。
- 加法:
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
add_result = arr1 + arr2
print(add_result)
- 减法:
sub_result = arr2 - arr1
print(sub_result)
- 乘法:
mul_result = arr1 * arr2
print(mul_result)
- 除法:
div_result = arr2 / arr1
print(div_result)
同样的运算也适用于多维数组,只要它们的形状相同。例如:
arr1_2d = np.array([[1, 2], [3, 4]])
arr2_2d = np.array([[5, 6], [7, 8]])
add_2d_result = arr1_2d + arr2_2d
print(add_2d_result)
4.2 矩阵乘法
对于二维数组,NumPy提供了矩阵乘法的功能。可以使用 np.dot()
函数或 @
运算符。例如:
arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[5, 6], [7, 8]])
dot_result = np.dot(arr1, arr2)
print(dot_result)
# 使用 @ 运算符
dot_result_alt = arr1 @ arr2
print(dot_result_alt)
4.3 一元运算
NumPy还支持一些一元运算,如计算数组元素的平方根、绝对值等。
- 平方根:
arr = np.array([4, 9, 16])
sqrt_result = np.sqrt(arr)
print(sqrt_result)
- 绝对值:
arr = np.array([-1, 2, -3])
abs_result = np.abs(arr)
print(abs_result)
5. 数组索引和切片
5.1 一维数组的索引和切片
与Python列表类似,NumPy一维数组可以通过索引访问单个元素,通过切片访问子数组。
- 索引:
arr = np.array([1, 2, 3, 4, 5])
print(arr[2])
- 切片:
# 从索引1开始(包括)到索引3结束(不包括)
sub_arr = arr[1:3]
print(sub_arr)
# 从开始到索引3结束(不包括)
sub_arr2 = arr[:3]
print(sub_arr2)
# 从索引2开始到结束
sub_arr3 = arr[2:]
print(sub_arr3)
5.2 二维数组的索引和切片
对于二维数组,需要使用两个索引(行索引和列索引)来访问单个元素。切片时也可以分别对行和列进行操作。
- 访问单个元素:
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr2d[1, 2])
- 切片行:
# 获取第一行
row1 = arr2d[0, :]
print(row1)
# 获取前两行
rows1_2 = arr2d[:2, :]
print(rows1_2)
- 切片列:
# 获取第二列
col2 = arr2d[:, 1]
print(col2)
# 获取前两列
cols1_2 = arr2d[:, :2]
print(cols1_2)
5.3 高级索引
除了基本的索引和切片,NumPy还支持高级索引,包括整数数组索引和布尔数组索引。
- 整数数组索引:
arr = np.array([1, 2, 3, 4, 5])
indices = np.array([0, 2, 4])
selected = arr[indices]
print(selected)
对于二维数组,整数数组索引可以用于选择特定的行和列组合。例如:
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
row_indices = np.array([0, 2])
col_indices = np.array([1, 2])
selected_elements = arr2d[row_indices, col_indices]
print(selected_elements)
- 布尔数组索引:可以使用布尔数组来选择满足特定条件的元素。例如:
arr = np.array([1, 2, 3, 4, 5])
bool_arr = arr > 3
selected = arr[bool_arr]
print(selected)
6. 数组变形
6.1 reshape() 方法
reshape()
方法用于改变数组的形状,前提是元素总数不变。例如:
arr = np.arange(12)
reshaped_arr = arr.reshape(3, 4)
print(reshaped_arr)
这里将一维的包含12个元素的数组变成了一个3行4列的二维数组。
6.2 ravel() 和 flatten() 方法
ravel()
和 flatten()
方法都用于将多维数组展平为一维数组。区别在于 ravel()
返回的是原数组的视图(如果可能的话,即共享数据),而 flatten()
返回的是原数组的副本。
ravel()
:
arr2d = np.array([[1, 2, 3], [4, 5, 6]])
raveled_arr = arr2d.ravel()
print(raveled_arr)
flatten()
:
flattened_arr = arr2d.flatten()
print(flattened_arr)
6.3 转置
对于二维数组,可以使用 transpose()
方法或 T
属性来转置数组,即交换行和列。例如:
arr2d = np.array([[1, 2, 3], [4, 5, 6]])
transposed_arr = arr2d.transpose()
print(transposed_arr)
# 使用 T 属性
transposed_arr_alt = arr2d.T
print(transposed_arr_alt)
7. 数组拼接和分割
7.1 数组拼接
np.concatenate()
:可以沿指定轴拼接多个数组。例如,沿行方向(axis = 0)拼接两个二维数组:
arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[5, 6], [7, 8]])
concatenated_row = np.concatenate((arr1, arr2), axis = 0)
print(concatenated_row)
沿列方向(axis = 1)拼接:
concatenated_col = np.concatenate((arr1, arr2), axis = 1)
print(concatenated_col)
np.vstack()
和np.hstack()
:np.vstack()
用于垂直堆叠(按行拼接),np.hstack()
用于水平堆叠(按列拼接)。例如:
vstack_result = np.vstack((arr1, arr2))
print(vstack_result)
hstack_result = np.hstack((arr1, arr2))
print(hstack_result)
7.2 数组分割
np.split()
:可以将一个数组分割成多个子数组。例如,将一维数组分成三个相等的部分:
arr = np.arange(9)
split_arrays = np.split(arr, 3)
for sub_arr in split_arrays:
print(sub_arr)
对于二维数组,可以沿指定轴进行分割。例如,沿行方向(axis = 0)将二维数组分成两个子数组:
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
split_2d_arrays = np.split(arr2d, 2, axis = 0)
for sub_2d_arr in split_2d_arrays:
print(sub_2d_arr)
np.vsplit()
和np.hsplit()
:np.vsplit()
用于垂直分割(按行分割),np.hsplit()
用于水平分割(按列分割)。例如:
arr2d = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
vsplit_result = np.vsplit(arr2d, 3)
for sub_vsplit in vsplit_result:
print(sub_vsplit)
hsplit_result = np.hsplit(arr2d, 2)
for sub_hsplit in hsplit_result:
print(sub_hsplit)
8. 聚合函数
8.1 求和(sum)
sum()
函数用于计算数组中所有元素的和。对于多维数组,可以指定轴进行求和。例如:
arr = np.array([1, 2, 3, 4, 5])
total_sum = arr.sum()
print(total_sum)
arr2d = np.array([[1, 2], [3, 4]])
# 按行求和
row_sums = arr2d.sum(axis = 1)
print(row_sums)
# 按列求和
col_sums = arr2d.sum(axis = 0)
print(col_sums)
8.2 求平均值(mean)
mean()
函数用于计算数组元素的平均值。同样可以指定轴。例如:
arr = np.array([1, 2, 3, 4, 5])
average = arr.mean()
print(average)
arr2d = np.array([[1, 2], [3, 4]])
# 按行求平均值
row_means = arr2d.mean(axis = 1)
print(row_means)
# 按列求平均值
col_means = arr2d.mean(axis = 0)
print(col_means)
8.3 求最大值(max)和最小值(min)
max()
和 min()
函数分别用于找到数组中的最大值和最小值。也可以指定轴。例如:
arr = np.array([1, 2, 3, 4, 5])
max_value = arr.max()
min_value = arr.min()
print(max_value)
print(min_value)
arr2d = np.array([[1, 2], [3, 4]])
# 按行找最大值
row_maxes = arr2d.max(axis = 1)
print(row_maxes)
# 按列找最小值
col_mins = arr2d.min(axis = 0)
print(col_mins)
8.4 标准差(std)和方差(var)
std()
函数用于计算数组元素的标准差,var()
函数用于计算方差。同样可以指定轴。例如:
arr = np.array([1, 2, 3, 4, 5])
std_dev = arr.std()
variance = arr.var()
print(std_dev)
print(variance)
arr2d = np.array([[1, 2], [3, 4]])
# 按行计算标准差
row_stds = arr2d.std(axis = 1)
print(row_stds)
# 按列计算方差
col_vars = arr2d.var(axis = 0)
print(col_vars)
9. 广播机制
广播是NumPy中一种强大的机制,它允许在形状不同的数组之间进行算术运算。当两个数组进行运算时,NumPy会尝试通过广播将它们的形状变得一致。 例如,将一个标量与一个数组相加:
arr = np.array([1, 2, 3])
scalar = 2
result = arr + scalar
print(result)
这里标量 2
被广播到与 arr
相同的形状,然后进行按元素相加。
对于两个形状不同的数组,广播遵循以下规则:
- 如果两个数组的维度数不同,在较小维度数组的形状前添加长度为1的维度,直到它们的维度数相同。
- 对于每个维度,如果两个数组在该维度上的大小相同,或者其中一个数组在该维度上的大小为1,则认为它们在该维度上是兼容的。
- 如果两个数组在所有维度上都是兼容的,则可以进行广播。广播后的数组形状是每个维度上两个数组大小的最大值。
例如,一个形状为 (3, 1)
的数组和一个形状为 (1, 4)
的数组进行加法运算:
arr1 = np.array([[1], [2], [3]])
arr2 = np.array([[1, 2, 3, 4]])
result = arr1 + arr2
print(result)
这里 arr1
被广播为 (3, 4)
的形状,arr2
也被广播为 (3, 4)
的形状,然后进行按元素相加。
通过广播机制,NumPy使得在处理不同形状数组的运算时更加灵活和高效,避免了手动扩展数组形状的繁琐操作。
以上就是关于Python使用NumPy进行数组运算的详细内容,NumPy在科学计算和数据分析领域有着广泛的应用,熟练掌握它的各种功能对于相关领域的开发者至关重要。通过不断实践和深入理解这些特性,可以大大提高数据处理和数值计算的效率。