|
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"]) |
|
|