我在日常工作中使用SAS,它的核心支持非常棒。然而,SAS作为一款软件,由于许多其他原因而很糟糕。

有一天,我希望用python和pandas来取代我对SAS的使用,但我目前缺乏用于大型数据集的核心工作流。我不是在谈论需要分布式网络的“大数据”,而是那些大到无法装入内存,但又小到可以装入硬盘的文件。

我的第一个想法是使用HDFStore将大型数据集保存在磁盘上,只将我需要的数据块放入数据框架中进行分析。其他人提到MongoDB是一种更容易使用的替代方案。我的问题是:

完成以下任务的最佳实践工作流程是什么:

将平面文件加载到永久的磁盘数据库结构中 查询该数据库以检索数据以输入pandas数据结构 在操作熊猫的碎片后更新数据库

现实世界的例子将非常受欢迎,尤其是那些在“大数据”上使用熊猫的人。

编辑—我希望这样工作的一个例子:

迭代地导入一个大型平面文件,并将其存储在一个永久的磁盘数据库结构中。这些文件通常太大,无法装入内存。 为了使用Pandas,我希望读取这些数据的子集(通常一次只有几列),这些子集可以放入内存中。 我将通过对所选列执行各种操作来创建新列。 然后,我必须将这些新列追加到数据库结构中。

我正在努力寻找执行这些步骤的最佳实践方法。阅读关于熊猫和pytables的链接,似乎添加一个新列可能是一个问题。

编辑——具体回答杰夫的问题:

I am building consumer credit risk models. The kinds of data include phone, SSN and address characteristics; property values; derogatory information like criminal records, bankruptcies, etc... The datasets I use every day have nearly 1,000 to 2,000 fields on average of mixed data types: continuous, nominal and ordinal variables of both numeric and character data. I rarely append rows, but I do perform many operations that create new columns. Typical operations involve combining several columns using conditional logic into a new, compound column. For example, if var1 > 2 then newvar = 'A' elif var2 = 4 then newvar = 'B'. The result of these operations is a new column for every record in my dataset. Finally, I would like to append these new columns into the on-disk data structure. I would repeat step 2, exploring the data with crosstabs and descriptive statistics trying to find interesting, intuitive relationships to model. A typical project file is usually about 1GB. Files are organized into such a manner where a row consists of a record of consumer data. Each row has the same number of columns for every record. This will always be the case. It's pretty rare that I would subset by rows when creating a new column. However, it's pretty common for me to subset on rows when creating reports or generating descriptive statistics. For example, I might want to create a simple frequency for a specific line of business, say Retail credit cards. To do this, I would select only those records where the line of business = retail in addition to whichever columns I want to report on. When creating new columns, however, I would pull all rows of data and only the columns I need for the operations. The modeling process requires that I analyze every column, look for interesting relationships with some outcome variable, and create new compound columns that describe those relationships. The columns that I explore are usually done in small sets. For example, I will focus on a set of say 20 columns just dealing with property values and observe how they relate to defaulting on a loan. Once those are explored and new columns are created, I then move on to another group of columns, say college education, and repeat the process. What I'm doing is creating candidate variables that explain the relationship between my data and some outcome. At the very end of this process, I apply some learning techniques that create an equation out of those compound columns.

我很少向数据集中添加行。我几乎总是会创建新的列(统计/机器学习术语中的变量或特征)。


当前回答

如果您选择创建数据管道的简单路径,将其分解为多个较小的文件,可以考虑Ruffus。

其他回答

我认为上面的答案遗漏了一个我认为非常有用的简单方法。

当我有一个文件太大而无法在内存中加载时,我将该文件分解为多个较小的文件(按行或cols)

例如:如果有30天的交易数据,大小约为30GB,我将其分解为每天大小约为1GB的文件。我随后分别处理每个文件,并在最后汇总结果

最大的优点之一是它允许并行处理文件(多线程或多线程)。

另一个优点是文件操作(如示例中的添加/删除日期)可以通过常规shell命令完成,这在更高级/复杂的文件格式中是不可能的

这种方法并不能覆盖所有的场景,但是在很多场景中都非常有用

如果您的数据集在1到20GB之间,那么您应该使用具有48GB RAM的工作站。然后Pandas可以将整个数据集保存在RAM中。我知道这不是你想要的答案,但是在一个有4GB内存的笔记本电脑上进行科学计算是不合理的。

值得一提的是,雷, 这是一个分布式计算框架,它以分布式的方式对pandas有自己的实现。

只需替换pandas导入,代码应该像这样工作:

# import pandas as pd
import ray.dataframe as pd

# use pd as usual

详情请点击此处:

https://rise.cs.berkeley.edu/blog/pandas-on-ray/


更新: 处理熊猫分布的部分,已经提取到modin项目。

现在正确的用法是:

# import pandas as pd
import modin.pandas as pd

我发现这一点有点晚,但我也处理过类似的问题(抵押贷款提前支付模型)。我的解决方案是跳过pandas HDFStore层,直接使用pytable。在最终文件中,我将每一列保存为单独的HDF5数组。

我的基本工作流程是首先从数据库中获得一个CSV文件。我把它压缩了,所以它不那么大。然后我将其转换为一个面向行的HDF5文件,方法是在python中遍历它,将每一行转换为真正的数据类型,并将其写入HDF5文件。这需要几十分钟,但它不使用任何内存,因为它只是逐行操作。然后我将面向行的HDF5文件“转置”为面向列的HDF5文件。

表的转置是这样的:

def transpose_table(h_in, table_path, h_out, group_name="data", group_path="/"):
    # Get a reference to the input data.
    tb = h_in.getNode(table_path)
    # Create the output group to hold the columns.
    grp = h_out.createGroup(group_path, group_name, filters=tables.Filters(complevel=1))
    for col_name in tb.colnames:
        logger.debug("Processing %s", col_name)
        # Get the data.
        col_data = tb.col(col_name)
        # Create the output array.
        arr = h_out.createCArray(grp,
                                 col_name,
                                 tables.Atom.from_dtype(col_data.dtype),
                                 col_data.shape)
        # Store the data.
        arr[:] = col_data
    h_out.flush()

然后读取它看起来是这样的:

def read_hdf5(hdf5_path, group_path="/data", columns=None):
    """Read a transposed data set from a HDF5 file."""
    if isinstance(hdf5_path, tables.file.File):
        hf = hdf5_path
    else:
        hf = tables.openFile(hdf5_path)

    grp = hf.getNode(group_path)
    if columns is None:
        data = [(child.name, child[:]) for child in grp]
    else:
        data = [(child.name, child[:]) for child in grp if child.name in columns]

    # Convert any float32 columns to float64 for processing.
    for i in range(len(data)):
        name, vec = data[i]
        if vec.dtype == np.float32:
            data[i] = (name, vec.astype(np.float64))

    if not isinstance(hdf5_path, tables.file.File):
        hf.close()
    return pd.DataFrame.from_items(data)

现在,我通常在内存很大的机器上运行这个程序,所以我可能对内存使用不够小心。例如,默认情况下,load操作读取整个数据集。

这通常适用于我,但它有点笨重,我不能使用华丽的pytables魔法。

编辑:与pytables默认的记录数组相比,这种方法的真正优势在于,我可以使用h5r将数据加载到R中,而h5r不能处理表。或者,至少,我无法让它加载异构表。

拼花文件格式非常适合您所描述的用例。使用pd可以有效地读入列的特定子集。Read_parquet (path_to_file, columns=["foo", "bar"])

https://pandas.pydata.org/docs/reference/api/pandas.read_parquet.html