Spaces:
Runtime error
Runtime error
| # کاتب v8 – نسخه نهایی بدون لیکیج و با دقت واقعی بازار تهران ۱۴۰۴ | |
| import pandas as pd | |
| import numpy as np | |
| from catboost import CatBoostRegressor | |
| from sklearn.model_selection import train_test_split | |
| from sklearn.metrics import mean_absolute_error | |
| import pickle | |
| print("کاتب v8 در حال ساخت — این بار بدون هیچ اشتباهی! 🔥") | |
| df = pd.read_csv("/kaggle/input/divar-dataset-2024/real_estate_ads.csv") | |
| df = df[(df['cat3_slug'] == 'apartment-sell') & (df['city_slug'] == 'tehran')].copy() | |
| # پیشپردازش پاک و بدون لیکیج | |
| df = df.rename(columns={ | |
| 'price_value': 'price', 'building_size': 'area', 'rooms_count': 'rooms_raw', | |
| 'neighborhood_slug': 'neighborhood', 'construction_year': 'year', | |
| 'has_elevator': 'elevator', 'has_parking': 'parking', 'has_warehouse': 'warehouse' | |
| }) | |
| df = df.dropna(subset=['price', 'area']) | |
| df['price'] = pd.to_numeric(df['price'], errors='coerce') | |
| df['area'] = pd.to_numeric(df['area'], errors='coerce') | |
| df = df.dropna(subset=['price', 'area']) | |
| # فیلترهای منطقی (واقعی بازار) | |
| df = df[(df['price'] > 800_000_000) & (df['price'] < 150_000_000_000)] | |
| df = df[(df['area'] > 40) & (df['area'] < 500)] | |
| # فیکس اتاق | |
| def fix_rooms(x): | |
| if pd.isna(x): return 2 | |
| x = str(x).lower() | |
| if x.isdigit(): return int(x) | |
| nums = {'یک':1,'دو':2,'سه':3,'چهار':4,'پنج':5,'شش':6,'هفت':7,'هشت':8} | |
| for k,v in nums.items(): | |
| if k in x: return v | |
| return 2 | |
| df['rooms'] = df['rooms_raw'].apply(fix_rooms) if 'rooms_raw' in df.columns else 2 | |
| df['rooms'] = df['rooms'].astype(int) | |
| # فیچرهای پاک (بدون price_per_m2!) | |
| df['year'] = pd.to_numeric(df['year'], errors='coerce') | |
| df['age'] = 1404 - df['year'].fillna(1398) | |
| df['is_new'] = (df['age'] <= 5).astype(int) | |
| df['log_area'] = np.log1p(df['area']) # لگاریتم متراژ کمک میکنه | |
| df['neighborhood'] = df['neighborhood'].fillna('نامشخص').astype(str) | |
| # امکانات | |
| for col in ['elevator', 'parking', 'warehouse']: | |
| if col in df.columns: | |
| df[col] = df[col].fillna(False).astype(bool) | |
| else: | |
| df[col] = False | |
| print(f"دیتاست نهایی v8: {len(df):,} آگهی پاک و بدون لیکیج") | |
| # فقط فیچرهای مجاز (هیچ اطلاعاتی از قیمت در ورودی نیست!) | |
| features = ['area', 'log_area', 'rooms', 'age', 'is_new', 'neighborhood', 'elevator', 'parking', 'warehouse'] | |
| X = df[features] | |
| y = df['price'] | |
| X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42) | |
| model_v8 = CatBoostRegressor( | |
| iterations=8000, | |
| depth=10, | |
| learning_rate=0.03, | |
| loss_function='RMSE', | |
| verbose=500, | |
| cat_features=['neighborhood'], | |
| random_seed=42, | |
| early_stopping_rounds=500 | |
| ) | |
| print("آموزش کاتب v8 شروع شد...") | |
| model_v8.fit(X_train, y_train, eval_set=(X_val, y_val)) | |
| # تست واقعی روی آگهی پونک (۶۸ متر مفید، ۲ خواب، پونک، فول امکانات، حدود ۱۰ سال ساخت) | |
| test = pd.DataFrame([{ | |
| 'area': 68, | |
| 'log_area': np.log1p(68), | |
| 'rooms': 2, | |
| 'age': 10, | |
| 'is_new': 0, | |
| 'neighborhood': 'پونک', | |
| 'elevator': True, | |
| 'parking': True, | |
| 'warehouse': True | |
| }]) | |
| pred = model_v8.predict(test)[0] / 1_000_000_000 | |
| print(f"\nپیشبینی کاتب v8 (۶۸ متر مفید - پونک - فول): {pred:.2f} میلیارد تومان") | |
| print(f"قیمت واقعی آگهی: 9.98 میلیارد → خطا: {abs(pred - 9.98):.2f} میلیارد") | |
| # ارزیابی کلی | |
| val_pred = model_v8.predict(X_val) | |
| mae = mean_absolute_error(y_val, val_pred) / 1e9 | |
| print(f"\nمیانگین خطا کلی (MAE): ±{mae:.2f} میلیارد تومان") | |
| # ذخیره مدل نهایی | |
| with open("kaatib_v8_best.pkl", "wb") as f: | |
| pickle.dump(model_v8, f) | |
| print("\nکاتب v8 آماده است — این بار واقعاً دقیق و بدون تقلب!") |