2016-05-18 6 views
1

Ich berechne die häufigste Zahl in einem Vektor von int8 s. Numba beschwert, wenn ich einen Zähler Reihe von int s einzurichten:Array von Ints in Numba

@jit(nopython=True) 
def freq_int8(y): 
    """Find most frequent number in array""" 
    count = np.zeros(256, dtype=int) 
    for val in y: 
     count[val] += 1 
    return ((np.argmax(count)+128) % 256) - 128 

es aufrufen ich die folgende Fehlermeldung erhalten:

TypingError: Invalid usage of Function(<built-in function zeros>) with parameters (int64, Function(<class 'int'>)) 

Wenn ich dtype=int löschen es funktioniert und ich eine anständige Beschleunigung. Ich bin jedoch verwirrt, warum das Deklarieren eines Arrays von int s nicht funktioniert. Gibt es einen bekannten Workaround, und wäre hier ein Effizienzgewinn sinnvoll?

Hintergrund: Ich versuche Mikrosekunden von etwas schwerfällig Code zu rasieren. Ich bin besonders verletzt von numpy.median, und habe in Numba untersucht, aber ich kämpfe um median zu verbessern. Die häufigste Nummer zu finden ist eine akzeptable Alternative zu median, und hier konnte ich etwas Leistung gewinnen. Der obige Numba-Code ist auch schneller als numpy.bincount.

Update: Nach der Eingabe in der Antwort akzeptiert, hier ist eine Implementierung von median für int8 Vektoren. Es ist in etwa eine Größenordnung schneller als numpy.median:

@jit(nopython=True) 
def median_int8(y): 
    N2 = len(y)//2 
    count = np.zeros(256, dtype=np.int32) 
    for val in y: 
     count[val] += 1 
    cs = 0 
    for i in range(-128, 128): 
     cs += count[i] 
     if cs > N2: 
      return float(i) 
     elif cs == N2: 
      j = i+1 
      while count[j] == 0: 
       j += 1 
      return (i + j)/2 

der Leistungsunterschied Überraschenderweise ist noch größer für kurze Vektoren, die offensichtlich auf Overhead in numpy Vektoren:

>>> a = np.random.randint(-128, 128, 10) 

>>> %timeit np.median(a) 
    The slowest run took 7.03 times longer than the fastest. This could mean that an intermediate result is being cached. 
    10000 loops, best of 3: 20.8 µs per loop 

>>> %timeit median_int8(a) 
    The slowest run took 11.67 times longer than the fastest. This could mean that an intermediate result is being cached. 
    1000000 loops, best of 3: 593 ns per loop 

Dieser Aufwand ist so groß, Ich frage mich, ob etwas nicht stimmt.

Antwort

4

Nur eine kurze Notiz, die häufigste Zahl zu finden, ist in der Regel mode genannt, und es ist ähnlich wie bei den Median wie es die mittleren ist ... in diesem Fall np.mean erheblich schneller sein. Es sei denn, Sie haben einige Einschränkungen oder Besonderheiten in Ihren Daten, there is no guarantee that the mode approximates the median.

Wenn Sie noch den Modus eine Liste von Integer-Zahlen zu berechnen, np.bincount, wie Sie erwähnen, sollten genug sein (wenn numba schneller ist, sollte es nicht viel sein):

count = np.bincount(y, minlength=256) 
result = ((np.argmax(count)+128) % 256) - 128 

Hinweis Ich habe den minlength-Parameter zu np.bincount hinzugefügt, so dass er die gleiche 256-Längen-Liste zurückgibt, die Sie in Ihrem Code haben. Aber es ist in der Praxis völlig unnötig, da nur die argmax, np.bincount (ohne minlength) eine Liste zurückgeben soll, deren Länge die maximale Anzahl in y ist.

Wie für die Numba-Fehler, sollte dtype=int durch dtype=np.int32 ersetzen das Problem lösen. int ist eine Python-Funktion, und Sie geben nopython im Header numba an. Wenn Sie nopython entfernen, funktioniert auch entweder dtype=int oder (mit dem gleichen Effekt).

+0

Das ist also was _mode_ bedeutet!Ja, ich verstehe den Unterschied zum Median, aber in meinem speziellen Anwendungsfall ist der Modus wahrscheinlich angemessener als der Median. Ihr Vorschlag, dtype = np.int32 zu verwenden, funktioniert in der Tat und führte zu weiteren 30% Beschleunigung. Was "bincount" angeht, funktioniert das auch wie gewünscht, ist aber ungefähr halb so schnell wie die numba-Version. – DNF

+1

@DNF numba ist in der Tat schneller als bilcount, aber beachte, dass der erste Aufruf von numba immer langsamer ist (außer du rufst ihn mit sehr großen Arrays an). Wenn Sie die Funktion so definieren, dass sie nur einmal aufgerufen wird (in einem kleinen Array), dann ist die Geschwindigkeit wesentlich schlechter als "np.bincount". Wenn auf der anderen Seite, wenn Sie die Funktion mehrere Male aufrufen, oder mit einem Array groß genug, dass numba es * on the fly * optimieren kann, sollte numba gut funktionieren. –

+0

Es sollte für Millionen oder Zehnen oder Millionen von Mal pro Sitzung ausgeführt werden und wird über mehrere Prozessoren ausgeführt. Aber wissen Sie zufällig, ob das Starten eines neuen Prozesses eine neue Kompilierung auslöst? – DNF

Verwandte Themen