Множественная линейная регрессия с определенным ограничением на каждый коэффициент на Python - PullRequest
0 голосов
/ 18 мая 2018

В настоящее время я выполняю множественную линейную регрессию на наборе данных.Сначала я не осознавал, что мне нужно ограничивать свои веса;на самом деле, мне нужно иметь конкретные положительные и отрицательные веса.

Чтобы быть более точным, я делаю систему оценок, и именно поэтому некоторые из моих переменных должны оказывать положительное или отрицательное влияние нанота.Тем не менее, при запуске моей модели результаты не соответствуют ожидаемым, некоторые из моих «положительных» переменных получают отрицательные коэффициенты и наоборот.

В качестве примера, давайте предположим, что моя модель:

     y = W0*x0 + W1*x1 + W2*x2 

Где x2 - «положительная» переменная, я бы хотел поставить ограничение на W2, чтобы она была положительной!

Я много раз обдумывал эту проблему, но не нашелЧто-нибудь об ограничениях на конкретные веса / коэффициенты, все, что я нашел, это об установке всех коэффициентов в положительное значение или суммировании их в единицу.

Я работаю над Python, используя пакеты ScikitLearn.Вот как я получаю свою лучшую модель:

    def ridge(Xtrain, Xtest, Ytrain, Ytest, position):
        param_grid={'alpha':[0.01 , 0.1, 1, 10, 50, 100, 1000]}
        gs = grid_search.GridSearchCV(Ridge(), param_grid=param_grid, n_jobs=-1, cv=3)
        gs.fit(Xtrain, Ytrain)
        hatytrain = gs.predict(Xtrain)
        hatytest = gs.predict(Xtest)

Есть идеи, как я могу назначить ограничение на коэффициент конкретной переменной?Возможно, будет сложно обойтись при определении каждого ограничения, но я не знаю, как поступить иначе.

Спасибо!

Примечание: я все еще начинающий в кодировании :)

1 Ответ

0 голосов
/ 21 мая 2018

Scikit-learn не допускает таких ограничений на коэффициенты.

Но вы можете наложить любые ограничения на коэффициенты и оптимизировать потери с помощью координаты спуска , если вы реализуете свою собственную оценку .В случае без ограничений спуск координат дает тот же результат, что и OLS, за разумное количество итераций.

Я написал класс, который устанавливает верхнюю и нижнюю границы для коэффициентов LinearRegression.Вы можете расширить его, чтобы использовать штраф Риджа или Эвел Лассо, если хотите:

from sklearn.linear_model.base import LinearModel
from sklearn.base import RegressorMixin
from sklearn.utils import check_X_y
import numpy as np

class ConstrainedLinearRegression(LinearModel, RegressorMixin):

    def __init__(self, fit_intercept=True, normalize=False, copy_X=True, nonnegative=False, tol=1e-15):
        self.fit_intercept = fit_intercept
        self.normalize = normalize
        self.copy_X = copy_X
        self.nonnegative = nonnegative
        self.tol = tol

    def fit(self, X, y, min_coef=None, max_coef=None):
        X, y = check_X_y(X, y, accept_sparse=['csr', 'csc', 'coo'], y_numeric=True, multi_output=False)
        X, y, X_offset, y_offset, X_scale = self._preprocess_data(
            X, y, fit_intercept=self.fit_intercept, normalize=self.normalize, copy=self.copy_X)
        self.min_coef_ = min_coef if min_coef is not None else np.repeat(-np.inf, X.shape[1])
        self.max_coef_ = max_coef if max_coef is not None else np.repeat(np.inf, X.shape[1])
        if self.nonnegative:
            self.min_coef_ = np.clip(self.min_coef_, 0, None)

        beta = np.zeros(X.shape[1]).astype(float)
        prev_beta = beta + 1
        hessian = np.dot(X.transpose(), X)
        while not (np.abs(prev_beta - beta)<self.tol).all():
            prev_beta = beta.copy()
            for i in range(len(beta)):
                grad = np.dot(np.dot(X,beta) - y, X)
                beta[i] = np.minimum(self.max_coef_[i], 
                                     np.maximum(self.min_coef_[i], 
                                                beta[i]-grad[i] / hessian[i,i]))

        self.coef_ = beta
        self._set_intercept(X_offset, y_offset, X_scale)
        return self    

Этот класс можно использовать, например, для того, чтобы все коэффициенты были неотрицательными

from sklearn.datasets import load_boston
from sklearn.linear_model import LinearRegression
X, y = load_boston(return_X_y=True)
model = ConstrainedLinearRegression(nonnegative=True)
model.fit(X, y)
print(model.intercept_)
print(model.coef_)

Этопроизводит вывод как

-36.99292986145538
[0.         0.05286515 0.         4.12512386 0.         8.04017956
 0.         0.         0.         0.         0.         0.02273805
 0.        ]

Вы можете видеть, что большинство коэффициентов равны нулю.Обычная LinearModel сделала бы их отрицательными:

model = LinearRegression()
model.fit(X, y)
print(model.intercept_)
print(model.coef_)

, который вернул бы вас

36.49110328036191
[-1.07170557e-01  4.63952195e-02  2.08602395e-02  2.68856140e+00
 -1.77957587e+01  3.80475246e+00  7.51061703e-04 -1.47575880e+00
  3.05655038e-01 -1.23293463e-02 -9.53463555e-01  9.39251272e-03
 -5.25466633e-01]

Вы также можете наложить произвольные границы для любых выбранных вами коэффициентов - это то, что вы просили.Например, в этой настройке

model = ConstrainedLinearRegression()
min_coef = np.repeat(-np.inf, X.shape[1])
min_coef[0] = 0
min_coef[4] = -1
max_coef = np.repeat(4, X.shape[1])
max_coef[3] = 2
model.fit(X, y, max_coef=max_coef, min_coef=min_coef)
print(model.intercept_)
print(model.coef_)

вы получите вывод

24.060175576410515
[ 0.          0.04504673 -0.0354073   2.         -1.          4.
 -0.01343263 -1.17231216  0.2183103  -0.01375266 -0.7747823   0.01122374
 -0.56678676]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...