Эффективная обработка очень большой строки Unicode в CSV
Обычно я могу довольно быстро найти ответы на свои дилеммы на этом сайте, но, возможно, эта проблема требует более специфического подхода;
У меня есть строка юникода длиной ~50 миллионов, которую я загружаю с осциллографа Tektronix. Получение этого назначения - это боль в ** для памяти (sys.getsizeof() сообщает ~100 МБ)
Проблема заключается в том, что мне нужно превратить это в CSV, чтобы я мог получить 10 000 из 10 миллионов значений запятой сентябрь (это исправлено)... 1) Я пробовал метод split(","), используя это, использование оперативной памяти в ядре python SPIKES еще 300 МБ.... НО процесс ОЧЕНЬ эффективен (за исключением случаев, когда я повторяю это ~100 раз в одной процедуре... где-то между итерациями 40-50, ядро выплевывает ошибку памяти.) 2) Я написал свой собственный скрипт, который после загрузки абсурдно длинной строки сканирует количество запятых, пока не увидит 10000 и не остановится, превращая все значения между запятыми в числа с плавающей точкой и заполняя массив np. Это довольно эффективно с точки зрения использования памяти (от импорта файла до запуска сценария использование памяти изменяется только на 150 МБ.) Однако оно НАМНОГО медленнее и обычно приводит к сбою ядра вскоре после завершения циклов 100x.
Ниже приведен код, используемый для обработки этого файла, и если вы отправите мне в личку, я могу выслать вам копию строки для эксперимента (однако я уверен, что ее будет проще сгенерировать)
Код 1 (с использованием метода split())
PPStrace = PPSinst.query('CURV?')
PPStrace = PPStrace.split(',')
PPSvals = []
for iii in range(len(PPStrace)): #does some algebra to values
PPStrace[iii] = ((float(PPStrace[iii]))-yoff)*ymult+yzero
maxes=np.empty(shape=(0,0))
iters=int(samples/1000)
for i in range(1000): #looks for max value in 10,000 sample increments, adds to "maxes"
print i
maxes = np.append(maxes,max(PPStrace[i*iters:(i+1)*iters]))
PPS = 100*np.std(maxes)/np.mean(maxes)
print PPS," % PPS Noise"
Код 2 (самостоятельно сгенерированный скрипт);
PPStrace = PPSinst.query('CURV?')
walkerR=1
walkerL=0
length=len(PPStrace)
maxes=np.empty(shape=(0,0))
iters=int(samples/1000) #samples is 10 million, iters then is 10000
for i in range(1000):
sample=[] #initialize 10k sample list
commas=0 #commas are 0
while commas<iters: #if the number of commas found is less than 10,000, keep adding values to sample
while PPStrace[walkerR]!=unicode(","):#indexes commas for value extraction
walkerR+=1
if walkerR==length:
break
sample.append((float(str(PPStrace[walkerL:walkerR]))-yoff)*ymult+yzero)#add value between commas to sample list
walkerL=walkerR+1
walkerR+=1
commas+=1
maxes=np.append(maxes,max(sample))
PPS = 100*np.std(maxes)/np.mean(maxes)
print PPS,"% PPS Noise"
Также попробовал Pandas Dataframe с StringIO для преобразования CSV. Эта вещь получает ошибку памяти, просто пытаясь прочитать ее в кадр.
Я думаю, что решение будет заключаться в том, чтобы загрузить это в таблицу SQL, а затем вытащить CSV на 10000 образцов фрагментов (что является целью сценария). Но я бы не хотел этого делать!
Спасибо за вашу помощь, ребята!
2 ответа
Вы пробовали класс cStringIO? Это похоже на файловый ввод-вывод, но вместо указанного файла используется строка в качестве буфера. Честно говоря, я ожидаю, что у вас хроническая проблема со скоростью. Ваш собственный сценарий должен быть правильным подходом. Вы можете получить некоторое ускорение, если будете читать блок за раз, а затем анализировать его во время чтения следующего блока.
Для параллельной обработки используйте многопроцессорный пакет. Смотрите официальную документацию или этот учебник для деталей и примеров.
Вкратце, вы создаете функцию, которая воплощает процесс, который вы хотите запустить параллельно. Затем вы создаете процесс с этой функцией в качестве целевого параметра. Затем начните процесс. Если вы хотите объединить свой поток с основной программой, используйте объединение.
Взгляните на numpy.frombuffer ( http://docs.scipy.org/doc/numpy-1.10.1/reference/generated/numpy.frombuffer.html). Это позволяет вам указать количество и смещение. Вы должны быть в состоянии поместить большую строку в буфер, а затем обработать ее порциями, чтобы избежать огромных скачков памяти.
РЕДАКТИРОВАТЬ 2016-02-01
Поскольку frombuffer должен иметь фиксированную ширину в байтах, я попробовал numpy.fromregex, и он, похоже, может быстро проанализировать строку. Это должно сделать все, что может вызвать проблемы с памятью. http://docs.scipy.org/doc/numpy-1.10.1/reference/generated/numpy.fromregex.html
Что-то вроде этого:
buf = StringIO.StringIO(big_string)
output = numpy.fromregex(buf, r'(-?\d+),', dtype=[('val', np.int64)])
# output['val'] is the array of values