März 2017

Band 32, Nummer 3

Dieser Artikel wurde maschinell übersetzt.

Test Run: Chi-Quadrat-Anpassungstest mithilfe von C#

Durch James McCaffrey

James McCaffreyEine Chi-Quadrat-(auch bezeichnet Chi-Quadrat) die Qualität der Übereinstimmung Test ist ein gängiges statistischen Verfahren, das verwendet wird, um festzustellen, ob beobachtet-Anzahl der erwarteten Anzahl Daten übereinstimmen. Angenommen Sie, Sie haben drei Web-Server-Computer entwickelt, um 50 Prozent, 30 Prozent und 20 Prozent des gesamten Netzwerkverkehrs zu behandeln. Wenn Sie 1.000 HTTP-Anforderungen beobachten, erwarten Sie 500 Anforderungen behandelt, die für den ersten Server, 300 Anforderungen, die durch den zweiten Server verarbeitet und 200 Anforderungen behandelt, indem der dritte Server finden Sie unter.

Aber angenommen, Ihre tatsächliche beobachtet werden Zahlen (480, 290, 230). Entscheiden Sie, dass die Unterschiede zwischen beobachteten und die erwartete Anzahl einfach aufgrund der Zufälligkeit, oder Sie, dass statistische Beweise dafür schließen, dass der Webserver Datenverkehr wie gewünscht verarbeitet werden nicht vorhanden ist? Dies ist ein Beispiel für die Art des Problems, das eine Chi-Quadrat-Eignung der Eignung Test behandeln kann.

Ich empfehle Ihnen, sich das Demoprogramm in Abbildung 1 anzusehen. Dort erfahren Sie, um was es bei diesem Artikel geht. Das Demoprogramm analysiert einer amerikanischen Handschrift Roulette Wheel. Dies ist eine standardmäßige Chi-Quadrat-Eignung der anpassen wird. Eine amerikanische Roulette Wheel ist 38 Steckplätze, wo 18 sind rot, 18 Schwarz, und 2 sind grün. Wenn Sie das Mausrad 380 Zeiten drehen und die Wheel gut, in dem Sinne ist, dass jeder Steckplatz gleichermaßen wahrscheinlich ist, erwarten Sie daher 20 Grün-, 180 Rot und Schwarz 180 finden Sie unter.

Chi-Quadrat-Eignung der Demo anpassen
Abbildung 1 Chi-Quadrat-Eignung der Demo anpassen

Angenommen, Sie beobachtet Anzahl (192, 163, 25) – ein paar weitere Rot und Grün-als erwartet, und weniger Schwarz als erwartet. Verwenden die beobachteten und die erwartete Anzahl, berechnet das Demoprogramm eine Chi-Quadrat-Statistik von 3,66. Dieser Wert ist ein Maß, wie die beobachtete und erwartete Werte unterscheiden, in denen größere Werte größer Unterschied angeben, an.

Die Demo verwendet dann die berechnete Chi-Quadrat-Statistik, um ein p-Wert ("Wahrscheinlichkeitswert") 0.1608 zu berechnen. Dieser Wert ist die ungefähre Wahrscheinlichkeit, dass Sie sehen würden berechnete Chi-Quadrat-Wert 3,66 oder höher, wenn tatsächlich die Roulette Wheel akzeptabel ist. Anders ausgedrückt, je kleiner der p-Wert ist, desto wahrscheinlicher das Rad wird nicht fair. Hier ist der p-Wert des 0.1608 nicht eindeutig. Die Wahrscheinlichkeit, dass das Rad akzeptabel ist ist 0.1608, also die Wahrscheinlichkeit, dass das Rad nicht fair ist 1 - 0.1608 = 0.8392 das Recht hoch, aber nicht entscheidend ist.

Dieser Artikel setzt fortgeschrittene oder höher Programmierkenntnisse verfügen jedoch nicht vorausgesetzt, dass Sie sich Chi-Quadrat-Eignung der geeignete Tests auskennen. Das Demoprogramm ist mit c# codiert, aber Sie haben keine Probleme beim Umgestalten des Codes in eine andere Sprache, z. B. JavaScript oder Python. Die Demo-Code wird in diesem Artikel vorgestellten und auch im begleitenden Download verfügbar ist.

Struktur des Demoprogramms

Die allgemeine Struktur des Demoprogramms mit ein paar kleinen Änderungen, um Platz zu sparen werden im Abbildung 2. Ich verwende eine statische Methode Stil statt auf einer objektorientierten Programmierung Formatvorlage aus Gründen der Einfachheit. Die Main-Methode hat die Steuerelementlogik. Das Demoprogramm ist nicht ganz so kompliziert, wie es zunächst den Anschein hat, da die meisten neun Methoden kurze Hilfsmethoden sind.

Abbildung 2: Struktur Chi-Quadrat-Demoprogramms

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

Um das Demoprogramm zu erstellen, starten Visual Studio ich und erstellt eine neue C#-Konsolenanwendungsprogramm und mit dem Namen ChiSquaredUsingCSharp. Ich verwendete Visual Studio 2015, aber das Demoprogramm hat keine nennenswerten .NET Abhängigkeiten, sodass jede aktuelle Version von Visual Studio funktionieren sollte.

Nach dem Laden des Vorlagencode in Editor-Fenster, ich mit der rechten Maustaste auf die Datei "Program.cs" im Fenster Projektmappen-Explorer die Datei in ChiSquaredProgram.cs umbenannt, und Visual Studio die für mich automatisch die Programmklasse umbenennen. Am Anfang der Vorlage generierte Code habe ich gelöscht unnötige using-Anweisungen, lassen nur die eine, die Namespace der obersten Ebene System verweist.

Die Main-Methode richtet die beobachteten zählt die Roulette Wheel wie folgt:

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);

Mir nur Zählwerte beobachteten da sie ein repräsentatives Beispiel geben. Hilfsmethode ShowVector, die ein Array von Ganzzahlen anzeigt wird wie folgt definiert:

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

Richten Sie nun anstelle der erwarteten Anzahl direkt festlegen, kann ich sie indirekt wie folgt:

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);

Die Wahrscheinlichkeit von Rot, Schwarz und grün sind 18/38, 18/38 und 2/38, wie bereits erläutert. Hilfsmethode ExpectedFromProbs akzeptiert ein Array von Wahrscheinlichkeiten und die Gesamtzahl und gibt ein Array von erwarteten Anzahl. Ich könnte direkt die erwarteten Werte für 380 dreht sich von der Roulette Wheel folgendermaßen eingerichtet:

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

Die erwartete Anzahl Hilfsmethode definiert ist:

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;
}

Und die überladene ShowVector-Methode für ein Array vom Typ double definiert ist:

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");
}

Das Demoprogramm wird fortgesetzt, indem der Chi-Quadrat-Statistik berechnen:

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

ChiFromProbs-Methode verwendet eine Signatur, die ein Ganzzahlarray der beobachteten und ein double-Array der erwarteten Wahrscheinlichkeiten akzeptiert, hauptsächlich, da die Signatur durch die entsprechende R Language chisq.test-Funktion ist. Z. B. in einer interaktiven R-Shell konnte, führen Sie die Demo wie folgt:

> 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

Beachten Sie die berechnete Chi-Quadrat-Statistik (3,66) und p-Wert (0.1608) mithilfe von R werden die gleichen Werte wie das Demoprogramm berechnet. Die Demo endet mit der berechnete Chi-Quadrat-Statistik den p-Wert zu berechnen:

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();

Variable df steht für Freiheitsgrade, die ich in Kürze eingehen werde.

Verstehen der Chi-Quadrat-Statistik

Wenn Sie ein Array von beobachteten und ein Array von erwarteten haben, können Sie eine Metrik Namens die Chi-Quadrat-Statistik berechnen, ein Maß für die verschiedenen beobachteten und erwarteten Anzahl. Größere Werte zeigen größer Unterschied.

Die Chi-Quadrat-Statistik wird definiert, wie durch die Summe der quadrierten Differenzen zwischen den beobachteten und den erwarteten geteilt erwartet:

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

Die Idee ist am besten mit einem Beispiel erläutert. Nehmen Sie an, wie in der Demo die beobachteten Werte für 380 Spins eines Rads Roulette sind (192, 163, 25) und die erwartete Anzahl ist das Rad fair (180, 180, 20). Die berechnete Chi-Quadrat-Statistik ist:

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

Die Demo implementiert diese Funktion als:

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;
}

Es ist keine fehlerprüfung hier der Einfachheit halber in einem Produktionssystem sollten Sie sicherstellen, dass Arrays beobachtete und erwartete haben die gleiche Länge und so weiter. Das Demoprogramm besitzt auch eine Methode, um eine Chi-Quadrat-Statistik über ein Array von beobachteten und ein Array von erwarteten Wahrscheinlichkeiten zu berechnen:

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);
}

Zusammenfassend lässt sich sagen, verwendet die mathematische Definition der Chi-Quadrat-Statistik, ein Array von beobachteten und ein Array von erwarteten Anzahl. Es ist auch sinnvoll, ein Array von beobachteten und ein Array von erwarteten Wahrscheinlichkeiten Chi-Quadrat zu berechnen. Um diese Berechnung auszuführen, ist es praktisch, haben eine Hilfsmethode, die erwartete Anzahl von erwarteten Wahrscheinlichkeiten berechnet.

Nachvollziehen der Chi-Quadrat-Verteilung

Wenn Sie einen berechnete Chi-Quadrat-Statistik-Wert haben, können Sie es verwenden, die Wahrscheinlichkeit (p-Wert) für den Chi-Quadrat-Wert zu berechnen. Dieses Konzept wird am besten visuell erläutert. Betrachten Sie das Diagramm im Abbildung 3, die zeigt, dass der Chi-Quadrat-Verteilungs für die demoproblem. Der gesamte Bereich unter jedem Chi-Quadrat-Verteilung ist 1.0. Der p-Wert ist der Bereich unterhalb des Diagramms aus der berechnete Chi-Quadrat-Statistik an, die plus unendlich.

Der Chi-Quadrat-Verteilung df = 2
Abbildung 3: die Chi-Quadrat-Verteilung df = 2

Diese Idee ist sehr subtil. Und leider Berechnen der Fläche unterhalb einer Chi-Quadrat-Verteilung ist äußerst schwierig. Glücklicherweise numerische Algorithmen zum Schätzen der Fläche unterhalb einer Chi-Quadrat-Verteilung in der 1960s und 1970er Jahren entwickelt wurden und noch heute verwendet werden.

Dadurch erschwert, ist die Tatsache, die nur eine Chi-Quadrat-Verteilung nicht vorhanden ist, gibt es viele. Für eine gut geeignete Tests ist kurz, ein Wert, der die Freiheitsgrade abgekürzten df aufgerufen. Der Wert von df für eine gut geeignete Tests ist einfach 1 minus der Anzahl der Anzahl der Buckets. Für die Demo stehen drei Anzahl der Buckets (Rot, Schwarz, Grün) also das df 3-1 = 2.

Es gibt eine andere Chi-Quadrat-Verteilung für jeden Wert von df. Das Diagramm im Abbildung 3 zeigt die Chi-Quadrat-Verteilung für df = 2. Beachten Sie die Chi-Quadrat-Werte auf der horizontalen Achse von 0,0 (die kleinste mögliche berechnete Chi-Quadrat-Statistik, wenn alle Zahlen, die die entsprechende erwarteten Anzahl entspricht beobachtet), zum Ausführen + unendlich (es gibt keine Beschränkung auf die verschiedenen beobachtete und erwartete sein kann).

Es gibt mehrere anspruchsvolle Algorithmen, die einen p-Wert berechnen können / Bereich unterhalb des Diagramms Chi-Quadrat-Verteilung. Das Demoprogramm verwendet genannte ACM-Algorithmus 299, die als Methode ChiSquarePval implementiert wird. Der Algorithmus verwendet wiederum einen anderen Algorithmus namens ACM 209, die als Gauß-Methode implementiert wird. Diese Algorithmen sind die Grundlagen der numerischen computing und dargestellt werden Abbildung 4. Sogar ein kurzer Blick auf den Code sollte überzeugen Sie einige sehr ernstes mathematische passiert ist, aber Glücklicherweise können Sie sich vorstellen der Methoden, die diese Algorithmen als schwarze Felder zu implementieren, da Sie nie den Code ändern müssen.

Abbildung 4 Methoden ChiSquarePval und 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()

Zusammenfassung

Es ist nicht wahrscheinlich müssen Sie Roulette Wheel Daten analysieren, aber wenn Sie den Typ der Problemszenario verstehen, in denen eine Chi-Quadrat-Eignung der Eignung Test anwendbar ist, stellen Sie möglicherweise viele praktische Verwendungsmöglichkeiten für den Test. Es stehen viele Tools, die eine Chi-Quadrat-Eignung der Eignung Test, einschließlich Excel und der Sprache R ausführen können, aber dieser Tools kann schwierig oder unmöglich ist, in ein Softwaresystem zu integrieren. In solchen Fällen können Sie den Code in diesem Artikel vorgestellten.

Es gibt verschiedene andere Typen von statistischen Tests, die die Chi-Quadrat-Verteilung verwenden. Der Test in diesem Artikel vorgestellten wird Pearson Chi-Quadrat-Tests zur Unterscheidung von anderen Chi-Quadrat-Tests bezeichnet. Es gibt auch mehrere andere statistische Tests, die beobachteten und die erwartete Anzahl vergleichen kann, wenn Chi-Quadrat-ist die am häufigsten verwendeten.

Es ist wichtig zu beachten, dass die Chi-Quadrat-Eignung der Eignung Test, wie die meisten statistische Tests probabilistisch, sodass konservativ Ergebnisse interpretiert werden soll. Auch wenn Sie einen sehr kleinen p-Wert erhalten, ist es wünschenswert, z. B. etwas wie "der kleinen p-Wert des 0.0085 schlägt vor, dass der Unterschied zwischen beobachteten und die erwartete Anzahl unwahrscheinlich zustande gekommen sind ist" statt, "der kleinen p-Wert gibt an, dass die beobachteten Werte konnte nicht zustande gekommen sind."


Dr. James McCaffreyist in Redmond (Washington) für Microsoft Research tätig. Er hat an verschiedenen Microsoft-Produkten mitgearbeitet, unter anderem an Internet Explorer und Bing. Dr. McCaffrey erreichen Sie unter jammc@microsoft.com.

Unser Dank gilt den folgenden technischen Experten von Microsoft für die Durchsicht dieses Artikels: Chris Lee und Kirk Olynyk