首先強調一下,本篇博客是我實驗得出來的結論,要是錯了,可以在評論區指正,嘻嘻
接下來我會介紹以下三個內容
- 爲什麼要用onehot
- 怎麼用
爲什麼要用onehot:
假設你有一個這樣的數據集,格式是csv或者arff格式:
體重 | 身高 | ... | class |
胖 | 1 5 0 | ... | 不好看 |
瘦 | 1 6 0 | ... | 還可以 |
有點胖 | 1 8 0 | ... | 帥 |
有點瘦 | 1 5 0 | ... | 還可以 |
你現在需要對這個數據構建一個分類器,挖掘一些有用的信息,此時你想到了sklearn(真是個錯誤的決定),你會發現如果你把這個數據集直接當成數據矩陣numpy,輸入sklearn中的分類器中,編譯器會提示你,類型錯誤,無法把string(或者btype)類型轉成float....
經過我查閱多方資料,我才明白,原來sklearn中的數據默認得是全數值類型。一個非常好又不方便的設定,好在:統一數據類型,不方便在:有得時候我們的數據就是數值,離散值,string類型混合的。那我們就來解決吧(當然,如果你換weka(java)這個機器學習庫就沒有這種奇怪的問題)
怎麼用:
在講怎麼寫onehot代碼之前,我先簡單介紹一下onehot方法,簡單地說,onehot方法可以把剛剛上面的這個數據變成這個樣子:
是否胖 | 是否瘦 | 是否有點胖 | 是否有點瘦 | 身高 | ... | class |
1 | 0 | 0 | 0 | 1 5 0 | ... | 不好看 |
0 | 1 | 0 | 0 | 1 6 0 | ... | 還可以 |
0 | 0 | 1 | 0 | 1 8 0 | ... | 帥 |
0 | 0 | 0 | 1 | 1 5 0 | ... | 還可以 |
從上面的數據,我們可以發現,onehot方法就是把離散取值(取名詞)的屬性裂變成多個屬性(取值爲01),這樣就可以給sklearn計算了。
好的,接下來,我展示一下,具體的代碼(使用onehot重新編碼,並進行knn分類,然後返回十折交叉驗證結果的代碼)調用示例:
def do_knn(fea,lab,k):
# sdata=fea+lab
auc=0
#x是個矩陣
#arffdata = imp.fit_transform(arffdata)
#lab.reshape(-1,1).reshape(-1)#?????去掉它的多餘括號
flo = [] # 存放數值型屬性
str = [] # 存放名詞性屬性
colmn = fea.shape[1] # 存放列數
raw = fea.shape[0] # 存放行數
strnumber = 0#判斷是否存在名詞性屬性
flonumber=0
for i in range(colmn):
if type(fea[0][i]) == bytes or type(fea[0][i]) == np.bytes_:
str.append(fea[:, i])
strnumber += 1
else:
flo.append(fea[:, i])
flonumber+=1
flo = np.array(flo).T
str = np.array(str).T
features=np.random.rand(1)#之後重新賦值
if strnumber != 0 and flonumber != 0:
enc = OneHotEncoder()
enc.fit(str)
str = enc.transform(str).toarray()
str = np.array(str)
features = np.concatenate((flo, str), 1)
if strnumber==0:
features = flo
if flonumber==0:
enc = OneHotEncoder()
enc.fit(str)
str = enc.transform(str).toarray()
features = np.array(str)
knn = KNeighborsClassifier(n_neighbors=k)
scores = cross_val_score(knn, features, lab, cv=5, scoring='accuracy')
auc=sum(scores)/len(scores)
#print(lab)#似乎是因爲btype類型的原因
return auc###auc有時居然是空的
代碼片段有點長,那是因爲這個方法用起來真的不方便(以前的版本是很方便,只需要一行就能實現,後來sklearn把一個關鍵的函數去掉了。。)
代碼解釋說明:這個函數是計算一組數據進行knn分類方法並返回十折交叉驗證的平均auc的函數。輸入的fea是數據的特徵(屬性),輸入的lab是數據的類別,所以這段代碼是對fea進行數值化處理的。
關鍵的代碼是這個:
enc = OneHotEncoder()
enc.fit(str)
str = enc.transform(str).toarray()
features = np.array(str)
首先,創建一個onehotencoder對象(方法),然後讓這個方法去學str(把fea的所有非數值類取出來,存放在str中)矩陣中的信息(每個屬性的取值有幾種),再通過transfrom函數就可以把非數值得矩陣轉成純數值的數據矩陣。
補充說明:
上面的代碼中,我先對數據集的屬性矩陣進行了一個評定,看看這個數據的屬性含不含非數值類型,並把數值型屬性和非數值屬性分開,最後調用onehot方法把非數值屬性的矩陣轉成純數值矩陣,最後再把這兩個矩陣拼接,構成數據集的完整屬性矩陣features,最後利用這個featurs和lab得到了分類的結果。
我這麼做的原因是因爲,onehot方法以前的版本是可以選擇哪一列需要數值化 的,方法是這樣 enc=onehotencoder(categories
_featuires=[1,2]),這樣的onehot就可以一行實現一個數據矩陣中的第一列和第二列數值化,真的是很方便,但是,不知道爲什麼,我這個版本把這種這麼好的輸入參數去掉了。。。。。。。所以他默認就是全部數值化,這樣就會導致,如果你有一個屬性是身高,取值有148.2,145.6,170.9等等,那麼他就會裂變出 是否148.2,是否145.6.......這麼多屬性。。。。。所以我才做得這麼麻煩。
要是你們知道怎麼快速進行onehot方法(可以選擇那一列裂變),可以在評論區告訴我呀,感謝感謝
、