【问题标题】:Converting CSV to numpy NPY efficiently有效地将 CSV 转换为 numpy NPY
【发布时间】:2022-10-21 16:03:44
【问题描述】:

如何有效地将.csv 文件转换为.npy

我试过了:

import numpy as np

filename = "myfile.csv"
vec =np.loadtxt(filename, delimiter=",")
np.save(f"{filename}.npy", vec)

虽然上述文件适用于较小的文件,但我正在处理的实际 .csv 文件有大约 1200 万行和 1024 列,在转换为 .npy 格式之前将所有内容加载到 RAM 中需要很多时间。

问(第 1 部分):对于大型 CSV 文件,是否有某种方法可以有效地将 .csv 加载/转换为 .npy

上面的代码 sn-p 类似于来自Convert CSV to numpy 的答案,但不适用于~12M x 1024 矩阵。

问(第 2 部分):如果没有任何方法可以有效地将.csv 加载/转换为.npy,是否有某种方法可以有效地将.csv 文件迭代读入.npy

此外,https://stackoverflow.com/a/53558856/610569 这里有一个答案,可以将 csv 文件迭代地保存为 numpy 数组。但似乎np.vstack 不是读取文件时的最佳解决方案。那里接受的答案建议 hdf5 但格式不是这个问题的主要目标,并且在我的用例中不需要 hdf5 格式,因为之后我必须将它读回一个 numpy 数组。

Q(Part 3):如果part 1和part2都不行,那么在加载保存的存储格式时,是否还有其他高效的存储(例如tensorstore)可以存储并高效转换为numpy数组?

还有另一个库tensorstore 似乎可以有效地处理在读取时支持转换为numpy 数组的数组https://google.github.io/tensorstore/python/tutorial.html。但不知何故,没有任何关于如何在没有确切尺寸的情况下保存tensor/array 的信息,所有示例似乎都包括'dimensions': [1000, 20000], 之类的配置。

与 HDF5 不同,从 docs 转换为 numpy 时,tensorstore 似乎没有读取开销问题:

转换为 numpy.ndarray 还隐式执行同步读取(由于刚刚检索到同一区域,因此会命中内存缓存)

【问题讨论】:

标签: python numpy csv tensor feature-store


【解决方案1】:

好问题;信息本身。

我了解您希望最终将整个数据集/数组作为 NumPy 数组存储在内存中。那么,我假设您有足够的(RAM)内存来托管这样的阵列——12M x 1K。

我不具体了解np.loadtxt (genfromtxt) 是如何在幕后运作的,所以我将告诉你我是如何做(像你一样尝试之后)。

关于记忆的推理...

请注意,一个简单的布尔数组将花费大约 12 GB 的内存:

>>> print("{:.1E} bytes".format(
        np.array([True]).itemsize * 12E6 * 1024
    ))
1.2E+10 bytes

这是为了一个布尔值数据类型。很可能,你有——什么——一个整数、浮点数的数据集?大小可能会显着增加:

>>> np.array([1], dtype=bool).itemsize
1
>>> np.array([1], dtype=int).itemsize
8
>>> np.array([1], dtype=float).itemsize
8

这是很多记忆(你知道,只是想强调)。

在这一点上,我想指出一个可能的交换的工作记忆。您的机器中可能有足够的物理 (RAM) 内存,但如果不够自由的内存,您的系统将使用交换记忆(即,磁盘) 以保持您的系统稳定并完成工作。您付出的代价很明确:从磁盘读取/写入磁盘非常慢。

到目前为止我的观点是:检查数据集的数据类型,估计未来数组的大小,并保证你有最少的可用 RAM 内存。

输入输出文本

考虑到您确实拥有托管整个 numpy 数组所需的所有(RAM)内存:然后我将遍历整个(~12M 行)文本文件,逐行填充预先存在的数组。

更准确地说,我会在开始读取文件之前已经实例化(大)数组。只有这样,我才会读取每一行,拆分列,并将其提供给 np.asarray 并将这些 (1024) 值分配给输出大批。

对文件的循环很慢,是的。这里的事情是您限制(和控制)正在使用的内存量。粗略地说,消耗内存的大对象是“输出”(大)数组和“线”(1024)数组。当然,在读取(文本!)值、拆分为列表元素和转换为数组期间,临时对象中的每个循环都会消耗相当多的内存。尽管如此,在整个约 1200 万行中,它仍将基本保持不变。

所以,我会经历的步骤是

0) estimate and guarantee enough RAM memory available
1) instantiate (np.empty or np.zeros) the "output" array
2) loop over "input.txt" file, create a 1D array from each line "i"
3) assign the line values/array to row "i" of "output" array

果然,你甚至可以让它并行:如果一方面文本文件不能被随机(r/w)访问,另一方面你可以很容易地分割它们(见How can I split one text file into multiple *.txt files?)有--如果乐趣就在桌子旁——如果时间很关键,他们会并行阅读。

希望有帮助。

【讨论】:

    【解决方案2】:

    TL;博士

    除非您的机器能够按照@Brandt answer 中的描述处理内存中数据的大小,否则导出到.npy 以外的其他函数似乎是不可避免的。


    读取数据,然后处理它(有点回答 Q 第 2 部分)

    为了处理大于 RAM 可以处理的数据大小,人们通常会求助于执行“核外" 计算,例如 turicreate.SFramevaexdask 。这些库将能够将 .csv 文件延迟加载到数据帧中,并在评估时按块处理它们。

    from turicreate import SFrame
    
    filename = "myfile.csv"
    sf = SFrame.read_csv(filename)
    sf.apply(...) # Trying to process the data
    

    或者

    import vaex
    
    filename = "myfile.csv"
    df = vaex.from_csv(filename, 
        convert=True, 
        chunk_size=50_000_000)
    
    df.apply(...)
    

    将读取的数据转换为 numpy 数组(有点回答 Q 第 1 部分)

    虽然核外库可以有效地读取和处理数据,但转换为 numpy 是一个“在记忆中" 操作时,机器需要有足够的 RAM 来容纳所有数据。

    turicreate.SFrame.to_numpy 文档写道:

    将此 SFrame 转换为 numpy 数组

    此操作将在内存中构造一个 numpy 数组。当返回对象的大小很大时必须小心。

    vaex 文档写道:

    内存数据表示

    可以从各种内存数据表示中构建 Vaex DataFrame。

    dask 最佳实践实际上重新实现了他们自己的数组对象,这些对象比 numpy 数组更简单,请参阅https://docs.dask.org/en/stable/array-best-practices.html。但是在浏览文档时,他们保存 dask 数组的格式似乎不是.npy,而是各种其他格式。

    将文件写入非.npy 版本(回答 Q 第 3 部分)

    鉴于 numpy 数组不可避免地在内存中,试图将数据保存到单个 .npy 并不是最可行的选择。

    不同的库似乎有不同的存储解决方案。例如。

    • 如果通过vaex.from_csv()读取数据时设置了convert=True参数,则vaex默认将数据保存到hdf5
    • sframe 将数据保存到他们的own binary format
    • daskexport functions保存to_hdf()to_parquet()格式

    【讨论】:

      猜你喜欢
      • 2016-04-28
      • 2014-07-09
      • 2019-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-31
      • 1970-01-01
      相关资源
      最近更新 更多