使用randomForest处理汇率分类任务时遇NA错误求助
解决randomForest报错"NA not permitted in predictors"的方案
问题根源分析
你遇到的NA not permitted in predictors错误,核心是建模用的特征数据中存在NA值,结合代码来看,主要来自三个方面:
- 指标计算时NA处理不当:计算RSI、MACD等指标时过早用
na.omit(),导致这些指标长度短于原始数据,后续手动截取[1:4350]合并时,不足部分自动填充NA。 - 标准化代码参数错误:
sapply(isa.data, mean, 2)中的2被当作mean函数的trim参数(而非按列计算的标识),导致均值计算完全错误,后续归一化产生NA。 - 训练数据与标签长度不匹配:手动截取
rfisnorma.data[11:3045,1:15]和na.omit(isdira.data)后,两者长度不一致,且未彻底清理数据中的NA。
分步修正方案
1. 修正指标计算逻辑,避免过早删除NA
去掉na.omit(),用rollapply参数保留对齐后的NA,后续统一处理:
library(priceR) library(tidyverse) library(quantmod) library(randomForest) # 获取汇率数据 a <- historical_exchange_rates("THB", to = "USD", start_date = "2010-01-01", end_date = "2021-12-31") # 计算技术指标,保留NA后续统一处理 a.avg10 <- rollapply(a[,2], 10, mean, align = "right", fill = NA) a.avg20 <- rollapply(a[,2], 20, mean, align = "right", fill = NA) a.std10 <- rollapply(a[,2], 10, sd, align = "right", fill = NA) # 修正原代码窗口错误(原误用20窗口) a.std20 <- rollapply(a[,2], 20, sd, align = "right", fill = NA) a.rsi5 <- RSI(a[,2], 5, "SMA") a.rsi14 <- RSI(a[,2], 14, "SMA") a.macd12269 <- MACD(a[,2], 12, 26, 9, "SMA") a.macd7205 <- MACD(a[,2], 7, 20, 5, "SMA") a.bbands <- BBands(a[,2], 20, "SMA", 2) # 创建方向变量 a.direction <- a %>% mutate(direction = ifelse(one_THB_equivalent_to_x_USD - lag(one_THB_equivalent_to_x_USD, 10) <= 0, 0, 1))
2. 合并数据并统一清理NA
用bind_cols对齐列,再用drop_na()一次性删除含NA的行,避免手动截取长度:
# 合并所有特征与标签 a.data <- bind_cols( exchange_rate = a[,2], avg10 = a.avg10, avg20 = a.avg20, as.data.frame(a.bbands), std10 = a.std10, std20 = a.std20, rsi5 = a.rsi5, rsi14 = a.rsi14, as.data.frame(a.macd12269), as.data.frame(a.macd7205), direction = a.direction$direction ) %>% drop_na() # 计算分类标签(Up/Down/Nowhere)并合并 a <- a %>% mutate( lagret = (one_THB_equivalent_to_x_USD - lag(one_THB_equivalent_to_x_USD, 10))/lag(one_THB_equivalent_to_x_USD, 10), rfa_direction = case_when( lagret > 0.02 ~ "Up", lagret < -0.02 ~ "Down", TRUE ~ "Nowhere" ) ) a.data <- a.data %>% bind_cols(rfa_direction = a$rfa_direction) %>% drop_na()
3. 修正训练测试集划分与标准化
用scale函数简化标准化,确保训练集和测试集用相同的均值/标准差,同时保证特征与标签长度一致:
# 设置随机种子保证可重复性 set.seed(123) # 划分训练测试集 split_idx <- sample(c(rep(0, round(0.7*nrow(a.data))), rep(1, round(0.3*nrow(a.data))))) train_data <- a.data[split_idx == 0,] test_data <- a.data[split_idx == 1,] # 分离特征与标签 train_features <- train_data %>% select(-direction, -rfa_direction) train_labels <- as.factor(train_data$rfa_direction) test_features <- test_data %>% select(-direction, -rfa_direction) test_labels <- as.factor(test_data$rfa_direction) # 标准化:用训练集的统计量标准化测试集,避免数据泄露 scaled_train <- scale(train_features) scaled_test <- scale(test_features, center = attr(scaled_train, "scaled:center"), scale = attr(scaled_train, "scaled:scale")) # 转换为数据框 rf_train_features <- as.data.frame(scaled_train) rf_test_features <- as.data.frame(scaled_test)
4. 重新构建randomForest模型
此时特征数据已无NA,且与标签长度匹配:
rfmodela.data <- randomForest(x = rf_train_features, y = train_labels, xtest = rf_test_features, ytest = test_labels, ntree = 500, importance = TRUE)
额外注意事项
- 始终用
set.seed()保证随机划分的可重复性 - 避免手动截取行号,用
drop_na()或complete.cases()统一处理NA - 标准化时必须用训练集的均值和标准差处理测试集,避免数据泄露
内容的提问来源于stack exchange,提问作者Napat Viseshsin
相关产品推荐
相关产品推荐

