NumPy学习指南第二版:Python数据分析与科学计算

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:《NumPy学习指南第二版》为Python编程者深入掌握NumPy库提供了全面参考。NumPy是Python进行科学计算的核心库,提供了高效的数组和矩阵操作功能。本书从基础到高级,详细介绍了如何利用NumPy进行高效数据处理,涵盖数组操作、线性代数、数值计算,以及与其他Python数据分析库的整合。无论读者是数据科学家、工程师还是学生,通过本书的学习和实践练习,都能提升自身在数据分析和科学计算方面的能力。电子版包含在压缩包内,便于随时随地学习。
NumPy学习指南第二版

1. NumPy基础概念介绍

NumPy是一个开源的Python库,用于进行高效的数值计算。它支持多种维度的数组与矩阵运算,并提供了一系列数学函数库,广泛应用于科学计算领域。NumPy在机器学习和数据分析领域尤其重要,是这两个领域的基石之一。本章将引导读者理解NumPy的核心理念,包括其与Python原生数据结构的差异以及如何通过NumPy进行基本的数值运算。对于想要提升代码效率,进行科学计算的程序员来说,NumPy是必不可少的工具。

2. ndarray对象构造与属性

2.1 ndarray对象的构造方法

2.1.1 ndarray的初始化

NumPy库的核心是 ndarray 对象,它是对n维数组的一种实现。要创建一个 ndarray 对象,我们通常使用 numpy.array 函数。这个函数可以将Python列表或其他数组类型的序列转换成ndarray对象。初始化ndarray时,可以指定数据类型(dtype),如果不指定,NumPy会自动推断。

import numpy as np

# 创建一个1维数组
a = np.array([1, 2, 3])

# 创建一个2维数组
b = np.array([(1.5, 2, 3), (4, 5, 6)])

# 创建一个3维数组,并显式指定dtype
c = np.array([[(1, 2, 3), (4, 5, 6)], [(3, 2, 1), (4, 5, 6)]], dtype=complex)

上述代码展示了如何创建不同维度的数组。通过初始化数组,我们可以开始对数据进行处理。需要注意的是,即使列表中的元素类型是一致的,数据类型(dtype)默认情况下仍然是对象类型,这在后续操作中可能会导致效率低下。因此,推荐在创建数组时明确指定数据类型。

2.1.2 ndarray的形状操作

形状操作主要是对数组的维度进行修改。通过 reshape 方法,我们可以改变数组的形状而不改变其数据。

# 假设有一个1维数组
arr = np.array([1, 2, 3, 4, 5, 6])

# 将其重塑成3x2的2维数组
reshaped_arr = arr.reshape((3, 2))

# 输出新数组的形状
print(reshaped_arr.shape)  # 输出:(3, 2)

reshape 方法允许我们改变数组的维度,创建新的视图而不复制数据。这意味着如果新的形状是有效的,NumPy会重用原始数据的内存。对形状的修改是数组操作中非常核心的一部分,因为很多函数在处理数据时都依赖于数组的形状。

2.2 ndarray对象的基本属性

2.2.1 ndim和shape属性

ndim 属性返回数组的维度数, shape 属性返回数组维度的具体信息。这两个属性对于理解数组结构至关重要。

# 继续使用上面的reshaped_arr
num_dimensions = reshaped_arr.ndim  # 数组的维度数
dimensions = reshaped_arr.shape  # 数组的形状

print(num_dimensions)  # 输出:2
print(dimensions)      # 输出:(3, 2)

ndim shape 属性帮助我们理解如何对数组进行维度操作。了解这两个属性能够让我们在处理多维数据时更加得心应手,尤其是在进行数据分析、图像处理或机器学习任务时。

2.2.2 dtype和itemsize属性

dtype 属性返回数组中元素的数据类型,而 itemsize 属性返回数组中每个元素所占用的字节数。

# 继续使用上面的reshaped_arr
element_type = reshaped_arr.dtype  # 元素的数据类型
element_size = reshaped_arr.itemsize  # 元素所占用的字节数

print(element_type)  # 输出:int32
print(element_size)  # 输出:4

理解 dtype itemsize 对于优化内存使用和计算速度至关重要,尤其是在处理大型数组时。选择合适的数据类型可以显著减少内存使用,提高性能。例如,如果数据可以无损地用 float32 表示,就没必要使用 float64 ,因为前者的内存占用只有后者的一半。

通过本章节的介绍,我们可以掌握使用NumPy创建数组的基本方法和理解数组的核心属性,为后续深入学习NumPy的功能打下坚实的基础。

3. 数组与Python内置结构区别

在数据科学和数值计算中,NumPy数组是一个基础且核心的概念。NumPy提供了高效的数组类型,以及一系列用于操作这些数组的函数。本章节主要探讨NumPy数组与Python标准库中的列表(list)、字典(dict)的区别,以及它们各自的使用场景和性能考量。

3.1 列表与数组的对比

3.1.1 存储效率与内存占用

Python的列表是一个动态数组,可以存储任何类型的对象。尽管这种灵活性很有用,但它也牺牲了存储效率和性能。相比之下,NumPy数组是一个固定类型的数组,这意味着所有元素都必须具有相同的类型。这种限制使得NumPy能够在内存中以更紧凑的方式存储数据,从而加快处理速度。

例如,以下代码展示了如何在列表和NumPy数组中存储整数,并使用 sys 模块来检查它们的内存占用:

import sys
import numpy as np

# 使用Python列表存储整数
python_list = list(range(1000000))

# 使用NumPy数组存储整数
numpy_array = np.arange(1000000)

# 检查内存占用
print(f"List size (bytes): {sys.getsizeof(python_list)}")
print(f"Array size (bytes): {sys.getsizeof(numpy_array)}")

执行上述代码通常会发现NumPy数组占用的内存显著少于列表。因为NumPy数组的元素都是同类型,且紧密打包,而列表需要额外的内存来存储每个元素的类型信息和引用计数。

3.1.2 操作性能差异

NumPy数组提供了大量的优化和并行计算能力,尤其是在涉及向量和矩阵操作时。这意味着对NumPy数组执行算术运算,如加法、乘法等,要比对Python列表执行相应的操作快得多。

考虑下面的性能对比示例:

# 列表操作
%timeit [i ** 2 for i in range(1000)]

# NumPy数组操作
%timeit np.arange(1000) ** 2

在上述代码中,使用 %timeit 魔法命令可以测量并比较两段代码的执行时间。通常,NumPy的数组操作会比列表操作快几个数量级,因为NumPy利用了底层的C和Fortran代码,以及SIMD(单指令多数据)指令集,如SSE和AVX。

3.2 字典与数组的对比

3.2.1 数据组织方式

字典是一种键值对集合,非常适合需要快速查找的场景。而NumPy数组是基于索引的,可以通过位置直接访问数据,但不支持基于键的快速查找。

NumPy数组是线性的,它们存储数据在一个连续的内存块中。相比之下,Python字典存储键值对,这些键值对通常是通过哈希表实现,这使得字典在执行查找操作时非常高效。

例如,当需要通过键快速访问数据时,字典是更好的选择:

# 创建一个字典
python_dict = {i: i**2 for i in range(1000)}

# 通过键访问字典中的元素
print(python_dict[10])

3.2.2 搜索和访问效率

尽管字典提供了快速的查找能力,但NumPy数组提供了另一种形式的高效访问——通过索引直接访问数据。这意味着如果我们知道元素在数组中的位置,我们可以立即获取它,而不需要进行键值对的查找。

我们可以通过下面的对比示例来观察访问效率的不同:

# 在NumPy数组中通过索引访问
numpy_array = np.arange(1000)
index = 100
print(numpy_array[index])

# 在字典中通过键访问
%timeit python_dict[index]

在执行上述代码时,可以观察到直接通过索引访问NumPy数组的元素非常快速,而字典的键值对查找则相对较慢。

总结

在这一章节中,我们探讨了NumPy数组与Python内置数据结构列表和字典的差异,重点关注了它们在存储效率、内存占用、操作性能和数据组织方式上的不同。通过比较,我们看到NumPy数组在执行高效的数值计算方面具有明显的优势,尤其是涉及大规模数据处理时。而列表和字典在特定的应用场景中仍然有其独特的优势。理解这些差异有助于我们根据需求选择合适的工具,实现最优的数据处理性能。

4. 数组数学运算与广播功能

4.1 数组的数学运算

数组的数学运算在科学计算中扮演着核心角色,NumPy作为Python中进行科学计算的核心库,提供了强大的数学运算功能,包括算术运算和线性代数运算等。这些功能使得NumPy在数值计算方面比传统的Python列表更加高效和强大。

4.1.1 算术运算

在NumPy中,对数组执行算术运算非常直观。例如,两个数组之间可以直接进行加、减、乘、除等操作。这些操作是元素级的,即操作应用于数组的每个对应元素上。

import numpy as np

# 创建两个数组
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

# 算术运算示例
addition = a + b  # [5 7 9]
subtraction = a - b  # [-3 -3 -3]
multiplication = a * b  # [ 4 10 18]
division = a / b  # [0.25 0.4 0.5]

在执行这些基本运算时,NumPy利用了广播规则,允许不同形状的数组进行运算,从而实现了更加灵活的操作。

4.1.2 线性代数运算

线性代数运算是科学计算中不可或缺的部分。NumPy支持多种线性代数运算,如矩阵乘法、求逆、求行列式等。这些运算在NumPy中通常可以通过简单的函数调用来完成。

# 线性代数运算示例
dot_product = np.dot(a, b)  # 32,点积运算
inverse_matrix = np.linalg.inv(np.array([[1, 2], [3, 4]]))  # [[-2.  1. ]
                                                               #  [ 1.5 -0.5]]
determinant = np.linalg.det(np.array([[1, 2], [3, 4]]))  # -2.0

线性代数运算通常比算术运算更加复杂,但NumPy通过高效的算法和优化的数值计算库实现了这些功能,使其在性能上不会成为瓶颈。

4.2 数组的广播功能

NumPy中的广播功能允许不同形状的数组以一种直观的方式进行算术运算。这一机制极大地增强了NumPy处理不同数据结构的能力。

4.2.1 广播机制介绍

广播机制是NumPy的核心特性之一,它描述了NumPy如何处理两个形状不同的数组的运算问题。简单来说,广播规则是这样的:

  • 如果两个数组的维数不相等,形状较小的数组会在其形状前面补1,直到两个数组的维数相同。
  • 如果两个数组在某个维度上的大小相同,或者其中一个数组在该维度上的大小为1,则认为这两个数组在该维度上是兼容的。
  • 如果两个数组在所有维度上都兼容,则可以进行运算。运算时,形状较大的数组不变,形状较小的数组在缺失的维度上视为重复。
4.2.2 广播应用实例

假设我们有一个形状为 (3, 4) 的数组 A 和一个形状为 (1, 4) 的数组 B 。按照广播规则, B 会沿着缺失的第一个维度进行复制,形成一个同样为 (3, 4) 的数组,然后再与 A 进行逐元素的加法运算。

A = np.array([[0, 1, 2, 3],
              [4, 5, 6, 7],
              [8, 9, 10, 11]])

B = np.array([0, 1, 2, 3])

# 无须使用循环即可进行逐元素加法运算
C = A + B  # C数组的每个元素都加上了B数组的对应元素

广播机制大大简化了代码,使得原本需要复杂的循环结构来实现的数组操作,变得异常简洁和高效。这也正是NumPy在数据分析和科学计算中大受欢迎的原因之一。

5. 数组创建、索引、操作与元素级运算

5.1 数组的创建与索引

5.1.1 常用数组创建方法

在处理科学计算时,创建数组是一项基础且关键的操作。NumPy 提供了多种方法来创建数组,这里我们将介绍几种常用的方法。

import numpy as np

# 从列表创建数组
list_array = np.array([[1, 2], [3, 4]])
print(list_array)

# 创建全零数组
zero_array = np.zeros((2, 3))
print(zero_array)

# 创建全一数组
one_array = np.ones((3, 2))
print(one_array)

# 创建单位矩阵
identity_matrix = np.eye(3)
print(identity_matrix)

# 创建等差数列
arange_array = np.arange(10)
print(arange_array)

# 生成特定范围内的随机数组
rand_array = np.random.random((2, 3))
print(rand_array)

在上述代码中, np.array 是最通用的方法,可以从Python列表或元组创建数组; np.zeros np.ones 分别用于创建指定形状的全零或全一数组; np.eye 用于生成单位矩阵; np.arange 类似于Python内建的 range 函数,但是生成的是数组而非列表; np.random.random 用于生成在0到1之间的随机数组。

5.1.2 高级索引技术

索引是访问数组元素的直接方式,而高级索引提供了更加强大和灵活的数据访问能力。NumPy支持整数索引、布尔索引和数组索引。

# 创建一个二维数组
a = np.array([[1, 2], [3, 4], [5, 6]])

# 整数索引
row_index = np.array([0, 1, 2])
col_index = np.array([1, 1, 0])
print(a[row_index, col_index])  # 输出: [2 4 5]

# 布尔索引
print(a[a > 2])  # 输出: [3 4 5 6]

# 数组索引
rows = np.array([[0, 0], [2, 2]])
cols = np.array([[0, 1], [0, 1]])
print(a[rows, cols])  # 输出: [[1 2] [5 6]]

在这个例子中,整数索引是通过提供行索引和列索引的数组来访问特定元素;布尔索引则是利用布尔数组来过滤元素;数组索引是使用索引数组来同时访问多个元素的位置。

5.2 数组的操作与元素级运算

5.2.1 数组形状变换

在数据分析过程中,经常需要对数组进行形状变换,比如重塑(reshape)、展平(flatten)、转置(transpose)等。

# 重塑数组
b = np.arange(8)
print(b.reshape(2, 4))

# 展平数组
c = np.array([[1, 2], [3, 4]])
print(c.flatten())

# 转置数组
d = np.array([[1, 2], [3, 4]])
print(d.transpose())

# 使用`swapaxes`交换轴
print(d.swapaxes(0, 1))

在上面的代码块中, reshape 方法可以改变数组的形状而不改变其数据; flatten 方法会返回一个新的一维数组,原数组保持不变; transpose 方法会返回原数组的转置; swapaxes 方法则用于交换数组的两个轴。

5.2.2 元素级函数应用

元素级函数是在数组上逐个元素执行操作的函数。NumPy 提供了大量此类函数,可以高效地对数组进行数学运算。

# 元素级算术运算
e = np.array([[1, 2], [3, 4]])
print(np.add(e, 1))  # 加法
print(np.subtract(e, 1))  # 减法
print(np.multiply(e, 2))  # 乘法
print(np.divide(e, 2))  # 除法

# 三角函数和对数函数
print(np.sin(e))  # 正弦
print(np.log(e))  # 自然对数

# 比较函数
print(np.greater(e, 2))  # 大于

以上代码展示了如何使用NumPy的元素级函数来进行基本的算术运算和数学函数计算。这些函数在处理大型数据集时比Python内建的函数更加高效,因为它们是向量化操作。

以上就是关于NumPy数组创建、索引、操作以及元素级运算的介绍。通过这些技术,您可以高效地处理和操作大型数组数据,为后续的数据分析和科学计算打下坚实的基础。

6. 数组排序与统计函数

6.1 数组排序技巧

6.1.1 排序算法基础

排序是数据分析和科学计算中经常遇到的需求,尤其在数据预处理和后处理阶段。NumPy 提供了多种数组排序的方法。最基本的是 numpy.sort() 函数,它返回的是一个已经排序的新数组,原数组不会被改变。理解排序算法的基础对于高效使用排序功能至关重要。

Python 内置的 sorted() 函数是通用的排序方法,但其在大型数据集上的表现不如 NumPy 的 sort() 函数。NumPy 的排序算法通常更加优化,且针对数值数组进行了优化。

6.1.2 高效排序策略

NumPy 中, numpy.argsort() 是一个非常有用的函数,它返回的是输入数组元素排序后的索引。这对于维护元素之间的关系非常有用。例如,如果你对数组进行部分排序,并想要知道其余元素的位置, argsort() 将给出答案。

对于多维数组, numpy.sort() 函数允许你沿着特定的轴进行排序。通过设置 axis 参数,可以实现对数组的行或列进行独立排序。

6.2 统计函数的使用

6.2.1 基本统计量计算

NumPy 提供了丰富的统计函数,可用来计算一维和多维数组的基本统计量。例如, numpy.mean() numpy.median() numpy.std() numpy.var() numpy.sum() 等函数分别用来计算均值、中位数、标准差、方差和总和。

6.2.2 数据分布分析

为了更好地理解数据的分布,NumPy 提供了一些有用的函数,如 numpy.percentile() ,它可以帮助我们了解数据的分位数。此外, numpy.max() numpy.min() 函数可以用来找出数组中的最大值和最小值。

NumPy 的 numpy.where() 函数也值得提及,它能够返回满足某个条件的数组元素的索引。这对于识别异常值或对数据集进行条件筛选很有帮助。

代码演示

下面的代码示例展示了如何使用 NumPy 的排序和统计函数:

import numpy as np

# 创建一个随机数组
data = np.random.rand(10)

# 计算均值
mean_value = np.mean(data)
print("均值:", mean_value)

# 计算中位数
median_value = np.median(data)
print("中位数:", median_value)

# 计算标准差
std_dev = np.std(data)
print("标准差:", std_dev)

# 排序
sorted_data = np.sort(data)
print("排序后的数组:", sorted_data)

# 计算数据集的分位数
quartiles = np.percentile(data, [25, 50, 75])
print("分位数:", quartiles)

# 查找满足条件的元素索引
condition = data > 0.5
indices = np.where(condition)
print("大于0.5的元素索引:", indices)

分析

  • np.mean(data) :计算 data 数组中所有元素的均值。
  • np.median(data) :找出 data 数组中的中位数。
  • np.std(data) :计算 data 数组的标准差。
  • np.sort(data) :返回一个新数组,其中包含 data 数组的排序副本。
  • np.percentile(data, [25, 50, 75]) :计算 data 数组的25%、50%(中位数)和75%分位数。
  • np.where(data > 0.5) :返回数组中所有大于0.5的元素的索引。

这些函数对于数据分析来说至关重要,因为它们能够帮助我们快速理解数据集的特征和统计属性。在处理大规模数据集时,这些函数通常优化为运行高效,且占用内存较少。

为了加深理解,可以尝试对上述代码段进行运行,观察输出,并对结果进行解释。这有助于掌握统计分析中关键概念的应用。

7. 线性代数功能与矩阵操作

线性代数是科学计算和数据分析中不可或缺的一部分,NumPy作为一个强大的数值计算库,提供了丰富的线性代数功能和矩阵操作工具。本章节将详细探讨这些功能和操作,以及它们在实际应用中的高级应用。

7.1 线性代数基础

7.1.1 向量与矩阵运算

NumPy提供了对向量和矩阵操作的支持,包括加法、乘法以及矩阵乘法等。这些操作是进行线性代数运算的基础。

import numpy as np

# 创建两个向量
v1 = np.array([1, 2, 3])
v2 = np.array([4, 5, 6])

# 向量加法
v_addition = v1 + v2

# 创建两个矩阵
m1 = np.array([[1, 2], [3, 4]])
m2 = np.array([[5, 6], [7, 8]])

# 矩阵乘法
m_multiplication = np.dot(m1, m2)

向量和矩阵的运算可以使用点积、叉积等多种方式。这些运算在物理、工程以及金融等领域中有着广泛的应用。

7.1.2 特征值与特征向量

特征值和特征向量是线性代数中的重要概念,它们用于描述线性变换的某些特性。在NumPy中,可以使用 numpy.linalg.eig 函数来计算矩阵的特征值和特征向量。

# 计算特征值和特征向量
eigenvalues, eigenvectors = np.linalg.eig(m1)

7.2 矩阵操作的高级应用

7.2.1 矩阵分解技术

矩阵分解是将矩阵分解为几个更有用的矩阵乘积的过程,如LU分解、QR分解、奇异值分解(SVD)等。NumPy提供了相应的函数来实现这些高级操作。

from numpy.linalg import lu, qr, svd

# LU分解
P, L, U = lu(m1)

# QR分解
Q, R = qr(m1)

# 奇异值分解
U, s, V = svd(m1)

矩阵分解技术在求解线性方程组、数据降维和统计分析等领域有重要应用。

7.2.2 矩阵运算优化

在进行大规模的矩阵运算时,运算效率变得尤为重要。NumPy通过内部优化和利用硬件加速(如使用Intel MKL或OpenBLAS库),能够显著提高矩阵运算的速度。

# 使用NumPy的优化矩阵乘法
result = np.dot(m1, m2)

在进行矩阵运算时,应当注意选择适当的函数和优化技巧,以求获得最优的性能。例如,对于大规模矩阵运算,可以考虑使用分布式计算或者GPU加速。

矩阵操作是NumPy库中非常强大的部分,它不仅支持基本的线性代数运算,还能进行高效的矩阵分解和优化。这些功能使得NumPy在处理科学计算和数据分析任务时显得非常得心应手。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:《NumPy学习指南第二版》为Python编程者深入掌握NumPy库提供了全面参考。NumPy是Python进行科学计算的核心库,提供了高效的数组和矩阵操作功能。本书从基础到高级,详细介绍了如何利用NumPy进行高效数据处理,涵盖数组操作、线性代数、数值计算,以及与其他Python数据分析库的整合。无论读者是数据科学家、工程师还是学生,通过本书的学习和实践练习,都能提升自身在数据分析和科学计算方面的能力。电子版包含在压缩包内,便于随时随地学习。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值