读取大型 csv 文件、python、pandas 的随机行

Posted

技术标签:

【中文标题】读取大型 csv 文件、python、pandas 的随机行【英文标题】:Reading random rows of a large csv file, python, pandas 【发布时间】:2016-11-09 01:52:55 【问题描述】:

您能帮帮我吗,我遇到了在 Windows(8 Gb RAM)上使用 0.18.1 pandas 和 2.7.10 Python 从大型 csv 文件中读取随机行的问题。

在Read a small random sample from a big CSV file into a Python data frame 我看到了一种方法,但是,我的 PC 非常消耗内存,即部分代码:

n = 100
s = 10
skip = sorted(rnd.sample(xrange(1, n), n-s))# skip n-s random rows from *.csv       
data = pd.read_csv(path, usecols = ['Col1', 'Col2'], 
                   dtype  = 'Col1': 'int32', 'Col2':'int32', skiprows = skip)

所以,如果我想从文件中取出一些随机行,不仅考虑 100 行,而且考虑 100 000 行,这变得很难,但是从文件中不取出随机行几乎没问题:

skiprows = xrange(100000)    
data = pd.read_csv(path, usecols = ['Col1', 'Col2'], 
                   dtype  = 'Col1': 'int32', 'Col2':'int32', skiprows = skip, nrows = 10000)

所以问题是我如何处理使用熊猫从大型 csv 文件中读取大量随机行,即因为我无法读取整个 csv 文件,即使对它进行分块,我对随机行完全感兴趣. 谢谢

【问题讨论】:

我认为关于这个问题的大部分讨论都是相关的。简而言之,没有一个不是内存密集型的好解决方案。 ***.com/questions/38039723/… skiprows 使用大量内存,请尝试与块一起使用:***.com/questions/36874993/… 如果您访问这些链接之一并发现它们有用,请尽可能为它们投票。您需要 15 声望才能投票。你现在有 6 个。 【参考方案1】:

如果内存是最大的问题,一个可能的解决方案可能是使用块,并从块中随机选择

n = 100
s = 10
factor = 1    # should be integer
chunksize = int(s/factor)

reader = pd.read_csv(path, usecols = ['Col1', 'Col2'],dtype  = 'Col1': 'int32', 'Col2':'int32', chunksize=chunksize)

out = []
tot = 0
for df in reader:
    nsample = random.randint(factor,chunksize)
    tot += nsample
    if  tot > s:
        nsample = s - (tot - nsample)
    out.append(df.sample(nsample))
    if tot >= s:
        break

data = pd.concat(out)

您可以使用 factor 来控制块的大小。

【讨论】:

一个问题是这种方法并不是真正随机的,因为您强制从每个块中进行选择。例如,有可能,尽管不可能,随机选择 n 个项目是前 n 个项目,而分块方法不承认这种可能性。但是,您也可以争辩说,这种方法对于大多数需要随机选择的情况来说已经足够了。 没错。我编辑了答案以考虑到这一点,其中每个块的样本数量是随机的。但是,仍然需要注意的是,每个块至少需要“因子”样本,才能在到达文件末尾之前获得所需数量的样本。要真正随机,需要考虑多次循环文件的可能性。 谢谢,是的,确实,我相信这也是出路:随机选择块并从中随机选择行,并以迭代的方式进行此操作。它看起来比 skiprows 选项需要更少的内存。【参考方案2】:

我认为这比此处显示的其他方法更快,可能值得一试。

假设,我们已经在列表skipped 中选择了要跳过的行。首先,我将其转换为查找布尔表。

# Some preparation:
skipped = np.asarray(skipped)
# MAX >= number of rows in the file
bool_skipped = np.zeros(shape(MAX,), dtype=bool)
bool_skipped[skipped] = True

主要内容:

from io import StringIO
# in Python 2 use
# from StringIO import StringIO

def load_with_buffer(filename, bool_skipped, **kwargs):
    s_buf = StringIO()
    with open(filename) as file:
        count = -1
        for line in file:
            count += 1
            if bool_skipped[count]:
                continue
            s_buf.write(line)
    s_buf.seek(0)
    df = pd.read_csv(s_buf, **kwargs)
    return df

我测试如下:

df = pd.DataFrame(np.random.rand(100000, 100))
df.to_csv('test.csv')

df1 = load_with_buffer('test.csv', bool_skipped, index_col=0)

跳过了 90% 的行。它的性能与

相当
pd.read_csv('test.csv', skiprows=skipped, index_col=0)

并且比使用 dask 或分块读取快大约 3-4 倍。

【讨论】:

以上是关于读取大型 csv 文件、python、pandas 的随机行的主要内容,如果未能解决你的问题,请参考以下文章

使用 Pandas 读取大型文本文件 [重复]

如何读取非常大的 CSV 的一小部分行。 Pandas - 时间序列 - 大型数据集

Python,pandas.read_csv 来自 Google Drive 文件的 1000 万行大型 csv 文件

使用pandas处理大型CSV文件

使用 python 和 pandas 将错误创建的大型 csv 文件转换为制表符分隔文件

连接大型 CSV 文件中单词的最有效方法:pandas 还是 Python 标准库? [复制]