小伙伴們大家好~o( ̄▽?zhuān)?/em>)ブ
我是菜菜,這里是我的sklearn課堂第3期:數(shù)據(jù)預(yù)處理和特征工程~
我的開(kāi)發(fā)環(huán)境是Jupyter lab,所用的庫(kù)和版本大家參考:
Python 3.7.1(你的版本至少要3.4以上
Scikit-learn 0.20.0 (你的版本至少要0.19
Numpy 1.15.3, Pandas 0.23.4, Matplotlib 3.0.1, SciPy 1.1.0
本文主要內(nèi)容:
?1 概述
??1.1 數(shù)據(jù)預(yù)處理與特征工程
??1.2 sklearn中的數(shù)據(jù)預(yù)處理和特征工程
?2 數(shù)據(jù)預(yù)處理 Preprocessing & Impute
??2.1 數(shù)據(jù)無(wú)量綱化
??2.2 缺失值
??2.3 處理分類(lèi)型特征:編碼與啞變量
??2.4 處理連續(xù)型特征:二值化與分段
1 概述
1.1 數(shù)據(jù)預(yù)處理與特征工程
想象一下未來(lái)美好的一天,你學(xué)完了菜菜的課程,成為一個(gè)精通各種算法和調(diào)參調(diào)庫(kù)的數(shù)據(jù)挖掘工程師了。某一天你從你的同事,一位藥物研究人員那里,得到了一份病人臨床表現(xiàn)的數(shù)據(jù)。藥物研究人員用前四列數(shù)據(jù)預(yù)測(cè)一下最后一數(shù)據(jù),還說(shuō)他要出差幾天,可能沒(méi)辦法和你一起研究數(shù)據(jù)了,希望出差回來(lái)以后,可以有個(gè)初步分析結(jié)果。于是你就看了看數(shù)據(jù),看著很普通,預(yù)測(cè)連續(xù)型變量,好說(shuō),導(dǎo)隨機(jī)森林回歸器調(diào)出來(lái),調(diào)參調(diào)呀調(diào),MSE很小,跑了個(gè)還不錯(cuò)的結(jié)果。

幾天后,你同事出差回來(lái)了,準(zhǔn)備要一起開(kāi)會(huì)了,會(huì)上你碰見(jiàn)了和你同事在同一個(gè)項(xiàng)目里工作的統(tǒng)計(jì)學(xué)家。他問(wèn)起你的分析結(jié)果,你說(shuō)你已經(jīng)小有成效了,統(tǒng)計(jì)學(xué)家很吃驚,他說(shuō):“不錯(cuò)呀,這組數(shù)據(jù)問(wèn)題太多,我都分析不出什么來(lái)。”
你心里可能咯噔一下,忐忑地回答說(shuō):“我沒(méi)聽(tīng)說(shuō)數(shù)據(jù)有什么問(wèn)題呀?!?/p>
于是統(tǒng)計(jì)學(xué)家說(shuō):“誒?沒(méi)人告訴你說(shuō),最后一列數(shù)據(jù)如果取個(gè)對(duì)數(shù),結(jié)果會(huì)更好嗎?”
你內(nèi)心毫無(wú)波動(dòng):“沒(méi)。”
統(tǒng)計(jì)學(xué)家:“誒那你肯定聽(tīng)說(shuō)了第四列數(shù)據(jù)有點(diǎn)問(wèn)題吧,這個(gè)特征的取值范圍是1~10,0是表示缺失值的。而且他們輸入數(shù)據(jù)的時(shí)候出錯(cuò),很多10都被錄入成0了,現(xiàn)在分不出來(lái)了?!?/p>
你:”......“
統(tǒng)計(jì)學(xué)家:”還有第二列和第三列數(shù)據(jù)基本是一樣的,相關(guān)性太強(qiáng)了?!?/p>
你:”這個(gè)我發(fā)現(xiàn)了,不過(guò)這兩個(gè)特征在預(yù)測(cè)中的重要性都不高,無(wú)論其他特征怎樣出錯(cuò),我這邊結(jié)果里顯示第一列的特征是最重要的,所以也無(wú)所謂啦?!?/p>
統(tǒng)計(jì)學(xué)家:“啥?第一列不就是編號(hào)嗎?”
你:“不是吧?!?/p>
統(tǒng)計(jì)學(xué)家:“哦我想起來(lái)了!第一列就是編號(hào),不過(guò)那個(gè)編號(hào)是我們根據(jù)第五列排序之后編上去的!這個(gè)第一列和第五列是由很強(qiáng)的聯(lián)系,但是毫無(wú)意義??!”
老血噴了一屏幕,數(shù)據(jù)挖掘工程師卒。
這個(gè)悲慘又可愛(ài)的故事來(lái)自《數(shù)據(jù)挖掘?qū)д摗罚m然這是故事里的狀況十分極端,但我還是想把這段對(duì)話(huà)作為今天這章的開(kāi)頭,博大家一笑(雖然可能聽(tīng)完就淚流滿(mǎn)面了)。在過(guò)去兩周,我們已經(jīng)講了兩個(gè)算法:決策樹(shù)和隨機(jī)森林,我們通過(guò)決策樹(shù)帶大家認(rèn)識(shí)了sklearn,通過(guò)隨機(jī)森林講解了機(jī)器學(xué)習(xí)中調(diào)參的基本思想,現(xiàn)在可以說(shuō),只要上過(guò)前面兩堂課的,人人都會(huì)調(diào)隨機(jī)森林和決策樹(shù)的分類(lèi)器了,而我呢,也只需要跟著各大機(jī)器學(xué)習(xí)書(shū)籍的步伐,給大家一周一個(gè)算法帶著講解就是了。如果這樣的話(huà),結(jié)果可能就是,大家去工作了,遇到了一個(gè)不那么靠譜的同事,給了你一組有坑的數(shù)據(jù),最后你就一屏幕老血吐過(guò)去,犧牲在數(shù)據(jù)行業(yè)的前線(xiàn)了。
數(shù)據(jù)不給力,再高級(jí)的算法都沒(méi)有用。
我們?cè)谡n堂中給大家提供的數(shù)據(jù),都是經(jīng)過(guò)層層篩選,適用于課堂教學(xué)的——運(yùn)行時(shí)間短,預(yù)測(cè)效果好,沒(méi)有嚴(yán)重缺失等等問(wèn)題。尤其是sklearn中的數(shù)據(jù),堪稱(chēng)完美。各大機(jī)器學(xué)習(xí)教材也是如此,都給大家提供處理好的數(shù)據(jù),這就導(dǎo)致,很多人在學(xué)了很多算法之后,到了現(xiàn)實(shí)應(yīng)用之中,發(fā)現(xiàn)模型經(jīng)常就調(diào)不動(dòng)了,因?yàn)楝F(xiàn)實(shí)中的數(shù)據(jù),離平時(shí)上課使用的完美數(shù)據(jù)集,相差十萬(wàn)八千里。所以我決定,少講一兩個(gè)簡(jiǎn)單的算法,為大家專(zhuān)門(mén)拿一堂課來(lái)講解建模之前的流程,數(shù)據(jù)預(yù)處理和特征工程。這樣大家即可以學(xué)到數(shù)據(jù)挖掘過(guò)程中很重要但是卻經(jīng)常被忽視的一些步驟,也可以不受課堂的限制,如果自己有時(shí)間,可以嘗試在真實(shí)數(shù)據(jù)上建模。
| 數(shù)據(jù)挖掘的五大流程: |
|---|
| 1. 獲取數(shù)據(jù) 2. 數(shù)據(jù)預(yù)處理 數(shù)據(jù)預(yù)處理是從數(shù)據(jù)中檢測(cè),糾正或刪除損壞,不準(zhǔn)確或不適用于模型的記錄的過(guò)程 可能面對(duì)的問(wèn)題有:數(shù)據(jù)類(lèi)型不同,比如有的是文字,有的是數(shù)字,有的含時(shí)間序列,有的連續(xù),有的間斷。也可能,數(shù)據(jù)的質(zhì)量不行,有噪聲,有異常,有缺失,數(shù)據(jù)出錯(cuò),量綱不一,有重復(fù),數(shù)據(jù)是偏態(tài),數(shù)據(jù)量太大或太小 數(shù)據(jù)預(yù)處理的目的:讓數(shù)據(jù)適應(yīng)模型,匹配模型的需求 3. 特征工程: 特征工程是將原始數(shù)據(jù)轉(zhuǎn)換為更能代表預(yù)測(cè)模型的潛在問(wèn)題的特征的過(guò)程,可以通過(guò)挑選最相關(guān)的特征,提取特征以及創(chuàng)造特征來(lái)實(shí)現(xiàn)。其中創(chuàng)造特征又經(jīng)常以降維算法的方式實(shí)現(xiàn)。 可能面對(duì)的問(wèn)題有:特征之間有相關(guān)性,特征和標(biāo)簽無(wú)關(guān),特征太多或太小,或者干脆就無(wú)法表現(xiàn)出應(yīng)有的數(shù)據(jù)現(xiàn)象或無(wú)法展示數(shù)據(jù)的真實(shí)面貌 特征工程的目的:1) 降低計(jì)算成本,2) 提升模型上限 4. 建模,測(cè)試模型并預(yù)測(cè)出結(jié)果 5. 上線(xiàn),驗(yàn)證模型效果 |
1.2 sklearn中的數(shù)據(jù)預(yù)處理和特征工程
sklearn中包含眾多數(shù)據(jù)預(yù)處理和特征工程相關(guān)的模塊,雖然剛接觸sklearn時(shí),大家都會(huì)為其中包含的各種算法的廣度深度所震驚,但其實(shí)sklearn六大板塊中有兩塊都是關(guān)于數(shù)據(jù)預(yù)處理和特征工程的,兩個(gè)板塊互相交互,為建模之前的全部工程打下基礎(chǔ)。
- 模塊preprocessing:幾乎包含數(shù)據(jù)預(yù)處理的所有內(nèi)容
- 模塊Impute:填補(bǔ)缺失值專(zhuān)用
- 模塊feature_selection:包含特征選擇的各種方法的實(shí)踐
- 模塊decomposition:包含降維算法
2 數(shù)據(jù)預(yù)處理 Preprocessing & Impute
2.1 數(shù)據(jù)無(wú)量綱化
在機(jī)器學(xué)習(xí)算法實(shí)踐中,我們往往有著將不同規(guī)格的數(shù)據(jù)轉(zhuǎn)換到同一規(guī)格,或不同分布的數(shù)據(jù)轉(zhuǎn)換到某個(gè)特定分布的需求,這種需求統(tǒng)稱(chēng)為將數(shù)據(jù)“無(wú)量綱化”。譬如梯度和矩陣為核心的算法中,譬如邏輯回歸,支持向量機(jī),神經(jīng)網(wǎng)絡(luò),無(wú)量綱化可以加快求解速度;而在距離類(lèi)模型,譬如K近鄰,K-Means聚類(lèi)中,無(wú)量綱化可以幫我們提升模型精度,避免某一個(gè)取值范圍特別大的特征對(duì)距離計(jì)算造成影響。(一個(gè)特例是決策樹(shù)和樹(shù)的集成算法們,對(duì)決策樹(shù)我們不需要無(wú)量綱化,決策樹(shù)可以把任意數(shù)據(jù)都處理得很好。)
數(shù)據(jù)的無(wú)量綱化可以是線(xiàn)性的,也可以是非線(xiàn)性的。線(xiàn)性的無(wú)量綱化包括中心化(Zero-centered或者M(jìn)ean-subtraction)處理和縮放處理(Scale)。中心化的本質(zhì)是讓所有記錄減去一個(gè)固定值,即讓數(shù)據(jù)樣本數(shù)據(jù)平移到某個(gè)位置??s放的本質(zhì)是通過(guò)除以一個(gè)固定值,將數(shù)據(jù)固定在某個(gè)范圍之中,取對(duì)數(shù)也算是一種縮放處理。
- preprocessing.MinMaxScaler
當(dāng)數(shù)據(jù)(x)按照最小值中心化后,再按極差(最大值 - 最小值)縮放,數(shù)據(jù)移動(dòng)了最小值個(gè)單位,并且會(huì)被收斂到[0,1]之間,而這個(gè)過(guò)程,就叫做數(shù)據(jù)歸一化(Normalization,又稱(chēng)Min-Max Scaling)。注意,Normalization是歸一化,不是正則化,真正的正則化是regularization,不是數(shù)據(jù)預(yù)處理的一種手段。歸一化之后的數(shù)據(jù)服從正態(tài)分布,公式如下:
在sklearn當(dāng)中,我們使用preprocessing.MinMaxScaler來(lái)實(shí)現(xiàn)這個(gè)功能。MinMaxScaler有一個(gè)重要參數(shù),feature_range,控制我們希望把數(shù)據(jù)壓縮到的范圍,默認(rèn)是[0,1]。
from sklearn.preprocessing import MinMaxScaler
data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]
#不太熟悉numpy的小伙伴,能夠判斷data的結(jié)構(gòu)嗎?
#如果換成表是什么樣子?
import pandas as pd
pd.DataFrame(data)
#實(shí)現(xiàn)歸一化
scaler = MinMaxScaler() #實(shí)例化
scaler = scaler.fit(data) #fit,在這里本質(zhì)是生成min(x)和max(x)
result = scaler.transform(data) #通過(guò)接口導(dǎo)出結(jié)果
result
result_ = scaler.fit_transform(data) #訓(xùn)練和導(dǎo)出結(jié)果一步達(dá)成
scaler.inverse_transform(result) #將歸一化后的結(jié)果逆轉(zhuǎn)
#使用MinMaxScaler的參數(shù)feature_range實(shí)現(xiàn)將數(shù)據(jù)歸一化到[0,1]以外的范圍中
data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]
scaler = MinMaxScaler(feature_range=[5,10]) #依然實(shí)例化
result = scaler.fit_transform(data) #fit_transform一步導(dǎo)出結(jié)果
result
#當(dāng)X中的特征數(shù)量非常多的時(shí)候,fit會(huì)報(bào)錯(cuò)并表示,數(shù)據(jù)量太大了我計(jì)算不了
#此時(shí)使用partial_fit作為訓(xùn)練接口
#scaler = scaler.partial_fit(data)
BONUS: 使用numpy來(lái)實(shí)現(xiàn)歸一化
import numpy as np
X = np.array([[-1, 2], [-0.5, 6], [0, 10], [1, 18]])
#歸一化
X_nor = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0))
X_nor
#逆轉(zhuǎn)歸一化
X_returned = X_nor * (X.max(axis=0) - X.min(axis=0)) + X.min(axis=0)
X_returned
- preprocessing.StandardScaler
當(dāng)數(shù)據(jù)(x)按均值(μ)中心化后,再按標(biāo)準(zhǔn)差(σ)縮放,數(shù)據(jù)就會(huì)服從為均值為0,方差為1的正態(tài)分布(即標(biāo)準(zhǔn)正態(tài)分布),而這個(gè)過(guò)程,就叫做數(shù)據(jù)標(biāo)準(zhǔn)化(Standardization,又稱(chēng)Z-score normalization),公式如下:
from sklearn.preprocessing import StandardScaler
data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]
scaler = StandardScaler() #實(shí)例化
scaler.fit(data) #fit,本質(zhì)是生成均值和方差
scaler.mean_ #查看均值的屬性mean_
scaler.var_ #查看方差的屬性var_
x_std = scaler.transform(data) #通過(guò)接口導(dǎo)出結(jié)果
x_std.mean() #導(dǎo)出的結(jié)果是一個(gè)數(shù)組,用mean()查看均值
x_std.std() #用std()查看方差
scaler.fit_transform(data) #使用fit_transform(data)一步達(dá)成結(jié)果
scaler.inverse_transform(x_std) #使用inverse_transform逆轉(zhuǎn)標(biāo)準(zhǔn)化
對(duì)于StandardScaler和MinMaxScaler來(lái)說(shuō),空值NaN會(huì)被當(dāng)做是缺失值,在fit的時(shí)候忽略,在transform的時(shí)候保持缺失NaN的狀態(tài)顯示。并且,盡管去量綱化過(guò)程不是具體的算法,但在fit接口中,依然只允許導(dǎo)入至少二維數(shù)組,一維數(shù)組導(dǎo)入會(huì)報(bào)錯(cuò)。通常來(lái)說(shuō),我們輸入的X會(huì)是我們的特征矩陣,現(xiàn)實(shí)案例中特征矩陣不太可能是一維所以不會(huì)存在這個(gè)問(wèn)題。
- StandardScaler和MinMaxScaler選哪個(gè)?
看情況。大多數(shù)機(jī)器學(xué)習(xí)算法中,會(huì)選擇StandardScaler來(lái)進(jìn)行特征縮放,因?yàn)镸inMaxScaler對(duì)異常值非常敏感。在PCA,聚類(lèi),邏輯回歸,支持向量機(jī),神經(jīng)網(wǎng)絡(luò)這些算法中,StandardScaler往往是最好的選擇。
MinMaxScaler在不涉及距離度量、梯度、協(xié)方差計(jì)算以及數(shù)據(jù)需要被壓縮到特定區(qū)間時(shí)使用廣泛,比如數(shù)字圖像處理中量化像素強(qiáng)度時(shí),都會(huì)使用MinMaxScaler將數(shù)據(jù)壓縮于[0,1]區(qū)間之中。
建議先試試看StandardScaler,效果不好換MinMaxScaler。
除了StandardScaler和MinMaxScaler之外,sklearn中也提供了各種其他縮放處理(中心化只需要一個(gè)pandas廣播一下減去某個(gè)數(shù)就好了,因此sklearn不提供任何中心化功能)。比如,在希望壓縮數(shù)據(jù),卻不影響數(shù)據(jù)的稀疏性時(shí)(不影響矩陣中取值為0的個(gè)數(shù)時(shí)),我們會(huì)使用MaxAbsScaler;在異常值多,噪聲非常大時(shí),我們可能會(huì)選用分位數(shù)來(lái)無(wú)量綱化,此時(shí)使用RobustScaler。更多詳情請(qǐng)參考以下列表。
2.2 缺失值
機(jī)器學(xué)習(xí)和數(shù)據(jù)挖掘中所使用的數(shù)據(jù),永遠(yuǎn)不可能是完美的。很多特征,對(duì)于分析和建模來(lái)說(shuō)意義非凡,但對(duì)于實(shí)際收集數(shù)據(jù)的人卻不是如此,因此數(shù)據(jù)挖掘之中,常常會(huì)有重要的字段缺失值很多,但又不能舍棄字段的情況。因此,數(shù)據(jù)預(yù)處理中非常重要的一項(xiàng)就是處理缺失值。
import pandas as pd
data = pd.read_csv(r"C:\work\learnbetter\micro-class\
week 3 Preprocessing\Narrativedata.csv",index_col=0)
data.head()
在這里,我們使用從泰坦尼克號(hào)提取出來(lái)的數(shù)據(jù),這個(gè)數(shù)據(jù)有三個(gè)特征,一個(gè)數(shù)值型,兩個(gè)字符型,標(biāo)簽也是字符型。從這里開(kāi)始,我們就使用這個(gè)數(shù)據(jù)給大家作為例子,讓大家慢慢熟悉sklearn中數(shù)據(jù)預(yù)處理的各種方式。
- impute.SimpleImputer
class sklearn.impute.SimpleImputer(missing_values=nan, strategy=’mean’, fill_value=None, verbose=0, copy=True)
在講解隨機(jī)森林的案例時(shí),我們用這個(gè)類(lèi)和隨機(jī)森林回歸填補(bǔ)了缺失值,對(duì)比了不同的缺失值填補(bǔ)方式對(duì)數(shù)據(jù)的影響。這個(gè)類(lèi)是專(zhuān)門(mén)用來(lái)填補(bǔ)缺失值的。它包括四個(gè)重要參數(shù):
| 參數(shù) | 含義&輸入 |
|---|---|
| missing_values | 告訴SimpleImputer,數(shù)據(jù)中的缺失值長(zhǎng)什么樣,默認(rèn)空值np.nan |
| strategy | 我們填補(bǔ)缺失值的策略,默認(rèn)均值。 輸入“mean”使用均值填補(bǔ)(僅對(duì)數(shù)值型特征可用) 輸入“median"用中值填補(bǔ)(僅對(duì)數(shù)值型特征可用) 輸入"most_frequent”用眾數(shù)填補(bǔ)(對(duì)數(shù)值型和字符型特征都可用) 輸入“constant"表示請(qǐng)參考參數(shù)“fill_value"中的值(對(duì)數(shù)值型和字符型特征都可用) |
| fill_value | 當(dāng)參數(shù)startegy為”constant"的時(shí)候可用,可輸入字符串或數(shù)字表示要填充的值,常用0 |
| copy | 默認(rèn)為T(mén)rue,將創(chuàng)建特征矩陣的副本,反之則會(huì)將缺失值填補(bǔ)到原本的特征矩陣中去。 |
data.info()
#填補(bǔ)年齡
Age = data.loc[:,"Age"].values.reshape(-1,1) #sklearn當(dāng)中特征矩陣必須是二維
Age[:20]
from sklearn.impute import SimpleImputer
imp_mean = SimpleImputer() #實(shí)例化,默認(rèn)均值填補(bǔ)
imp_median = SimpleImputer(strategy="median") #用中位數(shù)填補(bǔ)
imp_0 = SimpleImputer(strategy="constant",fill_value=0) #用0填補(bǔ)
imp_mean = imp_mean.fit_transform(Age) #fit_transform一步完成調(diào)取結(jié)果
imp_median = imp_median.fit_transform(Age)
imp_0 = imp_0.fit_transform(Age)
imp_mean[:20]
imp_median[:20]
imp_0[:20]
#在這里我們使用中位數(shù)填補(bǔ)Age
data.loc[:,"Age"] = imp_median
data.info()
#使用眾數(shù)填補(bǔ)Embarked
Embarked = data.loc[:,"Embarked"].values.reshape(-1,1)
imp_mode = SimpleImputer(strategy = "most_frequent")
data.loc[:,"Embarked"] = imp_mode.fit_transform(Embarked)
data.info()
BONUS:用Pandas和Numpy進(jìn)行填補(bǔ)其實(shí)更加簡(jiǎn)單
import pandas as pd
data = pd.read_csv(r"C:\work\learnbetter\micro-class\week 3 Preprocessing\Narrativedata.csv",index_col=0)
data.head()
data.loc[:,"Age"] = data.loc[:,"Age"].fillna(data.loc[:,"Age"].median())
#.fillna 在DataFrame里面直接進(jìn)行填補(bǔ)
data.dropna(axis=0,inplace=True)
.dropna(axis=0)刪除所有有缺失值的行,.dropna(axis=1)刪除所有有缺失值的列
參數(shù)inplace,為T(mén)rue表示在原數(shù)據(jù)集上進(jìn)行修改,為False表示生成一個(gè)復(fù)制對(duì)象,不修改原數(shù)據(jù),默認(rèn)False
2.3 處理分類(lèi)型特征:編碼與啞變量
在機(jī)器學(xué)習(xí)中,大多數(shù)算法,譬如邏輯回歸,支持向量機(jī)SVM,k近鄰算法等都只能夠處理數(shù)值型數(shù)據(jù),不能處理文字,在sklearn當(dāng)中,除了專(zhuān)用來(lái)處理文字的算法,其他算法在fit的時(shí)候全部要求輸入數(shù)組或矩陣,也不能夠?qū)胛淖中蛿?shù)據(jù)(其實(shí)手寫(xiě)決策樹(shù)和普斯貝葉斯可以處理文字,但是sklearn中規(guī)定必須導(dǎo)入數(shù)值型)。然而在現(xiàn)實(shí)中,許多標(biāo)簽和特征在數(shù)據(jù)收集完畢的時(shí)候,都不是以數(shù)字來(lái)表現(xiàn)的。比如說(shuō),學(xué)歷的取值可以是["小學(xué)",“初中”,“高中”,"大學(xué)"],付費(fèi)方式可能包含["支付寶",“現(xiàn)金”,“微信”]等等。在這種情況下,為了讓數(shù)據(jù)適應(yīng)算法和庫(kù),我們必須將數(shù)據(jù)進(jìn)行編碼,即是說(shuō),將文字型數(shù)據(jù)轉(zhuǎn)換為數(shù)值型。
- preprocessing.LabelEncoder:標(biāo)簽專(zhuān)用,能夠?qū)⒎诸?lèi)轉(zhuǎn)換為分類(lèi)數(shù)值
from sklearn.preprocessing import LabelEncoder
y = data.iloc[:,-1] #要輸入的是標(biāo)簽,不是特征矩陣,所以允許一維
le = LabelEncoder() #實(shí)例化
le = le.fit(y) #導(dǎo)入數(shù)據(jù)
label = le.transform(y) #transform接口調(diào)取結(jié)果
le.classes_ #屬性.classes_查看標(biāo)簽中究竟有多少類(lèi)別
label #查看獲取的結(jié)果label
le.fit_transform(y) #也可以直接fit_transform一步到位
le.inverse_transform(label) #使用inverse_transform可以逆轉(zhuǎn)
data.iloc[:,-1] = label #讓標(biāo)簽等于我們運(yùn)行出來(lái)的結(jié)果
data.head()
#如果不需要教學(xué)展示的話(huà)我會(huì)這么寫(xiě):
from sklearn.preprocessing import LabelEncoder
data.iloc[:,-1] = LabelEncoder().fit_transform(data.iloc[:,-1])
- preprocessing.OrdinalEncoder:特征專(zhuān)用,能夠?qū)⒎诸?lèi)特征轉(zhuǎn)換為分類(lèi)數(shù)值
from sklearn.preprocessing import OrdinalEncoder
#接口categories_對(duì)應(yīng)LabelEncoder的接口classes_,一模一樣的功能
data_ = data.copy()
data_.head()
OrdinalEncoder().fit(data_.iloc[:,1:-1]).categories_
data_.iloc[:,1:-1] = OrdinalEncoder().fit_transform(data_.iloc[:,1:-1])
data_.head()
- preprocessing.OneHotEncoder:獨(dú)熱編碼,創(chuàng)建啞變量
我們剛才已經(jīng)用OrdinalEncoder把分類(lèi)變量Sex和Embarked都轉(zhuǎn)換成數(shù)字對(duì)應(yīng)的類(lèi)別了。在艙門(mén)Embarked這一列中,我們使用[0,1,2]代表了三個(gè)不同的艙門(mén),然而這種轉(zhuǎn)換是正確的嗎?
我們來(lái)思考三種不同性質(zhì)的分類(lèi)數(shù)據(jù):
1) 艙門(mén)(S,C,Q)
? 三種取值S,C,Q是相互獨(dú)立的,彼此之間完全沒(méi)有聯(lián)系,表達(dá)的是S≠C≠Q(mào)的概念。這是名義變量。
2) 學(xué)歷(小學(xué),初中,高中)
? 三種取值不是完全獨(dú)立的,我們可以明顯看出,在性質(zhì)上可以有高中>初中>小學(xué)這樣的聯(lián)系,學(xué)歷有高低,但是學(xué)歷取值之間卻不是可以計(jì)算的,我們不能說(shuō)小學(xué) + 某個(gè)取值 = 初中。這是有序變量。
3) 體重(>45kg,>90kg,>135kg)
? 各個(gè)取值之間有聯(lián)系,且是可以互相計(jì)算的,比如120kg - 45kg = 90kg,分類(lèi)之間可以通過(guò)數(shù)學(xué)計(jì)算互相轉(zhuǎn)換。這是有距變量。
? 然而在對(duì)特征進(jìn)行編碼的時(shí)候,這三種分類(lèi)數(shù)據(jù)都會(huì)被我們轉(zhuǎn)換為[0,1,2],這三個(gè)數(shù)字在算法看來(lái),是連續(xù)且可以計(jì)算的,這三個(gè)數(shù)字相互不等,有大小,并且有著可以相加相乘的聯(lián)系。所以算法會(huì)把艙門(mén),學(xué)歷這樣的分類(lèi)特征,都誤會(huì)成是體重這樣的分類(lèi)特征。這是說(shuō),我們把分類(lèi)轉(zhuǎn)換成數(shù)字的時(shí)候,忽略了數(shù)字中自帶的數(shù)學(xué)性質(zhì),所以給算法傳達(dá)了一些不準(zhǔn)確的信息,而這會(huì)影響我們的建模。
類(lèi)別OrdinalEncoder可以用來(lái)處理有序變量,但對(duì)于名義變量,我們只有使用啞變量的方式來(lái)處理,才能夠盡量向算法傳達(dá)最準(zhǔn)確的信息:
這樣的變化,讓算法能夠徹底領(lǐng)悟,原來(lái)三個(gè)取值是沒(méi)有可計(jì)算性質(zhì)的,是“有你就沒(méi)有我”的不等概念。在我們的數(shù)據(jù)中,性別和艙門(mén),都是這樣的名義變量。因此我們需要使用獨(dú)熱編碼,將兩個(gè)特征都轉(zhuǎn)換為啞變量。
data.head()
from sklearn.preprocessing import OneHotEncoder
X = data.iloc[:,1:-1]
enc = OneHotEncoder(categories='auto').fit(X)
result = enc.transform(X).toarray()
result
#依然可以直接一步到位,但為了給大家展示模型屬性,所以還是寫(xiě)成了三步
OneHotEncoder(categories='auto').fit_transform(X).toarray()
#依然可以還原
pd.DataFrame(enc.inverse_transform(result))
enc.get_feature_names()
result
result.shape
#axis=1,表示跨行進(jìn)行合并,也就是將量表左右相連,如果是axis=0,就是將量表上下相連
newdata = pd.concat([data,pd.DataFrame(result)],axis=1)
newdata.head()
newdata.drop(["Sex","Embarked"],axis=1,inplace=True)
newdata.columns = ["Age","Survived","Female","Male","Embarked_C","Embarked_Q","Embarked_S"]
newdata.head()
特征可以做啞變量,標(biāo)簽也可以嗎?可以,使用類(lèi)sklearn.preprocessing.LabelBinarizer可以對(duì)做啞變量,許多算法都可以處理多標(biāo)簽問(wèn)題(比如說(shuō)決策樹(shù)),但是這樣的做法在現(xiàn)實(shí)中不常見(jiàn),因此我們?cè)谶@里就不贅述了。
2.4 處理連續(xù)型特征:二值化與分段
- sklearn.preprocessing.Binarizer
根據(jù)閾值將數(shù)據(jù)二值化(將特征值設(shè)置為0或1),用于處理連續(xù)型變量。大于閾值的值映射為1,而小于或等于閾值的值映射為0。默認(rèn)閾值為0時(shí),特征中所有的正值都映射到1。二值化是對(duì)文本計(jì)數(shù)數(shù)據(jù)的常見(jiàn)操作,分析人員可以決定僅考慮某種現(xiàn)象的存在與否。它還可以用作考慮布爾隨機(jī)變量的估計(jì)器的預(yù)處理步驟(例如,使用貝葉斯設(shè)置中的伯努利分布建模)。
#將年齡二值化
data_2 = data.copy()
from sklearn.preprocessing import Binarizer
X = data_2.iloc[:,0].values.reshape(-1,1) #類(lèi)為特征專(zhuān)用,所以不能使用一維數(shù)組
transformer = Binarizer(threshold=30).fit_transform(X)
transformer
- preprocessing.KBinsDiscretizer
這是將連續(xù)型變量劃分為分類(lèi)變量的類(lèi),能夠?qū)⑦B續(xù)型變量排序后按順序分箱后編碼??偣舶齻€(gè)重要參數(shù):
| 參數(shù) | 含義&輸入 |
|---|---|
| n_bins | 每個(gè)特征中分箱的個(gè)數(shù),默認(rèn)5,一次會(huì)被運(yùn)用到所有導(dǎo)入的特征 |
| encode | 編碼的方式,默認(rèn)“onehot” "onehot":做啞變量,之后返回一個(gè)稀疏矩陣,每一列是一個(gè)特征中的一個(gè)類(lèi)別,含有該 類(lèi)別的樣本表示為1,不含的表示為0 “ordinal”:每個(gè)特征的每個(gè)箱都被編碼為一個(gè)整數(shù),返回每一列是一個(gè)特征,每個(gè)特征下含 有不同整數(shù)編碼的箱的矩陣 "onehot-dense":做啞變量,之后返回一個(gè)密集數(shù)組。 |
| strategy | 用來(lái)定義箱寬的方式,默認(rèn)"quantile" "uniform":表示等寬分箱,即每個(gè)特征中的每個(gè)箱的最大值之間的差為 (特征.max() - 特征.min())/(n_bins) "quantile":表示等位分箱,即每個(gè)特征中的每個(gè)箱內(nèi)的樣本數(shù)量都相同 "kmeans":表示按聚類(lèi)分箱,每個(gè)箱中的值到最近的一維k均值聚類(lèi)的簇心得距離都相同 |
from sklearn.preprocessing import KBinsDiscretizer
X = data.iloc[:,0].values.reshape(-1,1)
est = KBinsDiscretizer(n_bins=3, encode='ordinal', strategy='uniform')
est.fit_transform(X)
#查看轉(zhuǎn)換后分的箱:變成了一列中的三箱
set(est.fit_transform(X).ravel())
est = KBinsDiscretizer(n_bins=3, encode='onehot', strategy='uniform')
#查看轉(zhuǎn)換后分的箱:變成了啞變量
est.fit_transform(X).toarray()