【问题标题】:More memory efficient method to one hot encode columns - Python 3.6.x一个热编码列的内存效率更高的方法 - Python 3.6.x
【发布时间】:2021-02-10 19:23:45
【问题描述】:

我有一种方法,可以对来自 pandas 数据帧的列列表进行热编码并删除原始列。虽然这对某些领域非常有效,但对于其他领域来说,这个过程需要非常长的时间。例如,我目前正在研究一个高度分类的数据集(即超过 80 个分类特征),其中单个特征将我带入超过 100,000 维度。

我正在寻找一种更优化、内存效率更高的例程来对高维数据进行一次热编码。

以下是我目前的做法:

# For each column to encode
for col in encode_cols:
    col_name = str(col)
    if col not in ('PRICE_AMOUNT', 'CHECKSUM_VALUE'):
        old_cols = df.shape[1]
        print("Now testing: {}".format(col_name))
        # Use pandas get_dummies function
        temp = pd.get_dummies(df[col], prefix=col_name, prefix_sep='_')
        df.drop(col, axis=1, inplace=True)
        df = pd.concat([df, temp], axis=1, join='inner')
        print("New Size: {}".format(df.shape))
        sizes[col] = df.shape[1] - old_cols
    else:
        continue
    
    del(temp)
    gc.collect()

就我而言,encode_cols 只有大约 75 个元素,但向量在完成时从 100 维度变为 107,000。如何优化此例程?

【问题讨论】:

  • 编码的目的是什么?你期待使用什么模型?你试过sklearns OneHotEncoder吗?
  • 一个热编码数据自然会输入模型@AndreS.,我和我的团队将找出给定结果的确切技术。我知道高维的诅咒,我们有解决这个问题的技术,但考虑到我们的业务问题,这就是我们需要表示数据的方式。
  • 好的,根据您使用的模型,您还可以使用标签编码来避免所有额外的列。缺点是当类别得到排名时,您不能对线性模型使用标签编码。另一方面,基于树的模型可以很好地处理标签编码的特征。

标签: python pandas optimization encoding


【解决方案1】:

我建议使用 scikit-learn 的 OneHotEncoder 工具。

from sklearn.preprocessing import OneHotEncoder

features_to_one_hot = ['feature1','feature2']
to_one_hot_df = df.loc[:,features_to_one_hot]

categorical_encoder = OneHotEncoder()
new_one_hot = cat_encoder.fit_transform(to_one_hot_df)

如果您希望编码器执行更具体的操作,Scikit-learn 使用鸭子类型。这意味着您可以实现自己的类。在这里,我展示了如何为编码器制作一个以删除旧列:

from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.preprocessing import OneHotEncoder


class OneHotAndDrop(BaseEstimator, TransformerMixin):
    def __init__(self, operate=True):
        self.operate = operate

    def fit(self, X, y=None):
        return self

    def transform(self, X):

        if self.operate:
            old_columns = list(X.columns)
            new_one_hot = OneHotEncoder().fit_transform(X)
            X = new_one_hot.drop(old_columns, axis=1)
            
        return X

one_hot_costum = OneHotAndDrop()
new_one_hot = one_hot_costum.fit_transform(to_one_hot_df)

然后您可以像在第一个示例中那样使用这个类。 此方法使用稀疏矩阵,它很可能比您的原始函数更有效,并且会自动命名新功能。

此外,根据您需要对它们进行编码的原因,对它们进行热编码可能不是最好的主意。如果是用于机器学习,这将产生太多的特征并且可能会过拟合。我建议先将它们分组,然后对它们进行分类以减少新功能的数量。

【讨论】:

  • 感谢您的回答。编码将与 ML 项目相关,但业务需求就是这样。即使是为了表现。但是,这与问题无关。此外,这会破坏 prefix 值的命名方案。将它与我们的某些模型一起使用时,我也会遇到错误。
【解决方案2】:

如果无法访问您的数据,我无法为您提供完全可用的代码,尽管这是我的想法。在处理非常稀疏的二进制特征时,可以使用稀疏矩阵,这是一种聪明(并且非常节省内存)的数据存储方式。

然后,您可以使用sklearn 中的OneHotEncoder(如here 所述)生成单热编码的稀疏分类特征。因此,在您的情况下,您必须计算每个分类特征 - 所有级别,并使用它来编码稀疏向量。

vec = OneHotEncoder(n_values=n_of_levels_among_all_features)
X = vec.fit_transform(level_ids_data)
 
X.toarray() # To get it back to an "normal" nd-array.

然后您可以按照here 的描述使用hstack,以便将密集特征(PRICE_AMOUNTCHECKSUM_VALUE)与稀疏特征合并。

from scipy.sparse import hstack

X = hstack((sparse_ohe_categorical_features, dense_features), format='csr')

X 现在是一个稀疏矩阵,包含您的所有数据。根据用例更改格式csr。例如,使用来自sklearn 的逻辑回归,稀疏矩阵必须采用csr 格式才能使拟合方法起作用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-14
    • 2017-09-24
    • 1970-01-01
    • 2020-06-18
    • 2014-05-06
    • 2011-01-24
    • 2016-09-11
    相关资源
    最近更新 更多