You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

考虑用户行为的时间序列数据拆分:避泄漏且贴近70:30比例

问题分析与解决方案

你的核心问题在于当前代码对每个(user_id, time)组内部进行行级拆分,这不仅违反了“同一用户同一天记录不能拆分”的规则(直接导致数据泄漏),还因为不同组的大小差异,使得整体比例偏离70:30的目标。

正确的思路应该是:以**(user_id, time)为完整单位**,要么整个组进入训练集,要么整个组进入测试集;同时利用数据已按时间排序的特性,按时间顺序累加组的大小,找到最接近总数据量70%的分割点,确保训练集全为历史数据、测试集全为未来数据,彻底避免泄漏。

调整后的代码实现

1. 生成正确的分组掩码

import pandas as pd

# 计算每个(user_id, time)组的行数
group_sizes = user_prod_data.groupby(['user_id', 'time']).size().reset_index(name='row_count')
# 按时间顺序计算累计行数(数据已按时间排序,组顺序天然符合时间逻辑)
group_sizes['cumulative_rows'] = group_sizes['row_count'].cumsum()

total_rows = group_sizes['cumulative_rows'].iloc[-1]
target_train_rows = total_rows * 0.7

# 找到最接近目标训练行数的分割点
split_index = group_sizes[group_sizes['cumulative_rows'] >= target_train_rows].index[0]
# 比较前一个组和当前组的累计行数,选择更接近目标的分割位置
if split_index > 0:
    prev_cum = group_sizes['cumulative_rows'].iloc[split_index - 1]
    curr_cum = group_sizes['cumulative_rows'].iloc[split_index]
    if (target_train_rows - prev_cum) > (curr_cum - target_train_rows):
        split_index += 1

# 筛选出属于训练集的组
train_groups = group_sizes.iloc[:split_index][['user_id', 'time']]
# 生成掩码:行所在组属于训练集则为True,否则为False
mask = user_prod_data.merge(train_groups, on=['user_id', 'time'], how='left').notna().any(axis=1).tolist()

2. TensorFlow数据集拆分代码(无需修改)

你的TensorFlow拆分逻辑本身没问题,直接使用上面生成的mask即可:

import tensorflow as tf

def splitting_data_tf(data_tf: tf.data.Dataset, use_time: bool, mask: list, random_seed: int = 18):
    """
    Split TF data into train and tests
    :param data_tf:
    :param use_time:
    :param mask:
    :param random_seed:
    :return:
    """
    tf.random.set_seed(random_seed)

    mask_tensor = tf.constant(mask, dtype=tf.bool)

    train = data_tf.enumerate().filter(lambda idx, _: mask_tensor[idx])
    test = data_tf.enumerate().filter(lambda idx, _: ~mask_tensor[idx])

    # Remove enumeration indices
    train = train.map(lambda idx, x: x)
    test = test.map(lambda idx, x: x)

    cached_train = train.apply(tf.data.experimental.dense_to_ragged_batch(batch_size=512)).cache()
    cached_test = test.apply(tf.data.experimental.dense_to_ragged_batch(batch_size=512)).cache()
    
    return cached_train, cached_test

关键说明

  • 拆分逻辑完全基于时间顺序,保证训练集都是测试集的历史数据,符合“用历史行为预测未来”的需求;
  • 每个(user_id, time)组作为整体拆分,彻底避免了同一用户同一天记录跨集的泄漏问题;
  • 通过累计组大小找分割点,能让整体比例尽可能接近70:30,误差仅来自组的最小粒度(即无法拆分单个组)。

内容的提问来源于stack exchange,提问作者Yana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 15:12:08