智能助教

1 NumPy 简介¶

NumPy (Numerical Python) 是 Python 中用于科学计算的核心库,特别适合处理表格数据、问卷调查结果、文本分析等文科常见任务。

NumPy 的全称是 Numerical Python,是 Python 中用于科学计算的重要第三方库之一。它提供了一个强大的多维数组对象 ndarray,以及对这些数组进行操作的函数和工具。NumPy 数组可以存储同质的数据(即数据类型相同),可以进行高效的数学计算和数据处理。

NumPy 的主要特点包括:

  • 多维数组对象 ndarray,支持向量化操作和广播(Broadcasting)。
  • 丰富的数组操作函数,包括数组形状操作、数学计算、排序、统计等。
  • 可以利用 NumPy 进行高效的数值计算。
  • 高效的内存管理和数据存储方式,支持磁盘数据读写和内存映射文件。
  • 开源、免费、跨平台、社区活跃。
  • NumPy 库在科学计算、数据处理、机器学习等领域都有广泛的应用。它是许多 Python 数据科学库的基础,如 SciPy、pandas、scikit-learn 等,也是许多机器学习框架的基础,如 TensorFlow、PyTorch 等。 在本章中,我们将介绍NumPy数组的创建、访问和操作,以及如何使用NumPy进行统计分析。

什么是数组?

数组(Array) 是计算机中用来存储同一类型数据的有序集合,可以高效地进行批量计算和操作。

想象一个整齐排列的数据表格:

一维数组 → 像一行或一列数据(例如:[85, 90, 78] 表示3个学生的成绩)。

二维数组 → 像Excel表格(例如:[[85, 90], [76, 88]] 表示2个学生的语文和数学成绩)。

三维数组 → 像多个表格叠在一起(例如:3个班级的成绩表组合成一个数据块)。

为什么需要数组?

高效计算:一次性处理大量数据(如求平均分、总和)。

结构化存储:整齐排列,便于查找和统计(如问卷数据、实验记录)。

支持多维数据:能表示表格(二维)、立体数据(三维)等复杂结构。

1.1 安装与导入¶

NumPy 通常已包含在 Anaconda 中。如需安装:

!pip install numpy

导入惯例:

In [ ]:
import numpy as np  # 使用 np 作为简称是约定俗成的

1.2 为什么需要NumPy?¶

想象这些场景:

  • 分析1000份问卷数据
  • 计算文学作品中的词频统计
  • 处理历史人口数据
  • 比较不同地区的经济指标

NumPy可以帮助我们高效处理这些结构化数据!

1.3 创建数组¶

数组就像整齐排列的数据表格

In [5]:
import numpy as np
# 创建一维数组(比如5个学生的考试成绩)
scores = np.array([85, 90, 78, 92, 88])
# print("学生成绩:", scores)
# print(type(scores))

#创建二维数组(比如3个班级,每班5人的成绩)
class_scores = np.array([
    [85, 90, 78, 92, 88],  # 1班
    [76, 89, 94, 81, 79],  # 2班
    [92, 87, 83, 90, 86]   # 3班
])
# print("\n各班成绩表:")
print(class_scores)
print(type(class_scores))
[[85 90 78 92 88]
 [76 89 94 81 79]
 [92 87 83 90 86]]
<class 'numpy.ndarray'>

1.4 数组基本操作¶

In [20]:
class_scores = np.array([
    [85, 90, 78, 92, 88],  # 1班
    [76, 89, 94, 81, 79],  # 2班
    [92, 87, 83, 90, 86]   # 3班
])
print(class_scores[1][2])
#class_scores[1][2] #取1班第二位同学的成绩
# 访问数据 - 获取2班第3个学生的成绩
# print("2班第3个学生成绩:", class_scores[1, 2])

# # 切片 - 获取所有班级的第2-4号学生成绩
# print("\n各班第2-4号学生成绩:")
# print(class_scores[:, 1:4])  # 逗号前选择班级,逗号后选择学生

# 改变形状 - 将成绩表重新排列为5行3列
#print(class_scores)
reshaped_scores = class_scores.reshape(5, 3)
# # print("\n重组后的成绩表:")
print(reshaped_scores)
[[85 90 78]
 [92 88 76]
 [89 94 81]
 [79 92 87]
 [83 90 86]]

初始化 NumPy 数组¶

NumPy 提供了多种方法来初始化数组,包括从列表、元组、零数组、单位矩阵等方式进行创建。

In [24]:
# 示例:初始化 NumPy 数组
import numpy as np
# 从列表初始化 NumPy 数组
array_from_list = np.array([1, 2, 3, 4, 5])
# print(array_from_list)
# 创建一个全是零的 NumPy 数组
array_zeros = np.zeros((3, 3))
array_zeros
# # 创建一个单位矩阵
identity_matrix = np.eye(3)
identity_matrix
# # 显示结果
# # print("从列表创建的数组:")
# # print(array_from_list)
# print("全零数组:")
# print(array_zeros)
# print("单位矩阵:")
# print(identity_matrix)
Out[24]:
array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])

ndarray 的属性¶

每个 ndarray 对象都有一些常见的属性,例如 ndarray.shape,ndarray.size,ndarray.dtype 等,用于获取数组的维度、元素数量和数据类型。

In [2]:
# 示例:ndarray 的属性

import numpy as np
# 创建一个 NumPy 数组
array = np.array([[1, 2, 3], [4, 5, 6]])
# 查看数组的形状
print("数组形状:", array.shape)
# 查看数组的元素数量
print("数组大小:", array.size)
# 查看数组的数据类型
print("数组数据类型:", array.dtype)
数组形状: (2, 3)
数组大小: 6
数组数据类型: int32

NumPy 的形状¶

数组的形状是指数组中各维度的大小,NumPy 提供了 .shape 属性来查看数组的形状。

In [28]:
# 示例:ndarray 的形状

import numpy as np

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

# 查看数组的形状
print("数组形状:", array.shape)

# 修改数组的形状
array_reshaped = array.reshape((2, 3))
print("修改后的数组形状:", array_reshaped.shape)
print(array)
print(array_reshaped)
数组形状: (3, 2)
修改后的数组形状: (2, 3)
[[1 2]
 [3 4]
 [5 6]]
[[1 2 3]
 [4 5 6]]

ndarray 的类型¶

NumPy 支持多种数据类型,常见的包括 int32,float64 等。可以使用 ndarray.dtype 查看数组元素的类型。

  • int32:32位整数(适合存普通整数)
  • float64:64位小数(适合存带小数点的数,精度更高) 做科学计算多用float64,存普通数字用int32就够了。

不同类型占用的内存空间不同,计算精度也不同。就像:

  • 整数计算快但存不了小数
  • 小数能存更精确但占用空间大
In [29]:
# 示例:ndarray 的数据类型
import numpy as np
# 创建一个 NumPy 数组
array = np.array([1.5, 2.5, 3.5])
# 查看数组的数据类型
print("数组数据类型:", array.dtype)
# 强制转换数据类型
array_int = array.astype(np.int32)
print("转换后的数据类型:", array_int.dtype)
数组数据类型: float64
转换后的数据类型: int32
The history saving thread hit an unexpected error (OperationalError('database or disk is full')).History will not be written to the database.

练习¶

  1. 创建一个 3x3 的 NumPy 数组,初始化为全零,使用 zeros() 方法。
  2. 创建一个 4x4 的单位矩阵,使用 eye() 方法。
  3. 创建一个 NumPy 数组并查看其形状、大小和数据类型。
  4. 修改数组的形状,例如将一个 2x3 的数组修改为 3x2。
  5. 创建一个浮点数类型的 NumPy 数组,将其转换为整数类型。
In [ ]:
#1.创建一个 3x3 的 NumPy 数组,初始化为全零,使用 `zeros()` 方法。
import numpy as np
arr_zeros = np.zeros((3, 3))

#2. 创建一个 4x4 的单位矩阵,使用 `eye()` 方法。
arr_eye = np.eye(4)

#3.创建一个 NumPy 数组并查看其形状、大小和数据类型。
arr = np.array([1, 2, 3])
print("形状:", arr.shape)      # 输出 (3,)
print("大小:", arr.size)       # 输出 3
print("数据类型:", arr.dtype)  # 输出 int32 或 int64

# 4. 修改数组的形状,例如将一个 2x3 的数组修改为 3x2。
arr = np.array([[1, 2, 3], [4, 5, 6]])  # 2x3
new_arr = arr.reshape(3, 2)             # 改为 3x2

#5.创建一个浮点数类型的 NumPy 数组,将其转换为整数类型。
arr_float = np.array([1.1, 2.5, 3.9])
arr_int = arr_float.astype(int)  # 输出 [1, 2, 3](直接截断小数)

1.5 实用案例¶

In [ ]:
# 案例1:分析问卷调查结果(5分制)
survey_data = np.array([
    [5, 4, 3, 2, 5],  # 问卷1
    [4, 3, 4, 3, 4],  # 问卷2
    [3, 2, 5, 4, 3]   # 问卷3
])

# 计算每个问题的平均分
print("各问题平均分:", np.mean(survey_data, axis=0))

# 案例2:文学作品词频统计(10个章节的词数)
word_counts = np.array([1245, 1320, 1180, 1450, 1260, 1390, 1420, 1280, 1350, 1410])
print("\n平均每章词数:", np.mean(word_counts))
print("最多词的章节:", np.max(word_counts))

# 案例3:GDP增长率比较(3个国家5年数据)
gdp_growth = np.array([
    [2.1, 2.3, 2.0, 1.9, 2.2],  # 国家A
    [3.2, 3.5, 3.1, 3.0, 3.4],  # 国家B
    [1.5, 1.6, 1.4, 1.3, 1.7]   # 国家C
])
print("\n各国平均增长率:", np.mean(gdp_growth, axis=1))

1.6 练习时间¶

In [ ]:
# 练习1:创建数组存储3本小说的评分(5位评委)
# 预期输出格式:
# [[8.2 7.9 8.5 8.1 8.3]
#  [7.8 8.0 7.7 8.2 7.9]
#  [8.5 8.3 8.6 8.4 8.7]]

# 练习2:计算每本小说的平均分

# 练习3:找出最高分的评委(提示:使用np.argmax)

# 练习4:创建一个2x4数组存储两个地区4个季度的降水量(毫米)
# 然后计算:
# 1) 每个地区的年平均降水量
# 2) 所有地区季降水量的标准差

参考答案¶

In [ ]:
# 练习1答案
novel_ratings = np.array([
    [8.2, 7.9, 8.5, 8.1, 8.3],
    [7.8, 8.0, 7.7, 8.2, 7.9],
    [8.5, 8.3, 8.6, 8.4, 8.7]
])

# 练习2答案
print("每本小说平均分:", np.mean(novel_ratings, axis=1))

# 练习3答案
max_judge = np.argmax(novel_ratings) % 5  # 获取评委编号(0-4)
print("给出最高分的评委编号:", max_judge + 1)  # 转为1-5编号

# 练习4答案
precipitation = np.array([
    [120, 150, 180, 90],  # 地区A
    [80, 110, 140, 70]   # 地区B
])
print("\n年平均降水量:", np.mean(precipitation, axis=1))
print("季降水量标准差:", np.std(precipitation))

2 数组间的运算¶

NumPy 提供了多种数组运算功能,可以让我们方便地进行数组与数组之间的运算,或者数组与数值之间的运算。这些操作可以帮助我们高效地进行数学计算和数据处理。

2.1 数组与数之间的运算¶

NumPy 支持数组与标量值之间的运算,可以将标量与数组的每个元素进行逐一运算,生成新的数组。

In [3]:
# 示例:数组与数之间的运算
import numpy as np
# 创建一个 NumPy 数组
array = np.array([1, 2, 3, 4, 5])
# 数组与标量相加
result_add = array + 10
# 数组与标量相乘
result_multiply = array * 2
# 数组与标量相减
result_subtract = array - 3
# 数组与标量相除
result_divide = array / 2
# 显示结果
print("数组与标量相加:", result_add)
print("数组与标量相乘:", result_multiply)
print("数组与标量相减:", result_subtract)
print("数组与标量相除:", result_divide)
数组与标量相加: [11 12 13 14 15]
数组与标量相乘: [ 2  4  6  8 10]
数组与标量相减: [-2 -1  0  1  2]
数组与标量相除: [0.5 1.  1.5 2.  2.5]

2.2 数组与数组之间的运算¶

NumPy 也支持数组与数组之间的运算,允许我们直接对两个数组进行加、减、乘、除等数学运算。

NumPy数组之间的加减乘除是对应位置的元素分别计算

In [4]:
# 示例:数组与数组之间的运算
import numpy as np
# 创建两个 NumPy 数组
array1 = np.array([1, 2, 3, 4, 5])
array2 = np.array([5, 4, 3, 2, 1])
# 数组相加
result_add_arrays = array1 + array2
# 数组相减
result_subtract_arrays = array1 - array2
# 数组相乘
result_multiply_arrays = array1 * array2
# 数组相除
result_divide_arrays = array1 / array2
# 数组的点积运算
dot_product = np.dot(array1, array2)  # 1×5 + 2×4 + 3×3 + 4×2 + 5×1 =
#点积(也叫内积)是线性代数中的一种基本运算,用于计算两个向量的乘积之和。在 NumPy 中,可以用 np.dot(a, b) 或 a @ b 来计算
# 显示结果  print("数组相加:", result_add_arrays)
print("数组相减:", result_subtract_arrays)
print("数组相乘:", result_multiply_arrays)
print("数组相除:", result_divide_arrays)
print("数组的点积运算:", dot_product)
数组相加: [6 6 6 6 6]
数组相减: [-4 -2  0  2  4]
数组相乘: [5 8 9 8 5]
数组相除: [0.2 0.5 1.  2.  5. ]
数组的点积运算: 35

练习¶

  1. 创建一个 NumPy 数组,将其与一个标量相加、相减、相乘和相除。
  2. 创建两个 NumPy 数组,分别进行加法、减法、乘法和除法运算。
  3. 计算两个数组的点积运算,并解释结果。
In [ ]:
# 创建一个 NumPy 数组,将其与一个标量相加、相减、相乘和相除。
import numpy as np

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

# 标量运算
print(arr + 2)   # [3, 4, 5]  
print(arr - 1)   # [0, 1, 2]  
print(arr * 3)   # [3, 6, 9]  
print(arr / 2)   # [0.5, 1.0, 1.5]  
In [ ]:
# 2. 创建两个 NumPy 数组,分别进行加法、减法、乘法和除法运算。
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

# 逐元素运算
print(a + b)   # [5, 7, 9]  
print(a - b)   # [-3, -3, -3]  
print(a * b)   # [4, 10, 18]  
print(a / b)   # [0.25, 0.4, 0.5]  
In [ ]:
# 3. 计算两个数组的点积运算,并解释结果。
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

dot_product = np.dot(a, b)  # 1 * 4 + 2 * 5 + 3 * 6 = 4 + 10 + 18 = 32
print(dot_product)  # 输出 32

补充 3 NumPy 轴(Axis)的代码示例¶

%E5%9B%BE%E7%89%871.png

%E5%9B%BE%E7%89%872.png

1. 一维数组(1D Array)

In [5]:
import numpy as np

# 创建一维数组(仅1个轴,方向为从左到右)
arr_1d = np.array([1, 2, 3, 4])
print("一维数组:", arr_1d)
print("形状(shape):", arr_1d.shape)  # 输出 (4,) 表示只有1个轴,长度为4
一维数组: [1 2 3 4]
形状(shape): (4,)

2. 二维数组(2D Array)

In [6]:
# 创建二维数组(2个轴:行和列)
arr_2d = np.array([[1, 2, 3], [4, 5, 6]])
print("二维数组:\n", arr_2d)
print("形状(shape):", arr_2d.shape)  # 输出 (2, 3) 表示2行3列

# 沿轴操作示例
print("沿 Axis 0(行方向)求和:", np.sum(arr_2d, axis=0))  # 输出 [5 7 9](每列相加)
print("沿 Axis 1(列方向)求和:", np.sum(arr_2d, axis=1))  # 输出 [6, 15](每行相加)
二维数组:
 [[1 2 3]
 [4 5 6]]
形状(shape): (2, 3)
沿 Axis 0(行方向)求和: [5 7 9]
沿 Axis 1(列方向)求和: [ 6 15]

3. 三维数组(3D Array)

In [1]:
import numpy as np
# 创建三维数组(3个轴:深度、行、列)
arr_3d = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
print("三维数组:\n", arr_3d)
print("形状(shape):", arr_3d.shape)  # 输出 (2, 2, 2) 表示2层2行2列

# 沿轴操作示例
print("沿 Axis 0(深度方向)求和:\n", np.sum(arr_3d, axis=0))  # 输出 [[6, 8], [10, 12]]
print("沿 Axis 1(行方向)求和:\n", np.sum(arr_3d, axis=1))  # 输出 [[4, 6], [12, 14]]
print("沿 Axis 2(列方向)求和:\n", np.sum(arr_3d, axis=2))  # 输出 [[3, 7], [11, 15]]
三维数组:
 [[[1 2]
  [3 4]]

 [[5 6]
  [7 8]]]
形状(shape): (2, 2, 2)
沿 Axis 0(深度方向)求和:
 [[ 6  8]
 [10 12]]
沿 Axis 1(行方向)求和:
 [[ 4  6]
 [12 14]]
沿 Axis 2(列方向)求和:
 [[ 3  7]
 [11 15]]

关键小结

  1. 轴编号:
    • axis=0:行方向(纵向)
    • axis=1:列方向(横向)
    • axis=2:深度方向(3D数组)

  2. 形状(shape)规则:
    • 一维:(n,)
    • 二维:(行, 列)
    • 三维:(层, 行, 列)

  3. 操作逻辑:
    • np.sum(arr, axis=k) 表示沿第 k 个轴求和,结果会消减该轴。 • 例如:(2,3) 数组沿 axis=0 求和后变为 (3,)。

axis 操作方向 效果 例子
0 跨行(垂直) 保留列,压缩行 计算每门课的平均分
1 跨列(水平) 保留行,压缩列 计算每个学生的总分
2 跨层(深度) 保留行和列,压缩层 计算多个班级中同一学生的平均分

具体说明

1. axis=0(跨行操作)

行为:操作会压缩行(保留列结构),即对每一列的所有行数据做计算。

例子:计算班级成绩表中各科目的平均分(对每个科目,跨所有学生计算)。

In [ ]:
import numpy as np

# 3个学生,2门课的成绩表(3行2列)
scores = np.array([
    [80, 90],  # 学生1
    [70, 85],  # 学生2
    [88, 92]   # 学生3
])

# 计算每门课的平均分(跨学生)
mean_by_subject = np.mean(scores, axis=0)
print(mean_by_subject)  # 输出: [79.33 89.0] → 数学平均79.33,语文平均89

2. axis=1(跨列操作)

行为:操作会压缩列(保留行结构),即对每一行的所有列数据做计算。

例子:计算每个学生的总分(对每个学生,跨所有科目求和)。

In [ ]:
# 计算每个学生的总分
total_per_student = np.sum(scores, axis=1)
print(total_per_student)  # 输出: [170 155 180] → 学生1总分170,学生2总分155...

3. axis=2(三维数组中的深度)

行为:在三维数组中操作深度方向(如多个表格叠加时的层间操作)。

例子:分析3个班级的成绩表(每个班级是一个二维表格,叠加成三维数组)。

In [ ]:
# 3个班级,每个班级2个学生,2门课(3层2行2列)
class_scores = np.array([
    [[80, 90], [70, 85]],  # 班级1
    [[75, 88], [82, 91]],   # 班级2
    [[90, 92], [78, 84]]    # 班级3
])

# 计算所有班级每个学生的平均分(跨班级)
mean_by_student = np.mean(class_scores, axis=0)
print(mean_by_student)
# 输出: [[81.67 90.0 ]  # 学生1的数学平均81.67,语文90
#       [76.67 86.67]]  # 学生2的数学平均76.67,语文86.67

场景:问卷调查统计

In [ ]:
#假设有3份问卷,每份问卷5个问题(3行5列):

surveys = np.array([
    [5, 4, 3, 2, 5],  # 问卷1
    [4, 3, 4, 3, 4],  # 问卷2
    [3, 2, 5, 4, 3]   # 问卷3
])

np.mean(surveys, axis=0)
np.sum(surveys, axis=1)
  • np.mean(surveys, axis=0) → 每个问题的平均分(跨问卷)。

  • np.sum(surveys, axis=1) → 每份问卷的总分(跨问题)。

In [ ]: