Esempio n. 1
0
    def fit(self, X, y=None, sample_weight=None):
        """Fit the model with X.

        Parameters
        ----------
        X : Triangle-like
            Set of LDFs to which the munich adjustment will be applied.
        y : Ignored
        sample_weight : Ignored

        Returns
        -------
        self : object
            Returns the instance itself.
        """
        if X.array_backend == 'sparse':
            X = X.set_backend('numpy')
        else:
            X = copy.deepcopy(X)
        xp = X.get_array_module()
        from chainladder.utils.utility_functions import num_to_nan
        if (type(X.ddims) != np.ndarray):
            raise ValueError(
                'Triangle must be expressed with development lags')
        if self.fillna:
            tri_array = num_to_nan((X + self.fillna).values)
        else:
            tri_array = num_to_nan(X.values.copy())
        if type(self.average) is not list:
            average = [self.average] * (tri_array.shape[-1] - 1)
        else:
            average = self.average
        average = np.array(average)
        self.average_ = average
        if type(self.n_periods) is not list:
            n_periods = [self.n_periods] * (tri_array.shape[-1] - 1)
        else:
            n_periods = self.n_periods
        n_periods = np.array(n_periods)
        self.n_periods_ = n_periods
        weight_dict = {'regression': 0, 'volume': 1, 'simple': 2}
        x, y = tri_array[..., :-1], tri_array[..., 1:]
        val = xp.array([weight_dict.get(item.lower(), 1) for item in average])
        for i in [2, 1, 0]:
            val = xp.repeat(val[None], tri_array.shape[i], axis=0)
        val = xp.nan_to_num(val * (y * 0 + 1))
        link_ratio = y / x
        self.w_ = xp.array(
            self._assign_n_periods_weight(X) *
            self._drop_adjustment(X, link_ratio))
        w = self.w_ / (x**(val))
        params = WeightedRegression(axis=2, thru_orig=True, xp=xp).fit(x, y, w)
        if self.n_periods != 1:
            params = params.sigma_fill(self.sigma_interpolation)
        else:
            warnings.warn('Setting n_periods=1 does not allow enough degrees '
                          'of freedom to support calculation of all regression'
                          ' statistics.  Only LDFs have been calculated.')
        params.std_err_ = xp.nan_to_num(params.std_err_) + \
            xp.nan_to_num(
                (1-xp.nan_to_num(params.std_err_*0+1)) *
                params.sigma_ /
                xp.swapaxes(xp.sqrt(x**(2-val))[..., 0:1, :], -1, -2))
        params = xp.concatenate(
            (params.slope_, params.sigma_, params.std_err_), 3)
        params = xp.swapaxes(params, 2, 3)
        self.ldf_ = self._param_property(X, params, 0)
        self.sigma_ = self._param_property(X, params, 1)
        self.std_err_ = self._param_property(X, params, 2)
        return self
Esempio n. 2
0
    def fit(self, X, y=None, sample_weight=None):
        """Fit the model with X.

        Parameters
        ----------
        X : Triangle-like
            Set of LDFs to which the munich adjustment will be applied.
        y : None
            Ignored
        sample_weight :
            Ignored

        Returns
        -------
        self : object
            Returns the instance itself.
        """
        if X.array_backend == "sparse":
            X = X.set_backend("numpy")
        else:
            X = X.copy()
        xp = X.get_array_module()
        from chainladder.utils.utility_functions import num_to_nan

        if type(X.ddims) != np.ndarray:
            raise ValueError(
                "Triangle must be expressed with development lags")
        if self.fillna:
            tri_array = num_to_nan((X + self.fillna).values)
        else:
            tri_array = num_to_nan(X.values.copy())
        if type(self.average) is not list:
            self.average_ = np.array([self.average] *
                                     (tri_array.shape[-1] - 1))
        else:
            self.average_ = np.array(self.average)
        if type(self.n_periods) is not list:
            n_periods = [self.n_periods] * (tri_array.shape[-1] - 1)
        else:
            n_periods = self.n_periods
        n_periods = np.array(n_periods)
        self.n_periods_ = n_periods
        weight_dict = {"regression": 0, "volume": 1, "simple": 2}
        x, y = tri_array[..., :-1], tri_array[..., 1:]
        val = xp.nan_to_num(
            xp.array([weight_dict.get(item, item)
                      for item in self.average_])[None, None, None] *
            (y * 0 + 1))
        link_ratio = y / x
        self.w_ = xp.array(
            self._assign_n_periods_weight(X) *
            self._drop_adjustment(X, link_ratio))
        w = self.w_ / (x**(val))
        params = WeightedRegression(axis=2, thru_orig=True, xp=xp).fit(x, y, w)
        if self.n_periods != 1:
            params = params.sigma_fill(self.sigma_interpolation)
        else:
            warnings.warn("Setting n_periods=1 does not allow enough degrees "
                          "of freedom to support calculation of all regression"
                          " statistics.  Only LDFs have been calculated.")
        params.std_err_ = xp.nan_to_num(params.std_err_) + xp.nan_to_num(
            (1 - xp.nan_to_num(params.std_err_ * 0 + 1)) * params.sigma_ /
            xp.swapaxes(xp.sqrt(x**(2 - val))[..., 0:1, :], -1, -2))
        params = xp.concatenate(
            (params.slope_, params.sigma_, params.std_err_), 3)
        params = xp.swapaxes(params, 2, 3)
        self.ldf_ = self._param_property(X, params, 0)
        self.sigma_ = self._param_property(X, params, 1)
        self.std_err_ = self._param_property(X, params, 2)

        resid = -X.iloc[..., :-1] * self.ldf_.values + X.iloc[..., 1:].values

        std = xp.sqrt((1 / num_to_nan(w)) * (self.sigma_**2).values)
        resid = resid / std
        self.std_residuals_ = resid[resid.valuation < X.valuation_date]
        return self
Esempio n. 3
0
    def fit(self, X, y=None, sample_weight=None):
        """Fit the model with X.

        Parameters
        ----------
        X : Triangle-like
            Set of LDFs to which the munich adjustment will be applied.
        y : None
            Ignored
        sample_weight :
            Ignored

        Returns
        -------
        self : object
            Returns the instance itself.
        """
        from chainladder.utils.utility_functions import num_to_nan

        # Validate inputs
        if X.is_cumulative == False:
            obj = self._set_fit_groups(X).incr_to_cum().val_to_dev().copy()
        else:
            obj = self._set_fit_groups(X).val_to_dev().copy()
        xp = obj.get_array_module()

        # Make sure it is a dev tri
        if type(obj.ddims) != np.ndarray:
            raise ValueError("Triangle must be expressed with development lags")
        # validate hyperparameters
        if self.fillna:
            tri_array = num_to_nan((obj + self.fillna).values)
        else:
            tri_array = num_to_nan(obj.values.copy())
        self.average_ = np.array(
            self._validate_axis_assumption(self.average, obj.development[:-1]))
        n_periods_ = self._validate_axis_assumption(self.n_periods, obj.development[:-1])
        weight_dict = {"regression": 0, "volume": 1, "simple": 2}
        x, y = tri_array[..., :-1], tri_array[..., 1:]
        exponent = xp.array([weight_dict.get(item, item) for item in self.average_])
        exponent = xp.nan_to_num(exponent[None, None, None] * (y * 0 + 1))
        link_ratio = y / x
        self.w_ = (self._assign_n_periods_weight(obj, n_periods_) *
                   self._drop_adjustment(obj, link_ratio))
        w = self.w_ / (x ** (exponent))
        params = WeightedRegression(axis=2, thru_orig=True, xp=xp).fit(x, y, w)
        if self.n_periods != 1:
            params = params.sigma_fill(self.sigma_interpolation)
        else:
            warnings.warn(
                "Setting n_periods=1 does not allow enough degrees "
                "of freedom to support calculation of all regression"
                " statistics.  Only LDFs have been calculated."
            )
        params.std_err_ = xp.nan_to_num(params.std_err_) + xp.nan_to_num(
            (1 - xp.nan_to_num(params.std_err_ * 0 + 1))
            * params.sigma_
            / xp.swapaxes(xp.sqrt(x ** (2 - exponent))[..., 0:1, :], -1, -2)
        )
        params = xp.concatenate((params.slope_, params.sigma_, params.std_err_), 3)
        params = xp.swapaxes(params, 2, 3)
        self.ldf_ = self._param_property(obj, params, 0)
        self.sigma_ = self._param_property(obj, params, 1)
        self.std_err_ = self._param_property(obj, params, 2)

        resid = -obj.iloc[..., :-1] * self.ldf_.values + obj.iloc[..., 1:].values

        std = xp.sqrt((1/num_to_nan(w))*(self.sigma_**2).values)
        resid = resid/std
        self.std_residuals_ = resid[resid.valuation < obj.valuation_date]
        return self