你遇到過特征超過1000個的數(shù)據(jù)集嗎?超過5萬個的呢?我遇到過。降維是一個非常具有挑戰(zhàn)性的任務(wù),尤其是當(dāng)你不知道該從哪里開始的時候。擁有這么多變量既是一個恩惠——數(shù)據(jù)量越大,分析結(jié)果越可信;也是一種詛咒——你真的會感到一片茫然,無從下手。
面對這么多特征,在微觀層面分析每個變量顯然不可行,因為這至少要幾天甚至幾個月,而這背后的時間成本是難以估計的。為此,我們需要一種更好的方法來處理高維數(shù)據(jù),比如本文介紹的降維:一種能在減少數(shù)據(jù)集中特征數(shù)量的同時,避免丟失太多信息并保持/改進(jìn)模型性能的方法。
什么是降維?
每天,我們都會生成大量數(shù)據(jù),而事實上,現(xiàn)在世界上約90%的數(shù)據(jù)都是在過去3到4年中產(chǎn)生的,這是個令人難以置信的現(xiàn)實。如果你不信,下面是收集數(shù)據(jù)的幾個示例:
Facebook會收集你喜歡、分享、發(fā)布、訪問的內(nèi)容等數(shù)據(jù),比如你喜歡哪家餐廳。
智能手機中的各類應(yīng)用會收集大量關(guān)于你的個人信息,比如你所在的地點。
淘寶會收集你在其網(wǎng)站上購買、查看、點擊的內(nèi)容等數(shù)據(jù)。
賭場會跟蹤每位客戶的每一步行動。
隨著數(shù)據(jù)的生成和數(shù)據(jù)收集量的不斷增加,可視化和繪制推理圖變得越來越困難。一般情況下,我們經(jīng)常會通過繪制圖表來可視化數(shù)據(jù),比如假設(shè)我們手頭有兩個變量,一個年齡,一個身高。我們就可以繪制散點圖或折線圖,輕松反映它們之間的關(guān)系。
下圖是一個簡單的例子:
其中橫坐標(biāo)X1的單位為“千克”,縱坐標(biāo)X2的單位為“磅”??梢园l(fā)現(xiàn),雖然是兩個變量,但它們傳達(dá)的信息是一致的,即物體的重量。所以我們只需選用其中的一個就能保留原始意義,把2維數(shù)據(jù)壓縮到1維(Y1)后,上圖就變成:
類似地,我們可以把數(shù)據(jù)從原本的p維轉(zhuǎn)變?yōu)橐幌盗衚維的子集(k<
為什么要降維?
以下是在數(shù)據(jù)集中應(yīng)用降維的用處:
隨著數(shù)據(jù)維度不斷降低,數(shù)據(jù)存儲所需的空間也會隨之減少。
低維數(shù)據(jù)有助于減少計算/訓(xùn)練用時。
一些算法在高維度數(shù)據(jù)上容易表現(xiàn)不佳,降維可提高算法可用性。
降維可以用刪除冗余特征解決多重共線性問題。比如我們有兩個變量:“一段時間內(nèi)在跑步機上的耗時”和“卡路里消耗量”。這兩個變量高度相關(guān),在跑步機上花的時間越長,燃燒的卡路里自然就越多。因此,同時存儲這兩個數(shù)據(jù)意義不大,只需一個就夠了。
降維有助于數(shù)據(jù)可視化。如前所述,如果數(shù)據(jù)維度很高,可視化會變得相當(dāng)困難,而繪制二維三維數(shù)據(jù)的圖表非常簡單。
數(shù)據(jù)集1:Big Mart Sales III
降維技術(shù)一覽
數(shù)據(jù)維度的降低方法主要有兩種:
僅保留原始數(shù)據(jù)集中最相關(guān)的變量(特征選擇)。
尋找一組較小的新變量,其中每個變量都是輸入變量的組合,包含與輸入變量基本相同的信息(降維)。
1. 缺失值比率(Missing Value Ratio)
假設(shè)你有一個數(shù)據(jù)集,你第一步會做什么?在構(gòu)建模型前,對數(shù)據(jù)進(jìn)行探索性分析必不可少。但在瀏覽數(shù)據(jù)的過程中,有時候我們會發(fā)現(xiàn)其中包含不少缺失值。如果缺失值少,我們可以填補缺失值或直接刪除這個變量;如果缺失值過多,你會怎么辦呢?
當(dāng)缺失值在數(shù)據(jù)集中的占比過高時,一般我會選擇直接刪除這個變量,因為它包含的信息太少了。但具體刪不刪、怎么刪需要視情況而定,我們可以設(shè)置一個閾值,如果缺失值占比高于閾值,刪除它所在的列。閾值越高,降維方法越積極。
下面是具體代碼:
# 導(dǎo)入需要的庫
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
加載數(shù)據(jù):
# 讀取數(shù)據(jù)
train=pd.read_csv("Train_UWu5bXk.csv")
[注]:應(yīng)在讀取數(shù)據(jù)時添加文件的路徑。
用.isnull().sum()檢查每個變量中缺失值的占比:
train.isnull().sum()/len(train)*100
如上表所示,缺失值很少。我們設(shè)閾值為20%:
# 保存變量中的缺失值
a = train.isnull().sum()/len(train)*100
# 保存列名
variables = train.columns
variable = [ ]
for i in range(0,12):
if a[i]<=20: ? #setting the threshold as 20%
variable.append(variables[i])
2. 低方差濾波(Low Variance Filter)
如果我們有一個數(shù)據(jù)集,其中某列的數(shù)值基本一致,也就是它的方差非常低,那么這個變量還有價值嗎?和上一種方法的思路一致,我們通常認(rèn)為低方差變量攜帶的信息量也很少,所以可以把它直接刪除。
放到實踐中,就是先計算所有變量的方差大小,然后刪去其中最小的幾個。需要注意的一點是:方差與數(shù)據(jù)范圍相關(guān)的,因此在采用該方法前需要對數(shù)據(jù)做歸一化處理。
放在示例中,我們先估算缺失值:
train['Item_Weight'].fillna(train['Item_Weight'].median, inplace=True)
train['Outlet_Size'].fillna(train['Outlet_Size'].mode()[0], inplace=True)
檢查缺失值是否已經(jīng)被填充:
train.isnull().sum()/len(train)*100
再計算所有數(shù)值變量的方差:
train.var()
如上圖所示,和其他變量相比,Item_Visibility的方差非常小,因此可以把它直接刪除。
umeric = train[['Item_Weight', 'Item_Visibility', 'Item_MRP', 'Outlet_Establishment_Year']]
var = numeric.var()
numeric = numeric.columns
variable = [ ]
for i in range(0,len(var)):
ifvar[i]>=10: # 將閾值設(shè)置為10%
variable.append(numeric[i+1])
以上代碼幫我們列出了方差大于10的所有變量。
3. 高相關(guān)濾波(High Correlation filter)
如果兩個變量之間是高度相關(guān)的,這意味著它們具有相似的趨勢并且可能攜帶類似的信息。同理,這類變量的存在會降低某些模型的性能(例如線性和邏輯回歸模型)。為了解決這個問題,我們可以計算獨立數(shù)值變量之間的相關(guān)性。如果相關(guān)系數(shù)超過某個閾值,就刪除其中一個變量。
作為一般準(zhǔn)則,我們應(yīng)該保留那些與目標(biāo)變量顯示相當(dāng)或高相關(guān)性的變量。
首先,刪除因變量(ItemOutletSales),并將剩余的變量保存在新的數(shù)據(jù)列(df)中。
df=train.drop('Item_Outlet_Sales', 1)
df.corr()
如上表所示,示例數(shù)據(jù)集中不存在高相關(guān)變量,但通常情況下,如果一對變量之間的相關(guān)性大于0.5-0.6,那就應(yīng)該考慮是否要刪除一列了。
4. 隨機森林(Random Forest)
隨機森林是一種廣泛使用的特征選擇算法,它會自動計算各個特征的重要性,所以無需單獨編程。這有助于我們選擇較小的特征子集。
在開始降維前,我們先把數(shù)據(jù)轉(zhuǎn)換成數(shù)字格式,因為隨機森林只接受數(shù)字輸入。同時,ID這個變量雖然是數(shù)字,但它目前并不重要,所以可以刪去。
from sklearn.ensemble importRandomForestRegressor
df=df.drop(['Item_Identifier', 'Outlet_Identifier'], axis=1)
model = RandomForestRegressor(random_state=1, max_depth=10)
df=pd.get_dummies(df)
model.fit(df,train.Item_Outlet_Sales)
擬合模型后,根據(jù)特征的重要性繪制成圖:
features = df.columns
importances = model.feature_importances_
indices = np.argsort(importances[0:9]) # top 10 features
plt.title('Feature Importances')
plt.barh(range(len(indices)), importances[indices], color='b', align='center')
plt.yticks(range(len(indices)), [features[i] for i in indices])
plt.xlabel('Relative Importance')
plt.show()
基于上圖,我們可以手動選擇最頂層的特征來減少數(shù)據(jù)集中的維度。如果你用的是sklearn,可以直接使用SelectFromModel,它根據(jù)權(quán)重的重要性選擇特征。
from sklearn.feature_selection importSelectFromModel
feature = SelectFromModel(model)
Fit = feature.fit_transform(df, train.Item_Outlet_Sales)
5. 反向特征消除(Backward Feature Elimination)
以下是反向特征消除的主要步驟:
先獲取數(shù)據(jù)集中的全部n個變量,然后用它們訓(xùn)練一個模型。
計算模型的性能。
在刪除每個變量(n次)后計算模型的性能,即我們每次都去掉一個變量,用剩余的n-1個變量訓(xùn)練模型。
確定對模型性能影響最小的變量,把它刪除。
重復(fù)此過程,直到不再能刪除任何變量。
在構(gòu)建線性回歸或Logistic回歸模型時,可以使用這種方法。
from sklearn.linear_model importLinearRegression
from sklearn.feature_selection import RFE
from sklearn import datasets
lreg = LinearRegression()
rfe = RFE(lreg, 10)
rfe = rfe.fit_transform(df, train.Item_Outlet_Sales)
我們需要指定算法和要選擇的特征數(shù)量,然后返回反向特征消除輸出的變量列表。此外,rfe.ranking_可以用來檢查變量排名。
6. 前向特征選擇(Forward Feature Selection)
前向特征選擇其實就是反向特征消除的相反過程,即找到能改善模型性能的最佳特征,而不是刪除弱影響特征。它背后的思路如下所述:
選擇一個特征,用每個特征訓(xùn)練模型n次,得到n個模型。
選擇模型性能最佳的變量作為初始變量。
每次添加一個變量繼續(xù)訓(xùn)練,重復(fù)上一過程,最后保留性能提升最大的變量。
一直添加,一直篩選,直到模型性能不再有明顯提高。
from sklearn.feature_selection import f_regression
ffs = f_regression(df,train.Item_Outlet_Sales )
上述代碼會返回一個數(shù)組,其中包括變量F值和每個F對應(yīng)的p值。在這里,我們選擇F值大于10的變量:
variable = [ ]
for i in range(0,len(df.columns)-1):
if ffs[0][i] >=10:
variable.append(df.columns[i])
[注]:前向特征選擇和反向特征消除耗時較久,計算成本也都很高,所以只適用于輸入變量較少的數(shù)據(jù)集。
到目前為止,我們介紹的6種方法都能很好地解決示例的商場銷售預(yù)測問題,因為這個數(shù)據(jù)集本身輸入變量不多。在下文中,為了展示多變量數(shù)據(jù)集的降維方法,我們將把數(shù)據(jù)集改成Fashion MNIST,它共有70,000張圖像,其中訓(xùn)練集60,000張,測試集10,000張。我們的目標(biāo)是訓(xùn)練一個能分類各類服裝配飾的模型。
數(shù)據(jù)集2:Fashion MNIST
7. 因子分析(Factor Analysis)
因子分析是一種常見的統(tǒng)計方法,它能從多個變量中提取共性因子,并得到最優(yōu)解。假設(shè)我們有兩個變量:收入和教育。它們可能是高度相關(guān)的,因為總體來看,學(xué)歷高的人一般收入也更高,反之亦然。所以它們可能存在一個潛在的共性因子,比如“能力”。
在因子分析中,我們將變量按其相關(guān)性分組,即特定組內(nèi)所有變量的相關(guān)性較高,組間變量的相關(guān)性較低。我們把每個組稱為一個因子,它是多個變量的組合。和原始數(shù)據(jù)集的變量相比,這些因子在數(shù)量上更少,但攜帶的信息基本一致。
import pandas as pd
import numpy as np
from glob import glob
import cv2
images = [cv2.imread(file) for file in glob('train/*.png')]
[注]:你必須使用train文件夾的路徑替換glob函數(shù)內(nèi)的路徑。
現(xiàn)在我們先把這些圖像轉(zhuǎn)換為numpy數(shù)組格式,以便執(zhí)行數(shù)學(xué)運算并繪制圖像。
images = np.array(images)
images.shape
返回:(60000, 28, 28, 3)
如上所示,這是一個三維數(shù)組,但我們的目標(biāo)是把它轉(zhuǎn)成一維,因為后續(xù)只接受一維輸入。所以我們還得展平圖像:
image = []
for i in range(0,60000):
img = images[i].flatten()
image.append(img)
image = np.array(image)
創(chuàng)建一個數(shù)據(jù)框,其中包含每個像素的像素值,以及它們對應(yīng)的標(biāo)簽:
train = pd.read_csv("train.csv") # Give the complete path of your train.csv file
feat_cols = [ 'pixel'+str(i) for i in range(image.shape[1]) ]
df = pd.DataFrame(image,columns=feat_cols)
df['label'] = train['label']
用因子分析分解數(shù)據(jù)集:
from sklearn.decomposition importFactorAnalysis
FA = FactorAnalysis(n_components = 3).fit_transform(df[feat_cols].values)
這里,n_components將決定轉(zhuǎn)換數(shù)據(jù)中的因子數(shù)量。轉(zhuǎn)換完成后,可視化結(jié)果:
%matplotlib inline
import matplotlib.pyplot as plt
plt.figure(figsize=(12,8))
plt.title('Factor Analysis Components')
plt.scatter(FA[:,0], FA[:,1])
plt.scatter(FA[:,1], FA[:,2])
plt.scatter(FA[:,2],FA[:,0])
在上圖中,x軸和y軸表示分解因子的值,雖然共性因子是潛在的,很難被觀察到,但我們已經(jīng)成功降維。
8. 主成分分析(PCA)
如果說因子分析是假設(shè)存在一系列潛在因子,能反映變量攜帶的信息,那PCA就是通過正交變換將原始的n維數(shù)據(jù)集變換到一個新的被稱做主成分的數(shù)據(jù)集中,即從現(xiàn)有的大量變量中提取一組新的變量。下面是關(guān)于PCA的一些要點:
主成分是原始變量的線性組合。
第一個主成分具有最大的方差值。
第二主成分試圖解釋數(shù)據(jù)集中的剩余方差,并且與第一主成分不相關(guān)(正交)。
第三主成分試圖解釋前兩個主成分等沒有解釋的方差。
再進(jìn)一步降維前,我們先隨機繪制數(shù)據(jù)集中的某些圖:
rndperm = np.random.permutation(df.shape[0])
plt.gray()
fig = plt.figure(figsize=(20,10))
for i in range(0,15):
ax = fig.add_subplot(3,5,i+1)
ax.matshow(df.loc[rndperm[i],feat_cols].values.reshape((28,28*3)).astype(float))
實現(xiàn)PCA:
from sklearn.decomposition import PCA
pca = PCA(n_components=4)
pca_result = pca.fit_transform(df[feat_cols].values)
其中n_components將決定轉(zhuǎn)換數(shù)據(jù)中的主成分。接下來,我們看一下這四個主成分解釋了多少方差:
plt.plot(range(4), pca.explained_variance_ratio_)
plt.plot(range(4), np.cumsum(pca.explained_variance_ratio_))
plt.title("Component-wise and Cumulative Explained Variance")
在上圖中,藍(lán)線表示分量解釋的方差,而橙線表示累積解釋的方差。我們只用四個成分就解釋了數(shù)據(jù)集中約60%的方差。
9. 獨立分量分析(ICA)
獨立分量分析(ICA)基于信息理論,是最廣泛使用的降維技術(shù)之一。PCA和ICA之間的主要區(qū)別在于,PCA尋找不相關(guān)的因素,而ICA尋找獨立因素。
如果兩個變量不相關(guān),它們之間就沒有線性關(guān)系。如果它們是獨立的,它們就不依賴于其他變量。例如,一個人的年齡和他吃了什么/看了什么電視無關(guān)。
該算法假設(shè)給定變量是一些未知潛在變量的線性混合。它還假設(shè)這些潛在變量是相互獨立的,即它們不依賴于其他變量,因此它們被稱為觀察數(shù)據(jù)的獨立分量。
下圖是ICA和PCA的一個直觀比較:
(a)PCA,(b)ICA
PCA的等式是x = Wχ。
這里,
x是觀察結(jié)果
W是混合矩陣
χ是來源或獨立成分
現(xiàn)在我們必須找到一個非混合矩陣,使成分盡可能獨立。而測試成分獨立性最常用的方法是非高斯性:
根據(jù)中心極限定理(Central Limit Theorem),多個獨立隨機變量混合之后會趨向于正態(tài)分布(高斯分布)。
因此,我們可以尋找所有獨立分量中能最大化峰度的分量。
一旦峰度被最大化,整個分布會呈現(xiàn)非高斯分布,我們也能得到獨立分量。
在Python中實現(xiàn)ICA:
from sklearn.decomposition importFastICA
ICA = FastICA(n_components=3, random_state=12)
X=ICA.fit_transform(df[feat_cols].values)
10. IOSMAP
代碼:
from sklearn import manifold
trans_data = manifold.Isomap(n_neighbors=5, n_components=3, n_jobs=-1).fit_transform(df[feat_cols][:6000].values)
使用的參數(shù):
n_neighbors:決定每個點的相鄰點數(shù)
n_components:決定流形的坐標(biāo)數(shù)
n_jobs = -1:使用所有可用的CPU核心
可視化:
plt.figure(figsize=(12,8))
plt.title('Decomposition using ISOMAP')
plt.scatter(trans_data[:,0], trans_data[:,1])
plt.scatter(trans_data[:,1], trans_data[:,2])
plt.scatter(trans_data[:,2], trans_data[:,0])
11. t-SNE
代碼:
from sklearn.manifold import TSNE
tsne = TSNE(n_components=3, n_iter=300).fit_transform(df[feat_cols][:6000].values)
可視化:
plt.figure(figsize=(12,8))
plt.title('t-SNE components')
plt.scatter(tsne[:,0], tsne[:,1])
plt.scatter(tsne[:,1], tsne[:,2])
plt.scatter(tsne[:,2], tsne[:,0])
12. UMAP
代碼:
import umap
umap_data = umap.UMAP(n_neighbors=5, min_dist=0.3, n_components=3).fit_transform(df[feat_cols][:6000].values)
這里,
n_neighbors:確定相鄰點的數(shù)量。
min_dist:控制允許嵌入的緊密程度,較大的值可確保嵌入點的分布更均勻。
可視化:
plt.figure(figsize=(12,8))
plt.title('Decomposition using UMAP')
plt.scatter(umap_data[:,0], umap_data[:,1])
plt.scatter(umap_data[:,1], umap_data[:,2])
plt.scatter(umap_data[:,2], umap_data[:,0])
總結(jié)
到目前為止,我們已經(jīng)介紹了12種降維方法,考慮到篇幅,我們沒有仔細(xì)介紹后三種方法的原理,感興趣的讀者可以找資料查閱,因為它們中的任何一個都足夠?qū)懸黄獙iT介紹的長文。本節(jié)會對這12種方法做一個總結(jié),簡要介紹它們的優(yōu)點和缺點。
缺失值比率:如果數(shù)據(jù)集的缺失值太多,我們可以用這種方法減少變量數(shù)。
低方差濾波:這個方法可以從數(shù)據(jù)集中識別和刪除常量變量,方差小的變量對目標(biāo)變量影響不大,所以可以放心刪去。
高相關(guān)濾波:具有高相關(guān)性的一對變量會增加數(shù)據(jù)集中的多重共線性,所以用這種方法刪去其中一個是有必要的。
隨機森林:這是最常用的降維方法之一,它會明確算出數(shù)據(jù)集中每個特征的重要性。
前向特征選擇和反向特征消除:這兩種方法耗時較久,計算成本也都很高,所以只適用于輸入變量較少的數(shù)據(jù)集。
因子分析:這種方法適合數(shù)據(jù)集中存在高度相關(guān)的變量集的情況。
PCA:這是處理線性數(shù)據(jù)最廣泛使用的技術(shù)之一。
ICA:我們可以用ICA將數(shù)據(jù)轉(zhuǎn)換為獨立的分量,使用更少的分量來描述數(shù)據(jù)。
ISOMAP:適合非線性數(shù)據(jù)處理。
t-SNE:也適合非線性數(shù)據(jù)處理,相較上一種方法,這種方法的可視化更直接。
UMAP:適用于高維數(shù)據(jù),與t-SNE相比,這種方法速度更快。
-
降維
+關(guān)注
關(guān)注
0文章
10瀏覽量
7640 -
數(shù)據(jù)集
+關(guān)注
關(guān)注
4文章
1201瀏覽量
24622
原文標(biāo)題:12種降維方法終極指南(含Python代碼)
文章出處:【微信號:jqr_AI,微信公眾號:論智】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論