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

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

        Returns
        -------
        self : object
            Returns the instance itself.
        """
        backend = "cupy" if X.array_backend == "cupy" else "numpy"
        self.X_ = X.copy()
        self.paid_w_ = Development(n_periods=self.paid_n_periods).fit(
            self.X_.sum(0).sum(1)).w_
        self.case_w_ = Development(n_periods=self.case_n_periods).fit(
            self.X_.sum(0).sum(1)).w_
        self.case_ldf_ = self.case_to_prior_case_.mean(2)
        self.paid_ldf_ = self.paid_to_prior_case_.mean(2)
        self.ldf_ = self._set_ldf(self.X_).set_backend(backend)
        return self
Exemplo n.º 2
0
    def transform(self, X):
        """ If X and self are of different shapes, align self to X, else
        return self.

        Parameters
        ----------
        X : Triangle
            The triangle to be transformed

        Returns
        -------
            X_new : New triangle with transformed attributes.
        """
        X_new = copy.copy(X)
        if 'ldf_' not in X_new:
            X_new = Development().fit_transform(X_new)
        X_new.p_to_i_X_ = self._get_p_to_i_object(X_new)
        X_new.p_to_i_ldf_ = self._get_p_to_i_object(X_new.ldf_)
        X_new.p_to_i_sigma_ = self._get_p_to_i_object(X_new.sigma_)
        X_new.q_f_, X_new.rho_sigma_ = self._get_MCL_model(X_new)
        X_new.munich_full_triangle_ = self._get_munich_full_triangle_(
            X_new.p_to_i_X_, X_new.p_to_i_ldf_, X_new.p_to_i_sigma_,
            self.lambda_coef_, X_new.rho_sigma_, X_new.q_f_)
        X_new.ldf_ = self._set_ldf(X_new, self._get_mcl_cdf(X_new, X_new.munich_full_triangle_))
        triangles = ['rho_', 'lambda_', 'lambda_coef_']
        for item in triangles:
            setattr(X_new, item, getattr(self, item))
        X_new._set_slicers()
        return X_new
Exemplo n.º 3
0
 def transform(self, X):
     if 'ldf_' not in X:
         X_new = Development().fit_transform(X)
     else:
         X_new = copy.deepcopy(X)
     xp = X_new.ldf_.get_array_module(
     ) if X_new.ldf_.array_backend != 'sparse' else np
     X_new.std_err_.values = xp.concatenate(
         (X_new.std_err_.values, self.std_err_.values[..., -1:]), -1)
     extend = self.cdf_.values[..., -self._ave_period[0] - 1:] * 0 + 1
     X_new.cdf_.values = xp.concatenate((X_new.cdf_.values, extend), -1)
     X_new.cdf_.values = X_new.cdf_.values * \
         self.cdf_.values[..., -self._ave_period[0]-1:-self._ave_period[0]]
     X_new.cdf_.values = xp.concatenate(
         (X_new.cdf_.values[..., :-1], self.cdf_.values[..., -1:]), axis=-1)
     X_new.ldf_.values = xp.concatenate(
         (X_new.ldf_.values, self.ldf_.values[...,
                                              -self._ave_period[0] - 1:]),
         -1)
     X_new.sigma_.values = xp.concatenate(
         (X_new.sigma_.values, self.sigma_.values[..., -1:]), -1)
     X_new.cdf_.ddims = X_new.ldf_.ddims = self.ldf_.ddims
     X_new.sigma_.ddims = X_new.std_err_.ddims = self.sigma_.ddims
     X_new.sigma_._set_slicers()
     X_new.ldf_._set_slicers()
     X_new.cdf_._set_slicers()
     X_new.std_err_._set_slicers()
     X_new._ave_period = self._ave_period
     X_new.tail_ = TailBase._tail_(X_new)
     return X_new
Exemplo n.º 4
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 tail will be applied.
        y : Ignored
        sample_weight : Ignored

        Returns
        -------
        self : object
            Returns the instance itself.
        """
        super().fit(X, y, sample_weight)
        xp = self.ldf_.get_array_module()
        tail = self.tail
        if self.attachment_age:
            attach_idx = xp.min(xp.where(X.ddims>=self.attachment_age))
        else:
            attach_idx = len(X.ddims) - 1
        self = self._apply_decay(X, tail, attach_idx)
        obj = Development().fit_transform(X) if 'ldf_' not in X else X
        if xp.max(xp.array(self.tail)) != 1.0:
            sigma, std_err = self._get_tail_stats(obj)
            self.sigma_.values = xp.concatenate(
                (self.sigma_.values[..., :-1], sigma[..., -1:]), axis=-1)
            self.std_err_.values = xp.concatenate(
                (self.std_err_.values[..., :-1], std_err[..., -1:]), axis=-1)
        return self
Exemplo n.º 5
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 (type(X.ddims) != np.ndarray):
            raise ValueError(
                'Triangle must be expressed with development lags')
        obj = copy.deepcopy(X)
        if obj.__dict__.get('ldf_', None) is None:
            obj = Development().fit_transform(obj)
        self.p_to_i_X_ = self._get_p_to_i_object(obj)
        self.p_to_i_ldf_ = self._get_p_to_i_object(obj.ldf_)
        self.p_to_i_sigma_ = self._get_p_to_i_object(obj.sigma_)
        self.q_f_, self.rho_sigma_ = self._get_MCL_model(obj)
        self.residual_, self.q_resid_ = self._get_MCL_residuals(obj)
        self.lambda_coef_ = self._get_MCL_lambda()
        self.cdf_ = self._get_cdf(obj)
        return self
Exemplo n.º 6
0
    def predict(self, X, sample_weight=None):
        """Predicts the chainladder ultimate on a new triangle **X**

        Parameters
        ----------
        X : Triangle
            The data used to compute the mean and standard deviation
            used for later scaling along the features axis.
        sample_weight : Triangle
            For exposure-based methods, the exposure to be used for predictions

        Returns
        -------
        X_new: Triangle

        """
        obj = copy.deepcopy(self)
        obj.X_ = copy.deepcopy(X)
        obj.sample_weight = sample_weight
        if np.unique(self.cdf_.values, axis=-2).shape[-2] == 1:
            obj.cdf_.values = np.repeat(np.unique(self.cdf_.values, axis=-2),
                                        len(X.odims), -2)
            obj.ldf_.values = np.repeat(np.unique(self.ldf_.values, axis=-2),
                                        len(X.odims), -2)
            obj.cdf_.odims = obj.ldf_.odims = obj.X_.odims
            obj.cdf_.valuation = obj.ldf_.valuation = \
                Development().fit(X).cdf_.valuation
        return obj
Exemplo n.º 7
0
 def validate_X(self, X):
     obj = X.copy()
     if "ldf_" not in obj:
         obj = Development().fit_transform(obj)
     if len(obj.ddims) - len(obj.ldf_.ddims) == 1:
         obj = TailConstant().fit_transform(obj)
     return obj
Exemplo n.º 8
0
 def validate_X(self, X):
     obj = copy.deepcopy(X)
     if 'ldf_' not in obj:
         obj = Development().fit_transform(obj)
     if len(obj.ddims) - len(obj.ldf_.ddims) == 1:
         obj = TailConstant().fit_transform(obj)
     return obj
Exemplo n.º 9
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 tail will be applied.
        y : Ignored
        sample_weight : Ignored

        Returns
        -------
        self : object
            Returns the instance itself.
        """
        super().fit(X, y, sample_weight)
        tail = self.tail
        self = self._apply_decay(X, tail)
        obj = Development().fit_transform(X) if 'ldf_' not in X else X
        xp = cp.get_array_module(X.values)
        if xp.max(self.tail) != 1.0:
            sigma, std_err = self._get_tail_stats(obj)
            self.sigma_.values[..., -1] = sigma[..., -1]
            self.std_err_.values[..., -1] = std_err[..., -1]
        return self
Exemplo n.º 10
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.
        """
        from chainladder import ULT_VAL

        if self.paid_to_incurred is None:
            raise ValueError("Must enter valid value for paid_to_incurred.")
        if X.array_backend == "sparse":
            obj = X.set_backend("numpy")
        else:
            obj = X.copy()
        xp = obj.get_array_module()
        self.xp = xp
        missing = xp.nan_to_num(obj.values) * obj.nan_triangle == 0
        self.rho_ = obj[obj.origin == obj.origin.min()]
        if len(xp.where(missing)[0]) > 0:
            if self.fillna:
                from chainladder.methods import Chainladder

                filler = Chainladder().fit(obj).full_expectation_
                filler = filler[filler.valuation <= obj.valuation_date].values
                obj.values = xp.where(missing, filler, obj.values)
            else:
                raise ValueError(
                    "MunichAdjustment cannot be performed when P/I or I/P " +
                    "ratios cannot be computed. Use `fillna=True` to impute zero"
                    +
                    " values of the triangle with simple chainladder expectation."
                )

        if "ldf_" not in obj:
            obj = Development().fit_transform(obj)
        self.p_to_i_X_ = self._get_p_to_i_object(obj)
        self.p_to_i_ldf_ = self._get_p_to_i_object(obj.ldf_)
        self.p_to_i_sigma_ = self._get_p_to_i_object(obj.sigma_)
        self.q_f_, self.rho_sigma_ = self._get_MCL_model(obj)
        self.residual_, self.q_resid_ = self._get_MCL_resids(obj)
        self.lambda_coef_ = self._get_MCL_lambda(obj)
        self.ldf_ = self._set_ldf(
            obj, self._get_mcl_cdf(obj, self.munich_full_triangle_))
        self.ldf_.is_cumulative = False
        self.ldf_.valuation_date = pd.to_datetime(ULT_VAL)
        self._map = {
            (list(X.columns).index(x)): (num % 2, num // 2)
            for num, x in enumerate(np.array(self.paid_to_incurred).flatten())
        }
        self.rho_.values = self._reshape("rho_sigma_")
        return self
Exemplo n.º 11
0
 def fit(self, X, y=None, sample_weight=None):
     obj = copy.copy(X)
     if 'ldf_'not in obj:
         obj = Development().fit_transform(obj)
     self._ave_period = {'Y': (1, 12),
                         'Q': (4, 3),
                         'M': (12, 1)}[obj.development_grain]
     ddims = np.concatenate(
         (obj.ddims, [(item+1)*self._ave_period[1] + obj.ddims[-1]
                      for item in range(self._ave_period[0])], [9999]), 0)
     self.ldf_ = copy.copy(obj.ldf_)
     tail = np.ones(self.ldf_.shape)[..., -1:]
     tail = np.repeat(tail, self._ave_period[0]+1, -1)
     self.ldf_.values = np.concatenate((self.ldf_.values, tail), -1)
     self.ldf_.ddims = np.array(['{}-{}'.format(ddims[i], ddims[i+1])
                                 for i in range(len(ddims)-1)])
     self.ldf_.valuation = self.ldf_._valuation_triangle()
     self.sigma_ = copy.copy(getattr(obj, 'sigma_', obj.cdf_*0))
     self.std_err_ = copy.copy(getattr(obj, 'std_err_', obj.cdf_*0))
     zeros = tail[..., -1:]*0
     self.sigma_.values = np.concatenate(
         (self.sigma_.values, zeros), -1)
     self.std_err_.values = np.concatenate(
         (self.std_err_.values, zeros), -1)
     self.sigma_.ddims = self.std_err_.ddims = \
         np.append(obj.ldf_.ddims, ['{}-9999'.format(int(obj.ddims[-1]))])
     val_array = self.sigma_._valuation_triangle(self.sigma_.ddims)
     self.sigma_.valuation = self.std_err_.valuation = val_array
     self.cdf_ = DevelopmentBase._get_cdf(self)
     self.cdf_.set_slicers()
     self.ldf_.set_slicers()
     self.sigma_.set_slicers()
     self.std_err_.set_slicers()
     return self
Exemplo n.º 12
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 tail will be applied.
        y : Ignored
        sample_weight : Ignored

        Returns
        -------
        self : object
            Returns the instance itself.
        """
        super().fit(X, y, sample_weight)
        xp = self.ldf_.get_array_module()
        tail = self.tail
        if self.attachment_age:
            attach_idx = xp.min(xp.where(X.ddims >= self.attachment_age))
        else:
            attach_idx = len(X.ddims) - 1
        self = self._apply_decay(X, tail, attach_idx)
        obj = Development().fit_transform(X) if "ldf_" not in X else X
        self._get_tail_stats(obj)
        return self
Exemplo n.º 13
0
 def validate_X(self, X):
     obj = copy.copy(X)
     if 'ldf_' not in obj:
         obj = Development().fit_transform(obj)
     if len(obj.ddims) - len(obj.ldf_.ddims) == 1:
         obj = TailConstant().fit_transform(obj)
     for item in ['cdf_', 'ldf_', 'average_']:
         setattr(self, item, getattr(obj, item, None))
     return obj
Exemplo n.º 14
0
 def validate_X(self, X):
     obj = copy.deepcopy(X)
     if obj.__dict__.get('ldf_', None) is None:
         obj = Development().fit_transform(obj)
     if len(obj.ddims) - len(obj.ldf_.ddims) == 1:
         obj = TailConstant().fit_transform(obj)
     self.cdf_ = obj.__dict__.get('cdf_', None)
     self.ldf_ = obj.__dict__.get('ldf_', None)
     self.average_ = obj.__dict__.get('average_', None)
     return obj
Exemplo n.º 15
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 tail will be applied.
        y : Ignored
        sample_weight : Ignored

        Returns
        -------
        self : object
            Returns the instance itself.
        """
        super().fit(X, y, sample_weight)
        xp = cp.get_array_module(self.ldf_.values)
        _y = self.ldf_.values[..., :X.shape[-1] - 1].copy()
        _w = xp.zeros(_y.shape)
        if type(self.fit_period) is not slice:
            raise TypeError('fit_period must be slice.')
        else:
            _w[..., self.fit_period] = 1.0
        if self.errors == 'ignore':
            _w[_y <= 1.0] = 0
            _y[_y <= 1.0] = 1.01
        elif self.errors == 'raise' and xp.any(y < 1.0):
            raise ZeroDivisionError('Tail fit requires all LDFs to be' +
                                    ' greater than 1.0')
        _y = xp.log(_y - 1)
        n_obs = X.shape[-1] - 1
        k, v = X.shape[:2]
        _x = self._get_x(_w, _y)
        # Get LDFs
        coefs = WeightedRegression(axis=3).fit(_x, _y, _w)
        slope, intercept = coefs.slope_, coefs.intercept_
        extrapolate = xp.cumsum(
            xp.ones(tuple(list(_y.shape)[:-1] +
                          [self.extrap_periods + n_obs])), -1)
        tail = self._predict_tail(slope, intercept, extrapolate)
        if self.attachment_age:
            attach_idx = xp.min(xp.where(X.ddims >= self.attachment_age))
        else:
            attach_idx = len(X.ddims) - 1
        self.ldf_.values = xp.concatenate(
            (self.ldf_.values[..., :attach_idx], tail[..., attach_idx:]), -1)
        obj = Development().fit_transform(X) if 'ldf_' not in X else X
        sigma, std_err = self._get_tail_stats(obj)
        self.sigma_.values[..., -1] = sigma[..., -1]
        self.std_err_.values[..., -1] = std_err[..., -1]
        self.slope_ = slope
        self.intercept_ = intercept
        self.cdf_ = DevelopmentBase._get_cdf(self)
        return self
Exemplo n.º 16
0
 def fit(self, X, y=None, sample_weight=None):
     if X.array_backend == "sparse":
         obj = X.set_backend("numpy")
         xp = np
     else:
         xp = X.get_array_module()
         obj = X.copy()
     if "ldf_" not in obj:
         obj = Development().fit_transform(obj)
     self._ave_period = {
         "Y": (1, 12),
         "Q": (4, 3),
         "M": (12, 1)
     }[obj.development_grain]
     ddims = np.concatenate(
         (
             obj.ddims,
             [(item + 1) * self._ave_period[1] + obj.ddims[-1]
              for item in range(self._ave_period[0])],
             [9999],
         ),
         0,
     )
     self.ldf_ = obj.ldf_.copy()
     tail = xp.ones(self.ldf_.shape)[..., -1:]
     tail = xp.repeat(tail, self._ave_period[0] + 1, -1)
     self.ldf_.values = xp.concatenate((self.ldf_.values, tail), -1)
     self.ldf_.ddims = np.array([
         "{}-{}".format(ddims[i], ddims[i + 1])
         for i in range(len(ddims) - 1)
     ])
     if hasattr(obj, "sigma_"):
         self.sigma_ = getattr(obj, "sigma_").copy()
     else:
         self.sigma_ = obj.ldf_ - obj.ldf_
     if hasattr(obj, "std_err_"):
         self.std_err_ = getattr(obj, "std_err_").copy()
     else:
         self.std_err_ = obj.ldf_ - obj.ldf_
     zeros = tail[..., 0:1, -1:] * 0
     self.sigma_.values = xp.concatenate((self.sigma_.values, zeros), -1)
     self.std_err_.values = xp.concatenate((self.std_err_.values, zeros),
                                           -1)
     self.sigma_.ddims = self.std_err_.ddims = np.concatenate(
         (obj.ldf_.ddims, np.array(["{}-9999".format(int(obj.ddims[-1]))])))
     if hasattr(obj, "average_"):
         self.average_ = obj.average_
     else:
         self.average_ = None
     self.ldf_._set_slicers()
     self.sigma_._set_slicers()
     self.std_err_._set_slicers()
     return self
Exemplo n.º 17
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 tail will be applied.
        y : Ignored
        sample_weight : Ignored

        Returns
        -------
        self : object
            Returns the instance itself.
        """
        super().fit(X, y, sample_weight)
        _y = self.ldf_.values[..., :-1].copy()
        _w = np.zeros(_y.shape)
        if type(self.fit_period) is not slice:
            raise TypeError('fit_period must be slice.')
        else:
            _w[..., self.fit_period] = 1.0
        if self.errors == 'ignore':
            _w[_y <= 1.0] = 0
            _y[_y <= 1.0] = 1.01
        elif self.errors == 'raise' and np.any(y < 1.0):
            raise ZeroDivisionError('Tail fit requires all LDFs to be \
                                     greater than 1.0')
        _y = np.log(_y - 1)
        n_obs = X.shape[-1] - 1
        k, v = X.shape[:2]
        _x = self._get_x(_w, _y)
        # Get LDFs
        coefs = WeightedRegression(axis=3).fit(_x, _y, _w)
        slope, intercept = coefs.slope_, coefs.intercept_
        extrapolate = np.cumsum(
            np.ones(tuple(list(_y.shape)[:-1] + [self.extrap_periods])),
            -1) + n_obs
        tail = self._predict_tail(slope, intercept, extrapolate)
        self.ldf_.values = self.ldf_.values[..., :-tail.shape[-1]]
        self.ldf_.values = np.concatenate((self.ldf_.values, tail), -1)
        if X.__dict__.get('ldf_', None) is None:
            obj = Development().fit_transform(X)
        else:
            obj = X
        sigma, std_err = self._get_tail_stats(obj)
        self.sigma_.values[..., -1] = sigma[..., -1]
        self.std_err_.values[..., -1] = std_err[..., -1]
        self.slope_ = slope
        self.intercept_ = intercept
        self.cdf_ = DevelopmentBase._get_cdf(self)
        return self
Exemplo n.º 18
0
 def fit(self, X, y=None, sample_weight=None):
     backend = X.array_backend
     if backend == "sparse":
         X = X.set_backend("numpy")
     else:
         X = X.copy()
     xp = X.get_array_module()
     if X.shape[:2] != (1, 1):
         raise ValueError(
             "Only single index/column triangles are supported")
     if type(X.ddims) != np.ndarray:
         raise ValueError(
             "Triangle must be expressed with development lags")
     lag = {"M": 1, "Q": 3, "Y": 12}[X.development_grain]
     obj = Development(
         n_periods=self.n_periods,
         drop=self.drop,
         drop_high=self.drop_high,
         drop_low=self.drop_low,
         drop_valuation=self.drop_valuation,
     ).fit_transform(X)
     self.w_ = obj.w_
     obj = Chainladder().fit(obj)
     # Works for only a single triangle - can we generalize this
     exp_incr_triangle = obj.full_expectation_.cum_to_incr().values[
         0, 0, :, :X.shape[-1]]
     exp_incr_triangle = xp.nan_to_num(
         exp_incr_triangle) * obj.X_.nan_triangle
     self.design_matrix_ = self._get_design_matrix(X)
     if self.hat_adj:
         try:
             self.hat_ = self._get_hat(X, exp_incr_triangle)
         except:
             warn("Could not compute hat matrix.  Setting hat_adj to False")
             self.had_adj = False
             self.hat_ = None
     else:
         self.hat_ = None
     self.resampled_triangles_, self.scale_ = self._get_simulation(
         X, exp_incr_triangle)
     n_obs = xp.nansum(self.w_)
     n_origin_params = X.shape[2]
     n_dev_params = X.shape[3] - 1
     deg_free = n_obs - n_origin_params - n_dev_params
     deg_free_adj_fctr = xp.sqrt(n_obs / deg_free)
     return self
Exemplo n.º 19
0
 def fit(self, X, y=None, sample_weight=None):
     if X.array_backend == 'sparse':
         obj = X.set_backend('numpy')
         xp = np
     else:
         xp = X.get_array_module()
         obj = copy.copy(X)
     if 'ldf_' not in obj:
         obj = Development().fit_transform(obj)
     self._ave_period = {
         'Y': (1, 12),
         'Q': (4, 3),
         'M': (12, 1)
     }[obj.development_grain]
     ddims = np.concatenate(
         (obj.ddims, [(item + 1) * self._ave_period[1] + obj.ddims[-1]
                      for item in range(self._ave_period[0])], [9999]), 0)
     self.ldf_ = copy.copy(obj.ldf_)
     tail = xp.ones(self.ldf_.shape)[..., -1:]
     tail = xp.repeat(tail, self._ave_period[0] + 1, -1)
     self.ldf_.values = xp.concatenate((self.ldf_.values, tail), -1)
     self.ldf_.ddims = np.array([
         '{}-{}'.format(ddims[i], ddims[i + 1])
         for i in range(len(ddims) - 1)
     ])
     if hasattr(obj, 'sigma_'):
         self.sigma_ = copy.copy(getattr(obj, 'sigma_'))
     else:
         self.sigma_ = obj.ldf_ - obj.ldf_
     if hasattr(obj, 'std_err_'):
         self.std_err_ = copy.copy(getattr(obj, 'std_err_'))
     else:
         self.std_err_ = obj.ldf_ - obj.ldf_
     zeros = tail[..., 0:1, -1:] * 0
     self.sigma_.values = xp.concatenate((self.sigma_.values, zeros), -1)
     self.std_err_.values = xp.concatenate((self.std_err_.values, zeros),
                                           -1)
     self.sigma_.ddims = self.std_err_.ddims = \
         np.concatenate(
             (obj.ldf_.ddims,
              np.array(['{}-9999'.format(int(obj.ddims[-1]))])))
     self.ldf_._set_slicers()
     self.sigma_._set_slicers()
     self.std_err_._set_slicers()
     return self
Exemplo n.º 20
0
    def fit_transform(self, X, y=None, sample_weight=None):
        """ Equivalent to fit(X).transform(X)

        Parameters
        ----------
        X : Triangle-like
            Set of LDFs based on the model.
        y : Ignored
        sample_weight : Ignored

        Returns
        -------
            X_new : New triangle with transformed attributes.
        """
        self.fit(X)
        if 'std_err_' not in X:
            X = Development().fit_transform(X)
        return self.transform(X)
Exemplo n.º 21
0
 def fit(self, X, y=None, sample_weight=None):
     obj = X.copy()
     if "ldf_" not in obj:
         obj = Development().fit_transform(obj)
     xp = obj.ldf_.get_array_module()
     m = int(self.projection_period / 12)
     self._ave_period = {
         "Y": (1 * m, 12),
         "Q": (4 * m, 3),
         "M": (12 * m, 1)
     }[obj.development_grain]
     t_ddims = [(item + 1) * self._ave_period[1] + obj.ldf_.ddims[-1]
                for item in range(self._ave_period[0] + 1)]
     ddims = np.concatenate(
         (obj.ldf_.ddims, t_ddims),
         0,
     )
     self.ldf_ = obj.ldf_.copy()
     tail = xp.ones(self.ldf_.shape)[..., -1:]
     tail = xp.repeat(tail, self._ave_period[0] + 1, -1)
     self.ldf_.values = xp.concatenate((self.ldf_.values, tail), -1)
     self.ldf_.ddims = ddims
     if hasattr(obj, "sigma_"):
         zeros = (obj.sigma_.iloc[..., -1:] * 0).values
         self.sigma_ = getattr(obj, "sigma_").copy()
         self.sigma_.values = xp.concatenate((self.sigma_.values, zeros),
                                             -1)
         self.std_err_ = getattr(obj, "std_err_").copy()
         self.std_err_.values = xp.concatenate(
             (self.std_err_.values, zeros), -1)
         self.sigma_.ddims = self.std_err_.ddims = self.ldf_.ddims[:obj.
                                                                   shape[2]]
         self.sigma_._set_slicers()
         self.std_err_._set_slicers()
     if hasattr(obj, "average_"):
         self.average_ = obj.average_
     else:
         self.average_ = None
     self.ldf_._set_slicers()
     return self
Exemplo n.º 22
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.
        """

        obj = copy.deepcopy(X)
        xp = cp.get_array_module(obj.values)
        if 'ldf_' not in obj:
            obj = Development().fit_transform(obj)
        self.p_to_i_X_ = self._get_p_to_i_object(obj)
        self.p_to_i_ldf_ = self._get_p_to_i_object(obj.ldf_)
        self.p_to_i_sigma_ = self._get_p_to_i_object(obj.sigma_)
        self.q_f_, self.rho_sigma_ = self._get_MCL_model(obj)
        self.residual_, self.q_resid_ = self._get_MCL_resids(obj)
        self.lambda_coef_ = self._get_MCL_lambda()
        self.cdf_ = self._get_cdf(obj)
        self.ldf_ = self._set_ldf(X)
        self._map = {
            (list(X.columns).index(x)): (num % 2, num // 2)
            for num, x in enumerate(np.array(self.paid_to_incurred).flatten())
        }
        self.rho_ = copy.deepcopy(X)
        self.rho_.odims = ['(All)']
        self.rho_.values = self._reshape('rho_sigma_')

        return self
Exemplo n.º 23
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 tail will be applied.
        y : Ignored
        sample_weight : Ignored

        Returns
        -------
        self : object
            Returns the instance itself.
        """
        super().fit(X, y, sample_weight)
        xp = cp.get_array_module(X.values)
        obj = Development().fit_transform(X) if 'ldf_' not in X else X
        b_optimized = []
        initial = xp.where(
            obj.ddims == self.earliest_age)[0][0] if self.earliest_age else 0
        for num in range(len(obj.vdims)):
            b0 = xp.ones(obj.shape[0]) * .5
            data = xp.log(obj.ldf_.values[:, num, 0, initial:])
            b_optimized.append(
                least_squares(TailBondy.solver, x0=b0, kwargs={
                    'data': data
                }).x[:, None])
        self.b_ = xp.concatenate(b_optimized, 1)
        tail = xp.exp(xp.log(obj.ldf_.values[..., 0:1, initial:initial+1]) * \
                      self.b_**(len(obj.ldf_.ddims)-1))
        tail = (tail**(self.b_ / (1 - self.b_))) * tail
        self = self._apply_decay(obj, tail)
        sigma, std_err = self._get_tail_stats(obj)
        self.sigma_.values[..., -1] = sigma[..., -1]
        self.std_err_.values[..., -1] = std_err[..., -1]
        return self
Exemplo n.º 24
0
    def fit(self, X, y=None, sample_weight=None):
        """Fit the model with X.

        Parameters
        ----------
        X : Triangle-like
            Triangle to which the incremental method is applied.  Triangle must
            be cumulative.
        y : None
            Ignored
        sample_weight :
            Exposure used in the method.

        Returns
        -------
        self : object
            Returns the instance itself.
        """
        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 X.array_backend == "sparse":
            X = X.set_backend("numpy")
        else:
            X = X.copy()
        if sample_weight.array_backend == "sparse":
            sample_weight = sample_weight.set_backend("numpy")
        else:
            sample_weight = sample_weight.copy()
        xp = X.get_array_module()
        sample_weight.is_cumulative = False
        obj = X.cum_to_incr() / sample_weight.values
        if hasattr(X, "trend_"):
            if self.trend != 0:
                warnings.warn(
                    "IncrementalAdditive Trend assumption is ignored when X has a trend_ property."
                )
            x = obj * obj.trend_.values
        else:
            x = obj.trend(self.trend, axis='valuation')

        w_ = Development(
            n_periods=self.n_periods - 1, drop=self.drop,
            drop_high=self.drop_high, drop_low=self.drop_low,
            drop_valuation=self.drop_valuation).fit(x).w_
        # This will miss drops on the latest diagonal
        w_ = num_to_nan(w_)
        w_ = xp.concatenate((w_, (w_[..., -1:] * x.nan_triangle)[..., -1:]), axis=-1)
        if self.average == "simple":
            y_ = xp.nanmean(w_ * x.values, axis=-2)
        if self.average == "volume":
            y_ = xp.nansum(w_ * x.values * sample_weight.values, axis=-2)
            y_ = y_ / xp.nansum(w_ * sample_weight.values, axis=-2)
        self.zeta_ = X.iloc[..., -1:, :]
        self.zeta_.values = y_[:, :, None, :]
        y_ = xp.repeat(y_[..., None, :], len(x.odims), -2)
        obj = x.copy()
        keeps = (
            1
            - xp.nan_to_num(x.nan_triangle)
            + xp.nan_to_num(
                x[x.valuation == x.valuation_date].values[0, 0, ...] * 0 + 1
            )
        )
        obj.values = y_ * keeps
        obj.valuation_date = obj.valuation.max()
        obj.values = obj.values * (1 - xp.nan_to_num(x.nan_triangle)) + xp.nan_to_num(
            (X.cum_to_incr().values / sample_weight.values)
        )

        obj.values[obj.values == 0] = xp.nan
        obj._set_slicers()
        obj.valuation_date = obj.valuation.max()
        future_trend = self.trend if not self.future_trend else self.future_trend
        self.incremental_ = obj * sample_weight.values
        self.incremental_ = self.incremental_.trend(
            1/(1+future_trend)-1, axis='valuation', start=X.valuation_date,
            end=self.incremental_.valuation_date)
        self.ldf_ = obj.incr_to_cum().link_ratio
        return self
Exemplo n.º 25
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 tail will be applied.
        y : Ignored
        sample_weight : Ignored

        Returns
        -------
        self : object
            Returns the instance itself.
        """
        if self.attachment_age and self.attachment_age < self.earliest_age:
            raise ValueError('attachment_age must not be before earliest_age.')
        super().fit(X, y, sample_weight)
        xp = cp.get_array_module(X.values)
        if self.earliest_age is None:
            earliest_age = X.ddims[0]
        else:
            earliest_age = X.ddims[int(self.earliest_age / ({
                'Y': 12,
                'Q': 3,
                'M': 1
            }[X.development_grain])) - 1]
        attachment_age = self.attachment_age if self.attachment_age else X.ddims[
            -2]
        obj = Development().fit_transform(X) if 'ldf_' not in X else X
        b_optimized = []
        initial = xp.where(
            obj.ddims == earliest_age)[0][0] if earliest_age else 0
        for num in range(len(obj.vdims)):
            b0 = (xp.ones(obj.shape[0]) * .5)[:, None]
            data = xp.log(obj.ldf_.values[:, num, 0, initial:])
            b0 = xp.concatenate((b0, data[..., 0:1]), axis=1)
            b_optimized.append(
                least_squares(TailBondy._solver,
                              x0=b0.flatten(),
                              kwargs={
                                  'data': data
                              }).x)
        self.b_ = xp.concatenate(
            [item.reshape(-1, 2)[:, 0:1] for item in b_optimized],
            axis=1)[..., None, None]
        self.earliest_ldf_ = xp.exp(
            xp.concatenate(
                [item.reshape(-1, 2)[:, 1:2] for item in b_optimized],
                axis=1)[..., None, None])
        if sum(X.ddims > earliest_age) > 1:
            tail = xp.exp(self.earliest_ldf_ *
                          self.b_**(len(obj.ldf_.ddims) - 1))
        else:
            tail = self.ldf_.values[..., 0, initial]
        tail = (tail**(self.b_ / (1 - self.b_)))
        f0 = self.ldf_.values[..., 0:1, initial:initial + 1]
        fitted = (f0**(self.b_**(np.arange(
            sum(X.ddims >= earliest_age))[None, None, None, :])))
        fitted = xp.concatenate(
            (fitted, fitted[..., -1:]**(self.b_ / (1 - self.b_))), axis=-1)
        fitted = xp.repeat(fitted, self.ldf_.shape[2], axis=2)
        idx = X._idx_table()
        self.b_ = pd.DataFrame(self.b_[..., 0, 0],
                               index=idx.index,
                               columns=idx.columns)
        self.earliest_ldf_ = pd.DataFrame(self.earliest_ldf_[..., 0, 0],
                                          index=idx.index,
                                          columns=idx.columns)
        self.ldf_.values = xp.concatenate(
            (self.ldf_.values[..., :sum(X.ddims <= attachment_age)],
             fitted[..., -sum(X.ddims >= attachment_age):]),
            axis=-1)
        sigma, std_err = self._get_tail_stats(obj)
        self.sigma_.values[..., -1] = sigma[..., -1]
        self.std_err_.values[..., -1] = std_err[..., -1]
        return self
Exemplo n.º 26
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 tail will be applied.
        y : Ignored
        sample_weight : Ignored

        Returns
        -------
        self : object
            Returns the instance itself.
        """

        if type(self.fit_period) == slice:
            warnings.warn(
                "Slicing for fit_period is deprecated and will be removed. Please use a tuple (start_age, end_age)."
            )
            fit_period = self.fit_period
        else:
            grain = {'Y': 12, 'Q': 3, 'M': 1}[X.development_grain]
            start = None if self.fit_period[0] is None else int(
                self.fit_period[0] / grain - 1)
            end = None if self.fit_period[1] is None else int(
                self.fit_period[1] / grain - 1)
            fit_period = slice(start, end, None)
        super().fit(X, y, sample_weight)
        xp = cp.get_array_module(self.ldf_.values)
        _y = self.ldf_.values[..., :X.shape[-1] - 1].copy()
        _w = xp.zeros(_y.shape)
        _w[..., fit_period] = 1.0
        if self.errors == 'ignore':
            _w[_y <= 1.0] = 0
            _y[_y <= 1.0] = 1.01
        elif self.errors == 'raise' and xp.any(y < 1.0):
            raise ZeroDivisionError(
                'Tail fit requires all LDFs to be greater than 1.0')
        _y = xp.log(_y - 1)
        n_obs = X.shape[-1] - 1
        k, v = X.shape[:2]
        _x = self._get_x(_w, _y)
        # Get LDFs
        coefs = WeightedRegression(axis=3).fit(_x, _y, _w)
        self._slope_, self._intercept_ = coefs.slope_, coefs.intercept_
        extrapolate = xp.cumsum(
            xp.ones(tuple(list(_y.shape)[:-1] +
                          [self.extrap_periods + n_obs])), -1)
        tail = self._predict_tail(extrapolate)
        if self.attachment_age:
            attach_idx = xp.min(xp.where(X.ddims >= self.attachment_age))
        else:
            attach_idx = len(X.ddims) - 1
        self.ldf_.values = xp.concatenate(
            (self.ldf_.values[..., :attach_idx], tail[..., attach_idx:]), -1)
        obj = Development().fit_transform(X) if 'ldf_' not in X else X
        sigma, std_err = self._get_tail_stats(obj)
        self.sigma_.values[..., -1] = sigma[..., -1]
        self.std_err_.values[..., -1] = std_err[..., -1]
        return self
Exemplo n.º 27
0
    def transform(self, X):
        """ If X and self are of different shapes, align self to X, else
        return self.

        Parameters
        ----------
        X : Triangle
            The triangle to be transformed

        Returns
        -------
            X_new : New triangle with transformed attributes.
        """
        backend = X.array_backend
        if backend == 'sparse':
            X_new = X.set_backend('numpy')
        else:
            X_new = copy.deepcopy(X)
        xp = X_new.get_array_module()
        self.xp = xp
        if 'ldf_' not in X_new:
            X_new = Development().fit_transform(X_new)
        self.xp = X_new.get_array_module()
        X_new.p_to_i_X_ = self._get_p_to_i_object(X_new)
        X_new.p_to_i_ldf_ = self._get_p_to_i_object(X_new.ldf_)
        X_new.p_to_i_sigma_ = self._get_p_to_i_object(X_new.sigma_)
        X_new.q_f_, X_new.rho_sigma_ = self._get_MCL_model(X_new)
        X_new.munich_full_triangle_ = self._get_munich_full_triangle_(
            X_new.p_to_i_X_, X_new.p_to_i_ldf_, X_new.p_to_i_sigma_,
            self.lambda_coef_, X_new.rho_sigma_, X_new.q_f_)
        X_new.ldf_ = self._set_ldf(X_new, self._get_mcl_cdf(X_new, X_new.munich_full_triangle_))
        del self.xp
        triangles = ['rho_', 'lambda_', 'lambda_coef_']
        for item in triangles:
            setattr(X_new, item, getattr(self, item))
        X_new._set_slicers()
        return X_new
Exemplo n.º 28
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 tail will be applied.
        y : Ignored
        sample_weight : Ignored

        Returns
        -------
        self : object
            Returns the instance itself.
        """
        if self.attachment_age and self.attachment_age < self.earliest_age:
            raise ValueError("attachment_age must not be before earliest_age.")
        backend = X.array_backend
        if X.array_backend == "cupy":
            X = X.set_backend("numpy", deep=True)
        else:
            X = X.set_backend("numpy")
        xp = X.get_array_module()
        super().fit(X, y, sample_weight)

        if self.earliest_age is None:
            earliest_age = X.ddims[-2]
        else:
            earliest_age = X.ddims[int(self.earliest_age / ({
                "Y": 12,
                "Q": 3,
                "M": 1
            }[X.development_grain])) - 1]
        attachment_age = self.attachment_age if self.attachment_age else X.ddims[
            -2]
        obj = Development().fit_transform(X) if "ldf_" not in X else X
        b_optimized = []
        initial = xp.where(
            obj.ddims == earliest_age)[0][0] if earliest_age else 0
        for num in range(len(obj.vdims)):
            b0 = (xp.ones(obj.shape[0]) * 0.5)[:, None]
            data = xp.log(obj.ldf_.values[:, num, 0, initial:])
            b0 = xp.concatenate((b0, data[..., 0:1]), axis=1)
            b_optimized.append(
                least_squares(TailBondy._solver,
                              x0=b0.flatten(),
                              kwargs={
                                  "data": data,
                                  "xp": xp
                              }).x)
        self.b_ = xp.concatenate(
            [item.reshape(-1, 2)[:, 0:1] for item in b_optimized],
            axis=1)[..., None, None]
        self.earliest_ldf_ = xp.exp(
            xp.concatenate(
                [item.reshape(-1, 2)[:, 1:2] for item in b_optimized],
                axis=1)[..., None, None])
        if sum(X.ddims > earliest_age) > 1:
            tail = xp.exp(self.earliest_ldf_ *
                          self.b_**(len(obj.ldf_.ddims) - 1))
        else:
            tail = self.ldf_.values[..., 0, initial]
        tail = tail**(self.b_ / (1 - self.b_))
        f0 = self.ldf_.values[..., 0:1, initial:initial + 1]
        fitted = f0**(self.b_**(np.arange(
            sum(X.ddims >= earliest_age))[None, None, None, :]))
        fitted = xp.concatenate(
            (fitted, fitted[..., -1:]**(self.b_ / (1 - self.b_))), axis=-1)
        fitted = xp.repeat(fitted, self.ldf_.shape[2], axis=2)
        rows = X.index.set_index(X.key_labels).index
        self.b_ = pd.DataFrame(self.b_[..., 0, 0], index=rows, columns=X.vdims)
        self.earliest_ldf_ = pd.DataFrame(self.earliest_ldf_[..., 0, 0],
                                          index=rows,
                                          columns=X.vdims)
        self.ldf_.values = xp.concatenate(
            (
                self.ldf_.values[..., :sum(X.ddims <= attachment_age)],
                fitted[..., -sum(X.ddims >= attachment_age):],
            ),
            axis=-1,
        )
        self._get_tail_stats(obj)
        if backend == "cupy":
            self = self.set_backend(backend, inplace=True, deep=True)
        return self
Exemplo n.º 29
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 tail will be applied.
        y : Ignored
        sample_weight : Ignored

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

        if X.array_backend == "sparse":
            X = X.set_backend("numpy")
        else:
            X = X.copy()
        xp = X.get_array_module()
        if type(self.fit_period) == slice:
            warnings.warn(
                "Slicing for fit_period is deprecated and will be removed. Please use a tuple (start_age, end_age)."
            )
            fit_period = self.fit_period
        else:
            grain = {"Y": 12, "Q": 3, "M": 1}[X.development_grain]
            start = (None if self.fit_period[0] is None else
                     int(self.fit_period[0] / grain - 1))
            end = (None if self.fit_period[1] is None else
                   int(self.fit_period[1] / grain - 1))
            fit_period = slice(start, end, None)
        super().fit(X, y, sample_weight)
        xp = self.ldf_.get_array_module()
        _y = self.ldf_.values[..., :X.shape[-1] - 1].copy()
        _w = xp.zeros(_y.shape)
        _w[..., fit_period] = 1.0
        if self.reg_threshold[0] is None:
            warnings.warn("Lower threshold for ldfs not set. Lower threshold will be set to 1.0 to ensure" \
                          "valid inputs for regression.")
            lower_threshold = 1
        elif self.reg_threshold[0] < 1:
            warnings.warn("Lower threshold for ldfs set too low (<1). Lower threshold will be set to 1.0 to ensure" \
                          "valid inputs for regression.")
            lower_threshold = 1
        else:
            lower_threshold = self.reg_threshold[0]
        if self.reg_threshold[1] is not None:
            if self.reg_threshold[1] <= lower_threshold:
                warnings.warn(
                    "Can't set upper threshold for ldfs below lower threshold. Upper threshold will be set to 'None'."
                )
                upper_threshold = None
            else:
                upper_threshold = self.reg_threshold[1]
        else:
            upper_threshold = self.reg_threshold[1]
        if self.errors == "ignore":
            if upper_threshold is None:
                _w[_y <= lower_threshold] = 0
                _y[_y <= lower_threshold] = 1.01
            else:
                _w[(_y <= lower_threshold) | (_y > upper_threshold)] = 0
                _y[(_y <= lower_threshold) | (_y > upper_threshold)] = 1.01
        elif self.errors == "raise" and xp.any(y < 1.0):
            raise ZeroDivisionError(
                "Tail fit requires all LDFs to be greater than 1.0")
        _y = xp.log(_y - 1)
        n_obs = X.shape[-1] - 1
        k, v = X.shape[:2]
        _x = self._get_x(_w, _y)
        # Get LDFs
        coefs = WeightedRegression(axis=3, xp=xp).fit(_x, _y, _w)
        self._slope_, self._intercept_ = coefs.slope_, coefs.intercept_
        extrapolate = xp.cumsum(
            xp.ones(tuple(list(_y.shape)[:-1] +
                          [self.extrap_periods + n_obs])), -1)
        tail = self._predict_tail(extrapolate)
        if self.attachment_age:
            attach_idx = xp.min(xp.where(X.ddims >= self.attachment_age))
        else:
            attach_idx = len(X.ddims) - 1
        self.ldf_.values = xp.concatenate(
            (self.ldf_.values[..., :attach_idx], tail[..., attach_idx:]), -1)
        obj = Development().fit_transform(X) if "ldf_" not in X else X
        self._get_tail_stats(obj)
        return self
Exemplo n.º 30
0
 def fit(self, X, y=None, sample_weight=None):
     if X.shape[1] > 1:
         from chainladder.utils.utility_functions import concat
         out = [
             BootstrapODPSample(**self.get_params()).fit(X.iloc[:, i])
             for i in range(X.shape[1])
         ]
         xp = X.get_array_module(out[0].design_matrix_)
         self.design_matrix_ = xp.concatenate(
             [i.design_matrix_[None] for i in out], axis=0)
         self.hat_ = xp.concatenate([i.hat_[None] for i in out], axis=0)
         self.resampled_triangles_ = concat(
             [i.resampled_triangles_ for i in out], axis=1)
         self.scale_ = xp.array([i.scale_ for i in out])
         self.w_ = out[0].w_
     else:
         backend = X.array_backend
         if backend == "sparse":
             X = X.set_backend("numpy")
         else:
             X = X.copy()
         xp = X.get_array_module()
         if len(X) != 1:
             raise ValueError("Only single index triangles are supported")
         if type(X.ddims) != np.ndarray:
             raise ValueError(
                 "Triangle must be expressed with development lags")
         lag = {"M": 1, "Q": 3, "Y": 12}[X.development_grain]
         obj = Development(
             n_periods=self.n_periods,
             drop=self.drop,
             drop_high=self.drop_high,
             drop_low=self.drop_low,
             drop_valuation=self.drop_valuation,
         ).fit_transform(X)
         self.w_ = obj.w_
         obj = Chainladder().fit(obj)
         # Works for only a single triangle - can we generalize this
         exp_incr_triangle = obj.full_expectation_.cum_to_incr().values[
             0, 0, :, :X.shape[-1]]
         exp_incr_triangle = xp.nan_to_num(
             exp_incr_triangle) * obj.X_.nan_triangle
         self.design_matrix_ = self._get_design_matrix(X)
         if self.hat_adj:
             try:
                 self.hat_ = self._get_hat(X, exp_incr_triangle)
             except:
                 warn(
                     "Could not compute hat matrix.  Setting hat_adj to False"
                 )
                 self.had_adj = False
                 self.hat_ = None
         else:
             self.hat_ = None
         self.resampled_triangles_, self.scale_ = self._get_simulation(
             X, exp_incr_triangle)
         n_obs = xp.nansum(self.w_)
         n_origin_params = X.shape[2]
         n_dev_params = X.shape[3] - 1
         deg_free = n_obs - n_origin_params - n_dev_params
         deg_free_adj_fctr = xp.sqrt(n_obs / deg_free)
     return self