Loading
Loading
هذا المشروع يجمع كل ما تعلمته في دورة تعلم الآلة في مشروع واحد متكامل: من استكشاف البيانات وحتى نشر النموذج.
بناء نموذج يتنبأ بأسعار المنازل بناءً على خصائصها، مع تطبيق منهجية Data Science الكاملة.
1. استكشاف البيانات (EDA)
↓
2. تنظيف البيانات وتحضيرها
↓
3. Feature Engineering
↓
4. تدريب وتقييم عدة نماذج
↓
5. Hyperparameter Tuning
↓
6. تحليل الأخطاء
↓
7. حفظ النموذج النهائي
| الدرس | ما تعلمته | |-------|---------| | 1. ما هو ML | البيانات → النموذج، Supervised/Unsupervised | | 2. أنواع التعلم | Regression، Classification، Clustering | | 3. Linear Regression | MSE، Gradient Descent، R² | | 4. Logistic Regression | Sigmoid، Precision/Recall، F1 | | 5. Decision Trees | Gini، Pruning، Overfitting | | 6. Random Forest | Bagging، OOB Score، Feature Importance | | 7. تقييم النماذج | Cross-Validation، Learning Curves، Grid Search | | 8. المشروع | Pipeline كامل من EDA لحفظ النموذج |
بعد هذه الدورة، أنت جاهز لـ:
المستوى التالي:
تطبيق عملي:
مسارات التخصص:
import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
from sklearn.linear_model import Ridge
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
from sklearn.preprocessing import StandardScaler, LabelEncoder
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
import joblib
import warnings
warnings.filterwarnings("ignore")
print("=" * 60)
print("🏠 مشروع: التنبؤ بأسعار المنازل — Pipeline كامل")
print("=" * 60)
# ─────────────────────────────────────────
# 1. توليد بيانات واقعية
# ─────────────────────────────────────────
np.random.seed(42)
n = 2000
districts = ["الرياض - العليا", "الرياض - النرجس", "الرياض - حطين",
"الرياض - الملقا", "الرياض - الروضة"]
data = pd.DataFrame({
"area_sqm": np.random.normal(200, 80, n).clip(60, 600),
"rooms": np.random.randint(2, 8, n),
"bathrooms": np.random.randint(1, 5, n),
"floors": np.random.randint(1, 4, n),
"age_years": np.random.randint(0, 30, n),
"has_pool": np.random.binomial(1, 0.2, n),
"has_garden": np.random.binomial(1, 0.4, n),
"parking": np.random.randint(0, 4, n),
"district": np.random.choice(districts, n),
"dist_center_km": np.random.exponential(8, n).clip(1, 30),
})
# قيم مفقودة (واقعية)
data.loc[np.random.choice(n, 50, replace=False), "bathrooms"] = np.nan
data.loc[np.random.choice(n, 30, replace=False), "age_years"] = np.nan
# السعر الحقيقي
district_premium = {d: p for d, p in zip(districts, [1.3, 1.1, 1.2, 0.9, 1.0])}
data["price"] = (
data["area_sqm"] * 3500
+ data["rooms"] * 25000
+ data["bathrooms"].fillna(2) * 15000
- data["age_years"].fillna(10) * 2000
+ data["has_pool"] * 80000
+ data["has_garden"] * 40000
+ data["parking"] * 20000
- data["dist_center_km"] * 5000
+ data["district"].map(district_premium) * 50000
+ np.random.normal(0, 50000, n)
).clip(200000, 5000000)
print(f"\n1. البيانات:")
print(f" عدد المنازل : {len(data)}")
print(f" الميزات : {data.shape[1] - 1}")
print(f" قيم مفقودة : {data.isnull().sum().sum()}")
print(f" نطاق الأسعار : {data['price'].min():,.0f} - {data['price'].max():,.0f} ريال")
print(f" متوسط السعر : {data['price'].mean():,.0f} ريال")
# ─────────────────────────────────────────
# 2. Feature Engineering
# ─────────────────────────────────────────
print("\n2. Feature Engineering:")
data["price_per_sqm"] = data["price"] / data["area_sqm"] # للتحليل فقط
data["total_amenities"] = data["has_pool"] + data["has_garden"] + (data["parking"] > 0)
data["rooms_per_floor"] = data["rooms"] / data["floors"]
le = LabelEncoder()
data["district_encoded"] = le.fit_transform(data["district"])
features = ["area_sqm", "rooms", "bathrooms", "floors", "age_years",
"has_pool", "has_garden", "parking", "dist_center_km",
"district_encoded", "total_amenities", "rooms_per_floor"]
X = data[features]
y = data["price"]
print(f" ميزات بعد الهندسة: {len(features)}")
# ─────────────────────────────────────────
# 3. مقارنة النماذج
# ─────────────────────────────────────────
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
models = {
"Ridge Regression": Pipeline([
("imputer", SimpleImputer(strategy="median")),
("scaler", StandardScaler()),
("model", Ridge(alpha=100))
]),
"Random Forest": Pipeline([
("imputer", SimpleImputer(strategy="median")),
("model", RandomForestRegressor(n_estimators=200, n_jobs=-1, random_state=42))
]),
"Gradient Boosting": Pipeline([
("imputer", SimpleImputer(strategy="median")),
("model", GradientBoostingRegressor(n_estimators=200, random_state=42))
]),
}
print("\n3. مقارنة النماذج (CV=5):")
print(f" {'النموذج':25s} | {'MAE':>12s} | {'R²':>8s}")
print(" " + "-" * 55)
best_model_name, best_r2 = None, -999
for name, pipe in models.items():
r2_scores = cross_val_score(pipe, X_train, y_train, cv=5, scoring="r2", n_jobs=-1)
mae_scores = cross_val_score(pipe, X_train, y_train, cv=5,
scoring="neg_mean_absolute_error", n_jobs=-1)
r2 = r2_scores.mean()
mae = -mae_scores.mean()
print(f" {name:25s} | {mae:>12,.0f} | {r2:>8.4f}")
if r2 > best_r2:
best_r2, best_model_name = r2, name
print(f"\n ✅ أفضل نموذج: {best_model_name}")
# ─────────────────────────────────────────
# 4. التدريب النهائي والتقييم
# ─────────────────────────────────────────
final_model = models[best_model_name]
final_model.fit(X_train, y_train)
y_pred = final_model.predict(X_test)
mae = mean_absolute_error(y_test, y_pred)
rmse = np.sqrt(mean_squared_error(y_test, y_pred))
r2 = r2_score(y_test, y_pred)
print("\n4. نتائج Test Set النهائية:")
print(f" MAE = {mae:>10,.0f} ريال")
print(f" RMSE = {rmse:>10,.0f} ريال")
print(f" R² = {r2:>10.4f}")
print(f" الخطأ النسبي = {mae/y_test.mean()*100:.1f}%")
# ─────────────────────────────────────────
# 5. حفظ النموذج
# ─────────────────────────────────────────
joblib.dump(final_model, "house_price_model.pkl")
print("\n5. ✅ تم حفظ النموذج في: house_price_model.pkl")
# ─────────────────────────────────────────
# 6. تنبؤ ببيت جديد
# ─────────────────────────────────────────
loaded_model = joblib.load("house_price_model.pkl")
new_house = pd.DataFrame([{
"area_sqm": 280, "rooms": 5, "bathrooms": 3, "floors": 2,
"age_years": 5, "has_pool": 1, "has_garden": 1, "parking": 2,
"dist_center_km": 8, "district_encoded": 2,
"total_amenities": 2, "rooms_per_floor": 2.5
}])
predicted_price = loaded_model.predict(new_house)[0]
print(f"\n6. تنبؤ لبيت جديد:")
print(f" الخصائص: 280م², 5 غرف, مسبح, حديقة, 8كم من المركز")
print(f" السعر المتوقع: {predicted_price:,.0f} ريال")
print("\n🎉 مبروك! أكملت دورة تعلم الآلة بنجاح")