Самый быстрый способ генерировать разграниченную строку от 1d numpy массив

У меня есть программа, которая должна повернуть много больших одномерных numpy массивов плаваний в разграниченные строки. Я нахожу эту операцию довольно медленной относительно математических операций в моей программе и задаюсь вопросом, существует ли способ ускорить ее. Например, рассмотрите следующий цикл, который берет 100 000 случайных чисел в массиве numpy и присоединяется к каждому массиву в разграниченную запятой строку.

import numpy as np
x = np.random.randn(100000)
for i in range(100):
    ",".join(map(str, x))

Этот цикл занимает приблизительно 20 секунд для завершения (общее количество, не каждый цикл). Напротив, полагайте, что 100 циклов чего-то как поэлементное умножение (x*x) взяли бы, чем один 1/10 секунды для завершения. Очевидно строковая операция соединения создает большое узкое место производительности; в моем реальном приложении это будет доминировать над общим временем выполнения. Это заставляет меня задаться вопросом, есть ли более быстрый путь, чем"", .join (карта (ул., x))? Так как карта () - то, где почти все время обработки происходит, это сводится к вопросу того, преобразовывает ли там более быстрое к пути очень большое количество чисел к строкам.

25
задан Abiel 27 April 2010 в 13:20
поделиться

4 ответа

Очень хорошая запись о производительности различных методов конкатенации строк в Python: http://www.skymind.com/~ocrow/python_string/

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

Самый быстрый метод, упомянутый на сайте

Метод 6: Составление списка

 def method6 (): 
return '' .join ([`num` for num in xrange (loop_count)]) { {1}} 

Этот способ самый короткий. Я испорчу сюрприз и скажу, что он к тому же самый быстрый. Он очень компактен и к тому же довольно понятен. Создайте список чисел, используя понимание списка , а затем соедините их все вместе. Что может быть проще? Этот на самом деле является сокращенной версией метода 4, и он потребляет примерно такой же объем памяти. Однако это быстрее, потому что нам не нужно вызывать функцию list.append () каждый раз, обходя цикл .

6
ответ дан 28 November 2019 в 21:23
поделиться

Использование imap из itertools вместо map в коде OP дает мне улучшение примерно на 2-3%, что немного, но что-то, что может сочетаться с другими идеями, чтобы дать больше улучшений.

Лично я думаю, что если вы хотите большего, вам придется использовать что-то вроде Cython.

0
ответ дан 28 November 2019 в 21:23
поделиться

numpy.savetxt даже медленнее, чем string.join. ndarray.tofile (), похоже, не работает с StringIO.

Но я нашел более быстрый метод (по крайней мере, применительно к примеру OP на python2.5 с более низкой версией numpy):

import numpy as np
x = np.random.randn(100000)
for i in range(100):
    (",%f"*100000)[1:] % tuple(x)

Похоже, строковый формат быстрее, чем строковое соединение, если у вас есть хорошо определенный формат, такой как в данном конкретном случае. Но мне интересно, зачем OP такая длинная строка плавающих чисел в памяти.

Новые версии numpy не показывают улучшения скорости.

1
ответ дан 28 November 2019 в 21:23
поделиться

Думаю, вы могли бы поэкспериментировать с numpy.savetxt , передавая объект cStringIO.StringIO как поддельный файл ...

Или, может быть, используя str (x) и замену пробелов запятыми (правка: это не сработает, потому что str делает многоточие для больших массивов: -s).

Поскольку целью этого было пересылка массива по сети, возможно, есть лучшие альтернативы (более эффективные как с точки зрения ЦП, так и с точки зрения пропускной способности). Тот, который я указал в комментарии к другому ответу, как кодировать двоичное представление массива в виде текстового блока Base64. Основным неудобством для этого быть оптимальным является то, что клиент, читающий кусок данных, должен иметь возможность делать неприятные вещи, такие как переинтерпретировать массив байтов как массив с плавающей запятой, что обычно не допускается в языках с типобезопасностью; но это можно сделать быстро с помощью вызова библиотеки C (и большинство языков предоставляют средства для этого).

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

Да, и следите за порядком байтов машин при отправке данных по сети: преобразовать в сетевой порядок -> base64encode -> отправить | получить -> base64decode -> преобразовать в порядок хоста

2
ответ дан 28 November 2019 в 21:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: