問題
在實際應用中,我們經常會遇到像下圖這樣的情況,那就是有的列是非數字的。但是 Machine Learning 只善於處理數字,所以我們需要將非數字的內容進行合理的轉換,再來訓練模型。
在上圖中的 town
列被稱為 categorical variables
(類別變數)。categorical variables
又分為兩種,一種是 nominal,另一種是 ordinal。下面分別解釋一下:
nominal: 分類的值沒有任何先後順序或等級關係
ordinal:分類的值是有等級關係的
例子如下:
解決方案
很顯然,上面 town 列應該屬於 nominal category variables, 我們可以用一種名為 One Hot Encoding 的技術來解決這個問題。我們為列中的每一種分類都分別單獨建一個列,用 0 或 1 填充,這些新建的列被稱作 dummy vaiables。最終想要的效果如下圖:
具體實現方法(兩種):
方法一:使用 Pandas 的 get_dummies 方法
import pandas as pd
from sklearn import linear_model
df = pd.read_csv('/Users/rachel/Downloads/py-master/ML/5_one_hot_encoding/homeprices.csv')
// 獲取 town 列的 dummies
dummies = pd.get_dummies(df.town)
// 合併新生成的 dummies 列與原表
merged = pd.concat([df, dummies], axis='columns')
// 把原表的 town 列刪掉, 還要刪掉 dummies 列中的任意一列
final = merged.drop(['town', 'west windsor'], axis='columns')
Tips:
這裡使用 'west windsor', 'monroe township' 和 'robbinsville' 三個列來分別表示原來 'town' 列的三個類別, 然後用 0 和 1 區別到底是哪個類別. 之所以要刪掉一列, 是因為用兩個列的值就可以推匯出第三列的值, 比如, 我們現在隨機刪掉了 'west windsor' 列的值, 那麼 'monroe township' 列或者 'robbinsville' 是 1 的時候, 'west windsor' 列必然是 0, 而如果這兩列都為 0 的時候, 'west windsor' 列必然是 1, 所以, 就可以省掉那一列,據說也是必須刪掉這多餘的一列,否則在訓練模型的時候會出現錯誤。另外, 如果是用 LinearRegression 的話, 其實, 它會自動幫我們刪除一列, 但是為了養成良好的習慣, 還是自己主動刪除吧.
看下最後整理後的資料:
// 例項化一個模型
model = linear_model.LinearRegression()
// 準備資料, 這裡 x 的資料就是表裡除了 price 的所有欄位, 所以直接把 price 欄位刪了, 方便快捷
x = final.drop('price', axis='columns')
y = final.price
// 訓練模型
model.fit(x, y)
// 從模型取資料: area 2800, robinsville 的房子價格
model.predict([[2800, 0, 1]])
// 這個方法是測下這個模型的精準度, 這個值應該是還可以
model.score(x, y) //0.9573929037221873
方法二:使用 sklearn 的 OneHotEncoder
1. 重新引入 dataframe
2. 將 town 列的值轉為數字
from sklearn.preprocessing import LabelEncoder
// 建立 LabelEncoder 物件
le = LabelEncoder()
// 把原 dataframe 重新賦給變數 dfle
dfle = df
// 把 town 列轉為數值
dfle.town = le.fit_transform(dfle.town)
dfle
看下效果:
// 設定 x 的值, 通過 values 方法, 把 x 值轉為陣列, 否則是 dataframe
x = dfle[['town', 'area']].values
x
3. 用 OneHotEncoder 獲取 dummy variables
from sklearn.preprocessing import OneHotEncoder
// 用 OneHotEncoder 將陣列的第一列轉為 dummy variable
ohe = OneHotEncoder(categorical_features=[0])
x = ohe.fit_transform(x).toarray()
// 取所有行的值, 去掉第一列的值, 也就是隻保留 dummy variables 中的任意兩列
x = x[:, 1:]
y = dfle.price
// 訓練模型
model.fit(x, y)
model.predict([[1, 0, 2800]])