机器学习-SVM在相同输入和参数的情况下在R中产生不同的结果



我使用以下参数开发了一个用于列车数据集中欺诈检测的SVM模型:

set.seed(1234)
gamma.optimal <- 0.02
cost.optimal <- 4
svm_model1 <- svm(log(response+0.00012345) ~ . , data_test, kernel="radial", gamma=gamma.opt, cost=cost.opt)

创建SVM后,我在测试数据集中评估了我的SVM_model1,以获得总欺诈量:sum(response),相当于30.080美元:

predictions <- exp(predict(svm_model1 , testing))

这一结果在笔记本电脑(带有R GUI的本地模式)和使用SparkR的小型集群(带有Cloudera 5.6的4个节点和1个主机)中是相同的

对这些结果感到满意的是,我尝试用相同的测试数据集执行同一个R脚本set.seed(1234)保存在.Rdata可执行文件中的相同svm_model1。但这次是在两个不同的系统中:Oracle BDA(6个从节点和1个主节点)和另一个有4个从节点的系统和Cloudera 5.7。

这两个最终系统的结果是:使用相同的sum(response)等于30.130美元。

predictions <- exp(predict(svm_model1 , testing))

我的问题是:

1) 如果我使用了相同的脚本、保存在可执行文件(.Rdata)中的相同模型和相同的数据;带有径向核的e1071 svm怎么可能给我不同的结果?

2) 这些结果是否与径向内核的性质和并行处理问题或不同的硬件特性有关?或者,如果你使用set.seed(),那么无论你有什么硬件,使用predict()函数在R中的结果都必须相同?

我事先非常感谢你的时间和帮助。顺致敬意,

由于预测函数(显然)是确定性的,结果应该是相同的——但e1071使用LIBSVM,即C++代码——浮点运算可以(也将)在硬件平台之间变化(甚至对于不同的编译器标志和/或编译器)。您可以尝试编写自己的R预测函数,它应该在所有平台上给出(对于固定模型)相同的答案。

我认为检查情况的最简单方法是自己计算预测值(不使用预测函数)。以下是关于如何手动计算e1071中创建的svm模型对象的预测值的说明。

#TO GENERAGE TOY DATA
set.seed(994522)
Se <- 0.15
D <- data.frame(X=runif(n=20,min=0,max=6))
D$ActualY <- 3 + sin(D$X)
D <- D[order(D$X),]
rownames(D) <- 1:nrow(D)
D$Residual <- rnorm(n=nrow(D),mean=0,sd=Se)
NoisyPoints <- sample(1:nrow(D),8,replace=F)
D$Noise <- ifelse(rownames(D) %in% NoisyPoints,rnorm(n=nrow(D),mean=0,sd=2*Se),0)
D$Noisy <- ifelse(rownames(D) %in% NoisyPoints,1,0)
D$Y <- D$ActualY + D$Residual + D$Noise
D[,-5] <- round(D[,-5],digits=2)
#PARAMETER GRID
(MyEpsilons <- mean(D$Y)*c(0.01, seq(0.05, 0.20, 0.05)))
(MyGammas <- 10^(seq(-3, 3, 1)))
(MyCosts <- 10^(0:3))
#PARAMETER TUNING
TunesRBF <- tune.svm(x=D$X, y=D$Y, gamma=MyGammas, cost=MyCosts, epsilon=MyEpsilons, kernel="radial")
(BestPar <- summary(TunesRBF)$best.parameters)
(BestSVRrbf <- best.svm(x=D$X, y=D$Y,tunecontrol=tune.control(cross=5),cost=MyCosts,epsilon=MyEpsilons,gamma=MyGammas))
#SVM FITTING
(SVRrbf <- svm(x=D$X, y=D$Y, gamma=BestPar$gamma, cost=BestPar$cost, epsilon=BestPar$epsilon, kernel="radial"))
#TO GENERATE NEW SAMPLES
set.seed(224599)
NewSamples <- data.frame(X=runif(n=5,min=0,max=6))
NewSamples$PredY <- predict(SVRrbf,NewSamples)
NewSamples <- round(NewSamples,digits=2)
#TO EXTRACT MODEL PARAMETERS
V <- as.matrix(SVRrbf$SV)
A <- as.matrix(SVRrbf$coefs)
(g <- SVRrbf$gamma)
(C <- SVRrbf$cost)
(r <- SVRrbf$rho)
#TO MANUALLY GET PREDICTED VALUES NEW SAMPLES
X <- NewSamples[,1,drop=F]
KernelNewSamples <- matrix(0, nrow(NewSamples), nrow(V))
MeanX <- mean(D[,1])  #YOU NEED THIS FOR STANDARDIZING NEW SAMPLES
SdX <- sd(D[,1])  #YOU NEED THIS FOR STANDARDIZING NEW SAMPLES
#STANDARDIZATION
Xs <- (NewSamples[,1,drop=F]-MeanX)/SdX
#GETTING THE KERNEL FOR THE rbf
for (i in 1:nrow(NewSamples)) {
    for (j in 1:nrow(V)) {
        Xi <- Xs[i,]
        Vj <- V[j,]
        XiMinusVj <- Xi - Vj
        SumSqXiMinusVj <- XiMinusVj %*% XiMinusVj
        KernelNewSamples[i,j] <- exp(-g*SumSqXiMinusVj)
    }
}
#TO PREDICT NEW SAMPLES
PredNewSamples <- KernelNewSamples %*% A - r
#TO BACK TRANSFORM TO ORIGINAL Y SCALE
MeanY <- as.numeric(SVRrbf$y.scale[1])
StdY <- as.numeric(SVRrbf$y.scale[2])
PredNewSamples <- PredNewSamples*StdY + rep(MeanY,nrow(NewSamples))
cbind(NewSamples,PredNewSamples)

svr包还建议交叉验证,在tune.svr 的情况下,默认为k=10(k倍交叉验证)

由于选择集合的过程是非常随机的,它可能在每次执行中导致不同的结果(但非常相似),因此在SVM的情况下会导致不同的预测结果。

在维基百科上关于交叉验证的内容,我们读到:

在k次交叉验证中,原始样本是随机的划分为k个大小相等的子样本。在k个子样本中保留单个子样本作为验证数据,用于测试模型,其余k−1个子样本用作训练数据。然后,交叉验证过程重复k次,每次k个子样本恰好使用一次作为验证数据。k然后可以对结果进行平均以产生单个估计。

相关内容

最新更新