Самый быстрый способ преобразования массива Numpy в разреженный словарь?

Я заинтересован в преобразовании массива numpy в разреженный словарь как можно быстрее. Позвольте мне уточнить:

Учитывая массив:

numpy.array([12,0,0,0,3,0,0,1]) 

Я хочу создать словарь:

 {0:12, 4:3, 7:1} 

Как вы можете видеть, мы просто преобразуем тип последовательности в явное отображение из индексов, отличных от их значений.

Чтобы сделать это немного интереснее, я предлагаю следующий тестовый жгут для тестирования альтернатив:

 from timeit import Timer if __name__ == "__main__": s = "import numpy; from itertools import izip; from numpy import nonzero, flatnonzero; vector = numpy.random.poisson(0.1, size=10000);" ms = [ "f = flatnonzero(vector); dict( zip( f, vector[f] ) )" , "f = flatnonzero(vector); dict( izip( f, vector[f] ) )" , "f = nonzero(vector); dict( izip( f[0], vector[f] ) )" , "n = vector > 0; i = numpy.arange(len(vector))[n]; v = vector[n]; dict(izip(i,v))" , "i = flatnonzero(vector); v = vector[vector > 0]; dict(izip(i,v))" , "dict( zip( flatnonzero(vector), vector[flatnonzero(vector)] ) )" , "dict( zip( flatnonzero(vector), vector[nonzero(vector)] ) )" , "dict( (i, x) for i,x in enumerate(vector) if x > 0);" ] for m in ms: print " %.2fs" % Timer(m, s).timeit(1000), m 

Я использую распределение пуассонов для моделирования массивов, которые меня интересуют.

Вот мои результаты:

  0.78sf = flatnonzero(vector); dict( zip( f, vector[f] ) ) 0.73sf = flatnonzero(vector); dict( izip( f, vector[f] ) ) 0.71sf = nonzero(vector); dict( izip( f[0], vector[f] ) ) 0.67sn = vector > 0; i = numpy.arange(len(vector))[n]; v = vector[n]; dict(izip(i,v)) 0.81si = flatnonzero(vector); v = vector[vector > 0]; dict(izip(i,v)) 1.01s dict( zip( flatnonzero(vector), vector[flatnonzero(vector)] ) ) 1.03s dict( zip( flatnonzero(vector), vector[nonzero(vector)] ) ) 4.90s dict( (i, x) for i,x in enumerate(vector) if x > 0); 

Как вы можете видеть, самое быстрое решение, которое я нашел, это

 n = vector > 0; i = numpy.arange(len(vector))[n] v = vector[n] dict(izip(i,v)) 

Любой более быстрый способ?

Изменить: шаг

 i = numpy.arange(len(vector))[n] 

Кажется особенно неуклюжим, генерируя весь массив, прежде чем выбирать только некоторые элементы, особенно, когда мы знаем, что это может быть только около 1/10 элементов, выбранных. Я думаю, что это все еще может быть улучшено.

6 Solutions collect form web for “Самый быстрый способ преобразования массива Numpy в разреженный словарь?”

Я задаюсь вопросом, изменяет ли временное время размер дикта, когда он растет.

Было бы неплохо, если бы у dict был метод (или вариант создания экземпляра), чтобы указать начальный размер; поэтому, если бы мы знали, что он будет большим, python может сэкономить время и просто сделать один большой mem-адрес впереди, а не то, что я предполагаю, дополнительные ассигнования по мере роста.

 >>> a=np.array([12,0,0,0,3,0,0,1]) >>> {i:a[i] for i in np.nonzero(a)[0]} {0: 12, 4: 3, 7: 1} 

используйте разреженную матрицу в scipy как мост:

 from scipy.sparse import * import numpy a=numpy.array([12,0,0,0,3,0,0,1]) m=csr_matrix(a) d={} for i in m.nonzero()[1]: d[i]=m[0,i] print d 

Следующим представляется значительное улучшение:

 i = np.flatnonzero(vector) dict.fromkeys(i.tolist(), vector[i].tolist()) 

Сроки:

 import numpy as np from itertools import izip vector = np.random.poisson(0.1, size=10000) %timeit f = np.flatnonzero(vector); dict( izip( f, vector[f] ) ) # 1000 loops, best of 3: 951 µs per loop %timeit f = np.flatnonzero(vector); dict.fromkeys(f.tolist(), vector[f].tolist()) # 1000 loops, best of 3: 419 µs per loop 

Я также пробовал scipy.sparse.dok_matrix и pandas.DataFrame.to_dict но в моем тестировании они были медленнее оригинала.

Вы можете использовать np.unique с return_index=True :

 >>> import numpy as np >>> arr = np.array([12,0,0,0,3,0,0,1]) >>> val, idx = np.unique(arr, return_index=True) >>> mask = val != 0 # exclude zero >>> dict(zip(idx[mask], val[mask])) # create the dictionary {0: 12, 4: 3, 7: 1} 

Как правило, быстрее перебирать list чем numpy.array чтобы вы могли быстрее, когда вы конвертировали их в списки со tolist :

 >>> dict(zip(idx[mask].tolist(), val[mask].tolist())) 

тайминг

Для коротких массивов этот подход может быть медленнее, но по моим настройкам быстрее, чем другие подходы для больших массивов:

 import numpy as np from scipy.sparse import csr_matrix arr = np.random.randint(0, 10, size=10000) # 10k items arr[arr < 7] = 0 # make it sparse # ---------- %timeit {i:arr[i] for i in np.nonzero(arr)[0]} # 3.7 ms ± 51 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) # ---------- %%timeit val, idx = np.unique(arr, return_index=True) mask = val != 0 dict(zip(idx[mask].tolist(), val[mask].tolist())) # 844 µs ± 42.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) # ---------- %%timeit m=csr_matrix(a) d={} for i in m.nonzero()[1]: d[i]=m[0,i] # 1.52 s ± 57.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) 

Пробовал это?

от импорта numpy, где

i = где (вектор> 0) [0]

  • Перемещения между цифрами и линиями
  • numpy ufuncs speed vs для скорости цикла
  • Python: является ли итерация многомерного массива супер медленным?
  • Ускорьте миллионы регулярных выражений в Python 3
  • Эффективное обнаружение изменений знака в python
  • Каков наиболее эффективный способ проверить, существует ли значение в массиве NumPy?
  • Читайте в большом файле и создайте словарь
  • Как пробовать массив numpy и эффективно выполнять вычисления по каждому образцу?
  •  
    Interesting Posts for Van-Lav
    Python - лучший язык программирования в мире.