Supposons que nous observions les données et que nous souhaitions ajuster un modèle de régression pour . Malheureusement, est parfois mesuré avec des erreurs dont la moyenne est non nulle.
Soit indiquer si est mesuré avec des erreurs moyennes nulles classiques ou des erreurs non nulles, respectivement. Nous aimerions estimer . Malheureusement, n'est généralement pas observé, et . Si nous ajustons une régression de sur , nous obtiendrons des prédictions biaisées.
Supposons que nous ne pouvons généralement pas observer , mais que nous ayons accès à un modèle pour (parce que nous avons appris manuellement Z sur un petit ensemble d'apprentissage et ajusté un modèle de classification avec Z comme variable cible) . Le fait d'ajuster une régression de Y sur X en utilisant \ Pr [Z = \ text {impartial} \, | \, X, Y] comme poids de régression produit une estimation non biaisée de \ mathbf {E} [Y \, | \, X, Z = \ text {impartiale}] (ou, à défaut, une estimation moins biaisée que celle que nous obtiendrions sans utiliser de pondérations)? Cette méthode est-elle utilisée dans la pratique et a-t-elle un nom?
Clarification: l'objectif est d'adapter un modèle qui minimise l'erreur quadratique moyenne sur des données invisibles (données de test) où . Le prédicteur optimal pour cet objectif est , c'est donc la fonction que nous essayons d'estimer. Les méthodes permettant de résoudre ce problème doivent être classées en fonction de leur efficacité à atteindre cet objectif.
Petit exemple en R avec df$y_is_unbiased
le rôle de et df$y_observed
le rôle de :
library(ggplot2)
library(randomForest)
set.seed(12345)
get_df <- function(n_obs, constant, beta, sd_epsilon, mismeasurement) {
df <- data.frame(x1=rnorm(n_obs), x2=rnorm(n_obs), epsilon=rnorm(n_obs, sd=sd_epsilon))
## Value of Y if measured correctly
df$y_unbiased <- constant + as.matrix(df[c("x1", "x2")]) %*% beta + df$epsilon
## Value of Y if measured incorrectly
df$y_biased <- df$y_unbiased + sample(mismeasurement, size=n_obs, replace=TRUE)
## Y is equally likely to be measured correctly or incorrectly
df$y_is_unbiased<- sample(c(TRUE, FALSE), size=n_obs, replace=TRUE)
df$y_observed <- ifelse(df$y_is_unbiased, df$y_unbiased, df$y_biased)
return(df)
}
## True coefficients
constant <- 5
beta <- c(1, 5)
df <- get_df(n_obs=2000, constant=constant, beta=beta, sd_epsilon=1.0, mismeasurement=c(-10.0, 5.0))
ggplot(df, aes(x=x1, y=y_observed, color=y_is_unbiased)) + geom_point() + scale_color_manual(values=c("#ff7f00", "#377eb8"))
## For facet_wrap title
df$string_y_is_unbiased <- paste0("y_is_unbiased: ", df$y_is_unbiased)
## Notice that Pr[Y | Z = biased] differs from Pr[Y | Z = unbiased]
ggplot(df, aes(x=y_observed)) + geom_histogram(color="black", fill="grey", binwidth=0.5) + facet_wrap(~ string_y_is_unbiased, ncol=1)
## Recover true constant and beta (plus noise) when using y_unbiased
summary(lm(y_unbiased ~ x1 + x2, data=df))
## Biased estimates when using y_biased (constant is biased downward)
summary(lm(y_biased ~ x1 + x2, data=df))
## Also get biased estimates when using y_observed (constant is biased downward)
summary(lm(y_observed ~ x1 + x2, data=df))
## Now image that we "rate" subset of the data (manually check/research whether y was measured with or without bias)
n_rated <- 1000
df_rated <- df[1:n_rated, ]
## Use a factor so that randomForest does classification instead of regression
df_rated$y_is_unbiased <- factor(df_rated$y_is_unbiased)
model_pr_unbiased <- randomForest(formula=y_is_unbiased ~ y_observed + x1 + x2, data=df_rated, mtry=2)
## Examine OOB confusion matrix (error rate < 5%)
print(model_pr_unbiased)
## Use the model to get Pr[Y is unbiased | X, observed Y] on unrated data
df_unrated <- df[(n_rated+1):nrow(df), ]
df_unrated$pr_unbiased <- as.vector(predict(model_pr_unbiased, newdata=df_unrated, type="prob")[, "TRUE"])
## Train a model on unrated data, using pr_unbiased as regression weights -- is this unbiased?
summary(lm(y_observed ~ x1 + x2, data=df_unrated, weights=df_unrated$pr_unbiased))
Dans cet exemple, le modèle est une forêt aléatoire avec . Si ce modèle était parfaitement précis, il générerait des pondérations de 1,0 où est sans biais, 0,0 où est biaisé, et la régression pondérée serait clairement sans biais. Que se passe-t-il lorsque le modèle de a une précision de test et des rappels qui ne sont pas parfaits (<100% de précision)? La régression pondérée est-elle garantie d'être moins biaisée qu'une régression non pondérée de sur ?formula=y_is_unbiased ~ y_observed + x1 + x2
Exemple un peu plus complexe dans lequel varie avec (contrairement à l'exemple plus simple que j'ai posté ci-dessus, où ):
library(ggplot2)
library(randomForest)
set.seed(12345)
logistic <- function(x) {
return(1 / (1 + exp(-x)))
}
pr_y_is_unbiased <- function(x1, x2) {
## This function returns Pr[ Z = unbiased | X ]
return(logistic(x1 + 2*x2))
}
get_df <- function(n_obs, constant, beta, sd_epsilon, mismeasurement) {
df <- data.frame(x1=rnorm(n_obs), x2=rnorm(n_obs), epsilon=rnorm(n_obs, sd=sd_epsilon))
## Value of Y if measured correctly
df$y_unbiased <- constant + as.matrix(df[c("x1", "x2")]) %*% beta + df$epsilon
## Value of Y if measured incorrectly
df$y_biased <- df$y_unbiased + sample(mismeasurement, size=n_obs, replace=TRUE)
## Note: in this example, Pr[ Z = biased | X ] varies with X
## In the first (simpler) example I posted, Pr[ Z = biased | X ] = 1/2 was constant with respect to X
df$y_is_unbiased <- runif(n_obs) < pr_y_is_unbiased(df$x1, df$x2)
df$y_observed <- ifelse(df$y_is_unbiased, df$y_unbiased, df$y_biased)
return(df)
}
## True coefficients
constant <- 5
beta <- c(1, 5)
df <- get_df(n_obs=2000, constant=constant, beta=beta, sd_epsilon=1.0, mismeasurement=c(-10.0, 5.0))
ggplot(df, aes(x=x1, y=y_observed, color=y_is_unbiased)) + geom_point() + scale_color_manual(values=c("#ff7f00", "#377eb8"))
## For facet_wrap title
df$string_y_is_unbiased <- paste0("y_is_unbiased: ", df$y_is_unbiased)
## Notice that Pr[Y | Z = biased] differs from Pr[Y | Z = unbiased]
ggplot(df, aes(x=y_observed)) + geom_histogram(color="black", fill="grey", binwidth=0.5) + facet_wrap(~ string_y_is_unbiased, ncol=1)
## Recover true constant and beta (plus noise) when using y_unbiased
summary(lm(y_unbiased ~ x1 + x2, data=df))
## Biased estimates when using y_biased (constant is biased downward)
summary(lm(y_biased ~ x1 + x2, data=df))
## Also get biased estimates when using y_observed
## Note: the constant is biased downward _and_ the coefficient on x2 is biased upward!
summary(lm(y_observed ~ x1 + x2, data=df))
## Now image that we "rate" subset of the data (manually check/research whether y was measured with or without bias)
n_rated <- 1000
df_rated <- df[1:n_rated, ]
## Use a factor so that randomForest does classification instead of regression
df_rated$y_is_unbiased <- factor(df_rated$y_is_unbiased)
model_pr_unbiased <- randomForest(formula=y_is_unbiased ~ y_observed + x1 + x2, data=df_rated, mtry=2)
## Examine OOB confusion matrix (error rate < 5%)
print(model_pr_unbiased)
## Use the model to get Pr[Y is unbiased | X, observed Y] on unrated data
df_unrated <- df[(n_rated+1):nrow(df), ]
df_unrated$pr_unbiased <- as.vector(predict(model_pr_unbiased, newdata=df_unrated, type="prob")[, "TRUE"])
## Train a model on unrated data, using pr_unbiased as regression weights -- is this unbiased? If not, is it _less_ biased than the unweighted model?
summary(lm(y_observed ~ x1 + x2, data=df_unrated, weights=df_unrated$pr_unbiased))
## What happens if we use pr_unbiased as a feature (aka predictor) in the regression, rather than a weight?
## In this case the weighted regression seems to do better, but neither is perfect
## Note: copied from shabbychef's answer
summary(lm(formula = y_observed ~ x1 + x2 + I(1 - pr_unbiased), data = df_unrated))
Dans cet exemple, la régression pondérée de sur semble moins biaisée que la régression non pondérée. Est-ce vrai en général? J'ai également essayé la suggestion de shabbychef (voir la réponse ci-dessous) sur cet exemple, et elle semble faire pire que la régression pondérée.
Pour ceux qui préfèrent Python à R, voici la deuxième simulation en Python:
import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LinearRegression
def logistic(x):
return 1 / (1 + np.exp(-x))
def pr_y_is_unbiased(x1, x2):
# This function returns Pr[ Z = unbiased | X ]
return logistic(x1 + 2*x2)
def get_df(n_obs, constant, beta, sd_epsilon, mismeasurement):
df = pd.DataFrame({
'x1': np.random.normal(size=n_obs),
'x2': np.random.normal(size=n_obs),
'epsilon': np.random.normal(size=n_obs, scale=sd_epsilon),
})
df['y_unbiased'] = constant + np.dot(np.array(df[['x1', 'x2']]), beta) + df['epsilon']
# Note: df['y_biased'].mean() will differ from df['y_unbiased'].mean() if the mismeasurements have a nonzero mean
df['y_biased'] = df['y_unbiased'] + np.random.choice(mismeasurement, size=n_obs)
df['y_is_unbiased'] = np.random.uniform(size=n_obs) < pr_y_is_unbiased(df['x1'], df['x2'])
df['y_observed'] = df.apply(lambda row: row['y_unbiased'] if row['y_is_unbiased'] else row['y_biased'], axis=1)
return df
constant = 5
beta = np.array([1, 5])
print(f'true coefficients:\n constant = {constant}, beta = {beta}')
n_obs = 2000
# Note: the mean of the possible mismeasurements is nonzero (this is the source of the bias)
df = get_df(n_obs=n_obs, constant=constant, beta=beta, sd_epsilon=1.0, mismeasurement=[-10.0, 5.0])
lr = LinearRegression()
lr.fit(X=df[['x1', 'x2']], y=df['y_observed'])
print(f'estimates from unweighted regression of Y on X ({df.shape[0]} obs):\n constant = {lr.intercept_}, beta = {lr.coef_}')
# Note: pretend that we only observe y_is_unbiased on a "rated" subset of the data
n_rated = n_obs // 2
df_rated = df.iloc[:n_rated].copy()
df_unrated = df.iloc[n_rated:].copy()
rf = RandomForestClassifier(n_estimators=500, max_features=2, oob_score=True)
rf_predictors = ['y_observed', 'x1', 'x2']
rf.fit(X=df_rated[rf_predictors], y=df_rated['y_is_unbiased'])
print(f'random forest classifier OOB accuracy (for predicting whether Y is unbiased): {rf.oob_score_}')
df_unrated['pr_y_is_unbiased'] = rf.predict_proba(df_unrated[rf_predictors])[:, 1]
lr.fit(X=df_unrated[['x1', 'x2']], y=df_unrated['y_observed'], sample_weight=df_unrated['pr_y_is_unbiased'])
print(f'estimates from weighted regression of Y on X ({df_unrated.shape[0]} obs):\n constant = {lr.intercept_}, beta = {lr.coef_}')
Réponses:
J'utiliserais la «probabilité de biais» comme variable muette dans la régression; cela peut éventuellement «éliminer» le biais présent dans le cas biaisé. En utilisant votre exemple, (mais en appelant
set.seed(1234)
avant l'appel àget_df
), j'ai essayéet a obtenu:
Le coefficient du terme
1-pr_unbiased
doit être la taille du biais.la source
Il s'agit d'un problème de variable omise où vous avez une variable indicatriceZ qui n'est pas observé, mais qui a une relation avec la variable de réponse. Étant donné que le «biais» est une propriété d'un estimateur, et non une variable de régression, je vais reformuler votre question comme celle où vous voulez trouver la vraie fonction de régression conditionnelle àZ=0 en utilisant des données de régression qui n'incluent pas cette variable, et un ensemble distinct de données d'entraînement de régression qui est utilisé pour estimer les probabilités p0(x,y)≡P(Z=0|X=x,Y=y) .
LaisserpOui| X dénoter la densité conditionnelle de la variable de réponse dans le problème de régression avec la variable de réponse Oui et variable explicative X (mais à l'exclusion Z ). A partir des règles de probabilité conditionnelle, la distribution cible des intérêts peut s'écrire:
On voit donc qu'il suffit de pouvoir estimer la fonction de régressionpOui| X dans le modèle de régression avec Z omis, et également estimer la fonction de probabilité p0 que vous avez comme estimateur distinct de vos données d'entraînement. Les premiers peuvent être estimés en utilisant l'estimation OLS sans imposer de pondération. La "pondération" intervient après estimation de cette fonction, par substitution dans l'équation ci-dessus.
Nous pouvons voir qu’il n’est pas nécessaire (ou souhaitable) d’utiliser des poids dans la régression deOui sur X , car il suffit d'estimer la densité conditionnelle pOui| X sans considération de Z . L'estimation OLS des coefficients de cette régression donne un estimateurp^Oui| X , et puisque vous avez également un estimateur distinct p^0 vous avez alors:
Une fois que vous avez substitué ces estimateurs, il ne reste plus qu'à essayer de déterminer la constante de mise à l'échelle qui donne une fonction de densité appropriée. Cela peut être fait par une gamme de méthodes d'intégration numérique (par exemple, la règle de Simpson, la quadrature, Metropolis-Hastings, etc.).
la source
Votre idée ne donnera pas d'estimation impartiale, sauf si vous pouvez toujours être sûr à 100% si elle est biaisée ou non. Dès qu'un exemple biaisé peut faire partie de votre ensemble d'entraînement avec une probabilité non nulle, il y aura un biais, car vous n'avez rien pour annuler ce biais. En pratique, votre biais sera simplement multiplié par un facteurα < 1 , où α est la probabilité qu'un exemple biaisé soit détecté comme tel.
En supposant que vous disposez de suffisamment de données, une meilleure approche consiste à calculerP(Z= b i a s ed|X,Y) pour chaque échantillon, puis supprimez tous les échantillons de l'ensemble d'apprentissage lorsque cette probabilité dépasse un certain seuil. Par exemple, s'il vous est possible de former votre ensemble de données sur les échantillons pour lesquelsP( Z= b i a s e d| X, Y) < 0,01 et votre jeu de données diminue de N biaisé et M impartial à n biaisé et m des exemples impartiaux, et le biais se multipliera par un facteur F=n ( N+ M)N( n + m ) . Depuis généralementnN sera bien inférieur à mM , F sera beaucoup plus petit que 1 , résultant en une amélioration significative.
Notez que les deux techniques peuvent être combinées: lignes avecp = P( Z= b i a s e d| X, Y) > β sortir (pour un choix de β , au-dessus j'ai utilisé β= 0,01 ), et les rangées qui restent obtiennent un poids ( 1 -pβ)2 , cela devrait vous donner le meilleur des deux mondes.
la source