领先的免费Web技术教程,涵盖HTML到ASP.NET

网站首页 > 知识剖析 正文

【Numpy】(3)数组操作

nixiaole 2025-02-11 13:04:04 知识剖析 19 ℃

索引

基本索引

NumPy索引类似于Python列表的索引,但它提供了更多的功能。对于一维数组,你可以使用整数索引访问特定位置的元素:

Bash
import numpy as np

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

对于多维数组,你可以使用逗号分隔的索引元组来访问元素:

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

切片索引

切片是Python和NumPy中一种常用的数据访问方式,允许你访问数组的一部分:

arr = np.array([0, 1, 2, 3, 4, 5])

# 获取索引1到4之前的元素
print(arr[1:4])  # 输出:[1 2 3]

# 获取从开始到索引3(不包含)的元素
print(arr[:3])  # 输出:[0 1 2]

# 获取索引2到末尾的元素
print(arr[2:])  # 输出:[2 3 4 5]

对于多维数组,你可以对每个维度分别进行切片:

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

# 获取第一行
print(arr[0, :])  # 输出:[1 2 3]

# 获取第一列
print(arr[:, 0])  # 输出:[1 4 7]

# 获取子数组(2x2,从arr[1:, 1:]开始)
print(arr[1:, 1:])  # 输出:
# [[5 6]
#  [8 9]]

布尔索引

布尔索引允许你根据布尔数组的值来索引目标数组,这在条件筛选数据时非常有用:

arr = np.array([0, 1, 2, 3, 4, 5])

# 创建一个布尔数组
bool_arr = arr > 2

# 使用布尔数组进行索引
print(arr[bool_arr])  # 输出:[3 4 5]

# 直接使用布尔表达式
print(arr[arr > 2])  # 输出:[3 4 5]

花式索引

花式索引(Fancy indexing)允许你使用整数数组作为索引:

arr = np.array([0, 1, 2, 3, 4, 5])

# 使用整数数组索引
print(arr[[1, 3, 4]])  # 输出:[1 3 4]

对于多维数组,花式索引可以让你访问数组的任意位置,甚至以非常灵活的方式重排数组:

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

# 获取(0,1)、(1,2)和(2,0)位置的元素
print(arr[[0, 1, 2], [1, 2, 0]])  # 输出:[2 6 7]

注意事项

  • NumPy索引是从0开始的。
  • 切片是原数组的视图,修改切片会影响原数组。如果需要复制,可以使用 .copy()方法。
  • 布尔索引和花式索引返回的数组不与原数组共享数据。

改变形状

numpy.reshape是NumPy库中的一个非常重要的函数,它允许你重新排列给定数组的维度,而不改变数组中的数据。这意味着你可以将任何形状的数组转换成你需要的任何其他形状,只要新形状的总元素数与原始数组相同。

reshape函数的基本语法如下:

numpy.reshape(a, newshape, order='C')
  • a:要被重塑的数组。
  • newshape:整数或整数元组,指定了新数组的形状。如果 newshape是整数,则结果将是一维数组。特别地, newshape可以为 -1,在这种情况下,值会自动计算以保持数组元素的总数不变。
  • order:{'C', 'F', 'A'},可选。指定重塑操作和数组数据在内存中的读写顺序。'C'意味着C风格的顺序,'F'意味着Fortran风格的顺序,'A'意味着如果 a是Fortran连续的,在重塑过程中也应该保持Fortran连续。

示例1:基础重塑

将一维数组重塑为二维数组:

import numpy as np

arr = np.arange(6)
print("Original array:", arr)

# 重塑为2x3数组
reshaped_arr = arr.reshape((2, 3))
print("Reshaped array:\n", reshaped_arr)

示例2:自动计算维度

使用 -1自动计算维度,让NumPy自动确定正确的维度:

arr = np.arange(6)

# 只指定行数,列数自动计算
reshaped_arr = arr.reshape((2, -1))
print("Reshaped array with -1:\n", reshaped_arr)

示例3:从多维到一维

将多维数组重塑为一维数组:

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

# 使用reshape
flat_arr = arr.reshape(-1)
print("Flattened array:", flat_arr)

# 使用ravel函数也可以实现相同的效果
flat_arr = np.ravel(arr)
print("Flattened array with ravel:", flat_arr)

# 返回一维数组的副本
flat_arr = np.flatten(arr)
print("Flattened array with flatten:", flat_arr)

注意事项

  • reshape操作不会改变原始数组,而是返回一个新的重塑后的数组。如果你想就地修改原始数组,可以使用 resize方法。
  • 使用 -1作为 newshape的一部分可以方便地自动计算维度,但需要确保总元素数不变。
  • reshaperavel(或 flatten)可以相互转换,但要注意 ravel通常返回视图,而 flatten总是返回副本。

数组拼接

数组的拼接是将不同的数组按照一定的顺序组合成一个新的数组。根据数组的维度和拼接方向,NumPy提供了几种不同的函数来实现数组的拼接,主要包括 np.concatenatenp.vstack(垂直栈)、 np.hstack(水平栈)和 np.dstack(深度栈)等。

np.concatenate

np.concatenate是最基础的数组拼接函数,它可以沿着指定的轴拼接一系列数组。

numpy.concatenate((a1, a2, ...), axis=0)
  • a1,a2,...:要拼接的数组序列。
  • axis:指定拼接的轴。默认为0,表示第一个轴。
import numpy as np

# 一维数组拼接
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
result = np.concatenate((arr1, arr2))
print(result)  # 输出:[1 2 3 4 5 6]

# 二维数组沿着第一个轴(行)拼接
arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[5, 6]])
result = np.concatenate((arr1, arr2), axis=0)
print(result)
# 输出:
# [[1 2]
#  [3 4]
#  [5 6]]

np.vstacknp.hstack

np.vstack(垂直栈)和 np.hstack(水平栈)提供了更简便的方法来进行垂直和水平方向的数组拼接。

# 垂直栈
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
result = np.vstack((arr1, arr2))
print(result)
# 输出:
# [[1 2 3]
#  [4 5 6]]

# 水平栈
result = np.hstack((arr1, arr2))
print(result)  # 输出:[1 2 3 4 5 6]

np.dstack

np.dstack将数组沿着第三个维度(深度方向)拼接。

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

注意事项

  • 拼接的数组在非拼接轴上的维度必须相同。
  • np.vstacknp.hstack在处理维度不同的数组时比 np.concatenate更加灵活,它们会自动处理维度以实现拼接。
  • 使用 np.concatenate和相关函数时,要确保拼接的数组在指定的轴上是兼容的,否则会抛出异常。

数组分裂

将一个数组分割成多个较小数组的过程。NumPy提供了几个函数来执行不同形式的数组分裂,包括 np.splitnp.hsplitnp.vsplitnp.array_split等。这些函数允许你按照指定的索引或轴将数组分割成多个子数组。

1.np.split

np.split是最基础的数组分裂函数,它沿指定轴分割数组。

基本用法

numpy.split(ary, indices_or_sections, axis=0)
  • ary:要分裂的输入数组。
  • indices_or_sections:如果是整数,表示要分割成的均等分的数量;如果是整数数组,则表示在哪些索引位置进行分割。
  • axis:指定分割的轴,默认为0。

示例

import numpy as np

arr = np.arange(9)
# 将数组分割成3个等长的子数组
print(np.split(arr, 3))

arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 沿水平轴分割数组
print(np.split(arr2d, [1], axis=0))

# 沿垂直轴分割数组
print(np.split(arr2d, [2], axis=1))

2.np.hsplit和np.vsplit

np.hsplitnp.vsplitnp.split的特例,分别用于沿水平轴和垂直轴分割数组。

示例

# 水平分割
print(np.hsplit(arr2d, 3))

# 垂直分割
print(np.vsplit(arr2d, 3))

3.np.array_split

np.array_splitnp.split类似,但它允许分割成不等长的子数组。

示例

# 分割成不等长的子数组
print(np.array_split(arr, 4))

注意事项

  • 使用 np.split时,如果指定的是分割成的均等分的数量,则数组的大小必须能被该数量整除,否则会报错。如果需要分割成不等长的子数组,应使用 np.array_split
  • 在使用索引数组进行分割时,提供的索引是分割点的位置。例如, np.split(arr,[2,5])会在索引2和5的位置分割数组,生成三个子数组。
  • np.hsplitnp.vsplit是为特定的分割方向提供便利的函数,分别对应于 axis=1axis=0np.split操作。

运算

1. 算术运算

NumPy允许你对数组执行各种算术运算,这些运算可以是数组与数组之间的,也可以是数组与标量之间的。

  • 加法( +np.add:数组元素相加。
  • 减法( -np.subtract:从第一个数组中减去第二个数组的元素。
  • 乘法( *np.multiply:数组元素相乘。
  • 除法( /np.divide:第一个数组元素除以第二个数组的元素。
  • 平方根( np.sqrt:数组每个元素的平方根。
  • 幂运算( **np.power:第一个数组元素的第二个数组元素次幂。
import numpy as np

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

# 算术运算示例
print(a + b)  # 加法
print(a - b)  # 减法
print(a * b)  # 乘法
print(a / b)  # 除法
print(np.sqrt(a))  # 平方根

2. 比较运算

支持所有常见的比较运算符,比如 <(小于)、 >(大于)、 <=(小于等于)、 >=(大于等于)、\==(等于)和 !=(不等于)。这些运算符被应用于数组时,会逐元素地进行比较,返回一个同形状的布尔数组。

import numpy as np

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

# 比较操作
print(x < 3)  # 小于3
# 输出:[ True  True False False False]

使用布尔数组作为掩码

得到比较运算的结果后,你可以将这个布尔数组用作掩码,以选择满足条件的元素。这通过简单地索引布尔数组来实现。

print(x[x < 3])
# 输出:[1 2]

组合条件

你还可以使用逻辑运算符,如 &(和)、 |(或)、 ^(异或)和 ~(非),来组合多个条件。注意,这些逻辑运算符要求使用括号来明确运算的顺序。

print(x[(x > 2) & (x < 5)])
# 输出:[3 4]

使用 np.where

np.where 是一个非常实用的函数,它返回满足条件的元素的索引。此外,它还可以作为三元运算符 cond?x:y 的向量化版本。

result = np.where(x < 3, x, -1)  # 小于3的保留,其他替换为-1
print(result)
# 输出:[ 1  2 -1 -1 -1]

修改数组

你可以使用布尔掩码来修改数组中满足特定条件的元素。

x[x < 3] = 0
print(x)
# 输出:[0 0 3 4 5]

计数满足条件的元素

np.count_nonzero 和布尔数组的 sum 方法都可以用来计数数组中 True 的数量,即满足条件的元素数量。

print(np.count_nonzero(x < 3))
# 输出:2

# 或者
print(np.sum(x < 3))
# 输出:2

布尔运算的其他函数

  • np.any():检查数组中是否至少有一个 True,用于测试是否至少有一个元素满足条件。
  • np.all():检查数组中所有元素是否都是 True,用于测试是否所有元素满足条件。
print(np.any(x > 4))  # 至少有一个元素大于4吗?
# 输出:True

print(np.all(x < 6))  # 所有元素都小于6吗?
# 输出:True

3. 逻辑运算

NumPy提供了逻辑操作函数,如逻辑与( np.logical_and)、逻辑或( np.logical_or)、逻辑非( np.logical_not)等。

print(np.logical_and(a > 2, b < 8))
print(np.logical_or(a < 2, b > 7))

4. 统计运算

NumPy提供了一系列的统计函数来分析数组中的数据,包括最大值( np.max)、最小值( np.min)、平均值( np.mean)、中位数( np.median)、标准差( np.std)等。

print(np.max(a))  # 最大值
print(np.mean(a))  # 平均值
print(np.std(b))   # 标准差

5.三角函数

常用的NumPy三角函数

  • np.sin(x): 正弦函数
  • np.cos(x): 余弦函数
  • np.tan(x): 正切函数
  • np.arcsin(x): 反正弦函数
  • np.arccos(x): 反余弦函数
  • np.arctan(x): 反正切函数
  • np.arctan2(y,x): 两个参数的反正切函数,返回给定的Y/X的反正切值
  • np.radians(deg): 角度转换为弧度
  • np.degrees(rad): 弧度转换为角度
  • np.hypot(x,y): 计算直角三角形的斜边长度

使用示例

下面通过一些简单的示例,来说明如何使用这些三角函数。

正弦函数示例

import numpy as np

# 创建一个角度数组
degrees = np.array([0, 30, 45, 60, 90])
# 将角度转换为弧度
radians = np.radians(degrees)

# 计算这些角度的正弦值
sin_values = np.sin(radians)
print("Sin values:", sin_values)

反三角函数示例

# 已知正弦值,计算角度
sin_values = np.array([0, 1/2, np.sqrt(2)/2, np.sqrt(3)/2, 1])
# 使用 arcsin 计算角度的弧度值
angles_radians = np.arcsin(sin_values)
# 将弧度转换为角度
angles_degrees = np.degrees(angles_radians)
print("Angles:", angles_degrees)

6.对数

NumPy 提供了一系列的对数函数,使得对数组中的每个元素进行对数运算变得非常简单和高效。这些对数函数包括计算自然对数、底数为10的对数、底数为2的对数等。对数运算在数据分析、科学计算、工程等领域中非常常见,特别是在处理指数增长或衰减的数据时。

NumPy 中的主要对数函数

  • np.log(x): 计算数组中各元素的自然对数(底数是e)。
  • np.log10(x): 计算数组中各元素的以10为底的对数。
  • np.log2(x): 计算数组中各元素的以2为底的对数。
  • np.log1p(x): 计算 1+x的自然对数,对于小值 x,提高计算精度。
  • np.expm1(x): 计算 exp(x)-1,与 np.log1p相对应,用于提高小值 x的计算精度。

使用示例

下面是一些使用NumPy进行对数运算的示例。

自然对数

import numpy as np

# 创建一个正数数组
x = np.array([1, e, e**2, e**3])

# 计算数组元素的自然对数
log_x = np.log(x)
print("Natural log:", log_x)

底数为10的对数

# 创建一个正数数组
x = np.array([1, 10, 100, 1000])

# 计算数组元素的以10为底的对数
log10_x = np.log10(x)
print("Log base 10:", log10_x)

底数为2的对数

# 创建一个正数数组
x = np.array([1, 2, 4, 8])

# 计算数组元素的以2为底的对数
log2_x = np.log2(x)
print("Log base 2:", log2_x)

提高小数计算精度的对数函数

对于非常接近0的正数,直接使用 np.log或其它对数函数可能会因为数值精度问题导致计算结果不准确。NumPy 提供了 np.log1p,它可以用来计算 1+x的自然对数,从而提高小数值计算的准确性。

# 对于非常小的数值
x = np.array([1e-99])

# 直接计算log(1+x)
log1p_x = np.log1p(x)
print("log(1+x) for small x:", log1p_x)

7.矩阵运算

创建矩阵:

import numpy as np

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

矩阵加法和减法

两个形状相同的矩阵可以进行加法和减法运算,对应元素相加或相减:

# 矩阵加法
C = A + B
print("Matrix addition:\n", C)

# 矩阵减法
D = A - B
print("Matrix subtraction:\n", D)

矩阵乘法

矩阵乘法可以使用 np.dot() 函数或者 @ 操作符:

# 方法1:使用 np.dot() 函数
E = np.dot(A, B)
print("Matrix multiplication using np.dot():\n", E)

# 方法2:使用 @ 操作符
F = A @ B
print("Matrix multiplication using @:\n", F)

元素级乘法

如果你想进行元素级的乘法(即Hadamard积),可以直接使用 * 操作符:

G = A * B
print("Element-wise multiplication:\n", G)

矩阵的转置

矩阵的转置可以通过 .T 属性得到:

H = A.T
print("Transpose of matrix A:\n", H)

矩阵的逆

矩阵的逆可以通过 np.linalg.inv() 函数计算:

I = np.linalg.inv(A)
print("Inverse of matrix A:\n", I)

行列式计算

矩阵的行列式可以通过 np.linalg.det() 函数计算:

det_A = np.linalg.det(A)
print("Determinant of matrix A:", det_A)

特征值和特征向量

矩阵的特征值和特征向量可以通过 np.linalg.eig() 函数得到:

eigenvalues, eigenvectors = np.linalg.eig(A)
print("Eigenvalues of A:", eigenvalues)
print("Eigenvectors of A:\n", eigenvectors)

8.广播运算

NumPy 的广播(Broadcasting)功能是一种强大的机制,允许 NumPy 在执行算术运算时自动处理不同形状的数组。广播会按照一定的规则自动扩展数组的形状,使得它们的维度匹配,然后执行逐元素的运算。这使得在不实际复制数据的情况下,对不同形状的数组执行运算成为可能,从而可以高效地使用内存。

广播遵循一组简单的规则来应用:

  1. 维度对齐:如果两个数组的维数不相同,形状中较短的数组会在其前面被补1,直到两者的维数相同。
  2. 形状匹配:在每个维度上,如果两个数组的大小相等,或者其中一个数组在该维度上的大小为1,则认为这两个数组在该维度上是兼容的。
  3. 数组扩展:当两个数组的形状在某个维度上兼容时,如果其中一个数组在该维度上的大小为1,那么它会被扩展为与另一个数组在该维度上的大小相同。
  4. 运算执行:当以上条件都满足时,广播机制就会被应用,两个数组的运算就可以按元素逐个进行。

这里通过一些例子来更直观地理解广播的概念。

示例 1:标量和数组的广播

import numpy as np

a = np.array([1, 2, 3])
b = 2

# 2 被广播到数组的每个元素
print(a * b)  # 输出:[2 4 6]

示例 2:一维数组和二维数组的广播

a = np.array([1, 2, 3])
b = np.array([[1, 2, 3], [4, 5, 6]])

# 'a' 在行方向上被广播,以匹配'b'的形状
print(a + b)

输出:

[[2 4 6]
 [5 7 9]]

示例 3:两个二维数组的广播

a = np.array([[1], [2], [3]])  # 形状为 (3, 1)
b = np.array([1, 2, 3])       # 形状为 (3,)

# 'a' 在列方向上被广播,'b' 在行方向上被广播
print(a + b)

输出:

[[2 3 4]
 [3 4 5]
 [4 5 6]]

9.求和、求积

求和:np.sum

np.sum 函数用于计算数组中所有元素的总和。你可以对整个数组进行求和,也可以指定轴(axis)进行求和。

示例:整个数组的求和

import numpy as np

arr = np.array([[1, 2], [3, 4]])
total_sum = np.sum(arr)
print("Total sum:", total_sum)  # 输出:10

示例:指定轴的求和

# 沿着第一个轴求和(列求和)
column_sum = np.sum(arr, axis=0)
print("Sum of each column:", column_sum)  # 输出:[4 6]

# 沿着第二个轴求和(行求和)
row_sum = np.sum(arr, axis=1)
print("Sum of each row:", row_sum)  # 输出:[3 7]

求积:np.prod

np.prod 函数用于计算数组中所有元素的乘积。同样,你可以对整个数组进行求积,或指定轴进行求积。

示例:整个数组的求积

product = np.prod(arr)
print("Total product:", product)  # 输出:24

示例:指定轴的求积

# 沿着第一个轴求积(列求积)
column_product = np.prod(arr, axis=0)
print("Product of each column:", column_product)  # 输出:[3 8]

# 沿着第二个轴求积(行求积)
row_product = np.prod(arr, axis=1)
print("Product of each row:", row_product)  # 输出:[2 12]

累计求和和累计求积

NumPy 还提供了计算累计求和和累计求积的函数: np.cumsumnp.cumprod,它们分别计算给定轴上的元素的累计和与累计积。

累计求和

cumulative_sum = np.cumsum(arr)
print("Cumulative sum:", cumulative_sum)  # 输出:[1 3 6 10]

累计求积

cumulative_product = np.cumprod(arr)
print("Cumulative product:", cumulative_product)  # 输出:[1 2 6 24]

10.中位数,均值,方差,标准差

中位数(Median)

中位数是将数据集按顺序排列后位于中间的值。如果数据集的数量是偶数,中位数则是中间两个数的平均值。它是一种衡量数据中心位置的指标,对异常值不敏感。

  • 计算方法: pythonimportnumpyasnp data=np.array([数值序列])median=np.median(data)

均值(Mean)

均值是所有数据加总后除以数据的数量。它是描述数据集平均水平的一个指标,但对异常值敏感。

  • 计算方法: python mean=np.mean(data)

方差(Variance)

方差衡量的是数据点与数据平均值之间的差异程度。方差越大,表示数据分布越分散。

  • 计算方法: python variance=np.var(data)

标准差(Standard Deviation)

标准差是方差的平方根,也用于衡量数据的分散程度。与方差相比,标准差与原始数据在同一量纲,更容易理解。

  • 计算方法: python std_deviation=np.std(data)

示例

假设我们有一组数据 [1,2,3,4,5],我们来计算它们的中位数、均值、方差、和标准差。

import numpy as np

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

median = np.median(data)
mean = np.mean(data)
variance = np.var(data)
std_deviation = np.std(data)

print("Median:", median)
print("Mean:", mean)
print("Variance:", variance)
print("Standard Deviation:", std_deviation)

排序

提供了多种排序算法来处理数组,包括一维和多维数组的排序。这些排序函数非常高效,适用于大数据集。主要的排序函数包括 np.sortnp.argsort,以及就地排序的 ndarray.sort 方法。此外,NumPy 还提供了用于查找元素的函数,如 np.partition

np.sort

np.sort 函数返回数组的排序副本。它不会修改原数组。

import numpy as np

arr = np.array([3, 1, 5, 2])
sorted_arr = np.sort(arr)
print(sorted_arr)  # 输出:[1 2 3 5]

对于多维数组,你可以指定 axis 参数来决定按哪个轴进行排序。

arr2d = np.array([[5, 2], [3, 4]])
sorted_arr2d = np.sort(arr2d, axis=0)  # 沿着第一个轴(列)排序
print(sorted_arr2d)

np.argsort

np.argsort 函数返回的是数组排序后的索引。

arr = np.array([3, 1, 5, 2])
sorted_index = np.argsort(arr)
print(sorted_index)  # 输出:[1 3 0 2]

使用这些索引可以对其他数组进行同样顺序的排序,这在数据分析中非常有用。

就地排序:ndarray.sort

使用 ndarray.sort 方法可以直接在原数组上进行排序,这称为就地排序。

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

部分排序:np.partition

np.partition 函数返回一个新数组,其中第 k个元素是这样一个值,它是数组排序后该位置上的元素,而前 k个元素都小于等于第 k个元素,后面的元素都大于等于第 k个元素。

arr = np.array([3, 4, 2, 1])
partitioned_arr = np.partition(arr, 2)
print(partitioned_arr)  # 输出可能是 [2 1 3 4]

高级排序算法

NumPy 的排序函数支持多种排序算法,包括 quicksort(快速排序,默认)、 mergesort(归并排序)、 heapsort(堆排序)等。你可以通过 kind 参数选择算法:

sorted_arr = np.sort(arr, kind='mergesort')
最近发表
标签列表