| import os |
| import pickle |
| import numpy as np |
| import lightgbm as lgb |
| import requests |
| import json |
| import time |
| from sklearn.preprocessing import StandardScaler |
|
|
| |
| GEOCODING_API_URL = "https://nominatim.openstreetmap.org/search" |
| CACHE_DIR = os.path.join(os.path.dirname(__file__), "cache") |
| os.makedirs(CACHE_DIR, exist_ok=True) |
|
|
| |
| MODEL_PATH = os.path.join(os.path.dirname(__file__), "model.pkl") |
| SCALER_PATH = os.path.join(os.path.dirname(__file__), "scaler.pkl") |
|
|
| |
| SOIL_TYPES = { |
| "kaya": 0.1, |
| "sert": 0.3, |
| "orta": 0.5, |
| "yumuşak": 0.7, |
| "alüvyon": 0.9 |
| } |
|
|
| |
| BUILDING_AGE_FACTORS = { |
| "0-10": 0.2, |
| "11-20": 0.4, |
| "21-30": 0.6, |
| "31-40": 0.8, |
| "41+": 1.0 |
| } |
|
|
| |
| EARTHQUAKE_ZONES = { |
| "İstanbul": 0.9, |
| "İzmir": 0.8, |
| "Ankara": 0.5, |
| "Bursa": 0.7, |
| "Kocaeli": 0.9, |
| "Sakarya": 0.9, |
| "Düzce": 0.9, |
| "Bolu": 0.8, |
| "Yalova": 0.9, |
| "Çanakkale": 0.7, |
| "Balıkesir": 0.8, |
| "Manisa": 0.8, |
| "Aydın": 0.7, |
| "Muğla": 0.6, |
| "Denizli": 0.7, |
| "Antalya": 0.6, |
| "Adana": 0.6, |
| "Hatay": 0.7, |
| "Osmaniye": 0.7, |
| "Kahramanmaraş": 0.9, |
| "Gaziantep": 0.8, |
| "Kilis": 0.7, |
| "Şanlıurfa": 0.6, |
| "Diyarbakır": 0.6, |
| "Mardin": 0.5, |
| "Batman": 0.6, |
| "Siirt": 0.6, |
| "Şırnak": 0.6, |
| "Hakkari": 0.7, |
| "Van": 0.8, |
| "Bitlis": 0.7, |
| "Muş": 0.7, |
| "Ağrı": 0.6, |
| "Iğdır": 0.6, |
| "Kars": 0.5, |
| "Ardahan": 0.5, |
| "Erzurum": 0.6, |
| "Erzincan": 0.9, |
| "Tunceli": 0.7, |
| "Bingöl": 0.8, |
| "Elazığ": 0.8, |
| "Malatya": 0.8, |
| "Sivas": 0.6, |
| "Kayseri": 0.5, |
| "Nevşehir": 0.5, |
| "Kırşehir": 0.5, |
| "Aksaray": 0.5, |
| "Niğde": 0.5, |
| "Konya": 0.4, |
| "Karaman": 0.5, |
| "Mersin": 0.6, |
| "Adıyaman": 0.8, |
| "Afyonkarahisar": 0.6, |
| "Kütahya": 0.7, |
| "Uşak": 0.6, |
| "Eskişehir": 0.6, |
| "Bilecik": 0.7, |
| "Çankırı": 0.5, |
| "Karabük": 0.5, |
| "Zonguldak": 0.6, |
| "Bartın": 0.6, |
| "Kastamonu": 0.5, |
| "Çorum": 0.5, |
| "Amasya": 0.5, |
| "Tokat": 0.6, |
| "Ordu": 0.5, |
| "Giresun": 0.5, |
| "Trabzon": 0.5, |
| "Rize": 0.5, |
| "Artvin": 0.5, |
| "Gümüşhane": 0.5, |
| "Bayburt": 0.5, |
| "Samsun": 0.5, |
| "Sinop": 0.5, |
| "Kırıkkale": 0.5, |
| "Yozgat": 0.5, |
| "Kırklareli": 0.4, |
| "Edirne": 0.4, |
| "Tekirdağ": 0.7, |
| |
| "default": 0.5 |
| } |
|
|
| def geocode_address(address, use_cache=True): |
| """Adresi koordinatlara dönüştür""" |
| |
| cache_file = os.path.join(CACHE_DIR, f"geocode_{address.replace(' ', '_').replace('/', '_')}.json") |
| if use_cache and os.path.exists(cache_file): |
| try: |
| with open(cache_file, 'r', encoding='utf-8') as f: |
| return json.load(f) |
| except Exception as e: |
| print(f"Cache loading error: {e}") |
| |
| params = { |
| "q": address, |
| "format": "json", |
| "limit": 1, |
| "countrycodes": "tr" |
| } |
| |
| try: |
| response = requests.get(GEOCODING_API_URL, params=params, timeout=10) |
| response.raise_for_status() |
| |
| data = response.json() |
| |
| if data and len(data) > 0: |
| lat = float(data[0]["lat"]) |
| lon = float(data[0]["lon"]) |
| display_name = data[0]["display_name"] |
| |
| |
| address_parts = display_name.split(", ") |
| province = None |
| for part in reversed(address_parts): |
| if "Province" in part or "İli" in part: |
| province = part.replace(" Province", "").replace(" İli", "") |
| break |
| |
| if not province and len(address_parts) > 1: |
| province = address_parts[-2] |
| |
| result = { |
| "latitude": lat, |
| "longitude": lon, |
| "display_name": display_name, |
| "province": province |
| } |
| |
| |
| with open(cache_file, 'w', encoding='utf-8') as f: |
| json.dump(result, f, ensure_ascii=False) |
| |
| return result |
| else: |
| return None |
| except Exception as e: |
| print(f"Geocoding error: {e}") |
| return None |
|
|
| def get_soil_type(lat, lon): |
| """Koordinatlara göre zemin türünü tahmin et (gerçek API olmadığı için simüle ediyoruz)""" |
| |
| |
| soil_types = list(SOIL_TYPES.keys()) |
| |
| seed = int((lat * 1000 + lon * 1000) % 100) |
| np.random.seed(seed) |
| soil_type = np.random.choice(soil_types, p=[0.2, 0.3, 0.3, 0.15, 0.05]) |
| return soil_type |
|
|
| def get_building_age(address): |
| """Adrese göre bina yaşını tahmin et (gerçek API olmadığı için simüle ediyoruz)""" |
| |
| |
| |
| seed = sum(ord(c) for c in address) % 100 |
| np.random.seed(seed) |
| age_categories = list(BUILDING_AGE_FACTORS.keys()) |
| age_category = np.random.choice(age_categories, p=[0.1, 0.2, 0.3, 0.2, 0.2]) |
| return age_category |
|
|
| def get_historical_earthquakes(lat, lon, radius_km=50): |
| """Belirli bir koordinat çevresindeki geçmiş depremleri getir (gerçek API olmadığı için simüle ediyoruz)""" |
| |
| |
| |
| seed = int((lat * 1000 + lon * 1000) % 100) |
| np.random.seed(seed) |
| |
| |
| province_factor = 0.5 |
| for province, factor in EARTHQUAKE_ZONES.items(): |
| if province.lower() in f"{lat},{lon}".lower(): |
| province_factor = factor |
| break |
| |
| num_earthquakes = int(np.random.randint(5, 50) * province_factor * 2) |
| max_magnitude = np.random.uniform(4.0, 7.0) * province_factor |
| avg_magnitude = np.random.uniform(3.0, max_magnitude - 0.5) |
| |
| return { |
| "count": num_earthquakes, |
| "max_magnitude": max_magnitude, |
| "avg_magnitude": avg_magnitude |
| } |
|
|
| def extract_features(address): |
| """Adresten özellik vektörü çıkar""" |
| |
| geo_data = geocode_address(address) |
| |
| if not geo_data: |
| print(f"Adres bulunamadı: {address}") |
| return None |
| |
| lat = geo_data["latitude"] |
| lon = geo_data["longitude"] |
| province = geo_data["province"] |
| |
| |
| soil_type = get_soil_type(lat, lon) |
| soil_factor = SOIL_TYPES[soil_type] |
| |
| |
| building_age = get_building_age(address) |
| age_factor = BUILDING_AGE_FACTORS[building_age] |
| |
| |
| if province in EARTHQUAKE_ZONES: |
| zone_factor = EARTHQUAKE_ZONES[province] |
| else: |
| zone_factor = EARTHQUAKE_ZONES["default"] |
| |
| |
| historical_eq = get_historical_earthquakes(lat, lon) |
| |
| |
| features = { |
| "latitude": lat, |
| "longitude": lon, |
| "soil_factor": soil_factor, |
| "age_factor": age_factor, |
| "zone_factor": zone_factor, |
| "eq_count": historical_eq["count"], |
| "eq_max_magnitude": historical_eq["max_magnitude"], |
| "eq_avg_magnitude": historical_eq["avg_magnitude"] |
| } |
| |
| return features |
|
|
| def prepare_features(address): |
| """Adresten model için özellik vektörü hazırla""" |
| |
| features = extract_features(address) |
| |
| if not features: |
| return None |
| |
| |
| feature_array = np.array([[ |
| features["latitude"], |
| features["longitude"], |
| features["soil_factor"], |
| features["age_factor"], |
| features["zone_factor"], |
| features["eq_count"], |
| features["eq_max_magnitude"], |
| features["eq_avg_magnitude"] |
| ]]) |
| |
| |
| if os.path.exists(SCALER_PATH): |
| with open(SCALER_PATH, "rb") as f: |
| scaler = pickle.load(f) |
| else: |
| |
| scaler = StandardScaler() |
| |
| sample_data = np.array([ |
| [41.0082, 28.9784, 0.5, 0.6, 0.7, 20, 5.5, 4.2], |
| [39.9334, 32.8597, 0.3, 0.4, 0.5, 10, 4.5, 3.5], |
| [38.4192, 27.1287, 0.7, 0.8, 0.8, 30, 6.0, 4.8] |
| ]) |
| scaler.fit(sample_data) |
| |
| |
| with open(SCALER_PATH, "wb") as f: |
| pickle.dump(scaler, f) |
| |
| |
| scaled_features = scaler.transform(feature_array) |
| |
| return scaled_features |
|
|
| def load_or_create_model(): |
| """Model dosyasını yükle veya yeni bir model oluştur""" |
| if os.path.exists(MODEL_PATH): |
| |
| with open(MODEL_PATH, "rb") as f: |
| model = pickle.load(f) |
| print(f"Model loaded: {MODEL_PATH}") |
| else: |
| |
| print("Model not found, creating a new model...") |
| |
| |
| params = { |
| "objective": "regression", |
| "metric": "rmse", |
| "num_leaves": 31, |
| "learning_rate": 0.05, |
| "feature_fraction": 0.9, |
| "bagging_fraction": 0.8, |
| "bagging_freq": 5, |
| "verbose": -1 |
| } |
| |
| model = lgb.LGBMRegressor(**params) |
| |
| |
| |
| X = np.array([ |
| |
| [41.0082, 28.9784, 0.7, 0.8, 0.9, 35, 6.8, 5.2], |
| [39.9334, 32.8597, 0.3, 0.4, 0.5, 12, 4.8, 3.7], |
| [38.4192, 27.1287, 0.6, 0.7, 0.8, 28, 6.2, 4.9], |
| [37.0000, 35.3213, 0.5, 0.6, 0.6, 18, 5.5, 4.3], |
| [40.1885, 29.0610, 0.6, 0.7, 0.7, 22, 5.8, 4.5], |
| [36.8841, 30.7056, 0.4, 0.5, 0.6, 15, 5.2, 4.0], |
| [37.9144, 40.2306, 0.5, 0.6, 0.6, 20, 5.6, 4.4], |
| [38.7312, 35.4787, 0.4, 0.5, 0.5, 14, 5.0, 3.9], |
| [41.2867, 36.3300, 0.3, 0.4, 0.5, 10, 4.5, 3.5], |
| [40.6560, 29.2840, 0.8, 0.9, 0.9, 40, 7.0, 5.5], |
| [40.7560, 30.3780, 0.8, 0.9, 0.9, 38, 6.9, 5.4], |
| [40.8380, 31.1630, 0.8, 0.9, 0.9, 36, 6.8, 5.3], |
| [39.7167, 39.4833, 0.7, 0.8, 0.9, 32, 6.6, 5.1], |
| [38.6823, 39.2262, 0.7, 0.8, 0.8, 30, 6.5, 5.0], |
| [38.3552, 38.3095, 0.7, 0.8, 0.8, 29, 6.4, 5.0], |
| [37.5833, 36.9333, 0.8, 0.9, 0.9, 34, 6.7, 5.2], |
| [37.0662, 37.3833, 0.7, 0.8, 0.8, 27, 6.3, 4.9], |
| [36.2000, 36.1667, 0.7, 0.8, 0.7, 26, 6.2, 4.8], |
| [38.5000, 43.4000, 0.7, 0.8, 0.8, 31, 6.5, 5.0], |
| ]) |
| |
| |
| y = np.array([ |
| 0.85, |
| 0.45, |
| 0.75, |
| 0.60, |
| 0.70, |
| 0.55, |
| 0.60, |
| 0.50, |
| 0.45, |
| 0.90, |
| 0.90, |
| 0.90, |
| 0.85, |
| 0.80, |
| 0.80, |
| 0.85, |
| 0.75, |
| 0.70, |
| 0.75, |
| ]) |
| |
| model.fit(X, y) |
| |
| |
| os.makedirs(os.path.dirname(MODEL_PATH), exist_ok=True) |
| with open(MODEL_PATH, "wb") as f: |
| pickle.dump(model, f) |
| |
| print(f"New model created and saved: {MODEL_PATH}") |
| |
| return model |
|
|
| def predict_risk(address): |
| """Adres için deprem risk skorunu tahmin et""" |
| |
| features = prepare_features(address) |
| |
| if features is None: |
| print(f"Features could not be extracted for address: {address}") |
| return None |
| |
| |
| model = load_or_create_model() |
| |
| |
| risk_score = model.predict(features)[0] |
| |
| |
| risk_score = max(0, min(1, risk_score)) |
| |
| return risk_score |
|
|
| def get_risk_category(risk_score): |
| """Risk skoruna göre kategori belirle""" |
| if risk_score < 0.2: |
| return "Çok Düşük" |
| elif risk_score < 0.4: |
| return "Düşük" |
| elif risk_score < 0.6: |
| return "Orta" |
| elif risk_score < 0.8: |
| return "Yüksek" |
| else: |
| return "Çok Yüksek" |
|
|
| def get_risk_explanation(risk_score, address): |
| """Risk skoru için açıklama oluştur""" |
| category = get_risk_category(risk_score) |
| |
| explanations = { |
| "Çok Düşük": f"{address} için deprem riski çok düşük seviyededir. Bölgenizde büyük depremler nadiren görülür ve zemin yapısı genellikle sağlamdır.", |
| "Düşük": f"{address} için deprem riski düşük seviyededir. Bölgenizde orta büyüklükte depremler görülebilir, ancak sık değildir.", |
| "Orta": f"{address} için deprem riski orta seviyededir. Bölgenizde zaman zaman orta ve büyük depremler görülebilir. Temel deprem hazırlıklarını yapmanız önerilir.", |
| "Yüksek": f"{address} için deprem riski yüksek seviyededir. Bölgenizde büyük depremler görülme olasılığı yüksektir. Kapsamlı deprem hazırlıkları yapmanız ve binanızın durumunu kontrol ettirmeniz önerilir.", |
| "Çok Yüksek": f"{address} için deprem riski çok yüksek seviyededir. Bölgenizde büyük depremler sık görülür. Acil deprem hazırlıkları yapmanız, binanızın depreme dayanıklılığını kontrol ettirmeniz ve gerekirse güçlendirme çalışmaları yaptırmanız önerilir." |
| } |
| |
| return explanations[category] |
|
|
| def predict_risk_with_details(address): |
| """Adres için deprem risk skorunu ve detayları döndür""" |
| |
| risk_score = predict_risk(address) |
| |
| if risk_score is None: |
| return { |
| "success": False, |
| "message": f"Adres bulunamadı veya risk hesaplanamadı: {address}" |
| } |
| |
| |
| category = get_risk_category(risk_score) |
| explanation = get_risk_explanation(risk_score, address) |
| |
| |
| geo_data = geocode_address(address) |
| |
| |
| soil_type = get_soil_type(geo_data["latitude"], geo_data["longitude"]) |
| |
| |
| building_age = get_building_age(address) |
| |
| return { |
| "success": True, |
| "address": address, |
| "display_name": geo_data["display_name"], |
| "province": geo_data["province"], |
| "latitude": geo_data["latitude"], |
| "longitude": geo_data["longitude"], |
| "risk_score": risk_score, |
| "risk_category": category, |
| "explanation": explanation, |
| "soil_type": soil_type, |
| "building_age": building_age |
| } |
|
|
| |
| if __name__ == "__main__": |
| |
| test_address = "İstanbul, Kadıköy" |
| |
| |
| result = predict_risk_with_details(test_address) |
| |
| if result["success"]: |
| print(f"Adres: {result['address']}") |
| print(f"Tam Adres: {result['display_name']}") |
| print(f"İl: {result['province']}") |
| print(f"Koordinatlar: {result['latitude']}, {result['longitude']}") |
| print(f"Zemin Türü: {result['soil_type']}") |
| print(f"Bina Yaşı: {result['building_age']}") |
| print(f"Risk Skoru: {result['risk_score']:.4f}") |
| print(f"Risk Kategorisi: {result['risk_category']}") |
| print(f"Açıklama: {result['explanation']}") |
| else: |
| print(result["message"]) |
|
|