在機器學習的過程中,對於資料的解釋以及處理是最前期也最重要的環節,在這個章節中,將使用資料本身較乾淨並且相當容易獲取的玩具資料集進行基礎講解,在基礎講解結束後將帶領各位讀者進行實際資料的實戰演練。
from sklearn.datasets import load_diabetes # 匯入Sklearn內建資料集
data = load_diabetes() # 將數據匯入
import pandas as pd # 匯入pandas套件並更名成pd
df = pd.DataFrame(data.data,columns = data.feature_names)
# 透過data.data來呼叫數據 回傳numpy.ndarray型態
# 透過data.feature_names來呼叫特徵名稱
# 將原先的data由numpy.ndarray變更為pandas.DataFrame型態
# 將特徵名稱與資料放入對應的行(columns)
data.head() # 顯示頭五筆資料
# 可使用data.head(10)顯示前10筆或是使用data.tail()顯示最後五筆資料
常見的量尺分為四種,對於不同的量尺所表達的數據有不同的處理原則。
從資料的名稱中我們可以發現,sex類別應該是1與0的數值,但他在這筆數裡面是0.050680與-0.044642兩個數字,顯示這整筆資料應該做過標準化處理,而sex類別表示的是男女,以1、0來表示會有遞增的關係,男女類別應該屬於「類別量尺」,因此在處理的過程中我們要先將數值還原成1、0並且將男、女兩個屬性獨立成一個特徵,這個動作叫做one-hot enconding。
# 對pandas.DataFrame或是pandas.Series可以執行兩種函式進行元素的選取
# .loc使用「key值」,也可以說使用「名稱」
# 例如.loc[列名稱,行名稱]
df.loc[0,"sex"] # ->回傳0.050680
df.loc[0,"age"] # ->回傳-0.001882
# .iloc使用「索引」
# 例如.iloc[列索引,行索引]
df.loc[0,1] # ->回傳0.050680
df.loc[0,0] # ->回傳-0.001882
有些讀者在選取與修改資料的時候,習慣與陣列相同使用切片(slice)操作,有時候會造成資料無法正確的修改,建議養成使用loc與iloc的操作進行改值會較為精準。
# 有機會造成值沒有正確修改
df["sex"][0] = 1
# 建議使用loc與iloc
df.loc[0,"sex"] = 1
df.loc[0,1] = 1
# 另外補充
df.loc[:,["sex"]]將回傳DataFrame型態
df.loc[:,"sex"]將回傳Series型態
# 冒號 : ->與slice相同 表示列/行全選
在進行資料的預處理時,由於每列(row)的資料都是一筆獨特的人、事、交易等等,因此時常需要針對單個列進行處理,相信部分讀者曾經遇過上百萬筆數據需要一筆一筆取出並調整,但這時候使用迴圈會因為python原生的限制導致速度極度的緩慢,這時候應該使用apply進行處理。
df.loc[:,"age"].apply(function)
# 這個操作將把df的資料依照列一筆一筆的傳遞給function
# 依序為 0.038076,-0.001882,0.085299......
這時候如果你想針對大於零或小於零的值做區隔,將兩個不同的條件分別套用到不同的值,可以使用匿名函式lambda。
condition = lambda x: 1 if x > 0 else 0
df.loc[:,"sex"].apply(condition)
# 或 df.loc[:,"sex"].apply(lambda x: 1 if x > 0 else 0)
# 兩個操作是等價的 個人偏好後者
這樣就可以高速的達到更新資料並且不需要使用到迴圈,但你可能想問,如果條件沒有這麼複雜,不需要使用到函數的話該怎麼辦呢?
這時候可以使用mask(掩碼數組)的操作來達到快速的選取資料與修改
df.loc[:,"sex"] > 0 # 將以Series回傳整個行的布林值
# 此處不修改值 使用df["sex"] > 0 亦可
# 將這個布林陣列放入前方的列索引
df.loc[df["sex"] > 0,"sex"] # 回傳符合條件(值>0)的資料
df.loc[df["sex"] > 0,"sex"] = 1 # 直接針對這些資料進行修改
學會上述這些方法之後,在資料的操作上比較不會手忙腳亂,也能夠較高效率的處理資料,更進一步的補值邏輯與其他預處理將在下篇文章介紹~