Пример #1
0
    def test_init_integer(self):
        """Tests initializations which only specify the order."""

        # Checks for a zero order Lfd object
        lfd_0 = LinearDifferentialOperator(order=0)
        weightfd = [FDataBasis(Constant(domain_range=(0, 1)), 1)]

        self._assert_equal_weights(
            lfd_0.weights, weightfd,
            "Wrong list of weight functions of the linear operator")

        # Checks for a non zero order Lfd object
        lfd_3 = LinearDifferentialOperator(3)
        consfd = FDataBasis(
            Constant(domain_range=(0, 1)),
            [[0], [0], [0], [1]],
        )
        bwtlist3 = list(consfd)

        self._assert_equal_weights(
            lfd_3.weights, bwtlist3,
            "Wrong list of weight functions of the linear operator")

        # Negative order must fail
        with np.testing.assert_raises(ValueError):
            LinearDifferentialOperator(-1)
Пример #2
0
    def test_basis_fpca_transform_result(self):

        n_basis = 9
        n_components = 3

        fd_data = fetch_weather()['data'].coordinates[0]
        fd_data = FDataGrid(np.squeeze(fd_data.data_matrix),
                            np.arange(0.5, 365, 1))

        # initialize basis data
        basis = Fourier(n_basis=n_basis, domain_range=(0, 365))
        fd_basis = fd_data.to_basis(basis)

        fpca = FPCA(n_components=n_components,
                    regularization=TikhonovRegularization(
                        LinearDifferentialOperator(2),
                        regularization_parameter=1e5))
        fpca.fit(fd_basis)
        scores = fpca.transform(fd_basis)

        # results obtained using Ramsay's R package
        results = [[-7.68307641e+01, 5.69034443e+01, -1.22440149e+01],
                   [-9.02873996e+01, 1.46262257e+01, -1.78574536e+01],
                   [-8.21155683e+01, 3.19159491e+01, -2.56212328e+01],
                   [-1.14163637e+02, 3.66425562e+01, -1.00810836e+01],
                   [-6.97263223e+01, 1.22817168e+01, -2.39417618e+01],
                   [-6.41886364e+01, -1.07261045e+01, -1.10587407e+01],
                   [1.35824412e+02, 2.03484658e+01, -9.04815324e+00],
                   [-1.46816399e+01, -2.66867491e+01, -1.20233465e+01],
                   [1.02507511e+00, -2.29840736e+01, -9.06081296e+00],
                   [-3.62936903e+01, -2.09520442e+01, -1.14799951e+01],
                   [-4.20649313e+01, -1.13618094e+01, -6.24909009e+00],
                   [-7.38115985e+01, -3.18423866e+01, -1.50298626e+01],
                   [-6.69822456e+01, -3.35518632e+01, -1.25167352e+01],
                   [-1.03534763e+02, -1.29513941e+01, -1.49103879e+01],
                   [-1.04542036e+02, -1.36794907e+01, -1.41555965e+01],
                   [-7.35863347e+00, -1.41171956e+01, -2.97562788e+00],
                   [7.28804530e+00, -5.34421830e+01, -3.39823418e+00],
                   [5.59974094e+01, -4.02154080e+01, 3.78800103e-01],
                   [1.80778702e+02, 1.87798201e+01, -1.99043247e+01],
                   [-3.69700617e+00, -4.19441020e+01, 6.45820740e+00],
                   [3.76527216e+01, -4.23056953e+01, 1.04221757e+01],
                   [1.23850646e+02, -4.24648130e+01, -2.22336786e-01],
                   [-7.23588457e+00, -1.20579536e+01, 2.07502089e+01],
                   [-4.96871011e+01, 8.88483448e+00, 2.02882768e+01],
                   [-1.36726355e+02, -1.86472599e+01, 1.89076217e+01],
                   [-1.83878661e+02, 4.12118550e+01, 1.78960356e+01],
                   [-1.81568820e+02, 5.20817910e+01, 2.01078870e+01],
                   [-5.08775852e+01, 1.34600555e+01, 3.18602712e+01],
                   [-1.37633866e+02, 7.50809631e+01, 2.42320782e+01],
                   [4.98276375e+01, 1.33401270e+00, 3.50611066e+01],
                   [1.51149934e+02, -5.47417776e+01, 3.97592325e+01],
                   [1.58366096e+02, -3.80762686e+01, -5.62415023e+00],
                   [2.17139548e+02, 6.34055987e+01, -1.98853635e+01],
                   [2.33615480e+02, -7.90787574e-02, 2.69069525e+00],
                   [3.45371437e+02, 9.58703622e+01, 8.47570770e+00]]
        results = np.array(results)

        # compare results
        np.testing.assert_allclose(scores, results, atol=1e-7)
Пример #3
0
    def test_init_default(self):
        """Tests default initialization (do not penalize)."""
        lfd = LinearDifferentialOperator()
        weightfd = [FDataBasis(Constant((0, 1)), 0)]

        np.testing.assert_equal(
            lfd.weights, weightfd,
            "Wrong list of weight functions of the linear operator")
Пример #4
0
    def test_init_wrong_params(self):

        # Check specifying both arguments fail
        with np.testing.assert_raises(ValueError):
            LinearDifferentialOperator(1, weights=[1, 1])

        # Check invalid domain range
        monomial = Monomial((0, 1), n_basis=3)
        fdlist = [FDataBasis(monomial, [1, 2, 3])]

        with np.testing.assert_raises(ValueError):
            LinearDifferentialOperator(weights=fdlist, domain_range=(0, 2))

        # Check wrong types fail
        with np.testing.assert_raises(ValueError):
            LinearDifferentialOperator(weights=['a'])

        with np.testing.assert_raises(ValueError):
            LinearDifferentialOperator(weights='a')
Пример #5
0
    def _test_penalty(self, basis, linear_diff_op, atol=0, result=None):

        operator = LinearDifferentialOperator(linear_diff_op)

        penalty = gramian_matrix(operator, basis)
        numerical_penalty = gramian_matrix_numerical(operator, basis)

        np.testing.assert_allclose(penalty, numerical_penalty, atol=atol)

        if result is not None:
            np.testing.assert_allclose(penalty, result, atol=atol)
Пример #6
0
    def test_vector_valued_smoothing(self):
        X, _ = skfda.datasets.fetch_weather(return_X_y=True)

        basis_dim = skfda.representation.basis.Fourier(
            n_basis=7, domain_range=X.domain_range)
        basis = skfda.representation.basis.VectorValued([basis_dim] * 2)

        for method in smoothing.BasisSmoother.SolverMethod:
            with self.subTest(method=method):

                basis_smoother = smoothing.BasisSmoother(
                    basis,
                    regularization=TikhonovRegularization(
                        LinearDifferentialOperator(2)),
                    return_basis=True,
                    smoothing_parameter=1,
                    method=method)

                basis_smoother_dim = smoothing.BasisSmoother(
                    basis_dim,
                    regularization=TikhonovRegularization(
                        LinearDifferentialOperator(2)),
                    return_basis=True,
                    smoothing_parameter=1,
                    method=method)

                X_basis = basis_smoother.fit_transform(X)

                self.assertEqual(X_basis.dim_codomain, 2)

                self.assertEqual(X_basis.coordinates[0].basis, basis_dim)
                np.testing.assert_allclose(
                    X_basis.coordinates[0].coefficients,
                    basis_smoother_dim.fit_transform(
                        X.coordinates[0]).coefficients)

                self.assertEqual(X_basis.coordinates[1].basis, basis_dim)
                np.testing.assert_allclose(
                    X_basis.coordinates[1].coefficients,
                    basis_smoother_dim.fit_transform(
                        X.coordinates[1]).coefficients)
Пример #7
0
    def test_init_list_int(self):
        """Tests initializations with integer weights."""

        coefficients = [1, 3, 4, 5, 6, 7]

        constant = Constant((0, 1))
        fd = FDataBasis(constant, np.array(coefficients).reshape(-1, 1))

        lfd = LinearDifferentialOperator(weights=coefficients)

        np.testing.assert_equal(
            lfd.weights, list(fd),
            "Wrong list of weight functions of the linear operator")
Пример #8
0
    def test_init_list_fdatabasis(self):
        """Test initialization with functional weights."""

        n_basis = 4
        n_weights = 6

        monomial = Monomial((0, 1), n_basis=n_basis)

        weights = np.arange(n_basis * n_weights).reshape((n_weights, n_basis))

        fd = FDataBasis(monomial, weights)

        fdlist = [FDataBasis(monomial, w) for w in weights]
        lfd = LinearDifferentialOperator(weights=fdlist)

        np.testing.assert_equal(
            lfd.weights, list(fd),
            "Wrong list of weight functions of the linear operator")

        # Check failure if intervals do not match
        constant = Constant((0, 2))
        fdlist.append(FDataBasis(constant, 1))
        with np.testing.assert_raises(ValueError):
            LinearDifferentialOperator(weights=fdlist)
Пример #9
0
    def test_bspline_penalty_special_case(self):
        basis = BSpline(n_basis=5)

        res = np.array([[1152., -2016., 1152., -288., 0.],
                        [-2016., 3600., -2304., 1008., -288.],
                        [1152., -2304., 2304., -2304., 1152.],
                        [-288., 1008., -2304., 3600., -2016.],
                        [0., -288., 1152., -2016., 1152.]])

        operator = LinearDifferentialOperator(basis.order - 1)
        penalty = gramian_matrix(operator, basis)
        numerical_penalty = gramian_matrix_numerical(operator, basis)

        np.testing.assert_allclose(penalty, res)

        np.testing.assert_allclose(numerical_penalty, res)
Пример #10
0
 def test_qr(self):
     t = np.linspace(0, 1, 5)
     x = np.sin(2 * np.pi * t) + np.cos(2 * np.pi * t)
     basis = BSpline((0, 1), n_basis=5)
     fd = FDataGrid(data_matrix=x, sample_points=t)
     smoother = smoothing.BasisSmoother(
         basis=basis,
         smoothing_parameter=10,
         regularization=TikhonovRegularization(
             LinearDifferentialOperator(2)),
         method='qr',
         return_basis=True)
     fd_basis = smoother.fit_transform(fd)
     np.testing.assert_array_almost_equal(
         fd_basis.coefficients.round(2),
         np.array([[0.60, 0.47, 0.20, -0.07, -0.20]]))
Пример #11
0
    def test_basis_fpca_fit_result(self):

        n_basis = 9
        n_components = 3

        fd_data = fetch_weather()['data'].coordinates[0]
        fd_data = FDataGrid(np.squeeze(fd_data.data_matrix),
                            np.arange(0.5, 365, 1))

        # initialize basis data
        basis = Fourier(n_basis=n_basis, domain_range=(0, 365))
        fd_basis = fd_data.to_basis(basis)

        fpca = FPCA(n_components=n_components,
                    regularization=TikhonovRegularization(
                        LinearDifferentialOperator(2),
                        regularization_parameter=1e5))
        fpca.fit(fd_basis)

        # results obtained using Ramsay's R package
        results = [[
            0.92407552, 0.13544888, 0.35399023, 0.00805966, -0.02148108,
            -0.01709549, -0.00208469, -0.00297439, -0.00308224
        ],
                   [
                       -0.33314436, -0.05116842, 0.89443418, 0.14673902,
                       0.21559073, 0.02046924, 0.02203431, -0.00787185,
                       0.00247492
                   ],
                   [
                       -0.14241092, 0.92131899, 0.00514715, 0.23391411,
                       -0.19497613, 0.09800817, 0.01754439, -0.00205874,
                       0.01438185
                   ]]
        results = np.array(results)

        # compare results obtained using this library. There are slight
        # variations due to the fact that we are in two different packages
        for i in range(n_components):
            if np.sign(fpca.components_.coefficients[i][0]) != np.sign(
                    results[i][0]):
                results[i, :] *= -1
        np.testing.assert_allclose(fpca.components_.coefficients,
                                   results,
                                   atol=1e-7)
Пример #12
0
 def test_monomial_smoothing(self):
     # It does not have much sense to apply smoothing in this basic case
     # where the fit is very good but its just for testing purposes
     t = np.linspace(0, 1, 5)
     x = np.sin(2 * np.pi * t) + np.cos(2 * np.pi * t)
     basis = Monomial(n_basis=4)
     fd = FDataGrid(data_matrix=x, sample_points=t)
     smoother = smoothing.BasisSmoother(
         basis=basis,
         smoothing_parameter=1,
         regularization=TikhonovRegularization(
             LinearDifferentialOperator(2)),
         return_basis=True)
     fd_basis = smoother.fit_transform(fd)
     # These results where extracted from the R package fda
     np.testing.assert_array_almost_equal(
         fd_basis.coefficients.round(2),
         np.array([[0.61, -0.88, 0.06, 0.02]]))
Пример #13
0
    def test_regression_mixed_regularization(self):

        multivariate = np.array([[0, 0], [2, 7], [1, 7], [3, 9], [4, 16],
                                 [2, 14], [3, 5]])

        X = [
            multivariate,
            FDataBasis(Monomial(n_basis=3),
                       [[1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 0, 1], [1, 0, 0],
                        [0, 1, 0], [0, 0, 1]])
        ]

        # y = 2 + sum([3, 1] * array) + int(3 * function)
        intercept = 2
        coefs_multivariate = np.array([3, 1])
        y_integral = np.array([3, 3 / 2, 1, 4, 3, 3 / 2, 1])
        y_sum = multivariate @ coefs_multivariate
        y = 2 + y_sum + y_integral

        scalar = LinearRegression(regularization=[
            TikhonovRegularization(lambda x: x),
            TikhonovRegularization(LinearDifferentialOperator(2))
        ])
        scalar.fit(X, y)

        np.testing.assert_allclose(scalar.intercept_, intercept, atol=0.01)

        np.testing.assert_allclose(scalar.coef_[0], [2.536739, 1.072186],
                                   atol=0.01)

        np.testing.assert_allclose(scalar.coef_[1].coefficients,
                                   [[2.125676, 2.450782, 5.808745e-4]],
                                   atol=0.01)

        y_pred = scalar.predict(X)
        np.testing.assert_allclose(y_pred, [
            5.349035, 16.456464, 13.361185, 23.930295, 32.650965, 23.961766,
            16.29029
        ],
                                   atol=0.01)
Пример #14
0
    def smooth_grids(self,
                     param_values: list = None,
                     smoother=None,
                     scorer=LinearSmootherGeneralizedCVScorer(),
                     return_history=False):
        '''
            Search hyperparameter of user's estimator, then transform datagrid with it
            If no param_values specified, algorithm will try 100 values between 10**-8 et 10**8
            smoother must be either a skfda.BasisSmoother or a list of skfda.BasisSmoother one by variable
        '''
        if param_values is None:
            param_values = np.logspace(-8, 8, num=100)
        if smoother is None:
            print("Default Smoother used")
            smoother = BasisSmoother(basis,
                                     regularization=TikhonovRegularization(
                                         LinearDifferentialOperator(order=2)))
        if isinstance(smoother, list) or isinstance(smoother, np.ndarray):
            if len(smoother) != self._nVar:
                raise ValueError(
                    "number of smoothers must be equal to the number of variable or equal to 1"
                )
        else:
            smoother.domain_range = self.init_grid.domain_range
            smoother = [smoother] * self._nVar

        smoothed_grids = []
        history = []
        print("Smoothing data...")

        for i in range(self._nVar):
            data_grid = self.coordinates_grids[i].copy()
            grid_search = SmoothingParameterSearch(estimator=smoother[i],
                                                   param_values=param_values,
                                                   scoring=scorer)
            _ = grid_search.fit(data_grid)
            history.append(grid_search.cv_results_['mean_test_score'])
            best_est = grid_search.best_estimator_
            smoothed_grids.append(best_est.fit_transform(data_grid))

        print("Smoothing Done")

        self.coordinates_grids = smoothed_grids
        self._smoothed = True
        self.coordinates_grids_dx1 = []
        self.coordinates_grids_dx2 = []
        self.coefficients = []

        for i in range(self._nVar):
            basis_representation = self.coordinates_grids[i].copy().to_basis(
                basis=smoother[i].basis)
            self.coefficients.append(basis_representation.coefficients)
            self.coordinates_grids_dx1.append(
                basis_representation.derivative(order=1).to_grid(
                    self.sample_points))
            self.coordinates_grids_dx2.append(
                basis_representation.derivative(order=2).to_grid(
                    self.sample_points))

        self.coefficients = np.array(self.coefficients)
        if return_history:
            return np.array(history)
        else:
            return None
Пример #15
0
    def test_grid_fpca_regularization_fit_result(self):

        n_components = 1

        fd_data = fetch_weather()['data'].coordinates[0]

        fd_data = FDataGrid(np.squeeze(fd_data.data_matrix),
                            np.arange(0.5, 365, 1))

        fpca = FPCA(n_components=n_components,
                    weights=[1] * 365,
                    regularization=TikhonovRegularization(
                        LinearDifferentialOperator(2)))
        fpca.fit(fd_data)

        # results obtained using fda.usc for the first component
        results = [[
            -0.06961236, -0.07027042, -0.07090496, -0.07138247, -0.07162215,
            -0.07202264, -0.07264893, -0.07279174, -0.07274672, -0.07300075,
            -0.07365471, -0.07489002, -0.07617455, -0.07658708, -0.07551923,
            -0.07375128, -0.0723776, -0.07138373, -0.07080555, -0.07111745,
            -0.0721514, -0.07395427, -0.07558341, -0.07650959, -0.0766541,
            -0.07641352, -0.07660864, -0.07669081, -0.0765396, -0.07640671,
            -0.07634668, -0.07626304, -0.07603638, -0.07549114, -0.07410347,
            -0.07181791, -0.06955356, -0.06824034, -0.06834077, -0.06944125,
            -0.07133598, -0.07341109, -0.07471501, -0.07568844, -0.07631904,
            -0.07647264, -0.07629453, -0.07598431, -0.07628157, -0.07654062,
            -0.07616026, -0.07527189, -0.07426683, -0.07267961, -0.07079998,
            -0.06927394, -0.068412, -0.06838534, -0.06888439, -0.0695309,
            -0.07005508, -0.07066637, -0.07167196, -0.07266978, -0.07275299,
            -0.07235183, -0.07207819, -0.07159814, -0.07077697, -0.06977026,
            -0.0691952, -0.06965756, -0.07058327, -0.07075751, -0.07025415,
            -0.06954233, -0.06899785, -0.06891026, -0.06887079, -0.06862183,
            -0.06830082, -0.06777765, -0.06700202, -0.06639394, -0.06582435,
            -0.06514987, -0.06467236, -0.06425272, -0.06359187, -0.062922,
            -0.06300068, -0.06325494, -0.06316979, -0.06296254, -0.06246343,
            -0.06136836, -0.0600936, -0.05910688, -0.05840872, -0.0576547,
            -0.05655684, -0.05546518, -0.05484433, -0.05465746, -0.05449286,
            -0.05397004, -0.05300742, -0.05196686, -0.05133129, -0.05064617,
            -0.04973418, -0.04855687, -0.04714356, -0.04588103, -0.04547284,
            -0.04571493, -0.04580704, -0.04523509, -0.04457293, -0.04405309,
            -0.04338468, -0.04243512, -0.04137278, -0.04047946, -0.03984531,
            -0.03931376, -0.0388847, -0.03888507, -0.03908662, -0.03877577,
            -0.03830952, -0.03802713, -0.03773521, -0.03752388, -0.03743759,
            -0.03714113, -0.03668387, -0.0363703, -0.03642288, -0.03633051,
            -0.03574618, -0.03486536, -0.03357797, -0.03209969, -0.0306837,
            -0.02963987, -0.029102, -0.0291513, -0.02932013, -0.02912619,
            -0.02869407, -0.02801974, -0.02732363, -0.02690451, -0.02676622,
            -0.0267323, -0.02664896, -0.02661708, -0.02637166, -0.02577496,
            -0.02490428, -0.02410813, -0.02340367, -0.02283356, -0.02246305,
            -0.0224229, -0.0225435, -0.02295603, -0.02324663, -0.02310005,
            -0.02266893, -0.02221522, -0.02168056, -0.02129419, -0.02064909,
            -0.02007801, -0.01979083, -0.01979541, -0.01978879, -0.01954269,
            -0.0191623, -0.01879572, -0.01849678, -0.01810297, -0.01769666,
            -0.01753802, -0.01794351, -0.01871307, -0.01930005, -0.01933,
            -0.01901017, -0.01873486, -0.01861838, -0.01870777, -0.01879,
            -0.01904219, -0.01945078, -0.0200607, -0.02076936, -0.02100213,
            -0.02071439, -0.02052113, -0.02076313, -0.02128468, -0.02175631,
            -0.02206387, -0.02201054, -0.02172142, -0.02143092, -0.02133647,
            -0.02144956, -0.02176286, -0.02212579, -0.02243861, -0.02278316,
            -0.02304113, -0.02313356, -0.02349275, -0.02417028, -0.0245954,
            -0.0244062, -0.02388557, -0.02374682, -0.02401071, -0.02431126,
            -0.02433125, -0.02427656, -0.02430442, -0.02424977, -0.02401619,
            -0.02402294, -0.02415424, -0.02413262, -0.02404076, -0.02397651,
            -0.0243893, -0.0253322, -0.02664395, -0.0278802, -0.02877936,
            -0.02927182, -0.02937318, -0.02926277, -0.02931632, -0.02957945,
            -0.02982133, -0.03023224, -0.03060406, -0.03066011, -0.03070932,
            -0.03116429, -0.03179009, -0.03198094, -0.03149462, -0.03082037,
            -0.03041594, -0.0303307, -0.03028465, -0.03052841, -0.0311837,
            -0.03199307, -0.03262025, -0.03345083, -0.03442665, -0.03521313,
            -0.0356433, -0.03606037, -0.03677406, -0.03735165, -0.03746578,
            -0.03744154, -0.03752143, -0.03780898, -0.03837639, -0.03903232,
            -0.03911629, -0.03857567, -0.03816592, -0.03819285, -0.03818405,
            -0.03801684, -0.03788493, -0.03823232, -0.03906142, -0.04023251,
            -0.04112434, -0.04188011, -0.04254759, -0.043, -0.04340181,
            -0.04412687, -0.04484482, -0.04577669, -0.04700832, -0.04781373,
            -0.04842662, -0.04923723, -0.05007637, -0.05037817, -0.05009794,
            -0.04994083, -0.05012712, -0.05094001, -0.05216065, -0.05350458,
            -0.05469781, -0.05566309, -0.05641011, -0.05688106, -0.05730818,
            -0.05759156, -0.05763771, -0.05760073, -0.05766117, -0.05794587,
            -0.05816696, -0.0584046, -0.05905105, -0.06014331, -0.06142231,
            -0.06270788, -0.06388225, -0.06426245, -0.06386721, -0.0634656,
            -0.06358049, -0.06442514, -0.06570047, -0.06694328, -0.0682621,
            -0.06897846, -0.06896583, -0.06854621, -0.06797142, -0.06763755,
            -0.06784024, -0.06844314, -0.06918567, -0.07021928, -0.07148473,
            -0.07232504, -0.07272276, -0.07287021, -0.07289836, -0.07271531,
            -0.07239956, -0.07214086, -0.07170078, -0.07081195, -0.06955202,
            -0.06825156, -0.06690167, -0.06617102, -0.06683291, -0.06887539,
            -0.07089424, -0.07174837, -0.07150888, -0.07070378, -0.06960066,
            -0.06842496, -0.06777666, -0.06728403, -0.06681262, -0.06679066
        ]]

        results = np.array(results)

        # compare results obtained using this library. There are slight
        # variations due to the fact that we are in two different packages
        for i in range(n_components):
            if np.sign(fpca.components_.data_matrix[i][0]) != np.sign(
                    results[i][0]):
                results[i, :] *= -1
        np.testing.assert_allclose(fpca.components_.data_matrix.reshape(
            fpca.components_.data_matrix.shape[:-1]),
                                   results,
                                   rtol=1e-2)
Пример #16
0
    def test_regression_regularization(self):

        x_basis = Monomial(n_basis=7)
        x_fd = FDataBasis(x_basis, np.identity(7))

        beta_basis = Fourier(n_basis=5)
        beta_fd = FDataBasis(beta_basis, [1.0403, 0, 0, 0, 0])
        y = [
            1.0000684777229512, 0.1623672257830915, 0.08521053851548224,
            0.08514200869281137, 0.09529138749665378, 0.10549625973303875,
            0.11384314859153018
        ]

        y_pred_compare = [
            0.890341, 0.370162, 0.196773, 0.110079, 0.058063, 0.023385,
            -0.001384
        ]

        scalar = LinearRegression(coef_basis=[beta_basis],
                                  regularization=TikhonovRegularization(
                                      LinearDifferentialOperator(2)))
        scalar.fit(x_fd, y)
        np.testing.assert_allclose(scalar.coef_[0].coefficients,
                                   beta_fd.coefficients,
                                   atol=1e-3)
        np.testing.assert_allclose(scalar.intercept_, -0.15, atol=1e-4)

        y_pred = scalar.predict(x_fd)
        np.testing.assert_allclose(y_pred, y_pred_compare, atol=1e-4)

        x_basis = Monomial(n_basis=3)
        x_fd = FDataBasis(x_basis,
                          [[1, 0, 0], [0, 1, 0], [0, 0, 1], [2, 0, 1]])

        beta_fd = FDataBasis(x_basis, [3, 2, 1])
        y = [1 + 13 / 3, 1 + 29 / 12, 1 + 17 / 10, 1 + 311 / 30]

        # Non regularized
        scalar = LinearRegression()
        scalar.fit(x_fd, y)
        np.testing.assert_allclose(scalar.coef_[0].coefficients,
                                   beta_fd.coefficients)
        np.testing.assert_allclose(scalar.intercept_, 1)

        y_pred = scalar.predict(x_fd)
        np.testing.assert_allclose(y_pred, y)

        # Regularized
        beta_fd_reg = FDataBasis(x_basis, [2.812, 3.043, 0])
        y_reg = [5.333, 3.419, 2.697, 11.366]

        scalar_reg = LinearRegression(regularization=TikhonovRegularization(
            LinearDifferentialOperator(2)))
        scalar_reg.fit(x_fd, y)
        np.testing.assert_allclose(scalar_reg.coef_[0].coefficients,
                                   beta_fd_reg.coefficients,
                                   atol=0.001)
        np.testing.assert_allclose(scalar_reg.intercept_, 0.998, atol=0.001)

        y_pred = scalar_reg.predict(x_fd)
        np.testing.assert_allclose(y_pred, y_reg, atol=0.001)
Пример #17
0
def get_fpca(fdo):
    """
    Performs functional PCA on funtional data object and returns results.
    
    Args:
        fdo (object): Functional data object.
        
    Returns:
        dict: Functional PCA results, includes the following keys:
            - 'C'       : Centered coefficients matrix 'C'
            - 'Cm'      : Mean coefficients 'Cm' 
            - 'inertia' : Inertia
            - 'W'       : Function-to-discrete metric equivalence matrix 'W'
            - 'M'       : Weighting matrix 'M'
            - 'values'  : PCs values
            - 'pval'    : Percentage of variance of PCs.
            - 'vecnotWM': PCs vectors
            - 'vectors' : PCs weighted vectors
            - 'axes'    : ? #TODO Etienne?
            - 'pc'      : PCs projected on the modes
    """
    
    # get number of samples, basis, and dimensions
    nsam = fdo.n_samples
    nbas = fdo.n_basis
    ndim = len(fdo.dim_names)
    
    # if 3d-array coefficients, convert to a 2d-array (n_samples, n_basis)
    if ndim>1:
        C = np.zeros((nsam, nbas*ndim))
        for k in range(ndim):
            j0          = nbas *  k
            j1          = nbas * (k+1)
            C[:, j0:j1] = fdo.coefficients[:, :, k]
    else:
        C = fdo.coefficients
    
    # compute centered coefficients matrix by subtractig the mean
    Cm = np.mean(C, axis=0)
    Cc = C - Cm[np.newaxis,:]
    
    # get basis penalty matrix
    regularization = TikhonovRegularization(LinearDifferentialOperator(0))
    penalty        = regularization.penalty_matrix(fdo.basis)
    
    # compute crossed-covariance matrix of C and Inertia
    inertia = np.zeros(ndim)
    for k in range(ndim):
        j0         = nbas *  k
        j1         = nbas * (k+1)
        V          = Cc[:, j0:j1].T @ Cc[:, j0:j1] @ penalty / nsam
        inertia[k] = np.trace( V )
        
    # compute weighting matrix 'M' to balance variables of different units
    M       = np.zeros((ndim*nbas,ndim*nbas))
    Mdeminv = M.copy()
    W       = M.copy()
    aux     = np.diag(np.ones(nbas))
    for k in range(ndim):
        i0, j0                = nbas *  k   , nbas *  k
        i1, j1                = nbas * (k+1), nbas * (k+1)    
        M      [i0:i1, j0:j1] = aux/inertia[k]
        Mdeminv[i0:i1, j0:j1] = aux*np.sqrt(inertia[k])
        W      [i0:i1, j0:j1] = penalty
    Mdem = np.sqrt(M);
    
    # compute function-to-discrete metric equivalence matrix 'W
    W       = (W+W.T)/2.
    Wdem    = np.linalg.cholesky(W).T
    Wdeminv = np.linalg.inv(Wdem)
    
    # compute crossed-covariance matrix 'V'
    V = Mdem @ Wdem @ Cc.T @ Cc @ Wdem.T @ Mdem / nsam
    
    # compute eigenvalues and eigenvectors
    pca_values, pca_vectors = np.linalg.eig(V)
    idx                     = pca_values.argsort()[::-1]
    pca_values              = pca_values[idx]
    pca_vectors             = pca_vectors[:,idx]
    pca_vectors_notWM       = pca_vectors
    pca_vectors             = Mdeminv @ Wdeminv @ pca_vectors
    
    # compute principal components projected on the modes
    pc = Cc @ W.T @ M @ pca_vectors
    
    # build PCA dictionary
    fpca              = {}
    fpca['C'        ] = C
    fpca['Cm'       ] = Cm
    fpca['inertia'  ] = inertia
    fpca['W'        ] = W
    fpca['M'        ] = M
    fpca['values'   ] = pca_values
    fpca['pval'     ] = 100 * pca_values.real / np.sum(pca_values.real)
    fpca['vecnotWM' ] = pca_vectors_notWM
    fpca['vectors'  ] = pca_vectors
    fpca['axes'     ] = pca_vectors * np.sqrt(pca_values)[:,np.newaxis].T
    fpca['pc'       ] = pc.real
    
    # Warn if eigen values are not orthogonal
    v1 = fpca['vectors'][:,0].T @ W @ M @ fpca['vectors'][:,0] - 1.
    v2 = fpca['vectors'][:,0].T @ W @ M @ fpca['vectors'][:,1]
    if v1>1.e-10 or v2>1.e-10:
        print('Warning : Eigen values not orthogonal (%s, %s)' % (v1, v2))
        
    return fpca