你是否曾經處理過具備一千多個特徵的數據集?5萬多個特徵呢?我曾經有過,讓我告訴你這是一項很是具備挑戰性的任務,特別是若是你不知道從哪裏開始的時候!擁有大量的變量既是好事,也是壞事。咱們有大量的數據用於分析,這很棒,但因爲規模太大,它變得很是具備挑戰性。算法
在微觀層面分析每一個變量是不可行的。咱們可能須要幾天或幾個月才能進行任何有意義的分析,咱們將會爲咱們的業務損失大量的時間和金錢!更不用說這將須要的計算能力。咱們須要一種更好的方法來處理高維數據,以便咱們可以快速從中提取模式和看法。那麼咱們如何處理這樣的數據集呢?編程
固然是使用降維技術。你可使用這個技術來減小數據集中的特徵數量,而沒必要丟失太多信息並保持(或改進)模型的性能。正如你將在本文中看到的,這是處理大型數據集的一種很是強大的方法。數組
這是一個能夠在實際場景中使用的各類降維技術的綜合指南。在深刻介紹我所涵蓋的12種不一樣技術以前,咱們將首先了解這個概念是什麼以及爲何要使用它。而且每種技術都有本身的Python實現代碼,讓你更好的熟悉它。安全
咱們天天都在生成大量的數據。事實上,世界上90%的數據都是在過去的3到4年中產生的!這些數字真的使人難以置信。如下是收集的數據的一些例子:數據結構
隨着數據生成和收集量的不斷增長,可視化和繪製分析變得愈來愈具備挑戰性。進行可視化的最多見方法之一是經過圖表。假設咱們有2個變量,年齡Age和身高Height。咱們可使用Age和Height之間的散點圖或線圖,並輕鬆地將它們的關係可視化:app
如今考慮咱們有100個變量(p = 100)的狀況。在這種狀況下,咱們能夠有100(100-1)/ 2 = 5000個不一樣的圖。將它們分別可視化是沒有多大意義的,對吧?在咱們有大量變量的狀況下,最好選擇這些變量的一個子集(p << 100),它獲取的信息與原始變量集同樣多。dom
讓咱們用一個簡單的例子來理解這一點。考慮下面的圖像:機器學習
這裏咱們有相似物體的重量,單位爲Kg(X1)和磅(X2)。若是咱們使用這兩個變量,它們將傳達相相似的信息。所以,僅使用一個變量是有意義的。咱們能夠將數據從2D(X1和X2)轉換爲1D(Y1),以下所示:分佈式
相似地,咱們能夠將數據的p維度減小爲k維度的子集(k << n)。這稱爲降維。ide
如下是將降維應用於數據集的一些好處:
是時候深刻了解本文的關鍵 - 各類降維技術!咱們將使用一個實踐問題:Big Mart Sales III中的數據集點擊這裏下載數據提取碼爲:fmk0 。
降維能夠經過兩種不一樣的方式完成:
咱們如今將介紹各類降維技術以及如何在Python中實現它們。
假設你有一個數據集。你的第一步是什麼?在構建模型以前,你應該會但願先探索數據。在研究數據時,你會發現數據集中存在一些缺失值。怎麼辦?你將嘗試找出這些缺失值的緣由,而後將輸入它們或徹底刪除具備缺失值的變量(使用適當的方法)。
若是咱們有太多的缺失值(好比說超過50%)怎麼辦?咱們應該輸入這些缺失值仍是直接刪除變量?我寧願放棄變量,由於它沒有太多的信息。然而,這不是一成不變的。咱們能夠設置一個閾值,若是任何變量中缺失值的百分比大於該閾值,咱們將刪除該變量。
讓咱們在Python中實現這種方法。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
首先,讓咱們加載數據:
train=pd.read_csv("Train_UWu5bXk.csv")
注意:應在讀取數據時添加文件的路徑。
如今,咱們將檢查每一個變量中缺失值的百分比。咱們可使用.isnull().sum()來計算它。
train.isnull().sum()/len(train)*100
正如你在上表中所看到的,並無太多的缺失值(實際上只有2個變量具備缺失值)。咱們可使用適當的方法來輸入變量,或者咱們能夠設置閾值,好比20%,並刪除具備超過20%缺失值的變量。讓咱們看看如何在Python中完成此操做:
a = train.isnull().sum()/len(train)*100
variables = train.columns
variable = [ ]
for i in range(0,12):
if a[i]<=20: #將閾值設置爲20%
variable.append(variables[i])
所以,要使用的變量存儲在「variables」中,它只包含哪些缺失值小於20%的特徵
假設咱們的數據集中的一個變量,其中全部觀察值都是相同的,例如1。若是咱們要使用此變量,你認爲它能夠改進咱們將要創建的模型麼?答案固然是否認的,由於這個變量的方差爲零。
所以,咱們須要計算給出的每一個變量的方差。而後刪除與咱們的數據集中其餘變量相比方差比較小的變量。如上所述,這樣作的緣由是方差較小的變量不會影響目標變量。
讓咱們首先使用已知ItemWeight觀察值的中值來填充temWeight列中的缺失值。對於OutletSize列,咱們將使用已知OutletSize值的模式來填充缺失值:
train['Item_Weight'].fillna(train['Item_Weight'].median(), inplace=True)
train['Outlet_Size'].fillna(train['Outlet_Size'].mode()[0], inplace=True)
讓咱們檢查一下是否全部的缺失值都已經被填滿了:
train.isnull().sum()/len(train)*100
嘿瞧!咱們都已經準備好了。如今讓咱們計算全部數值變量的方差。
train.var()
如上面的輸出所示,與其餘變量相比,Item_Visibility的方差很是小。咱們能夠安全地刪除此列。這就是咱們應用低方差過濾器的方法。讓咱們在Python中實現這個:
numeric = train[['Item_Weight', 'Item_Visibility', 'Item_MRP', 'Outlet_Establishment_Year']]
var = numeric.var()
numeric = numeric.columns
variable = [ ]
for i in range(0,len(var)):
if var[i]>=10: #將閾值設置爲10%
variable.append(numeric[i+1])
上面的代碼爲咱們提供了方差大於10的變量列表。
兩個變量之間的高度相關意味着它們具備類似的趨勢,而且可能攜帶相似的信息。這能夠大大下降某些模型的性能(例如線性迴歸和邏輯迴歸模型)。咱們能夠計算出本質上是數值的獨立數值變量之間的相關性。若是相關係數超過某個閾值,咱們能夠刪除其中一個變量(丟棄一個變量是很是主觀的,而且應該始終記住該變量)。
做爲通常準則,咱們應該保留那些與目標變量顯示出良好或高相關性的變量。
讓咱們在Python中執行相關計算。咱們將首先刪除因變量(ItemOutletSales)並將剩餘的變量保存在新的DataFrame(df)中。
df=train.drop('Item_Outlet_Sales', 1)
df.corr()
太棒了,咱們的數據集中沒有任何具備高相關性的變量。一般,若是一對變量之間的相關性大於0.5-0.6,咱們真的應該認真的考慮丟棄其中的一個變量。
隨機森林是最普遍使用的特徵選擇算法之一。它附帶內置的重要功能,所以你無需單獨編程。這有助於咱們選擇較小的特徵子集。
咱們須要經過應用一個熱編碼將數據轉換爲數字形式,由於隨機森林(Scikit-Learn實現)僅採用數字輸入。讓咱們也刪除ID變量(Item_Identifier和Outlet_Identifier),由於這些只是惟一的數字,目前對咱們來講並不重要。
from sklearn.ensemble import RandomForestRegressor
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)
擬合模型後,繪製特徵重要性圖:
features = df.columns
importances = model.feature_importances_
indices = np.argsort(importances)[-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()
基於上圖,咱們能夠手動選擇最頂層的特徵來減小數據集中的維度。值得注意的是,咱們可使用sklearn的SelectFromModel來實現這一點。它根據權重的重要性來選擇特徵。
from sklearn.feature_selection import SelectFromModel
feature = SelectFromModel(model)
Fit = feature.fit_transform(df, train.Item_Outlet_Sales)
按照如下步驟來理解和使用「反向特徵消除」技術:
在構建線性迴歸或邏輯迴歸模型時,可使用此方法。咱們來看看它的Python實現:
from sklearn.linear_model import LinearRegression
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)
咱們須要指定算法和要選擇的特徵數量,並返回從反向特徵消除中得到的變量列表。咱們還可使用「 rfe.ranking」命令檢查變量的排名。
這與咱們在上面看到的反向特徵消除的過程相反。咱們是嘗試找到改善模型性能的最佳特徵,而不是消除特徵。該技術的工做原理以下:
讓咱們用Python實現它:
from sklearn.feature_selection import f_regression
ffs = f_regression(df,train.Item_Outlet_Sales )
這將返回一個數組,其中包含變量的F值和與每一個F值對應的p值。爲了咱們的目的,咱們將選擇F值大於10的變量:
variable = [ ]
for i in range(0,len(df.columns)-1):
if ffs0 >=10:
variable.append(df.columns[i])
這爲咱們提供了基於正向特徵選擇算法的最多變量。
注意:反向特徵消除和正向特徵選擇都是很是耗時且計算成本高的。它們實際上僅用於具備少許輸入變量的數據集。
到目前爲止咱們看到的技術一般在咱們的數據集中沒有太多變量時使用。這些或多或少的特徵選擇技術,在接下來的部分中,咱們將使用Fashion MNIST數據集,該數據集包含屬於不一樣類型服裝的圖像,例如T恤,褲子,包等。數據集可點擊此處下載,提取碼爲:a708。
該數據集共有70,000張圖像,其中60,000張在訓練集中,其他10,000張是測試圖像。在本文的範圍中,咱們將僅處理訓練圖像。訓練集文件採用zip格式。解壓縮zip文件後,你將得到一個.csv文件和一個包含這60,000張圖像的訓練集文件夾。每一個圖像的相應標籤能夠在'train.csv'文件中找到。
假設咱們有兩個變量:收入和教育。這些變量可能具備高度相關性,由於具備較高教育水平的人每每具備顯着較高的收入,反之亦然。
在因子分析技術中,變量按其相關性進行分組,即特定組內的全部變量之間具備高度相關性,但每每與其餘組的變量之間相關性較低。在這裏,每一個組都被稱爲一個因子。與原始數據維度相比,這些因子的數量不多。可是,這些因子每每很難觀察到。
讓咱們先讀入訓練集文件夾中包含的全部圖像:
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函數內的路徑。
如今咱們將這些圖像轉換爲 numpy數組格式,以便咱們能夠執行數學運算並繪製圖像。
images = np.array(images)
images.shape
(60000,28,28,3)
如上所示,它是一個三維數組。咱們必須將它轉換爲一維的,由於全部即將出現的技術只須要一維輸入。爲此,咱們須要展平圖像:
image = []
for i in range(0,60000):
img = images[i].flatten()
image.append(img)
image = np.array(image)
如今讓咱們建立一個DataFrame,其中包含每一個圖像中每一個像素的像素值,以及它們對應的標籤(對於標籤,咱們將使用train.csv文件)。
train = pd.read_csv("train.csv") # 給出你的train.csv文件的完整路徑
feat_cols = [ 'pixel'+str(i) for i in range(image.shape[1]) ]
df = pd.DataFrame(image,columns=feat_cols)
df['label'] = train['label']
如今咱們將使用因子分析來分解數據集:
from sklearn.decomposition import FactorAnalysis
FA = FactorAnalysis(n_components = 3).fit_transform(df[feat_cols].values)
這裏,n_components將決定轉換數據中的因子數量。轉換數據後,是時候可視化結果了:
%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軸表示分解因子的值。正如我前面提到的,很難單獨觀察這些因素,但咱們已經可以成功地減小數據的維度。
PCA是一種技術,能夠幫助咱們從現有的大量變量中提取一組新的變量。這些新提取的變量稱爲主成分。爲了便於你快速學習PCA降維,如下是你在進一步處理以前應該瞭解的關於PCA的一些要點:
在繼續以前,咱們將從咱們的數據集中隨機繪製一些圖像:
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))
讓咱們使用Python實現PCA降維並轉換數據集:
from sklearn.decomposition import PCA
pca = PCA(n_components=4)
pca_result = pca.fit_transform(df[feat_cols].values)
在這種狀況下,n_components將決定轉換數據中的主要成分的數量。讓咱們看一下使用這4個成分解釋了多少差別。咱們將使用explainvarianceratio_來計算相同的內容。
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")
在上圖中,藍線表示按成分解釋的方差,而橙線表示累積解釋的方差。咱們只用四個組件就能夠解釋數據集中大約60%的方差變化。如今讓咱們嘗試可視化每一個分解的成分:
import seaborn as sns
plt.style.use('fivethirtyeight')
fig, axarr = plt.subplots(2, 2, figsize=(12, 8))
sns.heatmap(pca.components_[0, :].reshape(28, 84), ax=axarr0, cmap='gray_r')
sns.heatmap(pca.components_[1, :].reshape(28, 84), ax=axarr0, cmap='gray_r')
sns.heatmap(pca.components_[2, :].reshape(28, 84), ax=axarr1, cmap='gray_r')
sns.heatmap(pca.components_[3, :].reshape(28, 84), ax=axarr1, cmap='gray_r')
axarr0.set_title(
"{0:.2f}% Explained Variance".format(pca.explained_variance_ratio_[0]*100),
fontsize=12
)
axarr0.set_title(
"{0:.2f}% Explained Variance".format(pca.explained_variance_ratio_[1]*100),
fontsize=12
)
axarr1.set_title(
"{0:.2f}% Explained Variance".format(pca.explained_variance_ratio_[2]*100),
fontsize=12
)
axarr1.set_title(
"{0:.2f}% Explained Variance".format(pca.explained_variance_ratio_[3]*100),
fontsize=12
)
axarr0.set_aspect('equal')
axarr0.set_aspect('equal')
axarr1.set_aspect('equal')
axarr1.set_aspect('equal')
plt.suptitle('4-Component PCA')
咱們添加到PCA技術中的每一個額外維度獲取模型中的方差愈來愈少。第一個部分是最重要的成分,其次是第二個成分,而後是第三個成分,依此類推。
咱們還可使用奇異值分解 (SVD)將咱們的原始數據集分解爲其成分,從而減小維數。
SVD將原始變量分解爲三個組成矩陣。它主要用於從數據集中刪除冗餘的特徵。它使用特徵值和特徵向量的概念來肯定這三個矩陣。因爲本文的範圍,咱們不會深刻研究它的理論,但讓咱們堅持咱們的計劃,即減小數據集中的維度。
讓咱們實現SVD並分解咱們的原始變量:
from sklearn.decomposition import TruncatedSVD
svd = TruncatedSVD(n_components=3, random_state=42).fit_transform(df[feat_cols].values)
讓咱們經過繪製前兩個主成分來可視化變換後的變量:
plt.figure(figsize=(12,8))
plt.title('SVD Components')
plt.scatter(svd[:,0], svd[:,1])
plt.scatter(svd[:,1], svd[:,2])
plt.scatter(svd[:,2],svd[:,0])
上面的散點圖很是清晰地向咱們展現了分解的成分。如前所述,這些組件之間沒有太多相關性。
獨立成分分析(ICA)是基於信息理論的,也是最普遍使用的降維技術之一。PCA和ICA之間的主要區別在於PCA尋找不相關的因素,而ICA尋找獨立因素。
若是兩個變量不相關,則意味着它們之間沒有線性關係。若是它們是獨立的,則意味着它們不依賴於任何其餘變量。例如,一我的的年齡與該人吃什麼或他/她看多少電視無關。
該算法假設給定變量是一些未知潛在變量的線性混合。它還假設這些潛在變量是相互獨立的,即它們不依賴於其餘變量,所以它們被稱爲觀察數據的獨立成分。
讓咱們直觀地比較一下PCA和ICA,以便更好地瞭解它們的不一樣之處:
這裏,圖像(a)表示PCA結果,而圖像(b)表示相同數據集上的ICA結果。
PCA的方程是x = W x。
如今咱們必須找到一個非混合矩陣,使成分儘量的獨立。測量成分獨立性的最經常使用方法是非高斯性:
上述分佈是非高斯分佈,這又使得各成分互相獨立。讓咱們嘗試在Python中實現ICA:
from sklearn.decomposition import FastICA
ICA = FastICA(n_components=3, random_state=12)
X=ICA.fit_transform(df[feat_cols].values)
這裏,n_components將決定轉換數據中的成分數量。咱們使用ICA將數據轉換爲3個成分。讓咱們看看它是如何改變數據的:
plt.figure(figsize=(12,8))
plt.title('ICA Components')
plt.scatter(X[:,0], X[:,1])
plt.scatter(X[:,1], X[:,2])
plt.scatter(X[:,2], X[:,0])
數據已經被分紅不一樣的獨立成分,在上圖中能夠很是清楚地看到。X軸和Y軸表示分解的獨立成分的值。
如今咱們將看到一些使用投影技術來減小數據維度的方法。
首先,咱們須要瞭解投影是什麼。假設咱們有兩個向量,矢量a和矢量b,以下所示:
咱們想求a在b上的投影。那麼設a和b之間的角度爲∅。投影(a1)看起來像:
a1是與b平行的向量。所以,咱們可使用如下等式獲得向量a在向量b上的投影:
經過將一個矢量投影到另外一個矢量上,能夠下降維度。
在投影技術中,能夠經過將其點投影到較低維空間來表示多維數據。如今咱們將討論不一樣的預測方法:
曾幾什麼時候,人們認爲地球是平的。不管你去哪裏,它都會保持平坦(讓咱們暫時忽視山脈)。可是,若是你繼續向一個方向走,那麼你最終會走向何方。若是地球是平坦的,那這就不會發生。地球只是看起來比較平坦,那是由於咱們看到的與地球相比是微不足道的。
地球看起來平坦的這些小部分是多方面的,若是咱們將全部這些方面組合在一塊兒,咱們就能夠得到地球的大尺度視圖,也就是原始數據。相似地,對於n維曲線,小的平面快是流形,而且這些流形的組合將給出咱們原始的n維曲線。讓咱們看看投影到流形上的步驟:
讓咱們經過一個例子來理解流形投影技術。
若是一個流形連續可微縮到任意階,則稱爲平滑流形或可微分流形。ISOMAP是一種旨在恢復非線性流形的完整低維表示的算法。它假設流形是平滑的。
它還假設對於流形上的任何一對點,兩點之間的測地距離(曲面上兩點之間的最短距離)等於歐幾里德距離(直線上兩點之間的最短距離)。讓咱們首先形象化一對點之間的測地線和歐幾里德距離:
ISOMAP假設這兩個距離相等。如今讓咱們看一下這種技術更詳細的解釋。如前所述,全部這些技術都採用三步法。咱們將詳細介紹這些步驟:
讓咱們用Python實現它,這樣就更清楚的理解我在說什麼了。咱們將經過等距映射進行非線性降維。對於可視化,咱們將只採用數據集的一個子集,由於在整個數據集上運行它將須要花費大量時間。
from sklearn import manifold
trans_data = manifold.Isomap(n_neighbors=5, n_components=3, n_jobs=-1).fit_transform(dffeat_cols.values)
使用的參數:
可視化轉換後的數據:
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])
你能夠在上面看到這些成分之間的相關性很是低。實際上,與咱們以前使用SVD得到的成分相比,它們的相關性更小!
到目前爲止,咱們已經瞭解到PCA對於具備大量變量的數據集的降維和可視化是一個很好的選擇。可是,若是咱們可使用更高級的東西呢?若是咱們能夠輕鬆地以非線性方式搜索呢?t-SNE就是這樣一種技術。咱們可使用兩種方法來映射數據點:
xi和xj是數據點,|| xi-xj || 表示這些數據點之間的歐幾里德距離,σi是高維空間中數據點的方差
其中:|| yi-yj || 表示yi和yj之間的歐幾里德距離
如今咱們將用Python實現它,並將結果可視化:
from sklearn.manifold import TSNE
tsne = TSNE(n_components=3, n_iter=300).fit_transform(dffeat_cols.values)
n_components將決定轉換數據中的成分數量。是時候查看可視化轉換後的數據:
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])
在這裏,你能夠清楚地看到使用強大的t-SNE技術轉換的不一樣成分。
t-SNE在大型數據集上工做表現很好,但它也有它的侷限性,例如丟失大型的信息,計算時間慢,沒法有意義地表示很是大的數據集。統一流形近似和投影(UMAP)是一種降維技術,與t-SNE相比,能夠保留儘量多的本地數據結構和全局數據結構,而且運行時間更短。聽起來頗有趣,對吧。
UMAP的一些主要優點是:
該方法使用k-近鄰的概念,並使用隨機梯度降低來優化結果。它首先計算高維空間中的點之間的距離,將它們投影到低維空間,並計算該低維空間中的點之間的距離。而後,它使用隨機梯度降低來最小化這些距離之間的差別。
咱們如今將在Python中實現它:
import umap
umap_data = umap.UMAP(n_neighbors=5, min_dist=0.3, n_components=3).fit_transform(dffeat_cols.values)
讓咱們可視化一下這個變換:
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])
維度已經減小了,咱們能夠想象不一樣的變換成分。變換後的變量之間的相關性很是小。讓咱們比較UMAP和t-SNE的結果:
咱們能夠看到,與從t-SNE得到的成分之間的相關性相比,從UMAP得到的成分之間的相關性很是小。所以,UMAP傾向於提供更好的結果。
正如UMAP的GitHub代碼庫中所提到的,與t-SNE相比,它在保留數據全局結構方面的表現更好。這意味着它一般能夠提供更好的「全局」數據視圖以及保留本地鄰居關係。
深呼吸。咱們已經學習了至關多的降維技術。讓咱們簡要總結一下在那裏可使用它們。
在本節中,咱們將簡要總結咱們所涵蓋的每種降維技術的使用案例。瞭解在什麼地方可使用什麼樣的技術,由於它有助於節省時間,精力和計算能力。
這是一篇關於降維的全面文章,你能夠在任何地方用到它!在編寫過程當中我得到了不少的樂趣,並找到了一些我以前歷來沒用使用過的新方法(好比UMAP)。
處理成千上萬的特徵是任何數據科學家必備的技能。咱們天天生成的數據量是史無前例的,咱們須要找到不一樣的方法來肯定如何使用它。降維是一種很是有用的方法,對我來講,不管是在專業的應用中,仍是在機器學習的比賽中,它都產生了奇妙的效果。
The Ultimate Guide to 12 Dimensionality Reduction Techniques (with Python codes)