-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstreamlit_app.py
More file actions
216 lines (184 loc) ยท 10.5 KB
/
Copy pathstreamlit_app.py
File metadata and controls
216 lines (184 loc) ยท 10.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
import streamlit as st
import pandas as pd
from model.predict import get_prediction
# โโ Page config โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
st.set_page_config(
page_title="Insurance Fraud Detector",
page_icon="๐ก๏ธ",
layout="wide",
)
# โโ Helpers โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def risk_level(prob: float):
if prob < 0.25:
return "Rendah", "๐ข", "Klaim tampak legitimate. Proses klaim sesuai SOP standar."
elif prob < 0.50:
return "Sedang", "๐ก", "Terdapat beberapa indikasi mencurigakan. Lakukan verifikasi dokumen tambahan sebelum menyetujui klaim."
elif prob < 0.75:
return "Tinggi", "๐ ", "Risiko fraud signifikan. Eskalasi ke tim investigasi dan tahan pembayaran sementara investigasi berlangsung."
else:
return "Sangat Tinggi","๐ด", "Indikasi fraud kuat. Tolak sementara klaim, laporkan ke unit SIU (Special Investigation Unit), dan dokumentasikan seluruh bukti."
# โโ Session state โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
if "page" not in st.session_state:
st.session_state.page = "home"
# โโ Sidebar navigation โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
with st.sidebar:
st.title("๐ก๏ธ Fraud Detector")
st.markdown("---")
if st.button("๐ Beranda", use_container_width=True):
st.session_state.page = "home"
if st.button("๐ Single Prediction", use_container_width=True):
st.session_state.page = "single"
st.markdown("---")
st.caption("Insurance Fraud Detector v1.0")
page = st.session_state.page
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# PAGE: HOME
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
if page == "home":
st.title("๐ก๏ธ Insurance Fraud Detection System")
st.markdown(
"Sistem deteksi fraud asuransi berbasis machine learning untuk membantu "
"analis klaim mengidentifikasi potensi penipuan secara cepat dan akurat."
)
st.markdown("---")
col1, _ = st.columns(2)
with col1:
st.subheader("๐ Single Prediction")
st.write(
"Masukkan data klaim secara manual dan dapatkan prediksi probabilitas fraud "
"dengan cepat dan akurat."
)
if st.button("Mulai Single Prediction โ", use_container_width=True):
st.session_state.page = "single"
st.rerun()
st.markdown("---")
st.subheader("๐ Apa itu Insurance Fraud?")
st.markdown(
"""
**Insurance fraud** adalah tindakan disengaja untuk mendapatkan pembayaran klaim
asuransi secara tidak sah. Fraud asuransi merugikan industri secara masif โ
diperkirakan menyebabkan kerugian miliaran dolar per tahun secara global.
"""
)
c1, c2, c3 = st.columns(3)
with c1:
st.info(
"**๐ Staged Accidents**\n\n"
"Kecelakaan yang disengaja atau dibuat-buat untuk mengajukan klaim asuransi kendaraan."
)
with c2:
st.info(
"**๐ Inflated Claims**\n\n"
"Melaporkan nilai kerugian yang lebih besar dari kenyataan, misalnya harga kendaraan yang dimanipulasi."
)
with c3:
st.info(
"**๐ค Identity Fraud**\n\n"
"Menggunakan identitas orang lain atau membuat polis fiktif untuk mendapatkan pembayaran klaim."
)
st.markdown("---")
st.subheader("๐ฉ Red Flags Umum dalam Klaim")
col_a, col_b = st.columns(2)
with col_a:
st.warning(
"- Klaim diajukan sangat cepat setelah polis dibuat\n"
"- Tidak ada saksi dalam kejadian kecelakaan\n"
"- Riwayat klaim yang sangat banyak sebelumnya\n"
"- Kecelakaan terjadi di lokasi terpencil (Highway/Parking Lot)"
)
with col_b:
st.warning(
"- Perubahan alamat mendekati tanggal klaim\n"
"- Nilai estimasi klaim tidak proporsional dengan harga kendaraan\n"
"- Laporan polisi tidak diajukan meski klaim besar\n"
"- Persentase liability yang tidak wajar"
)
st.markdown("---")
st.subheader("โ๏ธ Tentang Model")
st.markdown(
"""
Model menggunakan **Random Forest Classifier** yang dilatih pada data historis klaim asuransi.
| Metrik | Nilai |
|--------|-------|
| Algoritma | Logistic Regression |
| Akurasi (test set) | 83.4% |
| Fitur yang digunakan | 21 fitur |
"""
)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# PAGE: SINGLE PREDICTION (TANPA SHAP)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
elif page == "single":
st.title("๐ Single Prediction")
st.markdown("Isi form di bawah ini untuk memprediksi potensi fraud pada satu klaim.")
st.markdown("---")
with st.form("single_form"):
st.subheader("๐ค Profil Pengemudi")
c1, c2, c3 = st.columns(3)
age_of_driver = c1.number_input("Usia Pengemudi", 16, 100, 35)
gender = c2.selectbox("Gender", ["M", "F"])
marital_status = c3.selectbox("Status Pernikahan", [1.0, 0.0], format_func=lambda x: "Menikah" if x == 1.0 else "Belum Menikah")
c1, c2, c3 = st.columns(3)
safty_rating = c1.slider("Safety Rating", 0, 100, 75)
annual_income = c2.number_input("Pendapatan Tahunan (USD)", 0, 500000, 60000, step=1000)
living_status = c3.selectbox("Status Tempat Tinggal", ["Own", "Rent"])
c1, c2, c3 = st.columns(3)
high_education_ind = c1.selectbox("Pendidikan Tinggi", [1, 0], format_func=lambda x: "Ya" if x == 1 else "Tidak")
address_change_ind = c2.selectbox("Perubahan Alamat", [0, 1], format_func=lambda x: "Ya" if x == 1 else "Tidak")
zip_code = c3.number_input("Kode Pos", 0, 99999, 85027)
st.subheader("๐ Detail Klaim")
c1, c2, c3 = st.columns(3)
claim_date = c1.text_input("Tanggal Klaim (M/D/YYYY)", value="1/1/2024")
claim_day_of_week = c2.selectbox("Hari Klaim", ["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"])
accident_site = c3.selectbox("Lokasi Kecelakaan", ["Local", "Parking Lot", "Highway"])
c1, c2, c3 = st.columns(3)
past_num_of_claims = c1.number_input("Jumlah Klaim Sebelumnya", 0, 50, 0)
witness_present_ind = c2.selectbox("Saksi Hadir", [1.0, 0.0], format_func=lambda x: "Ya" if x == 1.0 else "Tidak")
liab_prct = c3.slider("Liability (%)", 0, 100, 50)
c1, c2 = st.columns(2)
policy_report_filed_ind = c1.selectbox("Laporan Polisi Diajukan", [1, 0], format_func=lambda x: "Ya" if x == 1 else "Tidak")
claim_est_payout = c2.number_input("Estimasi Payout Klaim (USD)", 0.0, 100000.0, 5000.0, step=100.0)
st.subheader("๐ Informasi Kendaraan")
c1, c2, c3 = st.columns(3)
age_of_vehicle = c1.number_input("Usia Kendaraan (tahun)", 0, 30, 5)
vehicle_category = c2.selectbox("Kategori Kendaraan", ["Compact", "Medium", "Large"])
vehicle_color = c3.selectbox("Warna Kendaraan", ["other","blue","black","white","red","gray","silver"])
c1, c2 = st.columns(2)
vehicle_price = c1.number_input("Harga Kendaraan (USD)", 0.0, 200000.0, 30000.0, step=500.0)
vehicle_weight = c2.number_input("Berat Kendaraan (kg)", 0.0, 100000.0, 15000.0, step=100.0)
submitted = st.form_submit_button("๐ฎ Prediksi Sekarang", use_container_width=True)
if submitted:
input_dict = {
"claim_number": "", "age_of_driver": age_of_driver, "gender": gender,
"marital_status": marital_status, "safty_rating": safty_rating,
"annual_income": annual_income, "high_education_ind": high_education_ind,
"address_change_ind": address_change_ind, "living_status": living_status,
"zip_code": zip_code, "claim_date": claim_date,
"claim_day_of_week": claim_day_of_week, "accident_site": accident_site,
"past_num_of_claims": past_num_of_claims, "witness_present_ind": witness_present_ind,
"liab_prct": liab_prct, "channel": "Broker",
"policy_report_filed_ind": policy_report_filed_ind,
"claim_est_payout": claim_est_payout, "age_of_vehicle": age_of_vehicle,
"vehicle_category": vehicle_category, "vehicle_price": vehicle_price,
"vehicle_color": vehicle_color, "vehicle_weight": vehicle_weight,
}
raw_df = pd.DataFrame([input_dict])
prob = get_prediction([input_dict], proba=True)[0]
level, icon, rec = risk_level(prob)
st.markdown("---")
st.subheader("๐ Hasil Prediksi")
m1, m2, m3 = st.columns(3)
m1.metric("Probabilitas Fraud", f"{prob*100:.1f}%")
m2.metric("Level Risiko", f"{icon} {level}")
m3.metric("Confidence (Legitimate)", f"{(1-prob)*100:.1f}%")
st.progress(float(prob))
if prob < 0.25:
st.success(f"**{icon} Risiko {level}** โ {rec}")
elif prob < 0.50:
st.info(f"**{icon} Risiko {level}** โ {rec}")
elif prob < 0.75:
st.warning(f"**{icon} Risiko {level}** โ {rec}")
else:
st.error(f"**{icon} Risiko {level}** โ {rec}")
with st.expander("๐ Lihat Data Input"):
st.dataframe(raw_df, use_container_width=True)