Polinomial Reqressiya: Underfitting, Overfitting və Bias-Variance Trade-off
Bundan əvvəlki yazıdan xətti modeldən danışdıq. Bəs x və y arasında xətti bir münasibət yoxdursa necə olacaq? Xətti olmayan datalara da xətti model tətbiq edə bilərik. Bunun üçün hər bir x-i qüvvətini almaq və yeni bir sütun kimi istifadə etməkdir. Bu üsula Polinomial Reqressiya modeli deyilir.
Fərz edək ki, əlimizdə aşağıdakı kimi data var:
import numpy as np
import matplotlib.pyplot as plt
m=100
X=6*np.random.rand(m,1)-3
y=0.5*X**2+X+2+np.random.randn(m, 1)
plt.scatter(X, y)
plt.show()Göründüyü kimi xətti bir asılılıq yoxdur. O zaman düz bir model bu datanı yaxşı təmsil edə bilməyəcək.
Əgər sadəcə kvadrat dərəcədən seçsək mövcud x kvadrata yüksəldilir və əlavə edilir. Dərəcəni 3 olaraq götürsək, bu zaman mövcud x-in həm kvadratı, həm də kubu əlavə edilir. Bu məntiqlə dərəcəni istədiyimiz kimi seçə bilərik.
Bəs əgər x bir yox, bir neçə sütun olsa? Bütün x-lər yenə həmin dərəcəyə qədər qüvvəyə yüksəldilir və model daxil edilir. Eyni zamanda iki və ya daha çox dəyişən olduqda, model onların qarşılıqlı təsirini də nəzərə alır. Məsələn, x₁*x₂ ilə bir dəyişənin digərinə təsirini də öyrənə bilirik. Buna görə də “PolynomialFeatures” təkcə qüvvətləri deyil, həm də bütün uyğun polinom kombinasiyalarını yaradır.
Deməli, n sayda x-i olan datada dərəcədən asılı olaraq yeni yaranan sütunlarla birlikdə sonda əldə olacaq sütun sayı aşağıdakı düsturla hesablana bilər.
İndi 2-ci dərəcədən kod üzərində baxaq:
from sklearn.preprocessing import PolynomialFeatures
poly_features=PolynomialFeatures(degree=2, include_bias=False)
X_poly=poly_features.fit_transform(X)degree=2 götürdüyümüz üçün X_poly dəyişkənində x və x-in kvadratı olmaqla 2 sütun olacaq.
İndi artıq xətti modelimizi qura bilərik:
from sklearn.linear_model import LinearRegression
lin_reg=LinearRegression()
lin_reg.fit(X_poly, y)
y_predict=lin_reg.predict(X_poly)
sort_idx = np.argsort(X.ravel())
X_sorted = X[sort_idx]
y_predict_sorted = y_predict[sort_idx]
plt.scatter(X, y)
plt.plot(X_sorted, y_predict_sorted, linewidth=3, color="red", label="Predictions")
plt.xlabel('x₁')
plt.ylabel('y')
plt.legend()
plt.show()Bəs niyə xətti model işlədə bilirik? Çünki dərəcə modeli dəyişmir, sadəcə əlavə sütunlar əlavə edirik. Yəni bir neçə sütun var imiş kimi adi xətti reqressiya qururuq. Yəni Polinomial Reqressiya əslində yeni alqoritm deyil, sadəcə sütunların dərəcə metodu ilə artırılmasından sonra tətbiq olunan xətti reqressiyadır.
Get Natig Mamishov’s stories in your inbox
Join Medium for free to get updates from this writer.
İndi bir neçə fərqli dərəcəndən modeli vizual olaraq görək:
plt.scatter(X, y)
for degree in [1, 2, 30]:
poly_features=PolynomialFeatures(degree=degree, include_bias=False)
X_poly=poly_features.fit_transform(X)
lin_reg=LinearRegression()
lin_reg.fit(X_poly, y)
y_predict=lin_reg.predict(X_poly)
sort_idx = np.argsort(X.ravel())
X_sorted = X[sort_idx]
y_predict_sorted = y_predict[sort_idx]
plt.plot(X_sorted, y_predict_sorted, linewidth=3, label=f'degree={degree}')
plt.xlabel('x₁')
plt.ylabel('y')
plt.legend()
plt.legend()
plt.show()Qrafikə baxdığımız zaman, yüksək dərəcədən polinom model çox detallı qurulub(əzbərləyir) deyə bilərik. Bu səbəbdən model təlim datasında çox yaxşı nəticə göstərsə də, yeni məlumatlar üzərində ümumiləşdirmə qabiliyyəti zəif olacaq. Sadə xətti model isə yetərsiz görünür. Bu nümunədə daha yaxşı ümumiləşdirən model 2-ci dərəcəli modeldir. Başqa datalarda optimal dərəcə fərqli ola bilər. Çünki başda da gördüyümüz kimi datanı kvadrat bir funksiya istifadə edərək düzəltdik. Amma hər zaman başdan datanın necə funksional asılılıq içində olduğunu bilmirik. O zaman hansı dərəcədən bir model quracağımıza necə qərar verə bilərik? Yəni dərəcəni necə seçə bilərik? Modelin kifayət qədər öyrənmədiyini və ya əzbərləməyə başladığını necə təyin edə bilərik?
Overfitting və underfitting
Aşağıdakı kimi bir koda baxaq:
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
import numpy as np
def plot_learning_curves(model, X, y):
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2)
train_errors, val_errors = [], []
for m in range(1, len(X_train)):
model.fit(X_train[:m], y_train[:m])
y_train_predict = model.predict(X_train[:m])
y_val_predict = model.predict(X_val)
train_errors.append(mean_squared_error(y_train[:m], y_train_predict))
val_errors.append(mean_squared_error(y_val, y_val_predict))
plt.plot(np.sqrt(train_errors), "r-+", linewidth=2, label="train")
plt.plot(np.sqrt(val_errors), "b-", linewidth=3, label="val")
plt.xlabel("Training set size")
plt.ylabel("RMSE")
plt.legend()
plt.show()
lin_reg=LinearRegression()
plot_learning_curves(lin_reg, X, y)Gördüyümüz kimi train datada 1 və ya 2 sətir olduğu zaman model çox yaxşı öyrənir və xəta sıfırdan başlayır. Train dataya yeni sətirlər daxil olduqca model artıq əzbərləyə bilmir. Ona görə də xəta bir nöqtəyə qədər arta-arta gedir. Lakin o nöqtədən sonra train dataya nə qədər sətri daxil eldisə də model daha yaxşı və ya daha pis olmur. validation datada isə ilk başda xəta çox yüksəkdir. Çünki başda model çox az data ilə öyrəndiyi üçün bir ümumiləşdirmə edə bilmir. Sonra train datay yeni sətirlər daxil olduqca model öyrənməyə başlayır və xəta get-gedə azalır. Lakin bir nöqtəyə qədər enəndən sonra model xətası yenə sabit qalır. Yəni xətti bir modellə problemi həll edə bilmirik. Bu nümunə underfitting için yaxşı bir nümunədir. Model sabit bir xətaya çatıb, lakin hələ də yüksəkdir.
Qeyd: Əgər model train datanı ümumiləşdirə bilmirsə, yeni sətirlər əlavə etmək çox da fərq etməyəcək. Deməli, daha mürəkkəb modellərdən istifadə edilməlidir.
Aşağıdakı koda baxaq:
np.random.seed(42)
X = np.random.uniform(-3, 3, 20).reshape(-1, 1)
y = (2+ X.ravel()**2+ np.random.normal(0, 1.2, 20))
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.30,random_state=42)
results = {"degree": [], "train_error": [], "test_error": []}
for degree in range(1, 10):
poly = PolynomialFeatures(degree=degree, include_bias=False)
X_train_poly = poly.fit_transform(X_train)
X_test_poly = poly.transform(X_test)
model = LinearRegression()
model.fit(X_train_poly, y_train)
y_train_pred = model.predict(X_train_poly)
y_test_pred = model.predict(X_test_poly)
train_rmse = np.sqrt(mean_squared_error(y_train, y_train_pred))
test_rmse = np.sqrt(mean_squared_error(y_test, y_test_pred))
results["degree"].append(degree)
results["train_error"].append(train_rmse)
results["test_error"].append(test_rmse)
results = pd.DataFrame(results)plt.figure(figsize=(8, 5))
plt.plot(results["degree"], results["train_error"], marker="o", label="Train error")
plt.plot(results["degree"], results["test_error"], marker="o", label="Test error")
plt.xlabel("Polynomial degree")
plt.ylabel("Root Mean Squared Error")
plt.title("Train and Test Error by Polynomial Degree")
plt.xticks(range(1, 10))
plt.legend()
plt.grid()
plt.show()Gördüyümüz kimi dərəcə 1 olduğu zaman, model çox sadədir. Məlumat əyri formada olduğu halda model onu düz xətt kimi öyrənməyə çalışır. Buna görə həm train, həm də test datasında böyük xəta yaranır. Bu vəziyyət underfitting adlanır. Dərəcə 2 seçildiyi zaman hər iki xəta kəskin azalır. Deməli, model artıq məlumatın əsas qanunauyğunluğunu öyrənə və onu ümumiləşdirə bilir. Dərəcə 3–4 olduğu zaman test xətası aşağı qiymətə yaxın olur. Bu dərəcələr model mürəkkəbliyi ilə ümumiləşdirmə qabiliyyəti arasında ən yaxşı balansı yaradır. Dərəcə 5–9 seçildiyi zaman train xətası azalır, amma test xətası artır. Yəni model artıq əzbərləyib. Buna isə overfitting deyilir.
Qeyd: Əzbərləmə(overfitting) problemini həll etməyin yollarından biri validation və ya test xətası train xətasına yaxınlaşana qədər train dataya yeni sətirlər əlavə etməkdir.
Bias-Variance Trade-off
Bias xətanı, varyans isə dəyişkənliyi göstərən kəmiyyətdir. Yəni bias model əsl əlaqəni öyrənə bilirmi sualına cavab verir, varyans isə modelin məlumat dəyişəndə nə qədər dəyişdiyini göstərir. Koddan və şəkildən də göründüyü kimi modelin mürəkkəbliyi artdıqca modelin dəyişkənliyi artır və xətası azalır. Yəni model əlindəki bilgilərə əsasən hər nöqtəni düzgün öyrənməyə çalışır. Bəs bu bizə niyə kifayət etmir? Çünki bu model sadəcə öz gördükləri üzərində(train data)bu nəticəni göstərə biləcək. Bəs yeni şeylər gördükcə nə edəcək? Böyük xətalar ilə üzləşəcək. Şəkildən də göründüyü kimi komplekslik artdıqca bir müddətdən sonra Test xətaları, yəni görmədikləri qarşısında xətaları artmaya başlayır. Optimal model isə bias və varyansın qarşılıqlı minimum olduğu yerlərdə ortaya çıxır.
Praktikada polinomun dərəcəsi adətən train və validation (və ya cross-validation) nəticələrinə əsasən seçilir. Məqsəd həm train, həm də validation xətasının aşağı olduğu modeli tapmaqdır.
Polinomial reqressiya xətti olmayan əlaqələri modelləşdirmək üçün sadə və effektiv yanaşmadır. Lakin modelin dərəcəsi düzgün seçilmədikdə underfitting və ya overfitting problemləri yarana bilər. Buna görə praktikada model seçimi yalnız train nəticələrinə deyil, validation və ya test nəticələrinə əsasən aparılır. Növbəti yazıda isə modelin mürəkkəbliyini nəzarətdə saxlamaq və overfitting problemini azaltmaq üçün istifadə olunan Ridge(L2), Lasso(L1) və Elastic Net regularizasiya metodlarından danışacağıq.








