Condividi tramite



Marzo 2017

Volume 32 Numero 3

Il presente articolo è stato tradotto automaticamente.

Esecuzione di test - Test chi-quadrato per la bontà dell'adattamento con C#

Da James McCaffrey

James McCaffreyUn adeguatezza del chi quadrato (detta anche chi quadrato) di test appropriato è una tecnica statistica comune che viene utilizzata per determinare se i dati di conteggio osservati corrispondano ai dati di conteggio previsto. Ad esempio, si supponga di che avere tre sistemi di server Web progettati per gestire il 50%, il 30% e il 20% del traffico, rispettivamente. Se si osserva 1.000 richieste HTTP, è necessario che venga visualizzato 500 richieste gestite dal primo server, 300 richieste gestite dal secondo server e 200 richieste gestite dal terzo server.

Si supponga, tuttavia che l'effettivi osservati i conteggi vengono (480, 290, 230). Decidere che le differenze tra conteggi osservati e previsti sono semplicemente a causa della casualità o si conclude statistica prove che i server Web non sono la gestione del traffico come previsto? Questo è un esempio del tipo di problema che può indirizzare un adeguatezza del chi quadrato del test appropriato.

Un buon metodo per vedere futuro in questo articolo è di ottenere un quadro il programma demo in figura 1. Il programma demo analizza una rotellina roulette americano. Si tratta di un adeguatezza del chi quadrato standard di esempio appropriato. Una rotellina American roulette include 38 slot, in cui sono rossi 18, 18 sono nero e 2 sono di colore verde. Pertanto, se il ruotare la rotellina 380 tempi e la rotellina è notevole nel senso che ogni slot è ugualmente probabile, si prevede vedere 180 rossi e 180 neri 20 verdi.

Vantaggi del chi quadrato di Demo appropriato
Figura 1 adeguatezza del chi quadrato di Demo appropriato

Ma supponiamo si osservati conteggi (192, 163, 25), alcuni ulteriori rossi e verdi del previsto e neri meno del previsto. Il programma demo utilizza i conteggi osservati e previsti, calcola una statistica del chi quadrato di da 3,66. Questo valore è una misura di diversi i conteggi osservati e previsti sono, in cui i valori superiori indicano differenza maggiore.

La demo Usa quindi la statistica del chi quadrata calcolata per calcolare un valore p ("valore di probabilità") di 0.1608. Questo valore corrisponde alla probabilità approssimativa che si vedrà un valore calcolato del chi quadrato di 3,66 o successiva, se in realtà la rotellina roulette è notevole. In altre parole, è il valore di p più piccoli, più è probabile che la rotellina non è corretto. In questo caso, il valore di p di 0.1608 è senza risultato. La probabilità che la rotellina è lecita è 0.1608, pertanto la probabilità che la rotellina non corretto è 1 - 0.1608 = 0.8392 è elevato, ma non è determinante.

In questo articolo si presuppone che si dispone di intermedio o versioni successive delle competenze di programmazione, ma non che si ha alcuna nozione del chi quadrato adeguatezza del test appropriato. Il programma demo è codificato tramite c#, ma è non necessario alcun problema di refactoring del codice in un altro linguaggio, ad esempio JavaScript o Python. Tutto il codice demo viene presentato in questo articolo ed è anche disponibile nel download associato.

La struttura del programma Demo

La struttura generale del programma demo, con poche modifiche minori per risparmiare spazio, viene presentata in figura 2. Per semplicità utilizzato uno stile di metodo statico anziché uno stile di programmazione orientata agli oggetti. Il metodo Main contiene tutta la logica di controllo. Il programma demo non è abbastanza complesso come potrebbe sembrare innanzitutto poiché la maggior parte dei metodi di nove sono brevi helper.

Figura 2 struttura del programma Demo del chi quadrato

using System;
namespace ChiSquaredUsingCSharp
{
  class ChiSquaredProgram
  {
    static void Main(string[] args)
    {
      Console.WriteLine("Begin demo \n");
      // 1. Calculate chi-squared stat.
      // 2. Use chi-squared to calculate p-value.
      Console.WriteLine("End demo");
      Console.ReadLine();
    }
    public static void ShowVector(int[] v) { . . }
    public static void ShowVector(double[] v,
      int dec) { . . }
    public static double ChiFromFreqs(int[] observed,
      double[] expected) { . . }
    public static double ChiFromProbs(int[] observed,
      double[] probs) { . . }
    public static double[] ExpectedFromProbs(
      double[] probs, int N) { . . }
    public static double ChiSquarePval(double x,
      int df) { . . }
    private static double Exp(double x) { . . }
    public static double Gauss(double z) { . . }
  } // Program
} // ns

Per creare il programma demo, avviato Visual Studio e creato un nuovo programma dell'applicazione di console in c# e denominato ChiSquaredUsingCSharp. Ho utilizzato Visual Studio 2015, ma il programma demo senza dipendenze significativi .NET in modo funzionerà qualsiasi versione recente di Visual Studio.

Dopo che il codice del modello caricato nella finestra dell'editor, pulsante destro del mouse sul file Program.cs nella finestra Esplora soluzioni e rinominato il file in ChiSquaredProgram.cs, quindi Visual Studio rinominare automaticamente classe Program per me è consentito. Nella parte superiore del codice generati da un modello, eliminato tutto inutili istruzioni using, lasciando solo quella che fa riferimento lo spazio dei nomi principale di sistema.

Imposta il metodo Main i conteggi del selettore roulette osservati nel modo seguente:

Console.WriteLine("Is roulette wheel fair");
Console.WriteLine("Wheel was spun 380 times");
int[] observed = new int[] { 192, 163, 25 };  // 380
Console.WriteLine("Observed counts red, black, green:");
ShowVector(observed);

Apportate questi conteggi osservati poiché offrono un esempio rappresentativo. Viene definito il metodo di supporto ShowVector che visualizza una matrice di interi:

public static void ShowVector(int[] v)  {
  for (int I = 0; i < v.Length; ++i)
    Console.Write(v[i] +“" “");
  Console.WriteLine“"\”");
}

Successivamente, anziché impostare direttamente i conteggi previsti, è necessario configurare indirettamente simile al seguente:

double[] probs = new double[] {
  18.0/38, 18.0/38, 2.0/38 };
Console.WriteLine("Probabilities if fair:");
ShowVector(probs, 4);
double[] expected = ExpectedFromProbs(probs, 380);
Console.WriteLine("Expected counts if fair:");
ShowVector(expected, 1);

Le probabilità di rosso, bianco e verde sono 18/38, 18/38 e 2/38, come illustrato in precedenza. Il metodo di supporto ExpectedFromProbs accetta una matrice di probabilità e il numero totale e restituisce una matrice di conteggi previsti. Avrei potuto impostare direttamente i conteggi previsti per 380 rotazioni del selettore roulette simile al seguente:

double[] expected = new double[] { 180.0, 180.0, 20.0 };

Viene definito il metodo helper conteggio previsto:

public static double[] ExpectedFromProbs(double[] probs,
  int N)
{
  double[] expected = new double[probs.Length];
  for (int i = 0; i < probs.Length; ++i)
    expected[i] = probs[i] * N;
  return expected;
}

E viene definito il metodo di overload ShowVector per una matrice di tipo double:

public static void ShowVector(double[] v, int dec) {
  for (int i = 0; i < v.Length; ++i)
    Console.Write(v[i].ToString("F" + dec) + "  ");
  Console.WriteLine("\n");
}

Il programma demo continua calcolando la statistica del chi quadrata:

double chi = ChiFromProbs(observed, probs); 
Console.WriteLine("Calculated chi-squared = " +
  chi.ToString("F2"));  // 3.66

Metodo ChiFromProbs utilizza una firma che accetta una matrice di interi di conteggi osservati e una matrice double di probabilità previsto, principalmente perché è la firma utilizzata dalla funzione chisq.test linguaggio R equivalente. Ad esempio, una shell interattiva di R è possibile eseguire la demo come segue:

> obs <- c(192, 163, 25)
> probs <- c(18/38, 18/38, 2/38)
> chisq.test(x=obs, p=probs)
X-squared = 3.6556, df = 2, p-value = 0.1608

Si noti che la statistica del chi quadrata calcolata (da 3,66) e p-valore (0.1608) ottenuto usando R sono gli stessi valori calcolata per il programma demo. La demo è terminata con statistica del chi quadrato calcolata per calcolare il valore di p:

int df = observed.Length - 1;
double pval = ChiSquarePval(chi, 2);
Console.WriteLine("The pval with df of " + df +
  " = " + pval.ToString("F4") );
Console.WriteLine("Pval is probability, if wheel fair,");
Console.WriteLine("you'd see a chi-squared as calculated");
Console.WriteLine("End demo");
Console.ReadLine();

Df variabile è l'acronimo di gradi di libertà, spiegherò in breve.

Comprendere la statistica del chi quadrata

Se si dispone di una matrice di conteggi osservati e una matrice di conteggi previsti, è possibile calcolare una metrica denominata statistica del chi quadrato, una misura della modalità diverse di conteggi osservati e previsti. I valori superiori indicano differenza maggiore.

La statistica del chi quadrata viene definita come la somma dei quadrati delle differenze tra osservati e previsti diviso previsto:

chi-squared = sum( (obs[i] - exp[i])^2 / exp[i] )

L'idea di risposta è chiarita da un esempio. Si supponga, come la demo, i conteggi osservati per 380 rotazioni di una ruota roulette sono (192, 163, 25) e i conteggi previsto se la rotellina è lecita (180, 180, 20). La statistica del chi quadrata calcolata è:

chi-squared = (192 - 180)^2 / 180 +
              (163 - 180)^2 / 180 +
              (25 - 20)^2   / 20
            = (144 / 180) + (289 / 180) + (25 / 20)
            = 0.8000 + 1.6056 + 1.2500
            = 3.6556

La demo implementa questa funzione come:

public static double ChiFromFreqs(int[] observed,
  double[] expected)
{
  double sum = 0.0;
  for (int i = 0; i < observed.Length; ++i) {
    sum += ((observed[i] - expected[i]) *
      (observed[i] - expected[i])) / expected[i];
  }
  return sum;
}

Non esiste alcun controllo degli errori in questo caso, per semplicità, ma in un sistema di produzione si desidera assicurarsi che le matrici osservati e previsti abbiano la stessa lunghezza e così via. Il programma demo ha anche un metodo per calcolare una statistica del chi quadrato da una matrice dei conteggi osservati e una matrice di probabilità previsto:

public static double ChiFromProbs(int[] observed,
  double[] probs)
{
  int n = observed.Length;
  int sumObs = 0;
  for (int i = 0; i < n; ++i)
    sumObs += observed[i];
  double[] expected = ExpectedFromProbs(probs, sumObs);
  return ChiFromFreqs(observed, expected);
}

Ricapitolando, la definizione di matematica della statistica del chi quadrato utilizza una matrice di conteggi osservati e una matrice di conteggi previsti. È inoltre utile per il calcolo del chi quadrato da una matrice dei conteggi osservati e una matrice di probabilità previsto. Per eseguire questo calcolo, è utile disporre di un metodo helper che calcola conteggi previsti dalla probabilità previsto.

Informazioni sulla distribuzione del chi quadrato

Se si dispone di un valore calcolato statistica del chi quadrato, è possibile utilizzarlo per calcolare la probabilità (valore p) per ottenere il valore del chi quadrato. Questo concetto è la risposta è chiarito visivamente. Esaminiamo il grafico in figura 3, che mostra la distribuzione del chi quadrato per il problema demo. L'area totale in qualsiasi distribuzione del chi quadrato è 1.0. Il valore di p è l'area sotto il grafico dalla statistica del chi quadrato calcolata a + infinity.

Distribuzione del chi quadrato per df = 2
Figura 3. la distribuzione del chi quadrato per df = 2

Questo concetto è molto complesso. E, Sfortunatamente, il calcolo dell'area in una distribuzione del chi quadrato è molto difficile. Per fortuna, gli algoritmi numerici per stimare l'area in una distribuzione del chi quadrato sono stati sviluppati per il 1960s e 1970s e sono ancora utilizzati oggi.

Sono disponibili molti complicazione è il fatto che non vi è solo una distribuzione del chi quadrato. In breve, per adeguatezza del test appropriato, è disponibile un valore denominato i gradi di libertà, df abbreviato. Il valore di gradi di libertà per un adeguatezza del test più appropriato è semplicemente 1 meno il numero di bucket count. Per la demo, sono disponibili tre bucket count (rosso, bianco o verde) quindi i gradi di libertà è 3-1 = 2.

Esiste una distribuzione del chi quadrato diversa per ogni valore di gradi di libertà. Il grafico in figura 3 Mostra la distribuzione del chi quadrato per df = 2. Osservare i valori del chi quadrato l'asse orizzontale compreso tra 0,0 (più piccolo possibile calcolata statistica del chi quadrato, quando tutti osservati conteggi uguali i conteggi previsti corrispondenti), eseguire + infinity (vi è che alcun limite al numero totale di osservati e previsti diverse non può essere).

Esistono diversi algoritmi sofisticati che è possono calcolare un valore di p / area nel grafico della distribuzione del chi quadrato. Il programma demo utilizza cosiddetta ACM algoritmo 299, che viene implementata come metodo ChiSquarePval. L'algoritmo utilizza a sua volta un altro algoritmo detto 209 ACM, che viene implementata come metodo di Gauss. Questi algoritmi sono elementi di base dell'elaborazione numerico e vengono presentati figura 4. Anche un breve riepilogo il codice deve convincere l'utente è alcuni calcoli matematici molto gravi succedendo, ma fortunatamente è possibile considerare i metodi che implementano gli algoritmi come neri perché non sarà mai necessario modificare il codice.

Figura 4 metodi ChiSquarePval e Gauss

public static double ChiSquarePval(double x, int df)
{
  // x = a computed chi-square value.
  // df = degrees of freedom.
  // output = prob. x value occurred by chance.
  // ACM 299.
  if (x <= 0.0 || df < 1)
    throw new Exception("Bad arg in ChiSquarePval()");
  double a = 0.0; // 299 variable names
  double y = 0.0;
  double s = 0.0;
  double z = 0.0;
  double ee = 0.0; // change from e
  double c;
  bool even; // Is df even?
  a = 0.5 * x;
  if (df % 2 == 0) even = true; else even = false;
  if (df > 1) y = Exp(-a); // ACM update remark (4)
  if (even == true) s = y;
  else s = 2.0 * Gauss(-Math.Sqrt(x));
  if (df > 2)
  {
    x = 0.5 * (df - 1.0);
    if (even == true) z = 1.0; else z = 0.5;
    if (a > 40.0) // ACM remark (5)
    {
      if (even == true) ee = 0.0;
      else ee = 0.5723649429247000870717135;
      c = Math.Log(a); // log base e
      while (z <= x) {
        ee = Math.Log(z) + ee;
        s = s + Exp(c * z - a - ee); // ACM update remark (6)
        z = z + 1.0;
      }
      return s;
    } // a > 40.0
    else
    {
      if (even == true) ee = 1.0;
      else
        ee = 0.5641895835477562869480795 / Math.Sqrt(a);
      c = 0.0;
      while (z <= x) {
        ee = ee * (a / z); // ACM update remark (7)
        c = c + ee;
        z = z + 1.0;
      }
      return c * y + s;
    }
  } // df > 2
  else {
    return s;
  }
} // ChiSquarePval()
private static double Exp(double x)
{
  if (x < -40.0) // ACM update remark (8)
    return 0.0;
  else
    return Math.Exp(x);
}
public static double Gauss(double z)
{
  // input = z-value (-inf to +inf)
  // output = p under Normal curve from -inf to z
  // ACM Algorithm #209
  double y; // 209 scratch variable
  double p; // result. called ‘z’ in 209
  double w; // 209 scratch variable
  if (z == 0.0)
    p = 0.0;
  else
  {
    y = Math.Abs(z) / 2;
    if (y >= 3.0)
    {
      p = 1.0;
    }
    else if (y < 1.0)
    {
      w = y * y;
      p = ((((((((0.000124818987 * w
        - 0.001075204047) * w + 0.005198775019) * w
        - 0.019198292004) * w + 0.059054035642) * w
        - 0.151968751364) * w + 0.319152932694) * w
        - 0.531923007300) * w + 0.797884560593) * y
        * 2.0;
    }
    else
    {
      y = y - 2.0;
      p = (((((((((((((-0.000045255659 * y
        + 0.000152529290) * y - 0.000019538132) * y
        - 0.000676904986) * y + 0.001390604284) * y
        - 0.000794620820) * y - 0.002034254874) * y
       + 0.006549791214) * y - 0.010557625006) * y
       + 0.011630447319) * y - 0.009279453341) * y
       + 0.005353579108) * y - 0.002141268741) * y
       + 0.000535310849) * y + 0.999936657524;
    }
  }
  if (z > 0.0)
    return (p + 1.0) / 2;
  else
    return (1.0 - p) / 2;
} // Gauss()

Conclusioni

Non è probabile che sarà necessario analizzare i dati rotellina roulette, ma una volta compreso il tipo di problema scenario in cui è applicabile un adeguatezza del chi quadrato del test appropriato, è possibile molti utilizzi pratici per il test. Sono disponibili numerosi strumenti che possono eseguire un adeguatezza del chi quadrato del test appropriato, tra cui Excel e il linguaggio R, ma questi strumenti possono essere difficili o impossibili da integrare in un sistema software. In tali situazioni è possibile utilizzare il codice presentato in questo articolo.

Esistono diversi altri tipi di test statistici che utilizzano la distribuzione del chi quadrato. Il test presentato in questo articolo viene talvolta denominato test del chi quadrato di Pearson per distinguerlo da altri test chi quadrato. Inoltre, esistono diversi altri test statistici che può confrontare i conteggi osservati e previsti, anche se chi è il più comune.

È importante ricordare che l'adeguatezza del chi quadrato di test appropriato, come la maggior parte dei test statistici, probabilistico, pertanto è necessario interpretare i risultati ripagati. Anche se si ottiene un valore di p molto piccolo, è preferibile, diventando ad esempio, "p-valore ridotto di 0.0085 suggerisce che la differenza tra conteggi osservati e previsti è improbabile che si sono verificati casualmente", invece, "il valore di p small indica i conteggi osservati non è stato hanno casualmente."


Ripristino di emergenza. James McCaffreylavora per Microsoft Research a Redmond, Washington.  Ha lavorato di diversi prodotti Microsoft, inclusi Internet Explorer e Bing. Dr. È possibile contattarlo McCaffrey jammc@microsoft.com.

Grazie per i seguenti esperti tecnici Microsoft che ha esaminato in questo articolo: Kirk Olynyk e Chris Lee