我需要从一个大文件中创建一个Pandas DataFrame,该文件具有空格分隔值和依赖于列数的行结构。
原始数据如下所示:
2008231.0 4891866.0 383842.0 2036693.0 4924388.0 375170.0
在一行或几行中,会忽略换行符。
如果列数为3,则最终结果如下所示:
[(u'2008231.0', u'4891866.0', u'383842.0'),
(u'2036693.0', u'4924388.0', u'375170.0')]
将文件拆分成行取决于文件元部分中声明的列数。
目前,我将文件拆分为一个大清单并将其拆分为行:
def grouper(n, iterable, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
(代码来自itertools示例)
问题是,我最终在内存中存储了多个数据副本。使用500MB以上的文件可以快速占用内存,而Pandas在使用大型MultiIndexes读取这些大的列表时会遇到一些麻烦。
如何使用此类数据使用Pandas文件读取功能(read_csv,read_table,read_fwf)?
还是有其他方法可以在没有辅助数据结构的情况下将数据读入Pandas吗?
答案 0 :(得分:1)
虽然可以创建一个类似自定义文件的对象,但与pd.read_table
的正常用法相比,这将非常慢:
import pandas as pd
import re
filename = 'raw_data.csv'
class FileLike(file):
""" Modeled after FileWrapper
http://stackoverflow.com/a/14279543/190597 (Thorsten Kranz)
"""
def __init__(self, *args):
super(FileLike, self).__init__(*args)
self.buffer = []
def next(self):
if not self.buffer:
line = super(FileLike, self).next()
self.buffer = re.findall(r'(\S+\s+\S+\s+\S+)', line)
if self.buffer:
line = self.buffer.pop()
return line
with FileLike(filename, 'r') as f:
df = pd.read_table(f, header=None, delimiter='\s+')
print(len(df))
当我尝试在5.8M文件(包含200000行)上使用FileLike
时,上述代码需要3.9秒才能运行。
如果我改为预处理数据(将每行分成2行并将结果写入磁盘):
import fileinput
import sys
import re
filename = 'raw_data.csv'
for line in fileinput.input([filename], inplace = True, backup='.bak'):
for part in re.findall(r'(\S+\s+\S+\s+\S+)', line):
print(part)
然后您可以使用pd.read_table
with open(filename, 'r') as f:
df = pd.read_table(f, header=None, delimiter='\s+')
print(len(df))
重写文件所需的时间约为0.6秒,现在加载DataFrame需要约0.7秒。
因此,您最好先将数据重写到磁盘上。
答案 1 :(得分:0)
我认为没有办法用与列相同的分隔符分隔行。
在使用reshape
创建系列之后,解决此问题的一种方法是read_csv
(这很可能是副本而不是视图,以保持数据连续):
s = pd.read_csv(file_name, lineterminator=' ', header=None)
df = pd.DataFrame(s.values.reshape(len(s)/n, n))
在你的例子中:
In [1]: s = pd.read_csv('raw_data.csv', lineterminator=' ', header=None, squeeze=True)
In [2]: s
Out[2]:
0 2008231
1 4891866
2 383842
3 2036693
4 4924388
5 375170
Name: 0, dtype: float64
In [3]: pd.DataFrame(s.values.reshape(len(s)/3, 3))
Out[3]:
0 1 2
0 2008231 4891866 383842
1 2036693 4924388 375170