public PCA(double[] mu, double[] eigvalues, Matrix loadings, Matrix projection, String... columns) {
        super(projection, "PCA", columns);

        this.mu = mu;
        this.eigvalues = eigvalues;
        this.eigvectors = loadings;

        proportion = eigvalues.clone();
        MathEx.unitize1(proportion);

        cumulativeProportion = new double[eigvalues.length];
        cumulativeProportion[0] = proportion[0];
        for (int i = 1; i < eigvalues.length; i++) {
            cumulativeProportion[i] = cumulativeProportion[i - 1] + proportion[i];
        }

        pmu = projection.mv(mu);
    }
@Test
    public void testPCA() {
        System.out.println("learn");
        double[] prop = {0.9655342, 0.02781734, 0.005799535, 0.0008489079};
        double[] cumprop = {0.9655342, 0.99335156, 0.999151092, 1.0000000000};
        double[][] loadings = {
            {-0.0417043206282872, -0.0448216562696701, -0.0798906594208108, -0.994921731246978},
            {-0.995221281426497, -0.058760027857223, 0.0675697350838043, 0.0389382976351601},
            {-0.0463357461197108, 0.97685747990989, 0.200546287353866, -0.0581691430589319},
            {-0.075155500585547, 0.200718066450337, -0.974080592182491, 0.0723250196376097}
        };
        double[][] points = {
            {-64.8021636817436, -11.4480073977837, 2.49493284038366, -2.40790093375486},
            {-92.8274501566946, -17.9829427006718, -20.1265748735977, 4.09404703053042},
            {-124.068216289648, 8.83040304270359, 1.68744835668708, 4.35368520359609},
            {-18.3400354054072, -16.7039113810096, -0.210189364140469, 0.520993603601999},
            {-107.422953125475, 22.5200697704229, -6.74587299235952, 2.81182590291373},
            {-34.9759859594071, 13.7195840329554, -12.2793628034841, 1.72146370000854},
            {60.8872819318546, 12.9325301564357, 8.42065718885695, 0.699902287100493},
            {-66.7310254465241, 1.35379779717711, 11.2809573450628, 3.72798119075026},
            {-165.244370319248, 6.27469006959416, 2.99793314838690, -1.24768071379144},
            {-40.5351765876529, -7.29023959219438, -3.60952945561059, -7.34367284165603},
            {123.536105769847, 24.291207910916, -3.72444284008562, -3.47284940369505},
            {51.7970022509676, -9.46919099467921, 1.52006355638492, 3.347828326557},
            {-78.9920972971611, 12.8970604614357, 5.88326476858706, -0.36764073849423},
            {57.5509607347644, 2.84626471235194, -3.73816048848585, -1.64943016073772},
            {115.586789703854, -3.34213050228539, 0.654029354180591, 0.869495984279686},
            {55.7896941123023, 3.15723392471998, -0.384364163111931, -0.65279168994279},
            {62.383180611208, -10.6732714680385, -2.23708902971565, -3.87621641192646},
            {-78.2776313152135, -4.29491749799139, 3.82786965239577, -4.48355899807498},
            {89.2610442661687, -11.4878272008390, 4.69240561590091, 2.11619948317566},
            {-129.330135502788, -5.00703147597233, 2.34717281642702, 1.92832424634248},
            {21.2662826315275, 19.4501790329282, 7.5071483512444, 1.03481894814417},
            {-85.4515266722104, 5.90455669704365, -6.46434210133595, -0.499047890295277},
            {98.9548155235302, 5.20960058227443, -0.00657375986111987, 0.731895663983765},
            {-86.8563576862984, -27.4284196328667, 5.00343623998489, -3.87975768645157},
            {-7.98628866990333, 5.27564139833892, -5.50057972194064, -0.67940550460075},
            {62.4836353013543, -9.51050205328579, -1.83835536172303, -0.245942647407812},
            {69.096544351272, -0.211195916792749, -0.468020859327737, 0.656566426699305},
            {-83.6135784392142, 15.1021838986663, -15.8886948158415, -0.334196243688033},
            {114.777354501664, -4.73455836403614, 2.28238693378110, 0.935910562750778},
            {10.815725119435, 23.1373388713124, 6.31015739277925, -1.61242729238686},
            {-114.86816260433, -0.336453098274837, -2.26126996009524, 1.38124776395531},
            {-84.2942305183222, 15.9239655420362, 4.72125960088988, -0.89201935012913},
            {-164.325514489152, -31.0966152578345, 11.6961635002625, 2.11119273326001},
            {127.495596550323, -16.1350393817083, 1.31182982457759, 2.30096391525437},
            {50.0868216712847, 12.2793243774034, -1.65733077217564, -2.02911567315058},
            {19.6937228951609, 3.3701310208186, 0.453143294595288, 0.180345739332141},
            {11.1502395794911, 3.8660681516975, -8.12998049836994, 2.91401088922199},
            {64.6891419240492, 8.91154655201737, 3.20646858319651, -1.87493530726351},
            {-3.06397257106163, 18.3739704209844, 17.4700196999280, 2.30825967705141},
            {-107.281068657401, -23.5361158958813, 2.03279501430637, -1.25174625682114},
            {86.1067200506117, -16.5978586472767, -1.31437998489870, 1.25228738950292},
            {-17.5062642727291, -6.50657560196015, -6.10012753172529, -3.9228557513671},
            {-31.2911217386536, 12.984956649108, 0.393409217561249, -4.24200404821675},
            {49.9133974043838, 17.6484576673340, -1.78816852005472, 1.86770523912379},
            {124.714469158317, -27.3135590838199, -4.80277765111824, 2.00498567770794},
            {14.8174481590233, -1.7526150184141, -1.04538813418230, -1.17384083282033},
            {25.0758389831245, 9.96796690580462, -4.78112763617555, 2.69108186122184},
            {91.5446469773181, -22.9528777669385, 0.401983435298255, -0.736878098420183},
            {118.176327855097, 5.50757920474225, 2.71132076743689, -0.204972398473778},
            {10.4345393883043, -5.92445292066816, 3.79444682032120, 0.517867427500318}
        };
        PCA pca = PCA.fit(USArrests.x).getProjection(4);
        assertTrue(MathEx.equals(prop, pca.varianceProportion(), 1E-7));
        assertTrue(MathEx.equals(cumprop, pca.cumulativeVarianceProportion(), 1E-7));

        for (int i = 0; i < loadings.length; i++) {
            for (int j = 0; j < loadings[i].length; j++) {
                assertEquals(Math.abs(loadings[i][j]), Math.abs(pca.loadings().get(i, j)), 1E-5);
            }
        }

        double[][] p = pca.apply(USArrests.x);
        for (int i = 0; i < points.length; i++) {
            for (int j = 0; j < points[i].length; j++) {
                assertEquals(Math.abs(points[i][j]), Math.abs(p[i][j]), 1E-5);
            }
        }
    }