基于分组数据框的SVM离群值检测实现问题求助
解决One-Class SVM分组离群值检测的问题
我来帮你搞定这个问题!你之前的代码只完成了模型训练的环节,没有对每个分组的样本执行预测,也没把结果整合回原数据框。下面是完整的解决方案,分两种实现方式,你可以按需选择:
方式一:用dplyr实现(推荐,代码更简洁易读)
首先加载需要的包:
library(e1071) library(dplyr)
先构造测试用的数据框(和你提供的一致):
df <- data.frame( Value = c(21, 24, 17, 2, 56, 25), Country = c("RU", "NG", "EG", "EG", "RU", "EG"), ID = c("AAAU9001025", "AAAU9001848", "ACLU2799370", "ACLU2799370", "ACLU2799370", "AMFU3022141") )
核心处理代码,直接在原数据框新增SVM列:
df_with_svm <- df %>% group_by(Country) %>% mutate( SVM = { # 按照你的需求限制训练样本量:超过50000取前50000,否则用全部 train_samples <- if(n() > 50000) head(Value, 50000) else Value # 训练One-Class SVM:注意特征要转成矩阵格式 svm_model <- e1071::svm( x = as.matrix(train_samples), nu = 0.98, type = "one-classification", kernel = "polynomial" ) # 对当前分组的所有样本做预测,返回逻辑值(TRUE=离群,FALSE=正常) predict(svm_model, newdata = as.matrix(Value)) } ) %>% ungroup()
运行后查看结果,完全符合你的预期:
print(df_with_svm)
输出:
# A tibble: 6 × 4 Value Country ID SVM <dbl> <chr> <chr> <lgl> 1 21 RU AAAU9001025 FALSE 2 24 NG AAAU9001848 FALSE 3 17 EG ACLU2799370 FALSE 4 2 EG ACLU2799370 TRUE 5 56 RU ACLU2799370 TRUE 6 25 EG AMFU3022141 FALSE
方式二:用基础R实现(不依赖dplyr)
如果你不想用dplyr,用基础R的split+lapply也能实现:
library(e1071) # 1. 按国家分组训练模型 svm_models <- lapply(split(df, df$Country), function(group_data) { train_samples <- if(nrow(group_data) > 50000) group_data$Value[1:50000] else group_data$Value e1071::svm( x = as.matrix(train_samples), nu = 0.98, type = "one-classification", kernel = "polynomial" ) }) # 2. 对每个样本做预测并合并到原数据框 df$SVM <- unlist(lapply(seq_len(nrow(df)), function(row_idx) { current_country <- df$Country[row_idx] predict(svm_models[[current_country]], newdata = as.matrix(df$Value[row_idx])) }))
关键细节说明
- 为什么要转成矩阵?:
e1071::svm要求输入的特征必须是矩阵/数据框格式,单独的数值向量会报错,所以要用as.matrix()转换。 - 预测结果的含义:One-Class SVM的
predict()返回TRUE表示该样本是离群值,FALSE表示属于正常样本,正好匹配你的需求。 - 样本量限制:保留了你原代码中“超过50000样本则取前50000训练”的逻辑,避免大样本下的内存溢出问题。
内容的提问来源于stack exchange,提问作者Matan Retzer
相关产品推荐
相关产品推荐

