我有一个约200亿个约15亿个观测值的数据集,我需要在该数据集上进行一些条件分析和数据聚合*。
事实是,我不习惯(也不训练)处理大型数据集。我通常使用R或Python(侧面有一些Julia),当我无法将数据集放入内存时,我会完全迷失。
人们如何处理这些适合磁盘但不适合内存的数据集?我应该从哪里开始寻找解决方案?是否有集中大型而非大型数据集上的信息的地方?
*长话短说,我有另一个数据集(适合内存),对于这个小型数据集的每一行,我想计算大型数据集中符合小型条件中某些条件的观测次数。我最初的反应是分批运行代码,但这效率很低,并且需要几个世纪的单处理器计算时间。
由于已经特别询问过,因此我将描述文件的结构。
我有一个大文件,让我们称之为BIG,其中有两个ID变量,分别是$ ID0 $和$ ID1 $,以及一个日期变量$ date1 $。
我有一个小文件,叫我们SMALL,有两个ID变量$ ID2 $和$ ID3 $和一个日期变量$ date2 $。
对于每个$ ID2_i $,我想计算所有观察值,以便$ \ {ID0 = ID2_i,date1 <date2_i,ID1 = ID2_j | j:ID3_j = ID3_i \上限date2_j <date2_i \} $
有不同的方法
分块可让您简化许多操作,例如洗牌等等。
确保每个子集/块代表整个数据集。每个块文件应具有相同数量的行。
可以通过在一行文件之后追加一行来完成。很快,您将意识到打开每个文件并写一行是低效率的。特别是在同一驱动器上读写时。
->添加适合内存的读写缓冲区。
选择适合您需求的块大小。我选择此特定大小是因为我的默认文本编辑器仍然可以相当快地打开它。
较小的块可以提高性能,尤其是在您想要获取类分配之类的指标时,因为您只需要遍历一个代表性文件来获得整个数据集的估计就足够了。
较大的块文件确实可以更好地表示每个文件中的整个数据集,但是您也可以只浏览x个较小的块文件。
我之所以使用c#,是因为我在那里经验丰富,因此可以使用完整的功能集,例如将任务拆分reading / processing / writing
到不同的线程上。
如果您有使用python或r的经验,我怀疑也应该有类似的功能。在如此庞大的数据集上,并行化可能是一个巨大的因素。
块数据集可以建模为一个交错数据集,您可以使用张量处理单元进行处理。这可能会产生最佳性能,并且可以在本地以及大型计算机上的云中执行。但这需要对张量流进行大量学习。
而不是像all_of_it = file.read()
您想使用某种流读取器那样做。以下函数逐行读取一个块文件(或整个300gb数据集),以计算文件中的每个类。通过一次处理一行,您的程序将不会溢出内存。
您可能需要添加一些进度指示,例如X行/秒或X MBb,以便估算总处理时间。
def getClassDistribution(path):
classes = dict()
# open sample file and count classes
with open(path, "r",encoding="utf-8",errors='ignore') as f:
line = f.readline()
while line:
if line != '':
labelstring = line[-2:-1]
if labelstring == ',':
labelstring = line[-1:]
label = int(labelstring)
if label in classes:
classes[label] += 1
else:
classes[label] = 1
line = f.readline()
return classes
我结合使用分块数据集和估计。
绩效陷阱
cells = int(line.Split(',')[8])
这将很快导致内存吞吐量瓶颈。getClassDistribution
在我只想获得标签的地方可以找到一个适当的例子。以下C#函数可将csv行快速拆分为多个元素。
// Call function
ThreadPool.QueueUserWorkItem((c) => AnalyzeLine("05.02.2020,12.20,10.13").Wait());
// Parralelize this on multiple cores/threads for ultimate performance
private async Task AnalyzeLine(string line)
{
PriceElement elementToAdd = new PriceElement();
int counter = 0;
string temp = "";
foreach (char c in line)
{
if (c == ',')
{
switch (counter)
{
case 0:
elementToAdd.spotTime = DateTime.Parse(temp, CultureInfo.InvariantCulture);
break;
case 1:
elementToAdd.buyPrice = decimal.Parse(temp);
break;
case 2:
elementToAdd.sellPrice = decimal.Parse(temp);
break;
}
temp = "";
counter++;
}
else temp += c;
}
// compare the price element to conditions on another thread
Observate(elementToAdd);
}
处理类似数据的csv时,可以将数据加载到数据库中。
数据库是为容纳大量数据而设计的,您可以期望获得很高的性能。
与原始数据相比,数据库可能会占用更多的磁盘空间。这就是为什么我不再使用数据库的原因之一。
如果您的代码进行了优化,则瓶颈很可能是硬盘驱动器的吞吐量。
以下屏幕截图提供了在同一台机器上使用相同数据进行张量流训练的性能比较。在标准ssd上本地保存一次,在本地网络(普通硬盘)上的网络连接存储上一次保存。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句