如何使用python快速将数据加载到内存中?

时间:2015-05-05 01:36:26

标签: python performance pandas

我有一个大的csv文件(5 GB),我可以用pandas.read_csv()读取它。此操作需要大量时间10-20分钟。

如何加快速度?

sqllite格式转换数据会有用吗?如果我该怎么办?

编辑:更多信息: 该数据包含1852列和350000行。大多数列都是float65并包含数字。其他一些包含字符串或日期(我认为它被认为是字符串)

我正在使用配备16 GB RAM和SSD硬盘的笔记本电脑。数据应该适合内存(但我知道python往往会增加数据大小)

编辑2:

在加载过程中,我收到此消息

/usr/local/lib/python3.4/dist-packages/pandas/io/parsers.py:1164: DtypeWarning: Columns (1841,1842,1844) have mixed types. Specify dtype option on import or set low_memory=False.
  data = self._reader.read(nrows)

编辑:解决方案

读取一次csv文件并将其另存为 data.to_hdf('data.h5', 'table') 这种格式非常有效

3 个答案:

答案 0 :(得分:4)

这实际上取决于阅读的哪一部分需要10分钟。

  • 如果它实际上从磁盘读取,那么显然任何更紧凑的数据形式都会更好。
  • 如果它正在处理CSV格式(你可以说这是因为你的CPU在读取时在一个核心上接近100%;对于其他两个核心来说它会非常低),那么你想要一个表格已经预处理过。
  • 如果它交换内存,例如,因为你只有2GB的物理内存,那么除了分割数据之外什么都没有帮助。

知道你拥有哪一个很重要。例如,对数据进行流压缩(例如,使用gzip)会使第一个问题变得更好,但第二个问题会更糟。

听起来你可能有第二个问题,这很有用。 (但是,无论出现什么问题,你都可以做些更好的事情。)

您将它存储在sqlite数据库中的想法很好,因为它至少可以同时解决所有这三个问题。您只需根据需要从磁盘读取数据,并以合理紧凑且易于处理的形式存储。但对于前两个来说,它不是最好的解决方案,只是一个非常好的"之一。

特别是,如果您确实需要跨所有350000行进行数组范围的工作,并且无法将该工作转换为SQL查询,那么您将无法从sqlite中获得更多好处。最终,你将会做一个巨大的SELECT来获取所有数据,然后将它们全部处理成一个大框架。

写出形状和结构信息,然后以NumPy二进制形式编写底层数组。然后,为了阅读,你必须扭转它。 NumPy的二进制形式只是尽可能紧凑地存储原始数据,它是一种可以快速写入的格式(它基本上只是将原始内存存储器转储到磁盘上)。这将改善第一和第二个问题。

同样,将数据存储在HDF5中(使用Pandas IO或外部库如PyTables或h5py)将改善第一和第二个问题。 HDF5设计为一种相当紧凑和简单的格式,用于存储您通常存储在Pandas中的相同类型的数据。 (它包括可选的压缩作为内置功能,所以如果你知道你有哪两个,你可以调整它。)它不会像最后一个选项那样解决第二个问题,但可能好吧,它更简单(一旦你设置了你的HDF5库)。

最后,腌制数据有时可能会更快。 pickle是Python的本机序列化格式,并且它可以被第三方模块连接 - 而NumPy和Pandas都联系了它以便在搜索数据方面做得相当不错。

(虽然这不适用于此问题,但可能有助于稍后搜索:如果您使用的是Python 2.x,请务必明确使用pickle format 2; IIRC,NumPy是在默认的pickle格式为0时非常糟糕。在Python 3.0+中,这并不相关,因为默认格式至少为3.)

答案 1 :(得分:0)

Python有two built-in libraries名为picklecPickle,可以存储任何Python数据结构。 cPicklepickle完全相同,只是cPickle在使用Unicode时出现问题并且速度提高了1000倍。 两者都非常方便用于保存以某种形式重新加载到Python中的内容,因为您不必担心文件I / O中会出现某种错误。

在处理了大量XML文件之后,我发现加载pickle而不是原始XML会带来一些性能提升。我不完全确定性能与CSV相比如何,但值得一试,特别是如果您不必担心Unicode内容并且可以使用cPickle。它也很简单,所以如果它不是一个足够好的提升,你可以用最少的时间去继续使用其他方法。

一个简单的用法示例:

>>> import pickle
>>> stuff = ["Here's", "a", "list", "of", "tokens"]
>>> fstream = open("test.pkl", "wb")
>>> pickle.dump(stuff,fstream)
>>> fstream.close()
>>> 
>>> fstream2 = open("test.pkl", "rb")
>>> old_stuff = pickle.load(fstream2)
>>> fstream2.close()
>>> old_stuff
["Here's", 'a', 'list', 'of', 'tokens']
>>> 

注意" b"在文件流开放器中。这很重要 - 它保留了泡菜的跨平台兼容性。我之前未能做到这一点并让它回来困扰我。

对于你的东西,我建议编写第一个解析CSV并将其保存为pickle的脚本;当你进行分析时,与之关联的脚本会加载pickle,就像那里的第二个代码块一样。

我用XML尝试过这个;我很好奇你将通过CSV获得多大的提升。

答案 2 :(得分:0)

如果问题在于处理开销,那么您可以将文件分成较小的文件并在不同的CPU核心或线程中处理它们。同样对于某些算法,python时间将非线性地增加,并且分割方法将在这些情况下有所帮助。