mirror of
https://github.com/Visualize-ML/Book4_Power-of-Matrix.git
synced 2026-05-05 16:00:32 +08:00
Add files via upload
This commit is contained in:
committed by
GitHub
parent
79be5dda7d
commit
5adb9e44a7
242
Book4_Ch14_Python_Codes/Bk4_Ch14_01.ipynb
Normal file
242
Book4_Ch14_Python_Codes/Bk4_Ch14_01.ipynb
Normal file
@@ -0,0 +1,242 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "73bd968b-d970-4a05-94ef-4e7abf990827",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Chapter 14\n",
|
||||
"\n",
|
||||
"# 矩阵平方根\n",
|
||||
"Book_4《矩阵力量》 | 鸢尾花书:从加减乘除到机器学习 (第二版)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c263fc95-881a-49fb-9c6c-a25508996623",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"该代码的主要任务是通过矩阵分解和重构方法,基于给定的矩阵$A$,验证矩阵重构的正确性。具体流程如下:\n",
|
||||
"\n",
|
||||
"1. **定义矩阵$A$**: \n",
|
||||
" 代码首先创建了一个$2 \\times 2$矩阵 $A = \\begin{bmatrix} 1.25 & -0.75 \\\\ -0.75 & 1.25 \\end{bmatrix}$。矩阵 $A$ 是一个对称矩阵,因此可以进行特征值分解。\n",
|
||||
"\n",
|
||||
"2. **计算特征值和特征向量**: \n",
|
||||
" 代码使用 `np.linalg.eig` 函数对矩阵 $A$ 进行特征值分解,计算出$A$的特征值(存储在 $LAMBDA$ 中)和特征向量(存储在 $V$ 中),满足以下分解公式:\n",
|
||||
" $$\n",
|
||||
" A = V \\Lambda V^{-1}\n",
|
||||
" $$\n",
|
||||
" 其中,$\\Lambda$ 是一个包含特征值的对角矩阵,$V$ 是由特征向量组成的矩阵。\n",
|
||||
"\n",
|
||||
"3. **构建矩阵$B$**: \n",
|
||||
" 接下来,代码构建了一个新的矩阵 $B$。它的计算公式为:\n",
|
||||
" $$\n",
|
||||
" B = V \\sqrt{\\Lambda} V^{-1}\n",
|
||||
" $$\n",
|
||||
" 其中,$\\sqrt{\\Lambda}$ 是对角矩阵,其对角元素是 $\\Lambda$ 的平方根。也就是说,$B$ 是通过将 $A$ 的特征值取平方根后重新组合得到的矩阵。\n",
|
||||
"\n",
|
||||
"4. **重构矩阵$A$并验证结果**: \n",
|
||||
" 最后,通过矩阵 $B$ 构造了一个新矩阵 $A_{reproduced}$,其计算公式为:\n",
|
||||
" $$\n",
|
||||
" A_{reproduced} = B B^T\n",
|
||||
" $$\n",
|
||||
" 这是利用矩阵 $B$ 重构 $A$ 的过程。对称矩阵 $A$ 的特征值平方根分解使得 $B B^T$ 应等于原始矩阵 $A$。因此,通过打印 $A_{reproduced}$,可以验证 $B B^T$ 是否等于 $A$,从而确认重构的正确性。"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "2759881c-9e2a-4e4d-a79c-1617f2a4be4f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np # 导入NumPy库"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a685835a-bcda-40f8-ac57-ff3738c0209f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 初始化矩阵A"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "a6e9a15c-1d77-4a95-a13c-1c825598e8be",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"A = np.matrix([[1.25, -0.75], # 定义矩阵A\n",
|
||||
" [-0.75, 1.25]]) # 矩阵的元素"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "55297e89-757e-4136-a0af-4763d1db3e56",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 计算特征值和特征向量"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "998fa920-5e90-408f-8b70-dd3633c870e9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"LAMBDA, V = np.linalg.eig(A) # 计算矩阵A的特征值(LAMBDA)和特征向量(V)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "ce8e4f8c-19a0-4392-b1ef-e794dcc5f187",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"array([2. , 0.5])"
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"LAMBDA"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "13196da8-54c0-44bb-ac29-6cf7c6fec408",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"matrix([[ 0.70710678, 0.70710678],\n",
|
||||
" [-0.70710678, 0.70710678]])"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"V"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c6bb1a72-57de-4ae9-a2e2-599db3122538",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 构建矩阵B"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "cb92d4fe-8443-473f-a61c-378630468024",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"B = V @ np.diag(np.sqrt(LAMBDA)) @ np.linalg.inv(V) # 根据特征值和特征向量构建矩阵B"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "da0f2576-d262-41cd-8324-208cf3df1c82",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"matrix([[ 1.06066017, -0.35355339],\n",
|
||||
" [-0.35355339, 1.06066017]])"
|
||||
]
|
||||
},
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"B"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d70a4893-0524-47aa-91ad-4ad9863a5c89",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 重构矩阵A并打印"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "d07c6472-787a-44c2-9d20-99e4d070826a",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"[[ 1.25 -0.75]\n",
|
||||
" [-0.75 1.25]]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"A_reproduced = B @ B.T # 通过矩阵B的转置乘积重构矩阵A\n",
|
||||
"print(A_reproduced) # 输出重构后的矩阵A"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "85a80909-2aac-49ed-bb7a-f8cc6b80ee7d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ecd322f4-f919-4be2-adc3-69d28ef25e69",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.12.7"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
263
Book4_Ch14_Python_Codes/Bk4_Ch14_02.ipynb
Normal file
263
Book4_Ch14_Python_Codes/Bk4_Ch14_02.ipynb
Normal file
File diff suppressed because one or more lines are too long
54
Book4_Ch14_Python_Codes/Streamlit_Bk4_Ch14_02.py
Normal file
54
Book4_Ch14_Python_Codes/Streamlit_Bk4_Ch14_02.py
Normal file
@@ -0,0 +1,54 @@
|
||||
|
||||
###############
|
||||
# Authored by Weisheng Jiang
|
||||
# Book 4 | From Basic Arithmetic to Machine Learning
|
||||
# Published and copyrighted by Tsinghua University Press
|
||||
# Beijing, China, 2025
|
||||
###############
|
||||
|
||||
import numpy as np # 导入NumPy库,用于数值计算
|
||||
import streamlit as st # 导入Streamlit库,用于创建交互式Web应用
|
||||
import time # 导入time模块,用于添加延时效果
|
||||
|
||||
# 定义状态转移矩阵 A
|
||||
A = np.matrix([[0.7, 0.2], # 第一行表示从鸡到鸡的概率为0.7,从鸡到兔子的概率为0.3
|
||||
[0.3, 0.8]]) # 第二行表示从兔子到鸡的概率为0.2,从兔子到兔子的概率为0.8
|
||||
|
||||
# 在侧边栏中创建交互组件
|
||||
with st.sidebar:
|
||||
# 创建滑块,用于用户设置初始状态中鸡的比例
|
||||
pi_0_chicken = st.slider('Ratio of chicken:', # 滑块标题
|
||||
0.0, 1.0, step=0.1) # 范围从0到1,每次步进0.1
|
||||
pi_0_rabbit = 1 - pi_0_chicken # 计算兔子的比例,使鸡和兔子的比例和为1
|
||||
st.write('Ratio of rabbit: ' + str(round(pi_0_rabbit, 1))) # 显示兔子的比例,保留1位小数
|
||||
|
||||
# 创建滑块,用于用户设置模拟的天数
|
||||
num_iterations = st.slider('Number of nights:', # 滑块标题
|
||||
20, 100, step=5) # 范围从20到100,每次步进5
|
||||
|
||||
# 创建进度条和状态文本,用于显示迭代进度
|
||||
progress_bar = st.sidebar.progress(0) # 初始化进度条为0%
|
||||
status_text = st.sidebar.empty() # 创建一个空白的文本区域,用于显示进度百分比
|
||||
|
||||
# 初始化状态向量,将用户输入的初始比例存入数组
|
||||
last_rows = np.array([[pi_0_chicken, pi_0_rabbit]]) # 初始状态为一个行向量,包含鸡和兔子的比例
|
||||
|
||||
# 创建一个折线图,用于实时展示状态变化
|
||||
chart = st.line_chart(last_rows) # 初始化折线图,并将初始状态绘制到图上
|
||||
|
||||
# 开始迭代模拟状态转移
|
||||
for i in range(1, num_iterations): # 循环从第1天到用户设置的总天数
|
||||
last_status = last_rows[-1, :] # 获取当前的状态向量(最后一行)
|
||||
new_rows = last_status @ A.T # 使用矩阵乘法计算下一个状态,转移矩阵取转置
|
||||
percent = (i + 1) * 100 / num_iterations # 计算当前完成的百分比
|
||||
|
||||
# 更新进度条和状态文本
|
||||
status_text.text("%i%% Complete" % percent) # 显示当前完成的百分比
|
||||
chart.add_rows(new_rows) # 将新状态添加到折线图
|
||||
progress_bar.progress(i) # 更新进度条的值
|
||||
last_rows = new_rows # 更新最后的状态向量为当前计算的状态
|
||||
time.sleep(0.1) # 延时0.1秒,以便观察每次状态更新
|
||||
|
||||
# 清空进度条,表示模拟完成
|
||||
progress_bar.empty() # 移除进度条
|
||||
|
||||
119
Book4_Ch14_Python_Codes/Streamlit_Bk4_Ch14_03.py
Normal file
119
Book4_Ch14_Python_Codes/Streamlit_Bk4_Ch14_03.py
Normal file
@@ -0,0 +1,119 @@
|
||||
|
||||
###############
|
||||
# Authored by Weisheng Jiang
|
||||
# Book 4 | From Basic Arithmetic to Machine Learning
|
||||
# Published and copyrighted by Tsinghua University Press
|
||||
# Beijing, China, 2025
|
||||
###############
|
||||
|
||||
|
||||
import plotly.graph_objects as go # 导入 Plotly 的图形对象模块,用于创建复杂的图形
|
||||
import streamlit as st # 导入 Streamlit 库,用于创建交互式 Web 应用
|
||||
import numpy as np # 导入 NumPy,用于数值计算
|
||||
import plotly.express as px # 导入 Plotly Express,用于快速绘制图表
|
||||
import pandas as pd # 导入 Pandas,用于数据处理
|
||||
import sympy # 导入 SymPy,用于符号运算和公式化表达
|
||||
|
||||
# 定义函数 bmatrix,将 NumPy 数组转换为 LaTeX 格式的矩阵表示
|
||||
def bmatrix(a):
|
||||
"""返回一个 LaTeX 矩阵表示"""
|
||||
if len(a.shape) > 2: # 检查输入是否为二维数组
|
||||
raise ValueError('bmatrix 函数最多显示二维矩阵') # 如果不是二维,抛出异常
|
||||
lines = str(a).replace('[', '').replace(']', '').splitlines() # 将数组转换为字符串并去掉方括号
|
||||
rv = [r'\begin{bmatrix}'] # 开始 LaTeX 矩阵的格式
|
||||
rv += [' ' + ' & '.join(l.split()) + r'\\' for l in lines] # 逐行添加 LaTeX 矩阵行
|
||||
rv += [r'\end{bmatrix}'] # 结束 LaTeX 矩阵的格式
|
||||
return '\n'.join(rv) # 返回拼接后的 LaTeX 字符串
|
||||
|
||||
# 创建 Streamlit 侧边栏,用于调整矩阵 A 的参数
|
||||
with st.sidebar:
|
||||
# 显示矩阵 A 的 LaTeX 表示
|
||||
st.latex(r'''
|
||||
A = \begin{bmatrix}
|
||||
a & b\\
|
||||
b & c
|
||||
\end{bmatrix}''')
|
||||
|
||||
# 创建滑块,允许用户调整矩阵 A 的元素 a, b, c 的值
|
||||
a = st.slider('a', -2.0, 2.0, step=0.05, value=1.0) # 滑块用于调整 a 的值
|
||||
b = st.slider('b', -2.0, 2.0, step=0.05, value=0.0) # 滑块用于调整 b 的值
|
||||
c = st.slider('c', -2.0, 2.0, step=0.05, value=1.0) # 滑块用于调整 c 的值
|
||||
|
||||
#%% 创建一个单位圆的点集
|
||||
theta_array = np.linspace(0, 2 * np.pi, 36) # 在 [0, 2π] 区间生成 36 个点,表示角度
|
||||
X = np.column_stack((np.cos(theta_array), # 用 cos 和 sin 创建单位圆上的点
|
||||
np.sin(theta_array)))
|
||||
|
||||
# 创建矩阵 A
|
||||
A = np.array([[a, b], # 矩阵 A 的第一行
|
||||
[b, c]]) # 矩阵 A 的第二行
|
||||
|
||||
# 显示单位圆的方程和线性变换后的方程
|
||||
st.latex(r'''z^Tz = 1''') # 显示单位圆的方程
|
||||
st.latex(r'''x = Az''') # 显示线性变换的方程
|
||||
|
||||
# 显示矩阵 A 的 LaTeX 表示
|
||||
st.latex('A =' + bmatrix(A))
|
||||
|
||||
# 对单位圆的点集进行线性变换
|
||||
X_ = X @ A # 对单位圆上的点集 X 应用线性变换矩阵 A
|
||||
|
||||
#%% 使用符号运算求解椭圆的方程
|
||||
x1, x2 = sympy.symbols('x1 x2') # 定义符号变量 x1 和 x2
|
||||
y1, y2 = sympy.symbols('y1 y2') # 定义符号变量 y1 和 y2
|
||||
x = np.array([[x1, x2]]).T # 定义符号向量 x
|
||||
y = np.array([[y1, y2]]).T # 定义符号向量 y
|
||||
|
||||
# 计算 Q 矩阵
|
||||
Q = np.linalg.inv(A @ A.T) # Q = (AA^T)^(-1)
|
||||
D, V = np.linalg.eig(Q) # 计算 Q 的特征值和特征向量
|
||||
D = np.diag(D) # 将特征值转化为对角矩阵
|
||||
|
||||
# 显示 Q 矩阵的分解
|
||||
st.latex(r'Q = \left( AA^T\right)^{-1} = ' + bmatrix(np.round(Q, 3))) # 显示 Q 矩阵
|
||||
st.latex(r'''Q = V \Lambda V^{T}''') # 显示特征分解公式
|
||||
st.latex(bmatrix(np.around(Q, decimals=3)) + '=' +
|
||||
bmatrix(np.around(V, decimals=3)) + '@' +
|
||||
bmatrix(np.around(D, decimals=3)) + '@' +
|
||||
bmatrix(np.around(V.T, decimals=3))) # 显示分解过程
|
||||
|
||||
# 定义单位圆和变换后的椭圆方程
|
||||
f_x = x.T @ np.round(Q, 3) @ x # 单位圆在 Q 矩阵下的方程
|
||||
f_y = y.T @ np.round(D, 3) @ y # 椭圆在对角矩阵 D 下的方程
|
||||
|
||||
# 显示椭圆方程
|
||||
from sympy import *
|
||||
st.write('The formula of the ellipse:') # 显示椭圆方程的标题
|
||||
st.latex(latex(simplify(f_x[0][0])) + ' = 1') # 显示椭圆方程
|
||||
st.write('The formula of the transformed ellipse:') # 显示变换后椭圆方程的标题
|
||||
st.latex(latex(simplify(f_y[0][0])) + ' = 1') # 显示变换后的椭圆方程
|
||||
|
||||
#%% 添加颜色信息到变换后的点集
|
||||
color_array = np.linspace(0, 1, len(X)) # 为每个点生成一个颜色值
|
||||
X_c = np.column_stack((X_, color_array)) # 将颜色信息添加到点集中
|
||||
df = pd.DataFrame(X_c, columns=['x1', 'x2', 'color']) # 将点集转换为 DataFrame 格式
|
||||
|
||||
#%% 绘制散点图
|
||||
fig = px.scatter(df, # 使用 Pandas 数据框作为数据源
|
||||
x="x1", # 横轴为 x1
|
||||
y="x2", # 纵轴为 x2
|
||||
color='color', # 根据颜色值为点上色
|
||||
color_continuous_scale=px.colors.sequential.Rainbow) # 使用彩虹色带
|
||||
|
||||
# 设置图形布局
|
||||
fig.update_layout(
|
||||
autosize=False, # 禁用自动调整尺寸
|
||||
width=500, # 图表宽度为 500 像素
|
||||
height=500) # 图表高度为 500 像素
|
||||
|
||||
# 添加横轴和纵轴的参考线
|
||||
fig.add_hline(y=0, line_color='black') # 添加黑色的水平参考线
|
||||
fig.add_vline(x=0, line_color='black') # 添加黑色的垂直参考线
|
||||
fig.update_layout(coloraxis_showscale=False) # 隐藏颜色条
|
||||
fig.update_xaxes(range=[-3, 3]) # 设置 x 轴范围
|
||||
fig.update_yaxes(range=[-3, 3]) # 设置 y 轴范围
|
||||
|
||||
# 在 Streamlit 页面上显示图表
|
||||
st.plotly_chart(fig)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user