特征工程系列:聚合特征構造以及轉換特征構造


特征工程系列:聚合特征構造以及轉換特征構造

本文為數據茶水間群友原創,經授權在本公眾號發表。

關於作者:JunLiang,一個熱愛挖掘的數據從業者,勤學好問、動手達人,期待與大家一起交流探討機器學習相關內容~

0x00 前言

數據和特征決定了機器學習的上限,而模型和算法只是逼近這個上限而已。由此可見,特征工程在機器學習中占有相當重要的地位。在實際應用當中,可以說特征工程是機器學習成功的關鍵。

那特征工程是什么?

特征工程是利用數據領域的相關知識來創建能夠使機器學習算法達到最佳性能的特征的過程。

特征工程又包含了 Data PreProcessing(數據預處理)、Feature Extraction(特征提取)、Feature Selection(特征選擇)和 Feature construction(特征構造)等子問題,本章內容主要討論特征構造的方法。

 

 

創造新的特征是一件十分困難的事情,需要豐富的專業知識和大量的時間。機器學習應用的本質基本上就是特征工程。
——Andrew Ng

0x01 特征構造介紹

特征構造意味着從現有的數據中構造額外特征,這些特征通常分布在多張相關的表中。特征構造需要從數據中提取相關信息並將其存入單張表格中,然后被用來訓練機器學習模型。這需要我們花大量的時間去研究真實的數據樣本,思考問題的潛在形式和數據結構,同時能夠更好地應用到預測模型中。

特征構建需要很強的洞察力和分析能力,要求我們能夠從原始數據中找出一些具有物理意義的特征。對於表格數據,特征構建意味着將特征進行混合或組合以得到新的特征,或通過對特征進行分解或切分來構造新的特征;對於文本數據,特征夠自己按意味着設計出針對特定問題的文本指標;對於圖像數據,這意味着自動過濾,得到相關的結構。

特征構造是一個非常耗時的過程,因為每個新的特征通常需要幾步才能構造,特別是當使用多張表的信息時。我們可以將特征構造的操作分為兩類:“轉換”和“聚合”。

以下將介紹聚合特征構造以及簡單變換特征構造的方法。

 

0x02 聚合特征構造

通常基於 id 值(用戶id、商品id等)或類別特征的某個類別計算數值特征的一些統計量,一般在多個表好操作一些。

用 N1 和 N2 表示數值特征,用C1和C2表示類別特征(C2還可以是連續值特征離散化后的取值),利用 pandas 的 groupby 操作,可以創造出以下幾種有意義的新特征:

display(df.head(10))
# 輸出
C1 C2 N1 N2
0 A a 1 1.1
1 A a 1 2.2
2 A a 2 3.3
3 B a 2 4.4
4 B a 3 5.5
5 C b 3 6.6
6 C b 4 7.7
7 C b 4 8.8
8 D b 5 9.9
9 D b 5 10.0

1.分組統計特征

1)分組統計中位數

median(N1)_by(C1)

例子:不同公司職員工資的中位數。

df.groupby(['C1']).agg({'N1': 'median'})
# 輸出
N1
C1
A 1.0
B 2.5
C 4.0
D 5.0

2)分組統計算術平均數

mean(N1)_by(C1)

例子:顧客平均每次的購買金額。

df.groupby(['C1']).agg({'N1': 'mean'})
# 輸出
N1
C1
A 1.333333
B 2.500000
C 3.666667
D 5.000000

3)分組統計眾數

mode(N1)_by(C1)

例子:購買商品類型的眾數。

df.groupby(['C1'])['N1'].agg(lambda x: stats.mode(x)[0][0])
# 輸出
C1
A 1
B 2
C 4
D 5

4)分組統計最小值

min(N1)_by(C1)

例子:購買行為至今天數最小值(最近一次購買至今天數)。

df.groupby(['C1']).agg({'N1': 'min'})
# 輸出
N1
C1
A 1
B 2
C 3
D 5

5)分組統計最大值

max(N1)_by(C1)

例子:理財用戶的歷史最大在投金額。

df.groupby(['C1']).agg({'N1': 'max'})
# 輸出
N1
C1
A 2
B 3
C 4
D 5

6)分組統計標准差

std(N1)_by(C1)

df.groupby(['C1']).agg({'N1': 'std'})
# 輸出
N1
C1
A 0.577350
B 0.707107
C 0.577350
D 0.000000

7)分組統計方差

var(N1)_by(C1)

df.groupby(['C1']).agg({'N1': 'var'})
# 輸出
N1
C1
A 0.333333
B 0.500000
C 0.333333
D 0.000000

8)分組統計頻數

freq(C2)_by(C1)

例子:每個月購買商品次數。

df.groupby(['C1']).agg({'C2': 'count'})
# 輸出
C2
C1
A 3
B 2
C 3
D 2

僅僅將已有的類別和數值特征進行以上的有效組合,就能夠大量增加優秀的可用特征。

2.統計頻數構造特征

freq(C1) ,直接統計類別特征的頻數,這個不需要 groupby 也有意義。

df['C1'].count()
# 輸出:10

3.分組統計和基礎特征工程方法結合

將這種方法和線性組合等基礎特征工程方法結合(僅用於決策樹),可以得到更多有意義的特征,例如:

中位數分組和線性組合結合

  • N1 + median(N1)_by(C1)

  • N1 - median(N1)_by(C1)

  • N1 * median(N1)_by(C1)

  • N1 / median(N1)_by(C1)

df = pd.merge(df, df.groupby(['C1'])['N1'].median().reset_index().rename(columns={'N1': 'N1_Median'}),
on='C1', how='left')
df['N1+Median(C1)'] = df['N1'] + df['N1_Median']
df['N1-Median(C1)'] = df['N1'] - df['N1_Median']
df['N1*Median(C1)'] = df['N1'] * df['N1_Median']
df['N1/Median(C1)'] = df['N1'] / df['N1_Median']
display(df.head(20))
# 輸出:
C1 C2 N1 N2 N1_Median N1+Median(C1) N1-Median(C1) N1*Median(C1) N1/Median(C1)
0 A a 1 1.1 1.0 2.0 0.0 1.0 1.00
1 A a 1 2.2 1.0 2.0 0.0 1.0 1.00
2 A a 2 3.3 1.0 3.0 1.0 2.0 2.00
3 B a 2 4.4 2.5 4.5 -0.5 5.0 0.80
4 B a 3 5.5 2.5 5.5 0.5 7.5 1.20
5 C b 3 6.6 4.0 7.0 -1.0 12.0 0.75
6 C b 4 7.7 4.0 8.0 0.0 16.0 1.00
7 C b 4 8.8 4.0 8.0 0.0 16.0 1.00
8 D b 5 9.9 5.0 10.0 0.0 25.0 1.00
9 D b 5 10.0 5.0 10.0 0.0 25.0 1.00

均值分組和線性組合結合

  • N1 + mean(N1)_by(C1)

  • N1 - mean(N1)_by(C1)

  • N1 * mean(N1)_by(C1)

  • N1 / mean(N1)_by(C1)

df = pd.merge(df, df.groupby(['C1'])['N1'].mean().reset_index().rename(columns={'N1': 'N1_Mean'}),
on='C1', how='left')
df['N1+Mean(C1)'] = df['N1'] + df['N1_Mean']
df['N1-Mean(C1)'] = df['N1'] - df['N1_Mean']
df['N1*Mean(C1)'] = df['N1'] * df['N1_Mean']
df['N1/Mean(C1)'] = df['N1'] / df['N1_Mean']
display(df.head(20))
# 輸出:
C1 C2 N1 N2 N1_Mean N1+Mean(C1) N1-Mean(C1) N1*Mean(C1) N1/Mean(C1)
0 A a 1 1.1 1.333333 2.333333 -0.333333 1.333333 0.750000
1 A a 1 2.2 1.333333 2.333333 -0.333333 1.333333 0.750000
2 A a 2 3.3 1.333333 3.333333 0.666667 2.666667 1.500000
3 B a 2 4.4 2.500000 4.500000 -0.500000 5.000000 0.800000
4 B a 3 5.5 2.500000 5.500000 0.500000 7.500000 1.200000
5 C b 3 6.6 3.666667 6.666667 -0.666667 11.000000 0.818182
6 C b 4 7.7 3.666667 7.666667 0.333333 14.666667 1.090909
7 C b 4 8.8 3.666667 7.666667 0.333333 14.666667 1.090909
8 D b 5 9.9 5.000000 10.000000 0.000000 25.000000 1.000000
9 D b 5 10.0 5.000000 10.000000 0.000000 25.000000 1.000000

0x03 簡單轉換特征構造

1.單列特征加/減/乘/除一個常數

對於創造新的有用特征毫無用處;只能作為對已有特征的處理。

程序實現

df['Feature'] = df['Feature'] + n
df['Feature'] = df['Feature'] - n
df['Feature'] = df['Feature'] * n
df['Feature'] = df['Feature'] / n

2.單列特征單調變換

如果 u(x1, y1) > u(x2, y2),則 v(x1, y1) = f(u(x1, y1)) > v(x2, y2)=f(u(x2, y2)) ,那么 f() 就是(正)單調變化V是U的單調變換。設u為效用函數,f(u) 是其單調變換。

例子:冪變換

適用范圍:不適用於決策樹類算法。

程序實現

import numpy as np
# 計算n次方
df['Feature'] = df['Feature']**2
# 計算log變換
df['Feature'] = np.log(df['Feature'])

3.線性組合(linear combination)

  • [A X B]:

    將兩個特征的值相乘形成的特征組合;

  • [A x B x C x D x E]:

    將五個特征的值相乘形成的特征組合;

  • [A x A]:

    對單個特征的值求平方形成的特征組合。

借助特征組合,線性學習器可以很好擴展到大量數據,並有助於構建復雜模型解決非線性問題。

適用場景:僅適用於決策樹以及基於決策樹的 ensemble 算法,因為常見的 axis-aligned split function 不擅長捕獲不同特征之間的相關性;不適用於 SVM 、線性回歸、神經網絡等。

程序實現

df['Feature'] = df['A'] * df['B']
df['Feature'] = df['A'] * df['B'] * df['C'] * df['D'] * df['E']
df['Feature'] = df['A'] * df['A']

4.多項式特征(polynomial feature)

當兩個變量各自與 y 的關系並不強時候,把它們結合成為一個新的變量可能更會容易體現出它們與 y 的關系。

特征a和特征b的多項式輸出是:[1, a, b, a^2, ab, b^2]或者[1, a, b, ab]。

程序實現

import numpy as np
from sklearn.preprocessing import PolynomialFeatures
X = np.arange(6).reshape(3, 2)
print(X)
# 輸出:array([[0, 1],
[2, 3],
[4, 5]])

# 設置多項式階數為2
poly = PolynomialFeatures(2)
print(poly.fit_transform(X))
# 輸出:array([[ 1., 0., 1., 0., 0., 1.],
[ 1., 2., 3., 4., 6., 9.],
[ 1., 4., 5., 16., 20., 25.]])

#默認的階數是2,同時設置交互關系為true
poly = PolynomialFeatures(interaction_only=True)
print(poly.fit_transform(X))
# 輸出:array([[ 1., 0., 1., 0.],
[ 1., 2., 3., 6.],
[ 1., 4., 5., 20.]])

5.比例特征(ratio feature)

計算兩個特征的數值比例:X1/X2。

例子:購物車轉化比特征。

程序實現

df['Feature'] = df['X1']/df['X2']

6.絕對值特征(absolute value)

計算特征值的絕對值:|X|。

例子:某數據的相關系數特征。

程序實現

import numpy as np
df['Feature'] = np.abs(df['Feature'])

7.最大值特征

max(X1, X2)

例子:最近兩個月的最大購買金額。

程序實現

# 最大值
df['Feature'] = df.apply(lambda x: max(x['X1'], x['X2']), axis=1)

8.最小值特征

min(X1, X2)

例子:公司地址和宿舍地址距離商業中心的最小距離。

程序實現

# 最小值
df['Feature'] = df.apply(lambda x: min(x['X1'], x['X2']), axis=1)

9.排名編碼特征

按特征值對全體樣本進行排序,以排序序號作為特征。這種特征對異常點不敏感,不會導致特征值沖突。

例子:廣告歷史曝光量排名。

程序實現

X = [10, 9, 9, 8, 7]
df = pd.DataFrame({'X': X,})
df['num'] = df['X'].rank(ascending=0, method='dense')
display(df.head())
# 輸出
X num
0 10 1.0
1 9 2.0
2 9 2.0
3 8 3.0
4 7 4.0

10.異或值特征

計算兩特征的異或值:X1 xor X2。

實際應用中也可以先進行二值化,然后再進行異或運算。

程序實現

# 按位進行異或運算
df['Feature'] = df.apply(lambda x: x['X1'] ^ x['X2'], axis=1)

0x0FF 總結

特征構造是一個非常耗時的過程,因為每個新的特征通常需要幾步才能構造,特別是當使用多張表的信息時。我們可以將特征構造的操作分為兩類:“轉換”和“聚合”。

很多機器學習比賽都是直接給出了訓練集(特征+類標),我們可以對給出的特征進行“轉換”操作,構造更多的特征。而在實際的工作中,很多時候我們都沒有現成的特征,需要自己進行“聚合”操作從多個原始數據表中構造出模型所需要的特征。

例如,用戶行為數據表中每條記錄為某個用戶的一次瀏覽行為或一次點擊行為,我們需要通過“聚合”操作構造出用戶的行為特征(如:用戶最近一次瀏覽的時長、用戶最近一次登錄的點擊次數等特征),然后再使用“轉換”操作來構造更多特征,最后再使用這些特征訓練模型。

預告:下一篇文章將介紹笛卡爾乘積特征構造以及遺傳編程特征構造。

參考文獻

[1] https://machinelearning-notes.readthedocs.io/zh_CN/latest/feature/%E7%89%B9%E5%BE%81%E5%B7%A5%E7%A8%8B%E2%80%94%E2%80%94%E6%97%B6%E9%97%B4.html
[2] https://www.cnblogs.com/nxf-rabbit75/p/11141944.html#_nav_12
[3] https://gplearn.readthedocs.io/en/stable/examples.html#symbolic-classifier
[4] 利用 gplearn 進行特征工程. https://bigquant.com/community/t/topic/120709
[5] Practical Lessons from Predicting Clicks on Ads at Facebook. https://pdfs.semanticscholar.org/daf9/ed5dc6c6bad5367d7fd8561527da30e9b8dd.pdf
[6] Feature Tools:可自動構造機器學習特征的Python庫. https://www.jiqizhixin.com/articles/2018-06-21-2
[7] 各種聚類算法的系統介紹和比較. https://blog.csdn.net/abc200941410128/article/details/78541273


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM