使用sklearn進行數據挖掘系列文章:
- 1.使用sklearn進行數據挖掘-房價預測(1)
- 2.使用sklearn進行數據挖掘-房價預測(2)—划分測試集
- 3.使用sklearn進行數據挖掘-房價預測(3)—繪制數據的分布
- 4.使用sklearn進行數據挖掘-房價預測(4)—數據預處理
- 5.使用sklearn進行數據挖掘-房價預測(5)—訓練模型
- 6.使用sklearn進行數據挖掘-房價預測(6)—模型調優
上一節我們對數據集進行了了解,知道了數據集大小、特征個數及類型和數據分布等信息。做數據挖掘任務過程中需要對數據划分為訓練集和測試集合,你可能會問不就數據集的划分么,有必要單獨進行講解么?莫急,聽我慢慢道來,希望對你有幫助。
划分數據集###
在划分測試集的時候我們要完全隨機的划分,因為當我們看過數據集時候,我們會帶着主觀偏見進行模型的選取,這將會造成數據窺探偏見(data snooping bias),在划分數據集的時候非常簡單,我們只需要隨機抽取其中的一部分,例如20%,將之放在一邊即可。
import numpy as np
def split_train_test(data,test_ratio):
indices = np.random.permutation(len(data)) #隨機全排列
test_size = int(len(data) * test_ratio)
test_indices = indices[:test_size]
train_indices = indices[test_size:]
return data.iloc[train_indices],data.iloc[test_indices]
運行方法
train_set,test_set = split_train_test(housing,0.2)
print("train set len",len(train_set))
print("test set len",len(test_set))
('train set len', 16512)
('test set len', 4128)
note:這里面返回的結果是DataFrame
類型,如果取其中的某一條樣本不能像數組那樣train_set[0],需要使用train_set.iloc[0]
,這樣返回的是一個Series
類型的對象,如果取其值使用train_set.iloc[0].values
返回的是np.array類型
這樣我們就將訓練集和測試機划分完畢,那么這一節也就結束了。。等下,細心的人可能會發現,每次運行返回的數據集結果內容不一樣啊,這也就意味着跑算法的時候,每次跑的數據可能不一樣。一個解決方法是在第一次運行的時候,將訓練集保存起來,供后續使用,另外一個方法是在執行之前使用np.random.seed(42)
,這個整數任意。
可以嘗試下
a = [1,2,3,4,5,6]
np.random.seed(32) #使用和不使用
print np.random.permutation(a)
seed( ) 用於指定隨機數生成時所用算法開始的整數值。
- 1.如果使用相同的seed( )值,則每次生成的隨即數都相同;
- 2.如果不設置這個值,則系統根據時間來自己選擇這個值,此時每次生成的隨機數因時間差異而不同。
- 3.設置的seed()值僅一次有效
當數據集被更新的時候,這兩種方法就會失效。一種常用的方法是使用樣本的ID作為是否選為測試集的依據,我們可以選取樣本的hash值作為ID,選取hash的最后一位小於51(256 / 5)。這就保證了測試集始終如一(不會包含之前的訓練集樣本),即使更新了數據集。下面是實現方法:
def test_set_check(idd,test_ratio,hash):
return hash(str(idd)).digest()[-1] < 256 * test_ratio
def split_train_test_by_id(data,test_ratio,id_column,hash=hashlib.md5):
ids = data[id_column]
is_in_test = ids.apply(lambda id_:test_set_check(id_,test_ratio,hash))
return data.loc[~is_in_test],data.loc[is_in_test]
上面方法使用的是md5哈希方法,對上面使用的函數進行解釋一下
digest()
以二進制的形式返回摘要值;還有hexdigest()
這個是返回摘要的十六進制字符串;eg
a = hash('1')
a.digest()
Out[103]: '\xc4\xcaB8\xa0\xb9#\x82\r\xccP\x9aou\x84\x9b'
a.hexdigest()
Out[104]: 'c4ca4238a0b923820dcc509a6f75849b'
apply(func,axis=0)
,根據axis,應用當前的func函數iloc
和loc
,iloc[行號],loc[行標簽],兩者都可使用boolean類型的數組
使用行號作為ID的時候,需要保證當添加新數據的時候是添加到了數據集的尾部,並且保證數據集中的某些樣本被刪除;
sklearn也提供了划分數據集的方法
from sklearn.model_selection import train_test_split
train_set,test_set = train_test_split(housing,test_size=0.2,random_state=42)
目前我們講的划分測試集和訓練集的方法是純隨機,當我們的數據集比較大的時候,這是一個很好的方法,但如果數據集不夠大就將出現采樣偏差問題,就例如對1000人進行問卷調查,你到師范學校發現男女比例3:7女生那么多。。。為了反應總體,你應該男性選擇男生300人女性700人。這就叫做分層采樣(stratifed sampling),至於選取哪個特征作為分類指標和分多少層這就需要根據實際的工作場景來判斷,在這里選取median_income作為分層指標。先看一下這一特征的數據分布情況
從上圖可以看出,media_income
這一屬性為連續的數值類型,那么首先我們需要對其離散化,即划分為幾個類別;
housing["income_cat"] = np.ceil(housing["median_income"] / 1.5)
# Label those above 5 as 5
housing["income_cat"].where(housing["income_cat"] < 5, 5.0, inplace=True)
housing["income_cat"].hist()
上面這段代碼通過除以1.5來限制類別的個數,並將大於5的值歸為5這一類別,得到的結果如下圖所示:
從圖中可以看出,media_income這一屬性大多落在2和3類別之間。
note:
housing.where(cond, other=nan, inplace=True)
:判斷condition,如果為True值不變,如果為false則取other
的值,是否對值修改np.ceil:
向上取整>>a = np.array([-1.7, -1.5, -0.2, 0.2, 1.5, 1.7, 2.0]) >>np.ceil(a) array([-1., -1., -0., 1., 2., 2., 2.])
目前我們已經對樣本分好了類別,並加上了income_cat類標簽。接下來我們就需要按照類別划分數據集了。
from sklearn.model_selection import StratifiedShuffleSplit
split = StratifiedShuffleSplit(n_splits=1,test_size=0.2,random_state=42)
for train_index,test_index in split.split(housing,housing["income_cat"]):
strat_train_set = housing.loc[train_index]
strat_test_set = housing.loc[test_index]
這里面n_splits
是迭代的次數。
到這里數據集划分為訓練集和測試集已經完畢,剛剛添加的新的輔助分類特征income_cat
也可以退伍了,把他從原始數據集中刪除。
for set_ in (strat_train_set, strat_test_set):
set_.drop("income_cat", axis=1, inplace=True)