python - 在 pandas.read_csv() 中使用自定义对象

标签 python python-3.x pandas

我有兴趣将自定义对象流式传输到 pandas 数据框中。根据the documentation ,可以使用任何具有 read() 方法的对象。但是,即使在实现此功能后,我仍然会收到此错误:

ValueError: Invalid file path or buffer object type: <class '__main__.DataFile'>

这是对象的简单版本,以及我如何调用它:

class DataFile(object):
    def __init__(self, files):
        self.files = files

    def read(self):
        for file_name in self.files:
            with open(file_name, 'r') as file:
                for line in file:
                    yield line

import pandas as pd
hours = ['file1.csv', 'file2.csv', 'file3.csv']

data = DataFile(hours)
df = pd.read_csv(data)

我是不是遗漏了什么,或者只是无法在 Pandas 中使用自定义生成器?当我调用 read() 方法时,它工作正常。

编辑: 我想使用自定义对象而不是将数据帧连接在一起的原因是看是否可以减少内存使用。我用过 gensim库,它使使用自定义数据对象变得非常容易,所以我希望找到一些类似的方法。

最佳答案

在 Python3 中通过子类化 io.RawIOBase 创建类文件对象的一种方法. 并使用 Mechanical snail's iterstream , 你可以将任何可迭代的字节转换成类文件对象:

import tempfile
import io
import pandas as pd

def iterstream(iterable, buffer_size=io.DEFAULT_BUFFER_SIZE):
    """
    http://stackoverflow.com/a/20260030/190597 (Mechanical snail)
    Lets you use an iterable (e.g. a generator) that yields bytestrings as a
    read-only input stream.

    The stream implements Python 3's newer I/O API (available in Python 2's io
    module).

    For efficiency, the stream is buffered.
    """
    class IterStream(io.RawIOBase):
        def __init__(self):
            self.leftover = None
        def readable(self):
            return True
        def readinto(self, b):
            try:
                l = len(b)  # We're supposed to return at most this much
                chunk = self.leftover or next(iterable)
                output, self.leftover = chunk[:l], chunk[l:]
                b[:len(output)] = output
                return len(output)
            except StopIteration:
                return 0    # indicate EOF
    return io.BufferedReader(IterStream(), buffer_size=buffer_size)


class DataFile(object):
    def __init__(self, files):
        self.files = files

    def read(self):
        for file_name in self.files:
            with open(file_name, 'rb') as f:
                for line in f:
                    yield line

def make_files(num):
    filenames = []
    for i in range(num):
        with tempfile.NamedTemporaryFile(mode='wb', delete=False) as f:
            f.write(b'''1,2,3\n4,5,6\n''')
            filenames.append(f.name)
    return filenames

# hours = ['file1.csv', 'file2.csv', 'file3.csv']
hours = make_files(3)
print(hours)
data = DataFile(hours)
df = pd.read_csv(iterstream(data.read()), header=None)

print(df)

打印

   0  1  2
0  1  2  3
1  4  5  6
2  1  2  3
3  4  5  6
4  1  2  3
5  4  5  6

关于python - 在 pandas.read_csv() 中使用自定义对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46310030/

相关文章:

python - 如何在 iPython QtConsole (Anaconda) 中删除数据框显示的边框?

python - 复杂数据框的多级 Pandas 迭代

python - 如何将 str 转换为 bytes

python - Pandas 无法打开路径中带有变音符号的文件

python - 使用 yield from 时协程在哪个事件循环中运行?

python - 计算几种条件下的 T/F 值

python - pyqt QObject : Cannot create children for a parent that is in a different thread

python - 如何从父方法引用子类?

python - 将向量数组与矩阵数组相乘;返回向量数组?

python - 如何使用 Python 创建漂亮的 UI