【发布时间】:2015-08-06 16:06:41
【问题描述】:
问题:我将数据存储在 csv 文件中,其中包含以下列 data/id/value。我有 15 个文件,每个文件包含大约 10-20mio 行。每个 csv 文件涵盖一个不同的时期,因此时间索引不重叠,但列是(新的 id 不时输入,旧的消失)。我最初所做的是在没有枢轴调用的情况下运行脚本,但后来我在本地机器上遇到了内存问题(只有 8GB)。由于每个文件中有很多冗余,pivot 起初似乎是一个不错的出路(大约减少 2/3 数据),但现在性能开始发挥作用。如果我运行以下脚本,concat 函数将“永远”运行(我总是打断一段时间后手动到目前为止(2h>))。 Concat/append 似乎在大小方面有限制(我大约有 10000-20000 列),或者我在这里错过了什么?有什么建议吗?
import pandas as pd
path = 'D:\\'
data = pd.DataFrame()
#loop through list of raw file names
for file in raw_files:
data_tmp = pd.read_csv(path + file, engine='c',
compression='gzip',
low_memory=False,
usecols=['date', 'Value', 'ID'])
data_tmp = data_tmp.pivot(index='date', columns='ID',
values='Value')
data = pd.concat([data,data_tmp])
del data_tmp
编辑 I:澄清一下,每个 csv 文件有大约 10-20mio 行和三列,在应用透视后,这减少到大约 2000 行,但导致 10000 列。
我可以通过简单地将完整的 id 集拆分为子集并基于每个子集运行所需的计算来解决内存问题,因为它们对于每个 id 都是独立的。我知道这让我重新加载相同的文件 n 次,其中 n 是使用的子集的数量,但这仍然是合理的快。我仍然想知道为什么 append 没有执行。
编辑二:我试图通过模拟重新创建文件结构,它尽可能接近实际的数据结构。我希望很清楚,我没有花太多时间最小化模拟时间,但它在我的机器上运行得相当快。
import string
import random
import pandas as pd
import numpy as np
import math
# Settings :-------------------------------
num_ids = 20000
start_ids = 4000
num_files = 10
id_interval = int((num_ids-start_ids)/num_files)
len_ids = 9
start_date = '1960-01-01'
end_date = '2014-12-31'
run_to_file = 2
# ------------------------------------------
# Simulation column IDs
id_list = []
# ensure unique elements are of size >num_ids
for x in range(num_ids + round(num_ids*0.1)):
id_list.append(''.join(
random.choice(string.ascii_uppercase + string.digits) for _
in range(len_ids)))
id_list = set(id_list)
id_list = list(id_list)[:num_ids]
time_index = pd.bdate_range(start_date,end_date,freq='D')
chunk_size = math.ceil(len(time_index)/num_files)
data = []
# Simulate files
for file in range(0, run_to_file):
tmp_time = time_index[file * chunk_size:(file + 1) * chunk_size]
# TODO not all cases cover, make sure ints are obtained
tmp_ids = id_list[file * id_interval:
start_ids + (file + 1) * id_interval]
tmp_data = pd.DataFrame(np.random.standard_normal(
(len(tmp_time), len(tmp_ids))), index=tmp_time,
columns=tmp_ids)
tmp_file = tmp_data.stack().sortlevel(1).reset_index()
# final simulated data structure of the parsed csv file
tmp_file = tmp_file.rename(columns={'level_0': 'Date', 'level_1':
'ID', 0: 'Value'})
# comment/uncomment if pivot takes place on aggregate level or not
tmp_file = tmp_file.pivot(index='Date', columns='ID',
values='Value')
data.append(tmp_file)
data = pd.concat(data)
# comment/uncomment if pivot takes place on aggregate level or not
# data = data.pivot(index='Date', columns='ID', values='Value')
【问题讨论】:
-
如果你在一个循环中追加或连接(并且循环是不可避免的),你至少应该将
data_tmp追加到一个列表中,然后在循环之后一次性连接它们@ 987654324@ -
在这种情况下不会产生很大的性能影响,我认为问题的出现是因为数据框的大小(col 和 row 维度)
-
它会(因为它会阻止复制不断增长的数据帧 15 次),如果它能够运行由于内存。但我并没有完全关注那里。你说你有 15 倍的 10-20mio 行和 10000-20000 列,这怎么可能适合 8GB 内存? (快速计算表明至少在 TB 中)
-
为了清楚起见,原始的 csv 文件大约有 10mio 行和 3 列。然后 Pivot 通过将日期/id 信息唯一地存储在行和列索引中来减少冗余。然而,它最终有大约 10000-20000 列。
-
当我只附加两个更大的透视表时,问题实际上已经出现了。如果我在一个列表中收集这两个数据帧(如建议的那样),连接它们然后只旋转它是相当快的(由于内存限制,不能对完整的文件列表执行此操作),但是如果我首先旋转每个表然后附加/连接它未定义地运行。