iT邦幫忙

2021 iThome 鐵人賽

DAY 17
0

雖然好的模型和參數可以提高成效,但通常最關鍵還是資料本身。基本上資料的品質決定了八成以上模型的成效,因此大家有必要對自己的資料有所認識和了解。

而在做機器學習的問題,花費最多的通常也是資料處理;我們如果做好資料處理甚至可以大幅提升模型成效。

今天會引導大家認識常用的資料處理的方式,包含常用的 pandas 和 sklearn 套件。我會使用鐵達尼號的資料來示範。

1. 資料探索

Pandas 探索

train.pivot_table(columns=['Embarked'])

pandas_profiling

回顧一下在 pandas篇 有提到可以用 pandas_profiling 可以更方便探索資料

import numpy as np
import pandas as pd
from pandas_profiling import ProfileReport
import seaborn as sns
import matplotlib.pyplot as plt

train = pd.read_csv('train.csv')
profile = ProfileReport(train, title="Pandas Profiling Report")
profile

# Saving the report
profile.to_file("titantic_profiling_report.html")

相關係數

相關係數 r 介於 -1~1之間

  • 當 r >0 表示正相關;當 r < 0 表示負相關
  • 當 r = 0 表示兩變數之前為無線性相關
  • 當 |r| <= 0.4 表示兩變數之間為低度相關
  • 當 0.4 <= |r| <0.7 表示兩變數之間為顯著性相關
  • 當 |r| > 0.7 表示兩變數之間為高度相關
  • 當 |r| = 1 表示兩變數之間為完全線性相關

由於 Sex 不是數值,先進行轉換

train['Sex_encoder'] = train.Sex.apply(lambda x: 1 if x=='male' else 0)
train.corr()

我們大概先從相關係數得知以下事情:

  • Pclass 和 Fare 是顯著性相關
  • Pclass 和 Survived 是有低度相關
  • Pclass 和 Age 是低度相關
  • Parch 和 SibSp 是有顯著性相關
  • Sex 和 Survived 有相關

發現 Survived 跟 Pclass 、 Sex 有關係,這與我們要預測的方向會很有關係

繪圖

繪製圖型可以快速掌握資料

sns.countplot(train['Sex'], hue=train['Survived'])

刪除重複值或異常

這招非常重要,有時候資料很髒,還是要確定一下是否有無重複的資料或異常。

train[train.duplicated()]

2.處理遺漏值

# isnull() 若資料為空值則為 True,反之則為 False
train.isnull().head()
# isnull() + sum() 搭配操作
train.Age.isnull().sum()
# count 僅會計算非空值
train.count()

# 綜合運用 依照空值數量排序
total = train.isnull().sum().sort_values(ascending=False)
print(total)

# 或是調整成百分比型式
percent =(train.isnull().sum()/train.isnull().count()).sort_values(ascending=False)
missing_data = pd.concat([total, percent], axis=1, keys=['Total', 'Percent'])
missing_data

遺漏值的處理方法

通常有以下幾招

  • 用其他的均值來填補遺漏值,例如平均數、中位數、眾數,我們可以依照資料特性填補
  • 使用特殊值來填補離漏值,如-1 通常不要重複就好,把遺漏值歸類成一個類別
  • 忽略有缺失值的樣本,直接把該欄位 drop 。若遺漏值太多且該欄位也無相關性應該可以 drop
  • 使用其他欄位的均值添補遺漏值,例如可以利用其他欄位去簡單計算該欄位的值
  • 使用另外的機器學習演算法預測缺失值,例如可以利用其他欄位去預測該欄位的值
# 使用 dropna
## 預設是只有有空值就刪掉那筆
train.dropna()
# 使用 dropna
## 要全部為空才清楚那一筆資料
train.dropna(how='all')
# 使用 dropna
## 可以指定作用在哪一行
train.dropna(subset=['Fare'])

填補遺漏值方法

# 使用 fillna
## 空值都填上 -1
train.fillna(-1)
## 填上平均數
print(train['Age'].mean())
train['Age'].fillna(train['Age'].mean())
## 使用中位數填補
train['Fare'] = train['Fare'].fillna(train['Fare'].median())
## 使用出現次數最多的值填補
most = train['Embarked'].mode()[0]
train['Embarked'] = train['Embarked'].fillna(most)

# 用上下資料進行填補
## 前一個數據進行填充
train.Cabin.fillna(method='pad')
## 後一個數據進行填充
train.Cabin.fillna(method='bfill')
# 用插值法
train.Age.interpolate()

比較一下插值法前後的 displot

sns.distplot(train.Age, kde=True)

sns.distplot(train.Age.interpolate(method ='linear'), kde=True)

3.離群值處理

我們需要建立一個門檻值去界定離群值,因此我們將資料進行標準化

from sklearn.preprocessing import StandardScaler
#standardizing data
scaled = StandardScaler().fit_transform(train['Fare'][:,np.newaxis]);
low_range = scaled[scaled[:,0].argsort()][:10]
high_range= scaled[scaled[:,0].argsort()][-10:]
print('outer range (low) of the distribution:')
print(low_range)
print('\nouter range (high) of the distribution:')
print(high_range)

from scipy import stats
sns.distplot(x=train["Fare"])
fig = plt.figure()
res = stats.probplot(train['Fare'], plot=plt)

從上圖也很明顯地看到有三個點異常高,可以考慮移除

4.特徵工程

透過上述的資料處理,相信大家對資料有一點的認識,接著我們可以進行找特徵

特徵縮放

有些特徵是差距實在太大,會讓某些模型無法容易學習,因此我們要調整資料的 range,通常是進行標準化。

# 票價的資料有極端值,我們希望可以縮小差距
sns.distplot(x=train["Fare"])

取 log 的方法
sns.distplot(x=np.log(train["Fare"] + 1))

平均數變異數標準化
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler().fit(train[['Age']])
X_scaled = scaler.transform(train[['Age']])
最大值最小值標準化
from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler(feature_range=(0, 1)).fit(train[["Fare"]])
X_scaled = scaler.transform(train[["Fare"]])
絕對值最大標準化

資料會被縮放到 [-1, 1]之間

from sklearn.preprocessing import MaxAbsScaler
X = train[["Fare"]]
scaler = MaxAbsScaler().fit(X)
X_scaled = scaler.transform(X)
RobustScaler

中位數和四分位數標準化,可以有效縮放離群值

from sklearn.preprocessing import RobustScaler
X = train[["Fare"]]
scaler = RobustScaler().fit(X)
X_scaled = scaler.transform(X)

特徵處理

基本上演算法只是接近這份資料可以達到的預測水平上界,但透過特徵處理,或許可以大幅將預測上界往上移動。因此了解資料後新增特徵,或許預測會更準確!

# 可以新增一個家庭大小,由於有父母數量和兄弟姊妹數量的欄位,合成一個新的欄位
train['family_size'] = train['Parch'] + train['SibSp']

上一篇
Day 16 : 模型衡量指標
下一篇
Day 18 : 模型前的資料處理 (2)
系列文
Python資料分析學習地圖30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言