Edit on GitHub

insurance_frequency_severity.dependent

insurance_frequency_severity.dependent

Dependent frequency-severity neural two-part model for insurance pricing.

The core idea is multi-task learning: a single shared encoder trunk processes covariates and produces a latent representation that feeds both a Poisson frequency head and a Gamma severity head. Gradients from both losses flow through the trunk simultaneously, so it learns features that are jointly informative for frequency and severity. That shared information is where the implicit frequency-severity dependence lives.

On top of the latent dependence you can add the explicit Garrido-Genest-Schulz conditional covariate (log μ += γ·N), which gives a semi-analytical pure premium correction and a directly interpretable dependence parameter.

This subpackage is distinct from the Sarmanov copula approach in the parent package. Use Sarmanov when you need an analytical bivariate density and a simple omega parameter for a regulator; use this subpackage when you have a large dataset, suspect nonlinear interactions, and want a single model that learns both tasks jointly.

Requires torch for neural network classes. Install with: pip install insurance-frequency-severity[neural]

Public API

Model ~ DependentFreqSevNet – PyTorch nn.Module (shared trunk + heads) SharedTrunkConfig – dataclass for trunk hyperparameters (no torch needed) FrequencyHead – Poisson head module SeverityHead – Gamma head module

Training ~~~~ JointLoss – Poisson + Gamma NLL with configurable balancing TrainingConfig – dataclass for training hyperparameters (no torch needed) DependentFSTrainer – training loop with early stopping and LR scheduling

Wrapper ~~~ DependentFSModel – sklearn-compatible estimator (fit/predict/score)

Premium ~~~ PurePremiumEstimator – Monte Carlo + optional MGF analytical correction

Diagnostics ~~~ DependentFSDiagnostics – Lorenz, calibration, dependence tests, latent corr

Data ~~~~ FreqSevDataset – PyTorch Dataset with exposure handling prepare_features – numeric encoding helper (no torch needed)

Benchmarks ~~ make_dependent_claims – synthetic claims with known γ dependence make_independent_claims – synthetic independent baseline

  1"""
  2insurance_frequency_severity.dependent
  3=======================================
  4Dependent frequency-severity neural two-part model for insurance pricing.
  5
  6The core idea is multi-task learning: a single shared encoder trunk processes
  7covariates and produces a latent representation that feeds both a Poisson
  8frequency head and a Gamma severity head.  Gradients from both losses flow
  9through the trunk simultaneously, so it learns features that are jointly
 10informative for frequency *and* severity.  That shared information is where the
 11implicit frequency-severity dependence lives.
 12
 13On top of the latent dependence you can add the explicit Garrido-Genest-Schulz
 14conditional covariate (log μ += γ·N), which gives a semi-analytical pure
 15premium correction and a directly interpretable dependence parameter.
 16
 17This subpackage is distinct from the Sarmanov copula approach in the parent
 18package.  Use Sarmanov when you need an analytical bivariate density and a
 19simple omega parameter for a regulator; use this subpackage when you have a
 20large dataset, suspect nonlinear interactions, and want a single model that
 21learns both tasks jointly.
 22
 23Requires torch for neural network classes.
 24Install with: pip install insurance-frequency-severity[neural]
 25
 26Public API
 27----------
 28Model
 29~~~~~
 30``DependentFreqSevNet``   – PyTorch nn.Module (shared trunk + heads)
 31``SharedTrunkConfig``     – dataclass for trunk hyperparameters (no torch needed)
 32``FrequencyHead``         – Poisson head module
 33``SeverityHead``          – Gamma head module
 34
 35Training
 36~~~~~~~~
 37``JointLoss``             – Poisson + Gamma NLL with configurable balancing
 38``TrainingConfig``        – dataclass for training hyperparameters (no torch needed)
 39``DependentFSTrainer``    – training loop with early stopping and LR scheduling
 40
 41Wrapper
 42~~~~~~~
 43``DependentFSModel``      – sklearn-compatible estimator (fit/predict/score)
 44
 45Premium
 46~~~~~~~
 47``PurePremiumEstimator``  – Monte Carlo + optional MGF analytical correction
 48
 49Diagnostics
 50~~~~~~~~~~~
 51``DependentFSDiagnostics`` – Lorenz, calibration, dependence tests, latent corr
 52
 53Data
 54~~~~
 55``FreqSevDataset``        – PyTorch Dataset with exposure handling
 56``prepare_features``      – numeric encoding helper (no torch needed)
 57
 58Benchmarks
 59~~~~~~~~~~
 60``make_dependent_claims`` – synthetic claims with known γ dependence
 61``make_independent_claims`` – synthetic independent baseline
 62"""
 63
 64# SharedTrunkConfig and TrainingConfig are safe to import eagerly — pure dataclasses, no torch.
 65from insurance_frequency_severity.dependent.model import SharedTrunkConfig
 66from insurance_frequency_severity.dependent.training import TrainingConfig
 67# prepare_features is also torch-free.
 68from insurance_frequency_severity.dependent.data import prepare_features
 69# Benchmark generators use only numpy/scipy.
 70from insurance_frequency_severity.dependent.benchmarks import make_dependent_claims, make_independent_claims
 71
 72# All remaining names require torch and are loaded lazily.
 73_NEURAL_NAMES = {
 74    "DependentFreqSevNet": ("insurance_frequency_severity.dependent.model", "DependentFreqSevNet"),
 75    "FrequencyHead": ("insurance_frequency_severity.dependent.model", "FrequencyHead"),
 76    "SeverityHead": ("insurance_frequency_severity.dependent.model", "SeverityHead"),
 77    "JointLoss": ("insurance_frequency_severity.dependent.training", "JointLoss"),
 78    "DependentFSTrainer": ("insurance_frequency_severity.dependent.training", "DependentFSTrainer"),
 79    "DependentFSModel": ("insurance_frequency_severity.dependent.wrapper", "DependentFSModel"),
 80    "PurePremiumEstimator": ("insurance_frequency_severity.dependent.premium", "PurePremiumEstimator"),
 81    "DependentFSDiagnostics": ("insurance_frequency_severity.dependent.diagnostics", "DependentFSDiagnostics"),
 82    "FreqSevDataset": ("insurance_frequency_severity.dependent.data", "FreqSevDataset"),
 83    "make_train_val_loaders": ("insurance_frequency_severity.dependent.data", "make_train_val_loaders"),
 84}
 85
 86
 87def __getattr__(name: str):
 88    if name in _NEURAL_NAMES:
 89        module_path, attr = _NEURAL_NAMES[name]
 90        import importlib
 91        mod = importlib.import_module(module_path)
 92        return getattr(mod, attr)
 93    raise AttributeError(f"module 'insurance_frequency_severity.dependent' has no attribute {name!r}")
 94
 95
 96__all__ = [
 97    "SharedTrunkConfig",
 98    "TrainingConfig",
 99    "prepare_features",
100    "make_dependent_claims",
101    "make_independent_claims",
102    # Neural (torch required):
103    "DependentFreqSevNet",
104    "FrequencyHead",
105    "SeverityHead",
106    "JointLoss",
107    "DependentFSTrainer",
108    "DependentFSModel",
109    "PurePremiumEstimator",
110    "DependentFSDiagnostics",
111    "FreqSevDataset",
112    "make_train_val_loaders",
113]
@dataclass
class SharedTrunkConfig:
55@dataclass
56class SharedTrunkConfig:
57    """Hyperparameters for the shared encoder trunk.
58
59    Parameters
60    ----------
61    hidden_dims:
62        Width of each hidden layer in the trunk.  The trunk has
63        ``len(hidden_dims)`` hidden layers.  A good starting point for motor
64        pricing is ``[128, 64]``; reduce to ``[64, 32]`` for smaller datasets.
65    latent_dim:
66        Dimension of the latent representation h that feeds both heads.
67        Typically 16–64.  Higher values give more capacity but slower training.
68    dropout:
69        Dropout probability applied after each hidden layer (except the last).
70        Set to 0.0 to disable.
71    activation:
72        Activation function for all hidden layers.  ``"elu"`` is preferred for
73        count/severity data because it produces smooth gradients near zero.
74        ``"relu"`` and ``"tanh"`` are also supported.
75    use_batch_norm:
76        Whether to apply batch normalisation after each hidden layer.  Helps
77        training stability when input features have very different scales, but
78        can hurt if batch sizes are very small (< 32).
79    """
80
81    hidden_dims: List[int] = field(default_factory=lambda: [128, 64])
82    latent_dim: int = 32
83    dropout: float = 0.1
84    activation: Literal["elu", "relu", "tanh"] = "elu"
85    use_batch_norm: bool = True

Hyperparameters for the shared encoder trunk.

Parameters

hidden_dims: Width of each hidden layer in the trunk. The trunk has len(hidden_dims) hidden layers. A good starting point for motor pricing is [128, 64]; reduce to [64, 32] for smaller datasets. latent_dim: Dimension of the latent representation h that feeds both heads. Typically 16–64. Higher values give more capacity but slower training. dropout: Dropout probability applied after each hidden layer (except the last). Set to 0.0 to disable. activation: Activation function for all hidden layers. "elu" is preferred for count/severity data because it produces smooth gradients near zero. "relu" and "tanh" are also supported. use_batch_norm: Whether to apply batch normalisation after each hidden layer. Helps training stability when input features have very different scales, but can hurt if batch sizes are very small (< 32).

SharedTrunkConfig( hidden_dims: List[int] = <factory>, latent_dim: int = 32, dropout: float = 0.1, activation: Literal['elu', 'relu', 'tanh'] = 'elu', use_batch_norm: bool = True)
hidden_dims: List[int]
latent_dim: int = 32
dropout: float = 0.1
activation: Literal['elu', 'relu', 'tanh'] = 'elu'
use_batch_norm: bool = True
@dataclass
class TrainingConfig:
 62@dataclass
 63class TrainingConfig:
 64    """Hyperparameters for the training loop.
 65
 66    Parameters
 67    ----------
 68    max_epochs:
 69        Maximum number of training epochs.
 70    batch_size:
 71        Mini-batch size.  Larger batches give more stable gradient estimates
 72        but use more memory.  For most UK motor datasets 512-2048 works well.
 73    lr:
 74        Learning rate for the Adam optimiser.
 75    trunk_lr_multiplier:
 76        If not 1.0, the trunk uses ``lr * trunk_lr_multiplier`` while the heads
 77        use ``lr``.  A value < 1.0 (e.g. 0.3) slows trunk updates, which can
 78        help when the heads need to adapt faster.
 79    weight_decay:
 80        L2 regularisation applied to all parameters.
 81    loss_weight_sev:
 82        Fixed severity loss weight (used when ``auto_balance=False``).
 83    auto_balance:
 84        Equalise Poisson and Gamma loss magnitudes automatically each step.
 85    patience:
 86        Early stopping patience (epochs without improvement on validation loss).
 87        Set to None to disable early stopping.
 88    min_delta:
 89        Minimum improvement in validation loss to count as an improvement.
 90    lr_reduce_factor:
 91        Factor by which the LR scheduler reduces the learning rate on plateau.
 92    lr_patience:
 93        Epochs without improvement before the LR scheduler fires.
 94    verbose:
 95        Whether to print epoch-level training summaries.
 96    device:
 97        PyTorch device string.  ``"auto"`` selects CUDA if available, else CPU.
 98    """
 99
100    max_epochs: int = 100
101    batch_size: int = 512
102    lr: float = 1e-3
103    trunk_lr_multiplier: float = 1.0
104    weight_decay: float = 1e-4
105    loss_weight_sev: float = 1.0
106    auto_balance: bool = True
107    patience: Optional[int] = 15
108    min_delta: float = 1e-4
109    lr_reduce_factor: float = 0.5
110    lr_patience: int = 5
111    verbose: bool = True
112    device: str = "auto"

Hyperparameters for the training loop.

Parameters

max_epochs: Maximum number of training epochs. batch_size: Mini-batch size. Larger batches give more stable gradient estimates but use more memory. For most UK motor datasets 512-2048 works well. lr: Learning rate for the Adam optimiser. trunk_lr_multiplier: If not 1.0, the trunk uses lr * trunk_lr_multiplier while the heads use lr. A value < 1.0 (e.g. 0.3) slows trunk updates, which can help when the heads need to adapt faster. weight_decay: L2 regularisation applied to all parameters. loss_weight_sev: Fixed severity loss weight (used when auto_balance=False). auto_balance: Equalise Poisson and Gamma loss magnitudes automatically each step. patience: Early stopping patience (epochs without improvement on validation loss). Set to None to disable early stopping. min_delta: Minimum improvement in validation loss to count as an improvement. lr_reduce_factor: Factor by which the LR scheduler reduces the learning rate on plateau. lr_patience: Epochs without improvement before the LR scheduler fires. verbose: Whether to print epoch-level training summaries. device: PyTorch device string. "auto" selects CUDA if available, else CPU.

TrainingConfig( max_epochs: int = 100, batch_size: int = 512, lr: float = 0.001, trunk_lr_multiplier: float = 1.0, weight_decay: float = 0.0001, loss_weight_sev: float = 1.0, auto_balance: bool = True, patience: Optional[int] = 15, min_delta: float = 0.0001, lr_reduce_factor: float = 0.5, lr_patience: int = 5, verbose: bool = True, device: str = 'auto')
max_epochs: int = 100
batch_size: int = 512
lr: float = 0.001
trunk_lr_multiplier: float = 1.0
weight_decay: float = 0.0001
loss_weight_sev: float = 1.0
auto_balance: bool = True
patience: Optional[int] = 15
min_delta: float = 0.0001
lr_reduce_factor: float = 0.5
lr_patience: int = 5
verbose: bool = True
device: str = 'auto'
def prepare_features( df: pandas.DataFrame, numeric_cols: List[str], categorical_cols: Optional[List[str]] = None, transformer: Optional[sklearn.compose._column_transformer.ColumnTransformer] = None) -> Tuple[numpy.ndarray, sklearn.compose._column_transformer.ColumnTransformer]:
 55def prepare_features(
 56    df: pd.DataFrame,
 57    numeric_cols: List[str],
 58    categorical_cols: Optional[List[str]] = None,
 59    transformer: Optional[ColumnTransformer] = None,
 60) -> Tuple[np.ndarray, ColumnTransformer]:
 61    """Encode a DataFrame into a numeric matrix.
 62
 63    Numeric columns are standardised (zero mean, unit variance).  Categorical
 64    columns are one-hot encoded (unknown categories at inference are set to
 65    all-zero rows, not an error).
 66
 67    Does not require torch.
 68
 69    Parameters
 70    ----------
 71    df:
 72        Input data.  Must contain all columns in ``numeric_cols`` and
 73        ``categorical_cols``.
 74    numeric_cols:
 75        Names of numeric/continuous columns.
 76    categorical_cols:
 77        Names of categorical columns.  Pass ``None`` or ``[]`` if there are no
 78        categoricals.
 79    transformer:
 80        A fitted ``ColumnTransformer`` from a previous call to this function.
 81        Pass this when encoding held-out or test data to ensure the same
 82        encoding is applied.  When ``None``, a new transformer is fitted on
 83        ``df``.
 84
 85    Returns
 86    -------
 87    X: np.ndarray of shape (n, n_features_out)
 88        Encoded feature matrix.
 89    transformer: ColumnTransformer
 90        Fitted transformer (reuse for test data).
 91
 92    Examples
 93    --------
 94    >>> X_train, ct = prepare_features(df_train, numeric_cols=["age", "value"],
 95    ...                                categorical_cols=["vehicle_class"])
 96    >>> X_test, _  = prepare_features(df_test, numeric_cols=["age", "value"],
 97    ...                                categorical_cols=["vehicle_class"],
 98    ...                                transformer=ct)
 99    """
100    categorical_cols = categorical_cols or []
101
102    if transformer is None:
103        transformers = []
104        if numeric_cols:
105            transformers.append(
106                ("num", StandardScaler(), numeric_cols)
107            )
108        if categorical_cols:
109            transformers.append(
110                (
111                    "cat",
112                    OneHotEncoder(handle_unknown="ignore", sparse_output=False),
113                    categorical_cols,
114                )
115            )
116        transformer = ColumnTransformer(transformers, remainder="drop")
117        transformer.fit(df)
118
119    X = transformer.transform(df).astype(np.float32)
120    return X, transformer

Encode a DataFrame into a numeric matrix.

Numeric columns are standardised (zero mean, unit variance). Categorical columns are one-hot encoded (unknown categories at inference are set to all-zero rows, not an error).

Does not require torch.

Parameters

df: Input data. Must contain all columns in numeric_cols and categorical_cols. numeric_cols: Names of numeric/continuous columns. categorical_cols: Names of categorical columns. Pass None or [] if there are no categoricals. transformer: A fitted ColumnTransformer from a previous call to this function. Pass this when encoding held-out or test data to ensure the same encoding is applied. When None, a new transformer is fitted on df.

Returns

X: np.ndarray of shape (n, n_features_out) Encoded feature matrix. transformer: ColumnTransformer Fitted transformer (reuse for test data).

Examples

>>> X_train, ct = prepare_features(df_train, numeric_cols=["age", "value"],
...                                categorical_cols=["vehicle_class"])
>>> X_test, _  = prepare_features(df_test, numeric_cols=["age", "value"],
...                                categorical_cols=["vehicle_class"],
...                                transformer=ct)
def make_dependent_claims( n_policies: int = 10000, gamma: float = -0.15, base_freq: float = 0.08, base_sev: float = 3000.0, phi: float = 1.5, n_features: int = 5, seed: int = 42, test_fraction: float = 0.2) -> Tuple[pandas.DataFrame, pandas.DataFrame]:
 37def make_dependent_claims(
 38    n_policies: int = 10_000,
 39    gamma: float = -0.15,
 40    base_freq: float = 0.08,
 41    base_sev: float = 3_000.0,
 42    phi: float = 1.5,
 43    n_features: int = 5,
 44    seed: int = 42,
 45    test_fraction: float = 0.2,
 46) -> Tuple[pd.DataFrame, pd.DataFrame]:
 47    """Generate synthetic motor insurance claims with known frequency-severity dependence.
 48
 49    Data generating process
 50    -----------------------
 51    For each policy i with covariates xᵢ and exposure tᵢ:
 52
 53    1. log λᵢ = log(tᵢ) + β₀ + Xᵢ · β_freq       (Poisson frequency)
 54    2. Nᵢ ~ Poisson(λᵢ · tᵢ)
 55    3. log μᵢ = α₀ + Xᵢ · β_sev + γ · Nᵢ         (GGS conditional severity)
 56    4. If Nᵢ > 0: Ȳᵢ ~ Gamma(shape=Nᵢ/φ, mean=μᵢ); else Ȳᵢ = 0
 57
 58    The parameter γ is the true dependence parameter the model should recover.
 59    Negative γ (default −0.15) means higher-claim-count policies have lower
 60    average severity — the pattern typically found in UK motor.
 61
 62    Parameters
 63    ----------
 64    n_policies:
 65        Number of policies in the full dataset (train + test combined).
 66    gamma:
 67        True dependence parameter.  γ=0 gives independence; γ<0 gives negative
 68        frequency-severity correlation (typical for motor).
 69    base_freq:
 70        Baseline claim frequency (λ at x=0, t=1).
 71    base_sev:
 72        Baseline average severity (μ at x=0, N=0), in pounds.
 73    phi:
 74        Gamma dispersion parameter φ.  Higher values give more severity
 75        variability.
 76    n_features:
 77        Number of synthetic covariates.  First half affect frequency, second
 78        half affect severity; they all share the same feature matrix so the
 79        trunk has genuine heterogeneity to exploit.
 80    seed:
 81        Random seed.
 82    test_fraction:
 83        Fraction of data to hold out as test set.
 84
 85    Returns
 86    -------
 87    df_train, df_test : pd.DataFrame
 88        DataFrames with columns:
 89        ``feature_0``, …, ``feature_{n_features-1}``,
 90        ``exposure``, ``n_claims``, ``avg_severity``, ``total_loss``,
 91        ``true_lambda``, ``true_mu``.
 92
 93    Examples
 94    --------
 95    >>> df_train, df_test = make_dependent_claims(n_policies=20_000, gamma=-0.15)
 96    >>> df_train.head()
 97    """
 98    rng = np.random.default_rng(seed)
 99
100    # --- Covariates ---
101    X = rng.standard_normal((n_policies, n_features)).astype(np.float32)
102
103    # --- Exposure: mix of short- and full-year policies ---
104    exposure = rng.choice([0.25, 0.5, 0.75, 1.0, 1.0, 1.0], size=n_policies).astype(np.float32)
105
106    # --- Regression coefficients ---
107    n_freq_feats = max(1, n_features // 2)
108    n_sev_feats = n_features - n_freq_feats
109    beta_freq = rng.uniform(-0.3, 0.3, size=n_freq_feats).astype(np.float32)
110    beta_sev = rng.uniform(-0.2, 0.2, size=n_sev_feats).astype(np.float32)
111
112    # --- Frequency ---
113    log_lambda_base = np.log(base_freq) + X[:, :n_freq_feats] @ beta_freq
114    lambda_ = np.exp(log_lambda_base) * exposure
115    n_claims = rng.poisson(lambda_).astype(np.float32)
116
117    # --- Conditional severity ---
118    log_mu = np.log(base_sev) + X[:, n_freq_feats:] @ beta_sev + gamma * n_claims
119    mu = np.exp(log_mu)
120
121    avg_severity = np.zeros(n_policies, dtype=np.float32)
122    pos = n_claims > 0
123    if pos.sum() > 0:
124        alpha = n_claims[pos] / phi
125        rate = n_claims[pos] / (phi * mu[pos] + 1e-10)
126        avg_severity[pos] = rng.gamma(shape=alpha, scale=1.0 / rate).astype(np.float32)
127
128    total_loss = n_claims * avg_severity
129
130    feature_cols = [f"feature_{i}" for i in range(n_features)]
131    df = pd.DataFrame(X, columns=feature_cols)
132    df["exposure"] = exposure
133    df["n_claims"] = n_claims
134    df["avg_severity"] = avg_severity
135    df["total_loss"] = total_loss
136    df["true_lambda"] = lambda_ / exposure  # per unit exposure
137    df["true_mu"] = mu
138
139    # --- Split ---
140    n_test = max(1, int(n_policies * test_fraction))
141    df_test = df.iloc[-n_test:].copy().reset_index(drop=True)
142    df_train = df.iloc[:-n_test].copy().reset_index(drop=True)
143
144    return df_train, df_test

Generate synthetic motor insurance claims with known frequency-severity dependence.

Data generating process

For each policy i with covariates xᵢ and exposure tᵢ:

  1. log λᵢ = log(tᵢ) + β₀ + Xᵢ · β_freq (Poisson frequency)
  2. Nᵢ ~ Poisson(λᵢ · tᵢ)
  3. log μᵢ = α₀ + Xᵢ · β_sev + γ · Nᵢ (GGS conditional severity)
  4. If Nᵢ > 0: Ȳᵢ ~ Gamma(shape=Nᵢ/φ, mean=μᵢ); else Ȳᵢ = 0

The parameter γ is the true dependence parameter the model should recover. Negative γ (default −0.15) means higher-claim-count policies have lower average severity — the pattern typically found in UK motor.

Parameters

n_policies: Number of policies in the full dataset (train + test combined). gamma: True dependence parameter. γ=0 gives independence; γ<0 gives negative frequency-severity correlation (typical for motor). base_freq: Baseline claim frequency (λ at x=0, t=1). base_sev: Baseline average severity (μ at x=0, N=0), in pounds. phi: Gamma dispersion parameter φ. Higher values give more severity variability. n_features: Number of synthetic covariates. First half affect frequency, second half affect severity; they all share the same feature matrix so the trunk has genuine heterogeneity to exploit. seed: Random seed. test_fraction: Fraction of data to hold out as test set.

Returns

df_train, df_test : pd.DataFrame DataFrames with columns: feature_0, …, feature_{n_features-1}, exposure, n_claims, avg_severity, total_loss, true_lambda, true_mu.

Examples

>>> df_train, df_test = make_dependent_claims(n_policies=20_000, gamma=-0.15)
>>> df_train.head()
def make_independent_claims( n_policies: int = 10000, base_freq: float = 0.08, base_sev: float = 3000.0, phi: float = 1.5, n_features: int = 5, seed: int = 42, test_fraction: float = 0.2) -> Tuple[pandas.DataFrame, pandas.DataFrame]:
147def make_independent_claims(
148    n_policies: int = 10_000,
149    base_freq: float = 0.08,
150    base_sev: float = 3_000.0,
151    phi: float = 1.5,
152    n_features: int = 5,
153    seed: int = 42,
154    test_fraction: float = 0.2,
155) -> Tuple[pd.DataFrame, pd.DataFrame]:
156    """Generate synthetic claims with γ=0 (frequency-severity independence).
157
158    Identical to ``make_dependent_claims`` with ``gamma=0``.  Use this as the
159    null comparison to verify the model does not overfit spurious dependence.
160
161    Parameters
162    ----------
163    n_policies, base_freq, base_sev, phi, n_features, seed, test_fraction:
164        Same as ``make_dependent_claims``.
165
166    Returns
167    -------
168    df_train, df_test : pd.DataFrame
169    """
170    return make_dependent_claims(
171        n_policies=n_policies,
172        gamma=0.0,
173        base_freq=base_freq,
174        base_sev=base_sev,
175        phi=phi,
176        n_features=n_features,
177        seed=seed,
178        test_fraction=test_fraction,
179    )

Generate synthetic claims with γ=0 (frequency-severity independence).

Identical to make_dependent_claims with gamma=0. Use this as the null comparison to verify the model does not overfit spurious dependence.

Parameters

n_policies, base_freq, base_sev, phi, n_features, seed, test_fraction: Same as make_dependent_claims.

Returns

df_train, df_test : pd.DataFrame

DependentFreqSevNet
FrequencyHead
SeverityHead
JointLoss
DependentFSTrainer
DependentFSModel
PurePremiumEstimator
DependentFSDiagnostics
FreqSevDataset
make_train_val_loaders