You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Data-Science-For-Beginners/translations/fr/1-Introduction/04-stats-and-probability/notebook.ipynb

581 lines
19 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Introduction à la probabilité et aux statistiques\n",
"Dans ce carnet, nous allons explorer certains des concepts que nous avons précédemment abordés. De nombreux concepts de probabilité et de statistiques sont bien représentés dans les principales bibliothèques de traitement de données en Python, telles que `numpy` et `pandas`.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import pandas as pd\n",
"import random\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Variables aléatoires et distributions\n",
"Commençons par tirer un échantillon de 30 valeurs à partir d'une distribution uniforme de 0 à 9. Nous allons également calculer la moyenne et la variance.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"sample = [ random.randint(0,10) for _ in range(30) ]\n",
"print(f\"Sample: {sample}\")\n",
"print(f\"Mean = {np.mean(sample)}\")\n",
"print(f\"Variance = {np.var(sample)}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Pour estimer visuellement combien de valeurs différentes se trouvent dans léchantillon, nous pouvons tracer l'**histogramme** :\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.hist(sample)\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Analyse des données réelles\n",
"\n",
"La moyenne et la variance sont très importantes lors de l'analyse de données du monde réel. Chargons les données sur les joueurs de baseball depuis [SOCR MLB Height/Weight Data](http://wiki.stat.ucla.edu/socr/index.php/SOCR_Data_MLB_HeightsWeights)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df = pd.read_csv(\"../../data/SOCR_MLB.tsv\",sep='\\t', header=None, names=['Name','Team','Role','Weight','Height','Age'])\n",
"df\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> Nous utilisons un package appelé [**Pandas**](https://pandas.pydata.org/) ici pour l'analyse des données. Nous parlerons plus en détail de Pandas et du travail avec les données en Python plus tard dans ce cours.\n",
"\n",
"Calculons les valeurs moyennes pour l'âge, la taille et le poids :\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df[['Age','Height','Weight']].mean()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Concentrons-nous maintenant sur la taille, et calculons l'écart type et la variance :\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(list(df['Height'])[:20])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"mean = df['Height'].mean()\n",
"var = df['Height'].var()\n",
"std = df['Height'].std()\n",
"print(f\"Mean = {mean}\\nVariance = {var}\\nStandard Deviation = {std}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"En plus de la moyenne, il est judicieux d'examiner la valeur médiane et les quartiles. Ils peuvent être visualisés à l'aide d'un **diagramme en boîte** :\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.figure(figsize=(10,2))\n",
"plt.boxplot(df['Height'].ffill(), vert=False, showmeans=True)\n",
"plt.grid(color='gray', linestyle='dotted')\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Nous pouvons également réaliser des diagrammes en boîte de sous-ensembles de notre ensemble de données, par exemple, regroupés par rôle du joueur.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df.boxplot(column='Height', by='Role', figsize=(10,8))\n",
"plt.xticks(rotation='vertical')\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **Note** : Ce diagramme suggère qu'en moyenne, les joueurs de première base sont plus grands que les joueurs de deuxième base. Plus tard, nous apprendrons comment tester cette hypothèse de manière plus formelle, et comment démontrer que nos données sont statistiquement significatives pour le montrer. \n",
"\n",
"L'âge, la taille et le poids sont tous des variables aléatoires continues. Quelle est selon vous leur distribution ? Une bonne façon de le découvrir est de tracer l'histogramme des valeurs : \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df['Weight'].hist(bins=15, figsize=(10,6))\n",
"plt.suptitle('Weight distribution of MLB Players')\n",
"plt.xlabel('Weight')\n",
"plt.ylabel('Count')\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Distribution Normale\n",
"\n",
"Créons un échantillon artificiel de poids qui suit une distribution normale avec la même moyenne et variance que nos données réelles :\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"generated = np.random.normal(mean, std, 1000)\n",
"generated[:20]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.figure(figsize=(10,6))\n",
"plt.hist(generated, bins=15)\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.figure(figsize=(10,6))\n",
"plt.hist(np.random.normal(0,1,50000), bins=300)\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Puisque la plupart des valeurs dans la vie réelle suivent une distribution normale, nous ne devrions pas utiliser un générateur de nombres aléatoires uniformes pour générer des données d'échantillon. Voici ce qui se passe si nous essayons de générer des poids avec une distribution uniforme (générée par `np.random.rand`):\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"wrong_sample = np.random.rand(1000)*2*std+mean-std\n",
"plt.figure(figsize=(10,6))\n",
"plt.hist(wrong_sample)\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Intervalles de confiance\n",
"\n",
"Calculons maintenant les intervalles de confiance pour les poids et tailles des joueurs de baseball. Nous allons utiliser le code [de cette discussion Stack Overflow](https://stackoverflow.com/questions/15033511/compute-a-confidence-interval-from-sample-data) :\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import scipy.stats\n",
"\n",
"def mean_confidence_interval(data, confidence=0.95):\n",
" a = 1.0 * np.array(data)\n",
" n = len(a)\n",
" m, se = np.mean(a), scipy.stats.sem(a)\n",
" h = se * scipy.stats.t.ppf((1 + confidence) / 2., n-1)\n",
" return m, h\n",
"\n",
"for p in [0.85, 0.9, 0.95]:\n",
" m, h = mean_confidence_interval(df['Weight'].fillna(method='pad'),p)\n",
" print(f\"p={p:.2f}, mean = {m:.2f} ± {h:.2f}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Test d'hypothèse\n",
"\n",
"Explorons différents rôles dans notre ensemble de données sur les joueurs de baseball :\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df.groupby('Role').agg({ 'Weight' : 'mean', 'Height' : 'mean', 'Age' : 'count'}).rename(columns={ 'Age' : 'Count'})"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Testons l'hypothèse que les premiers buteurs sont plus grands que les seconds buteurs. La manière la plus simple de le faire est de tester les intervalles de confiance :\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"for p in [0.85,0.9,0.95]:\n",
" m1, h1 = mean_confidence_interval(df.loc[df['Role']=='First_Baseman',['Height']],p)\n",
" m2, h2 = mean_confidence_interval(df.loc[df['Role']=='Second_Baseman',['Height']],p)\n",
" print(f'Conf={p:.2f}, 1st basemen height: {m1-h1[0]:.2f}..{m1+h1[0]:.2f}, 2nd basemen height: {m2-h2[0]:.2f}..{m2+h2[0]:.2f}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Nous pouvons voir que les intervalles ne se chevauchent pas.\n",
"\n",
"Une manière statistiquement plus correcte de prouver lhypothèse est dutiliser un **test t de Student** :\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from scipy.stats import ttest_ind\n",
"\n",
"tval, pval = ttest_ind(df.loc[df['Role']=='First_Baseman',['Height']], df.loc[df['Role']=='Second_Baseman',['Height']],equal_var=False)\n",
"print(f\"T-value = {tval[0]:.2f}\\nP-value: {pval[0]}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Les deux valeurs retournées par la fonction `ttest_ind` sont :\n",
"* La p-value peut être considérée comme la probabilité que deux distributions aient la même moyenne. Dans notre cas, elle est très faible, ce qui signifie qu'il existe une forte preuve soutenant que les premiers buts sont plus grands.\n",
"* La t-value est la valeur intermédiaire de la différence de moyenne normalisée qui est utilisée dans le test t, et elle est comparée à une valeur seuil pour un niveau de confiance donné.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Simulation d'une distribution normale avec le théorème central limite\n",
"\n",
"Le générateur pseudo-aléatoire en Python est conçu pour nous donner une distribution uniforme. Si nous voulons créer un générateur pour une distribution normale, nous pouvons utiliser le théorème central limite. Pour obtenir une valeur distribuée normalement, nous allons simplement calculer la moyenne d'un échantillon généré uniformément.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def normal_random(sample_size=100):\n",
" sample = [random.uniform(0,1) for _ in range(sample_size) ]\n",
" return sum(sample)/sample_size\n",
"\n",
"sample = [normal_random() for _ in range(100)]\n",
"plt.figure(figsize=(10,6))\n",
"plt.hist(sample)\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Corrélation et Evil Baseball Corp\n",
"\n",
"La corrélation nous permet de trouver des relations entre des séquences de données. Dans notre exemple ludique, imaginons qu'il existe une corporation de baseball maléfique qui paie ses joueurs en fonction de leur taille - plus le joueur est grand, plus il/elle reçoit d'argent. Supposons qu'il y ait un salaire de base de 1000 $, et un bonus additionnel de 0 à 100 $, selon la taille. Nous prendrons les vrais joueurs de la MLB, et calculerons leurs salaires imaginaires :\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"heights = df['Height'].fillna(method='pad')\n",
"salaries = 1000+(heights-heights.min())/(heights.max()-heights.mean())*100\n",
"print(list(zip(heights, salaries))[:10])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Calculons maintenant la covariance et la corrélation de ces séquences. `np.cov` nous donnera une **matrice de covariance**, qui est une extension de la covariance à plusieurs variables. L'élément $M_{ij}$ de la matrice de covariance $M$ est une covariance entre les variables d'entrée $X_i$ et $X_j$, et les valeurs diagonales $M_{ii}$ sont la variance de $X_{i}$. De même, `np.corrcoef` nous donnera la **matrice de corrélation**.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(f\"Covariance matrix:\\n{np.cov(heights, salaries)}\")\n",
"print(f\"Covariance = {np.cov(heights, salaries)[0,1]}\")\n",
"print(f\"Correlation = {np.corrcoef(heights, salaries)[0,1]}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Une corrélation égale à 1 signifie qu'il existe une **relation linéaire** forte entre deux variables. Nous pouvons voir visuellement la relation linéaire en traçant une valeur par rapport à l'autre :\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.figure(figsize=(10,6))\n",
"plt.scatter(heights,salaries)\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Voyons ce qui se passe si la relation n'est pas linéaire. Supposons que notre entreprise ait décidé de cacher la dépendance linéaire évidente entre les tailles et les salaires, et ait introduit une certaine non-linéarité dans la formule, comme `sin` :\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"salaries = 1000+np.sin((heights-heights.min())/(heights.max()-heights.mean()))*100\n",
"print(f\"Correlation = {np.corrcoef(heights, salaries)[0,1]}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Dans ce cas, la corrélation est légèrement plus faible, mais elle reste assez élevée. Maintenant, pour rendre la relation encore moins évidente, nous pourrions vouloir ajouter un peu de hasard supplémentaire en ajoutant une variable aléatoire au salaire. Voyons ce qui se passe :\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"salaries = 1000+np.sin((heights-heights.min())/(heights.max()-heights.mean()))*100+np.random.random(size=len(heights))*20-10\n",
"print(f\"Correlation = {np.corrcoef(heights, salaries)[0,1]}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.figure(figsize=(10,6))\n",
"plt.scatter(heights, salaries)\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> Pouvez-vous deviner pourquoi les points salignent en lignes verticales comme ceci ?\n",
"\n",
"Nous avons observé la corrélation entre un concept artificiellement conçu comme le salaire et la variable observée *taille*. Voyons également si les deux variables observées, comme la taille et le poids, sont également corrélées :\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"np.corrcoef(df['Height'].ffill(),df['Weight'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Malheureusement, nous n'avons obtenu aucun résultat - seulement quelques valeurs étranges `nan`. Cela est dû au fait que certaines des valeurs de notre série sont indéfinies, représentées comme `nan`, ce qui entraîne que le résultat de l'opération soit également indéfini. En regardant la matrice, on peut voir que `Weight` est la colonne problématique, car la corrélation avec elle-même entre les valeurs de `Height` a été calculée.\n",
"\n",
"> Cet exemple montre l'importance de la **préparation des données** et du **nettoyage**. Sans données appropriées, nous ne pouvons rien calculer.\n",
"\n",
"Utilisons la méthode `fillna` pour remplir les valeurs manquantes, et calculons la corrélation :\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"np.corrcoef(df['Height'].fillna(method='pad'), df['Weight'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Il existe en effet une corrélation, mais pas aussi forte que dans notre exemple artificiel. En effet, si l'on regarde le nuage de points d'une valeur par rapport à l'autre, la relation serait beaucoup moins évidente :\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.figure(figsize=(10,6))\n",
"plt.scatter(df['Weight'],df['Height'])\n",
"plt.xlabel('Weight')\n",
"plt.ylabel('Height')\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Conclusion\n",
"\n",
"Dans ce carnet, nous avons appris comment effectuer des opérations de base sur les données pour calculer des fonctions statistiques. Nous savons maintenant comment utiliser un appareil mathématique et statistique solide afin de vérifier certaines hypothèses, et comment calculer des intervalles de confiance pour des variables arbitraires à partir d'un échantillon de données.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**Clause de non-responsabilité** : \nCe document a été traduit à laide du service de traduction automatique [Co-op Translator](https://github.com/Azure/co-op-translator). Bien que nous nous efforcions dassurer lexactitude de la traduction, veuillez noter que les traductions automatiques peuvent contenir des erreurs ou des inexactitudes. Le document original dans sa langue native doit être considéré comme la source faisant foi. Pour les informations critiques, il est recommandé de recourir à une traduction professionnelle effectuée par un humain. Nous déclinons toute responsabilité en cas de malentendus ou dinterprétations erronées résultant de lutilisation de cette traduction.\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "86193a1ab0ba47eac1c69c1756090baa3b420b3eea7d4aafab8b85f8b312f0c5"
},
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
},
"coopTranslator": {
"original_hash": "0f899e3c5019f948e7c787b22f3b2304",
"translation_date": "2026-01-16T07:34:36+00:00",
"source_file": "1-Introduction/04-stats-and-probability/notebook.ipynb",
"language_code": "fr"
}
},
"nbformat": 4,
"nbformat_minor": 4
}