# Python 資料科學與探索式資料分析
###### tags: `Python/SQL商業資料分析` `資料分析` `Python`
[TOC]
# 前言
本文主要會介紹資料科學專案會使用到的兩個主要的分析技巧:資料前處理(Data Preprocessing) 和 探索式資料分析(Exploratory data analysis) 以及機器學習演算法基礎和線性迴歸分析方法。
> 資料科學和機器學習專案在進行前一般會進行資料前處理與探索式資料分析來取出合適的特徵值(feature)進行模型的訓練和驗證,最後透過訓練出的模型來預測新的資料集並不斷的提升優化整個模型的成效。
**- 資料前處理:目的在於將資料進行整理,讓資料變得易於閱讀和分析使用。
** - 例如:將資料轉成列欄格式、補齊遺漏值、欄位資料單位和值的轉換、組合或去除特徵資料等。
- **探索式資料分析**:主要透過資料視覺化圖表來更深入了資料分布的狀況和特性,進而可以發現重要的特徵值。
- 例如:了解資料的分布情形、偵測異常值、確認資料間是否存在相關性或共變關係等。
# 專案實作:鐵達尼號資料集
## 下載資料集
以鐵達尼號乘客生存率資料集來介紹探索式資料分析,這個資料集主要是紀錄鐵達尼號沉沒時乘客的資訊和生存狀況,希望透過乘客資訊可以預測乘客的生存/死亡率,是一個 Kaggle 資料科學競賽網站上的經典案例。
首先先建立一個專案資料夾,並到資料集下載位置:[Titanic: Machine Learning from Disaster](https://www.kaggle.com/competitions/titanic) 下載資料檔案將檔案放到新建立的專案資料夾下。
總共有三個資料檔案,我們主要會使用到的是 train.csv (負責訓練模型提供了乘客是否存活的解答)來進行探索式資料分析,判斷哪些屬性特徵值是重要的。
## 載入資料集
```python
import pandas as pd
# 載入資料集
df = pd.read_csv('./train.csv')
# 印出列數和欄位數
print(df.shape)
# 印出欄位資訊
print(df.info())
```
| 參數 | 定義 | 值 |
| ----------- | ------------------------- | ---------------------------------------------- |
| PassengerId | 旅客 ID | |
| Survived | 是否存活 | 0 = No, 1 = Yes |
| Pclass | 票券等級 | 1 = 1st, 2 = 2nd, 3 = 3rd 數字越小越高級 |
| Name | 姓名 | |
| Sex | 性別 | |
| Age | 年齡 | |
| SibSp | 兄弟姊妹/配偶也在船上數量 | |
| Parch | 父母或小孩也在船上數量 | |
| Ticket | 票號 | |
| Fare | 票價 | |
| Cabin | 船艙號碼 | |
| Embarked | 登船港口 | C = Cherbourg, Q = Queenstown, S = Southampton |
觀看頭幾筆資料程式語法:
```python
print(df.head(5))
```
資料基本統計資訊程式語法:
```python
print(df.describe())
```
```python
PassengerId Survived Pclass Age SibSp \
count 891.000000 891.000000 891.000000 714.000000 891.000000
mean 446.000000 0.383838 2.308642 29.699118 0.523008
std 257.353842 0.486592 0.836071 14.526497 1.102743
min 1.000000 0.000000 1.000000 0.420000 0.000000
25% 223.500000 0.000000 2.000000 20.125000 0.000000
50% 446.000000 0.000000 3.000000 28.000000 0.000000
75% 668.500000 1.000000 3.000000 38.000000 1.000000
max 891.000000 1.000000 3.000000 80.000000 8.000000
Parch Fare
count 891.000000 891.000000
mean 0.381594 32.204208
std 0.806057 49.693429
min 0.000000 0.000000
25% 0.000000 7.910400
50% 0.000000 14.454200
75% 0.000000 31.000000
max 6.000000 512.329200
```
## 資料前處理
在載入資料並大概了解了資料的情況後接著我們要來進行資料前處理,設定 PassengerId 為 Index,將一些重要的**遺漏值補齊**(例如:Age)和將資料從文字的名目資料轉為數值標籤(例如:Sex)。
1. 檢視 `PassengerId` **是否唯一值**,若是則設為 index:
```python
import numpy as np
print(np.unique(df['PassengerId'].values).size)
```
2. 將 `PassengerId`**設為 index**:
```python
df = df.set_index('PassengerId')
```
3. 將 `Sex` 性別文字的欄位**轉換為數值**,男性:0, 女性:1 建立新欄位 SexCode:
```python
# 當 Sex 值為 female 則設為 1,反之為 0
df['SexCode'] = np.where(df['Sex'] == 'female', 1, 0)
print(df.head())
```
4. 在顯示資料的欄位資訊時發現有**欄位有缺值**,可使用 isnull() 方法來檢視:
```python
print(df.isnull().sum())
print(df['Age'].isnull().sum())
```
5. Age 可使用現有資料的**年齡平均數來補齊**。
```python
# 29.69911764705882
avg_age = df['Age'].mean()
df['Age'] = df['Age'].fillna(avg_age)
print(df['Age'].isnull().sum())
```
6. 根據性別進行**年齡的統計**:
```python
print(df.groupby('Sex')['Age'].size())
print(df.groupby('Sex')['Age'].mean())
#執行結果(男女生數量和平均年齡):
Sex
female 314
male 577
Name: Age, dtype: int64
Sex
female 28.216730
male 30.505824
Name: Age, dtype: float64
```
7. **新增欄位 Died**,可以比較存活和死亡狀況(將值設為 Survived 相反):
```python
# 當 Survived 值為 0 則設為 1,反之為 0
df['Died'] = np.where(df['Survived'] == 0, 1, 0)
print(df.head())
```
## 探索式資料分析
使用圖表來呈現根據 Sex 群組的生存和死亡**總數**:
```python
import matplotlib.pyplot as plt
df_group_by_sex = df[['Survived', 'Died']].groupby(df['Sex']).sum()
print(df_group_by_sex)
df_group_by_sex.plot(kind='bar')
plt.show()
```
![](https://i.imgur.com/Hu6sPHb.jpg)
使用圖表來呈現根據 Sex 群組的生存和死亡**平均數**:
```python
df_group_by_sex = df[['Survived', 'Died']].groupby(df['Sex']).mean()
print(df_group_by_sex)
df_group_by_sex.plot(kind='bar')
plt.show()
```
![](https://i.imgur.com/aYg2oXe.jpg)
使用圖表來呈現根據**Pclass 群組的生存和死亡總數**:
```python
df_group_by_pclass = df[['Survived', 'Died']].groupby(df['Pclass']).sum()
print(df_group_by_pclass)
df_group_by_pclass.plot(kind='bar')
plt.show()
```
![](https://i.imgur.com/WliRkSv.jpg)
使用圖表來呈現根據**Pclass 群組的生存和死亡平均數**:
Pclass 有三種 1、2 和 3,每一個數字代表乘客座位的等級,數字較小代表越高級。
```python
df_group_by_pclass = df[['Survived', 'Died']].groupby(df['Pclass']).mean()
print(df_group_by_pclass)
df_group_by_pclass.plot(kind='bar')
plt.show()
```
![](https://i.imgur.com/NZvSSe9.jpg)
使用 `corr()` 方法計算相關係數:
```python
# 由於欄位較多,我們僅取出認為比較有可能會和 Survived 有關的屬性欄位
df[['Survived', 'Age', 'Pclass', 'Fare', 'SexCode']].corr()
# 一般研究者認為,相關係數絕對值 0.3 以下為低相關,0.3 ~ 0.7為中等相關,0.7 以上為高度相關
```
![](https://i.imgur.com/JW2YScJ.jpg)
可以看到 SexCode相關係數取絕對值四捨五入到小數第二位約為 0.54(女性可能較容易存活)和 Pclass 相關係數取絕對值四捨五入約為 0.34(票券級數數字越小是比較高級,所以相關係數為負數,代表可能比較高級的票券乘客存活率比較高)都算是中度相關,而 Fare 相關係數取絕對值四捨五入約為 0.26 則是票價屬於低度相關。看起來 Age 的相關性比較不明顯,取絕對值四捨五入小於 0.1。
## 機器學習演算法基礎概論
在機器學習演算法中,最常的分類就是是否有提供訓練模型的標準解答,若有則稱為監督式學習,若無則稱為非監督學習。
- 監督式學習(Supervised learning)
主要分為分類和迴歸分析,差別在於分類結果為分類標籤有限集合(例如:決策樹等),而迴歸分析為連續性資料值的預測(例如:簡單線性迴歸分析、多元線性迴歸分析等)。
- 非監督式學習(Unsupervised learning)
主要為分群、關聯式分析(例如:購物籃分析)等。
### 簡單線性迴歸分析
簡單線性迴歸分析是一個簡單直覺可以用數學公式的簡單表示的演算法。**主要由反應變數和解釋變數所組成**。公式中 `y` 代表反應變數/應變數,`X` 代表解釋變數/自變數。`a` 為截距,`b` 為迴歸係數。當我們訓練模型就是希望找出,a 和 b,這樣一來就可以透過公式求得 y。
可以使用 `scikit-learn`(sklearn) 這個 Python 機器學習套件進行模型建立和預測。
```python
pip install scikit-learn
#Jupyter Notebook 使用:
!pip install scikit-learn
```
![](https://i.imgur.com/rW3nNdO.png)
範例程式碼:
```python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 載入 sklearn 套件
from sklearn.linear_model import LinearRegression
# 使用 numpy array 建立資料集陣列
distances = np.array([3.5, 4.7, 0.6, 3.9, 0.8, 0.5])
prices = np.array([40, 34, 70, 39, 62, 55])
# 建立解釋變數 DataFrame
X = pd.DataFrame(distances, columns=['distances'])
# 建立反應變數 DataFrame 並取出欄位內容
y = pd.DataFrame(prices, columns=['prices'])['prices']
# 建立 LinearRegression 模型物件
linear_reg = LinearRegression()
# 使用 LinearRegression 模型物件方法 fit 訓練模型
linear_reg.fit(X, y)
# 建立新的距離 DataFrame
new_distances = pd.DataFrame(np.array([1.3, 4.2]), columns=['distances'])
# 使用模型預測新資料
predicted_prices = linear_reg.predict(new_distances)
print(predicted_prices)
```
執行結果(使用建立好的模型預測新資料):
```
[57.35110294 36.72058824]
```
> 可以看到距離 1.3 和 4.2 公里的房屋物件,價格分別為 57.35 和 36.72。
接著我們可以把模型和資料**繪製成圖表**:
```python
# 將資料集繪製散佈圖
plt.scatter(distances, prices)
# 將所有距離資料使用模型進行預測
reg_prices = linear_reg.predict(X)
# 將原有資料預測結果繪製成圖
plt.plot(distances, reg_prices)
# 將新的資料預測結果繪製成圖
plt.plot(new_distances, predicted_prices)
plt.show()
```
![](https://i.imgur.com/pgBGv7A.jpg)
# 延伸閱讀
- [SQL 資料庫](https://hackmd.io/fQbgqRSYTDi2Ouis0fE3rg?view)
- [Python 網頁爬蟲](https://hackmd.io/JOc4g8AjSZiokS6vZckFSw?view)
- [Python 資料分析](https://hackmd.io/C5I9OzXzQCe6wJuZhwRV3Q)
- [Python 基礎語法](https://hackmd.io/4FH3w4_pQP6_dsandd45LA)
- [Python 進階語法使用](https://hackmd.io/QYVYsxE8QyWNsnIhukt-2Q)
- [營收與使用者行為資料分析專案](https://hackmd.io/i6kRZN8JQsq57uDrKeKoLQ)
- [Python專案實作 資料分析與爬蟲](https://hackmd.io/oh18KsFvSxe5Eh3ECHDJOA?view)