如何在R中按Cost比例拆分数据集并保证ObjectID唯一分组
解决方案:按ObjectID分组并保持Cost比例的数据集拆分
要实现每个ObjectID仅属于训练/测试组一组,同时保持Cost的整体比例,你需要先按ObjectID聚合总Cost,再基于这个聚合后的总Cost进行分层抽样,最后映射回原始数据集。以下是具体步骤和R代码示例:
步骤1:准备数据并按ObjectID聚合总Cost
首先我们需要计算每个ObjectID的总Cost,这样就能基于每个ID对整体Cost的贡献来抽样,确保最终拆分的Cost比例符合要求:
# 加载必要的包 library(dplyr) library(caret) # 示例数据(替换成你的实际数据集即可) data <- tibble( ObjectID = c(12345,12345,12345,12345,11111,11111,22222,22222,22222,33333,33333,44444,44444,44444,44444,55555,55555,55555), Cost = c(1624,1175,1049,1733,1945,1989,1448,1815,1244,1355,1134,1478,1082,1147,1290,1383,1378,1288), Type = c(rep("Test",4), rep("Train",2), rep("Test",3), rep("Train",2), rep("Train",4), rep("Train",3)) ) # 按ObjectID聚合,计算每个ID的总Cost id_cost_summary <- data %>% group_by(ObjectID) %>% summarise(TotalCost = sum(Cost), .groups = "drop")
步骤2:基于总Cost进行分层抽样,确保每个ID仅在一组
这里用caret包的createDataPartition函数,它会根据目标变量(这里是TotalCost)的分布来抽样,保证训练集和测试集的Cost比例接近你设定的拆分比例:
# 设置拆分比例(70%训练,30%测试) split_ratio <- 0.7 # 基于每个ID的TotalCost创建拆分索引,维持比例 train_id_indices <- createDataPartition(id_cost_summary$TotalCost, p = split_ratio, list = FALSE) # 提取训练组和测试组的ObjectID train_ids <- id_cost_summary$ObjectID[train_id_indices] test_ids <- id_cost_summary$ObjectID[-train_id_indices]
步骤3:将原始数据映射到训练/测试组
最后把原始数据中的每条记录根据ObjectID分配到对应的组:
# 给原始数据添加分组标签 data_split <- data %>% mutate(Group = ifelse(ObjectID %in% train_ids, "Train", "Test")) # 验证结果:检查训练组的总Cost占比 total_cost <- sum(data$Cost) train_total_cost <- sum(data_split %>% filter(Group == "Train") %>% pull(Cost)) cat("训练组Cost占比:", round(train_total_cost / total_cost, 2), "\n")
关键说明
- 这种方法彻底避免了同一个ObjectID的记录被拆分到两组的情况,完全符合你的需求。
- 通过基于每个ID的总Cost抽样,能确保训练集和测试集的整体Cost比例尽可能接近设定值。
- 如果需要更精确的Cost比例控制,也可以用
sample函数结合prob = id_cost_summary$TotalCost参数做加权抽样,但createDataPartition已经能覆盖大多数场景的需求。
内容的提问来源于stack exchange,提问作者NatR
相关产品推荐
相关产品推荐

