終于把機器學(xué)習(xí)中的特征工程搞懂了?。?!
大家好,我是小寒
今天給大家分享一個機器學(xué)習(xí)中的關(guān)鍵概念,特征工程
特征工程是機器學(xué)習(xí)中的重要步驟之一,其目的是通過對原始數(shù)據(jù)進(jìn)行處理、變換或生成新的特征,以增強模型的學(xué)習(xí)能力和預(yù)測性能。
特征工程直接影響機器學(xué)習(xí)模型的表現(xiàn),因為模型的效果很大程度上取決于輸入數(shù)據(jù)的質(zhì)量和特征的選擇。
下面,我們來分享10個常用的特征工程技術(shù)。
1.插補
插補是處理數(shù)據(jù)集中的缺失值的一種常用方法。
大多數(shù)機器學(xué)習(xí)算法無法直接處理缺失值,因此在特征工程中必須解決這個問題。
插補方法根據(jù)已有的數(shù)據(jù)推測或生成合理的替代值,以填補缺失的數(shù)據(jù)。
常見插補方法:
- 均值插補,將缺失值用該特征的均值替代,適用于數(shù)值型數(shù)據(jù)。
- 中位數(shù)插補,用中位數(shù)替代缺失值,適用于具有異常值的數(shù)值數(shù)據(jù),因為中位數(shù)對極端值不敏感。
- 眾數(shù)插補,對于類別型數(shù)據(jù),使用該特征的眾數(shù)(最常出現(xiàn)的值)進(jìn)行插補。
- K近鄰插補,基于 K 最近鄰算法,用與缺失值最近的 K 個相似樣本的平均值進(jìn)行插補。
- 插值,對時間序列或連續(xù)數(shù)據(jù),可以使用線性插值或多項式插值方法進(jìn)行插補。
優(yōu)缺點
- 插補可以讓數(shù)據(jù)集保持完整,但如果插補策略不當(dāng),可能會引入偏差或噪聲,影響模型的性能。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import gensim.downloader as api
from gensim.models import Word2Vec
from sklearn.pipeline import Pipeline
from sklearn.decomposition import PCA
from sklearn.datasets import load_iris
from sklearn.impute import SimpleImputer
from sklearn.compose import ColumnTransformer
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.preprocessing import MinMaxScaler, StandardScaler
data = pd.DataFrame({
'doors': [2, np.nan, 2, np.nan, 4],
'topspeed': [100, np.nan, 150, 200, np.nan],
'model': ['Daihatsu', 'Toyota', 'Suzuki', 'BYD','Wuling']
})
doors_imputer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='constant', fill_value=0))
])
topspeed_imputer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='median'))
])
pipeline = ColumnTransformer(
transformers=[
('doors_imputer', doors_imputer, ['doors']),
('topspeed_imputer', topspeed_imputer, ['topspeed'])
],
remainder='passthrough'
)
transformed = pipeline.fit_transform(data)
transformed_df = pd.DataFrame(transformed, columns=['doors', 'topspeed', 'model'])
圖片
2.分箱
分箱是將連續(xù)型數(shù)值特征離散化的過程,通過將數(shù)值范圍劃分為多個區(qū)間或“箱”,將原始數(shù)值轉(zhuǎn)換為離散的類別。
常見的分箱方法
- 等寬分箱,將數(shù)值區(qū)間按等寬度分成若干個區(qū)間,適合均勻分布的數(shù)據(jù)。
- 等頻分箱,將數(shù)值按頻數(shù)分箱,每個箱中的樣本數(shù)大致相同,適用于不均勻分布的數(shù)據(jù)。
- 自定義分箱,根據(jù)業(yè)務(wù)邏輯或數(shù)據(jù)特點,自定義分箱的邊界。
應(yīng)用場景
- 在信用評分等領(lǐng)域,通過分箱處理連續(xù)型變量,可以減少數(shù)據(jù)的噪聲,增加模型的穩(wěn)健性。
np.random.seed(42)
data = pd.DataFrame({'age' : np.random.randint(0, 100, 100)})
data['category'] = pd.cut(data['age'], [0, 2, 11, 18, 65, 101], labels = ['infants', 'children', 'teenagers', 'adults', 'elders'])
print(data)
print(data['category'].value_counts())
data['category'].value_counts().plot(kind='bar')
圖片
3.對數(shù)變換
對數(shù)變換是一種數(shù)值轉(zhuǎn)換方法,用于處理數(shù)據(jù)中呈現(xiàn)偏態(tài)分布的特征,將其轉(zhuǎn)換為更接近正態(tài)分布的數(shù)據(jù)形式。
對數(shù)變換可以減小大值的影響,壓縮特征的數(shù)值范圍。
應(yīng)用場景
- 處理右偏分布的特征,如收入、價格等數(shù)據(jù)。
- 適用于減少數(shù)據(jù)中極大值的影響,避免模型對大值的過度關(guān)注。
rskew_data = np.random.exponential(scale=2, size=100)
log_data = np.log(rskew_data)
plt.title('Right Skewed Data')
plt.hist(rskew_data, bins=10)
plt.show()
plt.title('Log Transformed Data')
plt.hist(log_data, bins=20)
plt.show()
圖片
4.縮放
縮放是將特征的數(shù)值范圍轉(zhuǎn)換到某一固定區(qū)間內(nèi)的過程。
常見的縮放方法
- 標(biāo)準(zhǔn)化
將特征值縮放為均值為 0,標(biāo)準(zhǔn)差為1的標(biāo)準(zhǔn)正態(tài)分布。
公式為:
其中, 是均值, 是標(biāo)準(zhǔn)差。 - 歸一化
將特征縮放到 [0, 1] 范圍內(nèi)。
公式為:
應(yīng)用場景
- 縮放對于基于距離的算法(如KNN、SVM)和梯度下降優(yōu)化的算法特別重要,因為特征值的尺度會影響模型的性能。
data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).reshape(-1, 1)
scaler = MinMaxScaler()
minmax = scaler.fit_transform(data)
scaler = StandardScaler()
standard = scaler.fit_transform(data)
df = pd.DataFrame({'original':data.flatten(),'Min-Max Scaling':minmax.flatten(),'Standard Scaling':standard.flatten()})
df
圖片
5.獨熱編碼
獨熱編碼是一種將類別型變量轉(zhuǎn)換為二進(jìn)制特征的編碼方式。
每個類別值被轉(zhuǎn)換為一個獨立的二進(jìn)制特征,這些特征值為0或1,表示該樣本是否屬于對應(yīng)的類別。
舉例
對于類別型特征 “顏色” = {紅,藍(lán),綠},獨熱編碼會將其轉(zhuǎn)換為三個新特征
- 紅:1, 0, 0
- 藍(lán):0, 1, 0
- 綠:0, 0, 1
應(yīng)用場景
- 獨熱編碼適用于無序的類別型數(shù)據(jù),如國家、城市、產(chǎn)品種類等。
- 適用于不具備自然排序關(guān)系的特征。
優(yōu)缺點
- 優(yōu)點:可以避免類別之間的錯誤關(guān)系,適合沒有順序的分類變量。
- 缺點:當(dāng)類別數(shù)過多時,會導(dǎo)致維度爆炸
data = pd.DataFrame({'models':['toyota','ferrari','byd','lamborghini','honda','tesla'],
'speed':['slow','fast','medium','fast','slow','medium']})
data = pd.concat([data, pd.get_dummies(data['speed'], prefix='speed')],axis=1)
data
圖片
6.目標(biāo)編碼
目標(biāo)編碼是一種處理類別型變量的編碼方式,通過用該類別與目標(biāo)變量的統(tǒng)計信息(如均值、概率)來替代類別值。
通常用于高基數(shù)的類別變量,避免獨熱編碼導(dǎo)致維度過高的問題。
舉例
假設(shè)目標(biāo)是二分類問題,對于類別型特征“城市”,可以用每個城市對應(yīng)的目標(biāo)變量均值來替換原始的類別值。
例如,城市A的目標(biāo)變量均值為0.7,城市B的均值為0.3,城市C的均值為0.5。
應(yīng)用場景
- 適用于高基數(shù)類別型變量(如用戶ID、產(chǎn)品ID等),特別是在類別與目標(biāo)變量有顯著關(guān)系時。
注意事項
- 為了避免數(shù)據(jù)泄露(即使用目標(biāo)值信息),需要對訓(xùn)練集和測試集分別進(jìn)行編碼,或者使用交叉驗證技術(shù)。
fruits = ['banana','apple','durian','durian','apple','banana']
price = [120,100,110,150,140,160]
data = pd.DataFrame({
'fruit': fruits,
'price': price
})
data['encoded_fruits'] = data.groupby('fruit')['price'].transform('mean')
data
圖片
7.主成分分析
PCA 是一種線性降維方法,通過將高維數(shù)據(jù)投影到一個低維空間,同時盡量保留原始數(shù)據(jù)的方差信息。
PCA 通過計算數(shù)據(jù)的協(xié)方差矩陣,找到數(shù)據(jù)的主成分(特征向量),然后選擇前幾個主成分作為新的特征。
步驟
- 標(biāo)準(zhǔn)化數(shù)據(jù)。
- 計算協(xié)方差矩陣。
- 計算協(xié)方差矩陣的特征值和特征向量。
- 根據(jù)特征值大小選擇前K個特征向量作為主成分。
- 將原始數(shù)據(jù)投影到新的主成分上。
應(yīng)用場景
- PCA常用于高維數(shù)據(jù)集的降維,如圖像、基因數(shù)據(jù),目的是減少特征數(shù)量,降低計算復(fù)雜度,同時保留最重要的信息。
iris_data = load_iris()
features = iris_data.data
targets = iris_data.target
pca = PCA(n_compnotallow=2)
pca_features = pca.fit_transform(features)
for point in set(targets):
plt.scatter(pca_features[targets == point, 0], pca_features[targets == point,1], label=iris_data.target_names[point])
plt.xlabel('PCA Component 1')
plt.ylabel('PCA Component 2')
plt.title('PCA on Iris Dataset')
plt.legend()
plt.show()
圖片
8.特征聚合
特征聚合是一種通過聚合現(xiàn)有特征來生成新特征的技術(shù)。
聚合可以通過多種方式實現(xiàn),如計算平均值、總和、最大值、最小值等。
特征聚合特別適合處理時間序列數(shù)據(jù)或分組數(shù)據(jù)。
應(yīng)用場景
- 在時間序列數(shù)據(jù)中,可以對某一特征在多個時間窗口上計算統(tǒng)計量,如移動平均、累計總和等。
- 在分組數(shù)據(jù)中,可以對每個用戶的購買記錄進(jìn)行聚合,生成新的特征(如總購買金額、平均購買頻率等)。
quarter = ['Q1','Q2','Q3','Q4']
car_sales = [10000,9850,13000,20000]
motorbike_sales = [14000,18000,9000,11000]
sparepart_sales = [5000, 7000,3000, 10000]
data = pd.DataFrame({'car':car_sales,
'motorbike':motorbike_sales,
'sparepart':sparepart_sales}, index=quarter)
data['avg_sales'] = data[['car','motorbike','sparepart']].mean(axis=1).astype(int)
data['total_sales'] = data[['car','motorbike','sparepart']].sum(axis=1).astype(int)
data
圖片
9.TF-IDF
TF-IDF 是一種衡量文本中詞匯重要性的特征工程技術(shù),廣泛應(yīng)用于自然語言處理(NLP)任務(wù)。
它通過計算詞頻(TF)和逆文檔頻率(IDF)來評估某個詞在文本中的重要性:
- 詞頻(TF),某個詞在文檔中出現(xiàn)的頻率。
- 逆文檔頻率(IDF),表示詞在所有文檔中出現(xiàn)的稀有程度,常見詞會被削弱。
TF-IDF 公式:
其中 N 是文檔總數(shù), 是詞 t 出現(xiàn)在多少個文檔中的次數(shù)。
texts = ["I eat rice with eggs.",
"I also love to eat fried rice. Rice is the most delicious food in the world"]
vectorizer = TfidfVectorizer()
tfidfmatrix = vectorizer.fit_transform(texts)
features = vectorizer.get_feature_names_out()
data = pd.DataFrame(tfidfmatrix.toarray(), columns=features)
print("TF-IDF matrix")
data
圖片
10.文本嵌入
文本嵌入是將文本數(shù)據(jù)轉(zhuǎn)化為數(shù)值向量的技術(shù),目的是將語義信息保留在低維向量空間中,使其能夠被機器學(xué)習(xí)模型處理。
常見的文本嵌入方法有:
- Word2Vec,將詞映射為向量,類似語義的詞會在向量空間中更接近。
- GloVe,基于共現(xiàn)矩陣生成詞向量,保持詞語之間的全局關(guān)系。
- BERT,上下文感知的詞向量模型,能夠捕捉詞在不同上下文中的含義。
文本嵌入可以捕捉文本中的語義信息,使模型能夠理解文本間的關(guān)系。
corpus = api.load('text8')
model = Word2Vec(corpus)
dog = model.wv['dog']
print("Embedding vector for 'dog':\n", dog)
圖片