-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathComparison_of_models.py
More file actions
326 lines (260 loc) · 11.8 KB
/
Comparison_of_models.py
File metadata and controls
326 lines (260 loc) · 11.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
# -*- coding: utf-8 -*-
"""
Car Price Prediction Model
مدل پیشبینی قیمت خودرو با استفاده از NewMetric Prediction
"""
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.linear_model import LinearRegression, Ridge, Lasso
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings("ignore")
# تنظیمات نمایش فارسی
plt.rcParams["font.family"] = "DejaVu Sans"
def calculate_new_metric(y_true, y_pred):
"""
محاسبه NewMetric - معیار ارزیابی سفارشی برای پیشبینی قیمت خودرو
NewMetric = 0.4 × MAE + 0.4 × RMSE + 0.2 × Relative Error Penalty
هرچه NewMetric کمتر باشد، مدل بهتر است.
"""
# محاسبه MAE
mae = mean_absolute_error(y_true, y_pred)
# محاسبه RMSE
rmse = np.sqrt(mean_squared_error(y_true, y_pred))
# محاسبه Relative Error Penalty (میانگین خطای نسبی)
relative_errors = np.abs((y_true - y_pred) / y_true)
relative_error_penalty = np.mean(relative_errors)
# نرمالسازی MAE و RMSE برای ترکیب بهتر
# تبدیل به مقیاس نسبی (نسبت به میانگین قیمت)
mean_price = np.mean(y_true)
normalized_mae = mae / mean_price
normalized_rmse = rmse / mean_price
# محاسبه NewMetric
new_metric = (
0.4 * normalized_mae + 0.4 * normalized_rmse + 0.2 * relative_error_penalty
)
return new_metric, {
"MAE": mae,
"RMSE": rmse,
"Normalized_MAE": normalized_mae,
"Normalized_RMSE": normalized_rmse,
"Relative_Error_Penalty": relative_error_penalty,
}
def load_and_prepare_data(file_path):
"""خواندن و آمادهسازی دادهها"""
df = pd.read_excel(file_path)
print(f"تعداد رکوردها: {len(df)}")
print(f"تعداد ویژگیها: {len(df.columns)}")
return df
def select_features(df):
"""انتخاب ویژگیهای نرمالسازی شده برای مدل"""
# استفاده از ستونهای نرمالسازی شده
normalized_cols = [
col for col in df.columns if "نرمال" in col and "قیمت" not in col
]
# حذف ستونهای با مقادیر گمشده
X = df[normalized_cols].copy()
X = X.fillna(0)
# متغیر هدف - قیمت
y = df["قیمت"].copy()
print(f"تعداد ویژگیهای انتخاب شده: {len(normalized_cols)}")
return X, y, normalized_cols
def train_models(X_train, X_test, y_train, y_test):
"""آموزش مدلهای مختلف و مقایسه آنها"""
models = {
"Linear Regression": LinearRegression(),
"Ridge Regression": Ridge(alpha=1.0),
"Lasso Regression": Lasso(alpha=1.0),
"Random Forest": RandomForestRegressor(n_estimators=100, random_state=42),
"Gradient Boosting": GradientBoostingRegressor(
n_estimators=100, random_state=42
),
}
results = {}
print("\n" + "=" * 70)
print("نتایج ارزیابی مدلها - NewMetric Prediction")
print("=" * 70)
for name, model in models.items():
# آموزش مدل
model.fit(X_train, y_train)
# پیشبینی
y_pred = model.predict(X_test)
# محاسبه معیارهای استاندارد
mae = mean_absolute_error(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
r2 = r2_score(y_test, y_pred)
mape = np.mean(np.abs((y_test - y_pred) / y_test)) * 100
# 🎯 محاسبه NewMetric - معیار سفارشی
new_metric, metric_details = calculate_new_metric(y_test, y_pred)
results[name] = {
"model": model,
"MAE": mae,
"RMSE": rmse,
"R2": r2,
"MAPE": mape,
"NewMetric": new_metric,
"NewMetric_Details": metric_details,
"predictions": y_pred,
}
print(f"\n{name}:")
print(f" MAE (میانگین خطای مطلق): {mae:,.0f} تومان")
print(f" RMSE (ریشه میانگین مربعات): {rmse:,.0f} تومان")
print(f" R² Score: {r2:.4f}")
print(f" MAPE (درصد خطا): {mape:.2f}%")
print(f" ⭐ NewMetric: {new_metric:.4f} (کمتر = بهتر)")
return results
def find_best_model(results):
"""
یافتن بهترین مدل بر اساس NewMetric
NewMetric = 0.4 × MAE + 0.4 × RMSE + 0.2 × Relative Error Penalty
هرچه کمتر باشد، بهتر است.
"""
# انتخاب مدل با کمترین NewMetric (بهترین عملکرد)
best_model_name = min(results, key=lambda x: results[x]["NewMetric"])
best_result = results[best_model_name]
print("\n" + "=" * 70)
print("🏆 انتخاب بهترین مدل بر اساس NewMetric")
print("=" * 70)
print(f"\n📊 فرمول NewMetric:")
print(f" NewMetric = 0.4 × MAE_norm + 0.4 × RMSE_norm + 0.2 × RelativeError")
print(f"\n✅ بهترین مدل: {best_model_name}")
print(f" ⭐ NewMetric: {best_result['NewMetric']:.4f}")
print(f" 📈 R² Score: {best_result['R2']:.4f}")
print(f" 📉 MAE: {best_result['MAE']:,.0f} تومان")
print(f" 📉 RMSE: {best_result['RMSE']:,.0f} تومان")
print(f" 📊 MAPE: {best_result['MAPE']:.2f}%")
# نمایش جزئیات NewMetric
details = best_result["NewMetric_Details"]
print(f"\n📋 جزئیات NewMetric:")
print(f" • Normalized MAE: {details['Normalized_MAE']:.4f}")
print(f" • Normalized RMSE: {details['Normalized_RMSE']:.4f}")
print(f" • Relative Error: {details['Relative_Error_Penalty']:.4f}")
print("=" * 70)
return best_model_name, best_result
def plot_results(y_test, results, best_model_name):
"""رسم نمودارهای نتایج"""
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# نمودار 1: مقایسه NewMetric (معیار اصلی)
ax1 = axes[0, 0]
model_names = list(results.keys())
new_metric_scores = [results[name]["NewMetric"] for name in model_names]
colors = [
"green" if name == best_model_name else "steelblue" for name in model_names
]
bars = ax1.barh(model_names, new_metric_scores, color=colors)
ax1.set_xlabel("NewMetric (Lower is Better)")
ax1.set_title("⭐ Model Comparison - NewMetric")
for bar, score in zip(bars, new_metric_scores):
ax1.text(
score + 0.005,
bar.get_y() + bar.get_height() / 2,
f"{score:.4f}",
va="center",
)
# نمودار 2: MAPE
ax2 = axes[0, 1]
mape_scores = [results[name]["MAPE"] for name in model_names]
colors = ["green" if name == best_model_name else "coral" for name in model_names]
bars = ax2.barh(model_names, mape_scores, color=colors)
ax2.set_xlabel("MAPE (%)")
ax2.set_title("Model Comparison - MAPE (Lower is Better)")
for bar, score in zip(bars, mape_scores):
ax2.text(
score + 0.5,
bar.get_y() + bar.get_height() / 2,
f"{score:.2f}%",
va="center",
)
# نمودار 3: قیمت واقعی vs پیشبینی (بهترین مدل)
ax3 = axes[1, 0]
y_pred_best = results[best_model_name]["predictions"]
ax3.scatter(y_test, y_pred_best, alpha=0.6, edgecolors="black", linewidth=0.5)
# خط ایدهآل
min_val = min(y_test.min(), y_pred_best.min())
max_val = max(y_test.max(), y_pred_best.max())
ax3.plot([min_val, max_val], [min_val, max_val], "r--", lw=2, label="Ideal Line")
ax3.set_xlabel("Actual Price")
ax3.set_ylabel("Predicted Price")
ax3.set_title(f"Actual vs Predicted - {best_model_name}")
ax3.legend()
# نمودار 4: توزیع خطا
ax4 = axes[1, 1]
errors = y_test.values - y_pred_best
ax4.hist(errors, bins=30, edgecolor="black", alpha=0.7, color="purple")
ax4.axvline(x=0, color="red", linestyle="--", lw=2)
ax4.set_xlabel("Prediction Error")
ax4.set_ylabel("Frequency")
ax4.set_title(f"Error Distribution - {best_model_name}")
plt.tight_layout()
plt.savefig("model_results.png", dpi=150, bbox_inches="tight")
plt.show()
print("\nنمودارها در فایل 'model_results.png' ذخیره شدند.")
def feature_importance(best_result, feature_names, best_model_name):
"""نمایش اهمیت ویژگیها برای مدلهای درختی"""
model = best_result["model"]
if hasattr(model, "feature_importances_"):
importance = model.feature_importances_
indices = np.argsort(importance)[-15:] # 15 ویژگی مهمتر
plt.figure(figsize=(10, 8))
plt.barh(range(len(indices)), importance[indices], color="teal")
plt.yticks(range(len(indices)), [feature_names[i] for i in indices])
plt.xlabel("Feature Importance")
plt.title(f"Top 15 Important Features - {best_model_name}")
plt.tight_layout()
plt.savefig("feature_importance.png", dpi=150, bbox_inches="tight")
plt.show()
print("\nنمودار اهمیت ویژگیها در فایل 'feature_importance.png' ذخیره شد.")
def predict_price(model, X, feature_names, scaler=None):
"""تابع پیشبینی قیمت برای داده جدید"""
# این تابع میتواند برای پیشبینی قیمت خودروی جدید استفاده شود
prediction = model.predict(X)
return prediction
def main():
"""اجرای اصلی برنامه"""
print("=" * 70)
print("Car Price Prediction - NewMetric Model")
print("مدل پیشبینی قیمت خودرو")
print("=" * 70)
# 1. خواندن دادهها
file_path = "data.xlsx"
df = load_and_prepare_data(file_path)
# 2. انتخاب ویژگیها
X, y, feature_names = select_features(df)
# 3. تقسیم دادهها
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
print(f"\nتعداد دادههای آموزش: {len(X_train)}")
print(f"تعداد دادههای تست: {len(X_test)}")
# 4. آموزش و ارزیابی مدلها
results = train_models(X_train, X_test, y_train, y_test)
# 5. یافتن بهترین مدل
best_model_name, best_result = find_best_model(results)
# 6. رسم نمودارها
try:
plot_results(y_test, results, best_model_name)
feature_importance(best_result, feature_names, best_model_name)
except Exception as e:
print(f"\nخطا در رسم نمودار: {e}")
print("نتایج به صورت متنی نمایش داده شدند.")
# 7. نمونه پیشبینی
print("\n" + "=" * 70)
print("نمونه پیشبینیها از مجموعه تست:")
print("=" * 70)
best_model = best_result["model"]
sample_indices = np.random.choice(len(X_test), min(5, len(X_test)), replace=False)
for idx in sample_indices:
actual = y_test.iloc[idx]
predicted = best_model.predict(X_test.iloc[[idx]])[0]
error_percent = abs(actual - predicted) / actual * 100
print(
f"قیمت واقعی: {actual:,.0f} | پیشبینی: {predicted:,.0f} | خطا: {error_percent:.1f}%"
)
return best_model, feature_names, results
if __name__ == "__main__":
best_model, feature_names, results = main()