有效地将CSV转换为NumPy NPY

izj3ouym  于 2022-11-10  发布在  其他
关注(0)|答案(5)|浏览(380)

如何将.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中。

Q(Part 1):对于大型CSV文件,有没有办法高效地将.csv加载/转换为.npy

上面的代码片段类似于Convert CSV to numpy的答案,但它不适用于~12M x 1024矩阵。

Q(第2部分):如果没有办法高效地将.csv加载/转换成.npy,有没有办法高效地迭代地将.csv文件读入.npy

另外,https://stackoverflow.com/a/53558856/610569给出了迭代地将CSV文件保存为NumPy数组的答案。但在读取文件时,np.vstack似乎不是最佳解决方案。公认的答案是hdf5,但格式不是这个问题的主要目标,在我的用例中也不需要hdf5格式,因为之后我必须将其读回一个数字数组中。

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

还有另一个库tensorstore似乎可以有效地处理在读取时支持转换为NumPy数组的数组,即https://google.github.io/tensorstore/python/tutorial.html。但不知何故,没有任何关于如何在没有确切维度的情况下保存tensor/数组的信息,所有的示例似乎都包括像'dimensions': [1000, 20000],这样的配置。
与HDF5不同,tensorstore在从文档转换为NumPy时似乎不存在读取开销问题:
转换为numpy.ndarray还隐式地执行同步读取(由于刚刚检索到相同的区域,因此会命中内存中的缓存)

55ooxyrt

55ooxyrt1#

问得好;本身就很有见地。
我知道您希望将整个数据集/数组最终作为NumPy数组存储在内存中。那么,我假设您有足够的(RAM)内存来存放这样的阵列--12Mx1K。
我不知道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内存。

I/O文本

考虑到您确实拥有托管整个NumPy数组所需的所有(RAM)内存:然后我将遍历整个(大约1200万行)文本文件,逐行填充先前存在的数组。
更准确地说,我应该在开始读取文件之前示例化(大)数组。只有这样,我才会读取每一行,拆分列,并将其赋给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?),以便--如果FUN在谈判桌上--并行阅读它们,如果那个时间是关键的话。
希望这能帮上忙。

nhaq1z21

nhaq1z212#

TL;DR

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

读取数据并进行处理(Kinda Answer Q Part下)

要处理超过RAM可以处理的数据量,通常会求助于执行“核外”计算的库,例如turicreate.SFramevaexdask。这些库将能够延迟地将.csv文件加载到 Dataframe 中,并在评估时按块处理它们。

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数组(有点答问第一部分)

虽然核外库可以高效地读取和处理数据,但将其转换为NumPy是一项“内存中”的操作,机器需要有足够的RAM来容纳所有数据。
turicreate.SFrame.to_numpy文档写道:
将此SFrame转换为Numy数组
此操作将在内存中构造一个Numy数组。当返回的对象很大时,必须小心。
vaex文档写道:
内存中数据表示法
可以从各种内存中的数据表示构造Vaex DataFrame。
dask最佳实践实际上重新实现了它们自己的数组对象,这些数组对象比NumPy数组更简单,请参阅https://docs.dask.org/en/stable/array-best-practices.html。但在浏览文档时,他们保存Dask数组的格式似乎不是.npy,而是各种其他格式。

将文件写入非.npy版本(回答QPart 3)

考虑到NumPy数组不可避免地在内存中,尝试将数据保存到一个.npy中不是最可行的选择。
不同的库似乎有不同的存储解决方案。例如。

  • 如果在通过vaex.from_csv()读取数据时设置了convert=True参数,则vaex默认情况下将数据保存到hdf5
  • sframe将数据保存为自己的二进制格式
  • daskexport functions保存to_hdf()to_parquet()
iklwldmw

iklwldmw3#

它的最新版本(4.14)VAEX支持“流”,即CSV文件的延迟加载。它在引擎盖下使用了箭,所以晚餐很快。试试像这样的东西

df = vaex.open(my_file.csv)

# or

df = vaex.from_csv_arrow(my_file.csv, lazy=True)

然后,您可以根据需要导出为多种格式,或者继续使用它(它的速度快得令人惊讶)。当然,最好是转换成某种二进制格式。

wwwo4jvm

wwwo4jvm4#

import numpy as np
import pandas as pd

# Define the input and output file names

csv_file = 'data.csv'
npy_file = 'data.npy'

# Create dummy data

data = np.random.rand(10000, 100)
df = pd.DataFrame(data)
df.to_csv(csv_file, index=False)

# Define the chunk size

chunk_size = 1000

# Read the header row and get the number of columns

header = pd.read_csv(csv_file, nrows=0)
num_cols = len(header.columns)

# Initialize an empty array to store the data

data = np.empty((0, num_cols))

# Loop over the chunks of the csv file

for chunk in pd.read_csv(csv_file, chunksize=chunk_size):
    # Convert the chunk to a numpy array
    chunk_array = chunk.to_numpy()
    # Append the chunk to the data array
    data = np.append(data, chunk_array, axis=0)

np.save(npy_file, data)

# Load the npy file and check the shape

npy_data = np.load(npy_file)
print('Shape of data before conversion:', data.shape)
print('Shape of data after conversion:', npy_data.shape)```
ruarlubt

ruarlubt5#

我不知道有任何现有的函数或实用程序可以直接高效地将CSV文件转换为NPY文件。我猜,高效的主要意思是内存需求低。
迭代地编写NPY文件确实是可能的,只需付出一些额外的努力。上已经有一个问题,所以这就解决了这个问题,请参见:save numpy array in append mode
例如,使用Michael's answer中的NpyAppendArray类,您可以执行以下操作:

with open('data.csv') as csv, NpyAppendArray('data.npy') as npy:
    for line in csv:
        row = np.fromstring(line, sep=',')
        npy.append(row[np.newaxis, :])

NpyAppendArray类在每次调用append时更新NPY文件头,这对于您的1200万行来说有点多了。也许您可以将类更新为(可选)仅在close上写入头。或者,您也可以轻松地批量写入:

batch_lines = 128
with open('data.csv') as csv, NpyAppendArray('data.npy') as npy:
    done = False
    while not done:
        batch = []
        for count, line in enumerate(csv):
            row = np.fromstring(line, sep=',')
            batch.append(row)
            if count + 1 >= batch_lines:
                break
        else:
            done = True
        npy.append(np.array(batch))

(代码未经过测试)

相关问题