用转换器抽取特征
特征抽取
特征抽取是數(shù)據(jù)挖掘任務(wù)為重要的一個(gè)環(huán)節(jié),一般而言,它對(duì)終結(jié)果的影響要高過(guò)數(shù)據(jù)挖掘算法本身。不幸的是,關(guān)于怎樣選取好的特征,還沒(méi)有嚴(yán)格、快捷的規(guī)則可循,其實(shí)這也是數(shù)據(jù)挖掘科學(xué)更像是一門藝術(shù)的所在。創(chuàng)建好的規(guī)則離不開(kāi)直覺(jué),還需要專業(yè)領(lǐng)域知識(shí)和數(shù)據(jù)挖 掘經(jīng)驗(yàn),光有這些還不夠,還得不停地嘗試、摸索,在試錯(cuò)中前進(jìn),有時(shí)多少還要靠點(diǎn)運(yùn)氣。
不是所有的數(shù)據(jù)集都是用特征來(lái)表示的。數(shù)據(jù)集可以是一位作家所寫的全部書籍,也可以是1979年以來(lái)所有電影的膠片,還可以是館藏的一批歷史文物。
我們可能想對(duì)以上數(shù)據(jù)集做數(shù)據(jù)挖掘。對(duì)于作家的作品,我們想知道這位作家都寫過(guò)哪些主題;對(duì)于電影,我們想知道女性形象是怎么塑造的;對(duì)于文物,我們想知道它們是何方產(chǎn)物。我們沒(méi)辦法把實(shí)物直接塞進(jìn)決策樹(shù)來(lái)得到結(jié)果。
只有先把現(xiàn)實(shí)用特征表示出來(lái),才能借助數(shù)據(jù)挖掘的力量找到問(wèn)題的答案。特征可用于建模, 模型以機(jī)器挖掘算法能夠理解的近似的方式來(lái)表示現(xiàn)實(shí)。因此可以說(shuō),模型描述了客觀世界中對(duì) 象的某些方面,是它的一個(gè)簡(jiǎn)化版本。舉例來(lái)說(shuō),象棋就是對(duì)過(guò)往戰(zhàn)事簡(jiǎn)化后得到的一種模型。
特征選擇的另一個(gè)優(yōu)點(diǎn)在于:降低真實(shí)世界的復(fù)雜度,模型比現(xiàn)實(shí)更容易操縱。實(shí)物的復(fù)雜性對(duì)目前的算法而言過(guò)于復(fù)雜,我們退而求其次,使用更為簡(jiǎn)潔的模型來(lái)表示實(shí)物。
我們應(yīng)該始終關(guān)注怎么用模型來(lái)表示現(xiàn)實(shí),要多考慮數(shù)據(jù)挖掘的目標(biāo),而不是輕率地用我們過(guò)去用過(guò)的特征。要經(jīng)常想想我們的目標(biāo)是什么。
年收入預(yù)測(cè)
這里,我們預(yù)測(cè)一個(gè)人年收入是否會(huì)多于5萬(wàn)美元。使用Adult數(shù)據(jù)集來(lái)為復(fù)雜現(xiàn)實(shí)世界建模。數(shù)據(jù)集的下載地址:http://archive.ics.uci.edu/ml/datasets/Adult
點(diǎn)擊Data Folder鏈接。下載adult.data和adult.names文件,在數(shù)據(jù)集文件夾(主目錄下Data文件夾)中創(chuàng)建Adult文件夾,將這兩個(gè)文件放到里面。
我們來(lái)導(dǎo)入數(shù)據(jù):
import os import pandas as pd data_folder = os.path.join(os.path.expanduser("~"), "Data", "Adult") adult_filename = os.path.join(data_folder, "adult.data")adult = pd.read_csv(adult_filename, header=None, names=["Age", "Work-Class", "fnlwgt", "Education","Education-Num", "Marital-Status", "Occupation","Relationship", "Race", "Sex", "Capital-gain","Capital-loss", "Hours-per-week", "Native-Country","Earnings-Raw"])adult.data文件末尾有兩處空行。pandas默認(rèn)把倒數(shù)第二行空行作為一條有效數(shù)據(jù)讀入(只不過(guò)各列的值為空)。我們需要?jiǎng)h除包含無(wú)效數(shù)字的行(設(shè)置inplace參數(shù)為真,表示改動(dòng)當(dāng)前數(shù)據(jù)框,而不是新建一個(gè))
刪除表中的某一行或者某一列更明智的方法是使用drop,它不改變?cè)械膁f中的數(shù)據(jù),而是返回另一個(gè)dataframe來(lái)存放刪除后的數(shù)據(jù)。
# 將全部項(xiàng)都是nan的row刪除 adult.dropna(how='all', inplace=True)下面查看所有保存在pandas中Index中的特征名
adult.columnsIndex([‘Age’, ‘Work-Class’, ‘fnlwgt’, ‘Education’, ‘Education-Num’,
‘Marital-Status’, ‘Occupation’, ‘Relationship’, ‘Race’, ‘Sex’,
‘Capital-gain’, ‘Capital-loss’, ‘Hours-per-week’, ‘Native-Country’,
‘Earnings-Raw’],
dtype=’object’)
通用特征創(chuàng)建模式
我們導(dǎo)入的數(shù)據(jù)集,包含連續(xù)特征、序數(shù)特征。例如,Hours-per-week特征表示一個(gè)人每周的工作時(shí)間。這個(gè)特征可用來(lái)計(jì)算平均工作時(shí)間、標(biāo)準(zhǔn)差、大值和小值。pandas提 供了常見(jiàn)統(tǒng)計(jì)量的計(jì)算方法。
adult["Hours-per-week"].describe()結(jié)果:
count 32561.000000
mean 40.437456
std 12.347429
min 1.000000
25% 40.000000
50% 40.000000
75% 45.000000
max 99.000000
Name: Hours-per-week, dtype: float64
對(duì)于序數(shù)特征,Education-Num(受教育年限)
adult["Education-Num"].median()結(jié)果為10,或者可以表述為剛好讀完高一。如果沒(méi)有受教育年限數(shù)據(jù),我們?yōu)椴煌逃A段 指定數(shù)字編號(hào),也可以計(jì)算均值。
特征也可以是類別型的。例如,一個(gè)球可以是網(wǎng)球、棒球、足球或其他種類。類別型特征也可以稱為名義特征(nominal)。對(duì)于名義特征而言,幾個(gè)值之間要么相同要么不同。
類別型特征二值化后就變成了數(shù)值型特征,對(duì)于上述球的種類,可以創(chuàng)建三個(gè)二值特征:“是網(wǎng)球”“是棒球”和“是足球”。如果是網(wǎng)球的話,特征向量就是[1, 0, 0], 棒球[0, 1, 0],足球[0, 0, 1]。這些特征都只有兩個(gè)取值,很多算法都可以把它們作為連續(xù)型特征使用。二值化的好處是,便于直接進(jìn)行數(shù)字上的比較(例如計(jì)算個(gè)體之間的距離)。
再舉一個(gè)類別形的例子,,例如Work-Class(工作),其中它的有些值可以進(jìn)行量級(jí)上的比較,比如不同的就業(yè)狀況影響收入(例如有工作的人比沒(méi)有工作的人收入高)
adult["Work-Class"].unique()array([’ State-gov’, ’ Self-emp-not-inc’, ’ Private’, ’ Federal-gov’,
’ Local-gov’, ’ ?’, ’ Self-emp-inc’, ’ Without-pay’, ’ Never-worked’], dtype=object)
數(shù)據(jù)集中有部分?jǐn)?shù)據(jù)缺失,但不會(huì)影響計(jì)算。
同理,數(shù)值型特征也可以通過(guò)離散化過(guò)程轉(zhuǎn)換為類別型特征,例如,高于 1.7m的人,我們稱其為高個(gè)子,低于1.7m的叫作矮個(gè)子。這樣就得到了類別型特征(雖然是序數(shù) 值類型)。在這個(gè)過(guò)程中確實(shí)丟失了一些信息。例如,有兩個(gè)人,身高分別為1.69m和1.71m,這 兩個(gè)個(gè)子差不多的將被分到兩個(gè)截然不同的類別里。而身高僅為1.2m的將會(huì)被認(rèn)為與身高1.69m 的“差不多高”!細(xì)節(jié)的丟失是離散化不好的一面,也是建模時(shí)需要考慮解決的問(wèn)題。
對(duì)于Adult數(shù)據(jù)集,我們可以創(chuàng)建LongHours(時(shí)長(zhǎng))特征,用它來(lái)表示一個(gè)人每周工作時(shí) 長(zhǎng)是否多于40小時(shí)。這樣就把連續(xù)值(Hours-per-week,每周工作時(shí)長(zhǎng))轉(zhuǎn)換為類別型特征。
adult["LongHours"] = adult["Hours-per-week"] > 40創(chuàng)建好的特征
建模過(guò)程中,需要對(duì)真實(shí)世界中的對(duì)象進(jìn)行簡(jiǎn)化,這會(huì)導(dǎo)致信息的丟失,這也就是為什么沒(méi)有一套能夠用于任何數(shù)據(jù)集的通用的數(shù)據(jù)挖掘方法。數(shù)據(jù)挖掘的行家里手需要擁有數(shù)據(jù)來(lái)源領(lǐng)域的知識(shí),沒(méi)有的話,要積極去掌握。他們弄清楚問(wèn)題是什么,了解有哪些可用數(shù)據(jù)后,在此基礎(chǔ)上,才能創(chuàng)建解決問(wèn)題所需的模型。
例如,身高這個(gè)特征描述的是一個(gè)人外表的某個(gè)方面,但是不能說(shuō)明這個(gè)人學(xué)習(xí)成績(jī)?nèi)绾?#xff0c; 所以預(yù)測(cè)學(xué)習(xí)成績(jī)時(shí),我們沒(méi)必要去測(cè)量每個(gè)人的身高。
這正是數(shù)據(jù)挖掘?yàn)槭裁醋兊酶袷且婚T藝術(shù)而不是科學(xué)的原因所在。抽取好的特征難度不小,該課題具有重要研究意義,因此它獲得了研究人員的持續(xù)關(guān)注。選擇好的分類算法也可以提升數(shù)據(jù)挖掘應(yīng)用的效果,但好還是通過(guò)選用好的特征來(lái)達(dá)到同樣的目的。
通常特征數(shù)量很多,但我們只想選用其中一小部分。有如下幾個(gè)原因。
降低復(fù)雜度: 隨著特征數(shù)量的增加,很多數(shù)據(jù)挖掘算法需要更多的時(shí)間和資源。減少特征數(shù)量,是提高算法運(yùn)行速度,減少資源使用的好方法。
降低噪聲 : 增加額外特征并不總會(huì)提升算法的表現(xiàn)。額外特征可能擾亂算法的正常工作, 這些額外特征間的相關(guān)性和模式?jīng)]有實(shí)際應(yīng)用價(jià)值(這種情況在小數(shù)據(jù)集上很常見(jiàn))。只 選擇合適的特征有助于減少出現(xiàn)沒(méi)有實(shí)際意義的相關(guān)性的幾率。
增加模型可讀性:根據(jù)成千上萬(wàn)個(gè)特征創(chuàng)建的模型來(lái)解答一個(gè)問(wèn)題,對(duì)計(jì)算機(jī)來(lái)說(shuō)很容易,但模型對(duì)我們自己來(lái)說(shuō)就晦澀無(wú)比。因此,使用更少的特征,創(chuàng)建我們自己可以理解的模型,就很有必要。
scikit-learn中的VarianceThreshold轉(zhuǎn)換器可用來(lái)刪除特征值的方差達(dá)不到低標(biāo)準(zhǔn) 的特征。下面通過(guò)代碼來(lái)講下它的用法。
import numpy as np X = np.arange(30).reshape((10, 3))上述矩陣包含0到29,共30個(gè)數(shù)字,分為3列10行。可以把它看成一個(gè)有10個(gè)個(gè)體、3個(gè)特征的數(shù)據(jù)集。
接著,把所有第二列的數(shù)值都改為1
X[:,1] = 1第一、三列特征值方差很大,而第二列方差為0。
這時(shí)再來(lái)創(chuàng)建VarianceThreshold轉(zhuǎn)換器,用它處理數(shù)據(jù)集。
from sklearn.feature_selection import VarianceThresholdvt = VarianceThreshold() Xt = vt.fit_transform(X)輸出Xt后,我們發(fā)現(xiàn)第二列消失了。
array([[ 0, 2],
[ 3, 5],
[ 6, 8],
[ 9, 11],
[12, 14],
[15, 17],
[18, 20],
[21, 23],
[24, 26],
[27, 29]])
輸出每一列的方差:
下面輸出結(jié)果表明第一、三列包含有價(jià)值信息,第二列方差為0,不包含具有區(qū)別意義的信息。
array([ 74.25, 0. , 74.25])
無(wú)論什么時(shí)候,拿到數(shù)據(jù)后,先做下類似簡(jiǎn)單、直接的分析,對(duì)數(shù)據(jù)集的特點(diǎn)做到心中有數(shù)。 方差為0的特征不但對(duì)數(shù)據(jù)挖掘沒(méi)有絲毫用處,相反還會(huì)拖慢算法的運(yùn)行速度。
選擇最佳特征
在特征逐漸變多的情況下,特征的組合復(fù)雜度呈指數(shù)增加。尋找最佳組合的時(shí)間復(fù)雜度也是呈指數(shù)增加。
其中一個(gè)變通方法是不要找表現(xiàn)好的子集,而只是去找表現(xiàn)好的單個(gè)特征(單變量),依據(jù)是它們各自所能達(dá)到的精確度。分類任務(wù)通常是這么做的,我們一般只要測(cè)量變量和目標(biāo)類別之間的某種相關(guān)性就行。
scikit-learn提供了幾個(gè)用于選擇單變量特征的轉(zhuǎn)換器,其中SelectKBest返回k個(gè)佳特征,SelectPercentile返回表現(xiàn)佳的前r%個(gè)特征。這兩個(gè)轉(zhuǎn)換器都提供計(jì)算特征表現(xiàn)的一系列方法。
單個(gè)特征和某一類別之間相關(guān)性的計(jì)算方法有很多。常用的有卡方檢驗(yàn)(χ2)。其他方法還有互信息和信息熵。
我們可以測(cè)試單個(gè)特征在Adult數(shù)據(jù)集上的表現(xiàn)。首先,選取下述特征,從pandas數(shù)據(jù)框中抽 取一部分?jǐn)?shù)據(jù)。
接著,判斷Earnings-Raw(稅前收入)是否達(dá)到五萬(wàn)美元,創(chuàng)建目標(biāo)類別列表。如果達(dá)到, 類別為True,否則,類別為False。
X = adult[["Age", "Education-Num", "Capital-gain", "Capital-loss", "Hours-per-week"]].values y = (adult["Earnings-Raw"] == ' >50K').values再使用SelectKBest轉(zhuǎn)換器類,用卡方函數(shù)打分,初始化轉(zhuǎn)換器。
from sklearn.feature_selection import SelectKBest from sklearn.feature_selection import chi2 transformer = SelectKBest(score_func=chi2, k=3)調(diào)用fit_transform方法,對(duì)相同的數(shù)據(jù)集進(jìn)行預(yù)處理和轉(zhuǎn)換。結(jié)果為分類效果較好的三個(gè)特征。代碼如下
Xt_chi2 = transformer.fit_transform(X, y) print(transformer.scores_)生成的矩陣只包含三個(gè)特征。我們還可以得到每一列的相關(guān)性,這樣就可以知道都使用了哪些特征。
結(jié)果:[8.60061182e+03 2.40142178e+03 8.21924671e+07 1.37214589e+06
6.47640900e+03]
相關(guān)性好的分別是第一、三、四列,分別對(duì)應(yīng)著Age(年齡)、Capital-Gain(資本收 益)和Capital-Loss(資本損失)三個(gè)特征。從單變量特征選取角度來(lái)說(shuō),這些就是佳特征。
還可以用其他方法計(jì)算相關(guān)性,比如皮爾遜(Pearson)相關(guān)系數(shù)。用于科學(xué)計(jì)算的SciPy 庫(kù)(scikit-learn在它基礎(chǔ)上開(kāi)發(fā),安裝scikit-learn時(shí)默認(rèn)安裝了)實(shí)現(xiàn)了該方法。
pearsonr函數(shù)的接口幾乎與scikit-learn單變量轉(zhuǎn)換器接口一致,該函數(shù)接收兩個(gè)數(shù)組 (當(dāng)前例子中為x和y)作為參數(shù),返回兩個(gè)數(shù)組:每個(gè)特征的皮爾遜相關(guān)系數(shù)和p值(p-value)。 前面用到的chi2函數(shù)使用的接口符合要求,因此我們直接把它傳入到SelectKBest函數(shù)中。
SciPy的pearsonr函數(shù)參數(shù)為兩個(gè)數(shù)組,但要注意的是第一個(gè)參數(shù)x為一維數(shù)組。我們來(lái)實(shí)現(xiàn)一個(gè)包裝器函數(shù),這樣就能像前面那樣處理多維數(shù)組。
from scipy.stats import pearsonrdef multivariate_pearsonr(X, y):# 創(chuàng)建scores和pvalues數(shù)組,遍歷數(shù)據(jù)集的每一列scores, pvalues = [], []for column in range(X.shape[1]):# 只計(jì)算該列的皮爾遜相關(guān)系數(shù)和p值,并將其存儲(chǔ)到相應(yīng)數(shù)組中cur_score, cur_p = pearsonr(X[:,column], y)scores.append(abs(cur_score))pvalues.append(cur_p)# 后返回包含皮爾遜相關(guān)系數(shù)和p值的元組return (np.array(scores), np.array(pvalues))p值為-1到1之間的任意值。值為1,表示兩個(gè)變量之間絕對(duì)正相關(guān),值為-1, 絕對(duì)負(fù)相關(guān),即一個(gè)變量值越大,另一個(gè)變量值就越小,反之亦然。這樣的特征 確實(shí)能反應(yīng)兩個(gè)變量之間的關(guān)系,但是根據(jù)大小進(jìn)行排序,這些值因?yàn)槭秦?fù)數(shù)而 排在后面,可能會(huì)被舍棄不用。因此,我們對(duì)p值取絕對(duì)值后,再保存到scores 數(shù)組中,而不是使用原始值。
現(xiàn)在可以使用轉(zhuǎn)換器,根據(jù)皮爾遜相關(guān)系數(shù)對(duì)特征進(jìn)行排序。
transformer = SelectKBest(score_func=multivariate_pearsonr, k=3) Xt_pearson = transformer.fit_transform(X, y) print(transformer.scores_)[ 0.2340371 0.33515395 0.22332882 0.15052631 0.22968907]
返回的結(jié)果和卡方檢驗(yàn)不一樣,可以說(shuō),對(duì)于最好的特征選擇,實(shí)際上沒(méi)有統(tǒng)一的度量標(biāo)準(zhǔn)。
我們最后看一下在該任務(wù)下,哪個(gè)特征選擇的效果更好:
from sklearn.tree import DecisionTreeClassifier from sklearn.cross_validation import cross_val_score clf = DecisionTreeClassifier(random_state=14) scores_chi2 = cross_val_score(clf, Xt_chi2, y, scoring='accuracy') scores_pearson = cross_val_score(clf, Xt_pearson, y, scoring='accuracy')print("Chi2 performance: {0:.3f}".format(scores_chi2.mean())) print("Pearson performance: {0:.3f}".format(scores_pearson.mean()))chi2方法的平均正確率為0.83,而皮爾遜相關(guān)系數(shù)正確率為0.77。用卡方檢驗(yàn)得到的特征組 合效果更好!
我們只用三個(gè)特征對(duì)于預(yù)測(cè)收入就能達(dá)到83%的正確率,可以說(shuō)是挺厲害的了。
參考資料
《Python數(shù)據(jù)挖掘入門與實(shí)踐》
總結(jié)
- 上一篇: 用亲和性分析方法推荐电影
- 下一篇: 创建自己的特征和转换器