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

581 lines
19 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": [
"# Wprowadzenie do prawdopodobieństwa i statystyki\n",
"W tym notatniku pobawimy się niektórymi z koncepcji, które omawialiśmy wcześniej. Wiele koncepcji z prawdopodobieństwa i statystyki jest dobrze reprezentowanych w głównych bibliotekach do przetwarzania danych w Pythonie, takich jak `numpy` i `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": [
"## Zmienne losowe i rozkłady\n",
"Zacznijmy od pobrania próbki 30 wartości z rozkładu jednostajnego od 0 do 9. Obliczymy również średnią i wariancję.\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": [
"Aby wizualnie oszacować, ile różnych wartości znajduje się w próbce, możemy narysować **histogram**:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.hist(sample)\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Analiza rzeczywistych danych\n",
"\n",
"Średnia i wariancja są bardzo ważne przy analizie danych ze świata rzeczywistego. Załadujmy dane o baseballistach z [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": [
"> Używamy tutaj pakietu o nazwie [**Pandas**](https://pandas.pydata.org/) do analizy danych. O Pandas i pracy z danymi w Pythonie porozmawiamy więcej później w tym kursie.\n",
"\n",
"Obliczmy średnie wartości dla wieku, wzrostu i wagi:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df[['Age','Height','Weight']].mean()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Skoncentrujmy się teraz na wzroście i obliczmy odchylenie standardowe oraz wariancję:\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": [
"Oprócz średniej warto spojrzeć na medianę i kwartyle. Można je zwizualizować za pomocą **wykresu pudełkowego**:\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": [
"Możemy także tworzyć wykresy pudełkowe podzbiorów naszego zbioru danych, na przykład pogrupowanych według roli zawodnika.\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": [
"> **Uwaga**: Ten diagram sugeruje, że średnio wzrost pierwszych bazmanów jest wyższy niż wzrost drugich bazmanów. Później nauczymy się, jak bardziej formalnie przetestować tę hipotezę i jak wykazać, że nasze dane są statystycznie istotne, aby to udowodnić. \n",
"\n",
"Wiek, wzrost i waga to wszystkie ciągłe zmienne losowe. Jak myślisz, jaki mają rozkład? Dobrym sposobem, aby się tego dowiedzieć, jest wykreślenie histogramu wartości: \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": [
"## Rozkład normalny\n",
"\n",
"Stwórzmy sztuczną próbkę wag, która będzie podążać za rozkładem normalnym o takim samym średnim i wariancji jak nasze rzeczywiste dane:\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": [
"Ponieważ większość wartości w rzeczywistym życiu jest rozłożona normalnie, nie powinniśmy używać generatora liczb losowych o rozkładzie jednostajnym do generowania danych próbki. Oto co się stanie, jeśli spróbujemy wygenerować wagi z rozkładem jednostajnym (wygenerowanym przez `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": [
"## Przedziały ufności\n",
"\n",
"Obliczmy teraz przedziały ufności dla wag i wzrostów zawodników baseballu. Użyjemy kodu [z tej dyskusji na 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": [
"## Testowanie hipotez\n",
"\n",
"Przyjrzyjmy się różnym rolom w naszym zestawie danych graczy baseballowych:\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": [
"Przetestujmy hipotezę, że gracze na pozycji pierwszej bazy są wyżsi niż gracze na pozycji drugiej bazy. Najprostszym sposobem jest sprawdzenie przedziałów ufności:\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": [
"Widzimy, że przedziały nie nakładają się.\n",
"\n",
"Statystycznie bardziej poprawnym sposobem na udowodnienie hipotezy jest użycie **testu t-Studenta**:\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": [
"Dwie wartości zwracane przez funkcję `ttest_ind` to:\n",
"* wartość p można uznać za prawdopodobieństwo, że dwie rozkłady mają tę samą średnią. W naszym przypadku jest ona bardzo niska, co oznacza, że istnieją mocne dowody na to, że pierwszi bazowi są wyżsi.\n",
"* wartość t jest pośrednią wartością znormalizowanej różnicy średnich, która jest używana w teście t i porównywana z wartością progową dla określonego poziomu ufności.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Symulacja rozkładu normalnego za pomocą twierdzenia granicznego centralnego\n",
"\n",
"Generator pseudolosowy w Pythonie jest zaprojektowany tak, aby dawać rozkład jednostajny. Jeśli chcemy stworzyć generator dla rozkładu normalnego, możemy użyć twierdzenia granicznego centralnego. Aby uzyskać wartość o rozkładzie normalnym, po prostu obliczymy średnią z próbki wygenerowanej równomiernie.\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": [
"## Korelacja i Zła Korporacja Baseballowa\n",
"\n",
"Korelacja pozwala nam znaleźć zależności między sekwencjami danych. W naszym przykładowym przykładzie załóżmy, że istnieje zła korporacja baseballowa, która płaci swoim graczom zgodnie z ich wzrostem - im wyższy zawodnik, tym więcej pieniędzy otrzymuje. Załóżmy, że jest podstawowa pensja w wysokości 1000$, oraz dodatkowa premia od 0 do 100$, w zależności od wzrostu. Weźmiemy prawdziwych graczy z MLB i obliczymy ich wyimaginowane wynagrodzenia:\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": [
"Obliczmy teraz kowariancję i korelację tych sekwencji. `np.cov` da nam tzw. **macierz kowariancji**, która jest rozszerzeniem kowariancji na wiele zmiennych. Element $M_{ij}$ macierzy kowariancji $M$ jest kowariancją między zmiennymi wejściowymi $X_i$ i $X_j$, a wartości diagonalne $M_{ii}$ to wariancje $X_{i}$. Podobnie, `np.corrcoef` da nam **macierz korelacji**.\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": [
"Korelacja równa 1 oznacza, że istnieje silna **liniowa zależność** między dwiema zmiennymi. Możemy wizualnie zobaczyć liniową zależność, wykreślając jedną wartość względem drugiej:\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": [
"Zobaczmy, co się stanie, jeśli relacja nie jest liniowa. Załóżmy, że nasza korporacja postanowiła ukryć oczywistą liniową zależność między wzrostem a wynagrodzeniem i wprowadziła do wzoru pewną nieliniowość, na przykład `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": [
"W tym przypadku korelacja jest nieco mniejsza, ale nadal dość wysoka. Teraz, aby związek był jeszcze mniej oczywisty, możemy dodać trochę dodatkowego losowego elementu, dodając do wynagrodzenia jakąś losową zmienną. Zobaczmy, co się stanie:\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": [
"> Czy potrafisz zgadnąć, dlaczego kropki układają się w pionowe linie w ten sposób?\n",
"\n",
"Zaobserwowaliśmy korelację między sztucznie zaprojektowaną koncepcją, taką jak wynagrodzenie, a obserwowaną zmienną *wzrost*. Zobaczmy także, czy dwie obserwowane zmienne, takie jak wzrost i waga, również korelują:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"np.corrcoef(df['Height'].ffill(),df['Weight'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Niestety, nie otrzymaliśmy żadnych wyników tylko kilka dziwnych wartości `nan`. Wynika to z faktu, że niektóre wartości w naszej serii są niezdefiniowane, reprezentowane jako `nan`, co powoduje, że wynik operacji również jest niezdefiniowany. Patrząc na macierz widzimy, że kolumna `Weight` jest problematyczna, ponieważ została obliczona autokorelacja pomiędzy wartościami `Height`.\n",
"\n",
"> Ten przykład pokazuje, jak ważne jest **przygotowanie danych** i **czyszczenie**. Bez odpowiednich danych nie możemy nic obliczyć.\n",
"\n",
"Użyjmy metody `fillna`, aby wypełnić brakujące wartości i obliczyć korelację:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"np.corrcoef(df['Height'].fillna(method='pad'), df['Weight'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Istnieje faktycznie korelacja, ale nie tak silna jak w naszym sztucznym przykładzie. Rzeczywiście, jeśli spojrzymy na wykres rozrzutu jednej wartości względem drugiej, związek byłby znacznie mniej oczywisty:\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": [
"## Wnioski\n",
"\n",
"W tym notatniku nauczyliśmy się, jak wykonywać podstawowe operacje na danych, aby obliczać funkcje statystyczne. Wiemy teraz, jak używać solidnego aparatu matematycznego i statystycznego, aby udowodnić niektóre hipotezy oraz jak obliczać przedziały ufności dla dowolnych zmiennych, mając próbkę danych.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**Zrzeczenie się odpowiedzialności**: \nNiniejszy dokument został przetłumaczony przy użyciu automatycznej usługi tłumaczeniowej AI [Co-op Translator](https://github.com/Azure/co-op-translator). Mimo że dokładamy starań, aby tłumaczenie było jak najbardziej precyzyjne, prosimy mieć na uwadze, że automatyczne przekłady mogą zawierać błędy lub nieścisłości. Oryginalny dokument w języku źródłowym należy uważać za ostateczne i autorytatywne źródło. W przypadku informacji o krytycznym znaczeniu zalecane jest skorzystanie z profesjonalnego tłumaczenia wykonanego przez człowieka. Nie ponosimy odpowiedzialności za jakiekolwiek nieporozumienia lub błędne interpretacje wynikające z korzystania z tego tłumaczenia.\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-16T13:50:48+00:00",
"source_file": "1-Introduction/04-stats-and-probability/notebook.ipynb",
"language_code": "pl"
}
},
"nbformat": 4,
"nbformat_minor": 4
}