如何处理大型而不是大数据的数据集?

SomePhDStudentGuy

我有一个约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

在此处输入图片说明

我结合使用分块数据集和估计。

绩效陷阱

  • 尽可能 避免嵌套循环。另一个循环中的每个循环将复杂度乘以n
  • 只要有可能, 就一次性处理数据。每次循环都增加了n的复杂度
  • 如果您的数据采用csv格式,请避免使用预制函数,因为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时,可以将数据加载到数据库中。
数据库是为容纳大量数据而设计的,您可以期望获得很高的性能。
与原始数据相比,数据库可能会占用更多的磁盘空间。这就是为什么我不再使用数据库的原因之一。

硬件优化

如果您的代码进行了优化,则瓶颈很可能是硬盘驱动器的吞吐量。

  • 如果数据适合您的本地硬盘驱动器,请在本地使用它,因为这将消除网络延迟(在本地网络中,每条记录的想象时间为2-5毫秒,在远程位置中为10-100毫秒)。
  • 使用现代硬盘。1TB的NVME SSD如今的价格约为130美元(英特尔600p 1TB)。nvme ssd使用pcie,比普通ssd快约5倍,比普通硬盘快50倍,尤其是在快速写入不同位置(分块数据)时。近年来,SSD的容量已大大增加,对于这样的任务,这将是野蛮的。

以下屏幕截图提供了在同一台机器上使用相同数据进行张量流训练的性能比较。在标准ssd上本地保存一次,在本地网络(普通硬盘)上的网络连接存储上一次保存。
在此处输入图片说明
在此处输入图片说明

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章