2014-01-18 7 views
10

Nehmen wir an, ich würfel einen 6-seitigen Würfel 60 Mal und ich bekomme 16, 5, 9, 7, 6, 15 Rollen für die Zahlen 1 bis 6, jeweils. Die Nummern 1 und 6 zeigen zu viel und there's only about a 1.8% chance of that being random. Wenn ich Statistics::ChiSquare verwenden, druckt es aus:Ein besserer Chi-Quadrat-Test für Perl?

There's a >1% chance, and a <5% chance, that this data is random. 

So ist es nicht nur eine schlechte Schnittstelle (ich kann nicht diese Zahlen direkt zurück zu bekommen), aber der Rundungsfehler ist signifikant.

Was ist schlimmer, was passiert, wenn ich 2 sechsseitige Würfel rolle? Die Wahrscheinlichkeit, eine bestimmte Zahl erhalten sind:

Sum Frequency Relative Frequency 
2 1   1/36 
3 2   2/36                                                    
4 3   3/36 
5 4   4/36 
6 5   5/36 
7 6   6/36 
8 5   5/36 
9 4   4/36 
10 3   3/36 
11 2   2/36 
12 1   1/36 

Statistics::ChiSquare used to have a chisquare_nonuniform() function, aber es wurde entfernt.

Also die Zahlen sind schlecht gerundet und ich kann es nicht für eine ungleichmäßige Verteilung verwenden. Mit einer Liste der tatsächlichen Häufigkeit und einer Liste der erwarteten Häufigkeit, was ist der beste Weg zur Berechnung der Chi-Quadrat-Test in Perl? Die verschiedenen Module, die ich auf dem CPAN finde, helfen mir nicht, also vermute ich, dass ich etwas Offensichtliches verpasst habe.

+1

Die Chi-Quadrat-Test ist einfach genug, um mathematisch direkt von Code in vielleicht 20 Zeilen zu implementieren, und ich erwarte, dass die meisten Menschen mehr direkte Kontrolle wollen wird genau das tun. Die Fehlergrenzen für 1%, 5% usw. sind schwieriger zu berechnen, daher werden einfache utils wahrscheinlich nur die Werte P <0,01, P <0,05 usw. fest codieren. Ich wäre nicht zu überrascht, einen besseren Chi-Quadrat-Test in einem generischen Statistik-Modul wie http://search.cpan.org/~mikek/Statistics-Distributions-1.02/Distributions.pm –

Antwort

13

Die Implementierung selbst ist so einfach, dass ich Yet Another Statistics Module nicht nur dafür hochladen möchte.

use Carp qw<croak>; 
use List::Util qw<sum>; 
use Statistics::Distributions qw<chisqrprob>; 

sub chi_squared_test { 
    my %args = @_; 
    my $observed = delete $args{observed} // croak q(Argument "observed" required); 
    my $expected = delete $args{expected} // croak q(Argument "expected" required); 
    @$observed == @$expected or croak q(Input arrays must have same length); 

    my $chi_squared = sum map { 
    ($observed->[$_] - $expected->[$_])**2/$expected->[$_]; 
    } 0 .. $#$observed; 
    my $degrees_of_freedom = @$observed - 1; 
    my $probability = chisqrprob($degrees_of_freedom, $chi_squared); 
    return $probability; 
} 

say chi_squared_test 
    observed => [16, 5, 9, 7, 6, 17], 
    expected => [(10) x 6]; 

Ausgang: 0.018360

+1

amon zu finden, danke. Das ist perfekt. Ich habe versucht, das selbst zu implementieren, aber ich habe gesehen, dass ich einen kleinen Rechenfehler bei der Berechnung von $ chi_squared gemacht habe. Ich schätze Ihre Hilfe! – Ovid

+3

Und wenn Sie neugierig sind, hier ist meine Aufschrift: http://blogs.perl.org/users/ovid/2014/01/testing-random-dice-rolls.html – Ovid

+0

@amon: Ich hatte nicht gesehen die Anweisung 'delete x // krächzen 'vorher. Die [docs] (http://perldoc.perl.org/perlop.html#Logical-Defined-Or) auf '//' sagen, dass sie einen Wert zurückgibt, der nicht als Lvalue verwendet werden kann. Wie funktioniert 'delete' also hier richtig, da es hier eigentlich nur um einen Wert und nicht um einen Lvalue geht? –

Verwandte Themen