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