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

581 lines
24 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": [
"В допълнение към средната стойност, има смисъл да се разгледа медианата и квартили. Те могат да бъдат визуализирани с помощта на **box plot**:\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": [
"> **Бележка**: Тази диаграма подсказва, че средно височините на първите бейзмени са по-големи от височините на вторите бейзмени. По-късно ще научим как можем да тестваме тази хипотеза по-формално и как да демонстрираме, че нашите данни са статистически значими, за да го покажем. \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-стойността може да се разглежда като вероятността две разпределения да имат еднаква средна стойност. В нашия случай тя е много ниска, което означава, че има силни доказателства, подкрепящи, че първите застъпници са по-високи.\n",
"* t-стойността е междинната стойност на нормализираната разлика на средните, която се използва в t-теста и се сравнява с прагова стойност за дадена стойност на доверие.\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": [
"## Корелация и Evil Baseball Corp\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-16T19:34:21+00:00",
"source_file": "1-Introduction/04-stats-and-probability/notebook.ipynb",
"language_code": "bg"
}
},
"nbformat": 4,
"nbformat_minor": 4
}