Python Pandas:为啥 numpy 在列分配方面比 Pandas 快得多?我可以进一步优化吗?

Posted

技术标签:

【中文标题】Python Pandas:为啥 numpy 在列分配方面比 Pandas 快得多?我可以进一步优化吗?【英文标题】:Python Pandas: Why is numpy so much faster than Pandas for column assignment? Can I optimize further?Python Pandas:为什么 numpy 在列分配方面比 Pandas 快得多?我可以进一步优化吗? 【发布时间】:2016-07-30 18:21:43 【问题描述】:

我正在通过将分类变量转换为二进制矩阵来预处理机器学习分类任务的数据,主要使用pd.get_dummies()。这应用于单个 Pandas DataFrame 列,并输出一个新的 DataFrame,其行数与原始列中唯一数量的分类变量的行数和宽度相同。

我需要为形状为:(3,000,000 x 16) 的 DataFrame 完成此操作,它输出形状为:(3,000,000 x 600) 的二进制矩阵。

在此过程中,转换为二进制矩阵pd.get_dummies() 的步骤非常快,但使用pd.DataFrame.loc[] 对输出矩阵的分配要慢得多。由于我已经切换到直接保存到np.ndarray,这快得多,我只是想知道为什么? (请查看问题底部的终端输出以进行时间比较

n.b. 正如 cmets 中所指出的,我可以在整个帧上都使用 pd.get_dummies()。但是,某些列需要定制的预处理,即:放入桶中。最难处理的列是包含一串标签的列(由,,分隔,必须这样处理:df[col].str.replace(' ','').str.get_dummies(sep=',')。另外,预处理的训练集和测试集需要相同的集合列(继承自 all_cols),因为一旦它们被分解成矩阵,它们可能就不会有相同的特征。

请查看下面每个版本的代码

DataFrame 版本:

def preprocess_df(df):
    with open(PICKLE_PATH + 'cols.pkl', 'rb') as handle:
        cols = pickle.load(handle)

    x = np.zeros(shape=(len(df),len(cols)))
    # x = pd.DataFrame(columns=all_cols)

    for col in df.columns:
        # 1. make binary matrix
        df_col = pd.get_dummies(df[col], prefix=str(col))

        print "Processed: ", col,  datetime.datetime.now()

        # 2. assign each value in binary matrix to col in output
        for dummy_col in df_col.columns:
            x.loc[:, dummy_col] = df_col[dummy_col]

        print "Assigned: ", col,  datetime.datetime.now()

    return x.values

np 版本:

def preprocess_np(df):
    with open(PICKLE_PATH + 'cols.pkl', 'rb') as handle:
        cols = pickle.load(handle)

    x = np.zeros(shape=(len(df),len(cols)))

    for col in df.columns:
        # 1. make binary matrix
        df_col = pd.get_dummies(df[col], prefix=str(col))

        print "Processed: ", col,  datetime.datetime.now()

        # 2. assign each value in binary matrix to col in output
        for dummy_col in df_col.columns:
            idx = [i for i,j in enumerate(all_cols) if j == dummy_col][0]
            x[:, idx] = df_col[dummy_col].values.T

        print "Assigned: ", col,  datetime.datetime.now()

    return x

定时输出(10,000 示例)

DataFrame 版本:

Processed:  Weekday 
Assigned:  Weekday 0.437081  
Processed:  Hour 0.002366
Assigned:  Hour 1.33815

np 版本:

Processed:  Weekday   
Assigned:  Weekday 0.006992
Processed:  Hour 0.002632
Assigned:  Hour 0.008989

是否有其他方法可以进一步优化?我很感兴趣,因为目前我正在丢弃一个可能有用的功能,因为处理额外的 15,000 列到输出太慢了。

对我所采取的方法的任何一般性建议也表示赞赏!

谢谢

【问题讨论】:

你不能在整个data.frame上使用get_dummies吗?为什么要按列应用它? 啊!有趣的问题,一些列需要定制的预处理,即:放入桶中。此外,一个特定的列处理标签列表,必须像这样处理:df[col].str.replace(' ','').str.get_dummies(sep=',')。此外,预处理的训练集和测试集需要相同的列集(继承自 all_cols),因为一旦它们被分解成矩阵,它们可能就不会有相同的特征。 @jfive 通常最好将这些输出为时间增量,对吗?所以更明显的是发生了什么。只需尝试从较早的日期中减去较晚的日期,或使用from timeit import default_timer as timer 并使用该计时器。 pd.Categorical 可能值得研究。它在数据类型中编码级别信息。对数据进行预处理以使其分类后,您可以在整个 df 上调用 pd.get_dummies。 标签列表,CountVectorizer是你的朋友! from sklearn.feature_extraction.text import CountVectorizer这是一个要点:gist.github.com/Zelazny7/c11c35aff39e775a84bdfe4ee0ad41ba 【参考方案1】:

一个实验是切换到x.loc[:, dummy_col] = df_col[dummy_col].values。如果输入是一个系列,pandas 将检查每个分配的索引顺序。如果不需要,使用 ndarray 分配会关闭它,这应该会提高性能。

【讨论】:

以上是关于Python Pandas:为啥 numpy 在列分配方面比 Pandas 快得多?我可以进一步优化吗?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 32 位和 64 位 numpy/pandas 之间存在差异

为啥 numpy 函数在 pandas 系列/数据帧上这么慢?

为啥 pandas.Series.std() 与 numpy.std() 不同?

为啥 Numpy 和 Pandas 数组比源数据消耗更多内存? [关闭]

为啥标签与 pandas、itertools 和 numpy 索引不一致?

Python:当文件在列标题中有特殊字符时,使用 Pandas 读取 Excel 文件