由于尺寸的原因,我需要在块中阅读一些非常棒的文件。
我想对这些文件执行groupby然后执行一个函数。
问题是,如果chunksize是50 000
并且某个组存在于行49998-50002
,则该组将被拆分为两个;第一个块中的一个组,第二个块中的另一个组。有没有办法解决组块之间存在的组的问题?
我能提出的所有解决方案都感觉un-Pandaish
所以也许我应该通过两次阅读来解决这个问题。
答案 0 :(得分:2)
我知道没有开箱即用的功能,但是你可以自己动手:
remainder = pd.DataFrame()
for filename in filenames: # 1
for chunk in pd.read_csv(filename, index_col=[0], chunksize=300): # 2
grouped = chunk.groupby(['group'])
for grp, nextgrp in iwindow(grouped, 2): # 3
group_num, df = grp # 4
if nextgrp is None:
# When nextgrp is None, grp is the last group
remainder = pd.concat([remainder, df]) # 5
break # 6
if len(remainder): # 7
df = pd.concat([remainder, df])
remainder = pd.DataFrame()
print(filename)
process(df) # 8
if len(remainder): # 9
process(remainder)
chunksize=300
告诉read_csv
以300字节的块读取文件。我为下面的例子做了一些小事。您可以增加此值以在每次迭代时读取更多文件。 iwindow
是一个滑动窗口实用程序功能。它一次返回grouped
两个项目。例如,
In [117]: list(iwindow([1,2,3], 2))
Out[117]: [(1, 2), (2, 3), (3, None)]
df
是一个具有常量group
值(等于group_num
)的DataFrame。
remainder
。remainder
包含一些未经处理的DataFrame,请将其添加到df
df
remainder
可能会保留最后一个未经处理的DataFrame。所以现在就处理它。当您需要以块的形式读取文件但根据其他一些分隔符处理块时,此处使用的一般概念非常有用。 基本上是same idea is used here将文件分成由正则表达式模式分隔的块。
例如,
import itertools as IT
import numpy as np
import pandas as pd
def make_data(groupsize, ngroups, filenames):
nfiles = len(filenames)
group_num = np.repeat(np.arange(ngroups), groupsize)
arr = np.random.randint(10, size=(len(group_num), 2))
arr = np.column_stack([group_num, arr])
for arri, filename in zip(np.array_split(arr, nfiles), filenames):
df = pd.DataFrame(arri, columns=['group','A','B'])
df.to_csv(filename)
def iwindow(iterable, n=2, fillvalue=None):
"""
Returns a sliding window (of width n) over data from the sequence.
s -> (s0,s1,...s[n-1]), (s1,s2,...,sn), ...
"""
iterables = IT.tee(iterable, n)
iterables = (IT.islice(it, pos, None) for pos, it in enumerate(iterables))
for result in IT.izip_longest(*iterables, fillvalue=None):
yield result
def process(df):
print(df)
print('-'*80)
filenames = ['/tmp/data-{}.csv'.format(i) for i in range(3)]
make_data(groupsize=40, ngroups=5, filenames=filenames)
remainder = pd.DataFrame()
for filename in filenames:
for chunk in pd.read_csv(filename, index_col=[0], chunksize=300):
grouped = chunk.groupby(['group'])
for grp, nextgrp in iwindow(grouped, 2):
group_num, df = grp
if nextgrp is None:
# When nextgrp is None, grp is the last group
remainder = pd.concat([remainder, df])
break
if len(remainder):
df = pd.concat([remainder, df])
remainder = pd.DataFrame()
print(filename)
process(df)
if len(remainder):
process(remainder)