deprem / model.py
therayz1's picture
Upload 15 files
0c954a9 verified
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 (adres -> koordinat)
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 dosya yolu
MODEL_PATH = os.path.join(os.path.dirname(__file__), "model.pkl")
SCALER_PATH = os.path.join(os.path.dirname(__file__), "scaler.pkl")
# Zemin türleri ve risk faktörleri
SOIL_TYPES = {
"kaya": 0.1,
"sert": 0.3,
"orta": 0.5,
"yumuşak": 0.7,
"alüvyon": 0.9
}
# Bina yaşı risk faktörleri
BUILDING_AGE_FACTORS = {
"0-10": 0.2,
"11-20": 0.4,
"21-30": 0.6,
"31-40": 0.8,
"41+": 1.0
}
# Türkiye'deki deprem bölgeleri (basitleştirilmiş)
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,
# Diğer iller için varsayılan değer
"default": 0.5
}
def geocode_address(address, use_cache=True):
"""Adresi koordinatlara dönüştür"""
# Cache kontrolü
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" # Türkiye ile sınırla
}
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"]
# İl bilgisini çıkar
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
}
# Cache'e kaydet
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)"""
# Gerçek uygulamada burada bir zemin türü API'si kullanılabilir
# Şimdilik rastgele bir zemin türü döndürelim
soil_types = list(SOIL_TYPES.keys())
# Deterministik olması için koordinatları seed olarak kullan
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)"""
# Gerçek uygulamada burada bir bina yaşı API'si kullanılabilir
# Şimdilik rastgele bir bina yaşı döndürelim
# Deterministik olması için adresi seed olarak kullan
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)"""
# Gerçek uygulamada burada AFAD veya USGS API'si kullanılabilir
# Şimdilik rastgele deprem sayısı ve büyüklüğü döndürelim
# Deterministik olması için koordinatları seed olarak kullan
seed = int((lat * 1000 + lon * 1000) % 100)
np.random.seed(seed)
# Bölgeye göre deprem sayısı ve büyüklüğünü ayarla
province_factor = 0.5 # Varsayılan
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"""
# Adresi koordinatlara dönüştür
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"]
# Zemin türü
soil_type = get_soil_type(lat, lon)
soil_factor = SOIL_TYPES[soil_type]
# Bina yaşı
building_age = get_building_age(address)
age_factor = BUILDING_AGE_FACTORS[building_age]
# Deprem bölgesi risk faktörü
if province in EARTHQUAKE_ZONES:
zone_factor = EARTHQUAKE_ZONES[province]
else:
zone_factor = EARTHQUAKE_ZONES["default"]
# Geçmiş depremler
historical_eq = get_historical_earthquakes(lat, lon)
# Özellik vektörü oluştur
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"""
# Özellikleri çıkar
features = extract_features(address)
if not features:
return None
# DataFrame'e dönüştür
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"]
]])
# Scaler yükle veya oluştur
if os.path.exists(SCALER_PATH):
with open(SCALER_PATH, "rb") as f:
scaler = pickle.load(f)
else:
# Gerçek uygulamada scaler eğitim verisiyle oluşturulmalı
scaler = StandardScaler()
# Varsayılan değerlerle fit et
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)
# Scaler'ı kaydet
with open(SCALER_PATH, "wb") as f:
pickle.dump(scaler, f)
# Özellikleri normalize et
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):
# Mevcut modeli yükle
with open(MODEL_PATH, "rb") as f:
model = pickle.load(f)
print(f"Model loaded: {MODEL_PATH}")
else:
# Yeni model oluştur (gerçek uygulamada eğitim verisiyle eğitilmeli)
print("Model not found, creating a new model...")
# LightGBM modeli oluştur
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)
# Basit bir veri seti ile eğit (gerçek uygulamada gerçek veri kullanılmalı)
# Türkiye'nin farklı bölgelerinden örnek veri
X = np.array([
# [latitude, longitude, soil_factor, age_factor, zone_factor, eq_count, eq_max_magnitude, eq_avg_magnitude]
[41.0082, 28.9784, 0.7, 0.8, 0.9, 35, 6.8, 5.2], # İstanbul
[39.9334, 32.8597, 0.3, 0.4, 0.5, 12, 4.8, 3.7], # Ankara
[38.4192, 27.1287, 0.6, 0.7, 0.8, 28, 6.2, 4.9], # İzmir
[37.0000, 35.3213, 0.5, 0.6, 0.6, 18, 5.5, 4.3], # Adana
[40.1885, 29.0610, 0.6, 0.7, 0.7, 22, 5.8, 4.5], # Bursa
[36.8841, 30.7056, 0.4, 0.5, 0.6, 15, 5.2, 4.0], # Antalya
[37.9144, 40.2306, 0.5, 0.6, 0.6, 20, 5.6, 4.4], # Diyarbakır
[38.7312, 35.4787, 0.4, 0.5, 0.5, 14, 5.0, 3.9], # Kayseri
[41.2867, 36.3300, 0.3, 0.4, 0.5, 10, 4.5, 3.5], # Samsun
[40.6560, 29.2840, 0.8, 0.9, 0.9, 40, 7.0, 5.5], # Kocaeli
[40.7560, 30.3780, 0.8, 0.9, 0.9, 38, 6.9, 5.4], # Sakarya
[40.8380, 31.1630, 0.8, 0.9, 0.9, 36, 6.8, 5.3], # Düzce
[39.7167, 39.4833, 0.7, 0.8, 0.9, 32, 6.6, 5.1], # Erzincan
[38.6823, 39.2262, 0.7, 0.8, 0.8, 30, 6.5, 5.0], # Elazığ
[38.3552, 38.3095, 0.7, 0.8, 0.8, 29, 6.4, 5.0], # Malatya
[37.5833, 36.9333, 0.8, 0.9, 0.9, 34, 6.7, 5.2], # Kahramanmaraş
[37.0662, 37.3833, 0.7, 0.8, 0.8, 27, 6.3, 4.9], # Gaziantep
[36.2000, 36.1667, 0.7, 0.8, 0.7, 26, 6.2, 4.8], # Hatay
[38.5000, 43.4000, 0.7, 0.8, 0.8, 31, 6.5, 5.0], # Van
])
# Risk skorları (0-1 arası, bölgesel risk faktörlerine göre)
y = np.array([
0.85, # İstanbul
0.45, # Ankara
0.75, # İzmir
0.60, # Adana
0.70, # Bursa
0.55, # Antalya
0.60, # Diyarbakır
0.50, # Kayseri
0.45, # Samsun
0.90, # Kocaeli
0.90, # Sakarya
0.90, # Düzce
0.85, # Erzincan
0.80, # Elazığ
0.80, # Malatya
0.85, # Kahramanmaraş
0.75, # Gaziantep
0.70, # Hatay
0.75, # Van
])
model.fit(X, y)
# Modeli kaydet
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"""
# Özellikleri hazırla
features = prepare_features(address)
if features is None:
print(f"Features could not be extracted for address: {address}")
return None
# Modeli yükle
model = load_or_create_model()
# Tahmin yap
risk_score = model.predict(features)[0]
# Skoru 0-1 aralığına normalize et
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 skorunu tahmin et
risk_score = predict_risk(address)
if risk_score is None:
return {
"success": False,
"message": f"Adres bulunamadı veya risk hesaplanamadı: {address}"
}
# Kategori ve açıklama
category = get_risk_category(risk_score)
explanation = get_risk_explanation(risk_score, address)
# Adres detayları
geo_data = geocode_address(address)
# Zemin türü
soil_type = get_soil_type(geo_data["latitude"], geo_data["longitude"])
# Bina yaşı
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
}
# Test
if __name__ == "__main__":
# Test adresi
test_address = "İstanbul, Kadıköy"
# Risk skorunu tahmin et
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"])