2014-03-02 17 views
5

Ich verwende den folgenden Code 24-bit binary data in einen 16-Bit-numpy Array zu laden:schnelleren Laden von 24-Bit-Binärdaten in 16-Bit-numpy Array

temp = numpy.zeros((len(data)/3, 4), dtype='b') 
temp[:, 1:] = numpy.frombuffer(data, dtype='b').reshape(-1, 3) 
temp2 = temp.view('<i4').flatten() >> 16  # >> 16 because I need to divide by 2**16 to load my data into 16-bit array, needed for my (audio) application 
output = temp2.astype('int16') 

I vorstellen, dass es möglich ist, zu verbessern Sie die Geschwindigkeit Effizienz, aber wie?

+0

Hinweis: 'Daten' werden aus einer Binärdatei mit' open', Modul 'chunk' und' chunk.read' gelesen. – Basj

Antwort

4

Es scheint, als ob Sie hier sehr umständlich sind. Wird das nicht dasselbe tun?

output = np.frombuffer(data,'b').reshape(-1,3)[:,1:].flatten().view('i2') 

Dies würde einige Zeit von nicht Null-Füllung ein temporäres Array speichern, die bitshift Überspringen und einige unneceessary Daten bewegt zu vermeiden. Ich habe es jedoch noch nicht einmal bewertet und erwarte, dass die Einsparungen bescheiden sind.

Edit: Ich habe jetzt den Benchmark durchgeführt. Für len(data) von 12 Millionen, ich bekomme 80 ms für Ihre Version und 39 ms für meine, so ziemlich genau ein Faktor 2 Beschleunigung. Keine große Verbesserung, wie erwartet, aber dann war dein Startpunkt schon ziemlich schnell.

Edit2: Ich sollte erwähnen, dass ich hier Little Endian angenommen habe. Der Code der ursprünglichen Frage nimmt jedoch implizit auch Little Endian an, also ist dies keine neue Annahme von mir.

(Für Big-Endian (Daten und Architektur), würden Sie 1: durch :-1 ersetzen. Wenn die Daten eine andere endianness als die CPU haben, dann würden Sie auch die Reihenfolge des Bytes (::-1) umkehren müssen.)

Edit3: Für noch mehr Geschwindigkeit, denke ich, dass Sie außerhalb Python gehen müssen. Diese Fortran-Funktion, die auch openMP nutzt, bringt mir eine Beschleunigung von Faktor 2 im Vergleich zu meiner Version (also 4+ schneller als deine Version).

subroutine f(a,b) 
     implicit none 
     integer*1, intent(in) :: a(:) 
     integer*1, intent(out) :: b(size(a)*2/3) 
     integer :: i 
     !$omp parallel do 
     do i = 1, size(a)/3 
       b(2*(i-1)+1) = a(3*(i-1)+2) 
       b(2*(i-1)+2) = a(3*(i-1)+3) 
     end do 
     !$omp end parallel do 
end subroutine 

Kompilieren Sie mit FOPT="-fopenmp" f2py -c -m basj{,.f90} -lgomp. Anschließend können Sie importieren und in Python verwenden:

import basj 
def convert(data): return def mine2(data): return basj.f(np.frombuffer(data,'b')).view('i2') 

Sie die Anzahl der Kerne steuern kann über die Umwelt variavble OMP_NUM_THREADS, aber es standardmäßig mit allen verfügbaren Kerne zu verwenden.

+0

Vielen Dank. Ich versuche gerade, es zu benchmarken, ich gebe dir die Ergebnisse. (Anmerkung: Ich brauche das Ergebnis als zusammenhängendes Array, daher ist die Verwendung einer Ansicht nicht möglich) – Basj

+0

Das Ergebnis ist zusammenhängend in meinem Test, laut '.flags'. Wenn Sie absolut sicher sein wollen, dass es immer zusammenhängend ist (obwohl ich nicht sehen kann, wie es variieren könnte), könnten Sie es in 'np.ascontiguousarray' umbrechen, was eine freie Operation ist, wenn das Array bereits zusammenhängend ist, aber ein zusammenhängende Kopie sonst. – amaurea

+2

Das Array wird zusammenhängend gemacht durch ['flatten'] (http://docs.scipy.org/doc/numpy/reference/generated/numpy.darray.flatten.html), welches immer eine Kopie erstellt. Hier interpretiert "Ansicht" einfach alle 2 Einzelbyte-Zahlen als eine 2-Byte-Zahl neu. – Jaime

1

Inspiriert von @ Amaurea Antwort, hier ist eine cython Version (I bereits cython in meiner ursprünglichen Code verwendet, also werde ich mit cython weiterhin statt cython + Fortran Mischen):

import cython 
import numpy as np 
cimport numpy as np 

def binary24_to_int16(char *data): 
    cdef int i 
    res = np.zeros(len(data)/3, np.int16) 
    b = <char *>((<np.ndarray>res).data) 
    for i in range(len(data)/3): 
     b[2*i] = data[3*i+1] 
     b[2*i+1] = data[3*i+2] 
    return res    

Es gibt eine Faktor 4 Geschwindigkeitszunahme :)