ANOVA à un facteur avec Oracle
Je suis tombé récemment sur un article décrivant la concurrence acharnée entre les grandes surfaces et les stations-service sur le marché du carburant. Cela m’a donné envie d’en savoir davantage et surtout de vérifier par moi-même si cette guerre des prix était « visible » lorsqu’on s’intéressait globalement aux tarifs à la pompe.
Les prix de vente des carburants font l’objet d’un suivi permanent par le ministère de l’économie qui met à disposition un relevé quotidien: http://www.prix-carburants.gouv.fr/rubrique/opendata/
Une réutilisation de ces données incluant la marque des stations-services (à partir des données GPS j’imagine) est accessible via le portail OpenDataSoft:
http://public.opendatasoft.com/explore/dataset/prix_des_carburants_j_7/?tab=metas
Avec l’information de la marque des stations, on peut réaliser des groupements en fonction du type de distributeur: « Grande Distribution » (enseignes comme Carrefour, Leclerc etc…), « Distributeur » (enseignes de vente des sociétés pétrolières comme Total, BP etc…), « Distributeur Low-Cost » (enseignes automatisées des sociétés pétrolières comme Total Access et Esso Express) et Autres pour le reste (Distributeurs Indépendants, petites chaines non-affiliées etc…). On peut ensuite réaliser des comparaisons du prix moyen de vente pour chacun de ces groupes.
Pour cela, j’utilise un test ANOVA qui permet de déterminer s’il existe des différences de moyenne statistiquement significatives entre les échantillons (i.e. H0: les échantillons sont issus d’une même population). Comme le test permet de traiter plusieurs groupes simultanément, on évite ainsi la multiplication de tests t (et l’augmentation associée du risque alpha de première espèce).
L’ANOVA repose sur l’équation d’analyse de variance SCT = SCE + SCR avec:
- SCT: Somme des Carrés Totaux ou Variance Totale
- SCE: Somme des Carrés des Ecarts Interclasse ou Variance Intergroupes
- SCR: Somme des Carrés des Résidus (Ecarts Intraclasse) ou Variance Intragroupe
Les conditions d’utilisation du test sont l’indépendance, la normalité et l’homoscédasticité des échantillons comparés. L’indépendance dépend du mode opératoire et la normalité est peu problématique si l’effectif est grand.
En revanche, la condition d’homoscédasticité est plus épineuse (et ce d’autant plus que les effectifs des échantillons sont différents). En pratique:
- si les plus petits échantillons proviennent d’une population avec la variance la plus importante, le test devient plus « libéral » = fausse significativité
- si les plus petits échantillons proviennent d’une population avec la variance la moins importante, le test devient plus « conservatif » = mauvaise détection
La règle approximative est que l’ANOVA est robuste pour des échantillons dont le rapport de variance n’excède pas 4:1. Au-delà, dans la limite du raisonnable, on peut essayer de compenser en diminuant le niveau alpha du test.
Oracle propose la fonction STATS_ONE_WAY_ANOVA pour réaliser des test ANOVA a un facteur.
Le fichier de données utilisé dans cette analyse est disponible ici: prix_des_carburants_j_7
Chargement des données via une table externe
SQL> CREATE TABLE exttab_carburants
2 (
3 Id NUMBER,
4 CP VARCHAR2 (20),
5 Axe VARCHAR2 (5),
6 Adresse VARCHAR2 (200),
7 Ville VARCHAR2 (50),
8 HO VARCHAR2 (30),
9 HF VARCHAR2 (30),
10 JF VARCHAR2 (200),
11 TF VARCHAR2 (50),
12 DF VARCHAR2 (20),
13 FF VARCHAR2 (20),
14 Carburant VARCHAR2 (50),
15 Rupture VARCHAR2 (30),
16 MAJ VARCHAR2 (30),
17 PGazole VARCHAR2 (30),
18 PSP95 VARCHAR2 (30),
19 PSP98 VARCHAR2 (30),
20 PGPL VARCHAR2 (30),
21 PE10 VARCHAR2 (30),
22 PE85 VARCHAR2 (30),
23 Services VARCHAR2 (500),
24 Marque VARCHAR2 (500),
25 Nom VARCHAR2 (500),
26 GeoPoint VARCHAR2 (50)
27 )
28 ORGANIZATION EXTERNAL
29 (TYPE oracle_loader
30 DEFAULT DIRECTORY datadir
31 ACCESS PARAMETERS
32 (
33 RECORDS DELIMITED BY NEWLINE
34 SKIP 1
35 FIELDS TERMINATED BY ';' OPTIONALLY ENCLOSED BY '"'
36 MISSING FIELD VALUES ARE NULL)
37 LOCATION ('prix_des_carburants_j_7.csv'));
Table created.
SQL>
Groupement des données par une vue
On s’intéresse uniquement aux données récentes (de la semaine passée) hors stations d’autoroute.
SQL> CREATE OR REPLACE VIEW CARBURANTS
2 AS
3 SELECT marque,
4 TO_NUMBER (pgazole) prix_gazole,
5 CASE
6 WHEN marque IN ('Agip',
7 'Esso',
8 'BP',
9 'Avia',
10 'Total',
11 'Elan',
12 'Shell',
13 'Dyneff',
14 'VITO')
15 THEN
16 'Distributeur'
17 WHEN marque IN ('Intermarché',
18 'Système U',
19 'Auchan',
20 'Leclerc',
21 'Carrefour',
22 'Carrefour Market',
23 'Carrefour Contact',
24 'Atac',
25 'Casino',
26 'Colruyt',
27 'CORA',
28 'Géant',
29 'Netto',
30 'Leader Price',
31 'Ecomarché',
32 'Intermarché Contact',
33 'Super Casino',
34 'Supermarché Match',
35 'Simply Market',
36 'Shopi')
37 THEN
38 'Grande Distribution'
39 WHEN marque IN ('Esso Express', 'Total Access')
40 THEN
41 'Distributeur Low Cost'
42 ELSE
43 'Autre'
44 END
45 type_distrib
46 FROM exttab_carburants
47 WHERE TO_DATE (SUBSTR (maj, 1, 10), 'YYYY-MM-DD') >=
48 TO_DATE ('03/06/2015', 'DD/MM/YYYY')
49 AND pgazole IS NOT NULL
50 AND axe != 'A';
View created.
SQL>
On obtient donc 4 classes:
- Grande Distribution
- Distributeur
- Distributeur Low-Cost
- Autre
La classe « Autre » représentant une grande hétérogénéité dans ses membres sera ignorée dans la suite.
Vérification de l’homoscédasticité
SQL> SELECT type_distrib, VAR_SAMP (prix_gazole), COUNT (*) 2 FROM carburants 3 WHERE type_distrib != 'Autre' 4 GROUP BY type_distrib; TYPE_DISTRIB VAR_SAMP(PRIX_GAZOLE) COUNT(*) --------------------- --------------------- ---------- Distributeur .001094295 1203 Distributeur Low Cost .000223032 358 Grande Distribution .000717468 3834 SQL>
Ici, les effectifs sont inégaux et le rapport entre les variances min/max est de 4.9:1.
On est donc aux limites d’applicabilité du test.
Réalisation du test
SQL> SELECT STATS_ONE_WAY_ANOVA (type_distrib, prix_gazole, 'SUM_SQUARES_BETWEEN')
2 SUM_SQUARES_BETWEEN,
3 STATS_ONE_WAY_ANOVA (type_distrib, prix_gazole, 'SUM_SQUARES_WITHIN')
4 SUM_SQUARES_WITHIN,
5 STATS_ONE_WAY_ANOVA (type_distrib, prix_gazole, 'F_RATIO') F_RATIO,
6 STATS_ONE_WAY_ANOVA (type_distrib, prix_gazole, 'SIG') p_value,
7 STATS_ONE_WAY_ANOVA (type_distrib,
8 prix_gazole,
9 'SUM_SQUARES_BETWEEN')
10 / ( STATS_ONE_WAY_ANOVA (type_distrib,
11 prix_gazole,
12 'SUM_SQUARES_BETWEEN')
13 + STATS_ONE_WAY_ANOVA (type_distrib,
14 prix_gazole,
15 'SUM_SQUARES_WITHIN'))
16 eta2
17 FROM carburants
18 WHERE type_distrib != 'Autre';
SUM_SQUARES_BETWEEN SUM_SQUARES_WITHIN F_RATIO P_VALUE ETA2
------------------- ------------------ ---------- ---------- ----------
7.9395189 4.14502067 5164.01356 0 .656998047
SQL>
La valeur p renvoyée est de 0. L’hypothèse H0 est donc rejetée et on peut considérer qu’il y a bien une différence de moyenne entre au moins deux groupes.
Outre les valeurs restituées par la fonction, je calcule le rapport de corrélation eta-2 via la formule SCE/SCT. Celui-ci indique le degré d’association entre le prix moyen et le type de distributeur – ici, 66% de la variance de prix est « expliquée » par le canal de distribution.
A ce stade, on sait donc que 2 classes au-moins ont un prix moyen statistiquement différent mais on ne sait pas dire lesquelles. En pratique, pour aller plus loin dans l’analyse, il faudrait mettre en œuvre un test post-hoc malheureusement, Oracle n’en propose pas en standard.