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-TW/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 身高/體重數據](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 值可以被視為兩個分布具有相同平均值的機率。在我們的案例中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
}