ランダムな予測子を使用したロジスティック回帰から均一なp値分布が得られないのはなぜですか?


7

以下のコードは、周囲に二項ノイズを含む一連の「信号」確率で構成されるテストデータのセットを生成します。次に、コードは5000組の乱数を「説明的な」系列として使用し、それぞれについてロジスティック回帰のp値を計算します。

ランダムな説明シリーズは、57%のケースで5%レベルで統計的に有意であることがわかりました。以下の投稿の長い部分を読んだ場合、これはデータに強い信号が存在することに起因します。

だから、ここに主な質問があります:データに強い信号が含まれているときに説明変数の統計的有意性を評価するときに、どの検定を使用すべきですか?単純なp値は誤解を招くようです。

問題の詳細な説明は次のとおりです。

予測子が実際には単なる乱数のセットであるときに、ロジスティック回帰のp値を取得した結果に戸惑っています。私の最初の考えは、この場合、p値の分布はフラットでなければならないということでした。以下のRコードは、実際には低いp値で大きなスパイクを示しています。これがコードです:

set.seed(541713)

lseries <-   50
nbinom  <-  100
ntrial  <- 5000
pavg    <- .1  # median probability
sd      <- 0 # data is pure noise
sd      <- 1 # data has a strong signal
orthogonalPredictor <- TRUE   # random predictor that is orthogonal to the true signal
orthogonalPredictor <- FALSE  # completely random predictor

qprobs  <- c(.05,.01) # find the true quantiles for these p-values

yactual <- sd * rnorm(lseries)  # random signal
pactual <- 1 / (1 + exp(-(yactual + log(pavg / (1-pavg)))))
heads   <- rbinom(lseries, nbinom, pactual)
  ## test data, binomial noise around pactual, the probability "signal"
flips   <- cbind(heads, nbinom - heads)
# summary(glm(flips ~ yactual, family = "binomial"))

pval <- numeric(ntrial)

for (i in 1:ntrial){
  yrandom <- rnorm(lseries)
  if (orthogonalPredictor){ yrandom <- residuals(lm(yrandom ~ yactual)) }
  s       <- summary(glm(flips ~ yrandom, family="binomial"))
  pval[i] <- s$coefficients[2,4]
}

hist(pval, breaks=100)
print(quantile(pval, probs=c(.01,.05)))
actualCL <- sapply(qprobs, function(c){ sum(pval <= c) / length(pval) })
print(data.frame(nominalCL=qprobs, actualCL))

コードは、強い信号の周囲の二項ノイズからなるテストデータを生成し、ループ内で一連の乱数に対してデータのロジスティック回帰を適合させ、ランダムな予測子のp値を累積します。結果は、p値のヒストグラム、1%と5%の信頼レベルの実際のp値分位数、およびこれらの信頼レベルに対応する実際の偽陽性率として表示されます。

予期しない結果の1つの理由は、ランダムな予測子が一般に真の信号と何らかの相関関係を持ち、これが主に結果を説明しているためだと思います。ただし、に設定orthogonalPredictorした場合TRUE、ランダムな予測子と実際の信号の相関はゼロになりますが、問題は低減されたレベルで存在します。それについての私の最高の説明は、真の信号がフィッティングされるモデルのどこにもないので、モデルが誤って指定され、p値がとにかく疑わしいということです。しかし、これはキャッチ22です。データに正確に適合する予測子のセットを利用できる人はいますか?だからここにいくつかの追加の質問があります:

  1. ロジスティック回帰の正確な帰無仮説は何ですか?それは、データが一定レベルの周りの純粋な2項ノイズであるということですか(つまり、真の信号はありません)。コードでsdを0に設定した場合、信号はなく、ヒストグラムは平坦に見えます。

  2. コードの暗黙の帰無仮説は、予測子が乱数のセット以上の説明力を持たないというものです。これは、コードによって表示されるp値の経験的な5%分位数を使用してテストされます。この仮説をテストするためのより良い方法、または数値的にそれほど集中的ではない少なくとも1つの方法はありますか?

- - - 追加情報

このコードは次の問題を模倣します。過去のデフォルトレートは、景気循環によって駆動される時間(信号)の間に大きな変動を示します。特定の時点での実際のデフォルトカウントは、これらのデフォルト確率を中心とした二項式です。私はp値が疑わしくなったときに、信号の説明変数を見つけようとしていました。このテストでは、シグナルは経済サイクルを示すのではなく、時間の経過に伴ってランダムに並べられますが、ロジスティック回帰では問題になりません。そのため、過度の分散はありません。信号は実際には信号であることを意味します。


4
これは興味深いですが、コードが50%であるため、それほど注目されることはないと思います。説明、式などを記述したコードを挿入できますか?これはスタックオーバーフローではなく、誰もあなたのコードをデバッグしません。また、4つの質問のうち少なくとも2つは必ず削除してください。ここでのポリシーは、投稿に関する1つの質問です。2つは許容できるかもしれません。4つは、答えが得られないことを確認するようなものです。
DeltaIV

1
おかげで、私は以前にクロス検証を使用したことがありません。いくつか編集します。
Ron Hylton、2017

回答:


12

ここにはいくつかの問題があります。特に、標準的なロジスティック回帰をどのようにシミュレートするかについて、いくつかの混乱があるようです。簡単に言うと、を追加しませんnoise around... the probability "signal"。これを実行した方法の結果として、結果として得られる「二項」(-esque)データには非常に多くのばらつきがあり、必要以上に大きくなります。データセットの確率は次のとおりです。

plot(flips[,1]/rowSums(flips))

ここに画像の説明を入力してください

これらの.4+の観測結果がどちらか一方に終わる場合、それらは「外れ値」として機能し(実際には外れ値ではありません)、これらのデータの事実を考慮に入れないモデルでタイプ1エラーを引き起こします本当に二項式ではありません。これは、モデルが過剰分散を検出して説明できるようにするために、単純なハックを使用するバージョンです。

set.seed(5082)
pval <- numeric(ntrial)
for (i in 1:ntrial){
  yrandom <- rnorm(lseries)
  s       <- summary(glm(flips ~ yrandom, family="quasibinomial"))  # changed family
  pval[i] <- s$coefficients[2,4]
}

hist(pval, breaks=100)
print(quantile(pval, probs=c(.01,.05)))
#          1%          5% 
# 0.006924617 0.046977246 
actualCL <- sapply(qprobs, function(c){ sum(pval <= c) / length(pval) })
print(data.frame(nominalCL=qprobs, actualCL))
#   nominalCL actualCL
# 1      0.05   0.0536
# 2      0.01   0.0128

ここに画像の説明を入力してください

これは、最後の反復からのモデルの要約です。分散は次のように推定されることに注意してください12× 真の二項式の場合:

s
# Call:
# glm(formula = flips ~ yrandom, family = "quasibinomial")
# 
# Deviance Residuals: 
#    Min      1Q  Median      3Q     Max  
# -5.167  -2.925  -1.111   1.101   8.110  
# 
# Coefficients:
#             Estimate Std. Error t value Pr(>|t|)    
# (Intercept) -1.96910    0.14942 -13.178   <2e-16 ***
# yrandom     -0.02736    0.14587  -0.188    0.852    
# ---
# Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
# 
# (Dispersion parameter for quasibinomial family taken to be 11.97867)
# 
#     Null deviance: 532.38  on 49  degrees of freedom
# Residual deviance: 531.96  on 48  degrees of freedom
# AIC: NA
# 
# Number of Fisher Scoring iterations: 5

これは別のバージョンです。私はあなたが行っているのと同じモデルに適合しますが、信号の周りにノイズを追加せずにデータを生成します。(簡潔にするため、それ以外は同じコードは省略されていることに注意してください。)

set.seed(541713)
...
pactual <- 1 / (1 + exp(-(log(pavg / (1-pavg)))))  # deleted yactual
...
for (i in 1:ntrial){
  yrandom <- rnorm(lseries)
  if (orthogonalPredictor){ yrandom <- residuals(lm(yrandom ~ yactual)) }
  s       <- summary(glm(flips ~ yrandom, family="binomial"))
  pval[i] <- s$coefficients[2,4]
}

hist(pval, breaks=100)
print(quantile(pval, probs=c(.01,.05)))
#         1%         5% 
# 0.01993318 0.07027473 
actualCL <- sapply(qprobs, function(c){ sum(pval <= c) / length(pval) })
print(data.frame(nominalCL=qprobs, actualCL))
#   nominalCL actualCL
# 1      0.05   0.0372
# 2      0.01   0.0036

ここに画像の説明を入力してください


コードが模倣している実際の問題の元の投稿の下部に説明を追加しました。信号は実際には信号であり、過分散ではありません。実際の問題は、信号周辺の二項ノイズです。
Ron Hylton 2017

2
@RonHylton、これは誤解です。あなたのデータは本当に二項分布に比べて過剰に分散しています。どういうわけかそれを説明する必要があります(いくつかの方法があります-準二項式を使用するのが最も簡単です)。明らかにそこにある過剰分散を説明する場合(これは、統計理論の観点からデータを生成する方法に当てはまり、経験的にも実証されています)、タイプ1のエラーインフレはなくなります。
ガン-モニカを復活

1
@RonHylton、あなたには治療効果がありません(そしてこのシミュレーションにはグループがありません-継続的な予測子のみyrandom)。それがこれらがタイプ1のエラーであり、あなたが正しく心配している理由です。条件付き応答分布には、2項式の場合よりもかなりばらつきがあります。それが過剰分散の定義です。より具体的には、条件付き分布は二項ではなくベータ二項です。
ガン-モニカの復活

1
FWIW、コード内のデータ生成メカニズムは、おそらくあなたが記述した状況と一致しませんfamily=quasibinomial。最も可能性が高いのは、過度の分散だけではなく、時間の経過に伴って相関しているエラーの可能性もあります。
gung-モニカの回復

1
@RonHylton、私はここで何を言うべきかわからない。コードはnullをシミュレートします。信号はありません。タイプ1のエラーインフレーションb / cがあり、過剰分散があり、モデルはそれを考慮していません。そうすると、タイプ1のエラーインフレは解消されます。コードが、ここまたは編集中の説明と一致しません。実際、あなたのコードはシミュレーションがセットアップされる通常の方法ではありません。説明やコードがGLMMとどのように関連しているかについてのあなたの考えには従いません。私が言えることは、あなたが過度に分散していることであり、「完全に通常の方法」で使用される「標準ロジスティック回帰」はそれを考慮していません。
ガン-モニカの復活

1

コードと実験的な目標との関係は混乱を招きます。あなたは直交予測またはSDの任意の選択のための重要な予測子を期待していますか?私はしません。

私の解釈によると、実験は私たちがテストしようとしているものと一致していないようです。ノイズが生成される場合、それは暗黙的に繰り返し(つまり、ランダムではなく)個々の観測に付加され、回帰に信号を提供します。

私が意図したものは次のとおりです:

lseries <-   50
nbinom  <-  100
ntrial  <- 5000
pavg    <- .1  # median probability

run_experiment <- function(sd = 0,
                           orthogonalPredictor = FALSE,
                           predictor_noise_sd = NA) {
  qprobs  <- c(.05,.01) # find the true quantiles for these p-values

  yactual <- sd * rnorm(lseries)  # random signal
  pactual <- 1 / (1 + exp(-(yactual + log(pavg / (1-pavg)))))
  heads   <- rbinom(lseries, nbinom, pactual)
  ## test data, binomial noise around pactual, the probability "signal"
  flips_expanded <- rbind(data.frame(flip_result = rep(rep(1, length(heads)), heads),
                               y_actual = rep(yactual, heads)),
                           data.frame(flip_result = rep(rep(0, length(heads)), nbinom-heads),
                                      y_actual = rep(yactual, nbinom-heads))
                               )
  summary(glm(flip_result ~ y_actual, flips_expanded, family = "binomial"))

  pval <- numeric(ntrial)

  for (i in 1:ntrial){
    flips_expanded$y <- rnorm(nrow(flips_expanded))
    if (orthogonalPredictor){ flips_expanded$y <- residuals(lm(y ~ y_actual, flips_expanded)) }
    if (!is.na(predictor_noise_sd)) {flips_expanded$y <- rnorm(nrow(flips_expanded), flips_expanded$y_actual, predictor_noise_sd)}
    s       <- summary(glm(flip_result ~ y, flips_expanded, family="binomial"))
    pval[i] <- s$coefficients[2,4]
  }

  hist(pval, breaks=100)
  print(quantile(pval, probs=c(.01,.05)))
  actualCL <- sapply(qprobs, function(c){ sum(pval <= c) / length(pval) })
  print(data.frame(nominalCL=qprobs, actualCL))
}

重要な変更は次のとおりです。

  • データフレームを圧縮形式ではなく観測ごとの形式に拡張する(flips_expanded)
  • 相関予測子を使って実験する

y_actualと予測子yの間に相関がない場合:

> run_experiment()
        1%         5% 
0.01077116 0.05045712 
  nominalCL actualCL
1      0.05   0.0496
2      0.01   0.0096

ここに画像の説明を入力してください

そして、かなり強い相関を作成します:

> run_experiment(1,FALSE,10)
          1%           5% 
0.0001252817 0.0019125482 
  nominalCL actualCL
1      0.05   0.3002
2      0.01   0.1286

ここに画像の説明を入力してください


2
これは正しくありません。問題は、行がグループ化されていることではありません。さらに、OPは、パラメーター設定のいくつかの組み合わせで機能することをすでに認識しています。sd =1orthogonalPredictor = FALSEX-変数(ので、(単純に)動作してはならないyrandom)、ランダム・発生しないY変数に関連しています。
ガン-モニカを復活

グループ化された行にノイズを追加する方法に問題がない場合、観測ごとにグループ化を解除してノイズを追加すると、均一なp値の分布が表示されるのはなぜですか?それがOPが実験しようとしていたことは私には思えない。
khol

1
グループ化されていないデータでは、過剰分散は検出できません。ただし、データのグループ化を解除した場合は、さまざまな観察結果が同じユニットからのものであることを何らかの方法で示す必要があります(患者-これらは実際のデータであると想定)。
gung-モニカの回復

コードが模倣している実際の問題の元の投稿の下部に説明を追加しました。これにより、実験の目標がより明確になると思います。
Ron Hylton 2017

2
あなたがシミュレートしようとしているものが見えるようになったので、これは正解ではありません。
khol
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.