下面是一篇以小明为主角,尝试用 TensorFlow 预测校园活动参与率的学习故事。我们会在故事情境中穿插对线性回归和逻辑回归的原理介绍,并附带必要的代码示例,帮助你从零基础理解并动手实践。文章结尾还有简要的分析总结。
小明最近加入了学生会,负责策划校园活动。每次活动都需要准备场地、宣传物料和餐饮,但经常会出现场地过小或准备物资不足等问题。为了让活动准备更加高效,小明决定尝试使用机器学习来预测校园活动的参与率。
在开始之前,小明收集了过往 50 场校园活动的数据,包括以下信息:
现实中,我们可能会收集更多特征,如活动类型、主讲人知名度等,但在示例中只展示一些关键的、容易理解的特征。
在本章中,我们将重点介绍:
我们先通过一个直观的例子认识这两种模型的含义和它们能解决的问题。
目标:预测一个连续值,例如“活动的参与人数”或“参与率”(可以理解为一个 0~1 的百分比)。
应用情景:如果小明想要直接预测参与活动的人数,或者预测活动参与率是 0.7 还是 0.8,那么可以把它当作一个连续值来回归。
目标:预测一个分类结果,例如参与人数是否“超过 100 人”(是/否),或者参与率是否“超过 50%”(是/否)。
应用情景:如果小明只想知道“活动参与率会不会超过 50%”这样的二分类问题,就可以使用逻辑回归。
以下我们会以 Keras 的方式来实现线性回归和逻辑回归。Keras 是 TensorFlow 提供的高阶 API,简单易用,能帮助我们快速搭建模型。
注意:数据部分我们将用随机生成的示例来演示流程,核心目的是理解训练步骤。实际项目中需要先对数据进行充分清洗、探索和分析。
假设我们要预测校园活动的实际参与率(范围 0~1 之间的浮点数),需要用线性回归。
import numpy as np
import tensorflow as tf
# 假设我们有 50 条记录,每条包含 4 个特征
# 例如:宣传力度、活动时间(数值化)、是否免费(0/1)、天气(数值化)
np.random.seed(42) # 为了保证结果可复现
X = np.random.rand(50, 4)
# 随机生成的特征,每行 4 个特征
# 实际工作中这里会是从数据库或文件中读入的真实特征
# 生成一个相对合理的“真实参与率” y_true
# 这里假设某些权重 w=[0.3, 0.2, -0.1, 0.4], 偏置 b=0.1, 并加一些噪声
w_real = np.array([0.3, 0.2, -0.1, 0.4])
b_real = 0.1
y = X.dot(w_real) + b_real + np.random.normal(0, 0.02, size=(50,))
# 将 y 限制在 [0,1] 之间(模拟参与率)
y = np.clip(y, 0, 1)
print("特征形状:", X.shape)
print("标签形状:", y.shape)
此时,X
大小为 (50,4)
, y
大小为 (50,)
,代表 50 条数据,4 个特征,1 个连续标签。
我们可以使用 tf.keras.Sequential
来快速构建。线性回归实际上就是输入层直接连接到输出层,因此可以只用一个 Dense
层,并且不加激活函数。
model_linear = tf.keras.Sequential([
tf.keras.layers.Dense(1, activation=None, input_shape=(4,))
])
# 设置优化器和损失函数
model_linear.compile(optimizer='sgd', loss='mse')
# 训练模型
model_linear.fit(X, y, epochs=100, verbose=0)
# 评估模型
mse_loss = model_linear.evaluate(X, y, verbose=0)
print("线性回归模型的最终损失(MSE):", mse_loss)
# 查看学到的权重和偏置
w_learned, b_learned = model_linear.layers[0].get_weights()
print("模型学到的权重:", w_learned.flatten())
print("模型学到的偏置:", b_learned)
示例输出:
线性回归模型的最终损失(MSE): 0.13851742446422577
模型学到的权重: [ 0.48031718 -0.56599224 0.61994004 -0.20186776]
模型学到的偏置: [0.3273381]
sgd
(随机梯度下降)。运行后我们可以看到训练过程中损失函数在降低,模型能学到与设定的真实权重相接近的参数,说明网络成功拟合了我们的模拟数据。
# 随机选取一条新数据(模拟)
X_new = np.array([[0.2, 0.5, 0.0, 0.8]])
y_pred = model_linear.predict(X_new)
print("预测的活动参与率为:", y_pred)
如果 y_pred
输出为 [0.7]
,可理解为:活动有 70% 的人会参与(或者报名),方便小明提前做准备。
现在,如果小明只想知道“活动的参与人数是否会超过 50%(二分类)”,可以使用逻辑回归。它输出一个概率值,表示活动“高参与率”的概率。
我们可以复用上面 X 的特征,为了演示二分类标签,这次手动把 y 转成 0/1:
# 将上面 y>0.5 的部分作为类1,<=0.5作为类0
y_binary = (y > 0.5).astype(int)
print("二分类标签示例:", y_binary[:10])
示例输出:
二分类标签示例: [1 1 1 0 0 0 1 0 1 0]
逻辑回归可以理解为线性变换 + sigmoid 函数。所以在 Keras 中,我们只需要一个 Dense(1, activation='sigmoid')
层即可。
model_logistic = tf.keras.Sequential([
tf.keras.layers.Dense(1, activation='sigmoid', input_shape=(4,))
])
model_logistic.compile(
optimizer='sgd',
loss='binary_crossentropy',
metrics=['accuracy']
)
model_logistic.fit(X, y_binary, epochs=100, verbose=0)
loss, acc = model_logistic.evaluate(X, y_binary, verbose=0)
print("逻辑回归模型的损失:", loss)
print("逻辑回归模型的准确率:", acc)
binary_crossentropy
常用于二分类问题。accuracy
是一个直观的分类指标。X_new = np.array([[0.2, 0.5, 0.0, 0.8]])
prob_pred = model_logistic.predict(X_new)
print("预测活动高参与率的概率:", prob_pred)
if prob_pred >= 0.5:
print("模型判断:活动参与率很可能超过 50%")
else:
print("模型判断:活动参与率应该不会超过 50%")
这样,小明就能够根据概率来进行决策:
通过这个小小的实验,小明已经初步体会到使用 TensorFlow 进行数据训练和模型预测的流程。从此,他在学校活动策划上有了更科学的依据,减少了场地浪费或物资不足的情况。