راهنمای جامع پروژه‌های رگرسیون (Regression) با پایتون و Scikit-learn

فهرست مطالب

راهنمای جامع پروژه‌های رگرسیون (Regression) با پایتون و Scikit-learn

در دنیای پرشتاب علم داده و یادگیری ماشین، توانایی پیش‌بینی مقادیر پیوسته از اهمیت ویژه‌ای برخوردار است. رگرسیون، به عنوان یکی از ستون‌های اصلی یادگیری تحت نظارت (Supervised Learning)، ابزاری قدرتمند برای درک روابط بین متغیرها و ساخت مدل‌های پیش‌بینی‌کننده است. این مقاله، یک راهنمای جامع و عمیق برای مهندسان داده، دانشمندان ماشین‌لرنینگ، و توسعه‌دهندگانی است که قصد دارند پروژه‌های رگرسیون را با استفاده از پایتون و کتابخانه فوق‌العاده Scikit-learn پیاده‌سازی و بهینه‌سازی کنند. ما از مفاهیم پایه تا تکنیک‌های پیشرفته، همراه با نمونه‌های کد و توضیحات تحلیلی، مسیری گام به گام را ارائه خواهیم داد.

هدف از این راهنما، نه تنها آموزش نحوه استفاده از توابع و کلاس‌ها، بلکه درک عمیق‌تر اصول زیربنایی، چالش‌های رایج، و بهترین شیوه‌ها در پروژه‌های رگرسیون است. ما به جزئیاتی مانند آماده‌سازی دقیق داده‌ها، انتخاب مدل مناسب، ارزیابی کارآمد مدل، و بهینه‌سازی هایپرپارامترها خواهیم پرداخت تا شما را برای ساخت مدل‌های رگرسیون قوی و قابل اعتماد مجهز کنیم.

مقدمه‌ای بر رگرسیون و کاربردهای آن در دنیای واقعی

رگرسیون در یادگیری ماشین به مجموعه‌ای از روش‌های آماری اطلاق می‌شود که برای پیش‌بینی یک متغیر وابسته (Dependent Variable) پیوسته بر اساس یک یا چند متغیر مستقل (Independent Variable) به کار می‌روند. برخلاف طبقه‌بندی (Classification) که هدف آن پیش‌بینی یک دسته گسسته است (مانند “بیمار” یا “سالم”)، رگرسیون به دنبال پیش‌بینی یک مقدار عددی و پیوسته است (مانند “دمای فردا”، “قیمت خانه” یا “میزان فروش”).

انواع رگرسیون و تفاوت آن با طبقه‌بندی

اساساً، تفاوت کلیدی بین رگرسیون و طبقه‌بندی در ماهیت متغیر خروجی نهفته است. در رگرسیون، خروجی یک مقدار عددی است که می‌تواند در یک محدوده پیوسته قرار گیرد. در حالی که در طبقه‌بندی، خروجی یک برچسب یا دسته گسسته است. به عنوان مثال، پیش‌بینی اینکه آیا یک ایمیل هرزنامه است یا خیر، یک مسئله طبقه‌بندی است، در حالی که پیش‌بینی درصد احتمال هرزنامه بودن آن، می‌تواند با رگرسیون حل شود.

مدل‌های رگرسیون می‌توانند از نظر پیچیدگی بسیار متفاوت باشند:

  • رگرسیون خطی (Linear Regression): ساده‌ترین شکل رگرسیون که فرض می‌کند رابطه خطی بین متغیرهای مستقل و وابسته وجود دارد.
  • رگرسیون چندجمله‌ای (Polynomial Regression): تعمیمی از رگرسیون خطی که به مدل اجازه می‌دهد روابط غیرخطی را با استفاده از ترم‌های چندجمله‌ای برای متغیرهای مستقل، مدل کند.
  • رگرسیون غیرخطی (Non-linear Regression): دسته‌ای از مدل‌ها که برای روابط پیچیده‌تر و غیرخطی استفاده می‌شوند که با توابع چندجمله‌ای نیز قابل تقریب نیستند.

کاربردهای واقعی رگرسیون

رگرسیون در صنایع مختلف کاربردهای بی‌شماری دارد:

  • اقتصاد و مالی: پیش‌بینی قیمت سهام، نرخ بهره، شاخص‌های اقتصادی، و ریسک اعتباری.
  • بازاریابی: پیش‌بینی فروش محصول، تعیین استراتژی‌های قیمت‌گذاری بهینه، و تخمین بازگشت سرمایه (ROI) کمپین‌های تبلیغاتی.
  • سلامت و پزشکی: پیش‌بینی طول عمر بیماران، تخمین دوز دارو، و پیش‌بینی شیوع بیماری‌ها.
  • هواشناسی: پیش‌بینی دما، میزان بارندگی، و سرعت باد.
  • املاک و مستغلات: تخمین قیمت مسکن بر اساس ویژگی‌هایی مانند متراژ، تعداد اتاق، و موقعیت مکانی.
  • تولید: پیش‌بینی کیفیت محصول، زمان لازم برای تولید، و مصرف انرژی.

چرا پایتون و Scikit-learn؟

پایتون با اکوسیستم غنی از کتابخانه‌های علمی و جامعه کاربری بزرگ خود، به زبان اصلی علم داده تبدیل شده است. Scikit-learn یکی از قدرتمندترین و پرکاربردترین کتابخانه‌ها در پایتون برای یادگیری ماشین است که مجموعه‌ای وسیع از الگوریتم‌های رگرسیون، طبقه‌بندی، خوشه‌بندی، و ابزارهای پیش‌پردازش و ارزیابی مدل را فراهم می‌کند. سادگی استفاده، مستندات عالی، و عملکرد بهینه، آن را به انتخابی ایده‌آل برای هر پروژه رگرسیونی تبدیل کرده است. در طول این راهنما، ما بر پیاده‌سازی مفاهیم با استفاده از Scikit-learn تمرکز خواهیم کرد.

آماده‌سازی داده‌ها برای مدل‌های رگرسیون: گامی حیاتی

کیفیت و ساختار داده‌ها نقش محوری در موفقیت هر پروژه یادگیری ماشین، به خصوص رگرسیون، ایفا می‌کند. مرحله آماده‌سازی داده‌ها اغلب بیشترین زمان را در کل فرآیند پروژه به خود اختصاص می‌دهد، اما سرمایه‌گذاری در این مرحله بازدهی قابل توجهی در عملکرد نهایی مدل خواهد داشت. “Garbage In, Garbage Out” یک اصل اساسی در این حوزه است؛ حتی پیشرفته‌ترین الگوریتم‌ها نیز نمی‌توانند از داده‌های بی‌کیفیت یا نامناسب نتایج قابل اعتمادی استخراج کنند.

بارگذاری و کاوش داده‌ها (Data Loading & EDA)

اولین گام، بارگذاری داده‌ها و انجام تحلیل اکتشافی داده‌ها (EDA) است. این مرحله به ما کمک می‌کند تا ساختار داده‌ها را بشناسیم، الگوها را شناسایی کنیم، و مشکلات احتمالی را کشف کنیم.


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_diabetes

# بارگذاری یک مجموعه داده نمونه
diabetes = load_diabetes(as_frame=True)
df = diabetes.frame
df['target'] = diabetes.target

print(df.head())
print(df.info())
print(df.describe())

# کاوش بصری (مثال: هیستوگرام برای توزیع متغیر هدف)
plt.figure(figsize=(8, 6))
sns.histplot(df['target'], kde=True)
plt.title('توزیع متغیر هدف (Progress)')
plt.xlabel('مقدار پیشرفت بیماری')
plt.ylabel('تعداد')
plt.show()

# ماتریس همبستگی
plt.figure(figsize=(10, 8))
sns.heatmap(df.corr(), annot=True, cmap='coolwarm', fmt=".2f")
plt.title('ماتریس همبستگی بین ویژگی‌ها و متغیر هدف')
plt.show()

df.head() برای مشاهده پنج ردیف اول، df.info() برای بررسی انواع داده و وجود مقادیر از دست رفته، و df.describe() برای خلاصه‌ای از آمار توصیفی (میانگین، میانه، انحراف معیار و …) استفاده می‌شود. نمودارهای هیستوگرام و جعبه‌ای (Box Plot) برای بررسی توزیع و شناسایی داده‌های پرت (Outliers) و ماتریس همبستگی (Correlation Matrix) برای درک روابط بین ویژگی‌ها و همچنین بین ویژگی‌ها و متغیر هدف بسیار مفید هستند.

رسیدگی به مقادیر از دست رفته (Missing Values)

مقادیر از دست رفته می‌توانند به اشکال مختلفی ظاهر شوند و باید قبل از مدل‌سازی به درستی مدیریت شوند. Scikit-learn ابزارهایی مانند SimpleImputer را برای این منظور فراهم می‌کند.

  • حذف (Deletion): حذف سطرها یا ستون‌هایی که حاوی مقادیر از دست رفته هستند. این روش زمانی مناسب است که تعداد مقادیر از دست رفته کم باشد یا حذف آنها تأثیر زیادی بر حجم داده نگذارد.
  • تکمیل (Imputation): جایگزینی مقادیر از دست رفته با یک مقدار تخمینی. روش‌های رایج شامل میانگین (mean)، میانه (median)، مد (mode)، یا استفاده از مدل‌های پیشرفته‌تر مانند K-Nearest Neighbors (KNN) یا MICE (Multiple Imputation by Chained Equations) است.

from sklearn.impute import SimpleImputer

# فرض کنید در df مقادیر NaN وجود دارد
# برای مثال، یک مقدار NaN اضافه می‌کنیم
df_missing = df.copy()
df_missing.loc[5, 'bmi'] = np.nan

# تکمیل با میانگین
imputer = SimpleImputer(strategy='mean')
df_imputed = pd.DataFrame(imputer.fit_transform(df_missing), columns=df_missing.columns)
print("DataFrame پس از تکمیل مقادیر از دست رفته با میانگین:")
print(df_imputed.head(10))

مهندسی ویژگی (Feature Engineering)

مهندسی ویژگی فرایند ایجاد ویژگی‌های جدید از ویژگی‌های موجود برای بهبود عملکرد مدل است. این مرحله نیاز به دانش دامنه و خلاقیت دارد و می‌تواند شامل موارد زیر باشد:

  • ایجاد ویژگی‌های ترکیبی: ترکیب دو یا چند ویژگی برای ایجاد یک ویژگی جدید (مثلاً نسبت قد به وزن).
  • ویژگی‌های چندجمله‌ای: تبدیل ویژگی‌های موجود به شکل چندجمله‌ای برای مدل‌سازی روابط غیرخطی (PolynomialFeatures در Scikit-learn).
  • تعامل ویژگی‌ها (Interaction Terms): ضرب دو ویژگی در یکدیگر برای مدل‌سازی اثر تعاملی آنها.

from sklearn.preprocessing import PolynomialFeatures

# مثال: ایجاد ویژگی‌های چندجمله‌ای برای BMI
poly = PolynomialFeatures(degree=2, include_bias=False)
df_poly = pd.DataFrame(poly.fit_transform(df[['bmi']]), columns=poly.get_feature_names_out(['bmi']))
print("ویژگی‌های چندجمله‌ای برای BMI:")
print(df_poly.head())

رمزگذاری ویژگی‌های طبقه‌ای (Categorical Feature Encoding)

مدل‌های یادگیری ماشین معمولاً با داده‌های عددی کار می‌کنند، بنابراین ویژگی‌های طبقه‌ای (Categorical Features) باید به فرمت عددی تبدیل شوند. روش‌های رایج عبارتند از:

  • رمزگذاری یک-داغ (One-Hot Encoding): برای ویژگی‌های طبقه‌ای بدون ترتیب ذاتی (مثلاً رنگ‌ها). یک ستون جدید برای هر دسته ایجاد می‌کند. (OneHotEncoder در Scikit-learn).
  • رمزگذاری برچسب (Label Encoding): برای ویژگی‌های طبقه‌ای با ترتیب ذاتی (مثلاً سطوح تحصیلات: “ابتدایی”، “متوسطه”، “دانشگاهی”). هر دسته را با یک عدد صحیح جایگزین می‌کند. (LabelEncoder در Scikit-learn).

مقیاس‌گذاری ویژگی‌ها (Feature Scaling)

اغلب الگوریتم‌های یادگیری ماشین، به خصوص آنهایی که بر پایه فاصله (مانند KNN) یا نزول گرادیان (مانند رگرسیون خطی، شبکه‌های عصبی) کار می‌کنند، به مقیاس ویژگی‌ها حساس هستند. مقیاس‌گذاری تضمین می‌کند که هیچ ویژگی خاصی به دلیل داشتن مقادیر بزرگتر، بر سایر ویژگی‌ها غالب نشود.

  • استانداردسازی (Standardization): تبدیل ویژگی‌ها به گونه‌ای که میانگین صفر و انحراف معیار یک داشته باشند (StandardScaler در Scikit-learn). فرمول: $X_{scaled} = (X – \mu) / \sigma$.
  • نرمال‌سازی (Normalization): مقیاس‌بندی ویژگی‌ها به یک محدوده ثابت، معمولاً [0, 1] (MinMaxScaler در Scikit-learn). فرمول: $X_{scaled} = (X – X_{min}) / (X_{max} – X_{min})$.
  • مقیاس‌گذاری قوی (Robust Scaling): مقیاس‌بندی ویژگی‌ها با استفاده از میانه و محدوده بین چارکی (Interquartile Range) که کمتر به داده‌های پرت حساس است (RobustScaler).

from sklearn.preprocessing import StandardScaler, MinMaxScaler

# مثال: استانداردسازی ویژگی‌های عددی
X = df.drop('target', axis=1)
y = df['target']

scaler = StandardScaler()
X_scaled = pd.DataFrame(scaler.fit_transform(X), columns=X.columns)
print("DataFrame پس از استانداردسازی:")
print(X_scaled.head())

تقسیم داده‌ها (Data Splitting)

برای ارزیابی صحیح عملکرد مدل، باید داده‌ها را به سه بخش تقسیم کنیم:

  • مجموعه آموزشی (Training Set): برای آموزش مدل.
  • مجموعه اعتبارسنجی (Validation Set): برای تنظیم هایپرپارامترها و جلوگیری از بیش‌برازش (Overfitting) در طول توسعه مدل.
  • مجموعه آزمایشی (Test Set): برای ارزیابی نهایی و بی‌طرفانه عملکرد مدل. این مجموعه فقط یک بار و پس از اتمام توسعه مدل استفاده می‌شود.

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=42)
print(f"اندازه مجموعه آموزش X: {X_train.shape}")
print(f"اندازه مجموعه تست X: {X_test.shape}")

با اتمام این مراحل پیش‌پردازش، داده‌های ما آماده برای ورود به مدل‌های رگرسیون هستند.

مدل‌های رگرسیون خطی و تعمیم‌یافته

رگرسیون خطی و مدل‌های مرتبط با آن، پایه‌های بسیاری از تحلیل‌های پیش‌بینی‌کننده را تشکیل می‌دهند. این مدل‌ها به دلیل سادگی، تفسیرپذیری بالا و کارایی، نقطه شروع خوبی برای بسیاری از پروژه‌های رگرسیون هستند.

رگرسیون خطی ساده و چندگانه

  • رگرسیون خطی ساده (Simple Linear Regression): این مدل به دنبال برقراری یک رابطه خطی بین یک متغیر مستقل (X) و یک متغیر وابسته (Y) است. معادله آن به صورت $Y = \beta_0 + \beta_1 X + \epsilon$ است، که در آن $\beta_0$ عرض از مبدأ، $\beta_1$ شیب خط و $\epsilon$ خطای مدل است.
  • رگرسیون خطی چندگانه (Multiple Linear Regression): این مدل تعمیمی از رگرسیون خطی ساده است که در آن چندین متغیر مستقل (X1, X2, …, Xn) برای پیش‌بینی یک متغیر وابسته (Y) استفاده می‌شوند. معادله آن به صورت $Y = \beta_0 + \beta_1 X_1 + \beta_2 X_2 + … + \beta_n X_n + \epsilon$ است.

فرضیات کلیدی رگرسیون خطی شامل خطی بودن رابطه، استقلال مشاهدات، همگنی واریانس باقی‌مانده‌ها (Homoscedasticity)، توزیع نرمال باقی‌مانده‌ها، و عدم وجود هم‌خطی بالا (Multicollinearity) بین متغیرهای مستقل است.


from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split

# فرض می‌کنیم X_scaled و y از قبل آماده شده‌اند
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=42)

# آموزش مدل رگرسیون خطی
lin_reg = LinearRegression()
lin_reg.fit(X_train, y_train)

# چاپ ضرایب و عرض از مبدأ
print(f"ضرایب (Coefficients): {lin_reg.coef_}")
print(f"عرض از مبدأ (Intercept): {lin_reg.intercept_}")

رگرسیون چندجمله‌ای (Polynomial Regression)

زمانی که رابطه بین متغیرهای مستقل و وابسته به وضوح خطی نباشد، رگرسیون چندجمله‌ای می‌تواند مفید باشد. این روش از طریق افزودن ترم‌های چندجمله‌ای (مانند $X^2$, $X^3$) به متغیرهای مستقل، به مدل اجازه می‌دهد تا روابط منحنی‌شکل را مدل‌سازی کند. این مدل هنوز هم از نظر ضرایب خطی است، اما از نظر متغیرهای ورودی غیرخطی است.


from sklearn.preprocessing import PolynomialFeatures

# ایجاد ویژگی‌های چندجمله‌ای با درجه 2
poly_features = PolynomialFeatures(degree=2, include_bias=False)
X_poly_train = poly_features.fit_transform(X_train)
X_poly_test = poly_features.transform(X_test)

# آموزش مدل رگرسیون خطی بر روی ویژگی‌های چندجمله‌ای
poly_reg = LinearRegression()
poly_reg.fit(X_poly_train, y_train)

print(f"ضرایب رگرسیون چندجمله‌ای: {poly_reg.coef_}")

رگرسیون منظم شده (Regularized Regression): Ridge, Lasso, Elastic Net

مدل‌های رگرسیون خطی و چندجمله‌ای ممکن است در معرض بیش‌برازش (Overfitting) قرار گیرند، به خصوص زمانی که تعداد ویژگی‌ها زیاد باشد یا بین آنها هم‌خطی وجود داشته باشد. رگرسیون‌های منظم شده با افزودن یک “جریمه” به تابع هزینه (Loss Function)، پیچیدگی مدل را کنترل می‌کنند و از بیش‌برازش جلوگیری می‌کنند.

  • رگرسیون Ridge (L2 Regularization): به تابع هزینه یک ترم جریمه متناسب با مربع بزرگی ضرایب ($\sum \beta_i^2$) اضافه می‌کند. این جریمه باعث می‌شود که ضرایب به سمت صفر کوچک شوند، اما هیچ‌گاه دقیقاً صفر نمی‌شوند. این کار به کاهش هم‌خطی واریانس (Variance) مدل کمک می‌کند.
  • رگرسیون Lasso (L1 Regularization): به تابع هزینه یک ترم جریمه متناسب با قدر مطلق بزرگی ضرایب ($\sum |\beta_i|$) اضافه می‌کند. ویژگی منحصربه‌فرد Lasso این است که می‌تواند برخی از ضرایب را دقیقاً به صفر برساند، که عملاً به معنای انتخاب ویژگی (Feature Selection) است. این مدل برای کاهش بایاس (Bias) و واریانس مفید است.
  • رگرسیون Elastic Net: ترکیبی از Ridge و Lasso است که هم از جریمه L1 و هم از جریمه L2 استفاده می‌کند. این مدل به خصوص زمانی مفید است که تعداد زیادی ویژگی همبسته وجود داشته باشد، یا زمانی که نمی‌دانیم کدام نوع منظم‌سازی (L1 یا L2) بهتر عمل می‌کند.

from sklearn.linear_model import Ridge, Lasso, ElasticNet

# رگرسیون Ridge
ridge_reg = Ridge(alpha=1.0) # alpha پارامتر جریمه است
ridge_reg.fit(X_train, y_train)
print(f"ضرایب Ridge Regression: {ridge_reg.coef_}")

# رگرسیون Lasso
lasso_reg = Lasso(alpha=0.1) # alpha بزرگتر -> جریمه بیشتر -> ضرایب بیشتر صفر می‌شوند
lasso_reg.fit(X_train, y_train)
print(f"ضرایب Lasso Regression: {lasso_reg.coef_}")
print(f"تعداد ضرایب صفر شده در Lasso: {np.sum(lasso_reg.coef_ == 0)}")

# رگرسیون Elastic Net
elastic_net_reg = ElasticNet(alpha=0.1, l1_ratio=0.5) # l1_ratio: نسبت L1 به L2
elastic_net_reg.fit(X_train, y_train)
print(f"ضرایب Elastic Net Regression: {elastic_net_reg.coef_}")

انتخاب مقدار بهینه برای هایپرپارامتر alphal1_ratio برای Elastic Net) بسیار مهم است و معمولاً از طریق اعتبارسنجی متقابل و جستجوی هایپرپارامتر انجام می‌شود که در ادامه به آن خواهیم پرداخت.

مدل‌های رگرسیون مبتنی بر درخت و Ensemble

مدل‌های مبتنی بر درخت و روش‌های Ensemble، رویکردهای قدرتمندی برای حل مسائل رگرسیون هستند که اغلب عملکرد بهتری نسبت به مدل‌های خطی در مواجهه با روابط پیچیده و غیرخطی ارائه می‌دهند. این مدل‌ها به طور ذاتی می‌توانند تعاملات بین ویژگی‌ها را مدل‌سازی کنند و کمتر به مقیاس‌گذاری ویژگی‌ها حساس هستند.

درخت تصمیم برای رگرسیون (Decision Tree Regressor)

درخت تصمیم با تقسیم بازگشتی فضای ویژگی به نواحی کوچکتر، پیش‌بینی‌ها را انجام می‌دهد. در رگرسیون، مقدار پیش‌بینی شده برای یک نمونه، میانگین مقادیر متغیر هدف در برگ (node) نهایی است که آن نمونه در آن قرار می‌گیرد. این مدل‌ها بسیار تفسیرپذیر هستند، اما در برابر تغییرات کوچک در داده‌ها حساس بوده و مستعد بیش‌برازش هستند.


from sklearn.tree import DecisionTreeRegressor

# آموزش Decision Tree Regressor
dt_reg = DecisionTreeRegressor(max_depth=5, random_state=42) # max_depth برای کنترل پیچیدگی
dt_reg.fit(X_train, y_train)

# می‌توان درخت را به صورت گرافیکی نمایش داد (با Graphviz) که در اینجا به دلیل محدودیت فرمت کد آورده نمی‌شود.

جنگل تصادفی برای رگرسیون (Random Forest Regressor)

جنگل تصادفی یک روش Ensemble مبتنی بر “Bagging” (Bootstrap Aggregating) است. این مدل با آموزش تعداد زیادی درخت تصمیم مستقل بر روی زیرمجموعه‌های تصادفی از داده‌های آموزشی (با جایگذاری) و زیرمجموعه‌های تصادفی از ویژگی‌ها ساخته می‌شود. برای پیش‌بینی، میانگین خروجی تمام درختان را در نظر می‌گیرد. جنگل تصادفی به طور قابل توجهی بیش‌برازش را کاهش داده و دقت پیش‌بینی را نسبت به یک درخت تصمیم تنها بهبود می‌بخشد.


from sklearn.ensemble import RandomForestRegressor

# آموزش Random Forest Regressor
rf_reg = RandomForestRegressor(n_estimators=100, max_depth=10, random_state=42, n_jobs=-1) # n_jobs=-1 برای استفاده از تمام هسته‌های CPU
rf_reg.fit(X_train, y_train)

# اهمیت ویژگی‌ها (Feature Importance)
feature_importances = pd.Series(rf_reg.feature_importances_, index=X.columns).sort_values(ascending=False)
print("اهمیت ویژگی‌ها در Random Forest:")
print(feature_importances)

گرادیان بوستینگ برای رگرسیون (Gradient Boosting Regressor)

گرادیان بوستینگ نیز یک روش Ensemble است، اما بر پایه “Boosting” کار می‌کند. در این روش، درختان تصمیم به صورت متوالی آموزش داده می‌شوند، به گونه‌ای که هر درخت جدید تلاش می‌کند خطاهای (باقی‌مانده‌های) درختان قبلی را تصحیح کند. این رویکرد به مدل اجازه می‌دهد تا به تدریج بر روی الگوهای پیچیده در داده‌ها تمرکز کند و معمولاً نتایج بسیار دقیق‌تری نسبت به جنگل تصادفی ارائه می‌دهد، اما می‌تواند مستعد بیش‌برازش باشد اگر به درستی تنظیم نشود.

Scikit-learn شامل GradientBoostingRegressor است. کتابخانه‌های محبوب دیگری مانند XGBoost، LightGBM و CatBoost نیز پیاده‌سازی‌های بسیار بهینه‌شده‌ای از گرادیان بوستینگ را ارائه می‌دهند که اغلب در مسابقات و کاربردهای صنعتی استفاده می‌شوند و فراتر از Scikit-learn قابلیت‌های پیشرفته‌ای دارند.


from sklearn.ensemble import GradientBoostingRegressor

# آموزش Gradient Boosting Regressor
gbr_reg = GradientBoostingRegressor(n_estimators=100, learning_rate=0.1, max_depth=3, random_state=42)
gbr_reg.fit(X_train, y_train)

# اهمیت ویژگی‌ها
feature_importances_gbr = pd.Series(gbr_reg.feature_importances_, index=X.columns).sort_values(ascending=False)
print("اهمیت ویژگی‌ها در Gradient Boosting:")
print(feature_importances_gbr)

مدل‌های دیگر (کوتاه): SVM Regressor, K-Neighbors Regressor

  • SVR (Support Vector Regressor): بر پایه ماشین‌های بردار پشتیبان عمل می‌کند و به جای طبقه‌بندی، برای پیش‌بینی مقادیر پیوسته استفاده می‌شود. برای مجموعه داده‌های کوچک تا متوسط عملکرد خوبی دارد و می‌تواند روابط غیرخطی را با استفاده از توابع هسته (Kernel Functions) مدل‌سازی کند.
  • K-Neighbors Regressor: یک مدل مبتنی بر فاصله است که برای پیش‌بینی مقدار یک نقطه، میانگین مقادیر K نزدیکترین همسایه آن نقطه را در نظر می‌گیرد. به مقیاس ویژگی‌ها بسیار حساس است.

from sklearn.svm import SVR
from sklearn.neighbors import KNeighborsRegressor

# SVR
# svr_reg = SVR(kernel='rbf', C=100, gamma=0.1)
# svr_reg.fit(X_train, y_train)

# K-Neighbors Regressor
# knn_reg = KNeighborsRegressor(n_neighbors=5)
# knn_reg.fit(X_train, y_train)

انتخاب مدل مناسب بستگی به ماهیت داده‌ها، اندازه مجموعه داده، نیاز به تفسیرپذیری و منابع محاسباتی دارد. اغلب، آزمایش با چند مدل مختلف و مقایسه عملکرد آنها بهترین رویکرد است.

ارزیابی عملکرد مدل‌های رگرسیون

پس از آموزش یک مدل رگرسیون، گام بعدی حیاتی ارزیابی عملکرد آن است. معیارهای ارزیابی به ما کمک می‌کنند تا میزان دقت پیش‌بینی‌های مدل را بسنجیم، مدل‌های مختلف را با هم مقایسه کنیم، و مشکلات مانند بیش‌برازش یا کم‌برازش را شناسایی کنیم.

معیارهای اصلی ارزیابی

  • خطای میانگین مطلق (Mean Absolute Error – MAE): میانگین قدر مطلق تفاوت بین مقادیر پیش‌بینی شده و مقادیر واقعی. این معیار به آسانی قابل تفسیر است زیرا واحد آن با واحد متغیر هدف یکسان است و به داده‌های پرت کمتر حساس است.
    $$MAE = \frac{1}{n} \sum_{i=1}^{n} |y_i – \hat{y}_i|$$
  • خطای میانگین مربعات (Mean Squared Error – MSE): میانگین مربعات تفاوت بین مقادیر پیش‌بینی شده و واقعی. MSE به داده‌های پرت بیشتر حساس است زیرا خطاها را به توان دو می‌رساند و بنابراین خطاهای بزرگتر را بیشتر جریمه می‌کند.
    $$MSE = \frac{1}{n} \sum_{i=1}^{n} (y_i – \hat{y}_i)^2$$
  • ریشه خطای میانگین مربعات (Root Mean Squared Error – RMSE): ریشه دوم MSE. RMSE نیز واحدی مشابه متغیر هدف دارد و به داده‌های پرت حساس است. اغلب ترجیح داده می‌شود زیرا تفسیر آن آسان‌تر از MSE است.
    $$RMSE = \sqrt{\frac{1}{n} \sum_{i=1}^{n} (y_i – \hat{y}_i)^2}$$
  • ضریب تعیین (R-squared – $R^2$ Score): معیاری است که نشان می‌دهد چه نسبتی از واریانس متغیر وابسته توسط مدل توضیح داده می‌شود. مقدار آن بین 0 تا 1 است (در برخی موارد می‌تواند منفی باشد). $R^2 = 1$ نشان‌دهنده یک مدل کامل است.
    $$R^2 = 1 – \frac{\sum_{i=1}^{n} (y_i – \hat{y}_i)^2}{\sum_{i=1}^{n} (y_i – \bar{y})^2}$$
    که در آن $\bar{y}$ میانگین مقادیر واقعی است.
  • ضریب تعیین تعدیل شده (Adjusted R-squared): $R^2$ با افزودن هر ویژگی جدید به مدل، حتی اگر ارتباطی با متغیر هدف نداشته باشد، افزایش می‌یابد. $R^2$ تعدیل شده این مشکل را با در نظر گرفتن تعداد ویژگی‌ها و اندازه نمونه برطرف می‌کند و فقط در صورتی بهبود می‌یابد که ویژگی‌های جدید به طور معنی‌داری به مدل کمک کنند.
    $$Adjusted R^2 = 1 – (1 – R^2) \frac{n – 1}{n – k – 1}$$
    که در آن $n$ تعداد مشاهدات و $k$ تعداد ویژگی‌های مستقل است.
  • خطای میانگین درصد مطلق (Mean Absolute Percentage Error – MAPE): میانگین خطاهای مطلق بر حسب درصد. این معیار به خصوص زمانی مفید است که بخواهید خطا را به صورت درصدی از مقدار واقعی بیان کنید، اما در صورتی که مقادیر واقعی نزدیک به صفر باشند، می‌تواند مشکل‌ساز باشد.
    $$MAPE = \frac{100\%}{n} \sum_{i=1}^{n} |\frac{y_i – \hat{y}_i}{y_i}|$$

from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
import numpy as np

# فرض کنید predictions_rf پیش‌بینی‌های مدل Random Forest است
predictions_rf = rf_reg.predict(X_test)

mae = mean_absolute_error(y_test, predictions_rf)
mse = mean_squared_error(y_test, predictions_rf)
rmse = np.sqrt(mse)
r2 = r2_score(y_test, predictions_rf)

print(f"MAE: {mae:.2f}")
print(f"MSE: {mse:.2f}")
print(f"RMSE: {rmse:.2f}")
print(f"R-squared: {r2:.2f}")

مفاهیم Overfitting و Underfitting

یکی از چالش‌های اصلی در یادگیری ماشین، یافتن تعادل بین بیش‌برازش (Overfitting) و کم‌برازش (Underfitting) است.

  • کم‌برازش (Underfitting): زمانی رخ می‌دهد که مدل برای یادگیری الگوهای اساسی در داده‌های آموزشی بیش از حد ساده باشد. در نتیجه، مدل در هر دو مجموعه آموزشی و آزمایشی عملکرد ضعیفی دارد. این مشکل اغلب با استفاده از مدل‌های پیچیده‌تر، افزودن ویژگی‌ها یا کاهش منظم‌سازی حل می‌شود.
  • بیش‌برازش (Overfitting): زمانی رخ می‌دهد که مدل الگوها و نویزهای خاص داده‌های آموزشی را بیش از حد حفظ کرده و در نتیجه در داده‌های جدید و ندیده شده (مجموعه آزمایشی) عملکرد ضعیفی دارد. این مشکل معمولاً با کاهش پیچیدگی مدل، افزایش داده‌های آموزشی، منظم‌سازی (Regularization)، یا استفاده از روش‌های Ensemble مانند Random Forest قابل حل است.

اعتبارسنجی متقابل (Cross-Validation)

برای اطمینان از ارزیابی قابل اعتماد و جلوگیری از بیش‌برازش در انتخاب مدل و تنظیم هایپرپارامترها، از اعتبارسنجی متقابل استفاده می‌شود. رایج‌ترین نوع آن اعتبارسنجی متقابل K-Fold است:

داده‌های آموزشی به K زیرمجموعه (Fold) تقسیم می‌شوند. در هر تکرار، یک Fold به عنوان مجموعه اعتبارسنجی و K-1 Fold باقی‌مانده به عنوان مجموعه آموزشی استفاده می‌شود. این فرآیند K بار تکرار می‌شود و در نهایت میانگین عملکرد مدل بر روی K مجموعه اعتبارسنجی، به عنوان معیار نهایی ارزیابی می‌شود. این روش یک ارزیابی پایدارتر و کمتر واریانسی از عملکرد مدل ارائه می‌دهد.


from sklearn.model_selection import cross_val_score

# محاسبه RMSE با 5-Fold Cross-Validation برای مدل Random Forest
# Scikit-learn به طور پیش‌فرض metric را به عنوان score در نظر می‌گیرد، که هرچه بیشتر بهتر است.
# برای MSE/RMSE که مقادیر خطا هستند و کمتر بهتر است، باید از 'neg_mean_squared_error' استفاده کنیم.
# سپس نتیجه را به مثبت تبدیل کرده و ریشه دوم می‌گیریم.

rmse_scores = np.sqrt(-cross_val_score(rf_reg, X_train, y_train, cv=5, scoring='neg_mean_squared_error'))

print(f"امتیازات RMSE در اعتبارسنجی متقابل: {rmse_scores}")
print(f"میانگین RMSE در اعتبارسنجی متقابل: {rmse_scores.mean():.2f}")
print(f"انحراف معیار RMSE در اعتبارسنجی متقابل: {rmse_scores.std():.2f}")

تحلیل باقی‌مانده‌ها (Residual Analysis)

بررسی باقی‌مانده‌ها (تفاوت بین مقادیر واقعی و پیش‌بینی شده) می‌تواند بینش‌های مهمی در مورد نقاط قوت و ضعف مدل ارائه دهد. یک مدل خوب باید دارای باقی‌مانده‌هایی باشد که:

  • به طور تصادفی توزیع شده باشند (بدون الگوی مشخص)
  • میانگین آنها نزدیک به صفر باشد.
  • همگنی واریانس (Homoscedasticity) داشته باشند (واریانس آنها در تمام سطوح پیش‌بینی ثابت باشد).
  • توزیع نرمال داشته باشند (برای برخی فرضیات رگرسیون خطی).

# پیش‌بینی‌ها و باقی‌مانده‌ها
y_pred_train = rf_reg.predict(X_train)
residuals_train = y_train - y_pred_train

y_pred_test = rf_reg.predict(X_test)
residuals_test = y_test - y_pred_test

plt.figure(figsize=(12, 5))

plt.subplot(1, 2, 1)
sns.histplot(residuals_train, kde=True)
plt.title('توزیع باقی‌مانده‌ها در مجموعه آموزش')
plt.xlabel('باقی‌مانده‌ها')
plt.ylabel('تعداد')

plt.subplot(1, 2, 2)
plt.scatter(y_pred_test, residuals_test, alpha=0.5)
plt.axhline(y=0, color='r', linestyle='--')
plt.title('باقی‌مانده‌ها در مقابل پیش‌بینی‌ها (مجموعه تست)')
plt.xlabel('مقادیر پیش‌بینی شده')
plt.ylabel('باقی‌مانده‌ها')
plt.show()

در نمودار پراکندگی باقی‌مانده‌ها در مقابل مقادیر پیش‌بینی شده، اگر الگویی (مانند شکل قیف یا منحنی) مشاهده شود، نشان‌دهنده مشکلات مدل مانند عدم خطی بودن رابطه یا ناهمگنی واریانس (Heteroscedasticity) است که ممکن است نیاز به مدل‌سازی پیچیده‌تر یا تبدیل متغیرها داشته باشد.

بهینه‌سازی هایپرپارامترها و پایپ‌لاین‌های رگرسیون

پس از انتخاب مدل اولیه و ارزیابی عملکرد آن، گام بعدی بهینه‌سازی هایپرپارامترهای مدل برای دستیابی به بهترین عملکرد ممکن است. همچنین، برای سازماندهی و افزایش قابلیت اطمینان کد، استفاده از پایپ‌لاین‌ها (Pipelines) در Scikit-learn توصیه می‌شود.

مفهوم هایپرپارامترها

هایپرپارامترها پارامترهایی هستند که قبل از فرآیند یادگیری، تنظیم می‌شوند (مثلاً max_depth در درخت تصمیم، n_estimators در جنگل تصادفی، یا alpha در رگرسیون Ridge). این پارامترها توسط الگوریتم از داده‌ها یاد گرفته نمی‌شوند، بلکه بر نحوه یادگیری مدل تأثیر می‌گذارند. تنظیم صحیح هایپرپارامترها می‌تواند تفاوت چشمگیری در عملکرد مدل ایجاد کند.

روش‌های بهینه‌سازی هایپرپارامترها

پیدا کردن ترکیب بهینه هایپرپارامترها معمولاً یک فرآیند تکراری و آزمون و خطا است. Scikit-learn ابزارهای قدرتمندی برای خودکارسازی این فرآیند فراهم می‌کند:

  • جستجوی شبکه‌ای (Grid Search): این روش شامل تعریف یک “شبکه” از مقادیر هایپرپارامترها است. سپس مدل برای تمام ترکیبات ممکن از این مقادیر آموزش داده و ارزیابی می‌شود. بهترین ترکیب بر اساس معیار اعتبارسنجی انتخاب می‌شود. Grid Search جامع است اما می‌تواند از نظر محاسباتی بسیار پرهزینه باشد، به خصوص برای تعداد زیادی هایپرپارامتر یا دامنه وسیعی از مقادیر.
    
    from sklearn.model_selection import GridSearchCV
    
    # تعریف شبکه هایپرپارامترها برای RandomForestRegressor
    param_grid = {
        'n_estimators': [50, 100, 200],
        'max_depth': [None, 10, 20],
        'min_samples_split': [2, 5],
        'min_samples_leaf': [1, 2]
    }
    
    grid_search_rf = GridSearchCV(estimator=RandomForestRegressor(random_state=42),
                                  param_grid=param_grid,
                                  cv=5, # اعتبارسنجی 5-Fold
                                  scoring='neg_mean_squared_error',
                                  n_jobs=-1, # استفاده از تمام هسته‌های CPU
                                  verbose=1)
    
    grid_search_rf.fit(X_train, y_train)
    
    print(f"بهترین هایپرپارامترها: {grid_search_rf.best_params_}")
    print(f"بهترین RMSE در اعتبارسنجی متقابل: {np.sqrt(-grid_search_rf.best_score_):.2f}")
    
    best_rf_model = grid_search_rf.best_estimator_
            
  • جستجوی تصادفی (Randomized Search): این روش به جای امتحان تمام ترکیبات، به صورت تصادفی تعداد مشخصی از ترکیبات هایپرپارامترها را از دامنه مشخص شده نمونه‌برداری و ارزیابی می‌کند. Randomized Search اغلب در زمان کمتری به نتایج مشابه Grid Search می‌رسد و به خصوص برای فضاهای هایپرپارامتر بزرگتر، کارآمدتر است.
    
    from sklearn.model_selection import RandomizedSearchCV
    from scipy.stats import randint, uniform
    
    # تعریف دامنه توزیع هایپرپارامترها برای Randomized Search
    param_distributions = {
        'n_estimators': randint(low=20, high=200),
        'max_depth': randint(low=5, high=30),
        'min_samples_split': randint(low=2, high=10),
        'min_samples_leaf': randint(low=1, high=5),
        'max_features': uniform(0.5, 0.5) # مثلاً بین 0.5 تا 1.0
    }
    
    random_search_rf = RandomizedSearchCV(estimator=RandomForestRegressor(random_state=42),
                                          param_distributions=param_distributions,
                                          n_iter=50, # تعداد ترکیبات تصادفی برای امتحان
                                          cv=5,
                                          scoring='neg_mean_squared_error',
                                          n_jobs=-1,
                                          random_state=42,
                                          verbose=1)
    
    random_search_rf.fit(X_train, y_train)
    
    print(f"بهترین هایپرپارامترها: {random_search_rf.best_params_}")
    print(f"بهترین RMSE در اعتبارسنجی متقابل: {np.sqrt(-random_search_rf.best_score_):.2f}")
            
  • بهینه‌سازی بیزی (Bayesian Optimization): (خارج از Scikit-learn اما بسیار مهم) این روش با استفاده از مدل‌های احتمالی، به طور هوشمندانه نقاط جدیدی را برای ارزیابی هایپرپارامترها پیشنهاد می‌دهد که احتمالاً منجر به بهبود عملکرد مدل می‌شوند. این روش معمولاً کارآمدتر از Grid Search و Randomized Search است، به خصوص برای فضاهای هایپرپارامتر با ابعاد بالا. کتابخانه‌هایی مانند Hyperopt، Optuna و Scikit-optimize این قابلیت را فراهم می‌کنند.

پایپ‌لاین‌ها در Scikit-learn (Pipelines)

پایپ‌لاین‌ها در Scikit-learn به شما امکان می‌دهند تا یک زنجیره از مراحل پیش‌پردازش (مانند تکمیل مقادیر از دست رفته، مقیاس‌گذاری ویژگی‌ها، رمزگذاری ویژگی‌های طبقه‌ای) و یک مدل نهایی را در یک شیء واحد ترکیب کنید. این کار مزایای زیادی دارد:

  • کد تمیزتر و سازمان‌یافته‌تر: تمام مراحل در یک مکان تعریف می‌شوند.
  • جلوگیری از نشت داده (Data Leakage): تضمین می‌کند که مراحل پیش‌پردازش فقط بر روی داده‌های آموزشی اعمال می‌شوند و اطلاعاتی از مجموعه تست به مدل نفوذ نمی‌کند.
  • استقرار آسان‌تر: مدل نهایی همراه با تمام مراحل پیش‌پردازش مرتبط، به راحتی قابل استقرار است.
  • سازگاری با ابزارهای اعتبارسنجی و بهینه‌سازی: پایپ‌لاین‌ها به طور کامل با GridSearchCV و RandomizedSearchCV سازگار هستند.

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer

# شناسایی ویژگی‌های عددی و طبقه‌ای
numeric_features = X.select_dtypes(include=np.number).columns
# فرض می‌کنیم هیچ categorical feature نداریم، در غیر این صورت باید لیست شود
# categorical_features = X.select_dtypes(include='object').columns

# ساخت یک Preprocessor برای تبدیل ویژگی‌ها
# این مثال فقط StandardScaler را برای ویژگی‌های عددی اعمال می‌کند
# اگر categorical_features داشتید، می‌توانید OneHotEncoder را برای آنها اضافه کنید
preprocessor = ColumnTransformer(
    transformers=[
        ('num', StandardScaler(), numeric_features)
        # ('cat', OneHotEncoder(handle_unknown='ignore'), categorical_features)
    ],
    remainder='passthrough' # ویژگی‌هایی که در لیست نیستند را دست نخورده رها می‌کند
)

# ساخت پایپ‌لاین شامل Preprocessor و مدل Random Forest
pipeline_rf = Pipeline(steps=[
    ('preprocessor', preprocessor),
    ('regressor', RandomForestRegressor(random_state=42))
])

# تعریف شبکه هایپرپارامترها برای پایپ‌لاین
# توجه کنید که پیشوند 'regressor__' برای هایپرپارامترهای مدل نهایی استفاده می‌شود.
pipeline_param_grid = {
    'regressor__n_estimators': [50, 100, 200],
    'regressor__max_depth': [10, 20]
}

# اجرای Grid Search بر روی پایپ‌لاین
grid_search_pipeline = GridSearchCV(estimator=pipeline_rf,
                                    param_grid=pipeline_param_grid,
                                    cv=5,
                                    scoring='neg_mean_squared_error',
                                    n_jobs=-1,
                                    verbose=1)

grid_search_pipeline.fit(X_train, y_train)

print(f"بهترین هایپرپارامترها برای پایپ‌لاین: {grid_search_pipeline.best_params_}")
print(f"بهترین RMSE برای پایپ‌لاین: {np.sqrt(-grid_search_pipeline.best_score_):.2f}")

best_pipeline_model = grid_search_pipeline.best_estimator_

# ارزیابی نهایی بر روی مجموعه تست
pipeline_predictions = best_pipeline_model.predict(X_test)
final_rmse = np.sqrt(mean_squared_error(y_test, pipeline_predictions))
print(f"RMSE نهایی بر روی مجموعه تست با پایپ‌لاین بهینه: {final_rmse:.2f}")

استفاده از پایپ‌لاین‌ها به شما امکان می‌دهد تا یک فرآیند مدل‌سازی کامل و قابل تکرار را ایجاد کنید که هم برای آموزش و هم برای پیش‌بینی‌های جدید قابل استفاده است.

پروژه عملی: پیش‌بینی قیمت مسکن با مجموعه داده کالیفرنیا

برای تثبیت مفاهیم آموخته شده، یک پروژه عملی پیش‌بینی قیمت مسکن با استفاده از مجموعه داده کالیفرنیا (California Housing) را مرور می‌کنیم. این مجموعه داده شامل اطلاعاتی درباره مناطق مسکونی کالیفرنیا و میانه قیمت مسکن در آن مناطق است.

بارگذاری و آماده‌سازی داده

ابتدا داده‌ها را بارگذاری کرده و آماده‌سازی‌های اولیه را انجام می‌دهیم.


from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error, r2_score
import pandas as pd
import numpy as np

# 1. بارگذاری مجموعه داده کالیفرنیا
housing = fetch_california_housing(as_frame=True)
df_housing = housing.frame
df_housing['MedHouseVal'] = housing.target # متغیر هدف: میانه قیمت مسکن

print("نمونه‌ای از داده‌ها:")
print(df_housing.head())
print("\nاطلاعات کلی:")
print(df_housing.info())
print("\nآمار توصیفی:")
print(df_housing.describe())

# 2. جداسازی ویژگی‌ها (X) و متغیر هدف (y)
X_housing = df_housing.drop('MedHouseVal', axis=1)
y_housing = df_housing['MedHouseVal']

# 3. تقسیم داده‌ها به مجموعه‌های آموزش و تست
X_train_h, X_test_h, y_train_h, y_test_h = train_test_split(X_housing, y_housing, test_size=0.2, random_state=42)

print(f"\nاندازه مجموعه آموزش X: {X_train_h.shape}")
print(f"اندازه مجموعه تست X: {X_test_h.shape}")

# 4. مقیاس‌گذاری ویژگی‌ها
# از آنجایی که همه ویژگی‌ها عددی هستند، می‌توانیم مستقیماً StandardScaler را اعمال کنیم.
scaler_housing = StandardScaler()
X_train_scaled_h = scaler_housing.fit_transform(X_train_h)
X_test_scaled_h = scaler_housing.transform(X_test_h)

# تبدیل به DataFrame برای خوانایی بهتر
X_train_scaled_h = pd.DataFrame(X_train_scaled_h, columns=X_train_h.columns)
X_test_scaled_h = pd.DataFrame(X_test_scaled_h, columns=X_test_h.columns)

مدل‌سازی و ارزیابی اولیه

با چندین مدل رگرسیون آزمایش کرده و عملکرد اولیه آنها را ارزیابی می‌کنیم.


from sklearn.linear_model import LinearRegression, Ridge
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor

# 1. مدل رگرسیون خطی
lin_reg_h = LinearRegression()
lin_reg_h.fit(X_train_scaled_h, y_train_h)
y_pred_lin = lin_reg_h.predict(X_test_scaled_h)
rmse_lin = np.sqrt(mean_squared_error(y_test_h, y_pred_lin))
r2_lin = r2_score(y_test_h, y_pred_lin)
print(f"\n--- Linear Regression ---")
print(f"RMSE: {rmse_lin:.3f}")
print(f"R2 Score: {r2_lin:.3f}")

# 2. مدل Ridge Regression (با تنظیم آلفا به صورت دستی)
ridge_reg_h = Ridge(alpha=1.0, random_state=42)
ridge_reg_h.fit(X_train_scaled_h, y_train_h)
y_pred_ridge = ridge_reg_h.predict(X_test_scaled_h)
rmse_ridge = np.sqrt(mean_squared_error(y_test_h, y_pred_ridge))
r2_ridge = r2_score(y_test_h, y_pred_ridge)
print(f"\n--- Ridge Regression ---")
print(f"RMSE: {rmse_ridge:.3f}")
print(f"R2 Score: {r2_ridge:.3f}")

# 3. مدل Random Forest Regressor
rf_reg_h = RandomForestRegressor(n_estimators=100, max_depth=10, random_state=42, n_jobs=-1)
rf_reg_h.fit(X_train_scaled_h, y_train_h)
y_pred_rf = rf_reg_h.predict(X_test_scaled_h)
rmse_rf = np.sqrt(mean_squared_error(y_test_h, y_pred_rf))
r2_rf = r2_score(y_test_h, y_pred_rf)
print(f"\n--- Random Forest Regressor ---")
print(f"RMSE: {rmse_rf:.3f}")
print(f"R2 Score: {r2_rf:.3f}")

# 4. مدل Gradient Boosting Regressor
gbr_reg_h = GradientBoostingRegressor(n_estimators=100, learning_rate=0.1, max_depth=5, random_state=42)
gbr_reg_h.fit(X_train_scaled_h, y_train_h)
y_pred_gbr = gbr_reg_h.predict(X_test_scaled_h)
rmse_gbr = np.sqrt(mean_squared_error(y_test_h, y_pred_gbr))
r2_gbr = r2_score(y_test_h, y_pred_gbr)
print(f"\n--- Gradient Boosting Regressor ---")
print(f"RMSE: {rmse_gbr:.3f}")
print(f"R2 Score: {r2_gbr:.3f}")

همانطور که مشاهده می‌شود، مدل‌های Ensemble (Random Forest و Gradient Boosting) معمولاً عملکرد بهتری نسبت به مدل‌های خطی ساده در این نوع داده‌ها دارند.

بهینه‌سازی با پایپ‌لاین و Grid Search

برای بهبود بیشتر مدل Random Forest، یک پایپ‌لاین ایجاد کرده و هایپرپارامترهای آن را با Grid Search بهینه می‌کنیم.


from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV

# 1. ساخت پایپ‌لاین (شامل مقیاس‌گذاری و مدل Random Forest)
# توجه: در این مثال، X_train_h هنوز مقیاس‌گذاری نشده است تا پایپ‌لاین کل فرآیند را انجام دهد.
# اما در عمل قبلا X_train و X_test را مقیاس‌گذاری کردیم. برای استفاده از پایپ‌لاین کامل،
# باید X_train_h و y_train_h اولیه (بدون مقیاس‌گذاری) را به GridSearchCV بدهیم.
# X_train_h_original, X_test_h_original, y_train_h, y_test_h = train_test_split(X_housing, y_housing, test_size=0.2, random_state=42)


pipeline_rf_optimized = Pipeline(steps=[
    ('scaler', StandardScaler()),
    ('regressor', RandomForestRegressor(random_state=42))
])

# 2. تعریف شبکه هایپرپارامترها برای Random Forest
# اینجا 'regressor__' را اضافه می‌کنیم تا به هایپرپارامترهای مدل داخل پایپ‌لاین اشاره کند.
pipeline_param_grid_rf = {
    'regressor__n_estimators': [100, 200, 300],
    'regressor__max_depth': [10, 15, 20],
    'regressor__min_samples_split': [2, 5],
    'regressor__min_samples_leaf': [1, 2]
}

# 3. اجرای Grid Search
grid_search_housing = GridSearchCV(estimator=pipeline_rf_optimized,
                                   param_grid=pipeline_param_grid_rf,
                                   cv=5,
                                   scoring='neg_mean_squared_error',
                                   n_jobs=-1,
                                   verbose=2)

grid_search_housing.fit(X_train_h, y_train_h) # استفاده از داده‌های X_train_h_original

print(f"\nبهترین هایپرپارامترها برای مدل نهایی: {grid_search_housing.best_params_}")
print(f"بهترین RMSE در اعتبارسنجی متقابل: {np.sqrt(-grid_search_housing.best_score_):.3f}")

# 4. ارزیابی مدل بهینه شده بر روی مجموعه تست نهایی
best_housing_model = grid_search_housing.best_estimator_
y_pred_final = best_housing_model.predict(X_test_h) # استفاده از داده‌های X_test_h_original

final_rmse_housing = np.sqrt(mean_squared_error(y_test_h, y_pred_final))
final_r2_housing = r2_score(y_test_h, y_pred_final)

print(f"\n--- عملکرد مدل نهایی (بهینه‌شده) بر روی مجموعه تست ---")
print(f"RMSE نهایی: {final_rmse_housing:.3f}")
print(f"R2 Score نهایی: {final_r2_housing:.3f}")

این پروژه نشان می‌دهد که چگونه می‌توان یک فرآیند کامل از بارگذاری داده تا مدل‌سازی، ارزیابی و بهینه‌سازی را با استفاده از پایتون و Scikit-learn پیاده‌سازی کرد.

نکات پیشرفته و ملاحظات عملی در پروژه‌های رگرسیون

فراتر از مفاهیم پایه، درک برخی نکات پیشرفته و ملاحظات عملی می‌تواند به شما در ساخت مدل‌های رگرسیون قوی‌تر، تفسیرپذیرتر و قابل اعتمادتر کمک کند.

رگرسیون غیرخطی و مدل‌های پیشرفته‌تر

در حالی که رگرسیون خطی و مدل‌های مبتنی بر درخت قدرتمند هستند، گاهی اوقات روابط در داده‌ها به قدری پیچیده و غیرخطی هستند که نیاز به رویکردهای پیشرفته‌تری دارند:

  • رگرسیون بردار پشتیبان (Support Vector Regression – SVR): همانند SVM برای طبقه‌بندی، SVR نیز سعی می‌کند یک hyperplane (در این مورد، یک خط یا سطح) پیدا کند که بیشترین تعداد نقاط را با یک حاشیه خطای مشخص (epsilon) در بر بگیرد. این مدل با استفاده از توابع هسته (مانند RBF، Polynomial) می‌تواند روابط غیرخطی پیچیده را مدل‌سازی کند. SVR به خصوص برای مجموعه داده‌های کوچک تا متوسط عملکرد خوبی دارد.
  • رگرسیون کرنل ریج (Kernel Ridge Regression): ترکیبی از Ridge Regression و مفهوم توابع هسته. این مدل می‌تواند روابط غیرخطی را با استفاده از هسته‌ها مدل‌سازی کند و در عین حال از مزایای منظم‌سازی Ridge برای جلوگیری از بیش‌برازش بهره‌مند شود.
  • شبکه‌های عصبی برای رگرسیون (Neural Networks for Regression): شبکه‌های عصبی عمیق، به خصوص شبکه‌های دارای لایه‌های متراکم (Dense Layers)، می‌توانند برای حل مسائل رگرسیون استفاده شوند. این مدل‌ها به طور خاص برای مجموعه داده‌های بزرگ و پیچیده با روابط غیرخطی بسیار قوی هستند. کتابخانه‌هایی مانند TensorFlow و PyTorch ابزارهای اصلی برای ساخت این مدل‌ها هستند.

تفسیرپذیری مدل (Model Interpretability)

در بسیاری از کاربردها، تنها دقت پیش‌بینی مدل کافی نیست؛ بلکه درک چگونگی و چرایی اتخاذ یک پیش‌بینی خاص نیز اهمیت دارد. تفسیرپذیری مدل به ما کمک می‌کند تا اعتماد به مدل را افزایش دهیم، خطاهای آن را درک کنیم، و بینش‌های جدیدی از داده‌ها به دست آوریم.

  • اهمیت ویژگی‌ها (Feature Importance): در مدل‌های مبتنی بر درخت (مانند Random Forest و Gradient Boosting)، می‌توان اهمیت نسبی هر ویژگی را در پیش‌بینی متغیر هدف محاسبه کرد.
  • SHAP (SHapley Additive exPlanations): یک رویکرد قدرتمند برای توضیح خروجی هر مدل یادگیری ماشین. SHAP مقادیر Shapley (مفهومی از تئوری بازی) را برای تخصیص “اهمیت” به هر ویژگی برای یک پیش‌بینی خاص محاسبه می‌کند. این ابزار هم توضیحات محلی (برای هر پیش‌بینی) و هم توضیحات سراسری (برای کل مدل) را ارائه می‌دهد.
  • LIME (Local Interpretable Model-agnostic Explanations): این روش با آموزش یک مدل ساده و قابل تفسیر (مانند رگرسیون خطی) در نزدیکی یک نقطه داده خاص، توضیحاتی محلی برای پیش‌بینی‌های مدل‌های پیچیده ارائه می‌دهد.

مدل‌های رگرسیون سری‌های زمانی (Time Series Regression)

زمانی که داده‌ها دارای وابستگی زمانی هستند (مثلاً پیش‌بینی قیمت سهام آینده بر اساس قیمت‌های گذشته)، رویکردهای رگرسیون سری‌های زمانی مناسب‌تر هستند. Scikit-learn به طور مستقیم الگوریتم‌های کلاسیک سری‌های زمانی (مانند ARIMA) را ارائه نمی‌دهد، اما می‌توان از مدل‌های رگرسیون آن برای ویژگی‌هایی که از داده‌های سری زمانی استخراج شده‌اند (مانند Lagged Features، Rolling Means) استفاده کرد. کتابخانه‌های Statsmodels و Prophet (فیس‌بوک) برای مدل‌سازی سری‌های زمانی تخصصی‌تر هستند.

استقرار مدل (Model Deployment)

ساخت یک مدل عالی تنها نیمی از راه است. برای اینکه مدل ارزش واقعی ایجاد کند، باید در محیط عملیاتی (Production) مستقر شود. این مرحله شامل بسته‌بندی مدل، ایجاد API برای تعامل با آن، و ادغام آن در یک سیستم بزرگتر است. پایپ‌لاین‌های Scikit-learn به دلیل سازماندهی و ایزوله کردن تمام مراحل، برای استقرار بسیار مناسب هستند. ابزارهایی مانند Flask, FastAPI برای ساخت API و Docker برای بسته‌بندی محیط مدل کاربرد فراوانی دارند.

اخلاق در هوش مصنوعی و مدل‌های رگرسیون (Ethics in AI and Regression Models)

همانند سایر کاربردهای هوش مصنوعی، مدل‌های رگرسیون نیز می‌توانند پیامدهای اخلاقی مهمی داشته باشند. مسائلی مانند:

  • سوگیری (Bias): اگر داده‌های آموزشی دارای سوگیری باشند (مثلاً نمونه‌های کمی از یک گروه خاص)، مدل می‌تواند پیش‌بینی‌های ناعادلانه یا تبعیض‌آمیزی برای آن گروه انجام دهد (مثلاً در پیش‌بینی ریسک اعتباری یا تصمیمات قضایی).
  • شفافیت (Transparency): لزوم درک چگونگی عملکرد مدل، به خصوص در کاربردهای حساس.
  • حریم خصوصی (Privacy): حفاظت از داده‌های حساس که برای آموزش مدل استفاده شده‌اند.

به عنوان مهندسان و دانشمندان داده، مسئولیت اخلاقی داریم که این مسائل را در طول فرآیند توسعه مدل در نظر بگیریم و تلاش کنیم مدل‌هایی منصفانه، شفاف و ایمن بسازیم.

جمع‌بندی

پروژه‌های رگرسیون ستون فقرات بسیاری از راه‌حل‌های تحلیل داده و هوش مصنوعی را تشکیل می‌دهند. از درک مفاهیم بنیادی و آماده‌سازی دقیق داده‌ها تا انتخاب و آموزش مدل‌های پیشرفته، ارزیابی دقیق عملکرد و بهینه‌سازی هایپرپارامترها، هر مرحله نیازمند دقت و تخصص است. پایتون و Scikit-learn ابزارهای قدرتمندی را برای پیمایش این مسیر فراهم می‌کنند، اما موفقیت نهایی به درک عمیق شما از داده‌ها، مدل‌ها، و نیازهای واقعی مسئله بستگی دارد.

با تمرین مستمر، آزمایش با مجموعه داده‌های مختلف، و به‌روز نگه داشتن دانش خود با آخرین پیشرفت‌ها، می‌توانید به یک متخصص در زمینه پروژه‌های رگرسیون تبدیل شوید و از قدرت یادگیری ماشین برای حل پیچیده‌ترین مسائل دنیای واقعی بهره ببرید.

“تسلط به برنامه‌نویسی پایتون با هوش مصنوعی: آموزش کدنویسی هوشمند با ChatGPT”

قیمت اصلی 2.290.000 ریال بود.قیمت فعلی 1.590.000 ریال است.

"تسلط به برنامه‌نویسی پایتون با هوش مصنوعی: آموزش کدنویسی هوشمند با ChatGPT"

"با شرکت در این دوره جامع و کاربردی، به راحتی مهارت‌های برنامه‌نویسی پایتون را از سطح مبتدی تا پیشرفته با کمک هوش مصنوعی ChatGPT بیاموزید. این دوره، با بیش از 6 ساعت محتوای آموزشی، شما را قادر می‌سازد تا به سرعت الگوریتم‌های پیچیده را درک کرده و اپلیکیشن‌های هوشمند ایجاد کنید. مناسب برای تمامی سطوح با زیرنویس فارسی حرفه‌ای و امکان دانلود و تماشای آنلاین."

ویژگی‌های کلیدی:

بدون نیاز به تجربه قبلی برنامه‌نویسی

زیرنویس فارسی با ترجمه حرفه‌ای

۳۰ ٪ تخفیف ویژه برای دانشجویان و دانش آموزان