从猜数游戏到模型训练:机器学习核心概念的无痛入门

Unity ML-Agents: 革新游戏AI开发的开源工具包 Unity ML-Agents为游戏开发者和AI研究人员提供了一个强大而灵活的工具,使他们能够轻松地在Unity环境中实现和训练智能代理。通过结合Unity的强大图形功能和最先进的机器学习算法,ML-Agents正在推动游戏AI的发展,为创造更智能、更有趣的游戏体验铺平道路。无论您是游戏开发者、AI研究人员还是对机器学习感兴趣的学生,ML-Agents都为您提供了一个绝佳的平台来探索和实现智能行为。 阅读详情

玄同 765

大语言模型 (LLM) 开发工程师 | 中国传媒大学 · 数字媒体技术(智能交互与游戏设计)

优快云 · 个人主页 | GitHub · Follow


关于作者

  • 深耕领域:大语言模型开发 / RAG 知识库 / AI Agent 落地 / 模型微调
  • 技术栈:Python | RAG (LangChain / Dify + Milvus) | FastAPI + Docker
  • 工程能力:专注模型工程化部署、知识库构建与优化,擅长全流程解决方案

「让 AI 交互更智能,让技术落地更高效」
欢迎技术探讨与项目合作,解锁大模型与智能交互的无限可能!


从猜数游戏到模型训练:机器学习核心概念的无痛入门

引言:一个每个人都玩过的游戏

想象这样一个场景:你的朋友心里想了一个1到100之间的数字,你需要通过提问猜出这个数字。每次你猜一个数字,朋友只会告诉你"太大了"、“太小了"或者"猜对了”。你会怎么猜?

大多数人会采用一个看似简单却极其有效的策略:首先猜50(中间值)。如果朋友说"太小了",你就知道答案在51到100之间,下次猜75。如果朋友说"太大了",你就知道答案在1到49之间,下次猜25。

这个不断缩小范围、逐步逼近正确答案的过程,其实就是机器学习最核心的思想的直观体现。你在根据每一步的反馈(“太大"或"太小”)来更新你的判断(猜测的范围),最终找到最优解。

现在让我们把视线转向真实的商业场景。假设你是一家电商公司的数据科学家,老板让你预测下个月某款商品的销量,你会怎么做?

传统的方法是让经验丰富的分析师根据直觉和经验来估算。但这种方法有两个致命的缺陷:第一,人类无法处理像"过去三年每天每小时的网站访问量、用户点击流、社交媒体热度变化"这样海量的数据;第二,人类的判断容易受到情绪、疲劳、偏见等因素的影响。

机器学习提供了一种全新的解决方案:让计算机从历史数据中自动学习规律,然后用学到的规律来预测未来。这听起来很神奇,但背后的原理其实跟我们的猜数游戏一样简单——都是通过不断调整、逐步逼近最优解。

今天,让我们从零开始,用最通俗的语言和最直观的图解,系统性地理解机器学习最核心的概念。无论你是计算机专业的学生,还是其他领域想要入门AI的从业者,这一篇文章将为你打下坚实的基础。


零、前置知识:搭建理解这座大厦的地基

0.1 什么是函数?用做菜来理解

在讨论机器学习之前,我们需要先理解一个最基本的概念:函数。

想象你正在做一道番茄炒蛋。食谱上写着:"番茄2个,鸡蛋3个,盐5克,糖10克。“这个食谱实际上定义了一个"做菜函数”:输入是食材和调料,输出是一道菜。

用更数学的语言来说,函数就像是一个魔法盒子。你把一些东西放进去,它就会按照某种固定规则,吐出一个结果。这个"固定规则"就是函数的本质。

输出

函数 f(番茄,鸡蛋,盐,糖)

输入

番茄

鸡蛋

盐

糖

魔法盒子
固定规则

番茄炒蛋

在数学中,我们通常写作 y = f ( x ) y = f(x) y=f(x),其中 x x x 是输入, f f f 是函数规则, y y y 是输出。比如 f ( x ) = 2 x + 1 f(x) = 2x + 1 f(x)=2x+1,当你输入 x = 3 x=3 x=3 时,输出就是 y = 2 × 3 + 1 = 7 y = 2 \times 3 + 1 = 7 y=2×3+1=7。

0.2 什么是求导?用开车来理解

导数是微积分的核心概念,理解它对于理解机器学习中的优化算法至关重要。

想象你正在高速公路上开车。仪表盘上有一个速度计,它告诉你现在开得有多快——这就是"瞬时速度"的概念。

但这里有一个更微妙的问题:如果我想知道我的速度"变化有多快",该怎么办?比如,我一脚油门踩下去,速度从60公里/小时飙升到120公里/小时,这个加速过程本身也有一个"加速度"。

导数描述的正是这样一个概念:当输入变化一点点时,输出会变化多少。

速度与导数

导数 = 速度的变化率

加速过程

瞬时速度

0秒

1秒

1秒

反映加速程度

加速度
(导数)

60 km/h

80 km/h

100 km/h

120 km/h

在数学中,函数 f ( x ) f(x) f(x) 的导数记作 f ′ ( x ) f'(x) f′(x) 或 d f d x \frac{df}{dx} dxdf​,它描述的是"当 x x x 变化一点点时, f ( x ) f(x) f(x) 如何变化"。如果 f ′ ( x ) > 0 f'(x) > 0 f′(x)>0,说明随着 x x x 增加, f ( x ) f(x) f(x) 在增加;如果 f ′ ( x ) < 0 f'(x) < 0 f′(x)<0,说明随着 x x x 增加, f ( x ) f(x) f(x) 在减少。

一个特别重要的例子是 f ( x ) = x 2 f(x) = x^2 f(x)=x2,它的导数是 f ′ ( x ) = 2 x f'(x) = 2x f′(x)=2x。这意味着:

  • 当 x = 1 x = 1 x=1 时, f ′ ( 1 ) = 2 f'(1) = 2 f′(1)=2,说明如果 x x x 增加一点点, f ( x ) f(x) f(x) 会以大约2倍的速度增加
  • 当 x = − 3 x = -3 x=−3 时, f ′ ( − 3 ) = − 6 f'(-3) = -6 f′(−3)=−6,说明如果 x x x 增加一点点, f ( x ) f(x) f(x) 会以大约6倍的速度减少

导数的符号告诉我们优化的方向:如果在某点 x x x 处 f ′ ( x ) > 0 f'(x) > 0 f′(x)>0,说明我们应该减小 x x x 来让 f ( x ) f(x) f(x) 变小;如果 f ′ ( x ) < 0 f'(x) < 0 f′(x)<0,说明我们应该增大 x x x 来让 f ( x ) f(x) f(x) 变小。

0.3 什么是向量和矩阵?用坐标来理解

向量和矩阵是机器学习中无处不在的数学工具。让我用一个生活中的例子来解释。

假设你要描述一个位置,你可以说:"在向东走300米、向北走400米的地方。"这两个数字(300和400)就构成一个二维向量。

坐标系表示

走了

原点 (0,0)

点 (300,400)

向量:方向和大小的组合

方向:向东+向北

向量 v = (300, 400)

大小:500米

向量

在机器学习中,向量和矩阵让我们能够高效地表示和操作海量数据。比如,一张100×100像素的灰度图像可以表示为一个10000维的向量;如果是彩色图像,则需要3个这样的向量(对应RGB三个通道)。

矩阵则是向量的集合。假设我们有1000张这样的图像,把它们堆在一起,就形成了一个1000 × 10000的矩阵。矩阵运算让我们能够一次性对所有数据进行批量处理,这正是GPU擅长并行计算的任务类型。


一、机器学习到底是什么?

1.1 从传统编程到机器学习的范式转变

在传统编程中,我们需要明确地告诉计算机"怎么做"。比如,要写一个判断邮件是否为垃圾邮件的程序,程序员需要手动编写规则:

# 传统编程方式
def is_spam(email):
    # 手动编写规则
    if "免费" in email.text and "点击这里" in email.text:
        return True
    if email.sender in spam_senders_list:
        return True
    return False

这种方法的问题在于:规则需要人工设计,而且很难覆盖所有情况。垃圾邮件发送者会不断绕过规则,我们需要不断手动更新规则库。

机器学习采用了一种完全不同的思路:我们不给计算机规则,而是给它大量的例子,让它自己发现规则。

# 机器学习方式
# 1. 准备数据:大量邮件,每封标注是"垃圾"还是"正常"
emails = [...]  # 10000封邮件
labels = [...]  # 每封邮件的标签

# 2. 定义模型结构(不是具体规则,而是一个待调的函数)
model = NeuralNetwork()  # 或 LogisticRegression(), RandomForest() 等

# 3. 训练:让模型从数据中自动学习规则
model.fit(emails, labels)

# 4. 预测:直接使用学到的规则
prediction = model.predict(new_email)

机器学习范式

训练数据
(输入+正确答案)

自动学习规则
(调参过程)

模型架构
(待调函数)

新数据

输出预测结果

传统编程范式

人工设计规则

程序员手动编写

输入数据

执行固定规则

输出结果

这就是机器学习的核心哲学:不是告诉计算机怎么做,而是让它从数据中自己学会怎么做。

1.2 机器学习的三种主要类型

根据学习方式的不同,机器学习可以分为三大类:监督学习、无监督学习和强化学习。

机器学习三大类型

强化学习 Reinforcement Learning

通过试错学习

最大化奖励信号

游戏AI、机器人控制

无监督学习 Unsupervised Learning

没有标签的数据

发现数据内部结构

客户分群、异常检测

监督学习 Supervised Learning

有标签的数据

学习输入到输出的映射

垃圾邮件分类、房价预测

监督学习是最常见的类型。想象你有一个导游,他带着你走过很多景点,同时告诉你每个景点叫什么名字(标签)。学习结束后,当你看到一个新的景点,你就知道该怎么称呼它了。监督学习就是这么回事:我们有"输入"和对应的"正确答案(标签)",模型学习从输入到标签的映射。

无监督学习则没有标签。想象你第一次去一个陌生的城市,没有人告诉你哪里是商业区、哪里是住宅区,但你通过观察人流量、店铺类型、建筑物密度等,自动发现城市自然地分成了几个区域。无监督学习就是在没有"正确答案"的情况下,让模型发现数据内在的结构。

强化学习则像是学习骑自行车。你会不断尝试,摔倒了很多次,但每次摔倒你都知道这是一个"坏结果"(负奖励)。当你终于能稳定骑行时,你收获了"好结果"(正奖励)。通过不断尝试和从结果中学习,你最终掌握了骑车技能。强化学习就是让智能体通过与环境交互、获得奖励或惩罚来学习最优策略。


二、监督学习:让模型从"有答案的练习"中学习

2.1 监督学习的核心流程

监督学习的过程可以类比为学生准备考试的过程。想象你要准备数学考试,你会:

  1. 做练习题:教材上的例题,每道题都有标准答案
  2. 对照答案:做完题后,和标准答案比对,看看自己哪里错了
  3. 理解错误:分析为什么会错,是粗心还是知识点没掌握
  4. 改进提高:下次遇到类似题目,争取做对

机器学习也是类似的流程:

监督学习完整流程

4. 最终预测

3. 模型验证

2. 模型训练

1. 准备训练数据

部署模型

收集数据

数据标注
(给数据贴标签)

喂入数据到模型

计算预测误差

调整模型参数

用验证集评估

调参优化

对新数据预测

让我把这个过程用具体的例子说得更清楚。假设我们要训练一个房价预测模型:

第一步:准备训练数据。我们需要收集大量房屋的信息,包括面积、位置、房龄、房间数等(这些称为特征,英文是features),以及每套房子的实际售价(这称为标签,英文是label)。比如:

面积(㎡)位置房龄(年)房价(万)
100市中心5500
80郊区10300
120市中心3650
…………

第二步:训练模型。我们把数据喂给模型,模型会学习从特征到标签的映射关系。这个"学习"的过程,本质上是不断调整模型参数,让预测值和真实值越来越接近。

第三步:验证模型。用模型没有"见过"的数据(验证集)来测试模型表现。如果表现不好,就需要调整模型结构或训练策略。

第四步:预测新数据。模型训练好后,给它一间新房子的信息,它就能预测出这房子大概值多少钱。

2.2 损失函数:模型表现的"计分器"

在训练过程中,我们需要一个指标来衡量模型表现的好坏,这个指标就是损失函数(Loss Function)。

继续用考试的例子:如果一道题标准答案是"3",你答了"5",误差就是|5-3|=2;如果另一个人答了"4",误差就是|4-3|=1。显然第二个人的误差更小,表现更好。

在回归任务中,常用的损失函数是均方误差(Mean Squared Error,MSE):

M S E = 1 n ∑ i = 1 n ( y i − y ^ i ) 2 MSE = \frac{1}{n} \sum_{i=1}^{n}(y_i - \hat{y}_i)^2 MSE=n1​i=1∑n​(yi​−y^​i​)2

这里的 y i y_i yi​ 是真实值, y ^ i \hat{y}_i y^​i​ 是模型预测值。公式的意思就是把每个样本的预测误差平方后求平均。为什么要平方?因为误差可能是正也可能是负,平方后全是正数,可以直接相加。

MSE Calculation Process

Calculate Average

Squared Error

Three Samples Prediction

(25+400+100)/3=175

Sample1: Actual 100 Pred 95

(-5)^2=25

(-20)^2=400

10^2=100

Sample2: Actual 200 Pred 180

Sample3: Actual 150 Pred 160

对于分类任务,常用的损失函数是交叉熵(Cross Entropy)。直观地理解,交叉熵衡量的是"预测分布"和"真实分布"之间的差异。预测越接近真实标签,交叉熵越小。

2.3 梯度下降:让模型"学会"的核心算法

现在我们有了损失函数来衡量模型的好坏,接下来问题就是:如何调整模型参数,让损失最小化?

这就要用到梯度下降(Gradient Descent)算法了。

回想一下我们之前讲的导数概念。导数告诉我们,当输入增加一点点时,输出会怎么变化。如果损失函数 L L L 关于某个参数 w w w 的导数 ∂ L ∂ w > 0 \frac{\partial L}{\partial w} > 0 ∂w∂L​>0,说明增大 w w w 会让损失变大,所以我们应该减小 w w w;如果导数 < 0 < 0 <0,说明增大 w w w 会让损失变小,所以我们应该增大 w w w。

梯度下降的核心思想就是:沿着梯度的反方向,一步一步地调整参数,逐步降低损失。

梯度下降优化过程

第三次迭代

第二次迭代

第一次迭代

初始状态

计算梯度

参数更新

计算梯度

参数更新

计算梯度

参数更新

梯度 ∂L/∂w = 6.4

当前参数 w = 5.0

梯度 ∂L/∂w = 10

更新: w = 5.0 - 0.1×10 = 4.0

梯度 ∂L/∂w = 8

更新: w = 4.0 - 0.1×8 = 3.2

更新: w = 3.2 - 0.1×6.4 = 2.56

当前损失 = 25

新损失 = 16

新损失 = 10.24

新损失 = 6.55

在上面的例子中,学习率(Learning Rate)设为0.1,这是一个很重要的超参数。如果学习率太大,可能"步子迈得太大",一下子跳过了最优点;如果太小,收敛速度会很慢,需要很多次迭代才能到达最优点。

学习率对收敛的影响

学习率过小 (0.001)

步幅太小

收敛极慢

学习率过大 (1.0)

步幅过大

振荡或发散

学习率适中 (0.1)

步幅合适

稳定收敛

2.4 过拟合与欠拟合:模型复杂度的权衡

在机器学习中,有一个永恒的主题:如何平衡模型的复杂度和泛化能力?

欠拟合(Underfitting)就像一个学生太笨了,连教材上的例题都做不对。这通常发生在模型太简单、或者训练时间太短的时候。

过拟合(Overfitting)就像一个学生太"聪明"了,他把教材上的每一道题都背下来了,但遇到一道新题就傻眼了——因为它没有真正理解知识,只是记住了答案。这发生在模型太复杂、或者训练数据太少的时候。

从欠拟合到过拟合

过拟合:模型太复杂

特征: 极高次多项式

记住每一个噪声点

训练误差: 极低, 测试误差: 高

欠拟合:模型太简单

特征: y = 2x + 1

无法捕捉数据规律

训练误差: 高, 测试误差: 高

适度拟合:复杂度刚好

特征: 适当的非线性

很好地捕捉规律

训练误差: 低, 测试误差: 低

在实际工作中,我们如何解决这两个问题?

对于欠拟合,解决方案包括:增加模型复杂度、增加训练轮数、添加更多特征等。

对于过拟合,解决方案包括:使用更多训练数据、减少模型复杂度、添加正则化、使用Dropout、数据增强等。


三、用"猜价格"游戏完整演示机器学习流程

3.1 问题设定

让我用一个完整的例子来串联所有概念。假设你要开发一个房价预测系统,用户输入房子的基本信息,系统预测房价。

首先,我们收集了1000套房子的历史数据。每套房子有5个特征:面积、卧室数、浴室数、房龄、距市中心距离。目标是预测房价(单位:万元)。

3.2 数据准备

在实际项目中,数据准备往往占据80%的工作量。让我详细解释这个过程。

# 典型的数据处理流程
import pandas as pd
import numpy as np

# 1. 加载数据
df = pd.read_csv('house_prices.csv')
print(f"数据集大小: {df.shape}")  # (1000, 6) - 1000个样本,6列

# 2. 查看数据基本信息
print(df.head())  # 查看前几行
print(df.describe())  # 统计数据:均值、标准差、分位数等
print(df.isnull().sum())  # 缺失值统计

# 3. 处理缺失值
df['卧室数'].fillna(df['卧室数'].median(), inplace=True)  # 用中位数填充

# 4. 特征标准化(很重要!)
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
features = ['面积', '卧室数', '浴室数', '房龄', '距市中心距离']
df[features] = scaler.fit_transform(df[features])

# 5. 划分训练集和测试集
from sklearn.model_selection import train_test_split
X = df[features]
y = df['房价']
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)
# 80%用于训练,20%用于测试

3.3 模型选择与训练

现在我们有了处理好的数据,接下来选择模型并进行训练。

import torch
import torch.nn as nn
from torch.utils.data import DataLoader, TensorDataset

# 定义一个简单的神经网络模型
class HousePricePredictor(nn.Module):
    """
    房价预测神经网络
    
    输入: 5个房屋特征 (面积、卧室数、浴室数、房龄、距市中心距离)
    输出: 预测房价 (单值输出)
    
    架构说明:
    - 输入层: 5个神经元
    - 隐藏层1: 64个神经元 + ReLU激活
    - 隐藏层2: 32个神经元 + ReLU激活
    - 输出层: 1个神经元 (房价)
    """
    
    def __init__(self, input_size=5):
        super().__init__()
        # 第一层: 5 -> 64
        self.layer1 = nn.Linear(input_size, 64)
        # 第二层: 64 -> 32
        self.layer2 = nn.Linear(64, 32)
        # 输出层: 32 -> 1
        self.output = nn.Linear(32, 1)
        # ReLU激活函数,增加非线性
        self.relu = nn.ReLU()
    
    def forward(self, x):
        """
        前向传播
        
        数据流向:
        输入 x -> Layer1 -> ReLU -> Layer2 -> ReLU -> Output -> 输出房价
        """
        x = self.relu(self.layer1(x))
        x = self.relu(self.layer2(x))
        x = self.output(x)
        return x

# 创建模型实例
model = HousePricePredictor()
print(model)

# 定义损失函数和优化器
criterion = nn.MSELoss()  # 均方误差,用于回归任务
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
# Adam优化器:自动调整学习率的梯度下降变体

3.4 训练循环详解

让我详细解释每一个训练步骤在做什么:

# 将数据转换为PyTorch张量
X_train_tensor = torch.FloatTensor(X_train.values)
y_train_tensor = torch.FloatTensor(y_train.values).reshape(-1, 1)
X_test_tensor = torch.FloatTensor(X_test.values)
y_test_tensor = torch.FloatTensor(y_test.values).reshape(-1, 1)

# 创建数据加载器,支持mini-batch训练
train_dataset = TensorDataset(X_train_tensor, y_train_tensor)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
# batch_size=32: 每次喂32个样本给模型
# shuffle=True: 每个epoch前打乱数据顺序

# 训练循环
num_epochs = 100  # 训练轮数

for epoch in range(num_epochs):
    model.train()  # 设置为训练模式,启用dropout等
    epoch_loss = 0.0  # 累计损失
    
    for batch_idx, (features, labels) in enumerate(train_loader):
        # ===== 第一步:前向传播 =====
        # 把特征喂给模型,得到预测值
        predictions = model(features)
        
        # 计算预测值和真实值的误差
        loss = criterion(predictions, labels)
        
        # ===== 第二步:反向传播 =====
        # 先将梯度清零(否则会累加)
        optimizer.zero_grad()
        # 计算梯度
        loss.backward()
        # 更新参数
        optimizer.step()
        
        # 累计这一轮的损失
        epoch_loss += loss.item()
    
    # 每10轮打印一次
    if (epoch + 1) % 10 == 0:
        # 切换到评估模式
        model.eval()
        with torch.no_grad():
            # 在测试集上评估
            test_predictions = model(X_test_tensor)
            test_loss = criterion(test_predictions, y_test_tensor)
        
        print(f"Epoch [{epoch+1}/{num_epochs}], "
              f"Train Loss: {epoch_loss/len(train_loader):.4f}, "
              f"Test Loss: {test_loss.item():.4f}")

训练过程的输出会像这样:

Epoch [10/100], Train Loss: 245.3215, Test Loss: 312.4587
Epoch [20/100], Train Loss: 156.7842, Test Loss: 198.2341
Epoch [30/100], Train Loss: 98.4567, Test Loss: 125.6789
...
Epoch [100/100], Train Loss: 45.1234, Test Loss: 52.3456

可以看到,随着训练进行,训练损失和测试损失都在下降,说明模型正在学习。

3.5 模型评估与部署

训练完成后,我们需要全面评估模型性能:

# 模型评估
model.eval()
with torch.no_grad():
    test_predictions = model(X_test_tensor)
    
    # 计算各种评估指标
    from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
    
    # 均方误差
    mse = mean_squared_error(y_test, test_predictions.numpy())
    # 均方根误差(单位:万元)
    rmse = np.sqrt(mse)
    # 平均绝对误差
    mae = mean_absolute_error(y_test, test_predictions.numpy())
    # R²分数(越接近1越好)
    r2 = r2_score(y_test, test_predictions.numpy())
    
    print(f"模型评估结果:")
    print(f"  均方根误差 (RMSE): {rmse:.2f} 万元")
    print(f"  平均绝对误差 (MAE): {mae:.2f} 万元")
    print(f"  R² 分数: {r2:.4f}")

# 使用模型进行预测
def predict_price(area, bedrooms, bathrooms, age, distance_to_center):
    """
    预测房价的实际使用函数
    
    参数:
        area: 面积 (平方米)
        bedrooms: 卧室数
        bathrooms: 浴室数
        age: 房龄 (年)
        distance_to_center: 距市中心距离 (公里)
    
    返回:
        预测房价 (万元)
    """
    # 转换为模型期望的格式
    input_data = np.array([[area, bedrooms, bathrooms, age, distance_to_center]])
    # 标准化
    input_scaled = scaler.transform(input_data)
    # 转为张量
    input_tensor = torch.FloatTensor(input_scaled)
    
    # 预测
    model.eval()
    with torch.no_grad():
        prediction = model(input_tensor)
    
    return prediction.item()

# 实际使用示例
predicted = predict_price(100, 3, 2, 5, 3)
print(f"对于一套100平米、3卧2卫、5年新、距中心3公里的房子")
print(f"预测房价: {predicted:.2f} 万元")

四、常见算法一览:从原理到适用场景

4.1 线性回归与逻辑回归:最简单的模型

线性回归是机器学习中最基础的算法之一。它的核心思想是:输出是输入的线性组合。

比如,对于房价预测,模型可能是这样的:

房价 = w 1 × 面积 + w 2 × 卧室数 + w 3 × 浴室数 + w 4 × 房龄 + w 5 × 距市中心 + b \text{房价} = w_1 \times \text{面积} + w_2 \times \text{卧室数} + w_3 \times \text{浴室数} + w_4 \times \text{房龄} + w_5 \times \text{距市中心} + b 房价=w1​×面积+w2​×卧室数+w3​×浴室数+w4​×房龄+w5​×距市中心+b

其中 w 1 , w 2 , . . . , w 5 w_1, w_2, ..., w_5 w1​,w2​,...,w5​ 是学习到的权重, b b b 是偏置。

线性回归模型结构

输出

加权求和

学习到的权重

输入特征

预测房价: 300万

面积: 100㎡

w₁ = 2.5

w₂ = -5.0

w₃ = 8.0

w₄ = -1.2

w₅ = -3.5

b = 50

卧室: 3个

浴室: 2个

房龄: 5年

距中心: 3km

100×2.5 + 3×(-5) + 2×8 + 5×(-1.2) + 3×(-3.5) + 50

线性回归适用于输出是连续值的问题(房价、温度、销售额等)。

逻辑回归虽然名字里有"回归",但实际上是一个分类算法。它输出的是一个0到1之间的概率值,适用于二分类问题(比如判断邮件是否为垃圾邮件)。

4.2 K近邻(KNN):物以类聚

K近邻算法的思想非常直观:如果你周围的邻居大多属于某个类别,那你也大概率属于这个类别。

K近邻分类示例 (K=5)

投票结果

K=5个最近邻居

待分类点 (绿色问号)

找5个最近邻居

找5个最近邻居

找5个最近邻居

找5个最近邻居

找5个最近邻居

投票

投票

投票

投票

投票

红色3票 vs 蓝色2票

?

红色

红色

蓝色

蓝色

蓝色

分类为: 红色

计算距离

欧氏距离

KNN的优点是简单直观、易于理解;缺点是预测速度慢(需要计算与所有样本的距离)、对异常值敏感。

4.3 决策树:自动生成if-else规则

决策树通过不断问问题来对数据进行分类。这些问题不是人工设计的,而是算法自动从数据中学习得到的。

贷款申请决策树

问题3: 有房产?
style=fill:#e1bee7,stroke:#7b1fa2

问题2: 信用分大于700
style=fill:#fff8e1,stroke:#ff8f00

问题1: 收入大于5000
style=fill:#e3f2fd,stroke:#1565c0

收入不足

高收入好信用

有房产担保

进一步审核

批准

继续问问题2

批准

继续问问题3

拒绝

拒绝

批准

评估其他因素

批准

人工审核

决策树的优点是易于解释(可以可视化)、能处理非线性关系;缺点是容易过拟合(通过剪枝和设置深度限制来缓解)。

4.4 集成学习:三个臭皮匠赛过诸葛亮

集成学习的核心思想是:组合多个模型的预测,得到一个更好的结果。

最典型的例子是随机森林——它由多棵决策树组成,每棵树都是随机地从数据和特征中采样后训练的。预测时,所有树各自投票,最终结果由投票决定。

Random Forest: Multiple Trees Integration

Predicting New Data

Prediction Stage

Training Stage

Voting Mechanism

New House Data

Training Set 1 (Random Sampling)

Decision Tree 1

Training Set 2 (Random Sampling)

Decision Tree 2

Training Set 3 (Random Sampling)

Decision Tree 3

Tree1: Price Up

Tree2: Price Down

Tree3: Price Up

2 votes大于1 vote Final Prediction Price Up

随机森林之所以有效,是因为:

  1. 多样性:每棵树看到的数据和特征略有不同
  2. 减少过拟合:多棵树的预测取平均,噪声会被抵消
  3. 稳定性:不容易被个别异常值带偏

五、业务实践:机器学习项目的常见陷阱

5.1 数据质量决定一切

在真实业务场景中,数据往往存在各种问题。我见过太多项目失败,不是因为模型不够好,而是因为数据质量太差。

常见数据问题:

  1. 缺失值:有些样本的某些特征是空的。可能的原因包括用户没填写、数据库同步问题、数据采集设备故障等。

  2. 异常值:有些数值明显不合理。比如年龄显示为200岁、工资显示为负数。这些可能是录入错误或数据污染。

  3. 数据泄露:训练数据中包含了不应该用于预测的信息。比如,用"是否购买"作为特征来预测"购买转化",但这个特征本身就是购买的结果——这会导致模型"偷看答案"。

常见数据陷阱

陷阱3: 数据泄露

陷阱2: 异常值

陷阱1: 缺失值

影响

影响

影响

影响

影响

影响

影响

影响

影响

用户没填年龄

系统没记录职业

部分数据丢失

年龄 = 200岁

收入 = -1000元

价格 = 99999999

用结果预测结果

包含未来信息

训练测试污染

模型偏差

预测失真

虚高的准确率

避坑指南:

# 检查缺失值
print(df.isnull().sum())
print(df.isnull().mean() * 100)  # 缺失百分比

# 处理缺失值的方法
# 方法1: 删除有缺失值的行(如果缺失比例小)
df_clean = df.dropna()

# 方法2: 用均值/中位数填充数值型
df['年龄'].fillna(df['年龄'].median(), inplace=True)

# 方法3: 用众数填充分类型
df['职业'].fillna(df['职业'].mode()[0], inplace=True)

# 方法4: 用模型预测缺失值(更高级)
# from sklearn.impute import KNNImputer
# imputer = KNNImputer(n_neighbors=5)
# df_imputed = imputer.fit_transform(df)

# 检查异常值
print(df.describe())  # 查看统计信息
# 箱线图检测: 超过1.5倍四分位距的值视为异常

# 处理异常值
# 方法1: 用边界值替代
df['收入'] = df['收入'].clip(lower=0)  # 把负值变为0

# 方法2: 删除异常值
df = df[(df['年龄'] > 0) & (df['年龄'] < 120)]

5.2 特征工程:让数据更适合模型

特征工程是机器学习中最能体现"经验"的部分。它指的是对原始数据进行转换,让模型更容易从中学习到规律。

常见的特征工程方法:

# 1. 特征缩放:让不同规模的特征具有可比性
from sklearn.preprocessing import MinMaxScaler, StandardScaler

# 标准化 (均值0, 标准差1) - 适用于大多数情况
scaler = StandardScaler()
df['面积_标准化'] = scaler.fit_transform(df[['面积']])

# 归一化 (0到1之间) - 适用于有明确边界的情况
minmax = MinMaxScaler()
df['面积_归一化'] = minmax.fit_transform(df[['面积']])

# 2. 类别特征编码
# 方法1: 标签编码 (简单但不建议用于无序类别)
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
df['城市_编码'] = le.fit_transform(df['城市'])

# 方法2: 独热编码 (One-Hot Encoding) - 推荐用于无序类别
df = pd.get_dummies(df, columns=['城市'], prefix='城市')

# 3. 特征组合
# 创建新特征:比如把"长"和"宽"组合成"面积"
df['面积_计算'] = df['长'] * df['宽']

# 4. 时间特征提取
df['月份'] = pd.to_datetime(df['日期']).dt.month
df['星期'] = pd.to_datetime(df['日期']).dt.dayofweek
df['是否周末'] = df['星期'].isin([5, 6]).astype(int)

5.3 模型选择不是一次性的

很多初学者会问:"我应该用什么模型?"答案是:看情况。

模型选择决策树

小数据小于1万

大数据大于10万

分类

回归

高实时小于100ms

可接受延迟

是

否

数据量多大?

任务类型?

实时性要求?

随机森林 / XGBoost

梯度提升树 / 线性回归

轻量模型 / 在线学习

需要高精度?

深度学习 / 集成学习

随机森林 / XGBoost

但更重要的是:不要只试一个模型。在真实项目中,我通常会:

  1. 先试简单的模型(线性回归、逻辑回归)作为baseline
  2. 再试复杂的模型(随机森林、XGBoost、神经网络)
  3. 比较它们的性能和速度
  4. 考虑模型可解释性(有时候简单的模型更容易向业务方解释)
  5. 最终选择能平衡性能、速度、可解释性的模型

六、总结:机器学习的全局视图

让我们用一张图来回顾今天学到的所有概念:

机器学习全局视图

部署应用

模型评估

模型训练

数据准备

循环迭代

需要改进

表现良好

模型保存

数据收集

数据清洗

特征工程

选择模型

定义损失函数

梯度下降优化

过拟合/欠拟合检测

指标计算

调参优化

API封装

线上预测

五句话核心总结

第一句:机器学习的核心思想是让计算机从数据中自动学习规律,而不是人工编写规则。这就像教小孩认识动物,不是告诉他每种动物的具体定义,而是给他看很多例子,让他自己总结规律。

第二句:监督学习、无监督学习和强化学习是机器学习的三种主要范式。监督学习像是有标准答案的练习题;无监督学习像是没有老师的情况下发现规律;强化学习像是在试错中学习骑自行车。

第三句:损失函数衡量模型预测和真实值之间的差距,梯度下降是让损失最小化的核心算法。梯度下降就像一个盲人下山,他只能感觉到脚下的坡度,然后朝着坡度最陡的方向迈步,最终到达山谷(最小损失点)。

第四句:过拟合和欠拟合是模型复杂度和泛化能力之间的权衡。过拟合像是把教材背下来了但不会做新题;欠拟合像是连教材都没看懂。好的模型需要在这两者之间找到平衡。

第五句:数据质量往往比模型选择更重要。再好的模型也救不了垃圾数据。真实项目中,80%的时间都花在数据处理和特征工程上。


下篇预告

在下一篇文章中,我们将深入探讨具体的机器学习算法,从最基础的KNN、线性回归,到更强大的决策树、随机森林、XGBoost。我会通过大量的图解和代码示例,让你彻底理解每个算法的原理,并学会在实际项目中选择合适的算法。

敬请期待:《KNN到随机森林:常用机器学习算法的直观理解与实战》


参考资料

  • 机器学习经典教材:《机器学习》- 周志华(西瓜书)
  • 在线课程:吴恩达《Machine Learning》- Coursera
  • PyTorch官方文档:https://pytorch.org/docs/
  • Scikit-learn官方文档:https://scikit-learn.org/stable/

如果你觉得这篇文章有帮助,欢迎分享给需要的朋友。有任何问题或建议,也可以在评论区留言交流。

机器学习基础概念详解:从入门到应用 机器学习基础涵盖数据划分(训练/验证/测试集)、特征与标签定义、模型与算法区别、三大学习范式(监督/无监督/强化)、过拟合与欠拟合问题、误差分析及分类/回归评估指标,是入门与实践的核心知识框架。 阅读详情

相关推荐

ML-Agent:Unity机器学习插件的全面解析

ML-Agent是一个开源的机器学习插件,使得开发者可以通过Unity来训练智能体。这使得在游戏和模拟环境中,使用增强学习技术成为可能,为AI研究和应用提供了全新的实验平台。ML-Agent 为 Unity 环境提供了强大的机器学习工具,其核心功能的设计允许开发者构建和训练智能体,以及在复杂的环境中进行模拟训练。在本章中,我们将详细介绍 ML-Agent 的主要功能,包括多智能体系统支持、智能体间通信机制、延迟奖励机制、环境同步更新、内置评估工具,以及插件的可扩展性。

weixin_35433448的博客 1625

如何为iOS应用训练核心ML模型

您将要创造的 Core ML使iOS开发人员可以轻松地向其应用程序添加深度机器学习。 在本文中,我将向您展示如何训练Core ML模型以得出智能见解。 过去一年,机器学习无疑是最热门的主题之一,各种公司都在努力使他们的产品更加智能,以改善用户体验并使其产品脱颖而出。 根据麦肯锡2017年的《机器学习与人工智能状况》,仅去年一年,谷歌就在人工智能上投资了200亿至300亿美元。 人工智...

代码教主 1396

10xGenomics官方可视化工具——Loupe Browser

Loupe Browser是⼀款10xGenomics开发的交互式桌⾯应⽤程序,⽤于探索10x单细胞数据,可以用来找出感兴趣的细胞、找出显著差异表达的基因、鉴定细胞类型、探索细胞亚类和数据共享。

weixin_47195452的博客 3342

【赠书第19期】跨平台机器学习:ML.NET架构及应用编程

在微软最有价值专家(16届)的指导下,运用跨平台机器学习框架ML.NET来创建机器学习解决方案,将人工智能技术应用于实际任务场景中。

无人机开发(开源Ardupilot) 2万+

别再死记硬背了!用Python+Matlab/Simulink手把手带你理解PID控制器的‘稳、快、准’

本文通过Python编程和Matlab/Simulink仿真,深入解析PID控制器的‘稳、快、准’三大核心指标,帮助读者直观理解PID控制的实现原理与参数整定技巧。内容涵盖经典控制理论和自动控制原理,提供实战案例和高级调参技巧,适合工业自动化领域的学习者和工程师。

weixin_42551227的博客 367

别再死记公式了!用TL072运放设计带通滤波器,调出干净正弦波的实战心得与误区盘点

本文分享了使用TL072运放设计带通滤波器的实战经验,重点解决波形失真问题,提供单电源供电优化、动态调谐技巧及仿真与现实的参数修正方法,帮助工程师调出纯净正弦波。内容涵盖模拟电路设计中的常见误区与解决方案,适合电子工程师和爱好者参考。

weixin_29172963的博客 403

机器学习入门:从猜数游戏到房价预测模型

机器学习作为人工智能的核心技术,通过数据驱动的方式让计算机自动发现规律。其基本原理类似于猜数游戏中的反馈调整机制,通过损失函数量化预测误差,并利用梯度下降等优化算法不断调整模型参数。在工程实践中,特征工程和模型正则化是提升性能的关键,如对房屋面积、房龄等特征进行归一化处理,或采用L2正则化防止过拟合。典型的应用场景包括房价预测、推荐系统等结构化数据分析任务。本文以线性回归为例,演示如何构建端到端的机器学习流程,涵盖数据预处理、模型训练到部署上线的完整生命周期。

weixin_29184371的博客 214

c语言版数据结构课程设计 学生成绩管理系统

此学生成绩管理系统完成15项功能,是我经过很多次的修改得到的。花费时间不短,功能齐全,主要完成了:输入,输出,插入,修改,删除,查询,读取文件,写入文件,复制文件,建立索引,显示各种情况下的信息,追加学生信息等等功能。一共15项。   代码如下: // shujujiegou.cpp : 定义控制台应用程序的入口点。///**本程序采用数组链表形式,原因:数组查询速度快,数组也能实现动态存储

Java 1万+

【AI&游戏】Unity ML-Agents机器学习

本文系统介绍了Unity ML-Agents机器学习工具包在游戏开发中的应用。主要内容包括:1)机器学习基础理论,重点讲解强化学习核心概念;2)ML-Agents三大核心组件(Agent、Brain、Academy)的详细解析;3)从环境配置到模型训练的完整工作流程;4)高级训练技术如课程学习和模仿学习;5)实战案例演示战斗AI训练过程。文章还提供了性能优化建议和常见问题解决方案,帮助开发者快速掌握这一革命性工具,为游戏创造真正智能和自适应的AI角色。Unity ML-Agents通过机器学习技术,使游戏A

设计 AI 玩游戏🎮 1146

MT5策略如何设置回测结果才能最接近实盘

摘要:在MT5回测中,选择"每笔分笔报价"模式最接近实盘交易,因其使用真实Tick数据模拟价格波动、点差和滑点。关键设置包括:下载高质量历史数据、合理设定点差和滑点、使用正常回测速度。该模式能准确测试挂单、止盈止损等策略,虽然速度较慢但结果最可靠,避免其他模式造成的失真,是评估交易策略表现的最佳选择。(149字)

weixin_38915451的博客 1875

IGV实战指南:从数据导入到Peak可视化的全流程解析

本文提供了一份IGV实战指南,详细解析了从数据导入到Peak可视化的全流程。内容包括软件安装、参考基因组加载、测序数据处理、信号调整以及如何精准定位和可视化Peak区域,并分享了导出出版级矢量图的高级技巧,帮助用户高效完成基因组数据可视化分析。

weixin_29212867的博客 147

从猜数游戏入门机器学习:监督学习与梯度下降原理

监督学习是机器学习的核心范式,其通过带标签的训练数据构建预测模型,与猜数游戏中根据'大了/小了'反馈调整策略的原理高度一致。梯度下降作为优化算法的基础,模拟了人类根据误差逐步修正决策的过程,通过计算损失函数的负梯度方向更新模型参数。在实际工程中,合理设置学习率、选择适当的损失函数(如均方误差MSE)对模型收敛至关重要。从简单的线性回归到深度神经网络,这些基础概念构成了解决图像识别、推荐系统等复杂场景的技术基石。本文以经典猜数游戏为切入点,生动诠释了机器学习中的模型训练、反向传播等关键机制。

weixin_32296621的博客 249

Android11车机系统海外项目资源包RRO方案优化

本文介绍了汽车设置应用如何通过Android RRO(运行时资源叠加)方案实现多车型差异化资源管理。针对不同车型(国内/海外、轿车/SUV)和配置(方向盘、轮毂等),采用产品变体(productFlavors)构建不同APK版本,并通过JSON配置文件动态启用对应资源包。系统根据车辆下线配置自动匹配适用的资源叠加包,解决了硬编码判断带来的维护问题。该方案实现了资源的高效复用,同时支持灵活配置多种车型组合,为汽车行业多车型共平台开发提供了可扩展的技术实现。

shusuanly的博客 469

机器学习的 10 个核心概念,新手入门必看!

机器学习的核心概念是理解和应用机器学习的基础。掌握这些概念后,你可以更自信地探索更复杂的算法和应用。如果你是初学者,建议从 Scikit-Learn 开始练习,逐步深入学习深度学习和强化学习。希望本文能为你提供清晰的入门指南,祝你在机器学习的旅程中取得成功!🚀。

m0_66191515的博客 813

自动识别象棋棋子的OpenCV应用

在计算机视觉领域,OpenCV是一个广泛应用的开源计算机视觉库,它提供了丰富的图像处理和分析工具。本文将介绍如何使用OpenCV实现自动识别象棋棋子的功能,并提供相应的源代码。通过以上代码,我们可以实现对棋盘图像中棋子的自动识别。需要注意的是,以上代码只是一个简单的示例,实际应用中可能需要根据具体情况进行参数调整和算法优化,以获得更好的识别效果。函数利用预处理后的图像,寻找图像中的轮廓,并根据轮廓的面积筛选出可能的棋子轮廓,最后在原图像中提取棋子区域。在主程序中,我们读取输入图像,并调用。

WzisTypescript的博客 903

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Unity机器学习实战:手把手教你训练会“自学成才”的游戏角色!(ML-Agents完全指南)

的游戏智能体(Agent)!想象一下:你的游戏角色不再是你预设的木偶,而是能自己摸索着通关、对战、甚至发明新策略的家伙!是时候给你的游戏角色装上“会思考的大脑”了!你把Agent(学员)丢进场景(健身房),设定好规则和奖惩制度(训练目标),它就会在里面疯狂的试错、学习,最终练就一身“绝世武功”(智能行为)!先扔掉你对“机器学习=高深数学=博士生专用”的刻板印象!(重要的事情说三遍)理论吹得再响,不如一行代码(哦不,这次可能真不需要几行代码)!的训练场:让一个小方块(Agent)学会从起点移动到目标点。

y5t3m4dm1n的博客 1126

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Python 中的机器学习入门:核心概念与线性回归实践

机器学习 (Machine Learning, ML)是人工智能的一个分支,它赋予计算机从数据中学习的能力,而无需进行明确的编程。简单来说,机器学习模型通过分析大量数据来识别模式、做出预测或决策,并随着新数据的输入和反馈而不断改进其性能。其核心思想是,不是告诉计算机如何解决某个特定问题,而是给它足够的数据,让它自己发现解决问题的方法。Python 在机器学习领域之所以如此受欢迎,很大程度上得益于其强大的生态系统和丰富的第三方库。线性回归 (Linear Regression)

weixin_42107409的博客 1001

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Unity ML-Agents 入门指南:从零开始训练3D平衡球AI

Unity ML-Agents 入门指南:从零开始训练3D平衡球AI 【免费下载链接】ml-agents Unity-Technologies/ml-agents: 是一个基于 Python 语言的机器学习库,可以方便地实现机器学习算法的实现和测试。该项目提供了一个简单易用的机器学习库,可以方便地实现机器学习算法的实现和...

gitblog_01196的博客 480

机器学习入门全解析:从概念到实践,一文打通核心知识

机器学习入门全解析!!!

小白成长之路 1152

Unity机器学习实战:手把手教你用ml-agents打造会学习的游戏NPC!(零基础友好)

传统的游戏AI(比如状态机、行为树)像是给NPC写好了厚厚的剧本,每一步都规定得死死的。而机器学习驱动的AI,更像是给了NPC一个目标和一个环境,让它自己摸索、试错,最终找到达成目标的最佳策略!你的敌人会学习玩家的战斗风格,动态调整策略?(再也不是无脑冲锋了!你的NPC伙伴能适应不同的任务场景,做出更合理的决策?(告别木头人队友!甚至,游戏里的虚拟生物可以进化出独特的行为模式?(生态模拟搞起来!ml-agents就是Unity官方为开发者提供的这座连接游戏世界与机器学习的桥梁!

pythonphoenix的博客 2133

Open3D-ML:扩展3D机器学习任务的强大工具

Open3D-ML 是 Open3D 核心库的一个扩展,专门用于3D数据的机器学习任务。这个项目在 Open3D 的基础上增加了机器学习工具,使得3D数据处理变得更加高效。Open3D-ML 专注于诸如语义点云分割等应用,并提供了一系列预训练模型以及训练管道,以方便用户快速应用和开发。 ## 项目技术分析 Open3D-ML 的设计目标是提供一个易于使用、高度集成的环境,支持 TensorFl...

gitblog_00680的博客 880

【机器学习入门宝典:核心概念 + 应用全图谱】

告别“不明觉厉”:一次搞懂机器学习是啥

dally2的博客 716

全面详解机器学习核心概念与算法:从基础到高级应用

机器学习是人工智能的核心分支,通过算法让计算机从数据中自动学习规律并做出预测或决策,无需显式编程。其核心在于​​数据驱动​​,利用统计学、优化理论等跨学科方法构建数学模型,实现分类、回归、聚类等任务。根据学习范式,机器学习分为: ​​监督学习​​(如线性回归、决策树),依赖标注数据训练模型; ​​无监督学习​​(如K-means、PCA),挖掘无标签数据的内在结构; ​​强化学习​​(如Q-learning),通过试错与奖励机制优化决策策略。 集成学习(如Bagging、Boosting)通过组合多个弱学

weixin_67868534的博客 1294

【GitHub项目推荐--ML For Beginners:微软的机器学习入门课程】

​​ 是微软开发的一个为期12周的机器学习入门课程,包含26节课和52个测验,专为初学者设计。该课程专注于经典机器学习技术,使用Scikit-learn库,避免深度学习内容,为学习者提供扎实的机器学习基础。

j8267643的博客 1105

Unity ML-Agents 工具包深度解析:游戏AI开发新范式

Unity ML-Agents 工具包深度解析:游戏AI开发新范式 【免费下载链接】ml-agents Unity-Technologies/ml-agents: 是一个基于 Python 语言的机器学习库,可以方便地实现机器学习算法的实现和测试。该项目提供了一个简单易用的机器学习库,可以方便地实现机器学习算法的实现和测...

gitblog_00070的博客 451

如何使用 Unity ML-Agents 快速开发智能游戏AI:完整入门指南

Unity ML-Agents 是一个基于 Python 的开源机器学习库,它允许开发者在 Unity 环境中训练智能体,通过强化学习等算法实现复杂的AI行为。无论是游戏开发、机器人模拟还是教育研究,这个强大的工具包都能帮助你轻松构建和测试AI模型。 ## 🌟 Unity ML-Agents 核心功能与优势 Unity ML-Agents 提供了一套完整的工具链,让AI开发变得简单直观:

gitblog_00434的博客 429
上一篇: 大模型推理成本优化指南:在生产环境中如何兼顾质量与效率
下一篇: KNN到随机森林:常用机器学习算法的直观理解与实战
玄同765
玄同765 新星创作者: 人工智能技术领域 新星创作者: 人工智能技术领域
博客等级 码龄6年 1万+粉丝 262原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值