Подтвердить что ты не робот

Чтение csv в Julia медленнее по сравнению с Python

Чтение больших файлов text/csv в Julia занимает много времени по сравнению с Python. Вот время, чтобы прочитать файл размером 486,6 МБ и имеет 153895 строк и 644 столбца.

Пример python 3.3

import pandas as pd
import time
start=time.time()
myData=pd.read_csv("C:\\myFile.txt",sep="|",header=None,low_memory=False)
print(time.time()-start)

Output: 19.90

R 3.0.2 пример

system.time(myData<-read.delim("C:/myFile.txt",sep="|",header=F,
   stringsAsFactors=F,na.strings=""))

Output:
User    System  Elapsed
181.13  1.07    182.32

Julia 0.2.0 (Julia Studio 0.4.4) пример # 1

using DataFrames
timing = @time myData = readtable("C:/myFile.txt",separator='|',header=false)

Output:
elapsed time: 80.35 seconds (10319624244 bytes allocated)

Julia 0.2.0 (Julia Studio 0.4.4) пример # 2

timing = @time myData = readdlm("C:/myFile.txt",'|',header=false)

Output:
elapsed time: 65.96 seconds (9087413564 bytes allocated)
  • Джулия быстрее, чем R, но довольно медленная по сравнению с Python. Что я могу сделать по-другому, чтобы ускорить чтение большого текстового файла?

  • отдельная проблема заключается в том, что размер в памяти составляет 18 x размер файла жесткого диска в Julia, но всего 2,5 x для python. в Matlab, который, как я обнаружил, имеет большую память для больших файлов, размер файла жесткого диска составляет 2 x. Любая конкретная причина для большого размера файла в памяти в Julia?

4b9b3361

Ответ 1

Лучший ответ, вероятно, в том, что я не такой хороший программист, как Уэс.

В общем, код в DataFrames гораздо менее оптимизирован, чем код в Pandas. Я уверен, что мы можем догнать, но это займет некоторое время, так как есть много базовых функций, которые нам нужно реализовать в первую очередь. Поскольку в Julia так много всего требуется, я сосредоточен на том, чтобы делать вещи в трех частях: (1) построить любую версию, (2) построить правильную версию, (3) построить быструю, правильную версию. Для работы, которую я делаю, Джулия часто не предлагает никаких версий существенной функциональности, поэтому моя работа фокусируется на (1) и (2). Поскольку больше инструментов мне нужно построить, будет легче сосредоточиться на производительности.

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

В этой заметке код readtable достаточно прост для чтения. Самый определенный способ получить readtable быстрее - это выкрикнуть профилировщик Julia и начать исправлять недостатки производительности, которые он открывает.

Ответ 2

Обратите внимание, что вывод "n байтов" из @time - это общий размер всех выделенных объектов, игнорируя, сколько из них могло быть освобождено. Это число часто намного превышает конечный размер живых объектов в памяти. Я не знаю, основано ли это на вашей оценке размера памяти, но я хотел бы указать на это.

Ответ 3

Я нашел несколько вещей, которые могут частично помочь в этой ситуации.

  • используя функцию readdlm() в Джулии, кажется, работает значительно быстрее (например, 3 раза в недавнем исследовании), чем readtable(). Конечно, если вы хотите тип объекта DataFrame, вам нужно будет его преобразовать, что может привести к большей или большей скорости улучшения.

  • Задание размеров вашего файла может привести к большой разнице, как по скорости, так и по распределению памяти. Я проверил это пробное чтение в файле размером 258,7 МБ на диске:

    julia> @time Data = readdlm("MyFile.txt", '\t', Float32, skipstart = 1);
    19.072266 seconds (221.60 M allocations: 6.573 GB, 3.34% gc time)
    
    julia> @time Data = readdlm("MyFile.txt", '\t', Float32, skipstart = 1, dims = (File_Lengths[1], 62));
    10.309866 seconds (87 allocations: 528.331 MB, 0.03% gc time)
    
  • Спецификация типа для вашего объекта имеет большое значение. Например, если ваши данные имеют в нем строки, то данные массива, который вы читаете, будут иметь тип Any, что является дорогостоящей памятью. Если память действительно проблема, вы можете рассмотреть возможность предварительной обработки ваших данных, сначала преобразуя строки в целые числа, выполняя вычисления, а затем конвертируя их обратно. Кроме того, если вам не нужна тонна точности, использование Float32-типа вместо Float64 может сэкономить много места. Вы можете указать это при чтении файла, например:

    Data = readdlm("file.csv", ',', Float32)

  • Что касается использования памяти, я нашел, в частности, что тип PooledDataArray (из пакета DataArrays) может быть полезен при сокращении использования памяти, если ваши данные имеют много повторяющихся значений. Время для преобразования в этот тип относительно велико, поэтому это не временная заставка как таковая, но, по крайней мере, помогает немного уменьшить использование памяти. Например. при загрузке набора данных с 19 миллионами строк и 36 столбцов, 8 из которых представляли собой категориальные переменные для статистического анализа, это уменьшало распределение памяти объекта с 5x его размер на диске до 4x его размера. Если есть еще более повторяющиеся значения, уменьшение памяти может быть еще более значительным (у меня были ситуации, когда PooledDataArray сокращает выделение памяти наполовину).

  • Также может помочь запустить функцию gc() (сборщик мусора) после загрузки и форматирования данных, чтобы очистить любое ненужное выделение ram, хотя обычно Julia сделает это автоматически довольно хорошо.

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

Ответ 4

Существует относительно новый пакет julia, называемый CSV.jl от Jacob Quinn, который обеспечивает гораздо более быстрый парсер CSV, во многих случаях наравне с pandas: https://github.com/JuliaData/CSV.jl

Ответ 5

По моему опыту, лучший способ справиться с большими текстовыми файлами - это не загружать их в Julia, а скорее передавать их. Этот метод имеет некоторые дополнительные фиксированные затраты, но обычно выполняется очень быстро. Некоторый псевдокод:

function streamdat()
    mycsv=open("/path/to/text.csv", "r")   # <-- opens a path to your text file

    sumvec = [0.0]                # <-- store a sum  here
    i = 1
    while(!eof(mycsv))            # <-- loop through each line of the file
       row = readline(mycsv) 
       vector=split(row, "|")     # <-- split each line by |
       sumvec+=parse(Float64, vector[i]) 
       i+=1
    end
end

streamdat()

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