目录
回归算法
回归算法用于预测连续的数值输出。回归分析的目标是建立一个模型,以便根据输入特征预测目标变量,在使用 TensorFlow 2.x 实现线性回归模型时,通常的步骤包括数据预处理、模型构建、训练和评估。
1、线性回归 (Linear Regression)
概述:线性回归是最基本的回归算法之一,假设目标变量与输入特征之间存在线性关系。
模型形式:y=+
+...+
+ϵ,其中 y 是目标变量,x 是特征,βi是权重,ϵ 是误差项。
一元线性回归举例
实现步骤:
导入必要的库。
生成或加载数据预处理:使用生成的线性数据集。生成了一个简单的线性关系 y = 2x + 1,并加上了一些噪声来模拟实际的观测数据。np.linspace 生成 100 个从 0 到 10 的点,np.random.normal 用于生成随机噪声。数据处理:使用 X.reshape(-1, 1) 将 X 变成二维数组,以适应 TensorFlow 的输入要求。
构建线性回归模型:使用 tf.keras.Sequential 创建一个简单的线性模型。只使用一个 Dense 层来表示线性回归,其中 input_dim=1 指明输入特征的维度为 1,output_dim=1 表示输出只有一个预测值。
编译模型:设置损失函数和优化器。使用了 adam 优化器,这是一个常用且效果不错的优化器。损失函数选择 mean_squared_error,这是回归问题中常见的损失函数。
训练模型:使用训练数据来训练模型。model.fit 方法用于训练模型。设置了 200 个 epoch 和10 的批次大小。
评估模型:通过测试数据评估模型性能。model.evaluate 会返回训练集的损失值,用来评估训练过程中的效果.
预测结果:使用训练好的模型进行预测。使用 matplotlib 绘制训练过程中每个 epoch 的损失变化情况,以便观察模型训练的收敛过程,使用 model.predict 来预测训练集上的输出,然后将预测结果与真实数据一起绘制出来,查看模型的拟合效果
import numpy as np
import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
# 1. 生成数据:y = 2x + 1
np.random.seed(42)
X = np.linspace(0, 10, 100) # 生成100个点,范围是[0, 10]
Y = 2 * X + 1 + np.random.normal(0, 1, X.shape[0]) # y = 2x + 1,加上一些噪声
# 2. 数据预处理:将数据转化为TensorFlow的张量(也可以直接使用NumPy数组)
X_train = X.reshape(-1, 1) # 特征,转换成二维数组
Y_train = Y.reshape(-1, 1) # 标签,转换成二维数组
# 3. 构建线性回归模型
model = keras.Sequential([
keras.layers.Dense(1, input_dim=1) # 只有一个输入特征,输出一个值
])
# 4. 编译模型:选择损失函数和优化器
model.compile(optimizer='adam', loss='mean_squared_error')
# 5. 训练模型
history = model.fit(X_train, Y_train, epochs=200, batch_size=10, verbose=0)
# 6. 评估模型
loss = model.evaluate(X_train, Y_train)
print(f"Final training loss: {loss}")
# 7. 绘制训练过程中的损失变化
plt.plot(history.history['loss'])
plt.title('Training Loss Over Epochs')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.show()
# 8. 预测结果
Y_pred = model.predict(X_train)
# 9. 可视化真实数据和预测结果
plt.scatter(X_train, Y_train, color='blue', label='Actual Data')
plt.plot(X_train, Y_pred, color='red', label='Predicted Line')
plt.title('Linear Regression with TensorFlow 2')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.show()


二元线性回归
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
# 设置中文显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# ==================== 1. 生成模拟数据 ====================
np.random.seed(42)
n_samples = 100
X1 = np.random.rand(n_samples) * 10 # 第一个特征
X2 = np.random.rand(n_samples) * 5 # 第二个特征
noise = np.random.randn(n_samples) * 2 # 噪声
# 真实参数:y = 3*X1 + 5*X2 + 10 + noise
y = 3 * X1 + 5 * X2 + 10 + noise
# 拼接特征矩阵 (添加偏置项)
X = np.column_stack((np.ones(n_samples), X1, X2))
# ==================== 2. 定义损失函数 ====================
def compute_loss(X, y, theta):
residuals = X.dot(theta) - y
return (residuals**2).mean() # MSE
# ==================== 3. 梯度下降实现 ====================
def gradient_descent(X, y, learning_rate=0.01, n_iters=100):
n_features = X.shape[1]
theta = np.zeros(n_features) # 初始化参数 [w0, w1, w2]
loss_history = []
for _ in range(n_iters):
gradients = 2/X.shape[0] * X.T.dot(X.dot(theta) - y)
theta -= learning_rate * gradients
loss_history.append(compute_loss(X, y, theta))
return theta, loss_history
# 训练模型
theta, loss_history = gradient_descent(X, y, learning_rate=0.01, n_iters=200)
# ==================== 4. 可视化 ====================
plt.figure(figsize=(18, 6))
# 子图1:损失函数下降曲线
plt.subplot(1, 3, 1)
plt.plot(loss_history, 'b-o', linewidth=2, markersize=4)
plt.title('损失函数下降曲线', fontsize=14)
plt.xlabel('迭代次数', fontsize=12)
plt.ylabel('MSE损失', fontsize=12)
plt.grid(True)
# 子图2:真实值 vs 预测值
plt.subplot(1, 3, 2)
y_pred = X.dot(theta)
plt.scatter(y, y_pred, c='r', edgecolors='k')
plt.plot([y.min(), y.max()], [y.min(), y.max()], 'k--', linewidth=2)
plt.title('真实值 vs 预测值', fontsize=14)
plt.xlabel('真实值', fontsize=12)
plt.ylabel('预测值', fontsize=12)
plt.grid(True)
# 子图3:3D回归平面
plt.subplot(1, 3, 3, projection='3d')
ax = plt.gca()
ax.scatter(X1, X2, y, c='b', label='真实数据')
ax.set_xlabel('特征X1', fontsize=12)
ax.set_ylabel('特征X2', fontsize=12)
ax.set_zlabel('y值', fontsize=12)
# 绘制回归平面
x1_range = np.linspace(X1.min(), X1.max(), 20)
x2_range = np.linspace(X2.min(), X2.max(), 20)
X1_mesh, X2_mesh = np.meshgrid(x1_range, x2_range)
y_mesh = theta[0] + theta[1]*X1_mesh + theta[2]*X2_mesh
ax.plot_surface(X1_mesh, X2_mesh, y_mesh, alpha=0.5, cmap=cm.coolwarm)
plt.title('3D回归平面', fontsize=14)
plt.tight_layout()
plt.show()
# ==================== 5. 打印结果 ====================
print(f"真实参数:截距=10, w1=3, w2=5")
print(f"学习到的参数:截距={theta[0]:.2f}, w1={theta[1]:.2f}, w2={theta[2]:.2f}")
print(f"最终MSE损失:{loss_history[-1]:.2f}")

2、非线性回归
创建合成数据集:使用 NumPy 生成从 -3 到 3 的 100 个点,并计算对应的 y 值为sin(x) 加上一些噪声。
划分训练集和测试集:使用 train_test_split 将数据集划分为训练集和测试集,比例为 80% 训练,20% 测试。
构建曲线拟合模型:使用 tf.keras.Sequential 创建一个简单的神经网络模型,包含两个隐藏层,每层有 64 个神经元,激活函数为 ReLU,最后一层为输出层。
编译模型:使用 Adam 优化器和均方误差损失函数编译模型。
训练模型:使用 fit 方法训练模型,设置训练轮数为 200,批次大小为 10。
进行预测:使用 predict 方法对测试集进行预测。可视化预测结果,使用 Matplotlib 绘制实际值和预测值的散点图。
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
# 1. 创建合成数据集
np.random.seed(0)
X = np.linspace(-3, 3, 100) # 生成从-3到3的100个点
y = np.sin(X) + np.random.normal(0, 0.1, X.shape) # y = sin(x) + 噪声
# 2. 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 3. 构建曲线拟合模型
# 将输入数据转换为二维数组
X_train = X_train.reshape(-1, 1)
X_test = X_test.reshape(-1, 1)
model = tf.keras.Sequential([
tf.keras.layers.Dense(64, activation='relu', input_shape=(1,)), # 隐藏层
tf.keras.layers.Dense(64, activation='relu'), # 隐藏层
tf.keras.layers.Dense(1) # 输出层
])
# 4. 编译模型
model.compile(optimizer='adam', loss='mean_squared_error')
# 5. 训练模型
model.fit(X_train, y_train, epochs=200, batch_size=10, verbose=0)
# 6. 进行预测
predictions = model.predict(X_test)
# 7. 可视化预测结果
plt.figure(figsize=(10, 6))
plt.scatter(X_test, y_test, color='blue', label='Actual Values') # 实际值
plt.scatter(X_test, predictions, color='red', label='Predicted Values') # 预测值
plt.title('Curve Fitting Regression')
plt.xlabel('X')
plt.ylabel('y')
plt.legend()
plt.grid()
plt.show()

3、回归分类
分类问题:
分类问题和回归问题有一定的相似性,都是通过对数据集的学习来对未知结果进行预测,区别在于输出值不同。分类问题的输出值是离散值(如垃圾邮件和正常邮件)。回归问题的输出值是连续值(例如房子的价格)。
二分类问题:表示分类任务中有两个类别新的样本属于哪种已知的样本类。如垃圾邮件识别,可以作为二分类问题,将邮件分为你「垃圾邮件」或者「正常邮件」。
多类分类(Multiclass Classification)问题:表示分类任务中有多类别。如图像内容识别:因为图像的内容种类不止一个,图像内容可能是猫、狗、人等等,因此是多类分类问题。
多标签分类(Multilabel Classification)问题:给每个样本一系列的目标标签。文本情感分析:既可以作为二分类问题,将情感分为褒贬两种,还可以作为多类分类问题,将情感种类扩展,比如分为:十分消极、消极、积极、十分积极等。
import numpy as np
import tensorflow as tf
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_classification, make_regression
import matplotlib.pyplot as plt
# 生成回归数据集
X_reg, y_reg = make_regression(n_samples=1000, n_features=1, noise=10, random_state=42)
# 生成分类数据集
X_class, y_class = make_classification(n_samples=1000, n_features=2, n_informative=2, n_redundant=0, n_clusters_per_class=1, random_state=42)
# 划分训练集和测试集
X_reg_train, X_reg_test, y_reg_train, y_reg_test = train_test_split(X_reg, y_reg, test_size=0.2, random_state=42)
X_class_train, X_class_test, y_class_train, y_class_test = train_test_split(X_class, y_class, test_size=0.2, random_state=42)
# 创建线性回归模型
model_reg = tf.keras.Sequential([
tf.keras.layers.Dense(1, input_shape=(1,)) # 输入特征为 1,输出为 1
])
# 编译模型
model_reg.compile(optimizer='adam', loss='mean_squared_error')
# 训练模型
model_reg.fit(X_reg_train, y_reg_train, epochs=100, batch_size=32, verbose=1)
# 评估模型
loss_reg = model_reg.evaluate(X_reg_test, y_reg_test, verbose=0)
print(f'回归模型测试集损失: {loss_reg:.4f}')
# 可视化回归结果
plt.scatter(X_reg, y_reg, color='blue', label='Data points')
plt.scatter(X_reg_test, model_reg.predict(X_reg_test), color='red', label='Predictions')
plt.title('Linear Regression Results')
plt.xlabel('Feature')
plt.ylabel('Target')
plt.legend()
plt.show()
# 创建逻辑回归模型
model_class = tf.keras.Sequential([
tf.keras.layers.Dense(1, activation='sigmoid', input_shape=(2,)) # 输入特征为 2,输出为 1
])
# 编译模型
model_class.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
# 训练模型
model_class.fit(X_class_train, y_class_train, epochs=100, batch_size=32, verbose=1)
# 评估模型
loss_class, accuracy_class = model_class.evaluate(X_class_test, y_class_test, verbose=0)
print(f'分类模型测试集损失: {loss_class:.4f}, 测试集准确率: {accuracy_class:.4f}')
# 可视化分类数据点
plt.scatter(X_class_train[y_class_train == 0][:, 0], X_class_train[y_class_train == 0][:, 1], color='blue', label='Class 0', alpha=0.5)
plt.scatter(X_class_train[y_class_train == 1][:, 0], X_class_train[y_class_train == 1][:, 1], color='red', label='Class 1', alpha=0.5)
# 绘制决策边界
x_min, x_max = X_class[:, 0].min() - 1, X_class[:, 0].max() + 1
y_min, y_max = X_class[:, 1].min() - 1, X_class[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.01), np.arange(y_min, y_max, 0.01))
Z = model_class.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, levels=[0, 0.5, 1], alpha=0.2, colors=['blue', 'red'])
plt.title('Logistic Regression Decision Boundary')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.legend()
plt.show()


make_classification 是 sklearn.datasets 模块中的一个函数,用于生成用于分类的合成数据集。可以通过不同的参数来控制生成数据的特性。
参数解释:n_samples: 生成的样本数量。
n_features: 特征的总数。设置为 2,表示每个样本有 2 个特征。
n_informative: 有效特征的数量,这些特征对分类任务有贡献。设置为 2,表示所有特征都是有效特征。
n_redundant: 冗余特征的数量,这些特征是通过线性组合生成的有效特征。设置为 0,表示没有冗余特征。
n_clusters_per_class: 每个类别的聚类数量。设置为 1,表示每个类别只有一个聚类。
random_state: 随机种子,用于确保结果的可重复性。设置为 42。
make_regression 是 sklearn.datasets 模块中的一个函数,用于生成用于回归的合成数据集。
参数解释:n_samples: 生成的样本数量。
n_features: 特征的总数。比如设置为 1,表示每个样本有 1 个特征。
n_informative: 有效特征的数量,这些特征对目标变量有贡献。比如设置为 1,表示所有特征都是有效特征。
n_targets: 目标变量的数量。默认值为 1,表示生成一个目标变量。
bias: 截距项,表示模型的偏置。可以设置为一个常数,比如 0。
noise: 添加到输出中的噪声的标准差。可以设置为一个浮点数,如 0.1表示添加一定的随机噪声。
random_state: 随机种子,用于确保结果的可重复性。可以设置为一个整数,比如 42。
既然分类和回归有一定相似性可以想到的一种尝试思路是,先用线性拟合,然后对线性拟合的预测结果值进行量化,即将连续值量化为离散值——即使用『线性回归+阈值』解决分类问题。
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
from sklearn.preprocessing import StandardScaler
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 设置随机种子保证可重复性
np.random.seed(42)
tf.random.set_seed(42)
# ==================== 1. 生成模拟数据 ====================
# 正常肿瘤数据(1-5cm)
X_normal = np.random.uniform(1, 5, 50)
y_normal = np.where(X_normal > 3, 1, 0) # >3cm为恶性
# 添加一个异常点(8cm的恶性肿瘤)
X = np.append(X_normal, [8])
y = np.append(y_normal, 1)
# 标准化数据(逻辑回归需要,线性回归不需要但为了公平对比)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X.reshape(-1, 1)).flatten()
# ==================== 2. 线性回归+阈值 ====================
# 添加偏置项
X_linear = np.column_stack((np.ones(len(X)), X))
# 最小二乘法求解
theta = np.linalg.inv(X_linear.T.dot(X_linear)).dot(X_linear.T).dot(y)
# 预测函数
def linear_predict(x):
return theta[0] + theta[1]*x
# 将线性回归输出通过sigmoid映射到0-1(仅用于对比)
def sigmoid(x):
return 1 / (1 + np.exp(-x))
# ==================== 3. 逻辑回归 ====================
model = tf.keras.Sequential([
tf.keras.layers.Dense(1, input_shape=(1,), activation='sigmoid')
])
model.compile(optimizer='adam', loss='binary_crossentropy')
model.fit(X_scaled, y, epochs=100, verbose=0)
# ==================== 4. 可视化对比 ====================
plt.figure(figsize=(15, 6))
# 生成测试点
x_test = np.linspace(0, 9, 100)
# 子图1:线性回归+阈值
plt.subplot(1, 2, 1)
plt.scatter(X[y==1], y[y==1], c='red', marker='x', label='恶性(真实)')
plt.scatter(X[y==0], y[y==0], c='green', marker='o', label='良性(真实)')
# 绘制线性回归输出
linear_output = linear_predict(x_test)
plt.plot(x_test, linear_output, 'blue', label='线性回归输出')
# 绘制sigmoid映射后的概率
plt.plot(x_test, sigmoid(linear_output), 'purple', label='线性回归+Sigmoid')
# 标记异常点(8cm肿瘤)
plt.scatter([8], [1], s=200, facecolors='none', edgecolors='black', linewidths=2, label='异常点(8cm)')
plt.axhline(y=0.5, color='gray', linestyle='--', label='阈值=0.5')
plt.title('线性回归+阈值分类\n异常点导致决策边界偏移', fontsize=14)
plt.xlabel('肿瘤大小(cm)', fontsize=12)
plt.ylabel('输出值/概率', fontsize=12)
plt.legend()
# 子图2:逻辑回归
plt.subplot(1, 2, 2)
plt.scatter(X[y==1], y[y==1], c='red', marker='x', label='恶性(真实)')
plt.scatter(X[y==0], y[y==0], c='green', marker='o', label='良性(真实)')
# 绘制逻辑回归预测概率
x_test_scaled = scaler.transform(x_test.reshape(-1, 1)).flatten()
logistic_probs = model.predict(x_test_scaled).flatten()
plt.plot(x_test, logistic_probs, 'blue', label='逻辑回归概率')
# 标记异常点(8cm肿瘤)
plt.scatter([8], [1], s=200, facecolors='none', edgecolors='black', linewidths=2, label='异常点(8cm)')
plt.axhline(y=0.5, color='gray', linestyle='--', label='阈值=0.5')
plt.title('逻辑回归分类\n对异常点更鲁棒', fontsize=14)
plt.xlabel('肿瘤大小(cm)', fontsize=12)
plt.ylabel('预测概率', fontsize=12)
plt.legend()
plt.tight_layout()
plt.show()
# ==================== 5. 打印关键点预测结果 ====================
print("=== 关键点预测对比 ===")
print(f"线性回归对8cm肿瘤的原始输出: {linear_predict(8):.2f}")
print(f"线性回归+Sigmoid对8cm肿瘤的概率: {sigmoid(linear_predict(8)):.2f}")
print(f"逻辑回归对8cm肿瘤的预测概率: {model.predict(scaler.transform([[8]]))[0][0]:.2f}")

线性回归的局限性
输出无界,异常值会显著影响模型参数,即使通过Sigmoid映射,决策边界仍会偏移,不适合直接用于概率估计
逻辑回归的优势
输出天然是概率值(0-1之间),使用交叉熵损失函数,对异常值更鲁棒,适合处理分类问题,尤其是需要概率输出的场景
实际应用建议
分类问题优先选择逻辑回归,线性回归可用于回归任务或作为逻辑回归的初始化,异常值处理是建模的重要环节。
import numpy as np
import matplotlib.pyplot as plt
# 生成简单线性可分数据(单特征)
np.random.seed(0)
num_samples = 100
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 类别0,均值1,标准差0.5
X0 = np.random.normal(1, 0.5, num_samples//2)
y0 = np.zeros(num_samples//2)
# 类别1,均值3,标准差0.5
X1 = np.random.normal(3, 0.5, num_samples//2)
y1 = np.ones(num_samples//2)
# 合并数据
X = np.hstack((X0, X1))
y = np.hstack((y0, y1))
# 转换成列向量形式,方便矩阵运算
X = X.reshape(-1, 1)
y = y.reshape(-1, 1)
# 添加偏置项(常数1列)
X_bias = np.hstack((np.ones_like(X), X)) # shape: (num_samples, 2)
# Sigmoid函数
def sigmoid(z):
return 1 / (1 + np.exp(-z))
# 交叉熵损失函数
def compute_loss(y_true, y_pred):
# 避免log(0)数值不稳定,加一个极小值epsilon
epsilon = 1e-15
y_pred = np.clip(y_pred, epsilon, 1 - epsilon)
loss = -np.mean(y_true * np.log(y_pred) + (1 - y_true) * np.log(1 - y_pred))
return loss
# 训练参数初始化
np.random.seed(42)
weights = np.random.randn(2, 1) * 0.01 # 包含偏置权重,shape=(2,1)
# 超参数
learning_rate = 0.1
num_epochs = 200
loss_history = []
# 训练过程
for epoch in range(num_epochs):
# 前向传播:计算线性组合 z = X_bias * weights
z = np.dot(X_bias, weights) # shape: (num_samples, 1)
# 计算预测概率
y_pred = sigmoid(z)
# 计算损失
loss = compute_loss(y, y_pred)
loss_history.append(loss)
# 反向传播:计算梯度
# 梯度 = X_bias.T * (y_pred - y) / num_samples
grad = np.dot(X_bias.T, (y_pred - y)) / num_samples
# 更新权重
weights -= learning_rate * grad
# 每20轮打印一次损失
if (epoch + 1) % 20 == 0:
print(f"Epoch {epoch+1}/{num_epochs}, Loss: {loss:.4f}")
# 训练完成,打印最终权重
print(f"训练完成,权重参数:\n{weights.flatten()}")
# 预测函数
def predict(X_input):
X_input_bias = np.hstack((np.ones((X_input.shape[0], 1)), X_input))
probs = sigmoid(np.dot(X_input_bias, weights))
return (probs >= 0.5).astype(int), probs
# 画拟合曲线和损失变化图
plt.figure(figsize=(12,5))
# 子图1:数据点和拟合曲线
plt.subplot(1, 2, 1)
plt.scatter(X[y.flatten()==0], y[y.flatten()==0], color='blue', label='类别 0')
plt.scatter(X[y.flatten()==1], y[y.flatten()==1], color='red', label='类别 1')
# 生成平滑的X用于画拟合概率曲线
X_plot = np.linspace(X.min()-1, X.max()+1, 200).reshape(-1, 1)
_, probs_plot = predict(X_plot)
plt.plot(X_plot, probs_plot, color='green', label='预测概率曲线')
plt.xlabel('特征 X')
plt.ylabel('类别 / 预测概率')
plt.title('逻辑回归拟合曲线')
plt.legend()
plt.grid(True)
# 子图2:损失变化曲线
plt.subplot(1, 2, 2)
plt.plot(range(num_epochs), loss_history, color='purple')
plt.xlabel('训练轮数 (Epoch)')
plt.ylabel('交叉熵损失')
plt.title('训练损失变化')
plt.grid(True)
plt.tight_layout()
plt.show()

逻辑回归的损失函数:
经过Sigmoid 函数的变换使得均方误差这种损失函数不光滑凹凸不平,可能多个局部最优解而找不到全局最优值,使用对数损失函数(二元交叉熵损失),这个损失函数同样能很好地衡量参数好坏,又能保证凸函数的特性。对数损失函数的公式如下:
仍然使用梯度下降寻找最优解的参数。
1748



被折叠的 条评论
为什么被折叠?



