我使用以下代码将24位二进制data
加载到16位numpy
数组中:
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')
我认为可以提高速度效率,但是如何?
答案 0 :(得分:4)
好像你在这里非常迂回。这不会做同样的事情吗?
output = np.frombuffer(data,'b').reshape(-1,3)[:,1:].flatten().view('i2')
这样可以节省一些时间,从不填充临时数组,跳过bitshift并避免一些不需要的数据移动。不过,我还没有真正对它进行基准测试,我希望节省的费用不高。
编辑:我现在已经执行了基准测试。对于1200万的len(data)
,我的版本为80毫秒,而我的版本为39毫秒,所以几乎可以说是速度提高了2倍。正如预期的那样,并没有一个很大的改进,但是你的出发点已经非常快了。
Edit2:我应该提一下,我在这里假设了小端。然而,原始问题的代码也隐含地假设小端,所以这不是我的新假设。
(对于大端(数据和体系结构),您将1:
替换为:-1
。如果数据的字节序数不同于CPU,那么您还需要反转bytes(::-1
)。)
Edit3:为了更快的速度,我想你将不得不走出python。这个fortran函数也使用openMP,与我的版本相比,速度提高了2倍(比你的版本快4倍)。
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
与FOPT="-fopenmp" f2py -c -m basj{,.f90} -lgomp
汇编。然后,您可以在python中导入并使用它:
import basj
def convert(data): return def mine2(data): return basj.f(np.frombuffer(data,'b')).view('i2')
您可以通过可变环境OMP_NUM_THREADS
控制要使用的核心数,但默认使用所有可用核心。
答案 1 :(得分:1)
受@ amaurea的回答启发,这里是一个cython
版本(我已经在我的原始代码中使用了cython,所以我将继续使用cython而不是混合使用cython + fortran):
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
速度增加4倍:)