379.CAN SAS DELIVER END-TO-END TLF (TABLES, LISTINGS, AND FIGURES) FOR INSURANCE CLAIMS ANALYSIS?
CAN SAS DELIVER END-TO-END TLF (TABLES, LISTINGS, AND FIGURES) FOR INSURANCE CLAIMS ANALYSIS?
HERE IN THIS PROJECT WE USED THESE SAS STATEMENTS —
DATA STEP | PROC SQL | PROC REPORT | PROC PRINT | PROC SGPLOT | MACROS | TABLES | LISTINGS | FIGURES
1. What is TLF in Insurance Analytics?
In clinical trials, TLF means:
• Tables
• Listings
• Figures
In insurance
analytics, TLF means:
|
Clinical Trials |
Insurance
Analytics |
|
Tables |
Claim summaries, fraud exposure |
|
Listings |
Claim-level audit reports |
|
Figures |
Risk distribution charts |
Insurance companies must submit:
• Fraud exposure reports
• Claim approval summaries
• High-risk case listings
• Settlement turnaround reports
2. Where TLF fits in the Insurance Claim
Lifecycle
Real insurance workflow:
1.
Claims submitted
2.
Risk calculated
3.
Fraud flagged
4.
Claims settled
5.
Regulatory reporting
Auditors, regulators, and management never see
raw SAS datasets — they see:
• Tables
• Listings
• Figures
3. Insurance ADaM-like Analysis Dataset
Just like clinical ADaM, we use claims_flagged as the analysis dataset.
It contains:
• Claim_ID
• Policy_Type
• Claim_Amount
• Approval_Time
• Days_To_Submit
• Risk_Score
• Fraud_Category
• Settlement_Status
4. TLF Plan (Just like SAP in Clinical Trials)
Before writing code, professionals write a TLF Plan.
|
No |
Output Type |
Purpose |
|
T1 |
Fraud Summary Table |
Management risk view |
|
T2 |
Settlement Summary Table |
Operations efficiency |
|
L1 |
High-Risk Claims Listing |
Investigator review |
|
L2 |
Pending Claims Listing |
Operations team |
|
F1 |
Risk Distribution Figure |
Fraud modeling |
|
F2 |
Claim Amount vs Risk |
Financial exposure |
5. Creating Raw Insurance Claims Dataset
data claims_raw;
format Claim_Date Submission_Date date9.;
input Claim_ID $ Policy_Type $ Claim_Amount Approval_Time Fraud_Flag$ Settlement_Status $
Claim_Date:date9. Submission_Date:date9.;
datalines;
C001 Health 120000 5 N Approved 01JAN2024 28DEC2023
C002 Motor 450000 12 Y Pending 05JAN2024 20DEC2023
C003 Travel 60000 3 N Approved 10JAN2024 08JAN2024
C004 Property 950000 25 Y Rejected 12JAN2024 01JAN2024
C005 Health 180000 7 N Approved 15JAN2024 10JAN2024
C006 Motor 320000 15 Y Pending 18JAN2024 02JAN2024
C007 Health 75000 4 N Approved 20JAN2024 17JAN2024
C008 Property 1500000 30 Y Rejected 25JAN2024 05JAN2024
C009 Travel 45000 2 N Approved 28JAN2024 27JAN2024
C010 Motor 280000 10 N Approved 30JAN2024 20JAN2024
C011 Health 220000 9 N Approved 02FEB2024 25JAN2024
C012 Property 680000 18 Y Pending 05FEB2024 15JAN2024
C013 Travel 55000 3 N Approved 07FEB2024 06FEB2024
C014 Motor 410000 14 Y Pending 10FEB2024 28JAN2024
C015 Health 195000 8 N Approved 12FEB2024 05FEB2024
;
run;
proc print data=claims_raw;
run;
OUTPUT:
| Obs | Claim_Date | Submission_Date | Claim_ID | Policy_Type | Claim_Amount | Approval_Time | Fraud_Flag | Settlement_Status |
|---|---|---|---|---|---|---|---|---|
| 1 | 01JAN2024 | 28DEC2023 | C001 | Health | 120000 | 5 | N | Approved |
| 2 | 05JAN2024 | 20DEC2023 | C002 | Motor | 450000 | 12 | Y | Pending |
| 3 | 10JAN2024 | 08JAN2024 | C003 | Travel | 60000 | 3 | N | Approved |
| 4 | 12JAN2024 | 01JAN2024 | C004 | Property | 950000 | 25 | Y | Rejected |
| 5 | 15JAN2024 | 10JAN2024 | C005 | Health | 180000 | 7 | N | Approved |
| 6 | 18JAN2024 | 02JAN2024 | C006 | Motor | 320000 | 15 | Y | Pending |
| 7 | 20JAN2024 | 17JAN2024 | C007 | Health | 75000 | 4 | N | Approved |
| 8 | 25JAN2024 | 05JAN2024 | C008 | Property | 1500000 | 30 | Y | Rejected |
| 9 | 28JAN2024 | 27JAN2024 | C009 | Travel | 45000 | 2 | N | Approved |
| 10 | 30JAN2024 | 20JAN2024 | C010 | Motor | 280000 | 10 | N | Approved |
| 11 | 02FEB2024 | 25JAN2024 | C011 | Health | 220000 | 9 | N | Approved |
| 12 | 05FEB2024 | 15JAN2024 | C012 | Property | 680000 | 18 | Y | Pending |
| 13 | 07FEB2024 | 06FEB2024 | C013 | Travel | 55000 | 3 | N | Approved |
| 14 | 10FEB2024 | 28JAN2024 | C014 | Motor | 410000 | 14 | Y | Pending |
| 15 | 12FEB2024 | 05FEB2024 | C015 | Health | 195000 | 8 | N | Approved |
6. Date Calculations using INTCK
data claims_dates;
set claims_raw;
Days_To_Submit = intck('day', Submission_Date, Claim_Date);
run;
proc print data=claims_dates;
var Claim_ID Policy_Type Days_To_Submit;
run;
OUTPUT:
| Obs | Claim_ID | Policy_Type | Days_To_Submit |
|---|---|---|---|
| 1 | C001 | Health | 4 |
| 2 | C002 | Motor | 16 |
| 3 | C003 | Travel | 2 |
| 4 | C004 | Property | 11 |
| 5 | C005 | Health | 5 |
| 6 | C006 | Motor | 16 |
| 7 | C007 | Health | 3 |
| 8 | C008 | Property | 20 |
| 9 | C009 | Travel | 1 |
| 10 | C010 | Motor | 10 |
| 11 | C011 | Health | 8 |
| 12 | C012 | Property | 21 |
| 13 | C013 | Travel | 1 |
| 14 | C014 | Motor | 13 |
| 15 | C015 | Health | 7 |
7. Risk Score Calculation
data claims_risk;
set claims_dates;
Risk_Score = (Claim_Amount/10000) + Approval_Time + (Days_To_Submit*2);
run;
proc print data=claims_risk;
var Claim_ID Policy_Type Days_To_Submit Risk_Score;
run;
OUTPUT:
| Obs | Claim_ID | Policy_Type | Days_To_Submit | Risk_Score |
|---|---|---|---|---|
| 1 | C001 | Health | 4 | 25.0 |
| 2 | C002 | Motor | 16 | 89.0 |
| 3 | C003 | Travel | 2 | 13.0 |
| 4 | C004 | Property | 11 | 142.0 |
| 5 | C005 | Health | 5 | 35.0 |
| 6 | C006 | Motor | 16 | 79.0 |
| 7 | C007 | Health | 3 | 17.5 |
| 8 | C008 | Property | 20 | 220.0 |
| 9 | C009 | Travel | 1 | 8.5 |
| 10 | C010 | Motor | 10 | 58.0 |
| 11 | C011 | Health | 8 | 47.0 |
| 12 | C012 | Property | 21 | 128.0 |
| 13 | C013 | Travel | 1 | 10.5 |
| 14 | C014 | Motor | 13 | 81.0 |
| 15 | C015 | Health | 7 | 41.5 |
8. Character Cleaning
data claims_clean;
set claims_risk;
Policy_Type = propcase(strip(Policy_Type));
Settlement_Status = upcase(trim(Settlement_Status));
run;
proc print data=claims_clean;
var Claim_ID Policy_Type Days_To_Submit Risk_Score Policy_Type Settlement_Status;
run;
OUTPUT:
| Obs | Claim_ID | Policy_Type | Days_To_Submit | Risk_Score | Policy_Type | Settlement_Status |
|---|---|---|---|---|---|---|
| 1 | C001 | Health | 4 | 25.0 | Health | APPROVED |
| 2 | C002 | Motor | 16 | 89.0 | Motor | PENDING |
| 3 | C003 | Travel | 2 | 13.0 | Travel | APPROVED |
| 4 | C004 | Property | 11 | 142.0 | Property | REJECTED |
| 5 | C005 | Health | 5 | 35.0 | Health | APPROVED |
| 6 | C006 | Motor | 16 | 79.0 | Motor | PENDING |
| 7 | C007 | Health | 3 | 17.5 | Health | APPROVED |
| 8 | C008 | Property | 20 | 220.0 | Property | REJECTED |
| 9 | C009 | Travel | 1 | 8.5 | Travel | APPROVED |
| 10 | C010 | Motor | 10 | 58.0 | Motor | APPROVED |
| 11 | C011 | Health | 8 | 47.0 | Health | APPROVED |
| 12 | C012 | Property | 21 | 128.0 | Property | PENDING |
| 13 | C013 | Travel | 1 | 10.5 | Travel | APPROVED |
| 14 | C014 | Motor | 13 | 81.0 | Motor | PENDING |
| 15 | C015 | Health | 7 | 41.5 | Health | APPROVED |
9. Fraud Detection Macro
%macro fraud_flag(input=, output=);
data &output;
set &input;
length Fraud_Category $12;
if Risk_Score > 80 then Fraud_Category = "HIGH";
else if Risk_Score > 50 then Fraud_Category = "MEDIUM";
else Fraud_Category = "LOW";
run;
proc print data=&output;
run;
%mend;
%fraud_flag(input=claims_clean, output=claims_flagged);
OUTPUT:
| Obs | Claim_Date | Submission_Date | Claim_ID | Policy_Type | Claim_Amount | Approval_Time | Fraud_Flag | Settlement_Status | Days_To_Submit | Risk_Score | Fraud_Category |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 01JAN2024 | 28DEC2023 | C001 | Health | 120000 | 5 | N | APPROVED | 4 | 25.0 | LOW |
| 2 | 05JAN2024 | 20DEC2023 | C002 | Motor | 450000 | 12 | Y | PENDING | 16 | 89.0 | HIGH |
| 3 | 10JAN2024 | 08JAN2024 | C003 | Travel | 60000 | 3 | N | APPROVED | 2 | 13.0 | LOW |
| 4 | 12JAN2024 | 01JAN2024 | C004 | Property | 950000 | 25 | Y | REJECTED | 11 | 142.0 | HIGH |
| 5 | 15JAN2024 | 10JAN2024 | C005 | Health | 180000 | 7 | N | APPROVED | 5 | 35.0 | LOW |
| 6 | 18JAN2024 | 02JAN2024 | C006 | Motor | 320000 | 15 | Y | PENDING | 16 | 79.0 | MEDIUM |
| 7 | 20JAN2024 | 17JAN2024 | C007 | Health | 75000 | 4 | N | APPROVED | 3 | 17.5 | LOW |
| 8 | 25JAN2024 | 05JAN2024 | C008 | Property | 1500000 | 30 | Y | REJECTED | 20 | 220.0 | HIGH |
| 9 | 28JAN2024 | 27JAN2024 | C009 | Travel | 45000 | 2 | N | APPROVED | 1 | 8.5 | LOW |
| 10 | 30JAN2024 | 20JAN2024 | C010 | Motor | 280000 | 10 | N | APPROVED | 10 | 58.0 | MEDIUM |
| 11 | 02FEB2024 | 25JAN2024 | C011 | Health | 220000 | 9 | N | APPROVED | 8 | 47.0 | LOW |
| 12 | 05FEB2024 | 15JAN2024 | C012 | Property | 680000 | 18 | Y | PENDING | 21 | 128.0 | HIGH |
| 13 | 07FEB2024 | 06FEB2024 | C013 | Travel | 55000 | 3 | N | APPROVED | 1 | 10.5 | LOW |
| 14 | 10FEB2024 | 28JAN2024 | C014 | Motor | 410000 | 14 | Y | PENDING | 13 | 81.0 | HIGH |
| 15 | 12FEB2024 | 05FEB2024 | C015 | Health | 195000 | 8 | N | APPROVED | 7 | 41.5 | LOW |
10. TABLE 1 – Fraud Exposure Summary
Business Question
How much money is exposed to fraud?
proc sql;
create table tlf_fraud_summary as
select
Fraud_Category,
count(*) as Total_Claims,
sum(Claim_Amount) as Total_Exposure,
mean(Risk_Score) as Avg_Risk
from claims_flagged
group by Fraud_Category;
quit;
proc print data=tlf_fraud_summary;
run;
OUTPUT:
| Obs | Fraud_Category | Total_Claims | Total_Exposure | Avg_Risk |
|---|---|---|---|---|
| 1 | HIGH | 5 | 3990000 | 132.00 |
| 2 | LOW | 8 | 950000 | 24.75 |
| 3 | MEDIUM | 2 | 600000 | 68.50 |
Why this Table Matters
• Regulators want fraud exposure
• Finance wants loss estimates
• Risk teams want severity
11. Display Table 1
proc report data=tlf_fraud_summary nowd;
columns Fraud_Category Total_Claims Total_Exposure Avg_Risk;
define Fraud_Category / "Fraud Level";
define Total_Claims / "Number of Claims";
define Total_Exposure / "Exposure Amount";
define Avg_Risk / "Average Risk Score";
run;
OUTPUT:
| Fraud Level | Number of Claims | Exposure Amount | Average Risk Score |
|---|---|---|---|
| HIGH | 5 | 3990000 | 132 |
| LOW | 8 | 950000 | 24.75 |
| MEDIUM | 2 | 600000 | 68.5 |
12. TABLE 2 – Settlement Efficiency Table
Business Question
Are risky claims taking longer to close?
proc sql;
create table tlf_settlement as
select
Fraud_Category,
Settlement_Status,
count(*) as Claims,
mean(Approval_Time) as Avg_Days
from claims_flagged
group by Fraud_Category, Settlement_Status;
quit;
proc print data=tlf_settlement;
run;
OUTPUT:
| Obs | Fraud_Category | Settlement_Status | Claims | Avg_Days |
|---|---|---|---|---|
| 1 | HIGH | PENDING | 3 | 14.6667 |
| 2 | HIGH | REJECTED | 2 | 27.5000 |
| 3 | LOW | APPROVED | 8 | 5.1250 |
| 4 | MEDIUM | APPROVED | 1 | 10.0000 |
| 5 | MEDIUM | PENDING | 1 | 15.0000 |
This is
used by:
• Claims
operations
• SLA monitoring
• Audit teams
13. Display Settlement Table
proc report data=tlf_settlement nowd;
columns Fraud_Category Settlement_Status Claims Avg_Days;
define Fraud_Category / "Fraud Level";
define Settlement_Status / "Settlement";
define Claims / "Count";
define Avg_Days / "Average Approval Days";
run;
OUTPUT:
| Fraud Level | Settlement | Count | Average Approval Days |
|---|---|---|---|
| HIGH | PENDING | 3 | 14.666667 |
| HIGH | REJECTED | 2 | 27.5 |
| LOW | APPROVED | 8 | 5.125 |
| MEDIUM | APPROVED | 1 | 10 |
| MEDIUM | PENDING | 1 | 15 |
14. LISTING 1 – High-Risk Claim Listing
Business Question
Which specific claims must be investigated?
proc sql;
create table listing_highrisk as
select Claim_ID,Policy_Type,Claim_Amount,Days_To_Submit,Risk_Score,Settlement_Status
from claims_flagged
where Fraud_Category="HIGH"
order by Risk_Score desc;
quit;
proc print data=listing_highrisk;
run;
OUTPUT:
| Obs | Claim_ID | Policy_Type | Claim_Amount | Days_To_Submit | Risk_Score | Settlement_Status |
|---|---|---|---|---|---|---|
| 1 | C008 | Property | 1500000 | 20 | 220 | REJECTED |
| 2 | C004 | Property | 950000 | 11 | 142 | REJECTED |
| 3 | C012 | Property | 680000 | 21 | 128 | PENDING |
| 4 | C002 | Motor | 450000 | 16 | 89 | PENDING |
| 5 | C014 | Motor | 410000 | 13 | 81 | PENDING |
15. Print High-Risk Listing
proc print data=listing_highrisk label noobs;
label Claim_ID="Claim ID"
Policy_Type="Policy"
Claim_Amount="Amount"
Days_To_Submit="Delay Days"
Risk_Score="Risk Score"
Settlement_Status="Status";
run;
OUTPUT:
| Claim ID | Policy | Amount | Delay Days | Risk Score | Status |
|---|---|---|---|---|---|
| C008 | Property | 1500000 | 20 | 220 | REJECTED |
| C004 | Property | 950000 | 11 | 142 | REJECTED |
| C012 | Property | 680000 | 21 | 128 | PENDING |
| C002 | Motor | 450000 | 16 | 89 | PENDING |
| C014 | Motor | 410000 | 13 | 81 | PENDING |
This is
sent to:
• Fraud
investigators
• Internal audit
• Regulators
16. LISTING 2 – Pending Claims
proc sql;
create table listing_pending as
select Claim_ID,Policy_Type,Claim_Amount,Fraud_Category,Approval_Time
from claims_flagged
where Settlement_Status="PENDING";
quit;
proc print data=listing_pending;
run;
OUTPUT:
| Obs | Claim_ID | Policy_Type | Claim_Amount | Fraud_Category | Approval_Time |
|---|---|---|---|---|---|
| 1 | C002 | Motor | 450000 | HIGH | 12 |
| 2 | C006 | Motor | 320000 | MEDIUM | 15 |
| 3 | C012 | Property | 680000 | HIGH | 18 |
| 4 | C014 | Motor | 410000 | HIGH | 14 |
17. FIGURE 1 – Risk Score Distribution
proc sgplot data=claims_flagged;
histogram Risk_Score;
density Risk_Score;
title "Distribution of Insurance Claim Risk Scores";
run;
OUTPUT:
Used for:
• Fraud
modeling
• Risk calibration
• Model validation
18. FIGURE 2 – Claim Amount vs Risk
proc sgplot data=claims_flagged;
scatter x=Risk_Score y=Claim_Amount;
title "Claim Amount vs Fraud Risk";
run;
OUTPUT:
Used by:
• Finance
• Fraud analytics
• Loss modeling
14. Why TLF is Mandatory in Insurance
Insurance is regulated by:
• IRDAI (India)
• NAIC (USA)
• EIOPA (Europe)
They do not accept datasets — they accept:
• Tables
• Listings
• Figures
15. How This Matches Clinical Trial TLF
|
This is why SAS clinical programmers easily move into insurance analytics.
16. Interview Value
If you explain this TLF:
You can answer:
• Regulatory reporting
• Risk modeling
• Audit compliance
• Data transparency
• End-to-end SAS pipelines
FINAL CONCLUSION
This project shows how raw insurance claim
data is transformed into regulatory-grade
Tables, Listings, and Figures using SAS.
The same workflow used in clinical trials was applied to fraud detection, risk scoring, and claim settlement
analysis.
By building TLFs, we converted raw transactional data into audit-ready, management-ready, and
regulator-ready outputs.
This is how real insurance companies
operate their SAS analytics platforms.
INTERVIEW QUESTIONS FOR YOU
About the Author:
SAS Learning Hub is a data analytics and SAS programming platform focused on clinical, financial, and real-world data analysis. The content is created by professionals with academic training in Pharmaceutics and hands-on experience in Base SAS, PROC SQL, Macros, SDTM, and ADaM, providing practical and industry-relevant SAS learning resources.
Disclaimer:
The datasets and analysis in this article are created for educational and demonstration purposes only. They do not represent Insurance Fraud TLF data.
Our Mission:
This blog provides industry-focused SAS programming tutorials and analytics projects covering finance, healthcare, and technology.
This project is suitable for:
SAS Programmer Interviews
SAS Programmer Job Seekers
SAS Analysts
Comments
Post a Comment