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/el/1-Introduction/04-stats-and-probability/notebook.ipynb

581 lines
25 KiB

This file contains ambiguous Unicode 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": [
"# Εισαγωγή στην Πιθανότητα και τη Στατιστική\n",
"Σε αυτό το σημειωματάριο, θα ασχοληθούμε με μερικές από τις έννοιες που έχουμε συζητήσει προηγουμένως. Πολλές έννοιες από την πιθανότητα και τη στατιστική είναι καλά εκπροσωπημένες σε μεγάλες βιβλιοθήκες για επεξεργασία δεδομένων στην Python, όπως οι `numpy` και `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": [
"## Τυχαίες Μεταβλητές και Κατανομές\n",
"Ας ξεκινήσουμε παίρνοντας ένα δείγμα 30 τιμών από μια ομοιόμορφη κατανομή από 0 έως 9. Θα υπολογίσουμε επίσης μέση τιμή και διακύμανση.\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": [
"Για να εκτιμήσουμε οπτικά πόσες διαφορετικές τιμές υπάρχουν στο δείγμα, μπορούμε να σχεδιάσουμε το **ιστόγραμμα**:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.hist(sample)\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Ανάλυση Πραγματικών Δεδομένων\n",
"\n",
"Ο μέσος όρος και η διασπορά είναι πολύ σημαντικά όταν αναλύουμε δεδομένα από τον πραγματικό κόσμο. Ας φορτώσουμε τα δεδομένα σχετικά με παίκτες του μπέιζμπολ από το [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": [
"> Χρησιμοποιούμε ένα πακέτο που ονομάζεται [**Pandas**](https://pandas.pydata.org/) εδώ για ανάλυση δεδομένων. Θα μιλήσουμε περισσότερα για τα Pandas και τη δουλειά με δεδομένα σε Python αργότερα σε αυτό το μάθημα.\n",
"\n",
"Ας υπολογίσουμε μέσες τιμές για την ηλικία, το ύψος και το βάρος:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df[['Age','Height','Weight']].mean()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Τώρα ας επικεντρωθούμε στο ύψος και να υπολογίσουμε την τυπική απόκλιση και την διασπορά:\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": [
"Εκτός από τον μέσο όρο, έχει νόημα να δούμε την διάμεσο τιμή και τα τεταρτημόρια. Μπορούν να απεικονιστούν χρησιμοποιώντας ένα **διάγραμμα κουτιού**:\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": [
"Μπορούμε επίσης να δημιουργήσουμε διαγράμματα κουτιού για υποσύνολα του συνόλου δεδομένων μας, για παράδειγμα, ομαδοποιημένα κατά ρόλο παίκτη.\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": [
"> **Σημείωση**: Αυτό το διάγραμμα υποδηλώνει, ότι κατά μέσο όρο, τα ύψη των πρώτων baseman είναι υψηλότερα από τα ύψη των δευτέρων baseman. Αργότερα θα μάθουμε πώς μπορούμε να δοκιμάσουμε αυτή την υπόθεση πιο επίσημα, και πώς να αποδείξουμε ότι τα δεδομένα μας είναι στατιστικά σημαντικά για να το δείξουν. \n",
"\n",
"Η ηλικία, το ύψος και το βάρος είναι όλες συνεχείς τυχαίες μεταβλητές. Τι πιστεύετε ότι είναι η κατανομή τους; Ένας καλός τρόπος να το ανακαλύψετε είναι να σχεδιάσετε το ιστόγραμμα των τιμών: \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": [
"## Κανονική Κατανομή\n",
"\n",
"Ας δημιουργήσουμε ένα τεχνητό δείγμα βαρών που ακολουθεί μια κανονική κατανομή με τον ίδιο μέσο όρο και διακύμανση με τα πραγματικά μας δεδομένα:\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": [
"Δεδομένου ότι οι περισσότερες τιμές στην πραγματική ζωή ακολουθούν κανονική κατανομή, δεν θα πρέπει να χρησιμοποιούμε γεννήτρια τυχαίων αριθμών ομοιόμορφης κατανομής για τη δημιουργία δειγματικών δεδομένων. Να τι συμβαίνει αν προσπαθήσουμε να δημιουργήσουμε βάρη με ομοιόμορφη κατανομή (που παράγεται από το `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": [
"## Διαστήματα Εμπιστοσύνης\n",
"\n",
"Ας υπολογίσουμε τώρα διαστήματα εμπιστοσύνης για τα βάρη και τα ύψη των παικτών του μπέιζμπολ. Θα χρησιμοποιήσουμε τον κώδικα [από αυτή τη συζήτηση στο stackoverflow](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": [
"## Δοκιμή Υπόθεσης\n",
"\n",
"Ας εξερευνήσουμε διαφορετικούς ρόλους στο σύνολο δεδομένων παικτών μπέιζμπολ μας:\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": [
"Ας ελέγξουμε την υπόθεση ότι οι παίκτες πρώτης βάσης είναι ψηλότεροι από τους παίκτες δεύτερης βάσης. Ο απλούστερος τρόπος για να το κάνουμε αυτό είναι να ελέγξουμε τα διαστήματα εμπιστοσύνης:\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": [
"Μπορούμε να δούμε ότι τα διαστήματα δεν επικαλύπτονται.\n",
"\n",
"Ένας στατιστικά πιο σωστός τρόπος να αποδείξουμε την υπόθεση είναι να χρησιμοποιήσουμε ένα **Student t-test**:\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": [
"Οι δύο τιμές που επιστρέφονται από τη συνάρτηση `ttest_ind` είναι: \n",
"* η τιμή p μπορεί να θεωρηθεί ως η πιθανότητα δύο κατανομών να έχουν τον ίδιο μέσο όρο. Στη δική μας περίπτωση, είναι πολύ χαμηλή, που σημαίνει ότι υπάρχουν ισχυρές αποδείξεις που υποστηρίζουν ότι οι πρώτοι δι baseman είναι πιο ψηλοί. \n",
"* η τιμή t είναι η ενδιάμεση τιμή της ομαλοποιημένης διαφοράς μέσων όρων που χρησιμοποιείται στο t-test, και συγκρίνεται με μια τιμή κατωφλίου για μια δεδομένη τιμή εμπιστοσύνης.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Προσομοίωση Κανονικής Κατανομής με το Κεντρικό Οριακό Θεώρημα\n",
"\n",
"Ο ψευδοτυχαίος γεννήτορας στην Python έχει σχεδιαστεί για να μας δίνει μια ομοιόμορφη κατανομή. Αν θέλουμε να δημιουργήσουμε έναν γεννήτορα για κανονική κατανομή, μπορούμε να χρησιμοποιήσουμε το κεντρικό οριακό θεώρημα. Για να πάρουμε μια τυπικώς κατανεμημένη τιμή, απλώς θα υπολογίσουμε τον μέσο όρο ενός δείγματος που έχει δημιουργηθεί ομοιόμορφα.\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": [
"## Συσχέτιση και η Εταιρεία Κακού Μπέιζμπολ\n",
"\n",
"Η συσχέτιση μας επιτρέπει να βρίσκουμε σχέσεις μεταξύ ακολουθιών δεδομένων. Στο παράδειγμα παιχνιδιού μας, ας υποθέσουμε ότι υπάρχει μια κακή εταιρεία μπέιζμπολ που πληρώνει τους παίκτες της ανάλογα με το ύψος τους - όσο πιο ψηλός είναι ο παίκτης, τόσα περισσότερα χρήματα παίρνει. Ας υποθέσουμε ότι υπάρχει ένας βασικός μισθός των $1000, και ένα επιπλέον μπόνους από $0 έως $100, ανάλογα με το ύψος. Θα πάρουμε τους πραγματικούς παίκτες από το MLB και θα υπολογίσουμε τους φανταστικούς μισθούς τους:\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": [
"Ας υπολογίσουμε τώρα τη συνδιακύμανση και τη συσχέτιση αυτών των ακολουθιών. Η `np.cov` θα μας δώσει τον λεγόμενο **πίνακα συνδιακύμανσης**, που είναι μια επέκταση της συνδιακύμανσης σε πολλαπλές μεταβλητές. Το στοιχείο $M_{ij}$ του πίνακα συνδιακύμανσης $M$ είναι η συνδιακύμανση μεταξύ των εισερχόμενων μεταβλητών $X_i$ και $X_j$, και οι διαγώνιες τιμές $M_{ii}$ είναι η διακύμανση του $X_{i}$. Ομοίως, η `np.corrcoef` θα μας δώσει τον **πίνακα συσχέτισης**.\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": [
"Μια συσχέτιση ίση με 1 σημαίνει ότι υπάρχει μια ισχυρή **γραμμική σχέση** μεταξύ δύο μεταβλητών. Μπορούμε να δούμε οπτικά τη γραμμική σχέση σχεδιάζοντας μια τιμή σε σχέση με την άλλη:\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": [
"Ας δούμε τι συμβαίνει αν η σχέση δεν είναι γραμμική. Ας υποθέσουμε ότι η εταιρεία μας αποφάσισε να κρύψει την προφανή γραμμική εξάρτηση μεταξύ ύψους και μισθών, και εισήγαγε κάποια μη γραμμικότητα στον τύπο, όπως το `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": [
"Σε αυτή την περίπτωση, η συσχέτιση είναι λίγο μικρότερη, αλλά εξακολουθεί να είναι αρκετά υψηλή. Τώρα, για να κάνουμε τη σχέση ακόμη λιγότερο προφανή, ίσως θέλουμε να προσθέσουμε λίγη επιπλέον τυχαιότητα προσθέτοντας κάποια τυχαία μεταβλητή στον μισθό. Ας δούμε τι συμβαίνει:\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": [
"> Μπορείτε να μαντέψετε γιατί οι κουκκίδες ευθυγραμμίζονται σε κατακόρυφες γραμμές σαν αυτές;\n",
"\n",
"Έχουμε παρατηρήσει τη συσχέτιση μεταξύ μιας τεχνητά δημιουργημένης έννοιας όπως ο μισθός και της παρατηρούμενης μεταβλητής *ύψος*. Ας δούμε επίσης αν οι δύο παρατηρούμενες μεταβλητές, όπως το ύψος και το βάρος, συσχετίζονται επίσης:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"np.corrcoef(df['Height'].ffill(),df['Weight'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Δυστυχώς, δεν λάβαμε κανένα αποτέλεσμα - μόνο κάποιες παράξενες τιμές `nan`. Αυτό οφείλεται στο γεγονός ότι μερικές από τις τιμές στη σειρά μας είναι απροσδιόριστες, παρουσιάζονται ως `nan`, γεγονός που προκαλεί το αποτέλεσμα της πράξης να είναι επίσης απροσδιόριστο. Κοιτώντας τον πίνακα μπορούμε να δούμε ότι η στήλη `Weight` είναι το πρόβλημα, επειδή έχει υπολογιστεί η αυτο-συσχέτιση μεταξύ των τιμών του `Height`.\n",
"\n",
"> Αυτό το παράδειγμα δείχνει τη σημασία της **προετοιμασίας δεδομένων** και του **καθαρισμού**. Χωρίς κατάλληλα δεδομένα δεν μπορούμε να υπολογίσουμε τίποτα.\n",
"\n",
"Ας χρησιμοποιήσουμε τη μέθοδο `fillna` για να συμπληρώσουμε τις ελλείπουσες τιμές και να υπολογίσουμε τη συσχέτιση:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"np.corrcoef(df['Height'].fillna(method='pad'), df['Weight'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Πράγματι υπάρχει συσχέτιση, αλλά όχι τόσο ισχυρή όσο στο τεχνητό μας παράδειγμα. Πράγματι, αν κοιτάξουμε το διάγραμμα διασποράς μιας τιμής σε σχέση με την άλλη, η σχέση θα ήταν πολύ λιγότερο προφανής:\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": [
"## Συμπέρασμα\n",
"\n",
"Σε αυτό το σημειωματάριο μάθαμε πώς να εκτελούμε βασικές λειτουργίες σε δεδομένα για να υπολογίσουμε στατιστικές συναρτήσεις. Τώρα ξέρουμε πώς να χρησιμοποιούμε ένα αξιόπιστο εργαλείο μαθηματικών και στατιστικής προκειμένου να αποδείξουμε ορισμένες υποθέσεις, και πώς να υπολογίζουμε διαστήματα εμπιστοσύνης για αυθαίρετες μεταβλητές δεδομένου ενός δείγματος δεδομένων.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**Αποποίηση ευθυνών**: \nΑυτό το έγγραφο έχει μεταφραστεί χρησιμοποιώντας την υπηρεσία αυτόματης μετάφρασης AI [Co-op Translator](https://github.com/Azure/co-op-translator). Παρόλο που επιδιώκουμε την ακρίβεια, παρακαλούμε να λάβετε υπόψη ότι οι αυτοματοποιημένες μεταφράσεις ενδέχεται να περιέχουν λάθη ή ανακρίβειες. Το πρωτότυπο έγγραφο στη γλώσσα του θεωρείται η επίσημη πηγή. Για κρίσιμες πληροφορίες, συνιστάται η επαγγελματική ανθρώπινη μετάφραση. Δεν φέρουμε ευθύνη για οποιεσδήποτε παρανοήσεις ή λανθασμένες ερμηνείες που προκύπτουν από τη χρήση αυτής της μετάφρασης.\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-16T14:47:31+00:00",
"source_file": "1-Introduction/04-stats-and-probability/notebook.ipynb",
"language_code": "el"
}
},
"nbformat": 4,
"nbformat_minor": 4
}