上圖為大家熟悉的機器學習建模流程圖(擴展閱讀:一文全覽機器學習建模流程(Python代碼)),整個建模流程非常重要的一步,是對于數(shù)據(jù)的預(yù)處理和特征工程,它很大程度決定了最后建模效果的好壞。

特征工程簡介

首先我們來了解一下『特征工程』。事實上大家在ShowMeAI的實戰(zhàn)系列文章?Python機器學習綜合項目-電商銷量預(yù)估[2]?和?Python機器學習綜合項目-電商銷量預(yù)估(進階)[3]?中已經(jīng)看到了我們做了特征工程的處理。

如果我們對特征工程(feature engineering)做一個定義,那它指的是:利用領(lǐng)域知識和現(xiàn)有數(shù)據(jù),創(chuàng)造出新的特征,用于機器學習算法;可以手動或自動。

在業(yè)界有一個很流行的說法:據(jù)與特征工程決定了模型的上限,改進算法只不過是逼近這個上限而已。

這是因為,在數(shù)據(jù)建模上,『理想狀態(tài)』和『真實場景』是有差別的,很多時候原始數(shù)據(jù)并不是規(guī)矩干凈含義明確充分的形態(tài):

而特征工程處理,相當于對數(shù)據(jù)做一個梳理,結(jié)合業(yè)務(wù)提取有意義的信息,以干凈整齊地形態(tài)進行組織:特征工程有著非常重要的意義:

本篇內(nèi)容,ShowMeAI帶大家一起來系統(tǒng)學習一下特征工程,包括『1.特征類型』『2.數(shù)據(jù)清洗』『3.特征構(gòu)建』『4.特征變換』『5.特征選擇』等板塊內(nèi)容。

Titanic實戰(zhàn)項目

我們這里用最簡單和常用的Titanic數(shù)據(jù)集給大家講解。

Titanic 數(shù)據(jù)集是非常適合數(shù)據(jù)科學和機器學習新手入門練習的數(shù)據(jù)集,數(shù)據(jù)集為1912年泰坦尼克號沉船事件中一些船員的個人信息以及存活狀況。我們可以根據(jù)數(shù)據(jù)集訓練出合適的模型并預(yù)測新數(shù)據(jù)(測試集)中的存活狀況。

Titanic 數(shù)據(jù)集可以通過 Seaborn 工具庫直接加載,如下代碼所示:

import pandas as pd
import numpy as np
import seaborn as sns
df_titanic = sns.load_dataset('titanic')

其中數(shù)據(jù)集的數(shù)據(jù)字段描述如下圖所示:

1.特征類型

在具體演示 Titanic 的數(shù)據(jù)預(yù)處理與特征工程之前,ShowMeAI再給大家構(gòu)建一些關(guān)于數(shù)據(jù)的基礎(chǔ)知識。

數(shù)據(jù)可以分為『結(jié)構(gòu)化數(shù)據(jù)』和『非結(jié)構(gòu)化數(shù)據(jù)』,比如在互聯(lián)網(wǎng)領(lǐng)域,大部分存儲在數(shù)據(jù)庫內(nèi)的表格態(tài)業(yè)務(wù)數(shù)據(jù),都是結(jié)構(gòu)化數(shù)據(jù);而文本、語音、圖像視頻等就屬于非結(jié)構(gòu)化數(shù)據(jù)。

對于我們記錄到的數(shù)據(jù),我們通常又可以以『定量數(shù)據(jù)』和『定性數(shù)據(jù)』對齊進行區(qū)分,其中:

2.數(shù)據(jù)清洗

實際數(shù)據(jù)挖掘或者建模之前,我們會有『數(shù)據(jù)預(yù)處理』環(huán)節(jié),對原始態(tài)的數(shù)據(jù)進行數(shù)據(jù)清洗等操作處理。

因為現(xiàn)實世界中數(shù)據(jù)大體上都是不完整、不一致的『臟數(shù)據(jù)』,無法直接進行數(shù)據(jù)挖掘,或者挖掘結(jié)果差強人意。

『臟數(shù)據(jù)』產(chǎn)生的主要成因包括:篡改數(shù)據(jù)、數(shù)據(jù)不完整、數(shù)據(jù)不一致、數(shù)據(jù)重復(fù)、異常數(shù)據(jù)等。

數(shù)據(jù)清洗過程包括『2.1 數(shù)據(jù)對齊』、『2.2 缺失值處理』、『2.3 異常值處理』『2.4 數(shù)據(jù)轉(zhuǎn)化等』數(shù)據(jù)處理方法。我們對這些處理方法做詳細講解。

2.1 數(shù)據(jù)對齊

采集到的原始數(shù)據(jù),格式形態(tài)不一,我們會對時間、字段以及相關(guān)量綱等進行數(shù)據(jù)對齊處理,數(shù)據(jù)對齊和規(guī)整化之后的數(shù)據(jù)整齊一致,更加適合建模。如下圖為一些處理示例:

① 時間

② 字段

③ 量綱

2.2 缺失值處理

數(shù)據(jù)缺失是真實數(shù)據(jù)中常見的問題,因為種種原因我們采集到的數(shù)據(jù)并不一定是完整的,我們有一些缺失值的常見處理方式。具體的處理方式可以展開成圖:

下面回到我們的Titanic數(shù)據(jù)集,我們演示一下各種方法。我們先對數(shù)據(jù)集的缺失值情況做一個了解(匯總分布):

df_titanic.isnull().sum()
survived         0
pclass 0
sex 0
age 177
sibsp 0
parch 0
fare 0
embarked 2
class 0
who 0
adult_male 0
deck 688
embark_town 2
alive 0
alone 0

(1) 刪除 · 缺失值處理

最直接粗暴的處理是剔除缺失值,即將存在遺漏信息屬性值的對象 (字段,樣本/記錄) 刪除,從而得到一個完備的信息表。優(yōu)缺點如下:

在我們當前Titanic的案例中,embark_town字段有 2 個空值,考慮刪除缺失處理下。

df_titanic[df_titanic["embark_town"].isnull()]
df_titanic.dropna(axis=0,how='any',subset=['embark_town'],inplace=True)

(2) 數(shù)據(jù)填充 · 缺失值處理

第2大類是我們可以通過一些方法去填充缺失值。比如基于統(tǒng)計方法、模型方法、結(jié)合業(yè)務(wù)的方法等進行填充。

① 手動填充。根據(jù)業(yè)務(wù)知識來進行人工手動填充。

② 特殊值填充。將空值作為一種特殊的屬性值來處理,它不同于其他的任何屬性值。如所有的空值都用unknown填充。一般作為臨時填充或中間過程。

df_titanic['embark_town'].fillna('unknown', inplace=True)

③ 統(tǒng)計量填充。若缺失率較低,可以根據(jù)數(shù)據(jù)分布的情況進行填充。常用填充統(tǒng)計量如下:

中位數(shù)填充——fare:缺失值較多,使用中位數(shù)填充。

df_titanic['fare'].fillna(df_titanic['fare'].median(), inplace=True) 

眾數(shù)填充——embarked:只有兩個缺失值,使用眾數(shù)填充。

df_titanic['embarked'].isnull().sum()
#執(zhí)行結(jié)果:2
df_titanic['embarked'].fillna(df_titanic['embarked'].mode(), inplace=True)
df_titanic['embarked'].value_counts()
#執(zhí)行結(jié)果:
#S 64

同類均值填充。

age:根據(jù) sex、pclass 和 who 分組,如果落在相同的組別里,就用這個組別的均值或中位數(shù)填充。

df_titanic.groupby(['sex', 'pclass', 'who'])['age'].mean()
age_group_mean = df_titanic.groupby(['sex', 'pclass', 'who'])['age'].mean().reset_index()
def select_group_age_median(row):
condition = ((row['sex'] == age_group_mean['sex']) &
(row['pclass'] == age_group_mean['pclass']) &
(row['who'] == age_group_mean['who']))
return age_group_mean[condition]['age'].values[0]

df_titanic['age'] =df_titanic.apply(lambda x: select_group_age_median(x) if np.isnan(x['age']) else x['age'],axis=1)

④ 模型預(yù)測填充。如果其他無缺失字段豐富,我們也可以借助于模型進行建模預(yù)測填充,將待填充字段作為Label,沒有缺失的數(shù)據(jù)作為訓練數(shù)據(jù),建立分類/回歸模型,對待填充的缺失字段進行預(yù)測并進行填充。

我們以 Titanic 案例中的 age 字段為例,講解一下:

age 缺失量較大,這里我們用 sex、pclass、who、fare、parch、sibsp 六個特征構(gòu)建隨機森林模型,填充年齡缺失值。

df_titanic_age = df_titanic[['age', 'pclass', 'sex', 'who','fare', 'parch', 'sibsp']]
df_titanic_age = pd.get_dummies(df_titanic_age)
df_titanic_age.head()
# 乘客分成已知年齡和未知年齡兩部分
known_age = df_titanic_age[df_titanic_age.age.notnull()]
unknown_age = df_titanic_age[df_titanic_age.age.isnull()]
# y 即目標年齡
y_for_age = known_age['age']
# X 即特征屬性值
X_train_for_age = known_age.drop(['age'], axis=1)
X_test_for_age = unknown_age.drop(['age'], axis=1)
from sklearn.ensemble import RandomForestRegressor
rfr = RandomForestRegressor(random_state=0, n_estimators=2000, n_jobs=-1)
rfr.fit(X_train_for_age, y_for_age)
# 用得到的模型進行未知年齡結(jié)果預(yù)測
y_pred_age = rfr.predict(X_test_for_age)
# 用得到的預(yù)測結(jié)果填補原缺失數(shù)據(jù)
df_titanic.loc[df_titanic.age.isnull(), 'age'] = y_pred_age
sns.distplot(df_titanic.age)

⑤ 插值法填充。還可以用插值法對數(shù)據(jù)填充,細分一下包括線性插值、多重插補、熱平臺插補、拉格朗日插值、牛頓插值等。

線性插值法

使用插值法可以計算缺失值的估計值,所謂的插值法就是通過兩點 , 估計中間點的值。假設(shè)  是一條直線,通過已知的兩點來計算函數(shù) ,然后只要知道  就能求出 ,以此方法來估計缺失值。

.interpolate(method = 'linear', axis)方法將通過linear插值使用沿著給定axis的值替換 NaN 值,這個差值也就是前后或者上下的中間值

df_titanic['fare'].interpolate(method = 'linear', axis = 0)

同時,也可用行值插入

df_titanic['fare'].interpolate(method = 'linear', axis = 1)

多重插補(Multiple Imputation)

多值插補的思想來源于貝葉斯估計,認為待插補的值是隨機的,它的值來自于已觀測到的值。具體實踐上通常是估計出待插補的值,然后再加上不同的噪聲,形成多組可選插補值。根據(jù)某種選擇依據(jù),選取最合適的插補值。 多重插補方法分為三個步驟:

⑥ 啞變量填充。有另外一種非常有意思的填充方式,叫做『啞變量填充』,在變量為離散型,且不同值較少的情況下可以采用。以 Titanic 數(shù)據(jù)為例:

以下為參考代碼示例:

sex_list = ['MALE', 'FEMALE', np.NaN, 'FEMALE', 'FEMALE', np.NaN, 'MALE']
df = pd.DataFrame({'SEX': sex_list})
display(df)

df.fillna('NA', inplace=True)
df = pd.get_dummies(df['SEX'],prefix='IS_SEX')
display(df)
# 原始數(shù)據(jù)
SEX
0 MALE
1 FEMALE
2 NaN
3 FEMALE
4 FEMALE
5 NaN
6 MALE
# 填充后
IS_SEX_FEMALE IS_SEX_MALE IS_SEX_NA
0 0 1 0
1 1 0 0
2 0 0 1
3 1 0 0
4 1 0 0
5 0 0 1
6 0 1

當特征值缺失超過??以上,建議刪除〖或加入『是』『否』標記位信息〗,容易影響模型效果

df_titanic.drop(["deck"],axis=1)

2.3 異常值處理

數(shù)據(jù)質(zhì)量也會很大程度影響機器學習應(yīng)用效果,數(shù)據(jù)的錯誤值或異常值可能會造成測量誤差或異常系統(tǒng)條件的結(jié)果,給模型學習帶來很大的問題。實際我們很多時候會有異常值檢測與處理環(huán)節(jié),下面給大家做一個梳理。

(1) 異常檢測方法

① 基于統(tǒng)計分析。通常用戶用某個統(tǒng)計分布對數(shù)據(jù)點進行建模,再以假定的模型,根據(jù)點的分布來確定是否異常。如通過分析統(tǒng)計數(shù)據(jù)的散度情況,即數(shù)據(jù)變異指標,對數(shù)據(jù)的分布情況有所了解,進而通過數(shù)據(jù)變異指標來發(fā)現(xiàn)數(shù)據(jù)中的異常點數(shù)據(jù)。

常用的數(shù)據(jù)變異指標有極差、四分位數(shù)間距均差標準差、變異系數(shù)等等,如變異指標的值大表示變異大、散布廣;值小表示離差小,較密集。

比如,最大最小值可以用來判斷這個變量的取值是否超過了合理的范圍,如客戶的年齡為  歲或  歲,為異常值。

② 3σ原則。如果數(shù)據(jù)近似正態(tài)分布,在??原則下,異常值為一組測定值中與平均值的偏差超過??倍標準差的值。

如果數(shù)據(jù)服從正態(tài)分布,距離平均值  之外的值出現(xiàn)的概率為 ,屬于極個別的小概率事件。 如果數(shù)據(jù)不服從正態(tài)分布,也可以用遠離平均值的多少倍標準差來描述。

③ 箱線圖分析。大家還記得在數(shù)據(jù)分析部分有一個很有效的工具叫做箱線圖[6]。箱型圖判斷異常值的方法以四分位數(shù)和四分位距為基礎(chǔ),四分位數(shù)具有魯棒性,因此箱型圖識別異常值比較客觀,在識別異常值時有一定的優(yōu)越性。

箱線圖提供了識別異常值的一個標準:如果一個值小于  或大于 的值,則被稱為異常值。

sns.catplot(y="fare",x="survived", kind="box", data=df_titanic,palette="Set2")


④ 基于模型檢測
。我們也可以基于模型對異常值檢測?;舅悸肥窍冉⒁粋€數(shù)據(jù)模型,那些同模型不能完美擬合的對象就視作異常。如果模型是簇的集合,則異常是不顯著屬于任何簇的對象。在使用回歸模型時,異常是相對遠離預(yù)測值的對象。

⑤ 基于距離。我們還有基于距離的方法可以用于異常檢測。這類方法基于下面這個假設(shè):如果一個數(shù)據(jù)對象和大多數(shù)點距離都很遠,那這個對象就是異常。通過定義對象之間的臨近性度量,根據(jù)距離判斷異常對象是否遠離其他對象,主要使用的距離度量方法有絕對距離(曼哈頓距離)、歐氏距離和馬氏距離等方法。

⑥ 基于密度。一個很直接的異常檢測思路是基于分布密度來做。具體為:考察當前點周圍密度,局部異常點/離群點的局部密度顯著低于大部分近鄰點。這類方法適用于非均勻的數(shù)據(jù)集。

⑦ 基于聚類。我們可以基于聚類的方法進行異常檢測,遠離 cluster 的樣本更可能是異常值。

不過該方法會受到聚類 cluster 個數(shù)  的影響,一種策略是對于不同的簇個數(shù)重復(fù)該分析;另一種方法是找出大量小簇,其想法是較小的簇傾向于更加凝聚。如果存在大量小簇時一個對象是異常點,則它多半是一個真正的異常點。不利的一面是一組異常點可能形成小簇而逃避檢測。

⑧ 基于鄰近度的異常點檢測。同樣的,我們也有基于近鄰度的思路來做異常檢測,我們認為異常點遠離大部分的點。這種方法比統(tǒng)計學方法更一般、更容易使用,因為確定數(shù)據(jù)集的有意義的鄰近性度量比確定它的統(tǒng)計分布更容易。

一個對象的異常點得分由到它的  最近鄰的距離給定,所以異常點得分對  的取值高度敏感:

在數(shù)據(jù)處理階段將離群點作為影響數(shù)據(jù)質(zhì)量的異常點考慮,而不是作為通常所說的異常檢測目標點,一般采用較為簡單直觀的方法,結(jié)合箱線圖和 MAD 的統(tǒng)計方法判斷變量的離群點。如下為繪制散點圖根據(jù)分布直接判斷。

sns.scatterplot(x="fare", y="age", hue="survived",data=df_titanic,palette="Set1")

(2) 異常處理方法

對異常值處理,需要具體情況具體分析,異常值處理方法常用的有以下幾種:

3.特征構(gòu)建

前序的數(shù)據(jù)預(yù)處理過程能保證我們拿到干凈整齊準確的數(shù)據(jù),但這些數(shù)據(jù)未必對于建模是最有效的,下一步我們通常會進行特征構(gòu)建,結(jié)合業(yè)務(wù)場景產(chǎn)生衍生變量來提升數(shù)據(jù)表達能力和模型建模效果。

3.1 統(tǒng)計特征構(gòu)建

統(tǒng)計特征是一類非常有效的特征,尤其在時序問題場景中,以下為統(tǒng)計特征構(gòu)建的一些思考維度和方法:

回到Titanic數(shù)據(jù)集,我們來看看結(jié)合業(yè)務(wù)理解,我們可以做哪些新特征:

① 年齡處理。我們對年齡 age 字段進行進一步處理,考慮到不同的年齡段對應(yīng)的人群可能獲救概率不同,我們根據(jù)年齡值分成不同區(qū)間段,對應(yīng)到 child、young、midlife、old 等

def age_bin(x):
if x <= 18:
return 'child'
elif x <= 30:
return 'young'
elif x <= 55:
return 'midlife'
else:
return 'old'
df_titanic['age_bin'] = df_titanic['age'].map(age_bin)
df_titanic['age_bin'].unique()
執(zhí)行結(jié)果:
array(['young', 'midlife', 'child', 'old'], dtype=object)

② 抽取『稱呼』特征。 我們在 name 字段里,可以看到各種不同的稱呼,如『Mr』『Master』『Dr』等,這些稱呼體現(xiàn)了乘客的身份等信息,我們可以對其做抽取構(gòu)建新的特征。

# 提取稱呼
df_titanic['title'] = df_titanic['name'].map(lambda x: x.split(',')[1].split('.')[0].strip())

df_titanic['title'].value_counts()

執(zhí)行結(jié)果如下:

Mr              757
Miss 260
Mrs 197
Master 61
Rev 8
Dr 8
Col 4
Ms 2
Major 2
Mlle 2
Dona 1
Sir 1
Capt 1
Don 1
Lady 1
Mme 1
the Countess 1
Jonkheer 1

我們做一個簡單的『稱呼』統(tǒng)計

# 對稱呼細分,是官員,還是皇室,還是女士、先生、小姐
df_titanic['title'].unique()

執(zhí)行結(jié)果:

array(['Mr', 'Mrs', 'Miss', 'Master', 'Don', 'Rev', 'Dr', 'Mme', 'Ms',
'Major', 'Lady', 'Sir', 'Mlle', 'Col', 'Capt', 'the Countess',
'Jonkheer', 'Dona'], dtype=object)

下面我們對這些『稱呼』『稱謂』做一個規(guī)范化統(tǒng)一。

title_dictionary = {
"Mr": "Mr",
"Mrs": "Mrs",
"Miss": "Miss",
"Master": "Master",
"Don": "Royalty",
"Rev": "Officer",
"Dr": "Officer",
"Mme": "Mrs",
"Ms": "Mrs",
"Major": "Officer",
"Lady": "Royalty",
"Sir": "Royalty",
"Mlle": "Miss",
"Col": "Officer",
"Capt": "Officer",
"the Countess": "Royalty",
"Jonkheer": "Royalty",
"Dona": 'Mrs'
}
df_titanic['title'] = df_titanic['title'].map(title_dictionary)
df_titanic['title'].value_counts()

執(zhí)行結(jié)果如下:

Mr         757
Miss 262
Mrs 201
Master 61
Officer 23
Royalty 5

③ 抽取家庭規(guī)模。在 Titanic 上,有的成員之間有親屬關(guān)系,考慮到家族大小對于最終是否獲救也有影響,我們可以構(gòu)建一個?family_size?的特征,用于表征家庭規(guī)模。

df_titanic['family_size'] = df_titanic['sibsp'] + df_titanic['parch'] + 1
df_titanic['family_size'].head()

執(zhí)行結(jié)果如下:

0    2
1 2
2 1
3 2
4 1

3.2 周期值

在電商等場景下,數(shù)據(jù)有一定的周期規(guī)律,我們可以提取一些周期值作為有效信息。時序周期的一些考慮維度如下:

3.3 數(shù)據(jù)分桶

數(shù)據(jù)分桶,是對連續(xù)值屬性處理的一種常用方法,它指的是我們把連續(xù)數(shù)值切段,并把連續(xù)值歸屬到對應(yīng)的段中。數(shù)據(jù)分桶也叫做數(shù)據(jù)分箱或離散化。

① 等頻、等距分桶

(a) 自定義分箱。指根據(jù)業(yè)務(wù)經(jīng)驗或者常識等自行設(shè)定劃分的區(qū)間,然后將原始數(shù)據(jù)歸類到各個區(qū)間中。

(b) 等距分箱。按照相同寬度將數(shù)據(jù)分成幾等份。

從最小值到最大值之間,均分為  等份。如果 、 為最小最大值,則每個區(qū)間的長度為 ,區(qū)間邊界值為 、、、。

等距分箱只考慮邊界,每個等份里面的實例數(shù)量可能不等。等距分桶的缺點是受到異常值的影響比較大。

(c) 等頻分箱。將數(shù)據(jù)分成幾等份,每等份數(shù)據(jù)里面的個數(shù)是一樣的。

在等頻分箱中,區(qū)間的邊界值要經(jīng)過計算獲得,最終每個區(qū)間包含大致相等的實例數(shù)量。比如說 ,每個區(qū)間應(yīng)該包含大約  的實例。

數(shù)值變量分箱。我們先對船票價格做一個等頻切分(大家如果對船票價格進行分布繪圖,會發(fā)現(xiàn)是很長尾的分布,并不適合等距切分),看看分開的區(qū)間段。

# qcut 等頻率分箱
df_titanic['fare_bin'], bins = pd.qcut(df_titanic['fare'], 5, retbins=True)
df_titanic['fare_bin'].value_counts()

結(jié)果如下:

(7.854, 10.5]        184
(21.679, 39.688] 180
(-0.001, 7.854] 179
(39.688, 512.329] 176
(10.5, 21.679] 172
bins #array([ 0. , 7.8542, 10.5 , 21.6792, 39.6875, 512.3292])

下面根據(jù)區(qū)間段對其進行等頻切分

# 對船票fare進行分段分桶
def fare_cut(fare):
if fare <= 7.8958:
return 0
if fare <= 10.5:
return 1
if fare <= 21.6792:
return 2
if fare <= 39.6875:
return 3
return 4

df_titanic['fare_bin'] = df_titanic['fare'].map(fare_cut)

相比船票價格,年齡 age 字段的分布更加集中,且區(qū)間大小比較明確,我們采用等距切分,代碼如下:

# cut 等距離分箱
bins = [0, 12, 18, 65, 100]
pd.cut(df_titanic['age'], bins).value_counts

② Best-KS分桶。

實現(xiàn)步驟

③ 卡方分桶。自底向上的(即基于合并的)數(shù)據(jù)離散化方法,依賴于卡方檢驗:具有最小卡方值的相鄰區(qū)間合并在一起,直到滿足確定的停止準則。

基本思想:如果兩個相鄰的區(qū)間具有非常類似的類分布,則這兩個區(qū)間可以合并;否則,它們應(yīng)當保持分開。而低卡方值表明它們具有相似的類分布。

實現(xiàn)步驟

代碼實現(xiàn):https://github.com/Lantianzz/Scorecard-Bundle

④ 最小熵法分箱。還有最小熵分箱法,需要使總熵值達到最小,也就是使分箱能夠最大限度地區(qū)分因變量的各類別。

是信息論中數(shù)據(jù)無序程度的度量標準,提出信息熵的基本目的是找出某種符號系統(tǒng)的信息量和冗余度之間的關(guān)系,以便能用最小的成本和消耗來實現(xiàn)最高效率的數(shù)據(jù)存儲、管理和傳遞。

數(shù)據(jù)集的熵越低,說明數(shù)據(jù)之間的差異越小,最小熵劃分就是為了使每箱中的數(shù)據(jù)具有最好的相似性。給定箱的個數(shù),如果考慮所有可能的分箱情況,最小熵方法得到的箱應(yīng)該是具有最小熵的分箱。

3.4 特征組合

我們在有些場景下會考慮特征組合構(gòu)建強特征,如下為常用的特征組合構(gòu)建方式:(擴展閱讀:一文歸納Python特征生成方法(全))

  1. 離散+離散:構(gòu)建笛卡爾積(即兩兩組合『且』關(guān)系)。
  2. 離散+連續(xù):連續(xù)特征分桶后進行笛卡爾積或基于類別特征 group by 構(gòu)建統(tǒng)計特征。
  3. 連續(xù)+連續(xù):加減乘除,多項式特征,二階差分等。

多項式特征。針對連續(xù)值特征,我們對幾個特征構(gòu)建多項式特征,以達到特征組合與高階增強的作用。

在Titanic的例子中,如下為數(shù)值型特征:

df_titanic_numerical = df_titanic[['age','sibsp','parch','fare','family_size']]
df_titanic_numerical.head()

我們可以參考下述代碼構(gòu)建多項式特征

# 擴展數(shù)值特征
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures(degree=2, include_bias=False, interaction_only=False)
df_titanic_numerical_poly = poly.fit_transform(df_titanic_numerical)
pd.DataFrame(df_titanic_numerical_poly, columns=poly.get_feature_names()).head()

在構(gòu)建完成特征后,我們查看下衍生新特征變量的相關(guān)性情況,下面的熱力圖heatmap里顏色越深相關(guān)性越大:

sns.heatmap(pd.DataFrame(df_titanic_numerical_poly, columns=poly.get_feature_names()).corr())

4.特征變換

我們對于構(gòu)建完的特征,會做一些『特征變換』的操作,以適應(yīng)不同的模型,更好地完成建模。

4.1 標準化(Standardization)

標準化操作也稱作 Z-score 變換,它使數(shù)值特征列的算數(shù)平均為 ,方差(以及標準差)為 ,如圖所示。

注意:如果數(shù)值特征列中存在數(shù)值極大或極小的outlier(通過EDA發(fā)現(xiàn)),應(yīng)該使用更穩(wěn)健(robust)的統(tǒng)計數(shù)據(jù):用中位數(shù)而不是算術(shù)平均數(shù),用分位數(shù)(quantile)而不是方差。這種標準化方法有一個重要的參數(shù):(分位數(shù)下限,分位數(shù)上限),最好通過EDA的數(shù)據(jù)可視化確定。免疫outlier。

from sklearn.preprocessing import StandardScale
#標準化模型訓練
Stan_scaler = StandardScaler()
Stan_scaler.fit(x)
x_zscore = Stan_scaler.transform(x)
x_test_zscore = Stan_scaler.transform(x_test)
joblib.dump(Stan_scaler,'zscore.m') #寫入文件

4.2 歸一化(Normalization)

歸一化操作會基于向量模長調(diào)整數(shù)據(jù)幅度大小,但并不會改變原始數(shù)據(jù)的順序。如圖所示。

4.3 幅度縮放(scaling)

幅度縮放是為了讓不同特征的取值在大體一致的數(shù)量級和數(shù)據(jù)區(qū)間內(nèi),比較常用的方法是最大最小值縮放,如圖所示。

from sklearn import preprocessing
min_max_scaler = preprocessing.MinMaxScaler()
min_max_scaler.fit_transform(x)
x_minmax = min_max_scaler.transform(x)
x_test_minmax = min_max_scaler.transform(x_test)
joblib.dump(min_max_scaler,'min_max_scaler.m') #寫入文件

4.4 歸一化 VS 標準化

歸一化和標準化是兩個非常常見的特征變換操作,下面我們來對比一下標準化和歸一化:

它們分別的適用場景可以歸納總結(jié)如下

  1. 在分類、聚類算法中,需要使用距離來度量相似性的時候(如 SVM、KNN)或者使用 PCA 技術(shù)進行降維的時候,標準化(Z-score standardization)表現(xiàn)更好。

參考ShowMeAI教程 圖解機器學習算法:從入門到精通系列教程[7]

  1. 在不涉及距離度量、協(xié)方差計算、數(shù)據(jù)不符合正太分布的時候,可以使用第一種方法或其他歸一化方法。例如圖像處理時,將 RGB 圖像轉(zhuǎn)換為灰度圖像后將其值限定在  的范圍。
  2. 基于樹的模型(如隨機森林、GBDT、XGBoost、LightGBM等)不需要進行特征的歸一化。如果是基于參數(shù)的模型或者基于距離的模型(邏輯回歸、K-Means聚類、神經(jīng)網(wǎng)絡(luò)等),因為需要對參數(shù)或者距離進行計算,都需要進行歸一化。

具體模型參考ShowMeAI教程?圖解機器學習算法:從入門到精通系列教程[8]

4.5 非線性變換

我們在有些場景下,還會對數(shù)值字段進行分布調(diào)整或者校正,利用統(tǒng)計或數(shù)學變換來減輕數(shù)據(jù)分布傾斜的影響。使原本密集的區(qū)間的值盡可能的分散,原本分散的區(qū)間的值盡量的聚合。 大部分變換函數(shù)都屬于冪變換函數(shù)簇,主要作用是穩(wěn)定方差,保持分布接近于正態(tài)分布并使得數(shù)據(jù)與分布的平均值無關(guān)。我們來看看一些典型的非線性統(tǒng)計變換

① log變換。log 變換通常用來創(chuàng)建單調(diào)的數(shù)據(jù)變換。主要作用為穩(wěn)定方差,始終保持分布接近于正態(tài)分布并使得數(shù)據(jù)與分布的平均值無關(guān)。

log 變換屬于冪變換函數(shù)簇,數(shù)學表達式為

下面我們對 Titanic 數(shù)據(jù)集中的船票價格字段進行 log1p 變換,示例代碼如下:

sns.distplot(df_titanic.fare,kde=False)
df_titanic['fare_log'] = np.log((1+df_titanic['fare']))
sns.distplot(df_titanic.fare_log,kde=False)


② box-cox變換
。box-cox 變換是 box 和 cox 在1964年提出的一種廣義冪變換方法,是統(tǒng)計建模中常用的一種數(shù)據(jù)變換,用于連續(xù)的響應(yīng)變量不滿足正態(tài)分布的情況。box-cox 變換之后,可以一定程度上減小不可觀測的誤差和預(yù)測變量的相關(guān)性。

box-cox 變換的主要特點是引入一個參數(shù),通過數(shù)據(jù)本身估計該參數(shù)進而確定應(yīng)采取的數(shù)據(jù)變換形式,box-cox 變換可以明顯地改善數(shù)據(jù)的正態(tài)性、對稱性和方差相等性,對許多實際數(shù)據(jù)都是行之有效的。

box-cox 變換函數(shù)數(shù)學表達式如下:

生成的變換后的輸出 ,是輸入  和變換參數(shù)的函數(shù);當  時,該變換就是自然對數(shù) log 變換,前面我們已經(jīng)提到過了。 的最佳取值通常由最大似然或最大對數(shù)似然確定。

下面我們對Titanic數(shù)據(jù)集中的船票價格字段進行 box-cox 變換,示例代碼如下:

# 從數(shù)據(jù)分布中移除非零值
fare_positive_value = df_titanic[(~df_titanic['fare'].isnull()) & (df_titanic['fare']>0)]['fare']
import scipy.stats as spstats
# 計算最佳λ值
l, opt_lambda = spstats.boxcox(fare_positive_value)
print('Optimal lambda value:', opt_lambda) # -0.5239075895755266
# 進行 Box-Cox 變換
fare_boxcox_lambda_opt = spstats.boxcox(df_titanic[df_titanic['fare']>0]['fare'],lmbda=opt_lambda)
sns.distplot(fare_boxcox_lambda_opt,kde=Fal

4.6 離散變量處理

對于類別型的字段特征(比如顏色、類型、好壞程度),有很多模型并不能直接處理,我們對其進行編碼后能更好地呈現(xiàn)信息和支撐模型學習。有以下常見的類別型變量編碼方式:

① 標簽編碼(label encoding)。標簽編碼(label encoding)是最常見的類別型數(shù)據(jù)編碼方式之一,編碼值介于??和 n_classes-1 之間的標簽。例如:比如有?我們把其轉(zhuǎn)換為?。

from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
le.fit(["超一線", "一線", "二線", "三線"])
print('特征:{}'.format(list(le.classes_)))
# 輸出 特征:['一線', '三線', '二線', '超一線']
print('轉(zhuǎn)換標簽值:{}'.format(le.transform(["超一線", "一線", "二線"])))
# 輸出 轉(zhuǎn)換標簽值:array([3 0 2]...)
print('特征標簽值反轉(zhuǎn):{}'.format(list(le.inverse_transform([2, 2, 1]))))
# 輸出 特征標簽值反轉(zhuǎn):['二線', '二線', '三線

② 獨熱向量編碼(one hot encoding)。獨熱編碼通常用于處理類別間不具有大小關(guān)系的特征。例如:特征:血型,一共有四種類別?,采用獨熱編碼后,會把血型變成有一個4維的稀疏向量(最終生成的稀疏向量的維度,和類別數(shù)相同):

如果借助于pandas工具庫(查看ShowMeAI的?數(shù)據(jù)分析系列教程[9]?和?數(shù)據(jù)科學工具速查 | Pandas使用指南[10]?進行詳細了解),獨熱向量編碼的 Python 代碼參考示例如下:

sex_list = ['MALE', 'FEMALE', np.NaN, 'FEMALE', 'FEMALE', np.NaN, 'MALE']
df = pd.DataFrame({'SEX': sex_list})
display(df)
df.fillna('NA', inplace=True)
df = pd.get_dummies(df['SEX'],prefix='IS_SEX')
display(df)

最終變換前后的結(jié)果如下:

# 原始數(shù)據(jù)
SEX
0 MALE
1 FEMALE
2 NaN
3 FEMALE
4 FEMALE
5 NaN
6 MALE

# 獨熱向量編碼后
IS_SEX_FEMALE IS_SEX_MALE IS_SEX_NA
0 0 1 0
1 1 0 0
2 0 0 1
3 1 0 0
4 1 0 0
5 0 0 1

下面我們對’sex’, ‘class’, ‘pclass’, ’embarked’, ‘who’, ‘family_size’, ‘age_bin’這些字段都進行獨熱向量編碼。

pd.get_dummies(df_titanic, columns=['sex', 'class', 'pclass', 'embarked', 'who', 'family_size', 'age_bin'],drop_first=True)

當然,我們也可以借助SKLearn(查看ShowMeAI教程?SKLearn最全應(yīng)用指南?和?AI建模工具速查 | Scikit-learn使用指南?詳細學習),進行獨熱向量編碼實現(xiàn):

import numpy as np
from sklearn.preprocessing import OneHotEncoder
# 非負整數(shù)表示的標簽列表
labels = [0,1,0,2]
# 行向量轉(zhuǎn)列向量
labels = np.array(labels).reshape(len(labels), -1)
# 獨熱向量編碼
enc = OneHotEncoder()
enc.fit(labels)
targets = enc.transform(labels).toarray()
# 如果不加 toarray() 的話,輸出的是稀疏的存儲格式,即索引加值的形式,也可以通過參數(shù)指定 sparse = False 來達到同樣的效果

輸出結(jié)果如下:

array([[ 1.,  0.,  0.],
[ 0., 1., 0.],
[ 1., 0., 0.],
[ 0., 0., 1.]])


③ 標簽二值化(LabelBinarizer)
。功能與 OneHotEncoder 一樣,但是 OneHotEncoder 只能對數(shù)值型變量二值化,無法直接對字符串型的類別變量編碼,而 LabelBinarizer 可以直接對字符型變量二值化。

from sklearn.preprocessing import LabelBinarizer
lb=LabelBinarizer()
labelList=['yes', 'no', 'no', 'yes','no2']
# 將標簽矩陣二值化
dummY=lb.fit_transform(labelList)
print("dummY:",dummY)
# 逆過程
yesORno=lb.inverse_transform(dummY)
print("yesOrno:",yesORno)

輸出如下:

dummY: [[0 0 1]
[1 0 0]
[1 0 0]
[0 0 1]
[0 1 0]]
yesOrno: ['yes' 'no' 'no' 'yes' 'no2']

4.7 降維

在實際的機器學習項目中,我們可能還會做降維[11]處理,主要因為數(shù)據(jù)存在以下幾個問題:

通過特征降維希望達到的目的:減少特征屬性的個數(shù),確保特征屬性之間是相互獨立的。

常用的降維方法有:PCA、SVD、LDA、T-sne等非線性降維。

這里降維的講解,我們給大家基于 iris 數(shù)據(jù)集講解:

from sklearn import datasets

iris_data = datasets.load_iris()

X = iris_data.data
y = iris_data.target

def draw_result(X, y):
plt.figure()
# 提取 Iris-setosa
setosa = X[y == 0]
# 繪制點:參數(shù) 1 x 向量,y 向量
plt.scatter(setosa[:, 0], setosa[:, 1], color="red", label="Iris-setosa")

versicolor = X[y == 1]
plt.scatter(versicolor[:, 0], versicolor[:, 1], color="orange", label="Iris-versicolor")

virginica = X[y == 2]
plt.scatter(virginica[:, 0], virginica[:, 1], color="blue", label="Iris-virginica")

plt.legend()
plt.show()

draw_result(X, y)

① PCA(Principal Component Analysis)。關(guān)于PCA主成分分析降維算法,大家可以查閱ShowMeAI文章?圖解機器學習 | 降維算法詳解[12]?進行詳細學習。

② SVD(Singular Value Decomposition)

SVD方法的主要步驟如下:

所以??是??特征值分解的特征向量按列組成的正交矩陣,??是??特征值組成的對角矩陣,也可以看出??的奇異值??是??特征值??的平方根。

假如  的特征向量為 , 中對應(yīng)的  則可以由下式求出:

也即奇異值分解的關(guān)鍵在于對??進行特征值分解。

from sklearn.decomposition import TruncatedSVD
iris_2d = TruncatedSVD(2).fit_transform(X)
draw_result(iris_2d, y)

PCA VS SVD

PCA求解關(guān)鍵在于求解協(xié)方差矩陣  的特征值分解。

SVD關(guān)鍵在于  的特征值分解。

很明顯二者所解決的問題非常相似,都是對一個實對稱矩陣進行特征值分解,如果取:

則有:

此時SVD與PCA等價,所以PCA問題可以轉(zhuǎn)化為SVD問題求解。

③ ?LDA(Linear Discriminant Analysis)。是有監(jiān)督的降維,通過最小化類內(nèi)離散度與最大化類間離散度來獲得最優(yōu)特征子集。

上圖解讀:LD1通過線性判定,可以很好的將呈正態(tài)分布的兩個類分開。LD2的線性判定保持了數(shù)據(jù)集的較大方差,但LD2無法提供關(guān)于類別的信息,因此LD2不是一個好的線性判定。

from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
lda = LDA(n_components=2)
iris_2d = lda.fit_transform(X, y)
draw_result(iris_2d, y)

LDA VS PCA

PCA 試圖尋找到方差最大的正交的主成分分量軸 LDA 發(fā)現(xiàn)可以最優(yōu)化分類的特征子空間 LDA 和 PCA 都是可用于降低數(shù)據(jù)集維度的線性轉(zhuǎn)換技巧 PCA 是無監(jiān)督算法 LDA 是監(jiān)督算法 LDA 是一種更優(yōu)越的用于分類的特征提取技術(shù)

④ ?T-SNE。T-SNE(t-distributed stochastic neighbor embedding)是一種非線性降維方法:

from sklearn.manifold import TSNE
tsne = TSNE(n_components=2)
iris_2d = tsne.fit_transform(X)
draw_result(iris_2d, y)

5.特征選擇

特征選擇是在建模過程中經(jīng)常會用到的一個處理,也有重要意義:

總體來說,進行特征選擇有2個主要考慮方向:

對特征選擇的方法進行歸類,又大體可以歸納為下述3種:

5.1 過濾式Filter

① 方差過濾。這是通過特征本身的方差來篩選特征的類。比如一個特征本身的方差很小,就表示樣本在這個特征上基本沒有差異,可能特征中的大多數(shù)值都一樣,甚至整個特征的取值都相同,那這個特征對于樣本區(qū)分沒有什么作用。

我們會剔除掉方差非常小的字段特征,參考代碼實現(xiàn)如下:

from sklearn.feature_selection import VarianceThreshold
variancethreshold = VarianceThreshold() #實例化,默認方差為 0.方差<=0 的過濾掉
df_titanic_numerical = df_titanic[['age','sibsp','parch','fare','family_size']]
X_var = variancethreshold.fit_transform(df_titanic_numerical) #獲取刪除不合格特征后的新特征矩陣
del_list = df_titanic_numerical.columns[variancethreshold.get_support()==0].to_list() #獲得刪除


② 卡方過濾
??ǚ綑z驗,專用于分類算法,捕捉相關(guān)性,追求p小于顯著性水平的特征??ǚ竭^濾是專門針對離散型標簽(即分類問題)的相關(guān)性過濾。

p值和取到這一個統(tǒng)計量的概率取值其實是正相關(guān)的:?值越大,取到這個統(tǒng)計量的概率就越大,即越合理;?值越小,取到這個統(tǒng)計量的概率就越小,即越不合理,此時應(yīng)該拒絕原假設(shè),接收備擇假設(shè)。

df_titanic_categorical = df_titanic[['sex', 'class', 'embarked', 'who',  'age_bin','adult_male','alone','fare_bin']]
df_titanic_numerical = df_titanic[['age','sibsp','parch','fare','family_size','pclass']]
df_titanic_categorical_one_hot = pd.get_dummies(df_titanic_categorical, columns=['sex', 'class', 'embarked', 'who', 'age_bin','adult_male','alone','fare_bin'], drop_first=True)
df_titanic_combined = pd.concat([df_titanic_numerical,df_titanic_categorical_one_hot],axis=1)

y = df_titanic['survived']
X = df_titanic_combined.iloc[:,1:]

from sklearn.feature_selection import chi2
from sklearn.feature_selection import SelectKBest
chi_value, p_value = chi2(X,y)
#根據(jù) p 值,得出 k 值
k = chi_value.shape[0] - (p_value > 0.05).sum() #要保留的特征的數(shù)量 14
#根據(jù)卡方值,選擇前幾特征,篩選后特征
X_chi = SelectKBest(chi2, k=14).fit_transform(X, y)

③ F檢驗。?檢驗捕捉線性相關(guān)性,要求數(shù)據(jù)服從正態(tài)分布,追求??值小于顯著性水平特征。

from sklearn.feature_selection import f_classif
f_value, p_value = f_classif(X,y)
#根據(jù) p 值,得出 k 值
k = f_value.shape[0] - (p_value > 0.05).sum()
#篩選后特征
X_classif = SelectKBest(f_classif, k=14).fit_transform(X, y)


④ 互信息法
?;バ畔⒎ㄊ怯脕聿蹲矫總€特征與標簽之間的任意關(guān)系(包括線性和非線性關(guān)系)的過濾方法。

from sklearn.feature_selection import mutual_info_classif as MIC
#互信息法
mic_result = MIC(X,y) #互信息量估計
k = mic_result.shape[0] - sum(mic_result <= 0) #16
X_mic = SelectKBest(MIC, k=16).fit_transform(X, y)

5.2 包裹式Wrapper

① 歸特征刪除法。遞歸消除刪除法使用一個基模型來進行多輪訓練,每輪訓練后,消除若干權(quán)值系數(shù)的特征,再基于新的特征集進行下一輪訓練。使用feature_selection?庫的 RFE 類來選擇特征的代碼如下:

from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression
#遞歸特征消除法,返回特征選擇后的數(shù)據(jù)
#參數(shù) estimator 為基模型
#參數(shù) n_features_to_select 為選擇的特征個數(shù)
X_ref = RFE(estimator=LogisticRegression(), n_features_to_select=10).fit_transform(X, y)

② 特征重要性評估。我們基于一些模型(如各類樹模型)可以得到特征重要度,進而進行篩選

from sklearn.ensemble import ExtraTreesClassifier
# 建模與獲取特征重要度
model = ExtraTreesClassifier()
model.fit(X, y)
print(model.feature_importances_)

# 特征重要度排序
feature=list(zip(X.columns,model.feature_importances_))
feature=pd.DataFrame(feature,columns=['feature','importances'])
feature.sort_values(by='importances',ascending=False).head(20)


③ 排列重要性評估
。我們還有一類方法可以評估特征重要度,進而進行篩選,叫作排列重要度。

原理:在訓練機器學習模型之后計算置換重要性。這種方法在向模型提出假設(shè),如果在保留目標和所有其他列的同時隨機打亂一列驗證集特征數(shù)據(jù),對預(yù)測機器學習模型的準確性的影響程度。對于一個具有高度重要性的特征,random-reshuffle 會對機器學習模型預(yù)測的準確性造成更大的損害。

優(yōu)點:快速計算;易于使用和理解;特征重要性度量的屬性;追求特征穩(wěn)定性。

參考代碼實現(xiàn)如下:

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
import eli5
from eli5.sklearn import PermutationImportance
my_model = RandomForestClassifier(random_state=0).fit(train_X, train_y)
perm = PermutationImportance(my_model, random_state=1).fit(val_X, val_y)
eli5.show_weights(perm, feature_names = val_X.columns.tolist())

5.3 嵌入式Embedded

① 基于懲罰項的特征選擇法。使用帶懲罰項的基模型,除了篩選出特征外,同時也進行了降維。

使用feature_selection庫的SelectFromModel類結(jié)合帶 L1 懲罰項的邏輯回歸模型,來選擇特征的代碼如下:

from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
#帶 L1 和 L2 懲罰項的邏輯回歸作為基模型的特征選擇,這個設(shè)置帶 L1 懲罰項的邏輯回歸作為基模型的特征選擇
lr = LogisticRegression(solver='liblinear',penalty="l1", C=0.1)
X_sfm = SelectFromModel(lr).fit_transform(X, y)
X_sfm.shape
(891, 7

使用 feature_selection 庫的 SelectFromModel 類結(jié)合 SVM 模型,來選擇特征的代碼如下:

from sklearn.feature_selection import SelectFromModel
from sklearn.svm import LinearSVC
lsvc = LinearSVC(C=0.01,penalty='l1',dual=False).fit(X, y)
model = SelectFromModel(lsvc,prefit=True)
X_sfm_svm = model.transform(X)
X_sfm_svm.shape
(891, 7

② 基于樹模型。樹模型中 GBDT 也可用來作為基模型進行特征選擇,使用 feature_selection 庫的 SelectFromModel 類結(jié)合 GBDT 模型,來選擇特征的代碼如下:

from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import GradientBoostingClassifier
#GBDT 作為基模型的特征選擇
gbdt = GradientBoostingClassifier()
X_sfm_gbdt = SelectFromModel(gbdt).fit_transform(X, y)

5.4 特征選擇總結(jié)

關(guān)于特征選擇,做一個經(jīng)驗總結(jié),如下:

  1. 類別型特征變量,那么可以從SelectKBest開始,用卡方或者基于樹的選擇器來選擇變量;
  2. 定量特征變量,可以直接用線性模型和基于相關(guān)性的選擇器來選擇變量;
  3. 二分類問題,可以考慮使用SelectFromModel和SVC;
  4. 特征選擇前,要充分了解數(shù)據(jù),一般需要做探索性數(shù)據(jù)分析EDA。

6.特征工程實戰(zhàn)建議

最后,ShowMeAI結(jié)合實際工業(yè)應(yīng)用經(jīng)驗,總結(jié)一些特征工程要點:

6.1 數(shù)據(jù)理解

構(gòu)建特征的有效性,和業(yè)務(wù)及數(shù)據(jù)分布強相關(guān),因此建議在此步驟之前做EDA探索性數(shù)據(jù)分析來充分理解數(shù)據(jù)。

可以參考ShowMeAI文章?Python機器學習綜合項目-電商銷量預(yù)估[13]?和?Python機器學習綜合項目-電商銷量預(yù)估<進階>[14]?了解EDA的基本過程和方法。

6.2 數(shù)據(jù)預(yù)處理

我們可能會做的一些數(shù)據(jù)預(yù)處理與特征處理如下:

① 連續(xù)特征離散化

② 數(shù)值截斷

6.3 數(shù)據(jù)清洗

結(jié)合業(yè)務(wù)場景和數(shù)據(jù)分布,進行合理的缺失值、異常值處理。

6.4 特征構(gòu)建與變換

建議不要上來就做PCA或LDA降維,最好先構(gòu)建特征并對特征做篩選。

① 線性組合(linear combination)

  • 適用于決策樹以及基于決策樹的ensemble(如gradient boosting,random forest),因為常見的 axis-aligned split function 不擅長捕獲不同特征之間的相關(guān)性;不適用于SVM、線性回歸、神經(jīng)網(wǎng)絡(luò)等。
  • ② 類別特征與數(shù)值特征的組合
  • 用 N1 和 N2 表示數(shù)值特征,用 C1 和 C2 表示類別特征,利用 pandas 的 groupby 操作,可以創(chuàng)造出以下幾種有意義的新特征:(其中,C2還可以是離散化了的 N1)
  • median(N1)_by(C1)   中位數(shù)
    mean(N1)_by(C1) 算術(shù)平均數(shù)
    mode(N1)_by(C1) 眾數(shù)
    min(N1)_by(C1) 最小值
    max(N1)_by(C1) 最大值
    std(N1)_by(C1) 標準差
    var(N1)_by(C1) 方差
    freq(C2)_by(C1) 頻數(shù)


    ③ 統(tǒng)計特征+線性組合

    N1 - median(N1)_by(C1)
    N1 - mean(N1)_by(C1)

    ④ 基于樹模型創(chuàng)造新特征

    在 Scikit-Learn 和 XGBoost 里,可以基于 apply() 以及 decision_path() 等方法實現(xiàn)。

    6.5 模型

    我們在不同類型的模型里,也會考慮不同的特征工程方法:

    ① 樹模型

    ② 依賴樣本距離的模型

    文章轉(zhuǎn)自微信公眾號@算法進階

    上一篇:

    Python數(shù)據(jù)分析指南(全)

    下一篇:

    吳恩達:機器學習的6個核心算法
    #你可能也喜歡這些API文章!

    我們有何不同?

    API服務(wù)商零注冊

    多API并行試用

    數(shù)據(jù)驅(qū)動選型,提升決策效率

    查看全部API→
    ??

    熱門場景實測,選對API

    #AI文本生成大模型API

    對比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力

    25個渠道
    一鍵對比試用API 限時免費

    #AI深度推理大模型API

    對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

    10個渠道
    一鍵對比試用API 限時免費