kNN数据归一化时触发undefined columns selected错误求助
kNN归一化报错问题分析与解决
错误核心原因
你遇到的Error in [.data.frame(newdata, , object$method$center, drop = FALSE) : undefined columns selected错误,本质是归一化模型norm.values训练时用的列,和new.df的列不匹配,具体问题出在两处:
- 用硬编码的数字索引排除列(
-c(1,8)),误把非响应变量当成要排除的对象,导致归一化模型包含了new.df没有的列,同时漏掉了new.df有的列。 - 划分数据集时,采样的是原数据集
bank.df的行名,却用在处理后的bank.dummies.df上,存在潜在行名不匹配风险。
解决步骤
1. 用列名代替数字索引(彻底避免列顺序坑)
永远不要用固定数字索引选择列,改用列名定位,不管列顺序怎么变都不会出错:
# 明确指定要排除的列(ID + 响应变量,这里假设响应变量是Personal.Loan,可根据实际调整) exclude_cols <- c("ID", "Personal.Loan") # 提取需要归一化的列 train_norm_cols <- train.df[, !names(train.df) %in% exclude_cols] # 创建归一化模型 norm.values <- preProcess(train_norm_cols, method=c("center", "scale"))
2. 确保new.df与训练列完全匹配
在执行预测前,先验证列的一致性:
# 检查训练归一化列和new.df的列差异 setdiff(names(train_norm_cols), names(new.df)) # 训练有但new.df缺失的列 setdiff(names(new.df), names(train_norm_cols)) # new.df有但训练没有的列
如果两个结果都为空,说明列完全匹配。如果有差异,要么给new.df补全缺失列,要么在预测时只传入匹配的列:
new.norm.df <- predict(norm.values, new.df[, names(train_norm_cols)])
3. 修正数据集划分的小错误
之前采样的是bank.df的行名,应该改用处理后的bank.dummies.df行名,避免行名不匹配:
set.seed(111) train.index <- sample(row.names(bank.dummies.df), 0.6*dim(bank.dummies.df)[1]) valid.index <- setdiff(row.names(bank.dummies.df), train.index) train.df <- bank.dummies.df[train.index, ] valid.df <- bank.dummies.df[valid.index, ]
修正后的完整代码
bank.df <- UniversalBank # 移除ZIP code变量 bank.df <- bank.df[,-5] # 处理Education哑变量 bank.df$Education <- as.factor(bank.df$Education) library(fastDummies) bank.dummies.df <- dummy_cols(bank.df, select_columns = c("Education"), remove_first_dummy = FALSE, remove_selected_columns = TRUE) # 划分训练集/验证集(修正行名采样对象) set.seed(111) train.index <- sample(row.names(bank.dummies.df), 0.6*dim(bank.dummies.df)[1]) valid.index <- setdiff(row.names(bank.dummies.df), train.index) train.df <- bank.dummies.df[train.index, ] valid.df <- bank.dummies.df[valid.index, ] # 构造新客户数据 new.df <- data.frame(Age = 40, Experience = 10, Income = 84, Family = 2, CCAvg = 2, Mortgage = 0, Securities.Account = 0, CD.Account = 0, Online = 1, CreditCard = 1, Education_1 = 0, Education_2 = 1, Education_3 = 0) # 初始化归一化数据集 train.norm.df <- train.df valid.norm.df <- valid.df # 用列名方式做归一化 library(caret) exclude_cols <- c("ID", "Personal.Loan") train_norm_cols <- train.df[, !names(train.df) %in% exclude_cols] norm.values <- preProcess(train_norm_cols, method=c("center", "scale")) train.norm.df[, !names(train.norm.df) %in% exclude_cols] <- predict(norm.values, train_norm_cols) valid.norm.df[, !names(valid.norm.df) %in% exclude_cols] <- predict(norm.values, valid.df[, !names(valid.df) %in% exclude_cols]) # 执行新客户数据归一化(确保列匹配) new.norm.df <- predict(norm.values, new.df[, names(train_norm_cols)])
内容的提问来源于stack exchange,提问作者robin_ricca
相关产品推荐
相关产品推荐

