Generieren Sie Vorhersagen, die orthogonal (nicht korreliert) zu einer bestimmten Variablen sind

8

Ich habe eine XMatrix, eine yVariable und eine andere Variable ORTHO_VAR. Ich muss die yVariable vorhersagen , wobei Xdie Vorhersagen aus diesem Modell orthogonal sein müssen, ORTHO_VARwährend sie so korreliert ywie möglich sind.

Ich würde es vorziehen, wenn die Vorhersagen mit einer nicht parametrischen Methode wie erzeugt werden, xgboost.XGBRegressoraber ich könnte eine lineare Methode verwenden, wenn dies absolut notwendig ist.

Dieser Code:

import numpy as np
import pandas as pd
from sklearn.datasets import make_regression
from xgboost import XGBRegressor

ORTHO_VAR = 'ortho_var'
TARGET = 'target'
PRED = 'yhat'

# Create regression dataset with two correlated targets
X, y = make_regression(n_features=20, random_state=245, n_targets=2)
indep_vars = ['var{}'.format(i) for i in range(X.shape[1])]

# Pull into dataframe
df = pd.DataFrame(X, columns=indep_vars)
df[TARGET] = y[:, 0]
df[ORTHO_VAR] = y[:, 1]

# Fit a model to predict TARGET
xgb = XGBRegressor(n_estimators=10)
xgb.fit(df[indep_vars], df[TARGET])
df[PRED] = xgb.predict(df[indep_vars])

# Correlation should be low or preferably zero
pred_corr_w_ortho = df.corr().abs()[PRED][ORTHO_VAR]
assert pred_corr_w_ortho < 0.01, "Correlation score: {0} is superior to the given threshold.".format(pred_corr_w_ortho)

Gibt Folgendes zurück:

---------------------------------------------------------------------------
AssertionError                           
      1 pred_corr_w_ortho = df.corr().abs()[PRED][ORTHO_VAR]
----> 2 assert pred_corr_w_ortho < 0.01, "Correlation score: {0} is superior to the given threshold.".format(pred_corr_w_ortho)

AssertionError: Correlation score: 0.5895885756753665 is superior to the given threshold.

... und ich möchte etwas, das so viel Vorhersagegenauigkeit wie möglich beibehält und dabei orthogonal zu bleibt ORTHO_VAR

Chris
quelle
2
Was ist die Korrelation von TARGET mit ORTHO_VAR?
Esmailian
Gute Frage. Sie sind in der Tat korreliert (sagen wir 50%). Die Vorhersagen werden wahrscheinlich in Bezug auf die Genauigkeit darunter leiden, wenn sie orthogonal gemacht werden.
Chris

Antworten:

5

Diese Anforderung kann erfüllt werden, indem Vorhersagen ausreichend Rauschen hinzugefügt wird y^ um sie von orthogonalen Werten zu dekorrelieren v. Idealerweise, wenny^ ist bereits dekorreliert von vwürde kein Rauschen hinzugefügt werden y^also y^ wäre maximal korreliert mit y.

Mathematisch wollen wir schaffen y^'=y^+ϵ von ϵN.(0,σϵ), befriedigen

ry^'v=σy^'vσy^'σv<δ
für beliebige Schwelle δ. Erweitern wir nun diese Ungleichung, um eine Untergrenze für Standardrauschen zu findenϵdh σϵ.
σy^'2=σy^2+σϵ2,σy^'v=E.[(y^+ϵ- -μy^- -μϵ=0)(v- -μv)]]=E.[(y^- -μy^)(v- -μv)]]+E.[ϵ(v- -μv)]]=0=σy^v,ry^'v=σy^'vσy^'σv=σy^vσvσy^2+σϵ2<δσy^(ry^vδ)2- -1<σϵ

Da alle Variablen auf der linken Seite der Ungleichung berechnet werden können, können wir Rauschen aus abtasten N.(0,σϵ) und füge sie hinzu y^ die ursprüngliche Ungleichung zu befriedigen.

Hier ist ein Code, der genau dasselbe tut:

import numpy as np
import pandas as pd
from sklearn.datasets import make_regression
from xgboost import XGBRegressor

ORTHO_VAR = 'ortho_var'
IND_VARNM = 'indep_var'
TARGET = 'target'
CORRECTED_VARNM = 'indep_var_fixed'

seed = 245
# Create regression dataset with two correlated targets
X, y = make_regression(n_samples=10000, n_features=20, random_state=seed, n_targets=2)
indep_vars = ['var{}'.format(i) for i in range(X.shape[1])]

# Pull into dataframe
df = pd.DataFrame(X, columns=indep_vars)
df[TARGET] = y[:, 0]
df[ORTHO_VAR] = y[:, 1]

# Fit a model to predict TARGET
xgb = XGBRegressor(n_estimators=10)
xgb.fit(df[indep_vars], df[TARGET])
df['yhat'] = xgb.predict(df[indep_vars])

delta = 0.01

# std of noise required to be added to y_hat to bring the correlation
# of y_hat with ORTHO_VAR below delta
std_y_hat = np.std(df['yhat'], ddof=1)
corr_y_hat_ortho_var = np.corrcoef(df['yhat'], df[ORTHO_VAR])[1, 0]
corr_y_hat_target = np.corrcoef(df['yhat'], df[TARGET])[1, 0]
std_noise_lower_bound = std_y_hat * np.sqrt((corr_y_hat_ortho_var / delta)**2 - 1.0)
std_noise = max(0, std_noise_lower_bound) + 1
print('delta: ', delta)
print('std_y_hat: ', std_y_hat)
print('corr_y_hat_target: ', corr_y_hat_target)
print('corr_y_hat_ortho_var: ', corr_y_hat_ortho_var)
print('std_noise_lower_bound: ', std_noise_lower_bound)
print('std_noise: ', std_noise)

# add noise
np.random.seed(seed)
noises = np.random.normal(0, std_noise, len(df['yhat']))
noises -= np.mean(noises)  # remove slight deviations from zero mean
print('noise_samples: mean:', np.mean(noises), ', std: ', np.std(noises))
df['yhat'] = df['yhat'] + noises

# measure new correlation
corr_y_hat_ortho_var = np.corrcoef(df['yhat'], df[ORTHO_VAR])[1, 0]
corr_y_hat_target = np.corrcoef(df['yhat'], df[TARGET])[1, 0]
print('new corr_y_hat_target: ', corr_y_hat_target)
print('new corr_y_hat_ortho_var: ', corr_y_hat_ortho_var)
# Correlation should be low or preferably zero
assert corr_y_hat_ortho_var < delta, corr_y_hat_ortho_var
assert -delta < corr_y_hat_ortho_var, corr_y_hat_ortho_var

welche Ausgänge:

delta:  0.01
std_y_hat:  69.48568725585938
corr_y_hat_target:  0.8207672834857673
corr_y_hat_ortho_var:  0.7663936356880843
std_noise_lower_bound:  5324.885500165032
std_noise:  5325.885500165032
noise_samples: mean: 1.1059455573558807e-13 , std:  5373.914830034988
new corr_y_hat_target:  -0.004125016071865934
new corr_y_hat_ortho_var:  -0.000541131379457552

Sie können mit anderen deltas experimentieren . Im Vergleich std_y_hatmit std_noise_lower_boundkönnen Sie sehen, dass ein großes Rauschen hinzugefügt werden mussy^ zu dekorrelieren v unten 0,01, die dramatisch dekoleriert y^ von y zu.

Hinweis: AssertionMöglicherweise schlägt dies bei zu kleinen Schwellenwerten fehlδ aufgrund unzureichender Probenzahl.

Esmailian
quelle
Hängt die fehlende Korrelation zwischen yhat und der Zielvariablen mit der hohen Korrelation zwischen den beiden Zielvariablen zusammen (z. B. meine Schuld)? Idealerweise möchten wir new corr_y_hat_targetso hoch wie möglich sein new corr_y_hat_ortho_var, um so niedrig wie möglich zu sein
Chris
@ Chris Indirekt ja. Wenn targetmit einer geringen Korrelation hat orth, y_hat(die eine hohe Korrelation mit hat target) würde hatte auch eine geringe Korrelation mit orth. Infolgedessen wäre ein geringes Rauschen hinzugefügt worden, y_hatund seine Korrelation mit targethätte sich geringfügig geändert.
Esmailian