与Python相比,阅读朱莉娅的csv很慢

时间:2014-02-19 19:51:19

标签: julia

与Python相比,阅读Julia中的大文本/ csv文件需要很长时间。以下是读取大小为486.6 MB且包含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)
  1. Julia比R快,但与Python相比速度相当慢。我可以采取哪些不同的方式来加快阅读大文本文件的速度?

  2. 一个单独的问题是内存大小是Julia中硬盘文件大小的18倍,但是python只有2.5倍大小。在Matlab中,我发现它对于大文件来说是最有效的内存,它是2 x大小的硬盘文件大小。朱莉娅内存中文件大小的任何特殊原因?

7 个答案:

答案 0 :(得分:43)

最好的答案可能是我不像韦斯那样优秀的程序员。

一般来说,DataFrames中的代码远没有Pandas中的代码那么优化。我相信我们可以赶上,但需要一些时间,因为我们需要首先实现许多基本功能。由于需要在Julia中构建这么多,我倾向于专注于三个部分:(1)构建任何版本,(2)构建正确的版本,(3)构建快速,正确的版本。对于我的工作,Julia通常不会提供任何版本的基本功能,所以我的工作主要集中在(1)和(2)上。随着我需要构建的工具越多,关注性能就越容易。

至于内存使用情况,我认为答案是我们在解析表格数据时使用一组数据结构,这些表格数据的效率远低于Pandas使用的表格数据。如果我更好地了解熊猫的内部,我可以列出我们效率较低的地方,但是现在我只是推测一个明显的失败是我们将整个数据集读入内存而不是从磁盘中抓取块。这当然是可以避免的,并且存在这样的问题。这只是时间问题。

在这方面,readtable代码相当容易阅读。让readtable更快的最明确的方法是甩掉Julia分析器并开始修复它发现的性能缺陷。

答案 1 :(得分:10)

请注意,@time的“n bytes”输出是所有已分配对象的总大小,忽略了可能已释放的对象数。此数字通常远高于内存中活动对象的最终大小。我不知道这是你的记忆大小估计的基础,但我想指出这一点。

答案 2 :(得分:10)

我发现了一些可以部分帮助这种情况的事情。

  1. 使用Julia中的readdlm()函数似乎比readtable()工作得更快(例如,最近一次试用时为3倍)。当然,如果您想要DataFrame对象类型,那么您需要转换为它,这可能会消耗大部分或全部速度提升。

  2. 指定文件的尺寸可以在速度和内存分配方面产生巨大差异。我将这个试用版读入磁盘上的258.7 MB文件:

    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)
    
  3. 对象的类型规范非常重要。例如,如果您的数据中包含字符串,那么您读入的数组的数据将是Any类型,这是昂贵的内存。如果内存确实存在问题,您可能需要考虑通过首先将字符串转换为整数,进行计算,然后转换回来来预处理数据。此外,如果您不需要大量的精度,使用Float32类型而不是Float64可以节省大量空间。您可以在读取文件时指定此项,例如:

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

  4. 关于内存使用情况,我特别发现,如果您的数据有很多重复值,PooledDataArray类型(来自DataArrays包)可以帮助减少内存使用量。转换为此类型的时间相对较大,因此这本身并不节省时间,但至少有助于减少内存使用量。例如。当加载一个包含1900万行和36列的数据集时,其中8列表示用于统计分析的分类变量,这将对象的内存分配从磁盘大小的5倍减小到其大小的4倍。如果存在更多重复值,则内存减少可能更加显着(我已经将PooledDataArray的内存分配减少了一半)。

  5. 在加载和格式化数据以清除任何不需要的ram分配后,有时也可以帮助运行gc()(垃圾收集器)功能,尽管Julia通常会自动执行此操作。

  6. 尽管如此,我还是期待Julia的进一步发展,以便为大型数据集提供更快的加载和更高效的内存使用。

答案 3 :(得分:9)

Jacob Quinn提供了一个名为CSV.jl的相对较新的julia软件包,它提供了更快的CSV解析器,在许多情况下与pandas相同:https://github.com/JuliaData/CSV.jl

答案 4 :(得分:9)

让我们首先创建一个您正在谈论的文件以提供可重复性:

open("myFile.txt", "w") do io
    foreach(i -> println(io, join(i+1:i+644, '|')), 1:153895)
end

现在我在Julia 1.4.2和CSV.jl 0.7.1。中阅读了此文件。

单线程:

julia> @time CSV.File("myFile.txt", delim='|', header=false);
  4.747160 seconds (1.55 M allocations: 1.281 GiB, 4.29% gc time)

julia> @time CSV.File("myFile.txt", delim='|', header=false);
  2.780213 seconds (13.72 k allocations: 1.206 GiB, 5.80% gc time)

并使用例如4个线程:

julia> @time CSV.File("myFile.txt", delim='|', header=false);
  4.546945 seconds (6.02 M allocations: 1.499 GiB, 5.05% gc time)

julia> @time CSV.File("myFile.txt", delim='|', header=false);
  0.812742 seconds (47.28 k allocations: 1.208 GiB)

R中为:

> system.time(myData<-read.delim("myFile.txt",sep="|",header=F,
+                                stringsAsFactors=F,na.strings=""))
   user  system elapsed 
 28.615   0.436  29.048 

在Python(熊猫)中,它是:

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

现在,如果我们从R(快速)测试fread,我们将得到:

> system.time(fread("myFile.txt", sep="|", header=F,
                    stringsAsFactors=F, na.strings="", nThread=1))
   user  system elapsed 
  1.043   0.036   1.082 
> system.time(fread("myFile.txt", sep="|", header=F,
                    stringsAsFactors=F, na.strings="", nThread=4))
   user  system elapsed 
  1.361   0.028   0.416 

所以在这种情况下,摘要为:

  • 尽管在Julia中首次运行CSV.File的编译成本很高,但它的运行速度明显快于base R或Python
  • 它的速度与R中的fread相当(在这种情况下,速度稍慢,但其他here进行的基准测试则显示了速度更快的情况)

编辑:根据请求,我为一个小文件添加了一个基准:10列,100,000行Julia vs Pandas。

数据准备步骤:

open("myFile.txt", "w") do io
    foreach(i -> println(io, join(i+1:i+10, '|')), 1:100_000)
end

CSV.jl,单线程:

julia> @time CSV.File("myFile.txt", delim='|', header=false);
  1.898649 seconds (1.54 M allocations: 93.848 MiB, 1.48% gc time)

julia> @time CSV.File("myFile.txt", delim='|', header=false);
  0.029965 seconds (248 allocations: 17.037 MiB)

熊猫:

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

结论:

  • 编译成本是必须支付的一次性成本,它是恒定的(大约不取决于要读取的文件的大小)
  • 对于小文件,CSV.jl比Pandas快(如果我们排除编译成本的话)

现在,如果您希望避免在每次新的Julia会话中都需要支付编译费用,则可以使用https://github.com/JuliaLang/PackageCompiler.jl

根据我的经验,如果您从事数据科学工作,例如您读了成千上万个CSV文件后,等待2秒钟进行编译就没有问题,如果以后可以节省时间的话。编写读取文件中的代码需要2秒钟以上的时间。

当然-如果编写的脚本工作量很少,并且在完成后终止,则它是一个不同的用例,因为编译时间实际上是计算成本的主要部分。在这种情况下,我使用PackageCompiler.jl是一种策略。

答案 5 :(得分: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()

上面的代码只是一个简单的总和,但这个逻辑可以扩展到更复杂的问题。

答案 6 :(得分:0)

using CSV
@time df=CSV.read("C:/Users/hafez/personal/r/tutorial for students/Book2.csv")

最近我在Julia 1.4.2中尝试过。我发现了不同的回应,起初,我不了解茱莉亚。然后我在Julia讨论论坛上发布了同样的内容。然后我知道这段代码只会提供编译时间。 here您可以找到基准测试