CCDM Procedure
Scenario Analysis
The distributions of loss frequency and loss severity often depend on exogenous variables (regressors). For example, the number of losses and the severity of each loss that an automobile insurance policyholder incurs might depend on the characteristics of both the policyholder and the vehicle. When you fit frequency and severity models, you need to account for the effects of such regressors on the probability distributions of the counts and severity. The CNTSELECT procedure enables you to model regression effects on the mean of the count distribution, and the SEVSELECT procedure enables you to model regression effects on the scale parameter of the severity distribution. When you use these models to estimate the compound distribution model of the aggregate loss, you need to specify a set of values for all the regressors, which represents the state of the world for which the simulation is conducted. This is referred to as the what-if or scenario analysis.
Suppose that you, as an automobile insurance company, have postulated that the distribution of the loss event frequency depends on five regressors (external factors): age of the policyholder, gender, type of car, miles driven annually, and policyholder’s education level. Further, the distribution of the severity of each loss depends on three regressors: type of car, safety rating of the car, and annual household income of the policyholder (which can be thought of as a proxy for the luxury level of the car). Note that the frequency model regressors and severity model regressors can be different, as illustrated in this example.
Let these regressors be recorded, respectively, in the variables Age (scaled by a factor of 1/50), Gender (1: female, 2: male), CarType (1: sedan, 2: sport utility vehicle), AnnualMiles (scaled by a factor of 1/5,000), Education (1: high school graduate, 2: college graduate, 3: advanced degree holder), CarSafety (scaled to be between 0 and 1, the safest being 1), and Income (scaled by a factor of 1/100,000).
To illustrate, the following DATA steps simulate and record the historical data about the number of losses that various policyholders incur in a year in the variable NumLoss of the data table mylib.LossCounts, and the severity of each loss in the variable LossAmount of the data table mylib.Losses:
/* Simulate data for losses that several policyholders incur in a year */
data losses(keep=policyholderId age gender carType annualMiles
education carSafety income noloss lossamount);
call streaminit(12345);
array cx{5} age gender carType annualMiles education;
array cbeta{6} _TEMPORARY_ (1 -0.75 1 0.6 -1 -0.25);
array sx{3} carType carSafety income;
array sbeta{4} _TEMPORARY_ (3.5 1.5 -0.8 0.6);
alpha = 1/3; theta = 1/alpha;
Sigma = 1;
do policyholderId=1 to 5000;
/* simulate policyholder and vehicle attributes */
age = MAX(int(rand('NORMAL', 35, 15)),16)/50;
if (rand('UNIFORM') < 0.5) then gender = 1; * female;
else gender = 2; * male;
if (rand('UNIFORM') < 0.7) then carType = 1; * sedan;
else carType = 2; * SUV;
annualMiles = MAX(1000, int(rand('NORMAL', 12000, 5000)))/5000;
educationLevel = rand('UNIFORM');
if (educationLevel < 0.5) then education = 1; *high school graduate;
else if (educationLevel < 0.85) then education = 2; *college graduate;
else education = 3; *advanced degree;
carSafety = rand('UNIFORM'); /* scaled to be between 0 & 1 */
income = MAX(15000,int(rand('NORMAL', education*30000, 50000)))/100000;
/* simulate number of losses incurred by this policyholder */
cxbeta = cbeta(1);
do i=1 to dim(cx);
cxbeta = cxbeta + cx(i) * cbeta(i+1);
end;
Mu = exp(cxbeta);
p = theta/(Mu+theta);
numloss = rand('NEGB',p,theta);
/* simulate severity of each loss */
if (numloss > 0) then do;
noloss = 0;
do iloss=1 to numloss;
Mu = sbeta(1);
do i=1 to dim(sx);
Mu = Mu + sx(i) * sbeta(i+1);
end;
lossamount = exp(Mu) * rand('LOGNORMAL')**Sigma;
output;
end;
end;
else do;
noloss = 1;
lossamount = .;
output;
end;
end;
run;
/* Aggregate number of annual loss events for each policyholder */
data losscounts(keep=age gender carType annualMiles education numloss);
set losses;
by policyholderId;
retain numloss 0;
if (noloss ne 1) then
numloss = numloss + 1;
if (last.policyholderId) then do;
output;
numloss = 0;
end;
run;
/* Load the data */
data mylib.losses;
set losses;
run;
data mylib.losscounts;
set losscounts;
run;
Note that the last two DATA steps in the previous program load the local SAS data sets Work.LossCounts and Work.Losses into the data tables mylib.LossCounts and mylib.Losses, respectively, in your CAS session that is associated with the mylib CAS engine libref.
The following PROC CNTSELECT step fits the count regression model and stores the fitted model information in the item store mylib.CountregModel:
/* Fit negative binomial frequency model for the number of losses */
proc cntselect data=mylib.losscounts store=mylib.countregmodel;
model numloss = age gender carType annualMiles education / dist=negbin;
run;
You can examine the parameter estimates of the count model that are stored in the item store mylib.CountregModel by submitting the following statements:
/* Examine the parameter estimates for the model in the item store */
proc cntselect data=mylib.losscounts;
viewstore / instore=mylib.countregmodel finalestimates;
run;
The "Parameter Estimates" table that is displayed by the SHOW statement is shown in Figure 5.
Figure 5: Parameter Estimates of the Count Regression Model
| Parameter Estimates | |||||
|---|---|---|---|---|---|
| Parameter | DF | Estimate | Standard Error | t Value | Approx Pr > |t| |
| Intercept | 1 | 0.910479 | 0.090515 | 10.06 | <.0001 |
| age | 1 | -0.626803 | 0.058547 | -10.71 | <.0001 |
| gender | 1 | 1.025034 | 0.032099 | 31.93 | <.0001 |
| carType | 1 | 0.615165 | 0.031153 | 19.75 | <.0001 |
| annualMiles | 1 | -1.010276 | 0.017512 | -57.69 | <.0001 |
| education | 1 | -0.280246 | 0.021677 | -12.93 | <.0001 |
| _Alpha | 1 | 0.318403 | 0.020090 | 15.85 | <.0001 |
The following PROC SEVSELECT step fits the severity scale regression models for all the common distributions that are predefined in the procedure:
/* Fit severity models for the magnitude of losses */
proc sevselect data=mylib.losses outest=mylib.sevregest print=all;
loss lossamount;
scalemodel carType carSafety income;
dist _predef_;
nloptions maxiter=100;
run;
The comparison of fit statistics of various scale regression models is shown in Figure 6. The scale regression model based on the lognormal distribution is deemed the best-fitting model according to the likelihood-based statistics, whereas the scale regression model based on the Pareto distribution is deemed the best-fitting model according to the statistics based on the empirical distribution function (EDF).
Figure 6: Severity Model Comparison
| All Fit Statistics | |||||||
|---|---|---|---|---|---|---|---|
| Distribution | -2 Log Likelihood | AIC | AICC | SBC | KS | AD | CvM |
| Burr | 127231 | 127243 | 127243 | 127286 | 4.66462 | 75.26361 | 9.17877 |
| Exp | 128431 | 128439 | 128439 | 128467 | 3.61201 | 61.22673 | 4.17008 |
| Gamma | 128324 | 128334 | 128334 | 128370 | 4.44757 | 92.64608 | 8.25474 |
| Igauss | 127434 | 127444 | 127444 | 127480 | 3.65517 | 71.24503 | 5.95287 |
| Logn | 127062* | 127072* | 127072* | 127107* | 4.13167 | 71.45566 | 7.20527 |
| Pareto | 128166 | 128176 | 128176 | 128211 | 3.24411* | 37.34514* | 2.41164* |
| Gpd | 128166 | 128176 | 128176 | 128211 | 3.24411 | 37.34527 | 2.41165 |
| Weibull | 128429 | 128439 | 128439 | 128475 | 3.65639 | 64.22930 | 4.54181 |
| Asterisk (*) denotes the best model in the column. | |||||||
Now, you are ready to analyze the distribution of the aggregate loss that can be expected from a specific policyholder. First, you need to encode and scale the policyholder’s information into the appropriate regressor variables of a data table. This table is called the scenario data table. Note that you need to follow the same encoding and scaling method for the regressor variables in the scenario data table as you use for the regressor variables in the input data tables of the SEVSELECT and CNTSELECT procedures. The following DATA steps create the scenario data table mylib.SinglePolicy, which contains a scenario that consists of a 59-year-old male policyholder who has an advanced degree, earns 159,870, and drives a sedan that has a very high safety rating about 11,474 miles annually:
/* Generate the scenario data table for single policyholder */
data singlePolicy(keep=age gender carType annualMiles
education carSafety income);
age = 59/50; * age scaled by 50;
gender = 2; * male;
carType = 1; * sedan;
annualMiles = 11474/5000; * miles scaled by 5,000;
education = 3; * advanced degree;
carSafety = 0.99532; * car safety in the range (0,1);
income = 159870/100000; * annual income scaled by 100,000;
output;
run;
/* Load the data */
data mylib.singlePolicy;
set singlePolicy;
run;
The following PROC CCDM step to analyzes the compound distribution of the aggregate loss that the policyholder in the scenario data table mylib.SinglePolicy incurs in a year by using the frequency model from the item store mylib.CountregModel and the two best severity models, lognormal and Pareto, from the data table mylib.SevRegEst:
/* Simulate the aggregate loss distribution for the scenario
with single policyholder */
proc ccdm data=mylib.singlePolicy nreplicates=10000 seed=13579 print=all
countstore=mylib.countregmodel severityest=mylib.sevregest;
severitymodel logn pareto;
outsum out=mylib.onepolicysum mean stddev skew kurtosis median
pctlpts=97.5 to 99.5 by 1;
run;
The results from the preceding PROC CCDM step are shown in Figure 7.
When you use a severity scale regression model, the "Compound Distribution Information" table displays the severity scale regression effects that PROC CCDM uses. PROC CCDM detects the severity regression effects automatically by examining the metadata that PROC SEVSELECT stores in the SEVERITYEST= data table and verifies the existence of the individual regressors in the DATA= data table.
Figure 7: Scenario Analysis Results for One Policyholder with Lognormal Severity Model
| Compound Distribution Information | |
|---|---|
| Severity Model | Lognormal Distribution |
| Scale Model Effects | carSafety carType income |
| Count Model | NegBin(p=2) Model in Item Store COUNTREGMODEL |
| Sample Summary Statistics | |||
|---|---|---|---|
| Mean | 208.61064 | Median | 0 |
| Standard Deviation | 417.46735 | Interquartile Range | 249.36197 |
| Variance | 174279.0 | Minimum | 0 |
| Skewness | 4.33531 | Maximum | 6395.5 |
| Kurtosis | 30.68677 | Sample Size | 10000 |
| Sample Percentiles | |
|---|---|
| Percentile | Value |
| 1 | 0 |
| 5 | 0 |
| 25 | 0 |
| 50 | 0 |
| 75 | 249.36197 |
| 95 | 971.66336 |
| 97.5 | 1358.9 |
| 98.5 | 1675.7 |
| 99 | 1964.1 |
| 99.5 | 2396.1 |
| Percentile Method = 5 | |
The "Sample Summary Statistics" and "Sample Percentiles" tables in Figure 7 show estimates of the aggregate loss distribution for the lognormal severity model. The percentiles table shows that the distribution is highly skewed to the right; this is also confirmed by the skewness estimate. The median estimate of 0 can be interpreted in two ways. One way is to conclude that the policyholder will not incur any loss in 50% of the years during which he or she is insured. The other way is to conclude that 50% of policyholders who have the characteristics of this policyholder will not incur any loss in a given year. However, there is a 2.5% chance that the policyholder will incur a loss that exceeds the 97.5th percentile in any given year and a 0.5% chance that the policyholder will incur a loss that exceeds the 99.5th percentile in any given year.
If the aggregate loss sample is simulated by using the Pareto severity model, then the results are as shown in Figure 8. These estimates are very close to the values that the lognormal severity model predicts.
Figure 8: Scenario Analysis Results for One Policyholder with Pareto Severity Model
| Compound Distribution Information | |
|---|---|
| Severity Model | Pareto Distribution |
| Scale Model Effects | carSafety carType income |
| Count Model | NegBin(p=2) Model in Item Store COUNTREGMODEL |
| Sample Summary Statistics | |||
|---|---|---|---|
| Mean | 206.71313 | Median | 0 |
| Standard Deviation | 390.78039 | Interquartile Range | 260.70822 |
| Variance | 152709.3 | Minimum | 0 |
| Skewness | 3.24907 | Maximum | 4625.0 |
| Kurtosis | 15.26508 | Sample Size | 10000 |
| Sample Percentiles | |
|---|---|
| Percentile | Value |
| 1 | 0 |
| 5 | 0 |
| 25 | 0 |
| 50 | 0 |
| 75 | 260.70822 |
| 95 | 999.56196 |
| 97.5 | 1360.5 |
| 98.5 | 1604.1 |
| 99 | 1777.6 |
| 99.5 | 2195.9 |
| Percentile Method = 5 | |
The scenario that you just analyzed contains only one policyholder. You can expand the scenario to include multiple policyholders. The following DATA step simulates the data table mylib.GroupOfPolicies, which records information about five different policyholders, as shown in Figure 9:
/* Generate the scenario data table for multiple policyholders */
data groupOfPolicies(keep=policyholderId age gender carType annualMiles
education carSafety income);
call streaminit(67897);
do policyholderId=1 to 5;
age = MAX(int(rand('NORMAL', 35, 15)),16)/50;
if (rand('UNIFORM') < 0.5) then gender = 1; * female;
else gender = 2; * male;
if (rand('UNIFORM') < 0.7) then carType = 1; * sedan;
else carType = 2; * SUV;
annualMiles = MAX(1000, int(rand('NORMAL', 12000, 5000)))/5000;
educationLevel = rand('UNIFORM');
if (educationLevel < 0.5) then education = 1; *high school graduate;
else if (educationLevel < 0.85) then education = 2; *college graduate;
else education = 3; *advanced degree;
carSafety = rand('UNIFORM'); /* scaled to be between 0 & 1 */
income = MAX(15000,int(rand('NORMAL', education*30000, 50000)))/100000;
output;
end;
run;
/* Load the data */
data mylib.groupOfPolicies;
set groupOfPolicies;
run;
Figure 9: Scenario Analysis Data for Multiple Policyholders
| policyholderId | age | gender | carType | annualMiles | education | carSafety | income |
|---|---|---|---|---|---|---|---|
| 1 | 1.18 | 2 | 1 | 2.2948 | 3 | 0.99532 | 1.59870 |
| 2 | 0.66 | 2 | 1 | 2.6718 | 2 | 0.86412 | 0.84459 |
| 3 | 0.64 | 2 | 2 | 1.9528 | 1 | 0.86478 | 0.50177 |
| 4 | 0.46 | 1 | 2 | 2.6402 | 2 | 0.27062 | 1.18870 |
| 5 | 0.62 | 1 | 1 | 1.7294 | 1 | 0.32830 | 0.37694 |
The following PROC CCDM step conducts a scenario analysis for the aggregate loss that is incurred by all five policyholders in the data table mylib.GroupOfPolicies together in one year:
/* Simulate the aggregate loss distribution for the scenario
of multiple policyholders */
proc ccdm data=mylib.groupOfPolicies nreplicates=10000 seed=13579 print=all
countstore=mylib.countregmodel severityest=mylib.sevregest
plots=(conditionaldensity(rightq=0.95)) nperturbedSamples=50;
severitymodel logn pareto;
outsum out=mylib.multipolicysum mean stddev skew kurtosis median
pctlpts=97.5 to 99.5 by 1;
run;
The preceding PROC CCDM step conducts perturbation analysis by simulating 50 perturbed samples. The perturbation summary results for the lognormal severity model are shown in Figure 10, and the results for the Pareto severity model are shown in Figure 11.
Figure 10: Perturbation Analysis of Losses from Multiple Policyholders with Lognormal Severity Model
| Compound Distribution Information | |
|---|---|
| Severity Model | Lognormal Distribution |
| Scale Model Effects | carSafety carType income |
| Count Model | NegBin(p=2) Model in Item Store COUNTREGMODEL |
| Sample Perturbation Analysis | ||
|---|---|---|
| Statistic | Estimate | Standard Error |
| Mean | 5318.6 | 175.49858 |
| Standard Deviation | 4179.3 | 141.45815 |
| Variance | 17486679 | 1178659.7 |
| Skewness | 2.09037 | 0.32112 |
| Kurtosis | 10.92294 | 7.21369 |
| Number of Perturbed Samples = 50 | ||
| Size of Each Sample = 10000 | ||
| Sample Percentile Perturbation Analysis | ||
|---|---|---|
| Percentile | Estimate | Standard Error |
| 1 | 199.34899 | 27.70726 |
| 5 | 745.77631 | 53.38547 |
| 25 | 2385.1 | 104.32994 |
| 50 | 4321.0 | 160.79384 |
| 75 | 7149.7 | 238.12755 |
| 95 | 13146.5 | 422.60230 |
| 95 | 13146.5 | 422.60230 |
| 97.5 | 15820.5 | 517.56323 |
| 98.5 | 17880.0 | 660.76788 |
| 99 | 19623.3 | 740.16275 |
| 99.5 | 22674.1 | 1032.8 |
| Number of Perturbed Samples = 50 | ||
| Size of Each Sample = 10000 | ||
If the severity of each loss follows the fitted Pareto distribution, then you can expect an average loss and a worst-case loss as shown in Figure 11.
The numbers for lognormal and Pareto are well within one or two standard errors of each other, which indicates that the aggregate loss distribution is less sensitive to the choice of these two severity distributions in this particular example. You can use the results from either of them.
Figure 11: Perturbation Analysis of Losses from Multiple Policyholders with Pareto Severity Model
| Compound Distribution Information | |
|---|---|
| Severity Model | Pareto Distribution |
| Scale Model Effects | carSafety carType income |
| Count Model | NegBin(p=2) Model in Item Store COUNTREGMODEL |
| Sample Perturbation Analysis | ||
|---|---|---|
| Statistic | Estimate | Standard Error |
| Mean | 5251.4 | 169.35598 |
| Standard Deviation | 3915.5 | 121.76718 |
| Variance | 15346184 | 945964.3 |
| Skewness | 1.49189 | 0.08940 |
| Kurtosis | 3.79266 | 0.85099 |
| Number of Perturbed Samples = 50 | ||
| Size of Each Sample = 10000 | ||
| Sample Percentile Perturbation Analysis | ||
|---|---|---|
| Percentile | Estimate | Standard Error |
| 1 | 162.52002 | 26.88218 |
| 5 | 700.88526 | 52.09737 |
| 25 | 2386.3 | 102.12837 |
| 50 | 4365.2 | 158.73203 |
| 75 | 7166.9 | 229.30068 |
| 95 | 12752.8 | 385.34531 |
| 95 | 12752.8 | 385.34531 |
| 97.5 | 15052.7 | 512.07368 |
| 98.5 | 16745.5 | 585.49172 |
| 99 | 18118.1 | 656.42766 |
| 99.5 | 20512.6 | 819.42806 |
| Number of Perturbed Samples = 50 | ||
| Size of Each Sample = 10000 | ||
The PLOTS=CONDITIONALDENSITY option that is used in the preceding PROC CCDM step creates the conditional density plots for the body and right-tail regions of the density function of the aggregate loss. The plots for the aggregate loss sample that is generated by using the lognormal severity model are shown in Figure 12. The plot on the left side is the plot of , where the limit is as specified by the RIGHTQ=0.95 suboption of the PLOTS=CONDITIONALDENSITY option. The plot on the right side is the plot of
, which helps you visualize the right-tail region of the density function. You can also request the plot of the left tail by specifying the LEFTQ= suboption if you want to explore the details of the left tail region. The conditional density plots are always produced by using the unperturbed sample.
Figure 12: Conditional Density Plots for the Aggregate Loss of Multiple Policyholders
