Environnement - Chargement, inspection¶
In [73]:
# activation de l'environnement
using Pkg
Pkg.activate("./env_julia_stats")
Activating project at `c:\Users\ricco\Desktop\demo\env_julia_stats`
In [74]:
# lister les packages installés
Pkg.status()
Status `C:\Users\ricco\Desktop\demo\env_julia_stats\Project.toml` [a93c6f00] DataFrames v1.8.1 [7073ff75] IJulia v1.34.4 [2913bbd2] StatsBase v0.34.10 [f3b207a7] StatsPlots v0.15.8 [fdbf4ff8] XLSX v0.11.2
Chargement et inspection des données¶
In [75]:
# chargement des données
import DataFrames as DFR
import XLSX
# lecture
df_source = DFR.DataFrame(XLSX.readtable("./autos.xlsx","dataset"))
println(DFR.first(df_source,10))
10×8 DataFrame Row │ Modele puissance cylindree vitesse poids prix origine carburant │ String Int64 Int64 Int64 Int64 Int64 String String ─────┼─────────────────────────────────────────────────────────────────────────── 1 │ PANDA 54 1108 150 860 8070 Europe Essence 2 │ TWINGO 60 1149 151 840 8950 France Essence 3 │ CITRONC2 61 1124 158 932 10700 France Essence 4 │ YARIS 65 998 155 880 10450 Autres Essence 5 │ FIESTA 68 1399 164 1138 14150 Europe Diesel 6 │ CORSA 70 1248 165 1035 13590 Europe Diesel 7 │ GOLF 75 1968 163 1217 19140 Europe Diesel 8 │ P1007 75 1360 165 1181 13600 France Essence 9 │ MUSA 100 1910 179 1275 17900 Europe Diesel 10 │ CLIO 100 1461 185 980 17600 France Diesel
In [76]:
# dimensions
println("Dimensions : $(DFR.size(df_source))")
println("Nb de lignes : $(DFR.nrow(df_source))")
println("Nb de colonnes : $(DFR.ncol(df_source))")
Dimensions : (30, 8) Nb de lignes : 30 Nb de colonnes : 8
In [77]:
# description sommaire
println(DFR.describe(df_source))
8×7 DataFrame Row │ variable mean min median max nmissing eltype │ Symbol Union… Any Union… Any Int64 DataType ─────┼─────────────────────────────────────────────────────────────────── 1 │ Modele ALFA156 YARIS 0 String 2 │ puissance 137.667 54 139.0 250 0 Int64 3 │ cylindree 1903.43 998 1979.5 3222 0 Int64 4 │ vitesse 199.4 150 200.5 250 0 Int64 5 │ poids 1310.4 840 1369.0 1735 0 Int64 6 │ prix 24557.3 8070 23975.0 46450 0 Int64 7 │ origine Autres France 0 String 8 │ carburant Diesel Essence 0 String
In [78]:
# uniquement pour les variables quantitatives
df_temp = df_source[:,names(df_source,Number)]
# description
println(DFR.describe(df_temp))
5×7 DataFrame Row │ variable mean min median max nmissing eltype │ Symbol Float64 Int64 Float64 Int64 Int64 DataType ─────┼───────────────────────────────────────────────────────────────── 1 │ puissance 137.667 54 139.0 250 0 Int64 2 │ cylindree 1903.43 998 1979.5 3222 0 Int64 3 │ vitesse 199.4 150 200.5 250 0 Int64 4 │ poids 1310.4 840 1369.0 1735 0 Int64 5 │ prix 24557.3 8070 23975.0 46450 0 Int64
In [79]:
# créer une copie "profonde"
df = DFR.deepcopy(df_source)
# premières lignes
println(df[1:10,:])
10×8 DataFrame Row │ Modele puissance cylindree vitesse poids prix origine carburant │ String Int64 Int64 Int64 Int64 Int64 String String ─────┼─────────────────────────────────────────────────────────────────────────── 1 │ PANDA 54 1108 150 860 8070 Europe Essence 2 │ TWINGO 60 1149 151 840 8950 France Essence 3 │ CITRONC2 61 1124 158 932 10700 France Essence 4 │ YARIS 65 998 155 880 10450 Autres Essence 5 │ FIESTA 68 1399 164 1138 14150 Europe Diesel 6 │ CORSA 70 1248 165 1035 13590 Europe Diesel 7 │ GOLF 75 1968 163 1217 19140 Europe Diesel 8 │ P1007 75 1360 165 1181 13600 France Essence 9 │ MUSA 100 1910 179 1275 17900 Europe Diesel 10 │ CLIO 100 1461 185 980 17600 France Diesel
In [80]:
# créer une variable supplémentaire (rapport poids/puissance)
# ./ parce qu'opération véctorisée
# c.-à-d. s'applique à un vecteur et non pas un scalaire
df.r_pp = df.poids ./ df.puissance
# premières lignes
println(DFR.first(df,10))
10×9 DataFrame Row │ Modele puissance cylindree vitesse poids prix origine carburant r_pp │ String Int64 Int64 Int64 Int64 Int64 String String Float64 ─────┼──────────────────────────────────────────────────────────────────────────────────── 1 │ PANDA 54 1108 150 860 8070 Europe Essence 15.9259 2 │ TWINGO 60 1149 151 840 8950 France Essence 14.0 3 │ CITRONC2 61 1124 158 932 10700 France Essence 15.2787 4 │ YARIS 65 998 155 880 10450 Autres Essence 13.5385 5 │ FIESTA 68 1399 164 1138 14150 Europe Diesel 16.7353 6 │ CORSA 70 1248 165 1035 13590 Europe Diesel 14.7857 7 │ GOLF 75 1968 163 1217 19140 Europe Diesel 16.2267 8 │ P1007 75 1360 165 1181 13600 France Essence 15.7467 9 │ MUSA 100 1910 179 1275 17900 Europe Diesel 12.75 10 │ CLIO 100 1461 185 980 17600 France Diesel 9.8
In [81]:
# ou autre manière de créer une variable avec transform()
# ratio chevaux/litre (de cylindrée)
df = DFR.transform(df,[:puissance,:cylindree] => ((x,y) -> x./(y ./ 1000.0)) => :r_pc)
# premières lignes
println(DFR.first(df,10))
10×10 DataFrame Row │ Modele puissance cylindree vitesse poids prix origine carburant r_pp r_pc │ String Int64 Int64 Int64 Int64 Int64 String String Float64 Float64 ─────┼───────────────────────────────────────────────────────────────────────────────────────────── 1 │ PANDA 54 1108 150 860 8070 Europe Essence 15.9259 48.7365 2 │ TWINGO 60 1149 151 840 8950 France Essence 14.0 52.2193 3 │ CITRONC2 61 1124 158 932 10700 France Essence 15.2787 54.2705 4 │ YARIS 65 998 155 880 10450 Autres Essence 13.5385 65.1303 5 │ FIESTA 68 1399 164 1138 14150 Europe Diesel 16.7353 48.6061 6 │ CORSA 70 1248 165 1035 13590 Europe Diesel 14.7857 56.0897 7 │ GOLF 75 1968 163 1217 19140 Europe Diesel 16.2267 38.1098 8 │ P1007 75 1360 165 1181 13600 France Essence 15.7467 55.1471 9 │ MUSA 100 1910 179 1275 17900 Europe Diesel 12.75 52.356 10 │ CLIO 100 1461 185 980 17600 France Diesel 9.8 68.4463
In [82]:
# les 5 voitures les plus performantes
# en termes de chevaux/litre (de cylindree)
println(DFR.sort(df,:r_pc,rev=true)[1:5,:])
5×10 DataFrame Row │ Modele puissance cylindree vitesse poids prix origine carburant r_pp r_pc │ String Int64 Int64 Int64 Int64 Int64 String String Float64 Float64 ─────┼─────────────────────────────────────────────────────────────────────────────────────────────── 1 │ MAZDARX8 231 1308 235 1390 34000 Autres Essence 6.01732 176.606 2 │ PTCRUISER 223 2429 200 1595 27400 Autres Essence 7.15247 91.8073 3 │ P307CC 180 1997 225 1490 28850 France Essence 8.27778 90.1352 4 │ PASSAT 150 1781 221 1360 27740 Europe Essence 9.06667 84.2223 5 │ CITRONC5 210 2496 230 1589 33000 France Essence 7.56667 84.1346
Statistiques sur une variable (package Statistics)¶
In [83]:
# accès à la variable prix
# ! veut dire qu'on a un pointeur sur la variable
# /!\ attention si on modifie le vecteur donc !!!
# df[:,:prix] on ferait une copie de la variable
prix = df[!,:prix]
println(prix)
[8070, 8950, 10700, 10450, 14150, 13590, 19140, 13600, 17900, 17600, 21630, 16950, 26400, 23400, 23400, 24550, 23100, 26550, 27740, 38250, 25350, 27800, 28850, 40550, 46450, 33000, 27400, 34000, 46400, 40800]
In [84]:
# 5 premières valeurs (pas de tri)
DFR.first(prix,5)
5-element Vector{Int64}:
8070
8950
10700
10450
14150
In [85]:
# 5 dernières valeurs (pas de tri)
DFR.last(prix,5)
5-element Vector{Int64}:
33000
27400
34000
46400
40800
In [86]:
# obtenir les valeurs triées
println(sort(prix))
[8070, 8950, 10450, 10700, 13590, 13600, 14150, 16950, 17600, 17900, 19140, 21630, 23100, 23400, 23400, 24550, 25350, 26400, 26550, 27400, 27740, 27800, 28850, 33000, 34000, 38250, 40550, 40800, 46400, 46450]
In [87]:
# description - méthode de DataFrames
println(DFR.describe(df[!,["prix"]]))
1×7 DataFrame Row │ variable mean min median max nmissing eltype │ Symbol Float64 Int64 Float64 Int64 Int64 DataType ─────┼────────────────────────────────────────────────────────────── 1 │ prix 24557.3 8070 23975.0 46450 0 Int64
In [88]:
# méthodes de la librairie Statistics
# installée par défaut
import Statistics as ST
println("Pour la variable Prix")
println("Moyenne : $(ST.mean(prix))")
println("Mediane : $(ST.median(prix))")
println("Min : $(ST.minimum(prix))")
println("Max : $(ST.maximum(prix))")
println("Variance : $(ST.var(prix))") #échantillon
println("Ecart-type : $(ST.std(prix))") #échantillon
Pour la variable Prix Moyenne : 24557.333333333332 Mediane : 23975.0 Min : 8070 Max : 46450 Variance : 1.1474124091954023e8 Ecart-type : 10711.733796148046
In [89]:
# variance et écart-type population
println("Variance : $(ST.var(prix,corrected=false))")
println("Ecart-type : $(ST.std(prix,corrected=false))")
Variance : 1.1091653288888888e8 Ecart-type : 10531.691834120902
In [90]:
# on peut effectuer plusieurs calculs d'un coup avec map()
DFR.map(f -> f(prix),[ST.mean,ST.median])
2-element Vector{Float64}:
24557.333333333332
23975.0
In [91]:
# les quantiles (quartiles ici)
println(ST.quantile(prix,[0.25,0.5,0.75]))
[17112.5, 23975.0, 28587.5]
In [92]:
# appliquer une fonction sur un ensemble de colonnes
# uniquement celles qui sont numériques
println(DFR.combine(df,names(df,Number) .=> ST.mean))
1×7 DataFrame Row │ puissance_mean cylindree_mean vitesse_mean poids_mean prix_mean r_pp_mean r_pc_mean │ Float64 Float64 Float64 Float64 Float64 Float64 Float64 ─────┼─────────────────────────────────────────────────────────────────────────────────────────── 1 │ 137.667 1903.43 199.4 1310.4 24557.3 10.7807 71.5036
In [93]:
# on peut passer n'importe quelle fonction callback
function moyenne(x)
return ST.mean(x)
end
moyenne (generic function with 1 method)
In [94]:
# et donc
println(DFR.combine(df,names(df,Number) .=> moyenne))
1×7 DataFrame Row │ puissance_moyenne cylindree_moyenne vitesse_moyenne poids_moyenne prix_moyenne r_pp_moyenne r_pc_moyenne │ Float64 Float64 Float64 Float64 Float64 Float64 Float64 ─────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────── 1 │ 137.667 1903.43 199.4 1310.4 24557.3 10.7807 71.5036
Plus loin avec le package StatsBase¶
In [95]:
# importation de StatsBase
# qu'il faut installer explicitement dans votre environnement
import StatsBase as STB
In [96]:
# résumé statistique
println(STB.summarystats(prix))
Summary Stats: Length: 30 Missing Count: 0 Mean: 24557.333333 Std. Deviation: 10711.733796 Minimum: 8070.000000 1st Quartile: 17112.500000 Median: 23975.000000 3rd Quartile: 28587.500000 Maximum: 46450.000000
In [97]:
# nombre de valeurs de prix
println(length(prix))
30
In [98]:
# échantillonnage SANS remise
print(STB.sample(prix,5,replace=false))
[13590, 10700, 40800, 27400, 33000]
In [99]:
# échantillonnage AVEC remise
# possible 35 > nombre de valeurs
print(STB.sample(prix,35,replace=true))
[10450, 25350, 17900, 38250, 17600, 23100, 26400, 40550, 34000, 23400, 21630, 46400, 26550, 40800, 16950, 23100, 23400, 46400, 8070, 17600, 46400, 23400, 13590, 14150, 10450, 27400, 27740, 8070, 23400, 25350, 38250, 28850, 40800, 17900, 13590]
In [100]:
# asymétrie et applatissement
println("Asymétrie : $(STB.skewness(prix))")
println("Aplatissement : $(STB.kurtosis(prix))")
Asymétrie : 0.41967761043926655 Aplatissement : -0.5611531575595277
In [101]:
# coefficient de variation
println(STB.variation(prix))
0.4361928736622345
In [102]:
# centrage réduction
z = STB.zscore(prix)
# vérification
println("Moyenne z = $(STB.mean(z))")
println("Ecart-type z = $(STB.std(z))")
Moyenne z = 4.4408920985006264e-17 Ecart-type z = 0.9999999999999999
In [103]:
# fréquence des valeurs - variable catégorielle
println(STB.countmap(df[!,:origine]))
Dict("Europe" => 13, "France" => 13, "Autres" => 4)
In [104]:
# fréquences relatives
println(STB.proportionmap(df[!,:origine]))
Dict("Europe" => 0.43333333333333335, "France" => 0.43333333333333335, "Autres" => 0.13333333333333333)
Quelques graphiques avec StatsPlots¶
In [105]:
# graphiques statistiques
# plus loin que le basique Plots
import StatsPlots as STP
Histogramme et densité¶
In [106]:
# histogramme
# le nombre de "bins" est paramétrable
STP.histogram(prix,label="Distrib")
In [107]:
# densité estimée
STP.density(prix,label="Densité")
In [108]:
# associer deux densités estimées
# superposition = noter le rôle de ! pour le 2nd appel
STP.density(prix[df.carburant .== "Essence"],label="Essence")
STP.density!(prix[df.carburant .== "Diesel"],label="Diesel")
Barplot¶
In [109]:
# comptage des valeurs pour la variable "origine"
count_origine = STB.countmap(df.origine)
print(count_origine)
Dict("Europe" => 13, "France" => 13, "Autres" => 4)
In [110]:
# dictionnaire : clés et valeurs
# clés
println("Clés = $(collect(keys(count_origine)))")
# valeurs
println("Valeurs = $(collect(values(count_origine)))")
Clés = ["Europe", "France", "Autres"] Valeurs = [13, 13, 4]
In [111]:
# barplot avec ces 2 infos
STP.bar(collect(keys(count_origine)),collect(values(count_origine)),label=nothing)
Nuage de points et corrélation¶
In [112]:
# nuage de points
STP.scatter(df.cylindree,
df.puissance,
xlabel ="Cylindrée",
ylabel = "Puissance",
label = nothing)
In [113]:
# puisque les données sont dans un data frame
# on peut aussi faire avec la directive @STP.df
# j'ai mis sciemment df_source pour qu'il n'y ait pas de confusion
# avec le nom du data frame que nous manipulons
@STP.df df_source STP.scatter(:cylindree,:puissance,label=nothing)
In [114]:
# corrélation
println(STB.cor(df.cylindree,df.puissance))
0.8016736413678706
In [115]:
# corrélation de Spearman
println(STB.corspearman(df.cylindree,df.puissance))
0.8083565911202398
In [116]:
# passage par les rangs
# qui utilise les rangs moyens pour les ex-aequo
rx = STB.tiedrank(df.cylindree)
ry = STB.tiedrank(df.puissance)
# corrélation sur les rangs -> corrélation de Spearman
println(STB.cor(rx,ry))
0.8083565911202398
In [117]:
# corrélation vitesse et poids
println("Vitesse, Poids = $(STB.cor(df.vitesse,df.poids))")
# corrélation vitesse et poids / puissance
println("(Vitesse, Poids)/Puissance = $(STB.partialcor(df.vitesse,df.poids,df.puissance))")
Vitesse, Poids = 0.8080739517413219 (Vitesse, Poids)/Puissance = 0.23724517451325983
In [118]:
# nuage de points et droite d'approximation régression linéaire)
STP.scatter(df.cylindree,
df.puissance,
xlabel ="Cylindrée",
ylabel = "Puissance",
label = nothing,
smooth = true)
In [119]:
# nuage de points avec regroupement (carburant)
STP.scatter(df.cylindree,
df.puissance,
xlabel ="Cylindrée",
ylabel = "Puissance",
group = df.carburant,
legend =:bottomright)
Boxplot et Violin¶
In [120]:
# boxplot
STP.boxplot(df.prix,label=nothing)
In [121]:
# boxplot conditionnels
# prix conditionnellement à carburant
STP.boxplot(df.carburant,df.prix,label=nothing)
In [122]:
# ou un violin plot
STP.violin(df.carburant,df.prix,label=nothing)
In [123]:
# et dans le délire total
STP.violin(df.carburant,df.prix,label=nothing,width=1)
STP.boxplot!(df.carburant,df.prix,label=nothing,bar_width=0.1)
Matrice des corrélations et pairplots¶
In [124]:
# isoler les variables quantitatives
df_quanti = DFR.select(df,names(df,Number))
println(names(df_quanti))
["puissance", "cylindree", "vitesse", "poids", "prix", "r_pp", "r_pc"]
In [125]:
# matrice des corrélations
m_cor = ST.cor(Matrix(df_quanti))
# type et dimension
println("Type = $(typeof(m_cor))")
println("Dimension = $(size(m_cor))")
Type = Matrix{Float64}
Dimension = (7, 7)
In [126]:
# affichage (sans println)
m_cor
7×7 Matrix{Float64}:
1.0 0.801674 0.936572 0.81084 0.899568 -0.930304 0.668476
0.801674 1.0 0.798366 0.826554 0.883874 -0.669906 0.113249
0.936572 0.798366 1.0 0.808074 0.90896 -0.914844 0.592768
0.81084 0.826554 0.808074 1.0 0.883386 -0.67105 0.371193
0.899568 0.883874 0.90896 0.883386 1.0 -0.781062 0.450371
-0.930304 -0.669906 -0.914844 -0.67105 -0.781062 1.0 -0.705166
0.668476 0.113249 0.592768 0.371193 0.450371 -0.705166 1.0
In [127]:
# heatmap avec statsplots
# yflip=true pour que l'affichage soit dans l'ordre des variables
STP.heatmap(names(df_quanti),names(df_quanti),m_cor,yflip=true)
In [128]:
# pairplot (pas présent directement)
# on passe par corrplot
@STP.df df_quanti STP.corrplot(cols(1:7),size=(800,800),markersize=2)
Tableaux croisés¶
In [129]:
# croisement d'origine et carburant, comptage
tab = DFR.combine(DFR.groupby(df,[:origine,:carburant]),DFR.nrow)
println(tab)
6×3 DataFrame Row │ origine carburant nrow │ String String Int64 ─────┼─────────────────────────── 1 │ Europe Essence 6 2 │ France Essence 9 3 │ Autres Essence 3 4 │ Europe Diesel 7 5 │ France Diesel 4 6 │ Autres Diesel 1
In [130]:
# sous forme de tableau croisé
tbc = DFR.unstack(tab,:origine,:carburant,:nrow)
println(tbc)
3×3 DataFrame Row │ origine Essence Diesel │ String Int64? Int64? ─────┼────────────────────────── 1 │ Europe 6 7 2 │ France 9 4 3 │ Autres 3 1