It is found that the combination of models has a prediction error slightly worse compared to a simple PLS model using physical chemical data. This is not so bad. On the one hand, PLS is very much a predictive method, so, it should be performing better. On the other hand, PLS does not take curvature into account. This means that the PLS model has a handicap for some of the details. It would seem that these two balance out. Finally, the separate models can be interpreted better than a PLS model.
Model fit
The model uses all the separate parts which were defined previously in this blog. For ease of use this is all placed in a small function. A second function is used to generate predictions. The first figure shows the predictions using all data. In addition the ideal line (y=x) is added.
The normal predictions are not very impressive. Especially, the least liked products are not found least liked at all. Part of the problem may be in an intermediate step. CJuiciness, which is the juiciness observed by the consumers, is not well predicted. As it was earlier discovered that CJuiciness is the main explaining factor for liking, this may explain part of the lack of prediction power.
Model prediction capability using cross validation
Cross validation predictions are given in the second figure. The sub figures make very clear that the model does not do a good job of predicting new data. Again, Juiciness is a big part of the problem, now both the sensory observed juiciness and the consumer observed juiciness.
Prediction error
For completeness, the prediction error is calculated. The Root Mean Squared Error of Prediction is 0.170. As a comparison, a PLS model of liking from physical chemical data has a slightly better prediction error. This makes the model defined at least a competitor to PLS. It also shows that predicting the liking poses a difficult problem.
Data: X dimension: 17 4
Y dimension: 17 1
Fit method: kernelpls
Number of components considered: 4
VALIDATION: RMSEP
Cross-validated using 17 leave-one-out segments.
(Intercept) 1 comps 2 comps 3 comps 4 comps
CV 0.174 0.1626 0.1617 0.2029 0.2007
adjCV 0.174 0.1615 0.1610 0.2005 0.1984
TRAINING: % variance explained
1 comps 2 comps 3 comps 4 comps
X 34.74 80.63 87.17 100.00
CLiking 33.80 36.71 40.89 40.96
R code
library(xlsReadWrite)
library(gam)
library(plyr)
datain <- read.xls('condensed.xls')
datain <- datain[-grep('bag|net',datain$Products,ignore.case=TRUE),]
datain$week <- sapply(strsplit(as.character(datain$Product),'_'),
function(x) x[[2]])
dataval <- datain
vars <- names(dataval)[-1]
for (descriptor in vars) {
dataval[,descriptor] <- as.numeric(gsub('[[:alpha:]]','',
dataval[,descriptor]))
}
# all fits in a model
FitCombinedModel <- function(dataval) {
# link instrument to sensory
MJuicsSEL3 <- gam(SJuiciness ~ AInstrumental.firmness + s(AJuice.release,3) +
s(ATitratable.acidity,3) ,data=dataval)
MSweetSEL <- gam(SSweetness ~ AInstrumental.firmness + s(AJuice.release,3) +
ASoluble.solids + ATitratable.acidity ,data=dataval)
MCrispSEL <- gam(SCrispness ~ s(AInstrumental.firmness,3) + AJuice.release +
ASoluble.solids + ATitratable.acidity ,data=dataval)
MMealiSEL <- gam(SMealiness ~ s(AInstrumental.firmness,3) + AJuice.release +
ASoluble.solids + ATitratable.acidity ,data=dataval)
# link sensory to consumer experience
MCJuic <- lm(CJuiciness ~ SJuiciness + SSweetness,data=dataval)
MCSweet <- lm(CSweetness ~ SSweetness + SCrispness ,data=dataval)
# link consumer experience to liking
Mliking <- lm(CLiking ~ CJuiciness+CSweetness + I(CJuiciness^2) ,data=dataval)
return(list(MJuicsSEL3=MJuicsSEL3,MSweetSEL=MSweetSEL,MCrispSEL=MCrispSEL,
MMealiSEL=MMealiSEL,MCJuic=MCJuic,MCSweet=MCSweet,Mliking=Mliking ))
}
PredictCombinedModel <- function(modellist,newdata) {
preddata <- data.frame(SJuiciness = predict(modellist$MJuicsSEL3,newdata),
SSweetness = predict(modellist$MSweetSEL,newdata),
SCrispness = predict(modellist$MCrispSEL,newdata),
SMealiness = predict(modellist$MMealiSEL,newdata))
preddata$CJuiciness <- predict(modellist$MCJuic,preddata)
preddata$CSweetness <- predict(modellist$MCSweet,preddata)
preddata$CLiking <- predict(modellist$Mliking,preddata)
preddata
}
FCM <- FitCombinedModel(dataval)
datain.nomiss <- dataval[-1,]
predictions <- PredictCombinedModel(FCM,datain.nomiss)
par(mfrow=c(2,3))
m_ply(c('SJuiciness','SSweetness','SCrispness','CJuiciness',
'CSweetness','CLiking'),function(x) {
plot(y=predictions[,x],x=datain.nomiss[,x],ylab=paste('predicted',x),
xlab=paste('observed',x))
abline(a=0,b=1)
})
#cross validation section
lopred <- mdply(1:nrow(datain.nomiss),function(x) {
datain.nomisslo <- datain.nomiss[-x,]
lomodel <- FitCombinedModel(datain.nomisslo)
PredictCombinedModel(lomodel,datain.nomiss[x,])
})
#lopred <- do.call(rbind,lopred)
par(mfrow=c(2,3))
m_ply(c('SJuiciness','SSweetness','SCrispness','CJuiciness',
'CSweetness','CLiking'),function(x) {
plot(y=lopred[,x],x=datain.nomiss[,x],
ylab=paste('cv predicted',x),xlab=paste('observed',x))
abline(a=0,b=1)
})
# root mean squared error of prediction
sqrt(mean((lopred$CLiking-datain.nomiss$CLiking)^2))
#pls as benchmark
library(pls)
plsmodel <- plsr(CLiking ~ AInstrumental.firmness + AJuice.release + ASoluble.solids + ATitratable.acidity,data=datain.nomiss,
scale=TRUE,validation='LOO' )
summary(plsmodel)
Thank you so much for these interesting posts. Can you please join us data. Is CLiking an average score for all consumers per product, or is an individual score ? How to deal with each consumer model. Thank you in advance
ReplyDeleteThe data should Be in a previous post. The were certainly not my own.
DeleteI've already read your first post on ( Liking of apples - some data to link). You said that this data refer to Peneau et al. (J. Sensory Studies, 2007). But i didn't find it on the Web. Please can you give me the link for downloading. Thank you
DeleteThis comment has been removed by the author.
ReplyDeleteThis comment has been removed by the author.
ReplyDelete