下载数据集

# 导入所需的库
import hashlib      # 用于计算文件的SHA-1哈希值,验证文件完整性
import os           # 用于操作系统路径、目录等操作
import tarfile      # 用于处理.tar或.gz压缩文件
import zipfile      # 用于处理.zip压缩文件
import requests     # 用于发送HTTP请求,下载文件

# @save 是d2l库的标记,表示该函数会被保存或复用
DATA_HUB = dict()   # 全局字典,存储数据集名称和对应的(URL, SHA-1哈希值)
DATA_URL = 'http://d2l-data.s3-accelerate.amazonaws.com/'  # 数据集基础URL

def download(name, cache_dir=os.path.join('..', 'data')):  #@save
    """下载一个DATA_HUB中的文件,返回本地文件名"""
    # 断言:确保要下载的文件名在DATA_HUB中已定义
    assert name in DATA_HUB, f"{name} 不存在于 {DATA_HUB}"
    
    # 从DATA_HUB获取URL和期望的SHA-1哈希值
    url, sha1_hash = DATA_HUB[name]
    
    # 创建缓存目录(如果不存在)
    os.makedirs(cache_dir, exist_ok=True)
    
    # 生成本地文件路径:缓存目录 + URL中的文件名
    fname = os.path.join(cache_dir, url.split('/')[-1])
    
    # 如果文件已存在,检查其哈希值是否匹配
    if os.path.exists(fname):
        sha1 = hashlib.sha1()
        # 以二进制模式打开文件,分块读取(每次1MB)
        with open(fname, 'rb') as f:
            while True:
                data = f.read(1048576)  # 1MB = 1024 * 1024
                if not data:
                    break
                sha1.update(data)
        # 如果哈希值匹配,直接返回缓存的文件路径
        if sha1.hexdigest() == sha1_hash:
            return fname  # 命中缓存
    
    # 如果文件不存在或哈希不匹配,则重新下载
    print(f'正在从{url}下载{fname}...')
    r = requests.get(url, stream=True, verify=True)  # 发送GET请求下载文件
    with open(fname, 'wb') as f:
        f.write(r.content)  # 将下载的内容写入文件
    return fname

def download_extract(name, folder=None):  #@save
    """下载并解压zip/tar文件"""
    fname = download(name)  # 调用download函数获取文件路径
    base_dir = os.path.dirname(fname)  # 获取文件所在目录
    data_dir, ext = os.path.splitext(fname)  # 分离文件名和扩展名
    
    # 根据扩展名选择解压方式
    if ext == '.zip':
        fp = zipfile.ZipFile(fname, 'r')  # 打开ZIP文件
    elif ext in ('.tar', '.gz'):
        fp = tarfile.open(fname, 'r')     # 打开TAR/GZ文件
    else:
        assert False, '只有zip/tar文件可以被解压缩'
    
    # 解压到基础目录
    fp.extractall(base_dir)
    
    # 如果指定了子文件夹,返回该子文件夹路径;否则返回解压后的目录
    return os.path.join(base_dir, folder) if folder else data_dir

def download_all():  #@save
    """下载DATA_HUB中的所有文件"""
    for name in DATA_HUB:
        download(name)

# 如果没有安装pandas,请取消下一行的注释
# !pip install pandas

# 设置matplotlib为内联模式,图像直接显示在Notebook中
%matplotlib inline

# 导入常用库
import numpy as np       # 数值计算库
import pandas as pd      # 数据处理和分析库
import torch             # PyTorch深度学习框架
from torch import nn     # PyTorch神经网络模块
from d2l import torch as d2l  # 导入d2l的PyTorch版本

# 定义Kaggle房价预测训练集的信息
DATA_HUB['kaggle_house_train'] = (  #@save
    DATA_URL + 'kaggle_house_pred_train.csv',  # 文件URL
    '585e9cc93e70b39160e7921475f9bcd7d31219ce')  # 文件的SHA-1哈希值

# 定义Kaggle房价预测测试集的信息
DATA_HUB['kaggle_house_test'] = (  #@save
    DATA_URL + 'kaggle_house_pred_test.csv',
    'fa19780a7b011d9b009e8bff8e99922a8ee2eb90')

# 下载并读取训练数据到pandas DataFrame
train_data = pd.read_csv(download('kaggle_house_train'))

# 下载并读取测试数据到pandas DataFrame
test_data = pd.read_csv(download('kaggle_house_test'))

主要功能总结:

  1. download():智能下载文件,支持缓存和完整性校验(SHA-1)。

  2. download_extract():下载并自动解压压缩文件。

  3. download_all():批量下载所有数据集。

结果:

数据预处理(key 不熟)

all_features = pd.concat(
    (train_data.iloc[:, 1:-1], 
     test_data.iloc[:, 1:])
)

把训练集的特征列和测试集的特征列拼在一起,形成一个新的 DataFrame(因为是pandas)。(没想到)

合并训练和测试集的特征(为了统一预处理)

结果:

填充缺失值和归一化特征

# 特征预处理
# 1. 识别数值特征
numeric_features = all_features.dtypes[all_features.dtypes != 'object'].index

# 2. 数值特征标准化(Z-score标准化)
# 注意:这里使用了整个数据集(训练+测试)计算均值和标准差
# 实际生产中应该只使用训练集统计量
all_features[numeric_features] = all_features[numeric_features].apply(
    lambda x: (x - x.mean()) / (x.std())
)

# 3. 标准化后,缺失值用0填充(因为标准化后均值为0)
all_features[numeric_features] = all_features[numeric_features].fillna(0)

# 4. 类别特征进行独热编码,dummy_na=True会将缺失值也视为一个类别
all_features = pd.get_dummies(all_features, dummy_na=True)

# 获取特征数量
print(f"预处理后的特征维度: {all_features.shape}")

# 分离回训练和测试集
n_train = train_data.shape[0]  # 训练集样本数
train_features = torch.tensor(all_features[:n_train].values, dtype=torch.float32)
test_features = torch.tensor(all_features[n_train:].values, dtype=torch.float32)

# 获取训练标签
train_labels = torch.tensor(
    train_data.SalePrice.values.reshape(-1, 1), dtype=torch.float32
)

# 打印数据形状
print(f"训练特征形状: {train_features.shape}")
print(f"训练标签形状: {train_labels.shape}")
print(f"测试特征形状: {test_features.shape}")
1细节 处理连续数据 取出数字列

指的是和object比较得到结果是布尔型序列(因为有很多个特征列) 下图所示

取出索引(类似于字典)

2细节 数字列归一化

先标准化再填充缺失值

处理离散特征,独热编码:

机器学习中处理离散特征(分类特征)的一种常用方法,叫做独热编码(One-Hot Encoding)

简单来说,它的目的是把文字类别变成计算机能读懂的数字向量

1. 为什么要这么做?

原始的表格里,像 MSZoning( zoning 分类)这样的列,里面的值是文字,比如 "RL"(住宅低密), "RM"(住宅中等密), 或者是空的(NaN)。

  • 计算机不认识字:模型只能计算数字。

  • 不能随便编数字:如果你把 "RL" 编成 1,"RM" 编成 2,模型可能会误以为 "RM" 比 "RL" 大,或者它们有高低之分,但这在现实中是不成立的(它们是平等的类别)。

2. 它是怎么工作的?(以 "RL" 为例)

独热编码的做法是:既然它们是平等的,那就给每个类别发一个专属的“开关”(0或1)。

不再有MSZoning这个列了

检查结果是否正确:
# 检查每一列的数据类型
print(all_features.dtypes)

# 找出所有非数值类型的列(object 或 string)
non_numeric_cols = all_features.select_dtypes(include=['object', 'string']).columns
print("以下列是非数值类型,导致了报错:")
print(non_numeric_cols)

弄出训练集和测试集(分割,因为最开始时候concat了)

通过values属性,我们可以 [pandas格式中提取NumPy格式,并将其转换为张量表示]用于训练。

# 获取训练集的样本数量(行数)
n_train = train_data.shape[0]  # train_data.shape[0]返回训练数据的行数,即样本数量

# 从合并的特征数据all_features中取出前n_train行作为训练特征
# all_features[:n_train] 通过切片获取前n_train行(训练集部分)
# .values 将DataFrame转换为NumPy数组
# torch.tensor(...) 将NumPy数组转换为PyTorch张量,并指定数据类型为float32
train_features = torch.tensor(all_features[:n_train].values, dtype=torch.float32)

# 从合并的特征数据all_features中取出从n_train行开始到最后一行的数据作为测试特征
# all_features[n_train:] 获取从第n_train行开始到最后一行的数据(测试集部分)
# 同样转换为PyTorch张量
test_features = torch.tensor(all_features[n_train:].values, dtype=torch.float32)

# 获取训练集的标签(房价)
# train_data.SalePrice 是训练集中的房价列
# .values 转换为NumPy数组
# .reshape(-1, 1) 将一维数组转换为二维数组,形状为[n, 1](n行1列)
# 这里-1表示自动计算该维度的大小,即自动根据原数组元素数量和指定的其他维度(1)来推断
# 例如,原数组有1460个元素,reshape(-1, 1)就会转换成1460行1列的二维数组
# 最后将其转换为PyTorch张量,数据类型为float32
train_labels = torch.tensor(
    train_data.SalePrice.values.reshape(-1, 1), dtype=torch.float32)

训练:

以简单的线性模型为baseline作为对比的

# 定义均方误差损失函数(Mean Squared Error Loss)
loss = nn.MSELoss()

# 获取输入特征的维度,即特征的数量
# train_features.shape[1] 返回训练特征张量的列数,即每个样本的特征数
in_features = train_features.shape[1]

# 定义一个函数用于创建神经网络模型
def get_net():
    # 使用nn.Sequential定义一个简单的线性回归模型
    # 该模型只包含一个全连接层(Linear),输入维度为in_features,输出维度为1
    net = nn.Sequential(nn.Linear(in_features,1))
    return net

# 定义一个函数,计算对数均方根误差(Log Root Mean Squared Error)
# 在房价预测任务中,通常使用对数均方根误差作为评估指标,因为房价的分布通常是偏态的,取对数可以使误差更接近正态分布
def log_rmse(net, features, labels):
    # 使用模型net对特征features进行预测
    # 通过torch.clamp将预测值限制在1到正无穷之间,避免取对数时出现负值或零(因为log(0)是负无穷,log(负数)是NaN)
    clipped_preds = torch.clamp(net(features), 1, float('inf'))
    # 计算对数均方根误差:
    # 1. 对预测值和真实值分别取对数
    # 2. 计算两者之间的均方误差(使用之前定义的MSE损失函数)
    # 3. 对均方误差开方,得到均方根误差
    rmse = torch.sqrt(loss(torch.log(clipped_preds),
                           torch.log(labels)))
    # 返回一个标量(Python浮点数),通过.item()将张量转换为浮点数
    return rmse.item()

# 定义训练函数
def train(net, train_features, train_labels, test_features, test_labels,
          num_epochs, learning_rate, weight_decay, batch_size):
    # 初始化两个列表,分别用于记录训练集和测试集在每个epoch后的对数均方根误差
    train_ls, test_ls = [], []
    
    # 使用d2l库中的load_array函数,将训练特征和训练标签转换为一个可以迭代的数据加载器
    # 每次迭代返回一个批次的数据(包含batch_size个样本)
    train_iter = d2l.load_array((train_features, train_labels), batch_size)
    
    # 定义优化器,这里使用Adam优化算法
    # net.parameters()返回网络中所有需要训练的参数
    # lr:学习率
    # weight_decay:权重衰减(L2正则化)系数,用于防止过拟合
    optimizer = torch.optim.Adam(net.parameters(),
                                 lr = learning_rate,
                                 weight_decay = weight_decay)
    
    # 开始训练,迭代num_epochs个周期
    for epoch in range(num_epochs):
        # 每个epoch中,遍历数据加载器中的每一个批次
        for X, y in train_iter:
            # 在计算梯度之前,先将优化器中之前存储的梯度清零
            optimizer.zero_grad()
            # 前向传播:计算模型在当前批次上的预测值,并计算损失
            l = loss(net(X), y)
            # 反向传播:计算损失函数关于模型参数的梯度
            l.backward()
            # 更新模型参数:根据梯度使用优化器更新参数
            optimizer.step()
        # 一个epoch结束后,计算整个训练集上的对数均方根误差,并记录
        train_ls.append(log_rmse(net, train_features, train_labels))
        # 如果提供了测试标签(即test_labels不为None),则计算测试集上的对数均方根误差并记录
        if test_labels is not None:
            test_ls.append(log_rmse(net, test_features, test_labels))
    # 返回训练和测试过程中每个epoch的对数均方根误差列表
    return train_ls, test_ls

k折交叉验证:重点

获取k折数据+进行k折验证:

# 定义一个函数,用于获取K折交叉验证中第i折的训练数据和验证数据
def get_k_fold_data(k, i, X, y):
    # 断言k必须大于1,因为至少需要2折才能进行交叉验证
    assert k > 1
    # 计算每一折的大小(样本数),这里使用整数除法,所以可能不能整除,余数部分被忽略
    fold_size = X.shape[0] // k
    # 初始化训练数据和标签为None
    X_train, y_train = None, None
    # 遍历k折
    for j in range(k):
        # 计算当前折的索引范围,slice对象用于切片
        idx = slice(j * fold_size, (j + 1) * fold_size)
        # 根据索引切片获取当前折的特征和标签
        X_part, y_part = X[idx, :], y[idx]
        # 如果当前折是第i折,则作为验证集
        if j == i:
            X_valid, y_valid = X_part, y_part
        # 否则,将当前折合并到训练集中
        # 如果训练集为空,则直接赋值
        elif X_train is None:
            X_train, y_train = X_part, y_part
        # 如果训练集不为空,则通过torch.cat在0维度(行方向)进行拼接
        else:
            X_train = torch.cat([X_train, X_part], 0)
            y_train = torch.cat([y_train, y_part], 0)
    # 返回训练集特征、训练集标签、验证集特征、验证集标签
    return X_train, y_train, X_valid, y_valid

# 定义一个函数,执行K折交叉验证
def k_fold(k, X_train, y_train, num_epochs, learning_rate, weight_decay,
           batch_size):
    # 初始化训练和验证误差总和
    train_l_sum, valid_l_sum = 0, 0
    # 遍历每一折
    for i in range(k):
        # 获取当前折的训练和验证数据
        data = get_k_fold_data(k, i, X_train, y_train)
        # 创建一个新的网络模型
        net = get_net()
        # 训练模型,并返回训练和验证的误差列表
        # 注意:这里使用了*data将返回的四个值作为参数传递给train函数
        train_ls, valid_ls = train(net, *data, num_epochs, learning_rate,
                                   weight_decay, batch_size)
        # 将最后一轮的训练和验证误差累加到总和中
        train_l_sum += train_ls[-1]
        valid_l_sum += valid_ls[-1]
        # 如果是第一折,绘制训练和验证误差曲线
        if i == 0:
            d2l.plot(list(range(1, num_epochs + 1)), [train_ls, valid_ls],
                     xlabel='epoch', ylabel='rmse', xlim=[1, num_epochs],
                     legend=['train', 'valid'], yscale='log')
        # 打印当前折的训练和验证误差(最后一轮)
        print(f'折{i + 1},训练log rmse{float(train_ls[-1]):f}, '
              f'验证log rmse{float(valid_ls[-1]):f}')
    # 返回K折交叉验证的平均训练误差和平均验证误差
    return train_l_sum / k, valid_l_sum / k

核心思想:把训练数据分成K份,轮流用其中K-1份训练,1份验证,重复K次,取平均结果。

类比

你有5个老师教同一个学生,每个老师用4/5的内容教,用剩下的1/5考试,最后看5个老师的平均分数。

例子:

eg:

# 遍历5折
for j in range(5):
    idx = slice(j*200, (j+1)*200)  # 当前折的索引范围
    
    if j == 0:  # 第0折 → 验证集
        X_valid, y_valid = X[0:200], y[0:200]
    elif j == 1:  # 第1折 → 训练集第一部分
        X_train, y_train = X[200:400], y[200:400]
    else:  # 第2,3,4折 → 拼接到训练集
        X_train = torch.cat([X_train, X[400:600]], 0)  # 第2折
        # ...继续拼接
划分数据代码解读:

我习惯第一种拼接写法
# 对比两种写法:

# 写法1:先创建空列表,再拼接
X_train_parts = []
for j in range(k):
    if j != i:  # 如果不是验证折
        X_train_parts.append(X_part)
# 最后用torch.cat拼接所有部分

# 写法2:当前代码的写法
X_train = None
for j in range(k):
    if j != i:  # 如果不是验证折
        if X_train is None:  # 第一次遇到训练折
            X_train = X_part
        else:  # 后续训练折
            X_train = torch.cat([X_train, X_part], 0)

0 1是dim参数的值

验证代码解读:

------------------

----------------------

train_l_sum += train_ls[-1]  # 只取最后一个epoch来加入
# 但有时最佳模型在中间epoch
# 应该取验证误差最小的那个epoch  但为了初学者懂

 train_ls, valid_ls = train(net, *data, num_epochs, learning_rate,
                                   weight_decay, batch_size)
        train_l_sum += train_ls[-1]
        valid_l_sum += valid_ls[-1]

和return train_l_sum / k, valid_l_sum / k 关系:

每个epoch都进行k折验证

 train_ls, valid_ls是训练了num_epochs的结果 最后 train_l_sum每次都只用最后一个epoch结果

所以最后 train_l_sum就只包含了k份数据,然后➗️得到平均值

模型选择(调参数):
先用部分数据(比如下图的某折来验证)来调参
k, num_epochs, lr, weight_decay, batch_size = 5, 100, 5, 0, 64
train_l, valid_l = k_fold(k, train_features, train_labels, num_epochs, lr,
                          weight_decay, batch_size)
print(f'{k}-折验证: 平均训练log rmse: {float(train_l):f}, '
      f'平均验证log rmse: {float(valid_l):f}')

上图是选择了一组未调优的超参数,并将其留给读者来改进模型。 找到一组调优的超参数可能需要时间,这取决于一个人优化了多少变量。 有了足够大的数据集和合理设置的超参数,折交叉验证往往对多次测试具有相当的稳定性。 然而,如果我们尝试了不合理的超参数,我们可能会发现验证效果不再代表真正的误差。

有时一组超参数的训练误差可能非常低,但折交叉验证的误差要高得多, 这表明模型过拟合了。 在整个训练过程中,我们希望监控训练误差和验证误差这两个数字。 较少的过拟合可能表明现有数据可以支撑一个更强大的模型, 较大的过拟合可能意味着我们可以通过正则化技术来获益。

用全部数据(已经得到合适的超参数了)来训练:
def train_and_pred(train_features, test_features, train_labels, test_data,
                   num_epochs, lr, weight_decay, batch_size):
    """
    完整的训练和预测函数
    
    参数:
    train_features: 训练集特征 (Tensor)
    test_features: 测试集特征 (Tensor)
    train_labels: 训练集标签 (Tensor)
    test_data: 原始的测试数据集 (Pandas DataFrame,包含Id列)
    num_epochs: 训练轮数
    lr: 学习率
    weight_decay: 权重衰减 (L2正则化系数)
    batch_size: 批次大小
    """
    
    # 1. 创建新的神经网络模型实例
    net = get_net()
    
    # 2. 使用全部训练数据训练模型
    # train函数的第4、5个参数设为None,表示不传入验证集/测试集
    # 所以只返回训练误差列表train_ls,第二个返回值用_接收表示忽略
    train_ls, _ = train(net, train_features, train_labels, None, None,
                        num_epochs, lr, weight_decay, batch_size)
    
    # 3. 绘制训练误差随训练轮次变化的曲线
    d2l.plot(np.arange(1, num_epochs + 1),  # x轴:1到num_epochs
             [train_ls],                     # y轴:训练误差列表
             xlabel='epoch',                 # x轴标签
             ylabel='log rmse',              # y轴标签
             xlim=[1, num_epochs],           # x轴范围
             yscale='log')                   # y轴使用对数刻度(误差值通常较小)
    
    # 4. 打印最终训练误差
    print(f'训练log rmse:{float(train_ls[-1]):f}')
    
    # 5. 使用训练好的模型在测试集上进行预测
    # net(test_features):模型前向传播,得到预测结果
    # .detach():从计算图中分离,不记录梯度
    # .numpy():转换为NumPy数组
    preds = net(test_features).detach().numpy()
    
    # 6. 将预测结果重新格式化以便导出到Kaggle
    # preds.reshape(1, -1):将预测结果重塑为1行多列的二维数组
    # [0]:取第一行(因为是1行,所以就是取所有预测值)
    # pd.Series:转换为Pandas Series,方便添加到DataFrame
    test_data['SalePrice'] = pd.Series(preds.reshape(1, -1)[0])
    
    # 7. 创建提交文件
    # 提取测试集的Id列和预测的SalePrice列
    submission = pd.concat([test_data['Id'], test_data['SalePrice']], axis=1)
    
    # 8. 将结果保存为CSV文件,用于Kaggle提交
    # index=False:不保存行索引
    submission.to_csv('submission.csv', index=False)

train_and_pred(train_features, test_features, train_labels, test_data,
               num_epochs, lr, weight_decay, batch_size)

输入数据
    ↓
创建新模型
    ↓
用全部训练数据训练

    ↓
绘制训练误差曲线
    ↓
打印最终训练误差
    ↓
在测试集上预测
    ↓
格式化预测结果
    ↓
保存为提交文件

细节:

竞赛总结:

10行代码战胜90%数据科学家?

10行代码战胜90%数据科学家?_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1rh411m7Hb/?from=search&seid=14820697425740410884&spm_id_from=333.788.comment.all.click&vd_source=5252d3cdd5246bf9326ccfc5acb9064410行代码战胜90%数据科学家?_哔哩哔哩_bilibili
第三h2o:

https://www.kaggle.com/wuwawa/automl-using-h2o
第四 随机森林:

https://www.kaggle.com/jackzh/the-4th-place-approach-random-forest

https://www.bilibili.com/video/BV15Q4y1o7vc/?spm_id_from=333.999.0.0&vd_source=5252d3cdd5246bf9326ccfc5acb90644

MLP效果不好

eg:

1有些特征文本很多,比如房子介绍

可以直接舍弃文本信息/transform等处理 但不能onehot编码,因为不会有两个文本一样的数据,这样维度就很高了,数据里面是10w条这样

2 数据较大

房子价格美金 差距很大,可以先取log再归一化处理

评分较高的automl:一样是集成模型

【机器学习】解放双手!AutoML入门:从原理到Auto-sklearn实战,告别繁琐调参_automl 开源框架-CSDN博客

一、 文本特征(地址、介绍)怎么处理?

在传统的机器学习中,直接把“我爱我家,温馨两居”这种文本扔进树模型(如XGBoost/LightGBM)是不行的。不能直接塞进去,必须先进行“结构化”或“向量化”提取。

1. 地址类文本:靠“正则表达式”提取标签

地址往往很长,但包含的关键信息(学区、地铁、商圈)对房价影响巨大。不要试图把整个地址字符串当作一个特征,而是要用正则把关键信息抠出来变成数值或类别:

  • 提取硬性配套:用正则匹配是否包含“地铁”、“学区”、“三甲医院”、“万达广场”等关键词,转换成 has_subway(0或1)、school_district(学区等级) 等布尔或数值特征。

  • 结构化解析:比如把“广州市天河区珠江新城保利心语”拆解成 城市=广州行政区=天河商圈=珠江新城小区=保利心语

  • 高阶玩法(聚类):如果小区名称有几千个,可以计算每个小区的历史均价,然后用 K-Means 把这几千个小区聚类成 5-10 个档次(如:豪宅盘、刚需盘),用聚类的标签代替原始小区名,既降维又保留了地理价值。

2. 介绍类文本(房源描述):靠“Embedding”获取语义

对于“南北通透,采光极佳,拎包入住”这种描述心情和状态的文本:

  • 传统方法(TF-IDF):简单粗暴,把词变成数字。但如果介绍太长,维度会爆炸,容易过拟合。

  • 深度学习方法(强烈推荐):使用 NLP 领域的预训练模型(如 BERT、Word2Vec)。

    • 把一段介绍文本输入 BERT,它会输出一个固定长度(比如 768 维)的向量。

    • 这个向量就代表了这段描述的“整体语义氛围”。

    • 将这个向量作为额外的特征拼接到你的表格数据中,能让模型理解“豪华装修”和“毛坯简装”在语义上的巨大差异。


二、 公榜和私榜是什么意思?

这是数据科学竞赛(如 Kaggle)最核心的机制,也是你提到的第三点“数据切分”的真正用意。

1. 基本定义

  • 公榜 (Public Leaderboard):比赛期间实时更新的排行榜。你的模型在一部分隐藏的测试数据上跑出的分数会显示在这里,所有人都能看到你的实时排名。

  • 私榜 (Private Leaderboard):比赛结束后才揭晓的排行榜。你的模型在另一部分更深度的隐藏数据上跑分,这决定了你的最终奖金和获奖资格。

2. 为什么要分公榜和私榜?(防作弊与防过拟合)

这就回到了你说的“时间切分”:前6个月训练,公榜是后3个月,私榜是再后3个月

  • 公榜的作用:给你的模型一个“试错反馈”。让你知道模型能不能推广到稍微未来的数据。

  • 私榜的作用终极审判。用来检验你的模型是不是真的学到了普适规律,还是在公榜那3个月的数据上“死记硬背”(过拟合)了。

3. 实战中的“致命陷阱”:Shake-Up(排名震荡)

如果你为了让公榜排名更高,疯狂地针对公榜那3个月的数据调参、加特征,你的模型就会完美适应公榜,但到了私榜(再后3个月,市场行情可能变了,尤其这个房价预测,波动太大了)就会一塌糊涂。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐