資料準備指南:10種基礎特徵工程方法的實戰教程

deephub發表於2024-10-14

在資料分析和機器學習領域,從原始資料中提取有價值的資訊是一個關鍵步驟。這個過程不僅有助於輔助決策,還能預測未來趨勢。為了實現這一目標,特徵工程技術顯得尤為重要。

特徵工程是將原始資料轉化為更具資訊量的特徵的過程。本文將詳細介紹十種基礎特徵工程技術,包括其基本原理和實現示例。

首先,我們需要匯入必要的庫以確保程式碼的正常執行。以下是本文中使用的主要庫:

 importpandasaspd  # 用於資料處理和操作
 importnumpyasnp  # 用於數值計算
 importmatplotlib.pyplotasplt  # 用於資料視覺化
 importgensim.downloaderasapi  # 用於下載gensim提供的語料庫
 fromgensim.modelsimportWord2Vec  # 用於詞嵌入
 fromsklearn.pipelineimportPipeline  # 用於構建資料處理管道
 fromsklearn.decompositionimportPCA  # 用於主成分分析
 fromsklearn.datasetsimportload_iris  # 用於載入iris資料集
 fromsklearn.imputeimportSimpleImputer  # 用於資料插補
 fromsklearn.composeimportColumnTransformer  # 用於對資料集應用轉換
 
 fromsklearn.feature_extraction.textimportTfidfVectorizer  # 用於TF-IDF實現
 fromsklearn.preprocessingimportMinMaxScaler, StandardScaler  # 用於資料縮放

1、資料插補

資料插補是處理缺失資料的重要技術,它透過用其他值替換缺失資料來完善資料集。在實際應用中,許多演算法(如線性迴歸和邏輯迴歸)無法直接處理包含缺失值的資料集。因此我們通常有兩種選擇:

  1. 刪除包含缺失值的行或列
  2. 對缺失值進行插補

資料插補的方法多樣,包括:

  1. 使用常數值填充(如0、1、2等)
  2. 使用統計量填充(如均值或中位數)
  3. 使用相鄰資料值填充(如前值或後值)
  4. 構建預測模型估計缺失值

以下是一個資料插補的實現示例:

 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'])

在這個例子中建立了一個包含汽車資料的DataFrame,其中

doors

topspeed

列存在缺失值。對於

doors

列,使用常數4進行填充(假設大多數汽車有4個門)。對於

topspeed

列,使用中位數進行填充。

下圖展示了插補前後的資料對比:

可以觀察到

doors

列的缺失值被填充為4,而

topspeed

列的缺失值被填充為資料的中位數。

2、資料分箱

資料分箱是將連續變數轉換為離散分類變數的技術。這種技術在日常生活中常被無意識地使用,例如將人按年齡段分類。

資料分箱的主要目的包括:

  1. 簡化資料,將連續值轉換為離散類別
  2. 處理非線性關係
  3. 減少資料中的噪聲和異常值

以下是一個資料分箱的實現示例:

 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之間的隨機整數作為年齡資料,然後將其分為五個類別:嬰兒、兒童、青少年、成年人和老年人。

以下是分箱結果的視覺化:

透過資料分箱,可以更直觀地理解資料的分佈情況。在某些演算法中,經過分箱處理的離散資料可能比原始的連續資料更有優勢。

3、對數變換

對數變換是將特徵值從x轉換為log(x)的技術。這種方法常用於處理高度偏斜的資料分佈或存在大量異常值的情況。

對數變換線上性迴歸和邏輯迴歸等模型中特別有用,因為它可以將乘法關係轉換為加法關係,從而簡化模型。

以下是對數變換的實現示例:

 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個右偏的資料點,然後對其進行對數變換。下圖展示了變換前後的資料分佈對比:

需要注意的是,對數變換並不會自動將資料分佈變為正態分佈,它主要用於減少資料的偏度

4、資料縮放

資料縮放是將資料調整到特定範圍或滿足特定條件的預處理技術。常見的縮放方法包括:

  • 最小-最大縮放:將資料調整到[0, 1]區間
  • 標準化:將資料調整為均值為0,標準差為1的分佈

最小-最大縮放主要用於將資料歸一化到特定範圍,而標準化則考慮了資料的分佈特徵。

以下是資料縮放的實現示例:

 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

下圖展示了原始資料、最小-最大縮放後的資料和標準化後的資料的對比:

可以觀察到,最小-最大縮放將資料調整到[0, 1]區間,而標準化後的資料均值接近0,標準差接近1。

5、One-Hot編碼

One-Hot編碼是處理分類資料的常用方法,特別適用於那些沒有固有順序的名義變數。這種技術將每個分類變數轉換為一系列二進位制特徵。

One-Hot編碼的工作原理如下:

  1. 對於分類特徵中的每個唯一值,建立一個新的二進位制列。
  2. 在新建立的列中,如果原始資料中出現了相應的分類值,則標記為1,否則為0。

這種方法也被稱為虛擬編碼(dummy encoding)。

以下是One-Hot編碼的實現示例:

 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

下圖展示了編碼後的結果:

'speed'列被轉換為三個新的二進位制列:'speed_fast'、'speed_medium'和'speed_slow'。每行在這些新列中只有一個1,其餘為0,對應原始的速度類別。

當分類變數的唯一值數量很大時,One-Hot編碼可能會導致特徵空間的急劇膨脹。在這種情況下,可能需要考慮其他編碼方法或降維技術。

6、目標編碼

目標編碼是一種利用目標變數來編碼分類特徵的方法。這種技術特別適用於高基數的分類變數(即具有大量唯一值的變數)。

目標編碼的基本步驟如下:

  1. 對於分類特徵中的每個類別,計算對應的目標變數統計量(如均值)。
  2. 用計算得到的統計量替換原始的類別值。

以下是目標編碼的一個簡單實現:

 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

結果如下圖所示:

我們用每種水果的平均價格替換了原始的水果名稱。這種方法不僅可以處理高基數的分類變數,還能捕捉類別與目標變數之間的關係。

使用目標編碼時需要注意以下幾點:

  1. 可能導致資料洩露,特別是在不做適當的交叉驗證的情況下。
  2. 對異常值敏感,可能需要進行額外的異常值處理。
  3. 在測試集中遇到訓練集中未出現的類別時,需要有合適的處理策略。

7、主成分分析(PCA)

主成分分析(Principal Component Analysis,PCA)是一種常用的無監督學習方法,主要用於降維和特徵提取。PCA透過線性變換將原始特徵投影到一個新的特徵空間,使得新的特徵(主成分)按方差大小排序。

PCA的主要步驟包括:

  1. 資料標準化
  2. 計算協方差矩陣
  3. 計算協方差矩陣的特徵值和特徵向量
  4. 選擇主成分
  5. 投影資料到新的特徵空間

以下是使用PCA的一個示例,我們使用著名的Iris資料集:

 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)
 
 forpointinset(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()

結果如下圖所示:

在這個例子中將原始的4維特徵空間降至2維。從圖中可以看出,即使在降維後,不同類別的資料點仍然保持了良好的可分性。

PCA的優點包括:

  1. 減少資料的維度,降低計算複雜度。
  2. 去除噪聲和冗餘資訊。
  3. 有助於資料視覺化。

PCA也有一些侷限性:

  1. 可能導致一定程度的資訊損失。
  2. 轉換後的特徵難以解釋,因為每個主成分都是原始特徵的線性組合。
  3. 僅捕捉線性關係,對於非線性關係效果可能不佳。

8、 特徵聚合

特徵聚合是一種透過組合現有特徵來建立新特徵的方法。這種技術常用於時間序列資料、分組資料或者需要綜合多個特徵資訊的場景。

常見的特徵聚合方法包括:

  1. 統計聚合:如平均值、中位數、最大值、最小值等。
  2. 時間聚合:如按天、周、月等時間單位聚合資料。
  3. 分組聚合:根據某些類別特徵對資料進行分組,然後在每個組內進行聚合。

以下是一個特徵聚合的示例:

 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

結果如下圖所示:

在這個例子中建立了兩個新的特徵:

  1. 'avg_sales':每個季度不同產品的平均銷售額。
  2. 'total_sales':每個季度所有產品的總銷售額。

這種聚合可以幫助我們從不同角度理解資料,發現可能被單個特徵忽略的模式。

特徵聚合的優點包括:

  1. 可以捕捉多個特徵之間的關係。
  2. 減少特徵的數量,有助於模型的解釋和計算效率。
  3. 可能創造出更有預測力的特徵。

在使用特徵聚合時也需要注意:

  1. 聚合可能會導致一些細節資訊的丟失。
  2. 需要領域知識來決定哪些聚合是有意義的。
  3. 過度聚合可能會導致過擬合。

9、TF-IDF(詞頻-逆文件頻率)

TF-IDF(Term Frequency-Inverse Document Frequency)是一種廣泛用於文字分析和資訊檢索的特徵提取技術。它結合了詞頻(TF)和逆文件頻率(IDF)兩個指標,用於評估一個詞對於一個文件集或一個語料庫中的某一個文件的重要程度。

TF-IDF的計算基於以下兩個概念:

  1. 詞頻(TF):衡量一個詞在文件中出現的頻率。計算公式為:TF(t,d) = (詞t在文件d中出現的次數) / (文件d中的總詞數)
  2. 逆文件頻率(IDF):衡量一個詞在整個文件集中的普遍重要性。計算公式為:IDF(t) = log(總文件數 / 包含詞t的文件數)

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

結果如下圖所示:

在這個例子中:

  • 第一行代表句子 "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)更高。這是因為雖然 "rice" 在第二個句子中出現得更頻繁,但第一個句子更短,使得 "rice" 在其中的相對重要性更高。

TF-IDF的主要優點包括:

  1. 能夠反映詞語在文件中的重要程度。
  2. 可以過濾掉常見詞語,突出關鍵詞。
  3. 計算簡單,易於理解和實現。

TF-IDF也有一些侷限性:

  1. 沒有考慮詞序和語法結構。
  2. 對於極短文字可能效果不佳。
  3. 不能捕捉詞語之間的語義關係。

10、文字嵌入

文字嵌入是將文字資料(如單詞、短語或文件)對映到連續向量空間的技術。這種技術能夠捕捉詞語之間的語義關係,是現代自然語言處理中的基礎技術之一。

常見的文字嵌入方法包括:

  1. Word2Vec
  2. GloVe (Global Vectors for Word Representation)
  3. FastText
  4. BERT (Bidirectional Encoder Representations from Transformers)

以下是使用Word2Vec進行文字嵌入的示例:

 corpus=api.load('text8')  
 model=Word2Vec(corpus)  
 dog=model.wv['dog']
 print("Embedding vector for 'dog':\n", dog)

輸出結果示例:

我們使用了gensim庫提供的text8語料庫(包含維基百科文字的前100,000,000個位元組)來訓練Word2Vec模型。每個詞被對映到一個100維的向量空間中。

文字嵌入的一個重要特性是能夠捕捉詞語之間的語義關係。我們可以透過計算詞向量之間的相似度來展示這一點:

 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)

輸出結果:

從結果可以看出,"dog"和"cat"的相似度明顯高於"dog"和"car"的相似度,這符合我們的語義直覺。

文字嵌入的主要優點包括:

  1. 能夠捕捉詞語之間的語義關係。
  2. 可以處理高維稀疏的文字資料,將其轉換為低維稠密的向量表示。
  3. 透過遷移學習,可以在小規模資料集上也能獲得良好的表現。

文字嵌入也存在一些挑戰:

  1. 訓練高質量的嵌入模型通常需要大量的文字資料和計算資源。
  2. 詞語的多義性可能無法被單一的靜態向量完全捕捉。
  3. 對於特定領域的任務,可能需要在領域特定的語料上重新訓練或微調嵌入模型。

總結

本文介紹了十種基本的特徵工程技術,涵蓋了數值型、分型別和文字型資料的處理方法。

每種技術都有其特定的應用場景和優缺點。在實際應用中,選擇合適的特徵工程技術需要考慮資料的特性、問題的性質以及模型的要求。often需要結合多種技術來獲得最佳的特徵表示。

還有許多其他高階的特徵工程技術未在本文中涉及,如時間序列特徵工程、影像特徵提取等。隨著機器學習和深度學習技術的發展,特徵工程的重要性可能會有所變化,但理解和掌握這些基本技術仍然是資料科學實踐中的重要基礎。

特徵工程不僅是一門技術,更是一門藝術。它需要領域知識、直覺和經驗的結合。透過不斷的實踐和實驗,我們可以逐步提高特徵工程的技能,從而為後續的機器學習任務奠定堅實的基礎。

https://avoid.overfit.cn/post/45b389046b2f473a9722389260773b7c

作者:Muhammad Ihsan

相關文章