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

575 lines
17 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",
"我們先從 0 到 9 的均勻分佈中抽取 30 個數值的樣本。並且計算其平均值及變異數。\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": [
"要視覺上估計樣本中有多少不同的值,我們可以繪製<strong>直方圖</strong>\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": [
"除了平均值之外,查看中位數和四分位數也是有意義的。它們可以用<strong>箱型圖</strong>來視覺化: \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.figure(figsize=(10,2))\n",
"plt.boxplot(df['Height'].ffill(), orientation='horizontal', 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": [
"> <strong>注意</strong>:此圖表顯示,一壘手的平均身高比二壘手的身高高。稍後我們會學習如何更正式地檢驗此假設,以及如何證明我們的數據在統計上具有顯著性。 \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'].ffill(),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檢定**\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": [
"## 相關性與邪惡棒球公司\n",
"\n",
"相關性讓我們能找到資料序列之間的關係。在我們的玩具示例中,假設有一間邪惡的棒球公司,根據球員的身高支付他們的薪水——球員越高,獲得的錢越多。假設有一個基本薪資是$1000還有一個根據身高介乎$0到$100的額外獎金。我們將取美國職棒大聯盟MLB的真實球員資料計算他們的虛構薪資\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"heights = df['Height'].ffill()\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` 會給我們所謂的<strong>協方差矩陣</strong>,這是多變量協方差的擴展。協方差矩陣 $M$ 的元素 $M_{ij}$ 是輸入變量 $X_i$ 和 $X_j$ 之間的相關性,而對角線上的值 $M_{ii}$ 則是 $X_i$ 的變異數。同樣地,`np.corrcoef` 會給我們<strong>相關係數矩陣</strong>。\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 意味著兩個變量之間存在強烈的 <strong>線性關係</strong>。我們可以通過將一個值與另一個值繪圖來直觀地看到線性關係:\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",
"我們已經觀察到像薪水這類人為設計的概念和觀察變量 <em>身高</em> 之間的相關性。現在讓我們也看看兩個觀察變量,例如身高和體重,是否也有相關性:\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",
"> 這個例子顯示了<strong>資料準備</strong>和<strong>清理</strong>的重要性。沒有適當的資料,我們無法計算任何東西。\n",
"\n",
"讓我們使用 `fillna` 方法填充缺失值,並計算相關性:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"np.corrcoef(df['Height'].ffill(), 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"
}
},
"nbformat": 4,
"nbformat_minor": 4
}