第1天(6月18日):数组的创建与基本操作
1.1 什么是NumPy?
大白话 :NumPy是Python的"科学计算器"。Python的列表只能一个一个处理数据,NumPy的数组可以一次性对所有数据做数学运算,而且速度飞快。
1.2 创建数组
python
import numpy as np
# 从列表创建数组(最常用)
np.array([1, 2, 3, 4, 5])
# 从元组创建
np.array((1, 2, 3, 4, 5))
# 从range创建
np.array(range(5))
# 二维数组(表格形式)
np.array([[1, 2, 3], [4, 5, 6]])
1.3 快速生成数组的常用函数
python
np.arange(8) # 像range一样,生成0到7的数组
np.arange(1, 10, 2) # 起始1,结束10,步长2 → [1,3,5,7,9]
np.linspace(0, 10, 11) # 0到10之间生成11个等间距的数
np.zeros(3) # 生成3个0 → [0, 0, 0]
np.zeros((3, 3)) # 3行3列的零矩阵
np.ones(3) # 生成3个1
np.identity(3) # 3行3列的单位矩阵(对角线为1,其余为0)
np.diag([1, 2, 3, 4]) # 对角矩阵,对角线上的值是1,2,3,4
# 随机数数组
np.random.randint(0, 50, 5) # 0-50之间随机5个整数
np.random.randint(0, 50, (3, 5)) # 0-50之间随机,3行5列
np.random.rand(10) # 10个0-1之间的随机小数
np.random.standard_normal(5) # 5个符合标准正态分布的随机数
记忆技巧:
arange= array + range(数组版的range)linspace= linear + space(线性空间,等间距)zeros= 全是零ones= 全是一
1.4 修改数组中的元素
python
x = np.arange(8)
# 追加元素(返回新数组,不改变原数组)
np.append(x, 8) # 末尾加一个
np.append(x, [9, 10]) # 末尾加多个
# 原地修改(会改变原数组)
x[3] = 8 # 直接改下标3的值
# 插入元素(返回新数组)
np.insert(x, 1, 8) # 在下标1处插入值8
# 二维数组的修改
x = np.array([[1,2,3], [4,5,6], [7,8,9]])
x[0, 2] = 4 # 改第0行第2列为4
x[1:, 1:] = 1 # 行≥1且列≥1的区域全改成1
x[1:, 1:] = [[1,2],[3,4]] # 同时改多个值(注意形状要匹配)
1.5 数组的运算
数组与常量运算 :数组里的每个元素都和常量做运算。
python
x = np.array([1, 2, 3, 4, 5])
# 数组在前,常量在后
x * 2 # [2, 4, 6, 8, 10] 每个元素乘2
x + 2 # [3, 4, 5, 6, 7] 每个元素加2
x ** 3 # [1, 8, 27, 64, 125] 每个元素的3次方
# 常量在前,数组在后(注意结果不同!)
2 ** x # [2, 4, 8, 16, 32] 2的x次方
2 / x # 2除以每个元素
数组与数组运算:
python
# 等长数组:对应位置元素运算
np.array([1,2,3]) + np.array([4,3,2]) # [5,5,5]
# 不等长但可广播:短的会"扩展"
a = np.array([1,2,3])
b = np.array([[1,2,3],[4,5,6],[7,8,9]])
a * b # a的每个元素乘b对应列的元素
a + b # a的每个元素加b对应列的元素
广播原则:如果两个数组维度不同,NumPy会尝试把小数组"扩展"到和大数组一样的形状。如果形状不兼容,就会报错。
1.6 数组的排序
python
x = np.array([3, 1, 2, 4])
# argsort()返回排序后的下标(不改变原数组)
np.argsort(x) # [1, 2, 0, 3] 对应 1→2→3→4
x[np.argsort(x)] # [1, 2, 3, 4] 用下标取出排序后的值
# 最大/最小值的下标
x.argmax() # 3(最大值4的下标)
x.argmin() # 1(最小值1的下标)
# sort()是原地排序(改变原数组)
x.sort() # x 变成 [1, 2, 3, 4]
1.7 访问数组元素
python
b = np.array([[1,2,3],[4,5,6],[7,8,9]])
# 基础访问
b[0] # 第0行所有元素 → [1,2,3]
b[0, 2] # 第0行第2列 → 3
b[0][2] # 等价写法
# 花式索引(用列表做下标)
b[[0, 1]] # 第0行和第1行
b[[0, 2, 1], [2, 1, 0]] # 分别取(0,2), (2,1), (1,0)
# 切片访问
a = np.arange(10)
a[::-1] # 反向 → [9,8,7,6,5,4,3,2,1,0]
a[::2] # 隔一个取一个 → [0,2,4,6,8]
a[:5] # 前5个 → [0,1,2,3,4]
1.8 改变数组形状
python
x = np.arange(1, 11) # [1,2,3,...,10]
# 方法1:修改shape属性(原地修改)
x.shape = 2, 5 # 变成2行5列
x.shape = 5, -1 # 5行,-1表示自动计算列数
# 方法2:reshape()(返回新数组,原数组不变)
x.reshape(2, 5)
# 方法3:resize()(可改变元素总数)
x.resize((1, 10)) # 变成1行10列,多的填0
np.resize(x, (1, 3)) # numpy的resize返回新数组
三种方法对比:
| 方法 | 是否修改原数组 | 能否改变元素总数 |
|---|---|---|
x.shape = ... |
原地修改 | 不能 |
x.reshape(...) |
返回新数组 | 不能 |
x.resize(...) |
原地修改 | 可以(多出填0) |
1.9 数组的内积运算
大白话:内积 = 对应位置元素相乘,再把乘积全部加起来。
python
x = np.array([1, 2, 3])
y = np.array([4, 5, 6])
# 三种等价写法
np.dot(x, y) # 32
x.dot(y) # 32
sum(x * y) # 32
# 计算过程:1×4 + 2×5 + 3×6 = 4 + 10 + 18 = 32
1.10 比较两个数组
python
x = np.array([1, 2, 3, 4.001, 5])
y = np.array([1, 1.999, 3, 4.01, 5.1])
np.allclose(x, y) # 所有元素都接近?返回True/False
np.allclose(x, y, atol=0.2) # 设置绝对误差范围
np.isclose(x, y) # 逐个位置判断,返回布尔数组
第2天(6月22日):函数运算、布尔筛选与条件处理
2.1 数组对函数运算的支持
大白话:NumPy可以对整个数组一次性做数学函数运算,不需要写for循环。
python
x = np.arange(0, 100, 10, dtype=np.floating)
np.sin(x) # 每个元素求正弦
np.cos(x) # 每个元素求余弦
np.round(np.cos(x)) # 先求余弦再四舍五入
np.ceil(x/2) # 每个元素除以2后向上取整
比喻:就像你有一筐苹果,NumPy帮你一次性全部削好皮,而不是一个一个削。
2.2 布尔运算(条件筛选)
大白话:用一个条件去"过滤"数组,只留下你想要的那些元素。
python
x = np.random.rand(10) # 10个随机数
# 数组与常量比较(返回True/False数组)
x > 0.5 # 每个元素判断是否大于0.5
# 用布尔数组做索引(取出满足条件的元素)
x[x > 0.5] # 只保留大于0.5的元素
# 组合条件(必须用 & 和 |,不能用 and 和 or)
sum((x > 0.4) & (x < 0.6)) # 大于0.4且小于0.6的元素个数
# True=1, False=0,sum求和就是计数
# 整体判断
np.all(x < 1) # 所有元素都小于1?
np.any(x > 0.8) # 存在大于0.8的元素?
# 两个数组逐个比较
a = np.array([1, 2, 3])
b = np.array([3, 2, 1])
a > b # [False, False, True]
a[a > b] # 取出a中大于b对应位置的元素 → [3]
a[a == b] # 取出a中等于b对应位置的元素 → [2]
# 多条件筛选
x = np.arange(1, 10)
x[(x % 2 == 0) & (x > 5)] # 大于5的偶数
x[(x % 2 == 0) | (x > 5)] # 大于5或者是偶数
关键提醒 :组合条件时用 & 和 |(位运算符),不是 and 和 or。每个条件必须用括号括起来。
2.3 分段函数
大白话:根据条件把数据分成几类,每类做不同的处理。
python
x = np.random.randint(0, 10, size=(1, 10))
# np.where():二分类(像Excel的IF函数)
np.where(x < 5, 0, 1) # 小于5→0,大于等于5→1
# np.piecewise():多分类(像Excel的多层IF嵌套)
np.piecewise(x, [x < 4, x > 7], [lambda n: n**2, lambda n: n*3])
# 小于4 → 求平方
# 大于7 → 乘以3
# 其他所有元素 → 变成0
np.piecewise(x, [x < 3, (3 < x) & (x < 5), x > 7], [-1, 1, lambda n: n*4])
# 小于3 → -1
# 大于3且小于5 → 1
# 大于7 → 乘以4
# 其他 → 0
piecewise()参数解析:
- 第1个参数:要操作的数组
- 第2个参数:条件列表
[条件1, 条件2, ...] - 第3个参数:处理列表
[处理1, 处理2, ...],可以是具体值或lambda函数 - 条件没有覆盖到的元素自动变为0
比喻 :就像快递分拣------小件放A区,大件放B区,不符合条件的直接退回。np.where是两分类,np.piecewise是多分类。
第3天(6月23日):矩阵运算与线性代数
3.1 数组与矩阵的区别
| 特性 | 数组(ndarray) | 矩阵(matrix) |
|---|---|---|
| 维度 | 可以是一维、二维、三维或更高 | 只能是二维 |
| 数据类型 | 可包含数字、字符串等 | 只能包含数字 |
python
x = np.matrix([[1,2,3], [4,5,6]]) # 创建矩阵
比喻:数组是瑞士军刀(什么都能装),矩阵是专门的数字表格(只能装数字,只有行和列)。
3.2 矩阵转置
大白话 :把矩阵的行变成列,列变成行,就像把表格旋转90度。
python
x = np.matrix([[1,2,3], [4,5,6]])
# [[1,2,3],
# [4,5,6]]
print(x.T)
# [[1,4],
# [2,5],
# [3,6]]
3.3 矩阵的统计操作
python
x = np.matrix([[1,2,3], [4,5,6]])
x.mean() # 所有元素的平均值 = 3.5
x.mean(axis=0) # 纵向平均值(按列算) → [2.5, 3.5, 4.5]
x.mean(axis=1) # 横向平均值(按行算) → [2.0, 5.0]
x.sum() # 所有元素的和 = 21
x.max(axis=0) # 纵向最大值
x.max(axis=1) # 横向最大值
x.argmax(axis=0) # 纵向最大值的下标
x.diagonal() # 对角线元素
x.nonzero() # 非0元素的下标
axis记忆法:有一张学生成绩表,每行是一个学生,每列是一个科目。
axis=0(纵向):按列计算 → 每个科目的全班平均分axis=1(横向):按行计算 → 每个学生的个人平均分
3.4 相关系数(衡量两个人走路方向是否一致)
大白话:相关系数衡量两个变量变化方向的关系。
- 接近 1:你涨我也涨(正相关)
- 接近 -1:你涨我跌(负相关)
- 接近 0:你走你的我走我的(无关)
python
# 正相关:变化方向一致
np.corrcoef([1,2,3,4], [1,2,3,4]) # → 接近1
# 负相关:变化方向相反
np.corrcoef([1,2,3,4], [4,3,2,1]) # → 接近-1
# 正相关但幅度不同
np.corrcoef([1,2,3,4], [1,2,3,40]) # → 仍接近1
3.5 方差和标准差(衡量一群人是不是整齐)
大白话:衡量数据离散程度的指标。
- 方差/标准差小:大家都差不多,队伍整齐
- 方差/标准差大:有人很高有人很矮,参差不齐
python
np.cov([1,1,1,1,1]) # 都一样 → 方差为0
np.cov([1,5,3,8,2]) # 有高有低 → 方差较大
np.std([1,1,1,1]) # 标准差也是0
标准差和方差的区别:标准差是方差的平方根,标准差的单位与原始数据一致,更好理解。
3.6 协方差(衡量两个人走路是否同步)
大白话:协方差衡量两个变量的变化是否同步。
- 大于0:你往前走我也往前走(同步)
- 小于0:你往前走我往后退(反向)
- 接近0:各走各的互不影响
python
x = [1, 2, 3, 4, 5]
y = [2, 4, 6, 8, 10] # y一直是x的两倍
np.cov(x, y) # 正数,说明同步变化
协方差 vs 相关系数:相关系数是"标准化的协方差",数值始终在-1到1之间,只看方向不看幅度。
3.7 特征值与特征向量
大白话 :矩阵乘以一个向量 = 对这个向量做变换(旋转+缩放)。大多数向量会改变方向,但有些特殊向量只改变长度不改变方向。
- 特征向量:这些方向不变的特殊向量
- 特征值:这个向量变长/变短了多少倍
python
A = np.array([[1, -3, 3], [3, -5, 3], [6, -6, 4]])
e, v = np.linalg.eig(A) # e是特征值,v是特征向量
np.dot(A, v) # 矩阵 × 特征向量
e * v # 特征值 × 特征向量
np.isclose(np.dot(A, v), e*v) # 验证二者相等
# 行列式|A-λE|的值应为0
np.linalg.det(A - np.eye(3,3) * e)
比喻:就像照哈哈镜。大部分东西照出来都变形了,但有一条直线照出来还是直的,只是变长了------这条线就是特征向量,变长的倍数就是特征值。
你现在只需要知道 :np.linalg.eig() 是计算特征值和特征向量的工具。不需要手算,NumPy会帮你完成。
3.8 逆矩阵
大白话:逆矩阵就是矩阵的"倒数"。
- 数字的倒数:3 × (1/3) = 1
- 矩阵的逆:A × A⁻¹ = 单位矩阵(相当于数字1)
python
x = np.matrix([[1,2,3],[4,5,6],[7,8,0]])
y = np.linalg.inv(x) # 计算逆矩阵
x * y # 验证:矩阵 × 它的逆 = 单位矩阵
3.9 解线性方程组
大白话:一步解出方程组的答案。
比如:
3x + y = 9
x + 2y = 8
python
a = np.array([[3, 1], [1, 2]]) # 系数矩阵
b = np.array([9, 8]) # 等号右边的值
x = np.linalg.solve(a, b) # 求解 → [2, 3]
np.dot(a, x) # 验证:结果应该等于b → [9, 8]
# 最小二乘解(方程个数多于未知数个数时)
np.linalg.lstsq(a, b)
3.10 奇异值分解(SVD)
大白话:把一个矩阵拆成三个部分,这三个部分乘起来能还原原来的矩阵。
python
a = np.matrix([[1,2,3],[4,5,6],[7,8,9]])
u, s, v = np.linalg.svd(a) # 奇异值分解
# 验证:u × 对角矩阵(s) × v 应该等于原矩阵
u * np.diag(s) * v # 还原
你只需要知道 :SVD用于数据压缩、降维、推荐系统等场景。np.linalg.svd() 就是做这件事的函数。
三天学习总结
| 天数 | 核心内容 | 一句话概括 |
|---|---|---|
| 第1天(6.18) | 数组创建、运算、筛选、形状变换 | 把列表变成能快速计算的数组,还能随便变形和筛选 |
| 第2天(6.22) | 函数运算、布尔筛选、分段函数 | 一次性对所有数据做数学运算,按条件分类处理 |
| 第3天(6.23) | 矩阵运算、统计、线性代数 | 用矩阵处理数字表格,计算统计指标,解方程 |
最重要的心态:
- 你不需要推导公式,只需要知道哪个函数干什么用
- 数学概念用比喻理解就够了,工作中没人让你手算特征值
- NumPy是工具箱,你现在在认识每个工具的用途,而不是学怎么造工具
- 函数忘了就查,开发时没人要求你全部背下来
注:已经使用DeepSeek进行整理精简核心内容,些许不理解的配合个人笔记进行理解。