大数据学习进度

今日学习:训练完模型,不能凭感觉判断好坏,得用指标量化。线性回归常用 2 个指标:①R²(决定系数):越接近 1,说明模型拟合得越好;②均方误差(MSE):数值越小,说明预测值和真实值差距越小。新手不用记复杂公式,会用 Scikit-learn 自带函数计算就行,重点是理解 “指标越好,模型越靠谱” 的逻辑。
贝叶斯朴素
import numpy as np
import pandas as pd
from sklearn.model_selection import KFold
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, classification_report, confusion_matrix
from sklearn.preprocessing import LabelEncoder
from sklearn.naive_bayes import GaussianNB
import matplotlib.pyplot as plt
import seaborn as sns

class GaussianNaiveBayes:
"""
自行实现的高斯朴素贝叶斯分类器
"""

def init(self):
"""
初始化高斯朴素贝叶斯分类器
"""
self.classes_ = None # 类别标签
self.class_prior_ = None # 类别先验概率
self.theta_ = None # 每个类别每个特征的均值
self.sigma_ = None # 每个类别每个特征的方差
self.epsilon = 1e-9 # 防止方差为0的小常数

def fit(self, X, y):
"""
训练高斯朴素贝叶斯模型

参数:
- X: 训练集特征数据,形状为(n_samples, n_features)
- y: 训练集目标变量,形状为(n_samples,)
"""
# 获取所有类别
self.classes_ = np.unique(y)
n_classes = len(self.classes_)
n_samples, n_features = X.shape

初始化参数

self.class_prior_ = np.zeros(n_classes)
self.theta_ = np.zeros((n_classes, n_features))
self.sigma_ = np.zeros((n_classes, n_features))

对每个类别计算参数

for i, c in enumerate(self.classes_):
# 获取属于当前类别的样本
X_c = X[y == c]

计算类别先验概率 P(y=c)

self.class_prior_[i] = len(X_c) / n_samples

计算每个特征的均值 μ

self.theta_[i] = np.mean(X_c, axis=0)

计算每个特征的方差 σ²

self.sigma_[i] = np.var(X_c, axis=0)

防止方差为0

self.sigma_[i] = np.maximum(self.sigma_[i], self.epsilon)

return self

def _gaussian_pdf(self, x, mu, sigma):
"""
计算高斯概率密度函数

参数:
- x: 特征值
- mu: 均值
- sigma: 方差

返回:
- 高斯概率密度值
"""
exponent = np.exp(-((x - mu) ** 2) / (2 * sigma))
return (1.0 / np.sqrt(2 * np.pi * sigma)) * exponent

def predict(self, X):
"""
预测样本的类别

参数:
- X: 测试集特征数据,形状为(n_samples, n_features)

返回:
- 预测的类别标签,形状为(n_samples,)
"""
# 计算每个样本属于每个类别的后验概率
posterior_probs = self.predict_proba(X)

返回后验概率最大的类别

return self.classes_[np.argmax(posterior_probs, axis=1)]

def predict_proba(self, X):
"""
预测样本属于每个类别的概率

参数:
- X: 测试集特征数据,形状为(n_samples, n_features)

返回:
- 每个样本属于每个类别的概率,形状为(n_samples, n_classes)
"""
n_samples = X.shape[0]
n_classes = len(self.classes_)

初始化后验概率矩阵

posterior_probs = np.zeros((n_samples, n_classes))

对每个类别计算后验概率

for i, c in enumerate(self.classes_):
# 计算先验概率的对数(避免数值下溢)
log_prior = np.log(self.class_prior_[i])

计算似然概率的对数

log_likelihood = np.sum(np.log(self.gaussian_pdf(X, self.theta[i], self.sigma_[i])), axis=1)

后验概率 = 先验概率 × 似然概率

使用对数空间计算避免数值下溢

posterior_probs[:, i] = log_prior + log_likelihood

将对数概率转换回概率(使用softmax归一化)

减去最大值以提高数值稳定性

posterior_probs = posterior_probs - np.max(posterior_probs, axis=1, keepdims=True)
posterior_probs = np.exp(posterior_probs)
posterior_probs = posterior_probs / np.sum(posterior_probs, axis=1, keepdims=True)

return posterior_probs

def score(self, X, y):
"""
计算模型在测试集上的准确率

参数:
- X: 测试集特征数据
- y: 测试集真实标签

返回:
- 准确率
"""
y_pred = self.predict(X)
return accuracy_score(y, y_pred)

def load_iris_data(file_path="d:\机器学习\iris\iris.data"):
"""
加载iris数据集

参数:
- file_path: 数据文件路径

返回:
- X: 特征数据
- y: 编码后的标签
- feature_names: 特征名称列表
- class_names: 类别名称列表
"""
# 读取数据
data = pd.read_csv(file_path, header=None)

设置列名

data.columns = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width', 'class']

提取特征和标签

X = data.iloc[:, :-1].values
y = data.iloc[:, -1].values

将类别标签转换为数值

le = LabelEncoder()
y_encoded = le.fit_transform(y)

获取特征名称和类别名称

feature_names = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
class_names = le.classes_.tolist()

return X, y_encoded, feature_names, class_names

def evaluate_model(y_true, y_pred):
"""
评估模型性能

参数:
- y_true: 真实标签
- y_pred: 预测标签

返回:
- 包含各项评估指标的字典
"""
accuracy = accuracy_score(y_true, y_pred)
precision = precision_score(y_true, y_pred, average='weighted')
recall = recall_score(y_true, y_pred, average='weighted')
f1 = f1_score(y_true, y_pred, average='weighted')

return {
'accuracy': accuracy,
'precision': precision,
'recall': recall,
'f1': f1
}

def cross_validate_custom(X, y, k=5):
"""
使用自行实现的高斯朴素贝叶斯进行五折交叉验证

参数:
- X: 特征数据
- y: 目标变量
- k: 折数

返回:
- 每折的评估结果列表
"""
# 创建K折交叉验证对象
kf = KFold(n_splits=k, shuffle=True, random_state=42)

存储每折的结果

results = []

for fold, (train_index, test_index) in enumerate(kf.split(X)):
print(f"\n===== 自行实现 - 第 {fold+1} 折 =====")

划分训练集和测试集

X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]

创建并训练模型

model = GaussianNaiveBayes()
model.fit(X_train, y_train)

在测试集上进行预测

y_pred = model.predict(X_test)

评估模型性能

metrics = evaluate_model(y_test, y_pred)
metrics['fold'] = fold + 1
results.append(metrics)

打印当前折的结果

print(f"准确率: {metrics['accuracy']:.4f}")
print(f"精确率: {metrics['precision']:.4f}")
print(f"召回率: {metrics['recall']:.4f}")
print(f"F1值: {metrics['f1']:.4f}")

计算平均性能

avg_accuracy = np.mean([r['accuracy'] for r in results])
avg_precision = np.mean([r['precision'] for r in results])
avg_recall = np.mean([r['recall'] for r in results])
avg_f1 = np.mean([r['f1'] for r in results])

print("\n===== 自行实现 - 平均性能 =====")
print(f"平均准确率: {avg_accuracy:.4f}")
print(f"平均精确率: {avg_precision:.4f}")
print(f"平均召回率: {avg_recall:.4f}")
print(f"平均F1值: {avg_f1:.4f}")

return results

def cross_validate_sklearn(X, y, k=5):
"""
使用scikit-learn的高斯朴素贝叶斯进行五折交叉验证

参数:
- X: 特征数据
- y: 目标变量
- k: 折数

返回:
- 每折的评估结果列表
"""
# 创建K折交叉验证对象
kf = KFold(n_splits=k, shuffle=True, random_state=42)

存储每折的结果

results = []

for fold, (train_index, test_index) in enumerate(kf.split(X)):
print(f"\n===== scikit-learn - 第 {fold+1} 折 =====")

划分训练集和测试集

X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]

创建并训练模型

model = GaussianNB()
model.fit(X_train, y_train)

在测试集上进行预测

y_pred = model.predict(X_test)

评估模型性能

metrics = evaluate_model(y_test, y_pred)
metrics['fold'] = fold + 1
results.append(metrics)

打印当前折的结果

print(f"准确率: {metrics['accuracy']:.4f}")
print(f"精确率: {metrics['precision']:.4f}")
print(f"召回率: {metrics['recall']:.4f}")
print(f"F1值: {metrics['f1']:.4f}")

计算平均性能

avg_accuracy = np.mean([r['accuracy'] for r in results])
avg_precision = np.mean([r['precision'] for r in results])
avg_recall = np.mean([r['recall'] for r in results])
avg_f1 = np.mean([r['f1'] for r in results])

print("\n===== scikit-learn - 平均性能 =====")
print(f"平均准确率: {avg_accuracy:.4f}")
print(f"平均精确率: {avg_precision:.4f}")
print(f"平均召回率: {avg_recall:.4f}")
print(f"平均F1值: {avg_f1:.4f}")

return results

def plot_confusion_matrix(y_true, y_pred, class_names, title="Confusion Matrix"):
"""
绘制混淆矩阵

参数:
- y_true: 真实标签
- y_pred: 预测标签
- class_names: 类别名称列表
- title: 图表标题
"""
cm = confusion_matrix(y_true, y_pred)

plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=class_names, yticklabels=class_names)
plt.title(title)
plt.xlabel('Predicted Label')
plt.ylabel('True Label')
plt.tight_layout()
plt.savefig('confusion_matrix_naive_bayes.png', dpi=300, bbox_inches='tight')
plt.show()

def main():
"""
主函数
"""
print("===== 朴素贝叶斯算法实验 =====")

加载数据

print("\n1. 加载iris数据集...")
X, y, feature_names, class_names = load_iris_data()
print(f"数据集大小: {X.shape}")
print(f"类别数量: {len(np.unique(y))}")
print(f"特征数量: {X.shape[1]}")

数据分析

print("\n2. 数据分析...")
for i, name in enumerate(feature_names):
print(f"{name}: 最小值={np.min(X[:, i]):.2f}, 最大值={np.max(X[:, i]):.2f}, "
f"平均值={np.mean(X[:, i]):.2f}, 标准差={np.std(X[:, i]):.2f}")

实验一:自行实现的高斯朴素贝叶斯

print("\n3. 实验一:自行实现的高斯朴素贝叶斯")
results_custom = cross_validate_custom(X, y, k=5)

实验二:scikit-learn的高斯朴素贝叶斯

print("\n4. 实验二:scikit-learn的高斯朴素贝叶斯")
results_sklearn = cross_validate_sklearn(X, y, k=5)

结果比较

print("\n5. 结果比较")
methods = ["自行实现", "scikit-learn"]
all_results = [results_custom, results_sklearn]

print("\n方法\t\t准确率\t精确率\t召回率\tF1值")
print("-" * 70)
for i, method in enumerate(methods):
avg_accuracy = np.mean([r['accuracy'] for r in all_results[i]])
avg_precision = np.mean([r['precision'] for r in all_results[i]])
avg_recall = np.mean([r['recall'] for r in all_results[i]])
avg_f1 = np.mean([r['f1'] for r in all_results[i]])
print(f"{method}\t{avg_accuracy:.4f}\t{avg_precision:.4f}\t{avg_recall:.4f}\t{avg_f1:.4f}")

训练最终模型并可视化

print("\n6. 训练最终模型并可视化")

使用自行实现的模型

print("\n自行实现的模型参数:")
custom_model = GaussianNaiveBayes()
custom_model.fit(X, y)
print(f"类别: {custom_model.classes_}")
print(f"类别先验概率: {custom_model.class_prior_}")
print(f"每个类别的特征均值:")
for i, c in enumerate(custom_model.classes_):
print(f" 类别 {c}: {custom_model.theta_[i]}")
print(f"每个类别的特征方差:")
for i, c in enumerate(custom_model.classes_):
print(f" 类别 {c}: {custom_model.sigma_[i]}")

使用scikit-learn的模型

print("\nscikit-learn模型参数:")
sklearn_model = GaussianNB()
sklearn_model.fit(X, y)
print(f"类别: {sklearn_model.classes_}")
print(f"类别先验概率: {sklearn_model.class_prior_}")
print(f"每个类别的特征均值:")
for i, c in enumerate(sklearn_model.classes_):
print(f" 类别 {c}: {sklearn_model.theta_[i]}")
print(f"每个类别的特征方差:")
for i, c in enumerate(sklearn_model.classes_):
print(f" 类别 {c}: {sklearn_model.var_[i]}")

绘制混淆矩阵

print("\n7. 绘制混淆矩阵")
y_pred = sklearn_model.predict(X)
plot_confusion_matrix(y, y_pred, class_names, "Naive Bayes Confusion Matrix")

详细分类报告

print("\n8. 详细分类报告")
print(classification_report(y, y_pred, target_names=class_names))

if name == "main":
main()

posted @ 2026-02-05 12:44  我嘞牛牛  阅读(13)  评论(0)    收藏  举报