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")
No description has been provided for this image
In [107]:
# densité estimée
STP.density(prix,label="Densité")
No description has been provided for this image
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")
No description has been provided for this image

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)
No description has been provided for this image

Nuage de points et corrélation¶

In [112]:
# nuage de points
STP.scatter(df.cylindree,
            df.puissance,
            xlabel ="Cylindrée",
            ylabel = "Puissance",
            label = nothing)
No description has been provided for this image
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)
No description has been provided for this image
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)
No description has been provided for this image
In [119]:
# nuage de points avec regroupement (carburant)
STP.scatter(df.cylindree,
            df.puissance,
            xlabel ="Cylindrée",
            ylabel = "Puissance",
            group = df.carburant,
            legend =:bottomright)
No description has been provided for this image

Boxplot et Violin¶

In [120]:
# boxplot
STP.boxplot(df.prix,label=nothing)
No description has been provided for this image
In [121]:
# boxplot conditionnels
# prix conditionnellement à carburant
STP.boxplot(df.carburant,df.prix,label=nothing)
No description has been provided for this image
In [122]:
# ou un violin plot
STP.violin(df.carburant,df.prix,label=nothing)
No description has been provided for this image
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)
No description has been provided for this image

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)
No description has been provided for this image
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)
No description has been provided for this image

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