2010-09-28 17 views
11

Używam Pythona 2.6.5 na Mac OS X 10.6.4 (to nie jest wersja natywna, zainstalowałem ją samodzielnie) z Scipy 0.8.0. Jeśli wykonuję następujące czynności:Czy można wyjaśnić to dziwne zachowanie hipergeometrycznej dystrybucji w scipy?

>>> from scipy.stats import hypergeom 
>>> hypergeom.sf(5,10,2,5) 

Otrzymuję IndexError. Następnie:

>>> hypergeom.sf(2,10,2,2) 
-4.44.... 

Podejrzewam, że wartość ujemna wynika z niewłaściwej precyzji zmiennoprzecinkowej. Następnie ponownie wykonuję pierwszą:

>>> hypergeom.sf(5,10,2,5) 
0.0 

Teraz działa! Czy ktoś może to wyjaśnić? Czy widzisz też to zachowanie?

+2

on robi to samo na Python 2.6.6 na Debianie. – eumiro

+2

Cokolwiek jest warte, brzmi to jak błąd, a zatem może być lepiej zapytany na liście użytkowników scipy: http://mail.scipy.org/mailman/listinfo/scipy-user Jest bardziej prawdopodobne, że dostanie uwaga twórców tam ... –

+5

Otworzyłem bilet na to: http://projects.scipy.org/scipy/ticket/1291. Jak wspomniał Joe Kington, przydatne byłoby zgłaszanie błędów lub nieoczekiwanych zachowań do listy mailingowej lub do śledzenia błędów pakietu. – user333700

Odpowiedz

3

Problem pojawia się, jeśli pierwsze wywołanie funkcji przeżycia znajduje się w zakresie, który powinien wynosić zero (zobacz mój komentarz do poprzedniej odpowiedzi). Np. W przypadku wywołań hypergeom.sf (x, M, n, N) nie powiedzie się, jeśli pierwszym wywołaniem funkcji hipergeometrycznej do funkcji jest sytuacja, w której x> n, gdzie funkcja przeżycia zawsze będzie wynosić zero.

Można trywialnie to naprawić tymczasowo przez:

def new_hypergeom_sf(k, *args, **kwds): 
    from scipy.stats import hypergeom 
    (M, n, N) = args[0:3] 
    try: 
     return hypergeom.sf(k, *args, **kwds) 
    except Exception as inst: 
     if k >= n and type(inst) == IndexError: 
      return 0 ## or conversely 1 - hypergeom.cdf(k, *args, **kwds) 
     else: 
      raise inst 

Teraz, jeśli nie masz edycji na /usr/share/pyshared/scipy/stats/distributions.py problemu (lub odpowiednik pliku), poprawka prawdopodobnie na linii 3966, gdzie teraz to brzmi:

place(output,cond,self._sf(*goodargs)) 
    if output.ndim == 0: 
     return output[()] 
    return output 

Ale jeśli go zmienić na:

if output.ndim == 0: 
     return output[()] 
    place(output,cond,self._sf(*goodargs)) 
    if output.ndim == 0: 
     return output[()] 
    return output 

Teraz działa bez indeksu IndexError. Zasadniczo, jeśli wynik jest zerowy, ponieważ nie sprawdza, próbuje wywołać miejsce, kończy się niepowodzeniem i nie generuje dystrybucji. (Nie dzieje się tak, jeśli poprzednia dystrybucja została już utworzona, co prawdopodobnie powoduje, że nie została ona przechwycona przez wcześniejsze testy.) Zauważ, że miejsce (zdefiniowane w numpy's function_base.py) zmieni elementy tablicy (chociaż ja nie jestem pewien, czy to zmienia wymiarowość), więc może być najlepiej, aby nadal pozostawić zerową kontrolę po miejscu też. Nie przetestowałem tego w pełni, aby sprawdzić, czy ta zmiana nie powoduje niczego innego (i dotyczy wszystkich dyskretnych rozkładów zmiennych losowych), więc może najlepiej wykonać pierwszą poprawkę.

To łamie; np. stats.hypergeom.sf (1,10,2,5) zwraca wartość zero (zamiast 2/9).

Ta poprawka wydaje się działać znacznie lepiej, w tej samej sekcji:

class rv_discrete(rv_generic): 
... 
    def sf(self, k, *args, **kwds): 
    ... 
     if any(cond): 
      place(output,cond,self._sf(*goodargs)) 
     if output.ndim == 0: 
      return output[()] 
     return output 
1

nie wiem, języka, jednak funkcja jest określona w następujący sposób: hypergeom.sf (X, M, N, N, loc = 0)

M jest kilka interesujących obiektów, N oznacza całkowita liczba obiektów, a n to częstotliwość "wybierania jednego" (przepraszam, niemiecki statystyk).

Jeśli miał miskę 20 kulki, 7 ci żółtej (interesujący żółty), wówczas n oznacza 20, a M oznacza 7.

Może funkcja zachowuje zdefiniowana dla (nonsens) przypadek, gdy M> N?

+0

Funkcja zdefiniowana w pythonie jest dobrze zdefiniowana dla użytych wartości M, n, N. Z docstringu w pythonie dla scipy.stats.hypergeom, M jest całkowitą liczbą obiektów, n jest liczbą obiektów typu 1, a N jest rysowane bez zastąpienia. Tak więc probs to hypergeom (x = 0,10,2,5) = 2/9, hypergeom (x = 1,10,2,5) = 5/9, hypergeom (x = 2,10,2,5) = 2/9; więc funkcja przeżycia dla x <0 wynosi 0, jej 7/9 dla 0 <= x <1, 2/9 dla 1 <= x <2 i 0 dla 2 <= x. W przypadku sf (funkcja przeżycia, odczytana jako 1-cdf, skumulowana funkcja rozkładu) hipergeometrycznego rozkładu, wiemy, że odpowiedź powinna wynosić 0. –