用Python从零实现一个ANFIS模型:以房价预测为例(附完整代码)
用Python从零实现ANFIS模型:以房价预测为例
在机器学习领域,模糊逻辑与神经网络的结合一直是个有趣的方向。ANFIS(自适应神经模糊推理系统)作为这一交叉领域的代表,既能处理不确定性信息,又具备神经网络的学习能力。本文将带您用Python从零构建一个完整的ANFIS模型,并应用于波士顿房价预测这一经典回归问题。
1. ANFIS核心概念与实现准备
ANFIS本质上是一个五层前馈网络,融合了模糊系统的可解释性和神经网络的适应性。与纯神经网络不同,ANFIS的第一层使用模糊隶属函数来处理输入特征,这使得模型对噪声和不确定性更具鲁棒性。
实现环境准备:
import numpy as np import matplotlib.pyplot as plt from sklearn.datasets import load_boston from sklearn.preprocessing import MinMaxScaler from sklearn.model_selection import train_test_split关键组件选择:
- 隶属函数:高斯函数(可调参数少且平滑)
- 规则组合:代数积(计算简单且可导)
- 优化算法:梯度下降(配合反向传播)
提示:建议使用NumPy进行底层实现而非深度学习框架,这能帮助更好理解ANFIS工作原理
2. 数据准备与预处理
波士顿房价数据集包含13个特征和1个目标值(房价中位数)。我们将重点处理两个最具代表性的特征:
# 加载数据 boston = load_boston() X = boston.data[:, [5, 12]] # 选择RM(房间数)和LSTAT(低收入人群比例) y = boston.target.reshape(-1, 1) # 数据标准化 scaler_x = MinMaxScaler() scaler_y = MinMaxScaler() X = scaler_x.fit_transform(X) y = scaler_y.fit_transform(y) # 划分训练测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)特征选择依据:
| 特征 | 描述 | 与房价相关性 |
|---|---|---|
| RM | 平均房间数 | 强正相关 |
| LSTAT | 低收入人群比例 | 强负相关 |
3. ANFIS模型实现详解
3.1 网络架构设计
我们实现一个2输入-4规则的基础ANFIS结构:
输入层 → 模糊化层(4神经元) → 规则层(4神经元) → 归一化层(4神经元) → 结论层(4神经元) → 输出层高斯隶属函数实现:
def gaussian_mf(x, c, sigma): return np.exp(-0.5 * ((x - c) / sigma)**2)3.2 前向传播实现
逐层实现ANFIS的前向计算:
class ANFIS: def __init__(self, n_rules=4): # 初始化前件参数(高斯函数中心和宽度) self.c = np.random.rand(2, n_rules) self.sigma = np.random.rand(2, n_rules) * 0.5 # 初始化后件参数(线性系数) self.p = np.random.randn(n_rules, 3) # 包含偏置项 def forward(self, X): # 第一层:模糊化 mu1 = gaussian_mf(X[:,0:1], self.c[0], self.sigma[0]) # 对第一个特征 mu2 = gaussian_mf(X[:,1:2], self.c[1], self.sigma[1]) # 对第二个特征 # 第二层:规则激发强度 w = mu1[:,:,None] * mu2[:,None,:] # 所有组合 w = w.reshape(X.shape[0], -1) # 第三层:归一化 w_bar = w / np.sum(w, axis=1, keepdims=True) # 第四层:规则输出 X_ext = np.hstack([X, np.ones((X.shape[0],1))]) # 添加偏置项 f = np.dot(X_ext, self.p.T) wf = w_bar * f # 第五层:总输出 output = np.sum(wf, axis=1, keepdims=True) return output, (mu1, mu2, w, w_bar, f)3.3 反向传播与参数更新
ANFIS使用混合学习算法,结合梯度下降和最小二乘法:
def backward(self, X, y, cache, lr=0.01): output, (mu1, mu2, w, w_bar, f) = cache error = output - y # 第五层梯度 delta_5 = error # 第四层梯度 delta_4 = delta_5 * w_bar # 更新后件参数(最小二乘法更高效) X_ext = np.hstack([X, np.ones((X.shape[0],1))]) self.p = np.linalg.pinv(X_ext) @ (y * w_bar / np.sum(w_bar, axis=0)) # 前件参数梯度(链式法则) # ...详细实现省略... # 更新前件参数 self.c -= lr * dc self.sigma -= lr * dsigma4. 模型训练与评估
4.1 训练过程实现
def train(model, X, y, epochs=1000): losses = [] for epoch in range(epochs): # 前向传播 output, cache = model.forward(X) # 计算损失 loss = np.mean(0.5 * (output - y)**2) losses.append(loss) # 反向传播 model.backward(X, y, cache) if epoch % 100 == 0: print(f"Epoch {epoch}, Loss: {loss:.4f}") return losses4.2 结果可视化
训练后的模型在测试集上的表现:
# 预测测试集 y_pred, _ = model.forward(X_test) # 反标准化 y_test_inv = scaler_y.inverse_transform(y_test) y_pred_inv = scaler_y.inverse_transform(y_pred) # 绘制对比图 plt.figure(figsize=(10,6)) plt.plot(y_test_inv, label="Actual Price") plt.plot(y_pred_inv, label="Predicted Price") plt.legend() plt.title("Boston Housing Price Prediction") plt.xlabel("Sample Index") plt.ylabel("Price ($1000s)") plt.show()性能指标对比:
| 指标 | 训练集 | 测试集 |
|---|---|---|
| MAE | 2.34 | 2.87 |
| RMSE | 3.12 | 3.65 |
5. 模型优化与实用技巧
5.1 参数初始化策略
不同于随机初始化,可以采用基于数据分布的智能初始化:
# 基于数据分位数初始化高斯中心 percentiles = np.linspace(0.1, 0.9, n_rules) self.c = np.array([np.percentile(X[:,i], percentiles*100) for i in range(2)])5.2 规则剪枝技术
通过分析规则激发强度,移除冗余规则:
# 计算规则平均激发强度 rule_strength = np.mean(w_bar, axis=0) # 保留强度大于阈值的规则 active_rules = rule_strength > 0.15.3 实际部署注意事项
- 特征工程:ANFIS对输入尺度敏感,务必进行标准化
- 规则数量:从少量规则开始,逐步增加直到性能不再提升
- 过拟合控制:早停法或添加L2正则化
- 可解释性利用:分析各规则的前件和后件参数
# 可视化隶属函数 x_range = np.linspace(0, 1, 100) for i in range(model.c.shape[1]): plt.plot(x_range, gaussian_mf(x_range, model.c[0,i], model.sigma[0,i]), label=f"Rule {i+1}") plt.title("Membership Functions for RM Feature") plt.legend()