###################################
# based on Code for: R for Marketing Research and Analytics, Chapter 13
#
# Authors: Chris Chapman Elea McDonnell Feit
# cnchapman+rbook@gmail.com efeit@drexel.edu
#
# Copyright 2015, Springer
#
# Last update: January 7, 2015
# Version: 1.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
#
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
answers <- read.csv("Feedback Bogen Alimentaris Locham 2015 (Responses) - conjoint.csv")
#####
## create data
attrib <- list(Hilfestellung = c("keinSupport", "rechtlichePruefung"),
Ausgabeformate = c("Etikette", "EtiketteAllergenaushang", "EtiketteAllergenaushangProduktsheet"),
Jahrespreis = c("99", "600", "1200", "2000")
)
matrix(c(1,2,3, 11,12,13), nrow = 2, ncol = 3, byrow = TRUE,
dimnames = list(c("row1", "row2"),
c("C.1", "C.2", "C.3")))
## C.1 C.2 C.3
## row1 1 2 3
## row2 11 12 13
q=array(dim= c(7,3,3), dimnames = c("ques", "alt", "attr"))
q[1,1,]= c(1,3,2)
q[1,2,]= c(2,1,3)
q[1,3,]= c(1,1,1)
q[2,1,]= c(2,2,2)
q[2,2,]= c(1,2,1)
q[2,3,]= c(2,3,4)
q[3,1,]= c(2,1,2)
q[3,2,]= c(1,3,1)
q[3,3,]= c(2,2,3)
q[4,1,]= c(2,1,1)
q[4,2,]= c(1,3,3)
q[4,3,]= c(2,2,2)
q[5,1,]= c(1,1,3)
q[5,2,]= c(1,2,4)
q[5,3,]= c(2,1,4)
q[6,1,]= c(2,3,2)
q[6,2,]= c(1,1,1)
q[6,3,]= c(2,1,1)
q[7,1,]= c(1,1,2)
q[7,2,]= c(1,3,3)
q[7,3,]= c(2,2,4)
cbc.df= data.frame(resp.id=integer(), ques=integer(), alt=integer(), Hilfestellung=character(), Ausgabeformate=character(), Jahrespreis=character(), choice=integer(), stringsAsFactors = FALSE)
for(userIndex in 1: nrow(answers)){
user = answers[userIndex,]
for(questionIndex in 1:ncol(user)) {
answerIndex = user[,questionIndex]
if (answerIndex==4)
next
row = NULL
for(alternativeIndex in 1:3){
attributeIndex = q[questionIndex, alternativeIndex, 1]
a=attrib$Hilfestellung[attributeIndex]
attributeIndex = q[questionIndex, alternativeIndex, 2]
b=attrib$Ausgabeformate[attributeIndex]
attributeIndex = q[questionIndex, alternativeIndex, 3]
c=attrib$Jahrespreis[attributeIndex]
choice=0
if (answerIndex == alternativeIndex)
choice=1;
row = data.frame(resp.id=userIndex, ques=questionIndex, alt=alternativeIndex, Hilfestellung=a, Ausgabeformate=b, Jahrespreis=c, choice=choice)
cbc.df = rbind(cbc.df, row);
}
}
}
## END long table generation
# Choice data descriptives
head(cbc.df)
## resp.id ques alt Hilfestellung Ausgabeformate
## 1 1 1 1 keinSupport EtiketteAllergenaushangProduktsheet
## 2 1 1 2 rechtlichePruefung Etikette
## 3 1 1 3 keinSupport Etikette
## 4 1 2 1 rechtlichePruefung EtiketteAllergenaushang
## 5 1 2 2 keinSupport EtiketteAllergenaushang
## 6 1 2 3 rechtlichePruefung EtiketteAllergenaushangProduktsheet
## Jahrespreis choice
## 1 600 1
## 2 1200 0
## 3 99 0
## 4 600 1
## 5 99 0
## 6 2000 0
summary(cbc.df)
## resp.id ques alt Hilfestellung
## Min. : 1.00 Min. :1.000 Min. :1 keinSupport :161
## 1st Qu.: 6.00 1st Qu.:2.000 1st Qu.:1 rechtlichePruefung:205
## Median :11.00 Median :3.500 Median :2
## Mean :11.39 Mean :3.738 Mean :2
## 3rd Qu.:17.00 3rd Qu.:6.000 3rd Qu.:3
## Max. :22.00 Max. :7.000 Max. :3
## Ausgabeformate Jahrespreis choice
## EtiketteAllergenaushangProduktsheet:114 600 :114 Min. :0.0000
## Etikette :146 1200: 80 1st Qu.:0.0000
## EtiketteAllergenaushang :106 99 :121 Median :0.0000
## 2000: 51 Mean :0.3333
## 3rd Qu.:1.0000
## Max. :1.0000
# write.csv(cbc.df, "rintro-chapter13conjoint.csv", row.names=FALSE)
preisAuswahl= xtabs(choice ~ Jahrespreis, data=cbc.df)
barplot(preisAuswahl)
formatWahl= xtabs(choice ~ Ausgabeformate, data=cbc.df)
barplot(formatWahl)
Wahl.der.Hilfestellung=xtabs(choice ~ Hilfestellung, data=cbc.df)
barplot(Wahl.der.Hilfestellung)
# Fitting a choice model with mlogit
library(mlogit)
## Loading required package: Formula
## Loading required package: maxLik
## Loading required package: miscTools
##
## Please cite the 'maxLik' package as:
## Henningsen, Arne and Toomet, Ott (2011). maxLik: A package for maximum likelihood estimation in R. Computational Statistics 26(3), 443-458. DOI 10.1007/s00180-010-0217-1.
##
## If you have questions, suggestions, or comments regarding the 'maxLik' package, please use a forum or 'tracker' at maxLik's R-Forge site:
## https://r-forge.r-project.org/projects/maxlik/
cbc.mlogit <- mlogit.data(data=cbc.df, choice="choice", shape="long", varying=3:6, alt.levels=paste("pos",1:3),
id.var="resp.id")
Einfachstes Modell
m1 <- mlogit(choice ~ 0 + Hilfestellung + Ausgabeformate + Jahrespreis, data = cbc.mlogit)
summary(m1)
##
## Call:
## mlogit(formula = choice ~ 0 + Hilfestellung + Ausgabeformate +
## Jahrespreis, data = cbc.mlogit, method = "nr", print.level = 0)
##
## Frequencies of alternatives:
## pos 1 pos 2 pos 3
## 0.44262 0.26230 0.29508
##
## nr method
## 5 iterations, 0h:0m:0s
## g'(-H)^-1g = 6.28E-08
## gradient close to zero
##
## Coefficients :
## Estimate Std. Error t-value
## HilfestellungrechtlichePruefung 1.98367 0.48661 4.0765
## AusgabeformateEtikette -1.89315 0.39876 -4.7476
## AusgabeformateEtiketteAllergenaushang -0.72565 0.33484 -2.1672
## Jahrespreis1200 -1.35761 0.35771 -3.7953
## Jahrespreis99 1.13068 0.38415 2.9433
## Jahrespreis2000 -2.79259 0.62508 -4.4675
## Pr(>|t|)
## HilfestellungrechtlichePruefung 4.572e-05 ***
## AusgabeformateEtikette 2.059e-06 ***
## AusgabeformateEtiketteAllergenaushang 0.0302207 *
## Jahrespreis1200 0.0001475 ***
## Jahrespreis99 0.0032471 **
## Jahrespreis2000 7.913e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Log-Likelihood: -109.88
Modell das von keinem Systematischen Bias ausgeht
m2 <- mlogit(choice ~ Hilfestellung + Ausgabeformate + Jahrespreis, data = cbc.mlogit)
summary(m2)
##
## Call:
## mlogit(formula = choice ~ Hilfestellung + Ausgabeformate + Jahrespreis,
## data = cbc.mlogit, method = "nr", print.level = 0)
##
## Frequencies of alternatives:
## pos 1 pos 2 pos 3
## 0.44262 0.26230 0.29508
##
## nr method
## 5 iterations, 0h:0m:0s
## g'(-H)^-1g = 5.24E-08
## gradient close to zero
##
## Coefficients :
## Estimate Std. Error t-value
## pos 2:(intercept) 0.37235 0.42123 0.8839
## pos 3:(intercept) 0.25893 0.34226 0.7565
## HilfestellungrechtlichePruefung 2.16044 0.52626 4.1053
## AusgabeformateEtikette -1.89972 0.41254 -4.6049
## AusgabeformateEtiketteAllergenaushang -0.88916 0.41350 -2.1503
## Jahrespreis1200 -1.64349 0.47772 -3.4403
## Jahrespreis99 0.97076 0.42247 2.2978
## Jahrespreis2000 -3.17591 0.75731 -4.1937
## Pr(>|t|)
## pos 2:(intercept) 0.376726
## pos 3:(intercept) 0.449335
## HilfestellungrechtlichePruefung 4.038e-05 ***
## AusgabeformateEtikette 4.126e-06 ***
## AusgabeformateEtiketteAllergenaushang 0.031530 *
## Jahrespreis1200 0.000581 ***
## Jahrespreis99 0.021572 *
## Jahrespreis2000 2.744e-05 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Log-Likelihood: -109.41
## McFadden R^2: 0.16338
## Likelihood ratio test : chisq = 42.733 (p.value = 1.3173e-07)
lrtest(m1, m2)
## Likelihood ratio test
##
## Model 1: choice ~ 0 + Hilfestellung + Ausgabeformate + Jahrespreis
## Model 2: choice ~ Hilfestellung + Ausgabeformate + Jahrespreis
## #Df LogLik Df Chisq Pr(>Chisq)
## 1 6 -109.88
## 2 8 -109.41 2 0.9415 0.6245
Aus dem Likely Ratio Test sehen wir dass beide Modelle gleich gut sind. Ein starker Hinweiss, dass die Schüler nicht einfach nur was angekreuzt haben ohne nachzudenken. Wir gehen weiter zu einem model mit numerischen Preisen:
m3 <- mlogit(choice ~ 0 + Hilfestellung + Ausgabeformate
+ as.numeric(as.character(Jahrespreis)),
data = cbc.mlogit)
summary(m3)
##
## Call:
## mlogit(formula = choice ~ 0 + Hilfestellung + Ausgabeformate +
## as.numeric(as.character(Jahrespreis)), data = cbc.mlogit,
## method = "nr", print.level = 0)
##
## Frequencies of alternatives:
## pos 1 pos 2 pos 3
## 0.44262 0.26230 0.29508
##
## nr method
## 5 iterations, 0h:0m:0s
## g'(-H)^-1g = 6.88E-08
## gradient close to zero
##
## Coefficients :
## Estimate Std. Error t-value
## HilfestellungrechtlichePruefung 1.96088179 0.43060066 4.5538
## AusgabeformateEtikette -1.86166288 0.34580311 -5.3836
## AusgabeformateEtiketteAllergenaushang -0.72233482 0.33655535 -2.1463
## as.numeric(as.character(Jahrespreis)) -0.00209939 0.00042374 -4.9544
## Pr(>|t|)
## HilfestellungrechtlichePruefung 5.268e-06 ***
## AusgabeformateEtikette 7.301e-08 ***
## AusgabeformateEtiketteAllergenaushang 0.03185 *
## as.numeric(as.character(Jahrespreis)) 7.255e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Log-Likelihood: -110.13
Die Preisneigung ist leicht negativ, Preis spielt bei der Auswahl nicht eine besonders grosse rolle
lrtest(m1, m3)
## Likelihood ratio test
##
## Model 1: choice ~ 0 + Hilfestellung + Ausgabeformate + Jahrespreis
## Model 2: choice ~ 0 + Hilfestellung + Ausgabeformate + as.numeric(as.character(Jahrespreis))
## #Df LogLik Df Chisq Pr(>Chisq)
## 1 6 -109.88
## 2 4 -110.13 -2 0.5006 0.7786
das Modell mit Numerischen Preis ist gut, wir verwenden es weiter Zahlungsbereitschaft
Zahlungsbereitschaft.RechtlichePrüfung=coef(m3)["HilfestellungrechtlichePruefung"]/(-coef(m3)["as.numeric(as.character(Jahrespreis))"])
print(c(round(Zahlungsbereitschaft.RechtlichePrüfung), "EUR"))
## HilfestellungrechtlichePruefung
## "934" "EUR"
Predicting shares
predict.mnl <- function(model, data) {
# Function for predicting shares from a multinomial logit model
# model: mlogit object returned by mlogit()
# data: a data frame containing the set of designs for which you want to
# predict shares. Same format at the data used to estimate model.
data.model <- model.matrix(update(model$formula, 0 ~ .), data = data)[,-1]
utility <- data.model%*%model$coef
share <- exp(utility)/sum(exp(utility))
cbind(share, data)
}
(new.data <- expand.grid(attrib)[c(1,2,3,12,24), ])
## Hilfestellung Ausgabeformate Jahrespreis
## 1 keinSupport Etikette 99
## 2 rechtlichePruefung Etikette 99
## 3 keinSupport EtiketteAllergenaushang 99
## 12 rechtlichePruefung EtiketteAllergenaushangProduktsheet 600
## 24 rechtlichePruefung EtiketteAllergenaushangProduktsheet 2000
predict.mnl(m3, new.data)
## share Hilfestellung Ausgabeformate
## 1 0.10493057 keinSupport Etikette
## 2 0.74559364 rechtlichePruefung Etikette
## 3 0.01630768 keinSupport EtiketteAllergenaushang
## 12 0.12647611 rechtlichePruefung EtiketteAllergenaushangProduktsheet
## 24 0.00669200 rechtlichePruefung EtiketteAllergenaushangProduktsheet
## Jahrespreis
## 1 99
## 2 99
## 3 99
## 12 600
## 24 2000
predict.mnl(m1, new.data)
## share Hilfestellung Ausgabeformate
## 1 0.10481403 keinSupport Etikette
## 2 0.76193071 rechtlichePruefung Etikette
## 3 0.01578465 keinSupport EtiketteAllergenaushang
## 12 0.09487818 rechtlichePruefung EtiketteAllergenaushangProduktsheet
## 24 0.02259243 rechtlichePruefung EtiketteAllergenaushangProduktsheet
## Jahrespreis
## 1 99
## 2 99
## 3 99
## 12 600
## 24 2000
Share sensitivity
sensitivity.mnl <- function(model, attrib, base.data, competitor.data) {
# Function for creating data for a share-sensitivity chart
# model: mlogit object returned by mlogit() function
# attrib: list of vectors with attribute levels to be used in sensitivity
# base.data: data frame containing baseline design of target product
# competitor.data: data frame contining design of competitive set
data <- rbind(base.data, competitor.data)
base.share <- predict.mnl(model, data)[1,1]
share <- NULL
for (a in seq_along(attrib)) {
for (i in attrib[[a]]) {
data[1,] <- base.data
data[1,a] <- i
share <- c(share, predict.mnl(model, data)[1,1])
}
}
data.frame(level=unlist(attrib), share=share, increase=share-base.share)
}
base.data <- expand.grid(attrib)[c(1), ]
competitor.data <- expand.grid(attrib)[c(4,6,12,18), ]
(tradeoff <- sensitivity.mnl(m1, attrib, base.data, competitor.data))
## level share
## Hilfestellung1 keinSupport 0.057413230
## Hilfestellung2 rechtlichePruefung 0.306892994
## Ausgabeformate1 Etikette 0.057413230
## Ausgabeformate2 EtiketteAllergenaushang 0.009089515
## Ausgabeformate3 EtiketteAllergenaushangProduktsheet 0.028636851
## Jahrespreis1 99 0.057413230
## Jahrespreis2 600 0.015428922
## Jahrespreis3 1200 0.158734010
## Jahrespreis4 2000 0.003717641
## increase
## Hilfestellung1 0.00000000
## Hilfestellung2 0.24947976
## Ausgabeformate1 0.00000000
## Ausgabeformate2 -0.04832371
## Ausgabeformate3 -0.02877638
## Jahrespreis1 0.00000000
## Jahrespreis2 -0.04198431
## Jahrespreis3 0.10132078
## Jahrespreis4 -0.05369559
barplot(tradeoff$increase, horiz=FALSE, names.arg=tradeoff$level,
ylab="Change in Share for Baseline Product")
# Share predictions for two identical vehicles
#new.data.2 <- expand.grid(attrib)[c(8, 8, 1, 3, 41, 49, 26), ]
#predict.mnl(m1, new.data.2)
# Prediction uncertainty & conjoint design
#small.cbc <- mlogit.data(data=cbc.df[1:(25*15*3),],
# choice="choice", shape="long",
# varying=3:6, alt.levels=paste("pos", 1:3),
# id.var="resp.id")
#m4 <- mlogit(choice ~ 0 + Hilfestellung + Ausgabeformate + eng + Jahrespreis, data = small.cbc)
#summary(m4) # larger standard errors
#cbind(predict.mnl(m4, new.data), predict.mnl(m1, new.data))