MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Python使用NumPy进行数组运算

2024-01-041.8k 阅读

1. NumPy简介

NumPy(Numerical Python)是Python中一个用于高效处理数值计算的库。它提供了高性能的多维数组对象 ndarray,以及大量用于对这些数组进行操作的函数。NumPy的诞生极大地提高了Python在科学计算领域的效率,成为众多科学计算库(如 pandasmatplotlibscikit - 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)

ndarrayshape 属性返回一个元组,描述数组在每个维度上的大小。例如:

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支持多种数据类型,如 int32float64 等。例如:

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的维度,直到它们的维度数相同。
  2. 对于每个维度,如果两个数组在该维度上的大小相同,或者其中一个数组在该维度上的大小为1,则认为它们在该维度上是兼容的。
  3. 如果两个数组在所有维度上都是兼容的,则可以进行广播。广播后的数组形状是每个维度上两个数组大小的最大值。

例如,一个形状为 (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在科学计算和数据分析领域有着广泛的应用,熟练掌握它的各种功能对于相关领域的开发者至关重要。通过不断实践和深入理解这些特性,可以大大提高数据处理和数值计算的效率。