跳至主要內容

    PCA:把資料壓縮時保留了什麼?

    從中心化、投影與重建誤差,分清變異、尺度和預測訊號

    sunny 桑尼· · 24 MIN READ · 102 次瀏覽

    PCA:把資料壓縮時保留了什麼?
    本文目錄

    資料有一百個欄位,不代表一百個方向都有同樣多的新資訊。某些欄位一起變動,資料可能大多集中在少數方向附近。PCA嘗試用較少的新座標描述它,同時讓保留下來的變異盡可能多。

    這裡的「多」有明確範圍:在選定尺度下,保留較多平方距離所描述的變化。它不是自動挑出最能預測y的欄位,也不是壓縮後仍保證分類準確。先弄清它的目標,才知道「保留95%」到底承諾了什麼。

    點看起來有三維,主要變化可能在一個平面附近

    圖1|同一組三維點雲與前兩主成分張成的平面,兩張只換觀看角度,不是投影前後、兩批資料或兩輪訓練。來源產生30,000筆,畫圖每10筆取1筆;顏色由生成密度函數計算,不是類別。來源:Gael Varoquaux、Jaques Grobler、Kevin Hughes/The scikit-learn developers,0.22版Principal components analysis原例,BSD-3-Clause;兩張完整原圖左右排,手機上下排。

    想像一張紙斜放在房間裡:每個位置都能寫成三個座標,但描述紙面上的相對位置,通常兩個座標已經足夠。真實資料可能有厚度,PCA保留平面附近的大變化,捨去較薄的方向時仍會留下誤差。

    「較薄」不是沒有價值的同義詞。若你的任務剛好需要辨認紙面上下的一點差異,刪掉那個方向就可能刪掉答案需要的訊號。

    從原始欄位換成主成分,並非只挑幾欄留下

    圖2|150朵Iris的四個特徵:花萼長、花萼寬、花瓣長、花瓣寬。非對角線是特徵兩兩散點,對角線是各欄分布,顏色是已知種類,僅供看圖。來源:The scikit-learn developers,Principal Component Analysis on Iris Dataset,BSD-3-Clause;桌機原圖未改,手機保留全圖並放大其中一格與類別圖例。

    兩個欄位若高度相關,可以想像它們共同沿某個方向變動。PCA建立的是原始欄位的線性組合,例如某個新座標同時使用多個長度與寬度。這和特徵選擇直接刪掉幾欄不同。

    圖3|原例將四個特徵轉成三個主成分,未先做StandardScaler;顏色和圖例依真實種類標示,PCA.fit_transform只讀iris.data,沒有把種類當成學習目標。各軸原圖刻意不顯示數字刻度。來源及BSD-3-Clause授權同圖2,原圖未改;此圖不證明所有種類只用一個PC便能完全分類。

    主成分依解釋的變異量排序。第一個方向在單位長度條件下讓投影變異最大;下一個方向與前面方向正交,再保留剩下盡可能多的變異。正交與不相關不等於任何分布下都統計獨立,也不會讓PC1自動成為「最重要的業務因素」。

    先中心化,再找方向

    令X每列是一筆樣本、每欄是一個特徵。訓練平均向量是μ,先算Xc=X−μ。對一個單位方向u,把每筆投影到它上面,得到分數Xc u。

    樣本共變異數 C = Xcᵀ Xc / (n−1)
    方向u上的樣本變異 = uᵀ C u,限制 ||u||=1
    

    最大化這個量,會得到C最大特徵值對應的方向;後續取正交方向。實作通常直接對中心化矩陣做SVD,不必先顯式形成共變異數矩陣。

    Xc = U Σ Vᵀ
    取前k個方向Vk:Z = Xc Vk
    重建:X̂ = Z Vkᵀ + μ
    

    Vk的每一欄是一個方向;sklearn的components_把這些方向逐列儲存。Z才是各筆資料在新方向上的座標。不要把方向權重、投影分數與解釋變異比例都叫成同一個「PCA分數」。

    若把某方向乘−1、同時把該軸分數乘−1,重建不會改變。不同版本或演算法讓軸符號翻轉,不必然代表找到了不同結構;重複特徵值時,同一子空間內也可能有不同的正交基底。

    四個點,手算80%與重建誤差

    取四點(12,22)、(8,18)、(11,19)、(9,21),平均為(10,20)。中心化後是(2,2)、(−2,−2)、(1,−1)、(−1,1)。

    C = [[10/3, 2],
         [2, 10/3]]
    
    第一方向 u1 = (1,1)/√2,變異 λ1=16/3
    第二方向 u2 = (1,−1)/√2,變異 λ2=4/3
    第一PC解釋比例 = (16/3)/(20/3) = 0.8
    

    只保留第一PC,四筆分數是2√2、−2√2、0、0。加回平均後,重建成(12,22)、(8,18)、(10,20)、(10,20),最後兩點無法分開了。

    誤差定義本例

    所有點、所有欄的平方誤差總和SSE
    4
    SSE除以4筆
    1
    SSE除以4筆×2欄,即逐元素MSE
    0.5

    這些數字都能描述誤差,但分母不同,不能混用。在這個固定資料、平方距離與線性正交投影的問題裡,前k個PC提供最小重建SSE的k維子空間;它不是對所有非線性壓縮、所有新資料或所有任務都最佳的保證。

    中心化、標準化與白化,是三個不同動作

    圖4|來源Wine資料,首PC在未縮放時幾乎由proline主導;標準化後,其他欄位也有明顯權重。藍與橘是兩種前處理,不是兩個類別。來源:The scikit-learn developers,Importance of Feature Scaling,BSD-3-Clause;原圖未改。正負號可整軸翻轉,不能用它直接判斷特徵好壞。

    sklearn標準PCA會減去各欄平均,但預設不除以各欄標準差。如果某欄只因單位比較大而有很大變異,它可能主導主成分。先做StandardScaler會重新分配尺度的影響,但也可能放大原本變異很小的雜訊欄。

    圖5|兩邊皆為來源訓練資料的前兩PC,但前處理、方向與座標尺度不同,不能直接拿橫軸數字互比。此例Wine先分70% train/30% test,種子42,Scaler只fit train;顏色依種類供觀察,不是PCA用來擬合的目標。來源及BSD-3-Clause授權同圖4,原圖未改,手機左右完整面板上下排。

    白化whiten=True則在主成分座標上,依每個方向的變異分別縮放,使訓練投影各軸具有單位變異。它不是只旋轉,也不是把所有軸乘相同常數。它可能適合某些下游模型的幾何假設,但會改變各軸原本的相對變異尺度。

    是否做這些處理,要看單位、雜訊與任務。訓練時選定的平均、Scaler與PCA方向,都應用相同版本套到新資料;不能在新批次重算平均後,卻繼續沿用舊方向當成同一轉換。

    保留95%變異,沒有保證保留95%分類能力

    解釋變異比例是某個PC的變異,除以所有方向的總變異;累積比例才是把前幾個比例加起來。四點例中,第一PC為80%,前兩PC累積100%。依樣本共變異數的定義,丟掉方向的訓練重建SSE為(n−1)乘上其特徵值總和,本例3×4/3=4。

    如果最後兩點有不同標籤,只留PC1時它們都投成0,下游分類器便無法靠這個座標分開它們。這是「保留很多變異,仍可能丟掉決策訊號」的具體情境。PCA不看y,因此不會替你保護某個低變異卻重要的方向。

    圖6|上半是每個主成分各自的explained variance ratio,並非累積曲線;下半是不同保留維度對應的分類CV accuracy,誤差棒為fold分數標準差。依來源程式,上半另外用未縮放全Digits fit PCA,下半搜尋則是Scaler、PCA、LogisticRegression的Pipeline,所以兩塊不能當同一個PCA座標下的直接對應;虛線是搜尋選出的維度,不是95%累積門檻。來源:The scikit-learn developers,Pipelining: chaining a PCA and a logistic regression,BSD-3-Clause;原圖未改,本站沒有重跑來源完整搜尋。

    如果目的是預測,維度與前處理應放進交叉驗證的選擇流程,並和不用PCA的基準模型比較。若先用全資料含test fit PCA,即使沒把y交給它,測試分布仍已參與建立方向;不能因此宣稱保留測試完全未參與。

    非線性結構,並不會只靠換線性座標解開

    圖7|來源1,000筆make_circles,factor=.3、noise=.05、seed=0,分成750 train/250 test並依類別分層。兩種顏色標示內外圈;顏色不表示PCA使用了標籤。來源:The scikit-learn developers,Kernel PCA,BSD-3-Clause;原圖未改,手機兩完整面板上下排,右圖沿用左圖的共用y軸尺度。

    兩個同心圓,不能只靠一條直線把內外圈分開。標準PCA仍是線性轉換,不能因為畫出新的PC軸,就把這個問題自動變成線性可分。

    圖8|左原測試點,中PCA保留兩個原維度,右是RBF KernelPCA輸出中的前兩軸,gamma=10。來源KernelPCA用n_components=None,不代表整個轉換只有兩個維度;畫圖只取前兩欄。來源及BSD-3-Clause授權同圖7;原圖未改,手機依左、中、右完整面板上下排;中、右圖的原y軸文字移到白邊,避免帶入鄰圖邊框,未重寫刻度或資料。

    Kernel PCA先以核函數表達非線性的相似關係,再在對應特徵空間做主成分分析。本例右圖更能把內外圈展成不同區域,但依賴核與參數,不是保證所有資料都更有用。

    這個對照也不表示標準PCA預設把每個PC縮成單位變異。本文沿用實際PCA API:未設定whiten時,中心化加方向轉換,不自動逐軸白化。來源說明中的直觀措辭不能替代其程式參數。

    逆轉換能做什麼,要看保留了哪些座標

    圖9|標準PCA在此保留原本兩維的全部兩軸,因此線性逆轉換可重建原點,並非丟掉一維後仍完全復原。KernelPCA開啟fit_inverse_transform,alpha=.1,以學得的逆映射近似重建,使用的是完整transform結果,並非只用圖8右側畫出的兩欄。來源及BSD-3-Clause授權同圖7;原圖未改,手機三面板上下排,後兩圖沿用第一圖的共用y軸尺度。

    標準PCA若只留部分方向,inverse_transform會補回訓練平均,再用保留下來的座標重建;捨去的分量無法憑空復原。若保留完整的正交基底,則可逆轉回原座標,差異主要來自數值精度。

    Kernel PCA原例的逆轉換需要另學一個從核座標回到原特徵的映射,帶有近似與正則化。不要拿圖9的KernelPCA重建誤差,當成圖中標準PCA已降低維度的損失;兩件事的來源不同。

    實跑:先驗四點,再用訓練方向處理新資料

    下方程式在WSL、Python 3.10.12、NumPy 1.26.3、scikit-learn 1.5.1實跑。第一段驗四點的方向與重建;第二段用Digits每張8×8影像的64個像素特徵,保留25%樣本作最後重建評估。

    這次像素都使用原本相同的強度單位,因此不做逐像素StandardScaler,讓誤差仍以原像素空間計算。類別只用來分層切分,PCA擬合不讀標籤;95%門檻事先固定,沒有依test誤差反覆調整。

    存成pca_projection.py後執行:

    python -m pip install numpy==1.26.3 scikit-learn==1.5.1
    python pca_projection.py
    
    import numpy as np
    import sklearn
    from sklearn.decomposition import PCA
    from sklearn.datasets import load_digits
    from sklearn.model_selection import train_test_split
    from threadpoolctl import threadpool_limits
    
    X = np.array([[12.0, 22.0], [8.0, 18.0],
                  [11.0, 19.0], [9.0, 21.0]])
    centered = X - X.mean(axis=0)
    covariance = centered.T @ centered / (len(X) - 1)
    u = np.array([1.0, 1.0]) / np.sqrt(2.0)
    scores = centered @ u
    reconstructed = scores[:, None] * u + X.mean(axis=0)
    with threadpool_limits(limits=1):
        full = PCA(n_components=2, svd_solver="full").fit(X)
        one = PCA(n_components=1, svd_solver="full").fit(X)
        one_reconstructed = one.inverse_transform(one.transform(X))
        print(f"numpy={np.__version__} sklearn={sklearn.__version__}")
        print(f"toy mean={X.mean(axis=0).tolist()}")
        print("toy covariance=" + np.array2string(covariance, precision=6))
        print("toy explained_variance=" +
              ",".join(f"{v:.6f}" for v in full.explained_variance_))
        print("toy explained_ratio=" +
              ",".join(f"{v:.6f}" for v in full.explained_variance_ratio_))
        print("toy scores_on_positive_diagonal=" +
              ",".join(f"{v:.6f}" for v in scores))
        print(f"toy reconstructed={reconstructed.round(6).tolist()}")
        print(f"toy rank1_SSE={np.square(X - one_reconstructed).sum():.6f}")
        print(f"toy entrywise_MSE={np.square(X - one_reconstructed).mean():.6f}")
        print(f"toy direct_and_sklearn_reconstruction_match="
              f"{np.allclose(reconstructed, one_reconstructed)}")
    
        # All pixel features share the same original intensity units.
        # Labels are used only for a stratified split, never for fitting PCA.
        digits, labels = load_digits(return_X_y=True)
        train, test = train_test_split(
            np.arange(len(digits)), test_size=0.25,
            stratify=labels, random_state=42,
        )
        model = PCA(n_components=0.95, svd_solver="full").fit(digits[train])
        train_back = model.inverse_transform(model.transform(digits[train]))
        test_back = model.inverse_transform(model.transform(digits[test]))
        print(f"digits train={len(train)} test={len(test)} original_features=64 "
              f"retained_components={model.n_components_}")
        print(f"digits train_explained_ratio_sum="
              f"{model.explained_variance_ratio_.sum():.6f}")
        print(f"digits train_pixel_MSE={np.square(digits[train] - train_back).mean():.6f}")
        print(f"digits test_pixel_MSE={np.square(digits[test] - test_back).mean():.6f}")
        print(f"digits mean_fit_on_train_only="
              f"{np.allclose(model.mean_, digits[train].mean(axis=0))}")
    

    四點的實際結果與手算吻合:兩方向變異5.333333、1.333333,比例0.8、0.2;只保留一軸的SSE=4、逐元素MSE=0.5。工具若選到相反軸符號,分數可整組反號,但逆轉換結果仍相同。

    Digits項目實測結果

    訓練/測試筆數
    1,347/450
    原始像素維度
    64
    由train的95%門檻選出的維度
    29
    train實際累積解釋比例
    0.954944
    train逐像素MSE
    0.842019
    test逐像素MSE
    0.897382

    保留29維時跨過95%門檻,所以實際比例不是剛好0.95。這是訓練分布上的比例;不代表每張新圖都保留95%的「內容」,也不代表test的分類accuracy已被驗證。本篇沒有訓練Digits分類器,沒有把重建MSE包裝成分類成效。

    新資料使用同一個模型的transform與inverse_transform,不能先對新資料重新fit方向再宣稱測試的是原模型。要選維度時,先說清楚你的判準是重建、儲存、可視化或下游預測,再用對應的保留資料與成本驗證,而不是把一個常見百分比當所有任務的答案。

    原始來源、配圖與授權

    依據sklearn PCA原理、0.22幾何原例、Iris PCA、Feature Scaling、Digits Pipeline與Kernel PCA。查核日2026-10-31。線上1.5系列目前頁面標1.5.2、stable原例可能更晚;本站固定實跑1.5.1,未照抄新版Pipeline依賴或冒稱重跑所有來源圖。

    圖1採Gael Varoquaux、Jaques Grobler、Kevin Hughes/The scikit-learn developers的舊官方原圖;圖2–9採The scikit-learn developers官方原例圖,均依各來源BSD-3-Clause使用,完整聲明附於文末。沒有把Jake教材的程式授權當成其圖像可改作的許可。

    封面取圖1的兩個完整視角等比縮放加白邊;手機圖1把兩原圖上下排,圖2保留完整矩陣並放大選定面板及原類別圖例,圖5與圖7–9完整面板按原左到右順序上下排,不改資料、軸或顏色。相關共用刻度由各圖說交代,未暗示原作者背書。四點算例及Digits保留測試的程式是本站新增教學設計,和來源實驗分開。

    BSD-3-Clause-current.txt 原始完整聲明

    BSD 3-Clause License
    
    Copyright (c) 2007-2026 The scikit-learn developers.
    All rights reserved.
    
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    
    * Redistributions of source code must retain the above copyright notice, this
      list of conditions and the following disclaimer.
    
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    
    * Neither the name of the copyright holder nor the names of its
      contributors may be used to endorse or promote products derived from
      this software without specific prior written permission.
    
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    

    BSD-3-Clause-0.22-COPYING.txt 原始完整聲明

    New BSD License
    
    Copyright (c) 2007–2019 The scikit-learn developers.
    All rights reserved.
    
    
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    
      a. Redistributions of source code must retain the above copyright notice,
         this list of conditions and the following disclaimer.
      b. Redistributions in binary form must reproduce the above copyright
         notice, this list of conditions and the following disclaimer in the
         documentation and/or other materials provided with the distribution.
      c. Neither the name of the Scikit-learn Developers  nor the names of
         its contributors may be used to endorse or promote products
         derived from this software without specific prior written
         permission.
    
    
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
    ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
    DAMAGE.
    

    留言0

    登入後就能留言。

    登入
    sunny 桑尼
    sunny 桑尼

    AI 資料科學 · 產品經理 · 蒙奇 D 桑尼

    專注於 AI 工具應用與資料科學教育,致力於讓每個人都能用 AI 提升工作效率。曾任職於科技業,現為全職教育創作者。

    讀更多文章 →想自己動手試?領免費 Starter Kit →