# 转型之路_第7篇_Python数据分析三件套
*摘要:* 本文是《转型之路》系列第7篇,为Java工程师量身打造Python数据分析三件套(NumPy、Pandas、Matplotlib)入门指南。文章从第一性原理出发,剖析数据分析在AI领域中的核心地位,并通过大量可运行的代码示例,系统讲解NumPy高性能数组运算、Pandas表格数据处理(SQL对照)与Matplotlib数据可视化技巧。内容涵盖数据清洗实战、端到端分析流程及常见性能优化方案,旨在帮助转型者快速建立AI数据处理的完整知识框架与实操能力。*
# 转型之路_第7篇_Python数据分析三件套
# Python数据分析三件套:NumPy/Pandas/Matplotlib入门
转型之路系列第7篇 | 上一篇:[Java转Python速成指南](/java-to-python-crash-course/) | 下一篇:[AI数学基础(上):线性代数](/ai-math-linear-algebra/)
## 📋 目录
1. 第一性原理:为什么数据分析是AI的地基
2. NumPy:高性能计算的引擎
3. Pandas:Python版SQL
4. Matplotlib:数据可视化利器
5. 三件套协同实战:端到端数据分析
6. 常见问题与技巧
7. 总结与下一步
—
## 一、第一性原理:为什么数据分析是AI的地基
在开始动手写代码之前,我们不妨先退一步思考:为什么数据分析能力如此重要?
**基本事实1**:AI的本质是从数据中学习规律。没有数据,再精妙的模型也只是空中楼阁。
**基本事实2**:真实世界的数据90%是”脏”的——存在缺失值、异常值、格式不统一等问题。AI模型再厉害,喂进去垃圾数据,出来的也是垃圾(Garbage In, Garbage Out)。
**基本事实3**:数据分析和处理占AI项目60%以上的工作量,而模型选择和调优仅占10%。
**结论**:数据分析能力是AI工程师的基本功,就像SQL是Java工程师的基本功一样。三件套(NumPy+Pandas+Matplotlib)就是AI领域的数据处理”铁三角”。
**三件套的分工**:
“`
NumPy → 底层计算引擎(高性能数组/矩阵运算)
Pandas → 数据处理框架(表操作,类似SQL)
Matplotlib → 数据可视化(画图表)
关系:Pandas底层用NumPy,Matplotlib读取Pandas数据画图
“`
—
## 二、NumPy:高性能计算的引擎
### 2.1 为什么NumPy比原生Python快?
**通俗解释**:Python列表像一个装了各种东西的袋子,每个元素可以是不同类型;NumPy数组像一个整齐排列的格子,所有元素类型相同。整齐排列 = 内存连续 = CPU缓存命中率高 = 快10-100倍。
“`python
“””
NumPy性能对比:直观感受快多少
安装:pip install numpy
“””
import numpy as np
import time
# 100万个数字求和
size = 1_000_000
# Python原生列表
py_list = list(range(size))
start = time.time()
total = sum(py_list)
py_time = time.time() – start
# NumPy数组
np_arr = np.arange(size)
start = time.time()
total = np_arr.sum()
np_time = time.time() – start
print(f”Python列表: {py_time*1000:.1f}ms”)
print(f”NumPy数组: {np_time*1000:.1f}ms”)
print(f”NumPy快了: {py_time/np_time:.0f}倍”)
“`
### 2.2 NumPy核心操作
“`python
“””
NumPy核心操作速查
这是你做AI最常用的NumPy代码
“””
import numpy as np
# ========== 1. 创建数组 ==========
# 从列表创建
arr = np.array([1, 2, 3, 4, 5])
# 创建特殊数组
zeros = np.zeros(5) # [0. 0. 0. 0. 0.]
ones = np.ones((3, 4)) # 3行4列全1矩阵
range_arr = np.arange(0, 10, 2) # [0 2 4 6 8]
linspace = np.linspace(0, 1, 5) # [0. 0.25 0.5 0.75 1.]
random_arr = np.random.randn(3, 3) # 3×3标准正态分布随机数
# ========== 2. 数组属性 ==========
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr.shape) # (2, 3) ← 2行3列,类似Java的arr.length
print(arr.ndim) # 2 ← 维度
print(arr.dtype) # int64 ← 数据类型
print(arr.size) # 6 ← 元素总数
# ========== 3. 索引和切片 ==========
arr = np.array([10, 20, 30, 40, 50])
print(arr[0]) # 10
print(arr[-1]) # 50
print(arr[1:4]) # [20 30 40]
print(arr[::2]) # [10 30 50] 每隔1个
# 二维数组索引
matrix = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(matrix[0, 1]) # 2 ← 第0行第1列
print(matrix[1, :]) # [4 5 6] ← 第1行全部
print(matrix[:, 1]) # [2 5 8] ← 第1列全部
print(matrix[0:2, 1:3]) # [[2 3], [5 6]] ← 子矩阵
# 布尔索引(Java没有,非常强大)
arr = np.array([10, 20, 30, 40, 50])
mask = arr > 25
print(arr[mask]) # [30 40 50] ← 筛选大于25的元素
# ========== 4. 数学运算 ==========
a = np.array([1, 2, 3, 4])
b = np.array([10, 20, 30, 40])
# 逐元素运算(不需要for循环!)
print(a + b) # [11 22 33 40]
print(a * b) # [10 40 90 160]
print(a ** 2) # [1 4 9 16]
print(np.sqrt(a)) # [1. 1.414 1.732 2.]
# 聚合运算
print(a.sum()) # 10
print(a.mean()) # 2.5
print(a.std()) # 1.118
print(a.max()) # 4
print(a.argmax()) # 3 ← 最大值的索引
# ========== 5. 矩阵运算 ==========
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
# 矩阵乘法(AI最核心的运算)
print(A @ B) # [[19 22], [43 50]]
print(np.dot(A, B)) # 同上
# 转置
print(A.T) # [[1 3], [2 4]]
# 逆矩阵
print(np.linalg.inv(A)) # [[-2. 1.], [1.5 -0.5]]
# ========== 6. 广播机制 ==========
# NumPy最强大的特性:不同形状的数组也能运算
# 类比:SQL里一个标量可以和整列运算
# 标量和数组
arr = np.array([1, 2, 3])
print(arr * 10) # [10 20 30] ← 10自动”广播”到每个元素
# 不同形状的数组
matrix = np.array([[1, 2, 3], # 2×3
[4, 5, 6]])
row = np.array([10, 20, 30]) # 1×3
print(matrix + row) # [[11 22 33], [14 25 36]]
# row自动”广播”到每一行,和Java的循环效果一样但不用写循环
“`
### 2.3 可运行练习:用NumPy实现线性回归
“`python
“””
用NumPy从零实现线性回归(不用任何ML库)
这是理解AI模型训练原理的最佳练习
安装:pip install numpy matplotlib
“””
import numpy as np
import matplotlib.pyplot as plt
# 1. 生成模拟数据
np.random.seed(42)
X = 2 * np.random.rand(100) # 100个0-2之间的随机数
y = 4 + 3 * X + np.random.randn(100) * 0.5 # y = 4 + 3x + 噪声
# 2. 用正规方程求解(一步到位的数学方法)
X_b = np.c_[np.ones(100), X] # 加一列1,用于计算截距
theta_exact = np.linalg.inv(X_b.T @ X_b) @ X_b.T @ y
print(f”正规方程结果: 截距={theta_exact[0]:.2f}, 斜率={theta_exact[1]:.2f}”)
# 输出约: 截距=4.02, 斜率=2.98(接近真实值4和3)
# 3. 用梯度下降求解(AI训练的通用方法)
theta = np.random.randn(2) # 随机初始化参数
learning_rate = 0.1
n_iterations = 1000
for i in range(n_iterations):
predictions = X_b @ theta # 预测
errors = predictions – y # 误差
gradients = (2/100) * X_b.T @ errors # 梯度
theta -= learning_rate * gradients # 更新参数
print(f”梯度下降结果: 截距={theta[0]:.2f}, 斜率={theta[1]:.2f}”)
# 4. 可视化
plt.figure(figsize=(8, 5))
plt.scatter(X, y, alpha=0.5, label=”数据点”)
plt.plot(X, theta[0] + theta[1]*X, “r-“, linewidth=2, label=”拟合线”)
plt.xlabel(“X”)
plt.ylabel(“y”)
plt.legend()
plt.title(“NumPy实现线性回归”)
plt.savefig(“linear_regression.png”, dpi=150)
print(“图表已保存”)
“`
—
## 三、Pandas:Python版SQL
### 3.1 DataFrame:你的数据表
**通俗解释**:DataFrame就是一张数据库表,有行有列,有列名有索引。你会SQL就会Pandas。
“`python
“””
Pandas核心操作:会SQL就会Pandas
安装:pip install pandas
“””
import pandas as pd
import numpy as np
# ========== 1. 创建DataFrame ==========
df = pd.DataFrame({
“name”: [“张三”, “李四”, “王五”, “赵六”, “钱七”],
“department”: [“技术”, “产品”, “技术”, “运营”, “技术”],
“salary”: [25000, 28000, 22000, 20000, 35000],
“years”: [5, 7, 3, 2, 10],
“level”: [“中级”, “高级”, “初级”, “初级”, “专家”]
})
# 查看基本信息
print(df.head(3)) # 前3行(类似SQL的LIMIT 3)
print(df.shape) # (5, 5) 行数和列数
print(df.dtypes) # 每列的数据类型
print(df.describe()) # 数值列的统计摘要
“`
### 3.2 SQL vs Pandas完整对照
“`python
# ========== 2. 查询(SELECT)==========
# SQL: SELECT * FROM employees
df
# SQL: SELECT name, salary FROM employees
df[[“name”, “salary”]]
# ========== 3. 过滤(WHERE)==========
# SQL: SELECT * FROM employees WHERE department = ‘技术’
df[df[“department”] == “技术”]
# SQL: SELECT * FROM employees WHERE salary > 25000 AND years >= 5
df[(df[“salary”] > 25000) & (df[“years”] >= 5)]
# SQL: SELECT * FROM employees WHERE department IN (‘技术’, ‘产品’)
df[df[“department”].isin([“技术”, “产品”])]
# SQL: SELECT * FROM employees WHERE name LIKE ‘%三’
df[df[“name”].str.endswith(“三”)]
# ========== 4. 排序(ORDER BY)==========
# SQL: SELECT * FROM employees ORDER BY salary DESC
df.sort_values(“salary”, ascending=False)
# SQL: SELECT * FROM employees ORDER BY department, salary DESC
df.sort_values([“department”, “salary”], ascending=[True, False])
# ========== 5. 聚合(GROUP BY)==========
# SQL: SELECT department, COUNT(*), AVG(salary) FROM employees GROUP BY department
df.groupby(“department”).agg(
count=(“name”, “count”),
avg_salary=(“salary”, “mean”),
max_salary=(“salary”, “max”)
)
# SQL: SELECT department, level, AVG(salary) FROM employees GROUP BY department, level
df.groupby([“department”, “level”])[“salary”].mean()
# ========== 6. 新增列(ALTER + UPDATE)==========
# SQL: UPDATE employees SET annual_salary = salary * 12
df[“annual_salary”] = df[“salary”] * 12
# 条件更新
# SQL: CASE WHEN years >= 5 THEN ‘资深’ ELSE ‘新人’ END
df[“category”] = np.where(df[“years”] >= 5, “资深”, “新人”)
# ========== 7. JOIN ==========
depts = pd.DataFrame({
“department”: [“技术”, “产品”, “运营”, “财务”],
“dept_head”: [“陈总”, “刘总”, “孙总”, “周总”],
“budget”: [500000, 300000, 200000, 150000]
})
# SQL: SELECT * FROM employees e INNER JOIN departments d ON e.department = d.department
pd.merge(df, depts, on=”department”, how=”inner”)
# LEFT JOIN
pd.merge(df, depts, on=”department”, how=”left”)
# ========== 8. 窗口函数 ==========
# SQL: ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC)
df[“salary_rank”] = df.groupby(“department”)[“salary”].rank(ascending=False, method=”dense”)
# SQL: LAG(salary) OVER (ORDER BY years)
df[“prev_salary”] = df.sort_values(“years”)[“salary”].shift(1)
“`
### 3.3 数据清洗实战
“`python
“””
数据清洗:AI项目中60%的工作量
这里展示最常见的5种数据清洗操作
安装:pip install pandas
“””
import pandas as pd
import numpy as np
# 创建有”脏数据”的示例
df = pd.DataFrame({
“name”: [“张三”, “李四”, “王五”, np.nan, “赵六”, “张三”],
“age”: [30, 25, np.nan, 35, -5, 30],
“salary”: [25000, 28000, np.nan, 20000, 22000, 25000],
“join_date”: [“2020-01-15”, “2021/03/20”, “2019-12-01”, “invalid”, “2022-06-30”, “2020-01-15”],
“department”: [“技术”, “产品”, “技术”, “运营”, “技术”, “技术”]
})
print(“原始数据:”)
print(df)
# 1. 处理缺失值
# 策略1:删除缺失行
df_clean = df.dropna(subset=[“name”]) # 只删name为空的行
# 策略2:填充缺失值(更常用)
df[“age”] = df[“age”].fillna(df[“age”].median()) # 用中位数填充
df[“salary”] = df[“salary”].fillna(df[“salary”].mean()) # 用均值填充
# 2. 处理异常值
# age不能为负数
df.loc[df[“age”] < 0, "age"] = df["age"].median()
# 3. 统一日期格式
df["join_date"] = pd.to_datetime(df["join_date"], errors="coerce")
# errors="coerce"表示解析失败时设为NaT(缺失时间),而不是报错
# 4. 删除重复行
df = df.drop_duplicates()
# 5. 标准化文本(去除空格、统一大小写)
df["name"] = df["name"].str.strip() # 去除首尾空格
print("\n清洗后数据:")
print(df)
```
---
## 四、Matplotlib:数据可视化利器
### 4.1 5种最常用的图表
```python
"""
Matplotlib 5种核心图表:覆盖80%可视化场景
安装:pip install matplotlib
"""
import matplotlib.pyplot as plt
import numpy as np
# 设置中文字体(防止乱码)
plt.rcParams["font.sans-serif"] = ["SimHei"] # Windows
# plt.rcParams["font.sans-serif"] = ["Arial Unicode MS"] # Mac
plt.rcParams["axes.unicode_minus"] = False # 解决负号显示问题
# 准备数据
x = np.arange(1, 13) # 1-12月
sales = np.array([120, 135, 110, 150, 165, 180, 175, 160, 190, 210, 230, 250])
target = np.full(12, 180) # 目标线
# 图1: 折线图(趋势分析)
plt.figure(figsize=(10, 6))
plt.plot(x, sales, "b-o", linewidth=2, markersize=6, label="实际销售")
plt.plot(x, target, "r--", linewidth=2, label="目标")
plt.fill_between(x, sales, target, alpha=0.2, color="gray")
plt.xlabel("月份")
plt.ylabel("销售额(万元)")
plt.title("2024年销售趋势")
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("line_chart.png", dpi=150)
# 图2: 柱状图(对比分析)
categories = ["技术", "产品", "运营", "市场"]
values = [150, 120, 80, 100]
colors = ["#4472C4", "#ED7D31", "#A5A5A5", "#FFC000"]
plt.figure(figsize=(8, 5))
bars = plt.bar(categories, values, color=colors, width=0.6)
# 在柱子上显示数值
for bar, val in zip(bars, values):
plt.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 2,
f"{val}", ha="center", va="bottom", fontsize=12)
plt.ylabel("人数")
plt.title("各部门人员分布")
plt.tight_layout()
plt.savefig("bar_chart.png", dpi=150)
# 图3: 散点图(相关性分析)
np.random.seed(42)
x = np.random.randn(200) * 2
y = 2 * x + np.random.randn(200)
plt.figure(figsize=(8, 5))
plt.scatter(x, y, alpha=0.6, s=30, c="steelblue", edgecolors="white")
# 添加趋势线
z = np.polyfit(x, y, 1)
p = np.poly1d(z)
plt.plot(x, p(x), "r--", linewidth=2, label=f"y = {z[0]:.2f}x + {z[1]:.2f}")
plt.xlabel("广告投入")
plt.ylabel("销售额")
plt.title("广告投入与销售额关系")
plt.legend()
plt.tight_layout()
plt.savefig("scatter_chart.png", dpi=150)
# 图4: 饼图(占比分析)
sizes = [35, 25, 20, 15, 5]
labels = ["技术", "产品", "运营", "市场", "其他"]
colors = ["#4472C4", "#ED7D31", "#A5A5A5", "#FFC000", "#70AD47"]
explode = (0.05, 0, 0, 0, 0) # 突出第一个扇区
plt.figure(figsize=(8, 8))
plt.pie(sizes, explode=explode, labels=labels, colors=colors,
autopct="%1.1f%%", shadow=True, startangle=90)
plt.title("各部门营收占比")
plt.tight_layout()
plt.savefig("pie_chart.png", dpi=150)
# 图5: 直方图(分布分析)
np.random.seed(42)
data = np.random.randn(1000) * 20 + 100
plt.figure(figsize=(8, 5))
plt.hist(data, bins=30, color="#4472C4", edgecolor="white", alpha=0.8)
plt.axvline(data.mean(), color="red", linestyle="--", linewidth=2,
label=f"均值={data.mean():.1f}")
plt.xlabel("数值")
plt.ylabel("频次")
plt.title("数据分布直方图")
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("histogram_chart.png", dpi=150)
print("5张图表已保存完毕!")
```
---
## 五、三件套协同实战:端到端数据分析
**实战场景**:某电商平台需要分析2024年销售数据,找出增长趋势和优化方向。
```python
"""
三件套协同作战:从数据到决策的完整流程
安装:pip install pandas numpy matplotlib
"""
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 设置中文字体
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
# ========== Step 1: 数据准备(Pandas)==========
np.random.seed(42)
dates = pd.date_range("2024-01-01", "2024-12-31", freq="D")
# 模拟销售数据
df = pd.DataFrame({
"date": dates,
"revenue": np.random.normal(50000, 8000, len(dates)),
"units": np.random.randint(50, 200, len(dates)),
"product": np.random.choice(["手机", "电脑", "平板", "耳机"], len(dates)),
"region": np.random.choice(["华东", "华南", "华北", "西部"], len(dates)),
"channel": np.random.choice(["线上", "线下"], len(dates))
})
# 加入趋势和季节性
df["revenue"] += np.linspace(0, 20000, len(dates)) # 增长趋势
df["revenue"] += 5000 * np.sin(np.arange(len(dates)) * 2 * np.pi / 30) # 月度周期
print(f"数据规模: {df.shape[0]}行 × {df.shape[1]}列")
# ========== Step 2: 数据清洗(Pandas)==========
# 检查缺失值
print(f"缺失值: {df.isnull().sum().sum()}")
# 处理异常值(用IQR方法)
Q1 = df["revenue"].quantile(0.25)
Q3 = df["revenue"].quantile(0.75)
IQR = Q3 - Q1
outliers = df[(df["revenue"] < Q1 - 1.5*IQR) | (df["revenue"] > Q3 + 1.5*IQR)]
print(f”异常值: {len(outliers)} 条 ({len(outliers)/len(df):.1%})”)
# ========== Step 3: 分析(Pandas + NumPy)==========
# 月度趋势
monthly = df.set_index(“date”).resample(“M”).agg(
总营收=(“revenue”, “sum”),
订单数=(“units”, “sum”),
客单价=(“revenue”, “mean”)
)
# 环比增长
monthly[“环比增长”] = monthly[“总营收”].pct_change() * 100
# 渠道对比
channel_stats = df.groupby(“channel”).agg(
营收=(“revenue”, “sum”),
占比=(“revenue”, lambda x: x.sum() / df[“revenue”].sum())
).round(4)
print(f”\n===== 渠道分析 =====”)
print(channel_stats)
# ========== Step 4: 可视化(Matplotlib)==========
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# 图1: 月度营收趋势
axes[0, 0].plot(monthly.index, monthly[“总营收”]/10000, “b-o”, linewidth=2)
axes[0, 0].set_title(“月度营收趋势”)
axes[0, 0].set_ylabel(“营收(万元)”)
axes[0, 0].grid(True, alpha=0.3)
# 图2: 渠道占比
channel_rev = df.groupby(“channel”)[“revenue”].sum()
axes[0, 1].pie(channel_rev, labels=channel_rev.index, autopct=”%1.1f%%”,
colors=[“#4472C4”, “#ED7D31”])
axes[0, 1].set_title(“渠道营收占比”)
# 图3: 产品×区域热力图
pivot = df.pivot_table(values=”revenue”, index=”region”, columns=”product”, aggfunc=”sum”)
im = axes[1, 0].imshow(pivot.values / 10000, cmap=”YlOrRd”)
axes[1, 0].set_xticks(range(len(pivot.columns)))
axes[1, 0].set_xticklabels(pivot.columns)
axes[1, 0].set_yticks(range(len(pivot.index)))
axes[1, 0].set_yticklabels(pivot.index)
axes[1, 0].set_title(“产品×区域营收热力图(万元)”)
plt.colorbar(im, ax=axes[1, 0])
# 图4: 日营收分布
axes[1, 1].hist(df[“revenue”], bins=50, color=”#4472C4″, edgecolor=”white”, alpha=0.8)
axes[1, 1].axvline(x=df[“revenue”].mean(), color=”red”, linestyle=”–“,
label=f”均值={df[‘revenue’].mean():.0f}”)
axes[1, 1].set_title(“日营收分布”)
axes[1, 1].legend()
plt.tight_layout()
plt.savefig(“sales_analysis.png”, dpi=150, bbox_inches=”tight”)
print(“\n分析报告已保存为 sales_analysis.png”)
“`
—
## 六、常见问题与技巧
### Q1:Pandas操作太慢怎么办?
“`python
# 方法1:指定数据类型(减少内存)
df = pd.read_csv(“data.csv”, dtype={“id”: “int32”, “name”: “category”})
# 方法2:只读需要的列
df = pd.read_csv(“data.csv”, usecols=[“id”, “name”, “amount”])
# 方法3:分块读取大文件
for chunk in pd.read_csv(“big_data.csv”, chunksize=10000):
process(chunk) # 每次只读1万行
“`
### Q2:NumPy和Pandas怎么选?
| 场景 | 选NumPy | 选Pandas |
|——|———|———-|
| 纯数值计算 | ✅ | |
| 矩阵运算 | ✅ | |
| 表格数据处理 | | ✅ |
| SQL式查询 | | ✅ |
| AI模型输入 | ✅ | |
| 数据清洗 | | ✅ |
### Q3:中文显示为方块怎么办?
“`python
# Windows
plt.rcParams[“font.sans-serif”] = [“SimHei”]
# Mac
plt.rcParams[“font.sans-serif”] = [“Arial Unicode MS”]
# Linux(需要先安装字体)
plt.rcParams[“font.sans-serif”] = [“WenQuanYi Micro Hei”]
“`
—
## 七、总结与下一步
### 核心要点
1. **NumPy是计算引擎**:高性能数组操作、矩阵运算,是所有AI库的底层
2. **Pandas是数据处理框架**:会SQL就会Pandas,覆盖90%的数据处理需求
3. **Matplotlib是可视化工具**:5种图表(折线、柱状、散点、饼图、直方图)覆盖80%场景
4. **三件套协同使用**:Pandas处理数据 → NumPy做计算 → Matplotlib画图
### SQL vs Pandas速查
| 操作 | SQL | Pandas |
|——|—–|——–|
| 查询 | SELECT | df[cols] |
| 过滤 | WHERE | df[cond] |
| 排序 | ORDER BY | sort_values() |
| 分组 | GROUP BY | groupby() |
| 连接 | JOIN | merge() |
| 窗口 | OVER() | rank()/shift() |
### 下一步
第8篇将进入AI数学基础,先从**线性代数**开始——只学AI需要的,用代码理解。
– 第8篇:AI必学的数学基础(上):线性代数快速入门
—
📍 **转型之路系列导航**:
上一篇:[Java转Python速成指南](/java-to-python-crash-course/) | 下一篇:[AI数学基础:线性代数](/ai-math-linear-algebra/) | 系列目录:[转型之路-Java软件工程师转AI](/java-to-ai-series/)