數(shù)據(jù)準(zhǔn)備指南:十種基礎(chǔ)特征工程方法的實(shí)戰(zhàn)教程
在數(shù)據(jù)分析和機(jī)器學(xué)習(xí)領(lǐng)域,從原始數(shù)據(jù)中提取有價值的信息是一個關(guān)鍵步驟。這個過程不僅有助于輔助決策,還能預(yù)測未來趨勢。為了實(shí)現(xiàn)這一目標(biāo),特征工程技術(shù)顯得尤為重要。
特征工程是將原始數(shù)據(jù)轉(zhuǎn)化為更具信息量的特征的過程。本文將詳細(xì)介紹十種基礎(chǔ)特征工程技術(shù),包括其基本原理和實(shí)現(xiàn)示例。
首先,我們需要導(dǎo)入必要的庫以確保代碼的正常運(yùn)行。以下是本文中使用的主要庫:
import pandas as pd # 用于數(shù)據(jù)處理和操作
import numpy as np # 用于數(shù)值計算
import matplotlib.pyplot as plt # 用于數(shù)據(jù)可視化
import gensim.downloader as api # 用于下載gensim提供的語料庫
from gensim.models import Word2Vec # 用于詞嵌入
from sklearn.pipeline import Pipeline # 用于構(gòu)建數(shù)據(jù)處理管道
from sklearn.decomposition import PCA # 用于主成分分析
from sklearn.datasets import load_iris # 用于加載iris數(shù)據(jù)集
from sklearn.impute import SimpleImputer # 用于數(shù)據(jù)插補(bǔ)
from sklearn.compose import ColumnTransformer # 用于對數(shù)據(jù)集應(yīng)用轉(zhuǎn)換
from sklearn.feature_extraction.text import TfidfVectorizer # 用于TF-IDF實(shí)現(xiàn)
from sklearn.preprocessing import MinMaxScaler, StandardScaler # 用于數(shù)據(jù)縮放
1、數(shù)據(jù)插補(bǔ)
數(shù)據(jù)插補(bǔ)是處理缺失數(shù)據(jù)的重要技術(shù),它通過用其他值替換缺失數(shù)據(jù)來完善數(shù)據(jù)集。在實(shí)際應(yīng)用中,許多算法(如線性回歸和邏輯回歸)無法直接處理包含缺失值的數(shù)據(jù)集。因此我們通常有兩種選擇:
- 刪除包含缺失值的行或列
- 對缺失值進(jìn)行插補(bǔ)
數(shù)據(jù)插補(bǔ)的方法多樣,包括:
- 使用常數(shù)值填充(如0、1、2等)
- 使用統(tǒng)計量填充(如均值或中位數(shù))
- 使用相鄰數(shù)據(jù)值填充(如前值或后值)
- 構(gòu)建預(yù)測模型估計缺失值
以下是一個數(shù)據(jù)插補(bǔ)的實(shí)現(xiàn)示例:
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=4))
])
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'])
在這個例子中創(chuàng)建了一個包含汽車數(shù)據(jù)的DataFrame,其中doors和topspeed列存在缺失值。對于doors列,使用常數(shù)4進(jìn)行填充(假設(shè)大多數(shù)汽車有4個門)。對于topspeed列,使用中位數(shù)進(jìn)行填充。
下圖展示了插補(bǔ)前后的數(shù)據(jù)對比:
可以觀察到doors列的缺失值被填充為4,而topspeed列的缺失值被填充為數(shù)據(jù)的中位數(shù)。
2、數(shù)據(jù)分箱
數(shù)據(jù)分箱是將連續(xù)變量轉(zhuǎn)換為離散分類變量的技術(shù)。這種技術(shù)在日常生活中常被無意識地使用,例如將人按年齡段分類。
數(shù)據(jù)分箱的主要目的包括:
- 簡化數(shù)據(jù),將連續(xù)值轉(zhuǎn)換為離散類別
- 處理非線性關(guān)系
- 減少數(shù)據(jù)中的噪聲和異常值
以下是一個數(shù)據(jù)分箱的實(shí)現(xià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')
在這個例子中,我們生成了100個0到100之間的隨機(jī)整數(shù)作為年齡數(shù)據(jù),然后將其分為五個類別:嬰兒、兒童、青少年、成年人和老年人。
以下是分箱結(jié)果的可視化:
通過數(shù)據(jù)分箱,可以更直觀地理解數(shù)據(jù)的分布情況。在某些算法中,經(jīng)過分箱處理的離散數(shù)據(jù)可能比原始的連續(xù)數(shù)據(jù)更有優(yōu)勢。
3、對數(shù)變換
對數(shù)變換是將特征值從x轉(zhuǎn)換為log(x)的技術(shù)。這種方法常用于處理高度偏斜的數(shù)據(jù)分布或存在大量異常值的情況。
對數(shù)變換在線性回歸和邏輯回歸等模型中特別有用,因?yàn)樗梢詫⒊朔P(guān)系轉(zhuǎn)換為加法關(guān)系,從而簡化模型。
以下是對數(shù)變換的實(shí)現(xià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()
在這個例子中,生成了100個右偏的數(shù)據(jù)點(diǎn),然后對其進(jìn)行對數(shù)變換。下圖展示了變換前后的數(shù)據(jù)分布對比:
需要注意的是,對數(shù)變換并不會自動將數(shù)據(jù)分布變?yōu)檎龖B(tài)分布,它主要用于減少數(shù)據(jù)的偏度。
4、數(shù)據(jù)縮放
數(shù)據(jù)縮放是將數(shù)據(jù)調(diào)整到特定范圍或滿足特定條件的預(yù)處理技術(shù)。常見的縮放方法包括:
- 最小-最大縮放:將數(shù)據(jù)調(diào)整到[0, 1]區(qū)間
- 標(biāo)準(zhǔn)化:將數(shù)據(jù)調(diào)整為均值為0,標(biāo)準(zhǔn)差為1的分布
最小-最大縮放主要用于將數(shù)據(jù)歸一化到特定范圍,而標(biāo)準(zhǔn)化則考慮了數(shù)據(jù)的分布特征。
以下是數(shù)據(jù)縮放的實(shí)現(xiàn)示例:
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
下圖展示了原始數(shù)據(jù)、最小-最大縮放后的數(shù)據(jù)和標(biāo)準(zhǔn)化后的數(shù)據(jù)的對比:
可以觀察到,最小-最大縮放將數(shù)據(jù)調(diào)整到[0, 1]區(qū)間,而標(biāo)準(zhǔn)化后的數(shù)據(jù)均值接近0,標(biāo)準(zhǔn)差接近1。
5、One-Hot編碼
One-Hot編碼是處理分類數(shù)據(jù)的常用方法,特別適用于那些沒有固有順序的名義變量。這種技術(shù)將每個分類變量轉(zhuǎn)換為一系列二進(jìn)制特征。
One-Hot編碼的工作原理如下:
- 對于分類特征中的每個唯一值,創(chuàng)建一個新的二進(jìn)制列。
- 在新創(chuàng)建的列中,如果原始數(shù)據(jù)中出現(xiàn)了相應(yīng)的分類值,則標(biāo)記為1,否則為0。
這種方法也被稱為虛擬編碼(dummy encoding)。
以下是One-Hot編碼的實(shí)現(xiàn)示例:
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
下圖展示了編碼后的結(jié)果:
'speed'列被轉(zhuǎn)換為三個新的二進(jìn)制列:'speed_fast'、'speed_medium'和'speed_slow'。每行在這些新列中只有一個1,其余為0,對應(yīng)原始的速度類別。
當(dāng)分類變量的唯一值數(shù)量很大時,One-Hot編碼可能會導(dǎo)致特征空間的急劇膨脹。在這種情況下,可能需要考慮其他編碼方法或降維技術(shù)。
6、目標(biāo)編碼
目標(biāo)編碼是一種利用目標(biāo)變量來編碼分類特征的方法。這種技術(shù)特別適用于高基數(shù)的分類變量(即具有大量唯一值的變量)。
目標(biāo)編碼的基本步驟如下:
- 對于分類特征中的每個類別,計算對應(yīng)的目標(biāo)變量統(tǒng)計量(如均值)。
- 用計算得到的統(tǒng)計量替換原始的類別值。
以下是目標(biāo)編碼的一個簡單實(shí)現(xiàn):
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
結(jié)果如下圖所示:
我們用每種水果的平均價格替換了原始的水果名稱。這種方法不僅可以處理高基數(shù)的分類變量,還能捕捉類別與目標(biāo)變量之間的關(guān)系。
使用目標(biāo)編碼時需要注意以下幾點(diǎn):
- 可能導(dǎo)致數(shù)據(jù)泄露,特別是在不做適當(dāng)?shù)慕徊骝?yàn)證的情況下。
- 對異常值敏感,可能需要進(jìn)行額外的異常值處理。
- 在測試集中遇到訓(xùn)練集中未出現(xiàn)的類別時,需要有合適的處理策略。
7、主成分分析(PCA)
主成分分析(Principal Component Analysis,PCA)是一種常用的無監(jiān)督學(xué)習(xí)方法,主要用于降維和特征提取。PCA通過線性變換將原始特征投影到一個新的特征空間,使得新的特征(主成分)按方差大小排序。
PCA的主要步驟包括:
- 數(shù)據(jù)標(biāo)準(zhǔn)化
- 計算協(xié)方差矩陣
- 計算協(xié)方差矩陣的特征值和特征向量
- 選擇主成分
- 投影數(shù)據(jù)到新的特征空間
以下是使用PCA的一個示例,我們使用著名的Iris數(shù)據(jù)集:
iris_data = load_iris()
features = iris_data.data
targets = iris_data.target
features.shape
# 輸出: (150, 4)
pca = PCA(n_components=2)
pca_features = pca.fit_transform(features)
pca_features.shape
# 輸出: (150, 2)
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()
結(jié)果如下圖所示:
在這個例子中將原始的4維特征空間降至2維。從圖中可以看出,即使在降維后,不同類別的數(shù)據(jù)點(diǎn)仍然保持了良好的可分性。
PCA的優(yōu)點(diǎn)包括:
- 減少數(shù)據(jù)的維度,降低計算復(fù)雜度。
- 去除噪聲和冗余信息。
- 有助于數(shù)據(jù)可視化。
PCA也有一些局限性:
- 可能導(dǎo)致一定程度的信息損失。
- 轉(zhuǎn)換后的特征難以解釋,因?yàn)槊總€主成分都是原始特征的線性組合。
- 僅捕捉線性關(guān)系,對于非線性關(guān)系效果可能不佳。
8、 特征聚合
特征聚合是一種通過組合現(xiàn)有特征來創(chuàng)建新特征的方法。這種技術(shù)常用于時間序列數(shù)據(jù)、分組數(shù)據(jù)或者需要綜合多個特征信息的場景。
常見的特征聚合方法包括:
- 統(tǒng)計聚合:如平均值、中位數(shù)、最大值、最小值等。
- 時間聚合:如按天、周、月等時間單位聚合數(shù)據(jù)。
- 分組聚合:根據(jù)某些類別特征對數(shù)據(jù)進(jìn)行分組,然后在每個組內(nèi)進(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
結(jié)果如下圖所示:
在這個例子中創(chuàng)建了兩個新的特征:
- 'avg_sales':每個季度不同產(chǎn)品的平均銷售額。
- 'total_sales':每個季度所有產(chǎn)品的總銷售額。
這種聚合可以幫助我們從不同角度理解數(shù)據(jù),發(fā)現(xiàn)可能被單個特征忽略的模式。
特征聚合的優(yōu)點(diǎn)包括:
- 可以捕捉多個特征之間的關(guān)系。
- 減少特征的數(shù)量,有助于模型的解釋和計算效率。
- 可能創(chuàng)造出更有預(yù)測力的特征。
在使用特征聚合時也需要注意:
- 聚合可能會導(dǎo)致一些細(xì)節(jié)信息的丟失。
- 需要領(lǐng)域知識來決定哪些聚合是有意義的。
- 過度聚合可能會導(dǎo)致過擬合。
9、TF-IDF(詞頻-逆文檔頻率)
TF-IDF(Term Frequency-Inverse Document Frequency)是一種廣泛用于文本分析和信息檢索的特征提取技術(shù)。它結(jié)合了詞頻(TF)和逆文檔頻率(IDF)兩個指標(biāo),用于評估一個詞對于一個文檔集或一個語料庫中的某一個文檔的重要程度。
TF-IDF的計算基于以下兩個概念:
- 詞頻(TF):衡量一個詞在文檔中出現(xiàn)的頻率。計算公式為:TF(t,d) = (詞t在文檔d中出現(xiàn)的次數(shù)) / (文檔d中的總詞數(shù))
- 逆文檔頻率(IDF):衡量一個詞在整個文檔集中的普遍重要性。計算公式為:IDF(t) = log(總文檔數(shù) / 包含詞t的文檔數(shù))
TF-IDF的最終得分是TF和IDF的乘積:TF-IDF(t,d) = TF(t,d) * IDF(t)
以下是使用TF-IDF的一個示例:
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
結(jié)果如下圖所示:
在這個例子中:
- 第一行代表句子 "I eat rice with eggs."
- 第二行代表句子 "I also love to eat fried rice. Rice is the most delicious food in the world"
可以觀察到,"rice" 這個詞在第一個句子中的TF-IDF值(0.409)比在第二個句子中的值(0.349)更高。這是因?yàn)殡m然 "rice" 在第二個句子中出現(xiàn)得更頻繁,但第一個句子更短,使得 "rice" 在其中的相對重要性更高。
TF-IDF的主要優(yōu)點(diǎn)包括:
- 能夠反映詞語在文檔中的重要程度。
- 可以過濾掉常見詞語,突出關(guān)鍵詞。
- 計算簡單,易于理解和實(shí)現(xiàn)。
TF-IDF也有一些局限性:
- 沒有考慮詞序和語法結(jié)構(gòu)。
- 對于極短文本可能效果不佳。
- 不能捕捉詞語之間的語義關(guān)系。
10、文本嵌入
文本嵌入是將文本數(shù)據(jù)(如單詞、短語或文檔)映射到連續(xù)向量空間的技術(shù)。這種技術(shù)能夠捕捉詞語之間的語義關(guān)系,是現(xiàn)代自然語言處理中的基礎(chǔ)技術(shù)之一。
常見的文本嵌入方法包括:
- Word2Vec
- GloVe (Global Vectors for Word Representation)
- FastText
- BERT (Bidirectional Encoder Representations from Transformers)
以下是使用Word2Vec進(jìn)行文本嵌入的示例:
corpus = api.load('text8')
model = Word2Vec(corpus)
dog = model.wv['dog']
print("Embedding vector for 'dog':\n", dog)
輸出結(jié)果示例:
我們使用了gensim庫提供的text8語料庫(包含維基百科文本的前100,000,000個字節(jié))來訓(xùn)練Word2Vec模型。每個詞被映射到一個100維的向量空間中。
文本嵌入的一個重要特性是能夠捕捉詞語之間的語義關(guān)系。我們可以通過計算詞向量之間的相似度來展示這一點(diǎn):
cat = model.wv['cat']
car = model.wv['car']
dogvscat = model.wv.similarity('dog','cat')
dogvscar = model.wv.similarity('dog','car')
print("Similarity:")
print("Dog vs Cat: ", dogvscat)
print("Dog vs Car: ", dogvscar)
輸出結(jié)果:
從結(jié)果可以看出,"dog"和"cat"的相似度明顯高于"dog"和"car"的相似度,這符合我們的語義直覺。
文本嵌入的主要優(yōu)點(diǎn)包括:
- 能夠捕捉詞語之間的語義關(guān)系。
- 可以處理高維稀疏的文本數(shù)據(jù),將其轉(zhuǎn)換為低維稠密的向量表示。
- 通過遷移學(xué)習(xí),可以在小規(guī)模數(shù)據(jù)集上也能獲得良好的表現(xiàn)。
文本嵌入也存在一些挑戰(zhàn):
- 訓(xùn)練高質(zhì)量的嵌入模型通常需要大量的文本數(shù)據(jù)和計算資源。
- 詞語的多義性可能無法被單一的靜態(tài)向量完全捕捉。
- 對于特定領(lǐng)域的任務(wù),可能需要在領(lǐng)域特定的語料上重新訓(xùn)練或微調(diào)嵌入模型。
總結(jié)
本文介紹了十種基本的特征工程技術(shù),涵蓋了數(shù)值型、分類型和文本型數(shù)據(jù)的處理方法。
每種技術(shù)都有其特定的應(yīng)用場景和優(yōu)缺點(diǎn)。在實(shí)際應(yīng)用中,選擇合適的特征工程技術(shù)需要考慮數(shù)據(jù)的特性、問題的性質(zhì)以及模型的要求。often需要結(jié)合多種技術(shù)來獲得最佳的特征表示。
還有許多其他高級的特征工程技術(shù)未在本文中涉及,如時間序列特征工程、圖像特征提取等。隨著機(jī)器學(xué)習(xí)和深度學(xué)習(xí)技術(shù)的發(fā)展,特征工程的重要性可能會有所變化,但理解和掌握這些基本技術(shù)仍然是數(shù)據(jù)科學(xué)實(shí)踐中的重要基礎(chǔ)。
特征工程不僅是一門技術(shù),更是一門藝術(shù)。它需要領(lǐng)域知識、直覺和經(jīng)驗(yàn)的結(jié)合。通過不斷的實(shí)踐和實(shí)驗(yàn),我們可以逐步提高特征工程的技能,從而為后續(xù)的機(jī)器學(xué)習(xí)任務(wù)奠定堅(jiān)實(shí)的基礎(chǔ)。