Yapay Zeka Sigortacılığı: Modern Sigortada Özellik Mühendisliği ve Risk Puanlaması
Sigortalama, herhangi bir sigorta şirketinin atan kalbidir: ve bunu sağlayan süreçtir. Riski kabul edip etmemeye, hangi fiyata ve hangi koşullar altında karar verir. Onlarca yıldır bu süreç kağıt belgeleri analiz eden ve uygulayan insan sigortacıların uzmanlığına bağlıydı. aktüeryal kurallar tablolarda kodlanmıştır. Sonuç? 3-5 iş günü içerisinde karar, maliyetler yüksek işletme maliyetleri ve sigortacılar arasında subjektif değişkenlik.
Yapay zeka bu kuralları kökten yeniden yazıyor. McKinsey'e göre, Sigortaya yönelik yapay zeka çözümlerine yapılan küresel yatırımlar, 6 milyar dolar 2025'teBCG'nin tahminine göre Sigorta yapay zekasının toplam değerinin %36'sı tam olarak sigortalama fonksiyonunda yoğunlaşmıştır. Operasyonel rakamlar da aynı derecede etkileyici: Ortalama sigortalama karar süresi 3-5 günden 3-5 güne düştü 12,4 dakika onlar için risk değerlendirmesinde %99,3 doğruluk oranını koruyan standart politikalar.
Peki yapay zeka sigortalama sistemi gerçekte nasıl çalışır? Bu kılavuz her şeyi yapıbozuma uğratıyor teknik yığın: özelliklerin toplanması ve mühendisliğinden risk puanlama modellerine kadar üretime hazır gerçek kod örnekleriyle yorumlanabilirlik ve önyargı yönetimi.
Ne Öğreneceksiniz
- Uçtan uca yapay zeka sigortalama sisteminin mimarisi
- Sigorta alanına özel özellik mühendisliği
- Risk puanlamasına yönelik makine öğrenimi modelleri: XGBoost, iki sıklık/şiddet aşaması
- Denetlenebilir ve uyumluluğa hazır kararlar için SHAP ile yorumlanabilirlik
- AB düzenleyici bağlamında önyargı tespiti ve adaletin azaltılması
- MLflow ile üretimdeki modellerin sigortalanması için MLOps
- Nüfus İstikrar Endeksi (PSI) ile veri kaymasının izlenmesi
Sigortacılık Süreci: Eskiden Yapay Zekaya
Bir yapay zeka sistemi tasarlamadan önce uğraştığımız geleneksel iş akışını anlamak önemlidir. otomatikleştirme. Sigortalama süreci dört temel aşamaya ayrılmıştır:
- Bilgi toplama: Başvuru sahibi kendisi ve risk hakkında veri sağlar (anket, belgeler, varlığın olası fiziksel muayenesi)
- Risk analizi: Sigortacı gelecekteki herhangi bir tazminat talebinin olasılığını ve ciddiyetini değerlendirir
- Fiyatlandırma: Değerlendirilen riske ve portföyün birleşik oran hedeflerine göre primin belirlenmesi
- Karar: Koşullarla kabul, ret veya kabul (istisnalar, franchise, prim)
Yapay zekaya özgü bir sistem bu aşamaları ortadan kaldırmaz ancak bunları derinlemesine dönüştürür: veri toplama Risk analizi heterojen kaynaklardan (açık veri, telematik, kredi bürosu) otomatik hale gelir. ML modelleri tarafından milisaniyeler içinde gerçekleştirilen fiyatlandırma dinamiktir ve her biri için kişiselleştirilmiştir. Başvuru sahibi ve karar, insan gözetimi altındaki standart vakalar için otomatik olarak verilmektedir. karmaşık veya sınırda vakalar.
Düzenleyici Çerçeve: AI Yasası AB ve Sigortacılık
Avrupa Yapay Zeka Yasası (Ağustos 2027'den itibaren tamamen yürürlüktedir) sistemleri sınıflandırır puanlama kredi ve sigorta gibi Yüksek riskli AI (Ek III). Bu belirli yükümlülükler gerektirir: otomatik kararların şeffaflığı, insan incelemesi hakkı, ayrıntılı teknik dokümantasyon ve pazar öncesi uygunluk değerlendirmesi. Tasarımı Yapay zeka sigortalama sistemleri bu gereksinimleri nasıl değil doğrudan mimariden içermelidir. müteakip güçlendirme.
Sigorta Sigortacılığı için Özellik Mühendisliği
Özellik mühendisliğinin kalitesi, bir sigortacılık modelini en çok farklılaştıran faktördür vasattan mükemmel. Özelliklerin olduğu bilgisayar görüşü gibi alanların aksine Evrişimli katmanlardan otomatik olarak çıkarılan sigorta tablo verileri gerektirir Aktüeryal alan bilgisine dayalı derin manuel mühendislik.
Otomotiv sektörünün özellikleri beş ana kategoriye ayrılmıştır:
- Demografik özellikler: yaş, medeni durum, ikamet türü
- Sürüş özellikleri: ehliyet yılı, ehliyetin ilk alındığı yaş, kaza ve kural ihlali geçmişi
- Araç özellikleri: marka, model, yıl, değer, güç, kayıt yılı
- Coğrafi özellikler: kentsel yoğunluk, bölgenin suç endeksi, hava durumu riski
- Ekonomik özellikler: kredi puanı, gerekli sigorta sözleşmesi türü
import pandas as pd
import numpy as np
from typing import Dict, Optional
from dataclasses import dataclass
from datetime import date
@dataclass
class PolicyApplicant:
"""Rappresenta i dati grezzi di un richiedente polizza auto."""
applicant_id: str
birth_date: date
license_date: date
zip_code: str
vehicle_make: str
vehicle_year: int
vehicle_value: float
annual_mileage: int
claims_3yr: int
violations_3yr: int
credit_score: Optional[int] = None
marital_status: str = "single"
housing_type: str = "tenant"
class AutoInsuranceFeatureEngineer:
"""
Feature engineering per underwriting auto.
Produce 40+ feature da dati grezzi del richiedente,
includendo feature derivate, interazioni e encoding
domain-specific.
"""
VEHICLE_MAKE_RISK: Dict[str, int] = {
"Ferrari": 5, "Lamborghini": 5, "Porsche": 4,
"BMW": 3, "Mercedes": 3, "Audi": 3,
"Toyota": 1, "Honda": 1, "Volkswagen": 2,
"Ford": 2, "Fiat": 2, "Renault": 2,
}
def __init__(self, reference_date: Optional[date] = None):
self.reference_date = reference_date or date.today()
def engineer_features(self, applicant: PolicyApplicant) -> Dict[str, float]:
features: Dict[str, float] = {}
features.update(self._demographic_features(applicant))
features.update(self._driving_experience_features(applicant))
features.update(self._vehicle_features(applicant))
features.update(self._claims_features(applicant))
features.update(self._geographic_features(applicant))
if applicant.credit_score is not None:
features.update(self._credit_features(applicant))
features.update(self._interaction_features(features))
return features
def _demographic_features(self, applicant: PolicyApplicant) -> Dict[str, float]:
age = (self.reference_date - applicant.birth_date).days / 365.25
return {
"age": age,
"age_squared": age ** 2,
"age_under_25": float(age < 25),
"age_over_70": float(age > 70),
"age_risk_young": max(0.0, (25 - age) / 25) if age < 25 else 0.0,
"age_risk_senior": max(0.0, (age - 70) / 20) if age > 70 else 0.0,
"is_married": float(applicant.marital_status == "married"),
"is_homeowner": float(applicant.housing_type == "owner"),
}
def _driving_experience_features(self, applicant: PolicyApplicant) -> Dict[str, float]:
years_licensed = (self.reference_date - applicant.license_date).days / 365.25
age = (self.reference_date - applicant.birth_date).days / 365.25
age_at_license = age - years_licensed
return {
"years_licensed": years_licensed,
"years_licensed_squared": years_licensed ** 2,
"age_at_first_license": age_at_license,
"late_license_ratio": max(0.0, (age_at_license - 18) / 10),
"is_new_driver": float(years_licensed < 2),
"is_experienced_driver": float(years_licensed > 10),
}
def _vehicle_features(self, applicant: PolicyApplicant) -> Dict[str, float]:
vehicle_age = self.reference_date.year - applicant.vehicle_year
make_risk = self.VEHICLE_MAKE_RISK.get(applicant.vehicle_make, 2)
return {
"vehicle_age": float(vehicle_age),
"vehicle_value": applicant.vehicle_value,
"vehicle_value_log": np.log1p(applicant.vehicle_value),
"vehicle_make_risk_score": float(make_risk),
"is_high_performance": float(make_risk >= 4),
"is_new_vehicle": float(vehicle_age <= 2),
"is_old_vehicle": float(vehicle_age > 10),
"annual_mileage": float(applicant.annual_mileage),
"annual_mileage_log": np.log1p(applicant.annual_mileage),
"high_mileage": float(applicant.annual_mileage > 20000),
}
def _claims_features(self, applicant: PolicyApplicant) -> Dict[str, float]:
claims = applicant.claims_3yr
violations = applicant.violations_3yr
return {
"claims_3yr": float(claims),
"violations_3yr": float(violations),
"has_any_claim": float(claims > 0),
"has_multiple_claims": float(claims > 1),
"has_violations": float(violations > 0),
# Score combinato ponderato: sinistri pesano 3x rispetto a infrazioni
"incident_score": claims * 3.0 + violations * 1.5,
"claims_x_violations": float(claims * violations),
}
def _geographic_features(self, applicant: PolicyApplicant) -> Dict[str, float]:
# In produzione: lookup su DB geografici (ISTAT, OpenStreetMap, criminalita)
zip_hash = hash(applicant.zip_code) % 100
urban_score = (zip_hash % 5) / 4.0
crime_index = (zip_hash % 3) / 2.0
weather_risk = (zip_hash % 4) / 3.0
return {
"urban_density_score": urban_score,
"area_crime_index": crime_index,
"area_weather_risk": weather_risk,
"composite_geo_risk": (urban_score + crime_index + weather_risk) / 3,
}
def _credit_features(self, applicant: PolicyApplicant) -> Dict[str, float]:
score = applicant.credit_score or 0
return {
"credit_score": float(score),
"credit_score_normalized": (score - 300) / (850 - 300),
"poor_credit": float(score < 580),
"fair_credit": float(580 <= score < 670),
"good_credit": float(670 <= score < 740),
"excellent_credit": float(score >= 740),
}
def _interaction_features(self, features: Dict[str, float]) -> Dict[str, float]:
return {
# Giovane + auto sportiva = rischio molto alto
"young_high_perf": (
features.get("age_risk_young", 0) *
features.get("is_high_performance", 0)
),
# Sinistri + area ad alto crimine amplificano il rischio
"claims_urban": (
features.get("claims_3yr", 0) *
features.get("urban_density_score", 0)
),
# Mileage alto + veicolo vecchio = rischio meccanico aumentato
"mileage_old_vehicle": (
features.get("annual_mileage_log", 0) *
features.get("is_old_vehicle", 0)
),
}
Risk Puanlama Modelleri: Yaklaşımlar ve Takaslar
Risk puanlaması için makine öğrenimi modelinin seçimi doğruluğu dengelemelidir tahmine dayalı, yorumlanabilirlik (uyumluluk için temel), çıkarım hızı ve kolaylık bakım. Sigorta sektörünün temel yaklaşımları şöyle:
Sigorta Riski Skorlama Modellerinin Karşılaştırılması
| Modeli | Kesinlik | Yorumlanabilirlik | İdeal Kullanım Durumu |
|---|---|---|---|
| GLM (Poisson/Gama) | Ortalama | Çok Yüksek | Aktüeryal temel, düzenleyici kabul |
| Rastgele Orman | Yüksek | Ortalama | Özelliğin önemi, aykırı değerlere karşı sağlamlık |
| XGBoost / LightGBM | Çok Yüksek | Ortalama | Standart üretim, tablo halindeki verilerde SOTA |
| Tablolu Sinir Ağı | Yüksek | Düşük | Kategorik yerleştirmelere sahip karmaşık özellikler |
Sektördeki en köklü yaklaşım, iki aşamalı model: bir model sıklığı (en az bir kaza geçirme olasılığı) ve ciddiyeti (kazanın beklenen maliyeti) meydana geldiği göz önüne alındığında). Beklenen saf prim: Sıklık x Şiddet.
import xgboost as xgb
from sklearn.metrics import mean_absolute_error, mean_squared_error
import numpy as np
import pandas as pd
from typing import Dict, Optional
class TwoStageRiskScorer:
"""
Modello a due stadi per pricing assicurativo auto.
Stage 1: Frequency model (Poisson regression con XGBoost)
Target = numero sinistri per polizza
Stage 2: Severity model (Tweedie/Gamma con XGBoost)
Target = importo sinistro, addestrato solo su polizze con sinistri
Pure Premium = E[Frequency] * E[Severity | has_claim]
"""
FREQUENCY_PARAMS: Dict = {
"objective": "count:poisson",
"eval_metric": "poisson-nloglik",
"max_depth": 6,
"learning_rate": 0.05,
"n_estimators": 500,
"min_child_weight": 50, # stabilità attuariale: min sinistri per leaf
"subsample": 0.8,
"colsample_bytree": 0.8,
"reg_alpha": 0.1,
"reg_lambda": 1.0,
"tree_method": "hist",
"early_stopping_rounds": 50,
}
SEVERITY_PARAMS: Dict = {
"objective": "reg:tweedie",
"tweedie_variance_power": 1.5, # 1=Poisson, 2=Gamma
"eval_metric": "tweedie-nloglik@1.5",
"max_depth": 5,
"learning_rate": 0.05,
"n_estimators": 300,
"min_child_weight": 30,
"subsample": 0.8,
"colsample_bytree": 0.7,
"reg_alpha": 0.1,
"reg_lambda": 1.0,
"tree_method": "hist",
"early_stopping_rounds": 30,
}
def __init__(self) -> None:
self.frequency_model = xgb.XGBRegressor(**self.FREQUENCY_PARAMS)
self.severity_model = xgb.XGBRegressor(**self.SEVERITY_PARAMS)
self.feature_names: list = []
def fit(
self,
X: pd.DataFrame,
y_claims: pd.Series,
y_amounts: pd.Series,
exposure: pd.Series,
eval_fraction: float = 0.2,
) -> "TwoStageRiskScorer":
"""
Addestra entrambi i modelli.
IMPORTANTE: usa split temporale, non random shuffle.
I dati assicurativi sono autocorrelati nel tempo.
"""
self.feature_names = X.columns.tolist()
split_idx = int(len(X) * (1 - eval_fraction))
X_train, X_val = X.iloc[:split_idx], X.iloc[split_idx:]
freq_train = y_claims.iloc[:split_idx]
freq_val = y_claims.iloc[split_idx:]
# Stage 1: Frequency
self.frequency_model.fit(
X_train, freq_train,
sample_weight=exposure.iloc[:split_idx],
eval_set=[(X_val, freq_val)],
verbose=50,
)
# Stage 2: Severity - solo su polizze con sinistri
has_claim = y_amounts > 0
X_sev = X[has_claim]
y_sev = y_amounts[has_claim]
sev_split = int(len(X_sev) * (1 - eval_fraction))
self.severity_model.fit(
X_sev.iloc[:sev_split], y_sev.iloc[:sev_split],
eval_set=[(X_sev.iloc[sev_split:], y_sev.iloc[sev_split:])],
verbose=30,
)
return self
def predict_pure_premium(
self, X: pd.DataFrame, exposure: float = 1.0
) -> np.ndarray:
"""Calcola il pure premium: E[Freq] * E[Severity]."""
freq = self.frequency_model.predict(X) * exposure
sev = self.severity_model.predict(X)
return freq * sev
def evaluate(self, X: pd.DataFrame, y_claims: pd.Series) -> Dict[str, float]:
pred = self.frequency_model.predict(X)
mae = mean_absolute_error(y_claims, pred)
rmse = float(np.sqrt(mean_squared_error(y_claims, pred)))
gini = self._gini_coefficient(y_claims.values, pred)
lift = self._lift_at_decile(y_claims.values, pred, 0.1)
return {
"mae": round(mae, 6),
"rmse": round(rmse, 6),
"gini_coefficient": round(gini, 4),
"lift_top_decile": round(lift, 4),
}
def _gini_coefficient(self, actual: np.ndarray, predicted: np.ndarray) -> float:
"""Gini coefficient: metrica attuariale standard per modelli di frequenza."""
idx = np.argsort(predicted)
cum = np.cumsum(actual[idx])
cum_norm = cum / cum[-1]
n = len(actual)
lorenz_area = float(np.sum(cum_norm)) / n
return 2 * (lorenz_area - 0.5)
def _lift_at_decile(
self, actual: np.ndarray, predicted: np.ndarray, decile: float
) -> float:
k = max(1, int(len(actual) * decile))
top_idx = np.argsort(predicted)[-k:]
base_rate = actual.mean()
if base_rate == 0:
return 0.0
return float(actual[top_idx].mean() / base_rate)
SHAP ile Yorumlanabilirlik: Denetlenebilir Kararlar
Sigorta gibi düzenlenmiş bir bağlamda kara kutu modeli yeterli değildir. Mevzuat, sigortalama kararlarının aşağıdaki durumlarda açıklanabilir olmasını gerektirmektedir: müşteri için (hak GDPR açıklamasına göre), sigortacılar için (sınır vakaların incelenmesi) ve düzenleyiciler için (Solvency II Sütun 3, ORSA). SHAP (SHapley Additive exPlanations) referans aracıdır topluluk modellerinin post-hoc yorumlanabilirliği için endüstri.
import shap
import pandas as pd
import numpy as np
from typing import Dict, List, Tuple
class UnderwritingExplainer:
"""
Spiegazioni SHAP per decisioni underwriting.
Genera output a tre livelli: cliente, underwriter, compliance.
"""
FEATURE_LABELS: Dict[str, str] = {
"age": "eta del guidatore",
"years_licensed": "anni di patente",
"claims_3yr": "sinistri negli ultimi 3 anni",
"violations_3yr": "infrazioni negli ultimi 3 anni",
"vehicle_make_risk_score": "categoria rischio veicolo",
"vehicle_age": "anzianita del veicolo",
"vehicle_value": "valore del veicolo",
"annual_mileage": "chilometraggio annuo dichiarato",
"composite_geo_risk": "rischio della zona geografica",
"credit_score": "score creditizio",
"young_high_perf": "combinazione giovane + veicolo sportivo",
}
def __init__(self, model, feature_names: List[str]) -> None:
self.feature_names = feature_names
self.explainer = shap.TreeExplainer(model)
def explain(
self, X_row: pd.DataFrame, risk_score: float
) -> Dict:
"""Spiegazione completa per una singola valutazione."""
shap_values = self.explainer.shap_values(X_row)
impacts: List[Tuple[str, float]] = sorted(
zip(self.feature_names, shap_values[0]),
key=lambda x: abs(x[1]),
reverse=True
)
return {
"risk_score": round(risk_score, 2),
"decision": self._score_to_decision(risk_score),
"customer_message": self._customer_message(impacts, risk_score),
"top_risk_factors": [
{
"name": name,
"label": self.FEATURE_LABELS.get(name, name),
"direction": "aumenta rischio" if shap > 0 else "riduce rischio",
"magnitude": round(abs(shap), 4),
}
for name, shap in impacts[:5]
],
"audit_trail": {
"base_expected_value": float(self.explainer.expected_value),
"all_shap_values": {
n: round(float(s), 6)
for n, s in zip(self.feature_names, shap_values[0])
},
"input_features": X_row.to_dict(orient="records")[0],
},
}
def _customer_message(
self, impacts: List[Tuple[str, float]], score: float
) -> str:
high = [(n, v) for n, v in impacts if abs(v) > 0.1]
if not high:
return "Il tuo profilo rientra nella fascia di rischio standard."
positivi = [self.FEATURE_LABELS.get(n, n) for n, v in high[:3] if v < 0]
negativi = [self.FEATURE_LABELS.get(n, n) for n, v in high[:3] if v > 0]
parts = []
if negativi:
parts.append(f"Fattori che aumentano il profilo di rischio: {', '.join(negativi)}.")
if positivi:
parts.append(f"Fattori a tuo favore: {', '.join(positivi)}.")
return " ".join(parts)
def _score_to_decision(self, score: float) -> str:
if score < 30:
return "ACCEPT_PREFERRED"
elif score < 60:
return "ACCEPT_STANDARD"
elif score < 80:
return "ACCEPT_SUBSTANDARD"
return "DECLINE_OR_MANUAL_REVIEW"
AB Bağlamında Adillik ve Önyargı Tespiti
Temsili değişkenlerin (posta kodu, kredi puanı) kullanımı dolaylı ayrımcılığa neden olabilir kanunen yasaklanmıştır. Avrupa'da cinsiyet eşitliği direktifi (tarafından onaylanmıştır) AB Adalet Divanı'nın 2011 tarihli Test-Achats kararı, fiyatlandırma için cinsiyetin kullanılmasını yasaklamaktadır. sigorta. Yapay Zeka Yasası, Ek III'te sınıflandırılan yüksek riskli sistemler için kısıtlamalar ekler, dağıtımdan önce zorunlu uyumluluk değerlendirmelerinin yapılmasını gerektirir.
import pandas as pd
import numpy as np
from sklearn.metrics import confusion_matrix
from typing import Dict, List
class FairnessAuditor:
"""
Auditor di fairness per modelli underwriting (EU-compliant).
Metriche implementate:
- Disparate Impact (regola 80%)
- Demographic Parity Gap
- Equal Opportunity (TPR parity)
- Calibration by group
"""
DISPARATE_IMPACT_THRESHOLD = 0.8 # EEOC 80% rule
MAX_DP_GAP = 0.1 # linee guida EIOPA
def __init__(
self,
predictions: np.ndarray,
true_labels: np.ndarray,
sensitive_df: pd.DataFrame,
) -> None:
self.predictions = predictions
self.true_labels = true_labels
self.sensitive_df = sensitive_df
def full_audit(self) -> Dict:
results: Dict = {}
for attr in self.sensitive_df.columns:
groups = self.sensitive_df[attr].unique()
attr_results: Dict = {}
for group in groups:
mask = self.sensitive_df[attr] == group
g_pred = self.predictions[mask]
g_true = self.true_labels[mask]
attr_results[str(group)] = {
"count": int(mask.sum()),
"acceptance_rate": float((g_pred < 0.6).mean()),
"avg_score": round(float(g_pred.mean()), 4),
"tpr": self._tpr(g_true, g_pred),
}
di = self._disparate_impact(attr_results)
dp = self._dp_gap(attr_results)
attr_results["_metrics"] = {
"disparate_impact": round(di, 4),
"demographic_parity_gap": round(dp, 4),
"passes_di_rule": di >= self.DISPARATE_IMPACT_THRESHOLD,
"passes_dp_rule": dp <= self.MAX_DP_GAP,
"overall_fair": di >= self.DISPARATE_IMPACT_THRESHOLD and dp <= self.MAX_DP_GAP,
}
results[attr] = attr_results
return results
def _tpr(self, labels: np.ndarray, preds: np.ndarray, thr: float = 0.5) -> float:
if len(labels) < 10:
return float("nan")
binary = (preds >= thr).astype(int)
try:
tn, fp, fn, tp = confusion_matrix(labels, binary, labels=[0, 1]).ravel()
return round(tp / (tp + fn), 4) if (tp + fn) > 0 else 0.0
except ValueError:
return float("nan")
def _disparate_impact(self, groups: Dict) -> float:
rates = [v["acceptance_rate"] for k, v in groups.items()
if not k.startswith("_") and isinstance(v, dict)]
if not rates or max(rates) == 0:
return 1.0
return min(rates) / max(rates)
def _dp_gap(self, groups: Dict) -> float:
rates = [v["acceptance_rate"] for k, v in groups.items()
if not k.startswith("_") and isinstance(v, dict)]
return (max(rates) - min(rates)) if rates else 0.0
Üretimde MLOps ve İzleme
Sigortacılık modelleri aşağıdaki şartlara tabidir: konsept kayması sık: profil Başvuru sahibi değişiklikleri (yeni elektrikli araç modelleri, demografik değişiklikler), maliyetler onarımların maliyeti enflasyona maruz kalıyor, aşırı iklim olayları hasar kalıplarını değiştiriyor. Sürekli izleme sistemi Nüfus İstikrar Endeksi (PSI) e modelin ne zaman yeniden çekilmesi gerektiğini belirlemek için gereklidir.
from scipy import stats
import numpy as np
import pandas as pd
from typing import Dict, List
from datetime import datetime
class DriftMonitor:
"""
Monitora data drift per modelli underwriting.
Usa PSI (Population Stability Index) come metrica primaria.
PSI interpretation:
- PSI < 0.1: Nessun cambiamento significativo
- PSI 0.1-0.25: Cambiamento moderato, monitorare
- PSI > 0.25: Cambiamento significativo, retraining consigliato
"""
def __init__(self, reference_df: pd.DataFrame, features: List[str]) -> None:
self.reference_df = reference_df
self.features = features
def check_drift(self, current_df: pd.DataFrame) -> Dict:
feature_results: Dict = {}
critical_features = []
for feat in self.features:
if feat not in current_df.columns:
continue
psi = self._psi(self.reference_df[feat], current_df[feat])
ks_stat, ks_p = stats.ks_2samp(
self.reference_df[feat].dropna(),
current_df[feat].dropna()
)
status = "ok" if psi < 0.1 else ("warning" if psi < 0.25 else "critical")
feature_results[feat] = {
"psi": round(psi, 4),
"ks_statistic": round(ks_stat, 4),
"ks_pvalue": round(ks_p, 4),
"status": status,
}
if status == "critical":
critical_features.append(feat)
avg_psi = float(np.mean([v["psi"] for v in feature_results.values()]))
return {
"checked_at": datetime.now().isoformat(),
"overall_psi": round(avg_psi, 4),
"retraining_recommended": avg_psi > 0.1,
"critical_features": critical_features,
"feature_details": feature_results,
}
def _psi(self, ref: pd.Series, cur: pd.Series, bins: int = 10) -> float:
ref_clean = ref.dropna().values
cur_clean = cur.dropna().values
edges = np.percentile(ref_clean, np.linspace(0, 100, bins + 1))
edges = np.unique(edges)
ref_counts, _ = np.histogram(ref_clean, bins=edges)
cur_counts, _ = np.histogram(cur_clean, bins=edges)
ref_pct = (ref_counts + 1e-10) / len(ref_clean)
cur_pct = (cur_counts + 1e-10) / len(cur_clean)
return float(np.sum((cur_pct - ref_pct) * np.log(cur_pct / ref_pct)))
En İyi Uygulamalar ve Anti-kalıplar
Yapay Zeka Sigortacılığı için En İyi Uygulamalar
- İki aşamalı mimari (frekans/şiddet): ve aktüeryal standart ile hasar tutarı üzerinde tek bir modelden daha doğru fiyatlandırma üretir
- Zorunlu zaman ayrımı: sigorta verileri zaman içinde otomatik olarak ilişkilendirilir; Eğitim/test ayrımı için asla rastgele karıştırma kullanmayın
- Ofset olarak pozlama: Talep sayısını normalleştirmek için Poisson modelinde her zaman poliçe süresini (yıl cinsinden risk) dengeleme olarak kullanın
- Temel bir GLM'yi koruyun: genelleştirilmiş doğrusal modeller düzenleyiciler tarafından daha kolay doğrulanır ve makine öğreniminin katma değerini değerlendirmek için kıyaslamalar sağlar
- Canlı yayına geçmeden önce gölge modu: Otomatikleştirmeden önce kararları karşılaştırarak modeli 30-90 gün boyunca insan sigortacılığına paralel olarak çalıştırın
- PSI'yi haftalık olarak izleyin: Yeni araç modelleri, onarım maliyetlerindeki enflasyon ve mevzuat değişiklikleri nedeniyle otomobil sektöründe sürüklenmeler sıklıkla yaşanıyor
Kaçınılması Gereken Anti-örüntüler
- Özellik sızıntısı: Frekans modelinin eğitim özellikleri olarak asla yalnızca talep sonrasında mevcut olan değişkenleri (talep tutarı, rezerv) kullanmayın
- Yalnızca AUC'yi optimize edin: Sigorta sektöründe ilgili metrikler riskin en üst onda birlik diliminde yer alan Gini katsayısı, Birleşik Oran ve Artış'tır
- 500+ özelliğe sahip modeller: Aktüeryal olarak doğrulamak ve düzenleyici kuruma gerekçelendirmek imkansız; titiz özellik seçimini tercih edin (maksimum 40-60 özellik)
- Portföy konsantrasyonunu göz ardı etmek: Yalnızca çok düşük risk profillerini kabul eden bir model, seçim karşıtı ve dengesiz bir portföy yaratır
- Vekalet ayrımcılığı: posta kodu gibi değişkenler etnik kökeni temsil edebilir; dağıtımdan önce her zaman farklı etkiyi kontrol edin
Sonuçlar ve Sonraki Adımlar
Yapay zeka sigortacılığı, insan sigortacının yerini almaz ancak onu güçlendirir: Standart politikalar (hacimin %80-90'ı) doğrulukla tamamen otomatikleştirilebilir insan ortalamasından daha yüksek olması, uzmanların deneyiminin önemli olduğu karmaşık vakalar için serbest kalmalarına olanak tanıyor. egemenlik ve yeri doldurulamaz.
Başarılı bir sistemin anahtarları şunlardır: Bilgiye dayalı derin özellik mühendisliği aktüeryal, iki aşamalı sıklık/şiddet mimarisi, uyumluluk için SHAP yorumlanabilirliği, sürüklenme yönetimi için zorunlu adalet denetimi ve PSI ile sürekli izleme.
Serinin bir sonraki makalesi konuyu araştırıyorGörüntü İşleme ile talep otomasyonu ve NLP: dijital FNOL'den otomatik fotoğrafik hasar değerlendirmesine kadar uçtan uca hızlandırılmış çözüm.
InsurTech Mühendislik Serisi
- 01 - Geliştiriciler için Sigorta Alanı: Ürünler, Aktörler ve Veri Modelleri
- 02 - Bulutta Yerel Politika Yönetimi: API Öncelikli Mimari
- 03 - Telematik İşlem Hattı: Geniş Ölçekte UBI Veri İşleme
- 04 - Yapay Zeka Sigortacılığı: Özellik Mühendisliği ve Risk Puanlaması (bu makale)
- 05 - Talep Otomasyonu: Bilgisayarla Görme ve NLP
- 06 - Dolandırıcılık Tespiti: Grafik Analizi ve Davranışsal Sinyal
- 07 - ACORD Standardı ve Sigorta API Entegrasyonu
- 08 - Uyumluluk Mühendisliği: Solvency II ve UFRS 17







