哈喽,我是小白~
今儿和大家聊聊最为基础的一个概念:监督学习。
监督学习算法通过已知输入-输出的映射关系来训练模型,使其能够在新数据上做出准确预测。这种算法广泛应用于分类、回归等任务,在实际应用中帮助实现如图像识别、文本分类等目标,推动了智能系统的发展。
监督学习使模型从标注数据中学习,有助于揭示数据间的规律性与关联性,为科学研究和工业实践提供了可靠的工具。
今天给大家列举10种最为常见 且 重要的监督学习算法模型:
线性回归 逻辑回归 K近邻算法 支持向量机 决策树 随机森林 朴素贝叶斯 梯度提升 人工神经网络 贝叶斯网络
如果需要 本文PDF版本 的同学,文末获取~
另外,文末有总结性的干货~
一起来看下具体细化内容~
1. 线性回归
原理
线性回归用于建模因变量 与一个或多个自变量 之间的线性关系。在监督学习中用于预测数值型变量。
假设
假设 可以表示为特征的线性组合,即:
其中, 是误差项,通常假设它满足均值为 0 且方差为 的正态分布。
目标函数
目标是最小化预测值和实际值之间的均方误差(MSE),即损失函数定义为:
参数优化(最小二乘法)
可以通过解析解求出最优参数 ,即:
推导步骤为:对 对 求导并令导数为零,从而得到最优解。
梯度下降法
当数据量很大时,可以使用梯度下降法逐步优化参数:
Python实现
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
# 生成虚拟数据集
np.random.seed(0)
n_samples = 1000
advertising_cost = np.random.normal(500, 150, n_samples) # 广告支出
other_factors = np.random.normal(50, 10, n_samples) # 其他因素
# 销售额为广告支出和其他因素的线性组合,加上一些噪声
sales = 0.6 * advertising_cost + 0.4 * other_factors + np.random.normal(0, 30, n_samples)
# 创建DataFrame
data = pd.DataFrame({
'AdvertisingCost': advertising_cost,
'OtherFactors': other_factors,
'Sales': sales
})
# 划分训练集和测试集
X = data[['AdvertisingCost', 'OtherFactors']]
y = data['Sales']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 训练线性回归模型
model = LinearRegression()
model.fit(X_train, y_train)
# 预测
y_pred_train = model.predict(X_train)
y_pred_test = model.predict(X_test)
residuals = y_test - y_pred_test
# 创建图形
fig, axes = plt.subplots(2, 2, figsize=(15, 12), constrained_layout=True)
fig.suptitle('Linear Regression Analysis', fontsize=16)
# 图1: 散点图与回归线
sns.scatterplot(ax=axes[0, 0], x=X_test['AdvertisingCost'], y=y_test, color='blue', s=60, label='Actual Sales')
sns.scatterplot(ax=axes[0, 0], x=X_test['AdvertisingCost'], y=y_pred_test, color='red', s=60, label='Predicted Sales')
axes[0, 0].set_title('Scatter Plot with Regression Line')
axes[0, 0].set_xlabel('Advertising Cost')
axes[0, 0].set_ylabel('Sales')
axes[0, 0].legend()
# 图2: 残差图
sns.residplot(x=y_pred_test, y=residuals, ax=axes[0, 1], color='purple', lowess=True)
axes[0, 1].set_title('Residuals Plot')
axes[0, 1].set_xlabel('Predicted Sales')
axes[0, 1].set_ylabel('Residuals')
# 图3: 预测值与实际值对比
sns.scatterplot(ax=axes[1, 0], x=y_test, y=y_pred_test, color='green', s=60)
axes[1, 0].plot([y.min(), y.max()], [y.min(), y.max()], '--r', linewidth=2)
axes[1, 0].set_title('Predicted vs Actual Sales')
axes[1, 0].set_xlabel('Actual Sales')
axes[1, 0].set_ylabel('Predicted Sales')
# 图4: 残差分布直方图
sns.histplot(residuals, ax=axes[1, 1], kde=True, color='orange')
axes[1, 1].set_title('Residuals Distribution')
axes[1, 1].set_xlabel('Residuals')
axes[1, 1].set_ylabel('Frequency')
plt.show()
散点图与回归线 - 可以直观地显示广告支出与销售额之间的线性关系,同时通过绘制预测值来观察模型的拟合效果。
残差图 - 检查残差的分布是否均匀,以及是否存在模式。理想情况下,残差应该随机分布在零值上下,以表明模型没有系统性偏差。
预测值与实际值对比图 - 展示模型预测的销售额和实际的销售额,可以帮助我们判断模型的精确度。
残差分布直方图 - 检查残差的分布是否接近正态分布,符合正态分布是线性回归的一项假设,确保模型的稳健性和准确性。
2. 逻辑回归
原理
逻辑回归是一种线性分类模型,通过sigmoid函数将线性组合的结果映射到概率空间,通常用于二分类问题。
假设
假设模型输出是特征的线性组合再经过sigmoid函数变换,模型形式为:
目标函数(对数似然)
损失函数采用对数似然形式:
该损失函数表示数据集下标签真实值与模型预测值之间的差异。
梯度下降法求解
利用梯度下降对 优化,更新公式为:
梯度计算涉及sigmoid函数的导数,最终的更新方向是误差的负梯度方向。
Python实现
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score, roc_curve, roc_auc_score
# 1. 创建虚拟数据集
np.random.seed(42)
data_size = 500
age = np.random.normal(40, 10, data_size).astype(int)
income = np.random.normal(50000, 15000, data_size).astype(int)
owns_house = np.random.choice([0, 1], data_size)
default = (0.3 * (age < 30) + 0.5 * (income < 40000) + 0.2 * owns_house + np.random.rand(data_size) > 1).astype(int)
data = pd.DataFrame({
'Age': age,
'Income': income,
'Owns_House': owns_house,
'Default': default
})
# 2. 数据预处理
X = data[['Age', 'Income', 'Owns_House']]
y = data['Default']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 标准化处理
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
# 3. 训练逻辑回归模型
model = LogisticRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
y_pred_prob = model.predict_proba(X_test)[:, 1]
# 4. 绘图
plt.figure(figsize=(16, 12))
# 图1:特征分布图
plt.subplot(2, 2, 1)
sns.histplot(data['Age'], kde=True, color="blue", label="Age Distribution", bins=30, alpha=0.7)
sns.histplot(data['Income'], kde=True, color="red", label="Income Distribution", bins=30, alpha=0.5)
plt.title("Feature Distribution")
plt.legend()
# 图2:特征与目标变量的关系
plt.subplot(2, 2, 2)
sns.boxplot(x="Default", y="Age", data=data, palette="Set2")
plt.title("Age vs Default")
plt.subplot(2, 2, 3)
sns.boxplot(x="Default", y="Income", data=data, palette="Set1")
plt.title("Income vs Default")
# 图3:ROC 曲线(模型性能)
fpr, tpr, _ = roc_curve(y_test, y_pred_prob)
plt.subplot(2, 2, 4)
plt.plot(fpr, tpr, color="purple", lw=2, label="ROC curve (area = %0.2f)" % roc_auc_score(y_test, y_pred_prob))
plt.plot([0, 1], [0, 1], color="navy", lw=2, linestyle="--")
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel("False Positive Rate")
plt.ylabel("True Positive Rate")
plt.title("Receiver Operating Characteristic (ROC) Curve")
plt.legend(loc="lower right")
# 展示图形
plt.tight_layout()
plt.show()
特征分布图:通过展示特征的直方图(
Age
和Income
),可以帮助我们观察这些数值特征的分布情况,发现是否有极端值或偏态分布等信息。特征与目标的关系:通过展示
Age
和Income
与目标变量Default
之间的关系(用箱线图),可以帮助我们发现年龄、收入等特征对违约的影响,例如年龄较小或收入较低的用户是否更容易违约。ROC 曲线:展示模型在不同阈值下的性能表现,用于衡量分类模型的整体效果。通过该图可以直观地看出模型的判别能力。
3. K近邻算法
原理
KNN是一种基于实例的非参数算法,直接依赖数据计算,无训练过程。通过测量新样本与训练集中样本的距离,选择K个最近的点作为参考。
距离度量
常见距离度量包括欧氏距离、曼哈顿距离等:
欧氏距离:
曼哈顿距离:
分类规则
找到样本点最近的K个邻居。 根据这K个邻居的类别,通过投票法确定样本点的类别(分类任务)或平均法(回归任务)。
K值选择
K值的选择对模型效果有显著影响。小K值使模型更复杂,但容易过拟合;大K值则对数据噪声的敏感性降低,但可能欠拟合。
Python实现
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.neighbors import KNeighborsClassifier
from matplotlib.colors import ListedColormap
# 生成虚拟数据集
np.random.seed(0)
X, y = make_classification(n_samples=3000, n_features=2, n_informative=2, n_redundant=0,
n_clusters_per_class=1, n_classes=3, class_sep=1.5)
# 定义颜色和网格
cmap_bold = ListedColormap(['#FF0000', '#00FF00', '#0000FF'])
h = .02 # 网格步长
# 创建图形对象
fig, axes = plt.subplots(1, 3, figsize=(18, 6))
fig.suptitle("K-Nearest Neighbors (KNN) 多图分析", fontsize=16)
# 1. 绘制类别分布图
axes[0].scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold, edgecolor='k', s=30)
axes[0].set_title("类别分布图")
axes[0].set_xlabel("特征 1")
axes[0].set_ylabel("特征 2")
# 2. 绘制决策边界(以k=5为例)
knn = KNeighborsClassifier(n_neighbors=5)
knn.fit(X, y)
# 创建网格以绘制决策边界
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
Z = knn.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
axes[1].contourf(xx, yy, Z, cmap=cmap_bold, alpha=0.3)
axes[1].scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold, edgecolor='k', s=30)
axes[1].set_title("K=5 的决策边界图")
axes[1].set_xlabel("特征 1")
axes[1].set_ylabel("特征 2")
# 3. 不同K值对模型的影响(k=1, 10, 20)
for i, k in enumerate([1, 10, 20]):
knn = KNeighborsClassifier(n_neighbors=k)
knn.fit(X, y)
Z = knn.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
axes[2].contourf(xx, yy, Z, cmap=cmap_bold, alpha=0.1*(i+1)) # 透明度递增
axes[2].scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold, edgecolor='k', s=30)
axes[2].set_title("不同K值(1, 10, 20)下的决策边界")
axes[2].set_xlabel("特征 1")
axes[2].set_ylabel("特征 2")
plt.tight_layout(rect=[0, 0, 1, 0.96])
plt.show()
类别分布图:这是一个基础的散点图,用于展示数据集的分布情况。在KNN中,数据点的分布对模型效果影响很大。该图可以帮助我们直观地查看每个类别的分布及它们之间的分离程度。
决策边界图:KNN的决策边界图用于可视化算法在特征空间中如何划分不同的类别区域。在这个案例中,我们选择
k=5
,可以看到在不同类别数据点的边界区域,KNN对数据空间的划分。这种图有助于理解算法对特征空间的分区方式和算法在不同区域的决策边界特性。不同K值下的决策边界图:K值会影响KNN模型的平滑度和噪声敏感性。通过对比
k=1
,k=10
, 和k=20
的分类结果,可以观察到较小的K值对噪声敏感、决策边界复杂,而较大的K值则使决策边界平滑化。这类图形能够帮助我们选择适当的K值,从而在决策边界的复杂性和模型的泛化能力之间取得平衡。
4. 支持向量机
原理
SVM通过构建最大化分类间隔的超平面实现二分类。适合线性可分和线性不可分问题,线性不可分问题可通过核技巧映射到高维空间处理。
超平面方程
假设超平面方程为:
间隔(Margin)
到超平面的距离为:
优化目标
最小化 以最大化间隔,同时满足:
最终目标为:
拉格朗日对偶与KKT条件
引入拉格朗日乘子,将原问题转化为对偶问题进行优化,通过KKT条件和SMO算法等方法求解。
Python实现
import numpy as np
import matplotlib.pyplot as plt
from sklearn.svm import SVC
from sklearn.datasets import make_blobs
from sklearn.metrics import accuracy_score
# 生成虚拟数据集
X, y = make_blobs(n_samples=1000, centers=2, random_state=6, cluster_std=1.5)
# 创建并训练SVM模型
model = SVC(kernel='linear', C=1)
model.fit(X, y)
# 预测结果
y_pred = model.predict(X)
# 获取支持向量
support_vectors = model.support_vectors_
# 绘制图形
plt.figure(figsize=(16, 8))
# 子图1:原始数据分布
plt.subplot(1, 3, 1)
plt.title("Original Data Distribution")
plt.scatter(X[:, 0], X[:, 1], c=y, cmap='coolwarm', edgecolors='k', s=70, alpha=0.7)
plt.xlabel("Feature 1")
plt.ylabel("Feature 2")
# 子图2:决策边界及支持向量
plt.subplot(1, 3, 2)
plt.title("Decision Boundary with Support Vectors")
plt.scatter(X[:, 0], X[:, 1], c=y, cmap='coolwarm', edgecolors='k', s=70, alpha=0.7)
plt.scatter(support_vectors[:, 0], support_vectors[:, 1], s=100, facecolors='none', edgecolors='yellow', linewidths=2)
# 画出决策边界
ax = plt.gca()
xlim = ax.get_xlim()
ylim = ax.get_ylim()
xx = np.linspace(xlim[0], xlim[1], 30)
yy = np.linspace(ylim[0], ylim[1], 30)
YY, XX = np.meshgrid(yy, xx)
xy = np.vstack([XX.ravel(), YY.ravel()]).T
Z = model.decision_function(xy).reshape(XX.shape)
ax.contour(XX, YY, Z, colors='black', levels=[-1, 0, 1], linestyles=['--', '-', '--'])
plt.xlabel("Feature 1")
plt.ylabel("Feature 2")
# 子图3:预测结果与真实标签对比
plt.subplot(1, 3, 3)
plt.title("Prediction vs True Labels")
plt.scatter(X[:, 0], X[:, 1], c=y_pred, cmap='coolwarm', edgecolors='k', s=70, alpha=0.7)
# 标注预测正确与否
correct = (y == y_pred)
plt.scatter(X[~correct, 0], X[~correct, 1], facecolors='none', edgecolors='red', s=100, linewidths=2, label="Misclassified")
plt.legend()
plt.xlabel("Feature 1")
plt.ylabel("Feature 2")
# 总结显示
plt.tight_layout()
plt.show()
原始数据分布图:帮助理解数据分布和类别的聚类特征。在特征空间中,可以观察到不同类别数据的分布特性和分离的可能性。 决策边界及支持向量图:直观展示SVM的决策边界和支持向量位置。支持向量对边界的确定至关重要,SVM通过这些边界将不同类别划分开。 预测结果与真实标签对比图:展示模型预测效果,通过标注误分类点(若有)观察模型在当前数据上的拟合程度。
5. 决策树
原理
决策树是一种基于树结构的模型,通过对特征的条件分裂实现分类或回归。
信息增益
信息增益表示分裂后信息的不确定性减少量。假设划分特征为 ,信息增益为:
其中, 是特征 取值为 的数据子集。
基尼系数
用于衡量分类的纯度。基尼系数为:
其中 表示样本中属于第 类的比例。
树剪枝
通过剪枝控制模型复杂度,避免过拟合。包括预剪枝(限制树深度)和后剪枝(根据验证集误差剪去叶节点)。
Python实现
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.tree import plot_tree
from sklearn.inspection import permutation_importance
# 1. 生成虚拟数据集
np.random.seed(42)
n_samples = 2000
study_hours = np.random.normal(5, 2, n_samples) # 学习小时数
extra_activities = np.random.randint(0, 10, n_samples) # 课外活动次数
avg_score = np.clip(study_hours * 10 + np.random.normal(0, 5, n_samples), 0, 100) # 平均分数
passed = (avg_score > 50).astype(int) # 是否通过(标签)
data = pd.DataFrame({
'study_hours': study_hours,
'extra_activities': extra_activities,
'avg_score': avg_score,
'passed': passed
})
# 2. 数据分割
X = data[['study_hours', 'extra_activities', 'avg_score']]
y = data['passed']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 3. 决策树模型训练
clf = DecisionTreeClassifier(max_depth=4, random_state=42)
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
# 4. 模型准确度
accuracy = accuracy_score(y_test, y_pred)
print("模型准确度:", accuracy)
# 5. 绘制图形
fig, axes = plt.subplots(1, 3, figsize=(18, 6), dpi=100)
fig.suptitle('决策树分析 - 学生是否通过考试', fontsize=16)
# 5.1 散点图:学习时间 vs 课外活动,按是否通过分类
colors = ['#FF6347' if p == 1 else '#4682B4' for p in data['passed']]
axes[0].scatter(data['study_hours'], data['extra_activities'], c=colors, alpha=0.7, edgecolor='k')
axes[0].set_xlabel('学习小时数')
axes[0].set_ylabel('课外活动次数')
axes[0].set_title('学习时间 vs 课外活动次数\n按是否通过分类')
axes[0].grid(True)
# 5.2 特征重要性图
importances = clf.feature_importances_
features = X.columns
axes[1].bar(features, importances, color=['#FF8C00', '#8A2BE2', '#32CD32'], alpha=0.7)
axes[1].set_title('特征重要性')
axes[1].set_ylabel('重要性得分')
axes[1].set_xticklabels(features, rotation=45)
# 5.3 决策边界图(仅取学习时间和课外活动两个特征)
x_min, x_max = X['study_hours'].min() - 1, X['study_hours'].max() + 1
y_min, y_max = X['extra_activities'].min() - 1, X['extra_activities'].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1), np.arange(y_min, y_max, 0.1))
Z = clf.predict(np.c_[xx.ravel(), yy.ravel(), np.zeros(xx.ravel().shape)])
Z = Z.reshape(xx.shape)
axes[2].contourf(xx, yy, Z, alpha=0.3, cmap='coolwarm')
axes[2].scatter(data['study_hours'], data['extra_activities'], c=colors, edgecolor='k', s=20, alpha=0.7)
axes[2].set_xlabel('学习小时数')
axes[2].set_ylabel('课外活动次数')
axes[2].set_title('决策边界 - 学习时间与课外活动')
axes[2].grid(True)
# 显示图形
plt.tight_layout(rect=[0, 0, 1, 0.95])
plt.show()
散点图展示了"学习时间"和"课外活动次数"这两个特征的关系,并通过颜色显示学生是否通过考试。这样有助于理解不同特征对通过率的影响。 特征重要性图表明了每个特征在决策树模型中的相对重要性,可以帮助我们理解模型的决策依据。 决策边界图展示了模型在两个特征维度下的决策边界,帮助我们直观地看到模型在不同特征组合下的预测效果。
6. 随机森林
原理
随机森林是一种集成学习算法,基于Bagging(Bootstrap Aggregating)技术构建多个决策树并通过投票或平均来得到最终的预测结果。其优点是提高了模型的稳定性和精度,减少了过拟合的风险。
算法步骤
Bootstrap采样:从原始数据集中有放回地随机抽取样本,生成 个不同的训练子集。 决策树生成:对每个子集生成一棵决策树,在每次节点分裂时随机选择部分特征来计算信息增益或基尼系数,避免所有树的一致性。 集成结果:对分类任务,用投票法来决定最终类别;对回归任务,用所有树的预测值的平均值作为最终输出。
核心公式
对于每棵决策树 ,分类问题的最终结果为:
而回归问题中预测值为:
重要性度量
随机森林的另一大优势是可以评估特征的重要性。常用的特征重要性度量方法有:
基尼重要性(Gini Importance):基于每棵树中对基尼系数的贡献来评估特征的重要性。 Out-of-Bag(OOB)误差:在训练每棵树时,被抽取的样本作为训练数据,未被抽取的样本即为OOB数据,可用于估计模型的泛化误差。
Python实现
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
from sklearn.model_selection import train_test_split
import seaborn as sns
# 生成虚拟数据集
X, y = make_classification(
n_samples=5000, n_features=5, n_informative=3, n_redundant=0,
n_classes=3, n_clusters_per_class=1, random_state=42
)
# 将数据分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 使用随机森林训练模型 (使用所有特征)
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)
# 预测测试集
y_pred = rf.predict(X_test)
# 获取特征重要性
feature_importances = rf.feature_importances_
# 创建图形
plt.figure(figsize=(18, 12))
# 1. 绘制训练数据的分布(使用前两个特征)
plt.subplot(2, 2, 1)
for class_value in np.unique(y_train):
plt.scatter(
X_train[y_train == class_value, 0], X_train[y_train == class_value, 1],
label=f'Class {class_value}', s=30, alpha=0.7
)
plt.title('Training Data Distribution')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.legend()
plt.grid(True)
# 2. 绘制特征重要性图
plt.subplot(2, 2, 2)
plt.bar(range(X.shape[1]), feature_importances, color=sns.color_palette("bright"))
plt.title('Feature Importances')
plt.xlabel('Feature Index')
plt.ylabel('Importance Score')
plt.grid(True)
# 3. 绘制混淆矩阵
plt.subplot(2, 2, 3)
cm = confusion_matrix(y_test, y_pred)
disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=np.unique(y))
disp.plot(cmap='coolwarm', ax=plt.gca())
plt.title('Confusion Matrix')
plt.grid(False)
# 4. 绘制决策边界(使用前两个特征)
# 创建一个仅使用前两个特征的随机森林分类器
rf_2d = RandomForestClassifier(n_estimators=100, random_state=42)
rf_2d.fit(X_train[:, :2], y_train) # 仅使用前两个特征进行训练
plt.subplot(2, 2, 4)
x_min, x_max = X_train[:, 0].min() - 1, X_train[:, 0].max() + 1
y_min, y_max = X_train[:, 1].min() - 1, X_train[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1), np.arange(y_min, y_max, 0.1))
Z = rf_2d.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, alpha=0.4, cmap='coolwarm')
for class_value in np.unique(y_test):
plt.scatter(
X_test[y_test == class_value, 0], X_test[y_test == class_value, 1],
label=f'Class {class_value}', s=30, edgecolor='k'
)
plt.title('Decision Boundary on Test Data')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.legend()
plt.grid(True)
# 显示所有子图
plt.tight_layout()
plt.show()
虚拟数据生成: make_classification
生成具有5个特征的多类分类数据集。随机森林训练:使用 RandomForestClassifier
训练模型,并在测试集上进行预测。
子图1:训练数据的分布图,展示不同类别在特征空间中的分布。 子图2:特征重要性条形图,帮助理解各个特征对分类的贡献。 子图3:混淆矩阵图,分析预测结果与真实值的匹配情况。 子图4:决策边界图,展示随机森林模型在测试集上的分类边界效果。
7. 朴素贝叶斯
原理
朴素贝叶斯是一种基于贝叶斯定理的概率分类算法,假设特征条件独立。常用于文本分类和垃圾邮件过滤等场景。
贝叶斯定理
贝叶斯定理用于计算后验概率,公式为:
其中:
表示给定特征 的情况下类别 的概率(后验概率)。 表示给定类别 的情况下特征 的概率(似然)。 表示类别 的先验概率。
条件独立假设
假设特征条件独立,则 可以表示为各特征的概率乘积:
因此,朴素贝叶斯分类器的决策规则为:
常见模型
高斯朴素贝叶斯:适用于连续数据,假设每个特征服从高斯分布。 多项式朴素贝叶斯:适用于离散数据,通常用于文本分类。 伯努利朴素贝叶斯:适用于二元数据(0-1变量),适用于二元特征场景,如文本的词频特征。
Python实现
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
from sklearn.datasets import make_classification
from sklearn.preprocessing import StandardScaler
from matplotlib.colors import ListedColormap
# Step 1: 生成虚拟数据
X, y = make_classification(n_samples=5000, n_features=3, n_informative=3, n_redundant=0,
n_classes=2, random_state=42, class_sep=1.5)
# 将特征分为 Age, Income, Browsing Time
df = pd.DataFrame(X, columns=['Age', 'Income', 'Browsing Time'])
df['Purchase Intention'] = y
# Step 2: 数据集分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# Step 3: 朴素贝叶斯模型训练
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
model = GaussianNB()
model.fit(X_train, y_train)
# Step 4: 预测和评价
y_pred = model.predict(X_test)
cm = confusion_matrix(y_test, y_pred)
# 绘制分析图形
fig, axes = plt.subplots(2, 2, figsize=(14, 12), dpi=100)
fig.suptitle('Customer Purchase Intention Analysis', fontsize=16)
# 特征分布
axes[0, 0].hist(df['Age'], bins=15, color='skyblue', edgecolor='black', alpha=0.7, label='Age')
axes[0, 0].hist(df['Income'], bins=15, color='salmon', edgecolor='black', alpha=0.7, label='Income')
axes[0, 0].hist(df['Browsing Time'], bins=15, color='lightgreen', edgecolor='black', alpha=0.7, label='Browsing Time')
axes[0, 0].set_title('Feature Distribution')
axes[0, 0].set_xlabel('Feature Values')
axes[0, 0].set_ylabel('Frequency')
axes[0, 0].legend()
# 购买意向类别分布
axes[0, 1].bar(['Not Purchase', 'Purchase'], [np.sum(y == 0), np.sum(y == 1)], color=['#FF9999', '#66B2FF'])
axes[0, 1].set_title('Purchase Intention Category Distribution')
axes[0, 1].set_ylabel('Count')
# 决策边界 (使用前两个特征)
X_set, y_set = X_train[:, :2], y_train
X1, X2 = np.meshgrid(np.arange(X_set[:, 0].min() - 1, X_set[:, 0].max() + 1, 0.01),
np.arange(X_set[:, 1].min() - 1, X_set[:, 1].max() + 1, 0.01))
Z = model.predict(np.array([X1.ravel(), X2.ravel(), np.zeros(X1.ravel().shape)]).T)
Z = Z.reshape(X1.shape)
axes[1, 0].contourf(X1, X2, Z, alpha=0.3, cmap=ListedColormap(('orange', 'purple')))
scatter = axes[1, 0].scatter(X_set[:, 0], X_set[:, 1], c=y_set, cmap=ListedColormap(('orange', 'purple')), edgecolor='k')
axes[1, 0].set_title('Decision Boundary (Age vs Income)')
axes[1, 0].set_xlabel('Age')
axes[1, 0].set_ylabel('Income')
axes[1, 0].legend(*scatter.legend_elements(), title="Category")
# 混淆矩阵
ConfusionMatrixDisplay(cm).plot(ax=axes[1, 1], cmap='Blues')
axes[1, 1].set_title('Confusion Matrix')
plt.tight_layout(rect=[0, 0, 1, 0.96])
plt.show()
特征分布图:这图展示了年龄、收入、浏览时间等特征的分布,能够帮助我们理解数据的范围和分布模式。它提供了模型输入特征的直观了解,便于观察特征是否需要标准化或是否有明显的偏态分布。
类别分布图:展示目标变量(购买意向)的分布,检查数据集中各类别的样本量是否均衡。若类别不平衡,模型可能会偏向于预测样本量多的类别。
决策边界图:用前两个特征(年龄和年收入)绘制决策边界,展示朴素贝叶斯模型在这些特征上的分类效果。决策边界可以帮助我们直观地观察模型对不同类别的区分能力。
混淆矩阵图:该图表明模型在测试集上的分类效果,清晰展示每个类别的预测和实际情况。混淆矩阵提供了模型在不同类别上的准确度、错误率等重要信息,便于诊断分类性能的不足之处。
8. 梯度提升
原理
梯度提升是一种集成算法,通过多个弱学习器(通常为决策树)逐步逼近残差,从而提高模型的准确性和稳定性。XGBoost是梯度提升的优化实现,采用了正则化、二阶泰勒展开和高效的分裂查找等方法。
算法步骤
初始化模型:以常数模型 作为初始模型。 逐步拟合残差:在每个步骤中训练一个新的决策树来拟合上一步模型的残差。 模型更新:更新模型为先前模型与新树的加权和。
目标函数
假设有 棵树,目标函数为:
其中, 为正则项,用于控制模型复杂度, 是树的叶节点数。
二阶泰勒展开
XGBoost使用二阶泰勒展开将损失函数展开至二阶:
其中 和 分别为损失函数对 的一阶和二阶导数,用于加速梯度更新。
叶节点权重优化
每个叶节点的权重 可通过最小化展开的损失函数来确定:
其中 是第 个叶节点的样本索引集合。
Python实现
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import accuracy_score
from sklearn.inspection import DecisionBoundaryDisplay
# 设置画图风格和随机种子
sns.set(style="whitegrid")
np.random.seed(42)
# 生成虚拟数据集
X, y = make_classification(
n_samples=1000,
n_features=5,
n_informative=3,
n_redundant=0,
n_clusters_per_class=1,
random_state=42
)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 使用所有特征训练主要模型
model = GradientBoostingClassifier(n_estimators=100, learning_rate=0.1, random_state=42)
model.fit(X_train, y_train)
# 计算准确率
y_pred = model.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"Model Accuracy: {accuracy:.2f}")
# 创建一个仅使用前两个特征的模型用于决策边界可视化
model_2d = GradientBoostingClassifier(n_estimators=100, learning_rate=0.1, random_state=42)
model_2d.fit(X_train[:, :2], y_train)
# 创建图表
fig, axes = plt.subplots(1, 3, figsize=(18, 6))
# 图1: 分类决策边界图(使用前两个特征)
DecisionBoundaryDisplay.from_estimator(
model_2d,
X_train[:, :2],
response_method="predict",
ax=axes[0],
cmap="coolwarm",
alpha=0.8
)
axes[0].scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap="coolwarm", edgecolor="k", s=20)
axes[0].set_title("Decision Boundary (Feature 1 & 2)")
axes[0].set_xlabel("Feature 1")
axes[0].set_ylabel("Feature 2")
# 图2: 特征重要性条形图
feature_importance = model.feature_importances_
sns.barplot(x=feature_importance, y=[f"Feature {i+1}" for i in range(len(feature_importance))], ax=axes[1], palette="viridis")
axes[1].set_title("Feature Importance")
axes[1].set_xlabel("Importance Score")
# 图3: 学习曲线图
train_errors = []
test_errors = []
for i, y_pred_train in enumerate(model.staged_predict(X_train)):
train_errors.append(1 - accuracy_score(y_train, y_pred_train))
for i, y_pred_test in enumerate(model.staged_predict(X_test)):
test_errors.append(1 - accuracy_score(y_test, y_pred_test))
axes[2].plot(range(1, len(train_errors) + 1), train_errors, label="Train Error", color="blue")
axes[2].plot(range(1, len(test_errors) + 1), test_errors, label="Test Error", color="red")
axes[2].set_title("Learning Curve")
axes[2].set_xlabel("Number of Trees")
axes[2].set_ylabel("Error")
axes[2].legend()
plt.tight_layout()
plt.show()
分类决策边界图:通过决策边界图可以直观地看到梯度提升分类器如何在特征空间上区分不同的类别。这里使用了前两个特征(Feature 1 和 Feature 2),从而在二维空间中展示模型的分类能力。颜色代表不同的分类区域,可以帮助我们理解模型的决策边界复杂性。
特征重要性条形图:梯度提升模型会自动评估每个特征在分类中的重要性。这个条形图显示了模型认为哪些特征在分类过程中更为关键。高权重的特征对模型的影响较大,因此通过这个图可以帮助我们识别特征的重要性。
学习曲线图:展示了训练集和测试集上的误差随迭代次数的变化情况。这可以帮助我们分析模型的拟合情况,评估是否发生了过拟合或欠拟合。理想情况下,训练误差和测试误差应在一定迭代次数后稳定在较低值,这样可以确认模型的鲁棒性和泛化能力。
9. 人工神经网络
原理
人工神经网络是一种基于神经元结构的非线性模型。通过多个神经元的连接实现特征组合和映射,尤其适用于复杂模式识别任务。
结构
神经网络由输入层、隐藏层和输出层组成,输入层接收输入特征,隐藏层实现特征提取,输出层提供预测结果。每层神经元都通过权重与激活函数实现非线性变换。
激活函数
常用激活函数包括:
Sigmoid:,适用于概率输出。 ReLU:,常用于隐藏层。 Softmax:用于多分类任务,输出类别概率分布。
前向传播
假设输入特征为 ,权重为 ,则第 层输出为:
损失函数
常用损失函数为交叉熵损失(分类)和均方误差(回归)。
反向传播与梯度下降
反向传播用于计算梯度,基于链式法则逐层更新参数,使损失最小化。更新规则为:
其中 为学习率。
Python实现
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier
from sklearn.metrics import confusion_matrix
import seaborn as sns
# 1. 生成虚拟数据集
np.random.seed(42)
n_samples = 5000
X = np.random.rand(n_samples, 2) * 10 # 两个特征,范围在0到10之间
y = (X[:, 0] + X[:, 1] > 10).astype(int) # 类别标签为0或1
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 2. 训练神经网络模型
mlp = MLPClassifier(hidden_layer_sizes=(10, 10), max_iter=200, random_state=42)
history = mlp.fit(X_train, y_train)
# 预测并计算混淆矩阵
y_pred = mlp.predict(X_test)
conf_matrix = confusion_matrix(y_test, y_pred)
# 3. 创建可视化图形
fig, axes = plt.subplots(1, 3, figsize=(18, 5), gridspec_kw={'width_ratios': [1.5, 1.5, 1]})
# 图1:数据分布图
colors = ['#FF6F61', '#6B5B95']
axes[0].scatter(X[y == 0, 0], X[y == 0, 1], color=colors[0], label="Class 0")
axes[0].scatter(X[y == 1, 0], X[y == 1, 1], color=colors[1], label="Class 1")
axes[0].set_xlabel("Feature 1")
axes[0].set_ylabel("Feature 2")
axes[0].set_title("Data Distribution")
axes[0].legend()
# 图2:损失曲线
loss_curve = mlp.loss_curve_
axes[1].plot(loss_curve, color='dodgerblue')
axes[1].set_xlabel("Iterations")
axes[1].set_ylabel("Loss")
axes[1].set_title("Training Loss Curve")
# 图3:混淆矩阵
sns.heatmap(conf_matrix, annot=True, fmt="d", cmap="YlGnBu", cbar=False, ax=axes[2], annot_kws={"size": 16})
axes[2].set_xlabel("Predicted Label")
axes[2].set_ylabel("True Label")
axes[2].set_title("Confusion Matrix")
plt.tight_layout()
plt.show()
数据生成:我们生成了两个特征,目标标签为0或1,基于特征的简单规则来生成二分类数据集。 训练模型:使用 MLPClassifier
训练一个简单的神经网络,定义为两层隐藏层,每层10个神经元。
数据分布图:有助于理解输入数据的类别分布,直观展示两个类别数据的分布情况。 损失曲线:帮助观察训练过程中的损失下降情况,评估模型的收敛性。 混淆矩阵:提供分类模型性能的详细信息,包括每个类别的正确率和误分类情况。
10. 贝叶斯网络
原理
贝叶斯网络是一种基于概率的有向无环图模型,表示随机变量及其条件依赖关系。适用于表示复杂的条件概率关系。
图模型结构
贝叶斯网络的节点表示随机变量,边表示依赖关系。对于给定变量 ,其条件概率依赖于父节点:
条件概率表(CPT)
每个节点的条件概率表(CPT)记录了该节点在不同父节点组合下的概率值。
联合概率分布
贝叶斯网络可以通过链式法则计算联合概率分布:
通过这种方式,可以实现复杂系统中
各变量之间的概率推断。
推断方法
贝叶斯网络的推断包括求边缘分布和条件分布。常用推断算法有:
精确推断:如变量消除、信念传播。 近似推断:如马尔科夫链蒙特卡罗(MCMC)和变分推断。
Python实现
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from pgmpy.models import BayesianNetwork
from pgmpy.factors.discrete import TabularCPD
from pgmpy.inference import VariableElimination
# 创建贝叶斯网络模型
model = BayesianNetwork([('Age', 'Health Status'),
('Smoking', 'Health Status'),
('Health Status', 'Risk')])
# 定义条件概率分布 (CPDs)
cpd_age = TabularCPD(variable='Age', variable_card=2, values=[[0.7], [0.3]], state_names={'Age': ['Young', 'Old']})
cpd_smoking = TabularCPD(variable='Smoking', variable_card=2, values=[[0.8], [0.2]], state_names={'Smoking': ['Non-Smoker', 'Smoker']})
cpd_health = TabularCPD(variable='Health Status', variable_card=3,
values=[[0.9, 0.6, 0.5, 0.2],
[0.1, 0.3, 0.4, 0.3],
[0.0, 0.1, 0.1, 0.5]],
evidence=['Age', 'Smoking'], evidence_card=[2, 2],
state_names={'Health Status': ['Good', 'Average', 'Poor'], 'Age': ['Young', 'Old'], 'Smoking': ['Non-Smoker', 'Smoker']})
cpd_risk = TabularCPD(variable='Risk', variable_card=2,
values=[[0.8, 0.4, 0.1],
[0.2, 0.6, 0.9]],
evidence=['Health Status'], evidence_card=[3],
state_names={'Risk': ['Low', 'High'], 'Health Status': ['Good', 'Average', 'Poor']})
# 将CPDs添加到模型中
model.add_cpds(cpd_age, cpd_smoking, cpd_health, cpd_risk)
model.check_model()
# 进行推断
inference = VariableElimination(model)
# 生成虚拟数据
samples = model.simulate(n_samples=1000, show_progress=False)
# 设置图形样式
sns.set(style="whitegrid")
fig, axes = plt.subplots(1, 3, figsize=(18, 6), dpi=100)
fig.suptitle("Probability Distributions and Dependencies of Different Features in the Bayesian Network", fontsize=16)
# 图1:边际分布图
sns.histplot(samples['Age'], kde=False, color='skyblue', ax=axes[0], binwidth=0.5)
sns.histplot(samples['Smoking'], kde=False, color='salmon', ax=axes[0], binwidth=0.5)
sns.histplot(samples['Health Status'], kde=False, color='purple', ax=axes[0], binwidth=0.5)
axes[0].set_title('Marginal Distribution')
axes[0].legend(['Age', 'Smoking', 'Health Status'])
# 图2:条件概率热力图
pivot_table = samples.pivot_table(index='Smoking', columns='Health Status', values='Risk', aggfunc='count')
sns.heatmap(pivot_table, annot=True, fmt="d", cmap="YlGnBu", cbar=True, ax=axes[1])
axes[1].set_title('Conditional Probability Heatmap\n(Impact of Health Status and Smoking on Risk)')
# 图3:条件分布堆积图
risk_counts = samples.groupby(['Health Status', 'Risk']).size().unstack()
risk_counts.plot(kind='bar', stacked=True, color=['orange', 'green'], ax=axes[2])
axes[2].set_title('Conditional Distribution Stacked Bar\n(Disease Risk by Health Status)')
axes[2].set_xlabel('Health Status')
axes[2].set_ylabel('Count')
plt.tight_layout(rect=[0, 0, 1, 0.95])
plt.show()
边际分布图:展示了每个特征(年龄、吸烟习惯、健康状况)的边际分布情况,帮助我们了解数据集中各变量的总体分布。 条件概率热力图:通过健康状况和吸烟习惯来查看患病风险的分布,以直观显示不同变量组合对目标变量的影响。 条件分布堆积图:展示了健康状况条件下的患病风险变化,进一步探索健康状况对患病风险的影响。
最后