前言
Python 提供了一个 array 模块。array和 list不同,array直接保存数值,和C语言的一维数组比较类似。但是由于Python的array 模块不支持多维,也没有各种运算函数,因此不适合做数值运算。NumPy弥补了Python不支持多维等不足之处,它提供了一种存储单一数据类型的多维数组——ndarray。
ndarray 对象简介
ndarray
是 NumPy 中用于存储单一数据类型的多维数组的对象。与 Python 的内置列表(list)不同,ndarray
中的元素必须是同质的(即同一类型),并且存储在一块连续的内存中,这使得 ndarray
的运算速度远快于 Python 的内置列表。
ndarray 的主要特点
- 同质性:数组中的元素必须是相同的数据类型。
- 连续的内存块:数组在内存中连续存储,这提高了访问速度和计算效率。
- 动态大小:数组的大小可以根据需要进行调整。
- 多维性:可以存储一维、二维、三维甚至更高维度的数据。
- 丰富的数学函数:NumPy 提供了大量的数学函数和操作,可以直接在数组上进行计算。
1 创建数组对象
NumPy 提供了两种基本的对象:ndarray(N-dimensional Array)和 ufunc(Universal Function)。ndarray是存储单一数据类型的多维数组,而ufunc则是能够对数组进行处理的函数。在NumPy中,维度称为轴。
import numpy as np
# 创建一个一维数组
a = np.array([1, 2, 3, 4, 5])
# 创建一个二维数组(矩阵)
b = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(a)
print(b)
1.数组属性
为了更好地理解和使用数组,在创建数组之前,了解数组的基本属性是十分有必要的。数组的属性及其说明如下表所示。
属性名称 | 属性说明 |
ndim | 返回int。表示数组的维数 |
shape | 返回tuple。表示数组形状,对于n行m列的矩阵,形状为(n,m) |
size | 返回int。表示数组的元素总数,等于数组形状中各元素的积 |
dtype | 返回data-type。表示数组中元素的数据类型 |
itemsize | 返回int。表示数组的每个元素的存储空间(以B为单位)。例如,一个元素类型为float64的数组的itemsize属性值为8(float64占用64bit,1B为8bit,所以float64,占用8B)。一个元素类型为complex32的数组的itemsize属性值为4 |
2.数组创建
NumPy 提供的array 函数可以创建一维或多维数组,其基本使用格式如下。
numpy.array(object, dtype = None, *, copy = True, order = 'K', subok = False, ndmin = 0, like = None)
array函数的主要参数及其说明如下图所示。
参数说明 | 参数说明 |
object | 接收 array _like。表示所需创建的数组对象。无默认值 |
dtype | 接收data-type。表示数组所需的数据类型,如果未给定,那么选择保存对象所需的最小的数据类型。默认为None |
ndmin | 接收int。用于指定生成数组应该具有的最小维数。默认为0 |
创建一维数组与多维数组并查看数组属性的过程,如下代码所示。
import numpy as np #导入Numpy 库
arr1 = np.array([1,2,3,4]) #创建一维数组
print('创建的数组为:',arr1)
#创建二维数组
arr2 = np.array([[1,2,3,4],[4,5,6,7],[7,8,9,10]])
print('创建的数组为:\n',arr2)
print('数组的形状为:',arr2.shape) #查看数组形状
print('数组元素类型为:',arr2.dtype) #查看数组类型
print('数组元素个数为:',arr2.size) #查看数组元数个数
print('数组每个元素存储空间为:',arr2.itemsize) #查看数组每个元素存储空间
在如上代码中,数组arr1只有一行元素,因此它是一维数组。而数组 arr2有3行4列元素,因此它是二维数组,第0轴的长度为3(即行数),第1轴的长度为4(即列数)。其中,第0轴也称横轴,第1轴也称纵轴。还可以通过修改数组的shape 属性,在保持数组元素个数不变的情况下改变数组每个轴的长度。
代码如下将数组 arr2的shape改为(4,3)。注意,从(3,4)改为(4,3)并不是对数组进行转置,而是改变每个轴的长度,数组元素的顺序并没有改变。
arr2.shape = 4,3 # 重新设置shape
print('重新设置shape后的arr2为:\n',arr2)
3. 数组的数据类型
NumPy 支持多种数据类型,包括整数、浮点数、布尔值、复数等。这些数据类型可以用来指定数组中元素的数据类型。NumPy 中的数据类型比 Python 内置的类型更加丰富,例如,int32
、int64
、float32
、float64
等。在创建数组时,可以通过 dtype
参数指定数组的数据类型。
4. 数组切片和索引
NumPy 支持像列表一样的切片操作,通过切片可以获取数组的子集。对于多维数组,可以使用逗号分隔的索引来访问特定的元素或子数组。例如,arr2[0, 2]
将会返回 arr2
第一行第三列的元素。
5. 数组运算
NumPy 数组支持多种运算,包括算术运算、比较运算、逻辑运算等。当对这些数组进行运算时,NumPy 会应用元素级别的运算,即对应位置的元素进行运算。例如,两个数组相加,实际上是它们对应元素的相加。
6. 数组广播
NumPy 的一个强大特性是数组广播。它允许在不同形状的数组之间进行算术运算。在某些条件下,较小的数组会“广播”到较大数组的大小,以便它们具有兼容的形状。
7. 常用函数
NumPy 提供了许多用于数组操作的函数,如 zeros
、ones
、eye
用于创建特定大小的数组,arange
、linspace
用于创建数值序列的数组。还有用于数学和统计的函数如 sum
、mean
、std
等。
8. 线性代数运算
NumPy 还提供了线性代数模块 numpy.linalg
,它包含了解线性方程组、计算特征值、求逆矩阵等函数。
import numpy as np
# 创建一个全零的二维数组
arr_zeros = np.zeros((3, 4))
# 创建一个全一的二维数组
arr_ones = np.ones((2, 3))
# 创建一个单位矩阵
arr_eye = np.eye(3)
# 创建一个等差数列的数组
arr_arange = np.arange(10)
# 创建一个线段上的等分点数组
arr_linspace = np.linspace(0, 10, 5)
# 矩阵乘法
matrix_a = np.array([[1, 2], [3, 4]])
matrix_b = np.array([[5, 6], [7, 8]])
matrix_product = np.dot(matrix_a, matrix_b)
# 计算矩阵的特征值和特征向量
eigenvalues, eigenvectors = np.linalg.eig(matrix_a)
# 输出结果
print("零数组:\n", arr_zeros)
print("一数组:\n", arr_ones)
print("单位矩阵:\n", arr_eye)
print("等差数列:\n", arr_arange)
print("线段等分点:\n", arr_linspace)
print("矩阵乘法结果:\n", matrix_product)
print("特征值:\n", eigenvalues)
print("特征向量:\n", eigenvectors)
9. 数组重塑
NumPy 允许您通过 reshape
方法改变数组的形状而不改变其数据。这在对数据进行处理和准备进行分析时非常有用。
arr = np.array([1, 2, 3, 4, 5, 6])
new_shape = arr.reshape(2, 3) # 将一维数组转换为二维数组
10. 数组转置
对于二维数组,可以使用 T
属性或 transpose
方法来进行转置操作,即行列互换。
arr = np.array([[1, 2], [3, 4]])
transposed_arr = arr.T # 或者 np.transpose(arr)
11. 数组堆叠
NumPy 提供了多种方法来堆叠数组,如 vstack
(垂直堆叠)、hstack
(水平堆叠)和 concatenate
(沿指定轴堆叠)。
arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[5, 6], [7, 8]])
vstacked_arr = np.vstack((arr1, arr2))
hstacked_arr = np.hstack((arr1, arr2))
12. 数组分割
与堆叠相反,可以使用 vsplit
、hsplit
或 split
方法来分割数组。
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
vsplit_arr = np.vsplit(arr, 3) # 垂直分割
hsplit_arr = np.hsplit(arr, 3) # 水平分割
13. 数组排序
NumPy 提供了 sort
方法来对数组进行排序,以及 argsort
方法来获取排序后的索引。
arr = np.array([2, 1, 5, 3, 7, 4])
sorted_arr = np.sort(arr)
indices = np.argsort(arr)
14. 数组过滤
可以使用布尔索引来过滤数组中的元素。
arr = np.array([1, 2, 3, 4, 5, 6])
filtered_arr = arr[arr > 3] # 选择数组中大于3的元素
15. 数组文件操作
NumPy 支持将数组保存到磁盘上,以及从磁盘加载数组,使用 save
、savez
、load
等函数。
np.save('filename.npy', arr) # 保存数组
loaded_arr = np.load('filename.npy') # 加载数组
2 生成随机数
关于生成随机数,NumPy在numpy.random
模块中提供了丰富的函数来生成随机数和随机样本。以下是一些常用的随机数生成函数:
-
numpy.random.rand(d0, d1, ..., dn)
: 创建一个给定形状的数组,并使用[0, 1)区间内的均匀分布填充它。 -
numpy.random.randn(d0, d1, ..., dn)
: 创建一个给定形状的数组,并使用标准正态分布(均值为0,方差为1)填充它。 -
numpy.random.randint(low, high=None, size=None, dtype=int)
: 从指定的上下限之间随机选取整数,填充到给定大小的数组中。 -
numpy.random.random_integers(low, high=None, size=None)
: 和randint
类似,但是high
是包含的,即取值范围是[low, high]。 -
numpy.random.choice(a, size=None, replace=True, p=None)
: 从给定的数组中随机选取元素,可以指定是否放回(replace
),以及每个元素被选中的概率(p
)。 -
numpy.random.seed()
: 设置随机数生成的种子,使得随机数结果可重复。
下面是一个生成随机数的例子:
import numpy as np
# 设置随机数种子
np.random.seed(0)
# 生成一个3x3的随机数组,元素值在[0, 1)区间内
print(np.random.rand(3, 3))
# 生成一个3x3的标准正态分布的随机数组
print(np.random.randn(3, 3))
# 从1到10之间随机选取整数,生成一个3x3的数组
print(np.random.randint(1, 10, (3, 3)))
# 从[1, 2, 3, 4, 5]中随机选取元素,生成一个3x3的数组
print(np.random.choice([1, 2, 3, 4, 5], (3, 3)))
3 通过索引访问数组
在NumPy中,索引操作是非常灵活和强大的。以下是一些常用的索引方式:
-
基本索引:使用整数索引可以访问数组中的特定元素。对于一维数组,这很简单。对于多维数组,可以使用逗号分隔的索引来访问元素。例如,
arr[0, 2]
会返回第一行第三列的元素。 -
切片索引:使用切片可以访问数组中的一段元素。切片索引使用冒号
:
分隔的起始索引、终止索引和步长。例如,arr[0:2, :]
会返回第一和第二行的所有列。 -
布尔索引:使用布尔数组作为索引可以选出满足特定条件的元素。例如,
arr[arr > 5]
会返回数组中所有大于5的元素。 -
花式索引:使用整数数组作为索引可以按照特定的顺序选出元素。例如,
arr[[0, 2, 4]]
会返回一维数组中的第1、第3和第5个元素。 -
负数索引:使用负数索引可以从数组的末尾开始访问元素。例如,
arr[-1]
会返回一维数组的最后一个元素。
下面是一个使用不同索引方式访问数组的例子:
import numpy as np
# 创建一个二维数组
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 使用基本索引访问第一行第三列的元素
print(arr[0, 2]) # 输出 3
# 使用切片索引访问第一和第二行的所有列
print(arr[0:2, :]) # 输出 [[1 2 3][4 5 6]]
# 使用布尔索引选出大于5的元素
print(arr[arr > 5]) # 输出 [6 7 8 9]
# 使用花式索引选出特定的行
print(arr[[0, 2]]) # 输出 [[1 2 3][7 8 9]]
# 使用负数索引访问最后一列
print(arr[:, -1]) # 输出 [3 6 9]
4 数组重塑
NumPy 允许通过 reshape
方法来改变数组的形状,而不改变其数据。这可以用于将数组转换为不同的形状,以便于后续的数据处理和分析。
import numpy as np
# 创建一个一维数组
arr1 = np.array([1, 2, 3, 4, 5, 6])
# 重塑为一维数组
new_shape = arr1.reshape(3, 2)
print("重塑后的数组:", new_shape) # 输出:[[1 2][3 4][5 6]]
# 重塑为二维数组
new_shape = arr1.reshape(2, 3)
print("重塑后的数组:", new_shape) # 输出:[[1 2 3][4 5 6]]
5 数组转置
对于二维数组,可以使用 T
属性或 transpose
方法来进行转置操作,即行列互换。
import numpy as np
# 创建一个二维数组
arr = np.array([[1, 2, 3], [4, 5, 6]])
# 使用 T 属性进行转置
transposed_arr = arr.T
print("转置后的数组:", transposed_arr) # 输出:[[1 4][2 5][3 6]]
# 使用 transpose 方法进行转置
transposed_arr = np.transpose(arr)
print("转置后的数组:", transposed_arr) # 输出:[[1 4][2 5][3 6]]
6 数组堆叠
NumPy 提供了多种方法来堆叠数组,如 vstack
(垂直堆叠)、hstack
(水平堆叠)和 concatenate
(沿指定轴堆叠)。
import numpy as np
# 创建两个二维数组
arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[5, 6], [7, 8]])
# 垂直堆叠
vstacked_arr = np.vstack((arr1, arr2))
print("垂直堆叠后的数组:", vstacked_arr) # 输出:[[1 2][3 4][5 6][7 8]]
# 水平堆叠
hstacked_arr = np.hstack((arr1, arr2))
print("水平堆叠后的数组:", hstacked_arr) # 输出:[[1 2 5 6][3 4 7 8]]
# 沿指定轴堆叠
arr3 = np.array([[9, 10], [11, 12]])
concatenated_arr = np.concatenate((arr1, arr3), axis=0)
print("沿0轴堆叠后的数组:", concatenated_arr) # 输出:[[1 2][3 4][9 10][11 12]]
7 数组分割
与堆叠相反,可以使用 vsplit
、hsplit
或 split
方法来分割数组。
import numpy as np
# 创建一个二维数组
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 垂直分割
vsplit_arr = np.vsplit(arr, 3)
print("垂直分割后的数组:", vsplit_arr) # 输出:[array([[1, 2, 3]]), array([[4, 5, 6]]), array([[7, 8, 9]])]
# 水平分割
hsplit_arr = np.hsplit(arr, 3)
总结
ndarray
是 NumPy 库的核心,它提供了一种高效、灵活的方式来处理数组和矩阵运算。掌握 ndarray
的基本概念和操作方法,是进行数据科学和机器学习等工作的基础。