suppressMessages(library(Ecdat))
suppressMessages(library(mlogit))
suppressMessages(library(kableExtra))
suppressMessages(library(tidyverse))
suppressMessages(library(ggthemes))
suppressMessages(library(stargazer))
suppressMessages(library(tinytex))
library(Ecdat)
library(mlogit)
library(tidyverse)
library(kableExtra)
library(ggthemes)
library(stargazer)
library(tinytex)Modele de Choix discret
Introduction
L’étude empirique des choix des consommateurs et des déterminants de ces choix est un sujet d’intérêt pour les chercheurs en marketing depuis les travaux pionniers de Guadagni et Little (1982). Au cours de la dernière décennie, plusieurs modèles alternatifs ont été proposés, mis en œuvre et analysés. Une grande proportion de ces modèles sont des variantes dérivées du cadre de la Valeur Extrême Généralisée proposé par McFadden (1978). Peut-être le plus populaire d’entre eux est le modèle logit multinomial (MNL). La popularité du MNL est attribuée à sa simplicité analytique et bien que certaines de ses propriétés, notamment la propriété d’indépendance des alternatives non pertinentes (IIA), soient considérées comme limitantes, il reste le modèle de choix.
alternative—-Les modèles à utilité aléatoire sont l’approche de référence en économie lorsqu’il s’agit d’analyser le choix par un décideur parmi un ensemble d’alternatives mutuellement exclusives. Depuis les travaux pionniers de Daniel McFadden (McFadden 1974, 1978), qui a remporté le prix Nobel d’économie “pour son développement de la théorie et des méthodes d’analyse du choix discret”, une grande quantité de littérature théorique et empirique a été développée dans ce domaine.
Ces modèles reposent sur l’hypothèse que le décideur est capable de classer les différentes alternatives par ordre de préférence, représenté par une fonction d’utilité, l’alternative choisie étant celle qui est associée au niveau d’utilité le plus élevé. Ils sont appelés modèles à utilité aléatoire car une partie de l’utilité est inobservée et est modélisée comme la réalisation d’une variable aléatoire.
Différentes hypothèses sur la distribution de cette variable aléatoire conduisent à différentes variantes de modèles à utilité aléatoire. Les premiers développements de ces modèles étaient basés sur l’hypothèse d’erreurs identiques et indépendantes suivant une distribution de Gumbel, conduisant au modèle logit multinomial (MNL). Des modèles plus généraux ont depuis été proposés, soit basés sur des hypothèses de distribution moins restrictives, soit en introduisant l’hétérogénéité individuelle.
Application aux choix des consommateurs pour les marques de Yogurt
Chargement des packages
| Package | Utilisation |
|---|---|
| Ecdat | Charger les données Yogurt en mode wide |
| mlogit | Préparer, Estimer le Modèle de Choix Discret et Analyser (summary) |
| kableExtra | Affichager des tableaux |
| tidyverse | Analyser les données avec la fonction $summarise$ |
| ggthemes | Utiliser le thème Economist |
| stargazer | Affichager des tableaux |
| tinytex | Export en mode pdf |
# tinytex::install_tinytex(force = TRUE)# tinytex::is_tinytex()Phase 1- Présentation des données \(`Yogurt`\)
Les données \(`Yogurt`\) sont initialement présentées en format large (wide). Pour mieux les comprendre, nous allons les transformer en format long et afficher quelques tableaux descriptifs.
#descriptif des data dans le dictionnaire
df<- Yogurt
head(df) id feat.yoplait feat.dannon feat.hiland feat.weight price.yoplait
1 1 0 0 0 0 10.8
2 1 0 0 0 0 10.8
3 1 0 0 0 0 10.8
4 1 0 0 0 0 10.8
5 1 0 0 0 0 12.5
6 1 0 0 0 0 10.8
price.dannon price.hiland price.weight choice
1 8.1 6.1 7.9 weight
2 9.8 6.4 7.5 dannon
3 9.8 6.1 8.6 dannon
4 9.8 6.1 8.6 dannon
5 9.8 4.9 7.9 dannon
6 9.2 5.0 7.9 dannon
Affichage des données au format wide après avoir supprimé \(`feat`\) et \(`price`\) des entêtes.
names(df)<- gsub("^feat\\.","",names(df))
names(df)<- gsub("^price\\.","",names(df))
df%>%head(10)%>%knitr::kable(caption="Le tableau de données brutes Yogurt (les 10 premères lignes)")| id | yoplait | dannon | hiland | weight | yoplait | dannon | hiland | weight | choice |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 0 | 0 | 0 | 0 | 10.8 | 8.1 | 6.1 | 7.9 | weight |
| 1 | 0 | 0 | 0 | 0 | 10.8 | 9.8 | 6.4 | 7.5 | dannon |
| 1 | 0 | 0 | 0 | 0 | 10.8 | 9.8 | 6.1 | 8.6 | dannon |
| 1 | 0 | 0 | 0 | 0 | 10.8 | 9.8 | 6.1 | 8.6 | dannon |
| 1 | 0 | 0 | 0 | 0 | 12.5 | 9.8 | 4.9 | 7.9 | dannon |
| 1 | 0 | 0 | 0 | 0 | 10.8 | 9.2 | 5.0 | 7.9 | dannon |
| 1 | 0 | 0 | 0 | 0 | 10.3 | 8.1 | 4.9 | 7.9 | dannon |
| 1 | 0 | 0 | 0 | 0 | 10.8 | 8.6 | 5.4 | 7.9 | weight |
| 2 | 0 | 0 | 0 | 0 | 10.8 | 9.8 | 5.0 | 7.9 | yoplait |
| 2 | 0 | 0 | 0 | 0 | 10.8 | 9.8 | 5.0 | 7.9 | yoplait |
Mettre les données de \(`Yogurt`\) au format long via la fonction \(`pivot\_longer`\) et rajouter la colonne \(`choiceid`\) au tableau pour avoir un index unique.
# convertir le format wide en long via pivot_longer
Ylong <- pivot_longer(Yogurt,
cols = 2:9,
names_to = c(".value", "brand"),
names_sep = "\\.")
Ylong<-Ylong%>%mutate(Ylong,choice=ifelse(choice==brand,1,0))
Ylong <- Ylong %>%mutate(choiceid = row_number())
# Afficher le résultat
# names(Ylong)
#print(subset(Ylong,price < 0.5))Présentation de la part de marché de chaque marque en utilisant un Pie Chart
ggplot(subset(Ylong,choice ==1), aes(x = "", fill = factor(brand), group = brand)) +
geom_bar(width = 1) +
coord_polar("y", start = 0) +
scale_fill_manual(values = c("blue", "red","green","orange")) + # Couleurs pour les choix (1: bleu, 0: rouge)
labs(
x = NULL,
y = NULL,
fill = "Choice",
title = "Parts de marché"
) +
guides(fill = guide_legend(title.position = "top")) +
theme_economist()+
theme(legend.position = "left",
legend.direction = "vertical",
legend.key.size = unit(0.8, "cm"), # Taille des carrés de la légende
legend.spacing.x = unit(0.5, "cm"), # Espacement horizontal entre les éléments de la légende
legend.box.margin = margin(10, 10, 10, 10) # Marge autour du cadre de la légende
)Affichage d’un histogramme qui affiche la distribution des prix par marque dans un même graphique en utilisant l’option facet_wrap.
# Affichage du graphique via ggplot
ggplot(Ylong, aes(x =price))+
geom_histogram (binwidth=1.5)+
scale_x_continuous() +
labs(x = "Prix", y = "Fréquence") + # Ajout des étiquettes d'axe
ggtitle("Distribution des prix") +
theme_economist()+
facet_wrap(~ brand)Affichage de la distribution des prix par marque en utilisant l’objet Boxplot
ggplot(Ylong, aes(x=brand,y =price))+
geom_boxplot()+
#scale_x_continuous() +
labs(x = "brand", y = "Prix") + # Ajout des étiquettes d'axe
ggtitle("Distribution des prix") +
theme_economist() Affichage du tableau en utilisant Kable avec le Kable_styling
# Affichage du tableau
fin %>%kable()%>%
kable_styling(bootstrap_options = "responsive", position = "c", row_label_position = "l", full_width = FALSE)%>%
add_header_above(header = c("Yogurt Data" =4) , bold = FALSE,
align = "c",
extra_css = "border-bottom: 2px double #000;")%>%
collapse_rows(columns = 1, valign = "middle", latex_hline = "major")| variable | brand | mean | std |
|---|---|---|---|
| Market share | dannon | 0.0816347 | 0.0106289 |
| hiland | 0.0536294 | 0.0080539 | |
| weight | 0.0794909 | 0.0077350 | |
| yoplait | 0.1068213 | 0.0190626 | |
| Feature | dannon | 0.0377280 | 0.1905772 |
| hiland | 0.0368988 | 0.1885525 | |
| weight | 0.0377280 | 0.1905772 | |
| yoplait | 0.0559701 | 0.2299117 | |
| Price($ per oz) | dannon | 0.4021559 | 0.4904348 |
| hiland | 0.0294362 | 0.1690607 | |
| weight | 0.2292703 | 0.4204506 | |
| yoplait | 0.3391376 | 0.4735148 |
Phase 2 - Application de Modèles d’Utilité Aléatoire avec \(`mlogit`\)
La modélisation des choix de marques de yaourt dans l’ensemble des données \(`Yogurt`\) utilise la fonction \(`mlogit`\). Ce processus démarre avec des données brutes structurées en format large (wide) et suit les étapes principales suivantes :
- Préparation des Données : Utiliser la fonction \(‘mlogit.data‘\) pour transformer et préparer les données en format long (long).
# Transformer et Restructurer les données pour mlogit
Ywide <- Yogurt %>%mutate(across(starts_with("price."), ~ . / 100),choiceid = row_number())
mlogit_data <- mlogit.data(Ywide, choice = "choice",
shape = "wide",
varying = 2:9,
sep = ".")- Estimation du Modèle : Utiliser la fonction \(`mlogit‘\) pour estimer les paramètres du modèle.
# Estimer le modèle logit multinomial}
mnl_model <- mlogit(choice ~ price + feat , data = mlogit_data, reflevel = "hiland")- Analyse des Résultats : Interpréter les coefficients estimés du modèle
# Analyser les résultat avec summary de
model_summary<-summary(mnl_model)
coef_table <- model_summary$coefficients
coef_df <- as.data.frame(coef_table)
names(coef_df) <- c("Coef.")
# Créer un tableau de résultats pour stargazer
# Afficher le tableau LaTeX avec stargazer
stargazer(coef_df, type = "latex", summary = FALSE, title = "Distrib", header = FALSE)
\begin{table}[!htbp] \centering
\caption{Distrib}
\label{}
\begin{tabular}{@{\extracolsep{5pt}} cc}
\\[-1.8ex]\hline
\hline \\[-1.8ex]
& Coef. \\
\hline \\[-1.8ex]
(Intercept):dannon & $3.716$ \\
(Intercept):weight & $3.074$ \\
(Intercept):yoplait & $4.450$ \\
price & $$-$36.658$ \\
feat & $0.491$ \\
\hline \\[-1.8ex]
\end{tabular}
\end{table}
# impression par Kable
print(coef_df) Coef.
(Intercept):dannon 3.7155950
(Intercept):weight 3.0744107
(Intercept):yoplait 4.4501662
price -36.6584451
feat 0.4914334
coef_df_data<-data_frame(coef_df)Warning: `data_frame()` was deprecated in tibble 1.1.0.
ℹ Please use `tibble()` instead.
coef_df_data %>%kable()%>%
kable_styling(bootstrap_options = "responsive", position = "c", row_label_position = "l", full_width = FALSE)%>%
add_header_above(header = c("MNL Estimation of Yogurt Data" =1) , bold = FALSE,
align = "c",
extra_css = "border-bottom: 2px double #000;")%>%
collapse_rows(columns = 1, valign = "middle", latex_hline = "major")| Coef. |
|---|
| 3.7155950 |
| 3.0744107 |
| 4.4501662 |
| -36.6584451 |
| 0.4914334 |
Ces étapes marquent le début de la modélisation avec mlogit, où chaque commande construit la fondation pour l’analyse des choix entre différentes alternatives de marques de Yogurt
Modèle Nested-Logit
Dans le cadre du projet Yogurt, nous allons réestimer des modèles de choix discret en utilisant le jeu de données Yogurt. Ce jeu de données est un classique pour l’analyse des choix de consommateurs entre différentes marques de yaourts. Nous nous concentrerons ici sur un modèle Nested-Logit pour capturer la similarité entre certaines alternatives, tel qu’il est estimé dans l’article que nous étudierons.
Utilisation du package MLogit de R
Pour estimer ce modèle avec le package MLogit de R, vous devez vous référer à la documentation de référence du package. Chaque package R dispose d’une documentation détaillée, souvent appelée ”vignette”, qui explique comment utiliser les fonctions du package. Consultez cette documentation pour mettre en place l’estimation du modèle Nested-Logit en fonction de ce qui est expliqué ici.
Utilisation du package MLogit de R
Dans le jeu de données Yogurt, les marques de yaourt sont regroupées en deux nids :
• Marques internationales : Dannon et Yoplait
• Marques locales : Hiland et Weight
Probabilités de Choix dans le Modèle Nested- Logit
Pour estimer correctement le modèle Nested-Logit avec le package MLogit de R, il est essentiel de comprendre les probabilités de choix sous-jacentes. En raison de la symétrie du modèle, où chaque nid contient deux produits, la forme de la probabilité de choisir une alternative est la même pour toutes les alternatives. Ainsi, nous illustrons ci-dessous la probabilité de choisir la première alternative :
Cette formule illustre la probabilité de choisir l’alternative 1, mais elle prend la même forme pour les autres alternatives en raison de la structure symétrique du modèle. Cette symétrie est présente ici parce qu’il y a deux produits dans chaque nid. L’attribution des indices aux différentes marques est purement arbitraire, ce qui justifie de ne considérer qu’une seule probabilité pour l’illustration.
Interprétation du Paramètre σ
Le paramètre σ joue un rôle crucial dans la modélisation des corrélations entre les alternatives au sein des nids :
• σ = 0 : Indique qu’il n’y a aucune corrélation entre les alternatives, ce qui revient à un modèle Logit simple.
• σ = 1 : Indique que les alternatives dans le même nid sont parfaitement corrélées.
Vous remarquerez peut-être que ce modèle rajoute un paramètre, σ, et englobe le modèle initial, le modèle Logit Multinomial (MNL). Cela pourrait vous amener à penser que c’est un meilleur modèle. Cependant, enéconométrie, nous cherchons à utiliser les paramètres avec parcimonie. Ajouter plus de paramètres va nécessairement améliorer l’ajustement du modèle aux données, mais cela peut aussi conduire à un sur-ajustement (overfitting).
Chaque fois que nous ajoutons un paramètre, nous avons un bénéfice en ter- mes de meilleur ajustement des données, mais nous devons aussi considérer une pénalité pour l’ajout de ce paramètre. Pour déterminer si l’ajout de paramètres est bénéfique, nous utilisons des critères comme le critère d’Akaike (AIC), que nous n’expliquerons pas en détail ici, mais dont vous devez être conscients.
# Préparation des données en utilsant mlogit.data
Ywide <- Yogurt %>% mutate(choiceid = row_number())
yogurt_data_mlogit <- mlogit.data(Ywide, shape = "wide", choice = "choice",
varying = 2:9, sep = ".",
id.var = "id",
chid.var = "choiceid")- Estimation du modèle Nested logit en définissant dans l’argument \(‘nests‘\) la structure de nids suivante :
International (yoplait, dannon)
Local (hiland, weight)
# Estimation du modèle en activant l'options nests
nested_model <- mlogit(choice ~ log(price) | 0,
data = yogurt_data_mlogit,
nests = list(International = c("yoplait", "dannon"),
Local = c("hiland", "weight")),
reflevel = "hiland")
# reflevel est la référence, ici le produit (hiland)- Analyse des résultats : Après l’estimation, l’analyse des résultats utilise \(`summary`\) pour examiner les fréquences des alternatives, l’optimisation, et les mesures de qualité du modèle.
# Results analysis
summary(nested_model)
Call:
mlogit(formula = choice ~ log(price) | 0, data = yogurt_data_mlogit,
reflevel = "hiland", nests = list(International = c("yoplait",
"dannon"), Local = c("hiland", "weight")))
Frequencies of alternatives:choice
hiland dannon weight yoplait
0.029436 0.402156 0.229270 0.339138
bfgs method
35 iterations, 0h:0m:1s
g'(-H)^-1g = 23.9
last step couldn't find higher value
Coefficients :
Estimate Std. Error z-value Pr(>|z|)
log(price) -2.7862 0.3592 -7.7568 8.66e-15 ***
iv:International -1062.8439 36939.3100 -0.0288 0.977
iv:Local -1065.8509 36939.2393 -0.0289 0.977
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Log-Likelihood: -2984.1