数据科学/机器学习中如何应对超大型数据集的处理


说明

在数据科学领域,python应当是目前最为常用的开发语言。由于数据分析、机器学习大部分时间基本在处理数据集,对于一般大小的数据文件,采用pandas读取基本已经足够。但若一个数据集大小达到1G甚至10G,pandas读取就显得效率太低,变得不再实用。

那么有哪些应对大数据集的提速处理方式呢?本文从以下两个角度说明几种提供数据处理速度的方式:

  • 相较pandas,python中提速方式
  • 采用c++处理数据,实现提速

pandas read_csv

数据科学中,典型的结构化数据存储形式为csv格式,通常是用pandas来对其进行操作:

df_data = pd.read_csv(r'data/df_data.csv')
df_data.info()

image

一般情况下,我们所处理的单个csv文件大小不会超过100M。pandas基本可以较快地对其进行读取和操作。但当达到几个G的大小时,pandas直接处理就显得力不从心。速度慢是一方面,若文件太大,内存可能都无法读入全部的数据,比如下图所示:

image

下面说明几种提速方式,并给出相应的用法。

python 中的提速方式

pandas read_csv的chunksize字段

chunks = pd.read_csv(r'data/df_data.csv', chunksize=5000)
df_data = pd.concat(chunks)
df_data.info()

image
可以看到,通过增加chunksize字段,读取时间反而有所上升。这是由于chunksize的大小影响了读取的速度,因此,要想通过这一字段提速,前提是能够选择合适大小的chunksize,否则反而对读取效率产生负面影响。

pandas read_csv的engine字段

df_data = pd.read_csv(r'data/df_data.csv', engine='c')
df_data.info()

image

可以看到,通过将读取csv的后端引擎更改为C语言,读取效率有明显提升。

dask dataframe

dask是由google主导开发的适用于大数据集的pandas替代方案。一直以来,spark在大数据分析领域占据主导领域,近年来,之前采用spark的用户也在开始切换到dask上来。另外,同时存在一些其他的处理方案,比如RayVaex。在使用覆盖面上,dask是被使用最多的,。Ray是由Berkeley主导开发的,Vaex主要是由荷兰的程序员和数据科学家开发的。初看各家发展生态,dask应当是更胜一筹。

dask本身主要存在两点优势:

  • 并行化:相较于pandas单核处理数据,dask可以进行多线程并行处理数据;
  • delayed计算:dask采用一种lazy的方式,对数据进行处理。所谓的lazy计算,是以仅保存计算流程图的方式,记录计算目标的计算流程。但并不执行计算本身。只有需要获取计算目标结果时,通过compute()来执行整个计算流程,获得输出结果。

其用法如下:

import dask.dataframe as dd

data = dd.read_csv(r'data/output/df_data.csv')
df_data = data.compute()
df_data.info()

image

可以看到,相比于pandas直接读取,dask读取整个数据集所需时间降低了1/3,是提速表现最好的。

通过c++进行数据处理提速

前面我们看到,通过python处理一个数据集,将其保存到一个numpy array对象中,该对象大小达到9G。无法将其保存为dataframe对象写入到本地csv文件中,也无法通过numpy、pickle写入到本地。原因都是太占内存(MemoryError)。如果无法将其保存到本地,那么目标数据就无法持久化,也就降低了重复使用性。

既然无法直接通过python将该对象存储到本地文件中,此时想出了下面的解决办法:

  • 先将numpy array对象转换为list对象,然后通过python将该list对象写入到本地txt。出乎意料的是,python将这么大的对象写入到txt的速度出奇的快,9个G大小的list对象,写入到本地txt完成所花时间不到30s;
    with open(r'all_vals.txt', 'w', encoding="utf-8") as fp:
        for item in contents:
            fp.write("%s\n" % item)
  • 通过c++将该txt文件准换为csv文件。c++本身作为基础编程语言,在效率上一直是其最大的优势:
    string file_name = "all_vals.txt";
    string nfile_name = "all_vals.csv";
    
    ifstream in(file_name);
    string line;
    
    ofstream textfile;
    textfile.open(nfile_name);
    
    const char* bom = "\xef\xbb\xbf"; // 写入csv,需要加上bom头,否则写入中文乱码
    textfile << bom;
    
    while (getline(in, line)) // line中没有换行符
    {
        string ss = line.substr(1,line.length() - 2);          
        textfile << ss << endl;
    }
    将2个多G的txt文件重新写入到csv文件,所需时间为5分钟左右。整体而言,通过转换思路,并借助于python之外的开发语言,使我们的数据开发效率得到很大的提升。

小结

  • 在应对csv大数据集的读取上,采用dask能够显著提高效率,这也是最终我们采取的数据集处理方式
  • 当涉及大数据集的读取写入时,可以采用c++来完成我们的数据准备工作。

文章作者: 安立广
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 安立广 !
  目录