【问题标题】:Python: One-hot encoding for huge dataPython:大数据的一键编码
【发布时间】:2025-12-19 13:00:10
【问题描述】:

我在尝试将 字符串标签 编码为 one-hot 编码时不断遇到内存问题。大约有 500 万行和大约 10000 个不同的标签。我尝试了以下方法,但不断收到内存错误:

from sklearn import preprocessing
lb = preprocessing.LabelBinarizer()
label_fitter = lb.fit(y)
y = label_fitter.transform(y)

我也试过这样的:

import numpy as np

def one_hot_encoding(y):
    unique_values = set(y)
    label_length = len(unique_values)
    enu_uniq = zip(unique_values , range(len(unique_values)))
    dict1 = dict(enu_uniq)
    values = []
    for i in y:
        temp = np.zeros((label_length,), dtype="float32")
        if i in dict1:
            temp[dict1[i]] = 1.0
        values.append(temp)
    return np.array(values)

仍然出现内存错误。任何提示?堆栈中有一些人在问同样的问题,但没有答案似乎有用。

【问题讨论】:

    标签: python one-hot-encoding


    【解决方案1】:

    您的主要问题似乎是二进制化的y 不适合您的记忆。您可以使用稀疏数组来避免这种情况。

    >>> import numpy as np
    >>> from scipy.sparse import csc_matrix
    >>> y = np.random.randint(0, 10000, size=5000000) # 5M random integers [0,10K)
    

    您可以将这些标签y 转换为5M x 10K 稀疏矩阵,如下所示:

    >>> dtype = np.uint8 # change to np.bool if you want boolean or other data type
    >>> rows = np.arange(y.size) # each of the elements of `y` is a row itself
    >>> cols = y # `y` indicates the column that is going to be flagged
    >>> data = np.ones(y.size, dtype=dtype) # Set to `1` each (row,column) pair
    >>> ynew = csc_matrix((data, (rows, cols)), shape=(y.size, y.max()+1), dtype=dtype)
    

    ynew 是一个稀疏矩阵,其中每一行都是零,除了一个条目:

    >>> ynew
    <5000000x10000 sparse matrix of type '<type 'numpy.uint8'>'
         with 5000000 stored elements in Compressed Sparse Column format>
    

    你必须调整你的代码来学习如何处理稀疏矩阵,但这可能是你最好的选择。此外,您可以从稀疏矩阵中恢复完整的行或列:

    >>> row0 = ynew[0].toarray() # row0 is a standard numpy array
    

    对于字符串标签或任意数据类型的标签:

    >>> y = ['aaa' + str(i) for i in np.random.randint(0, 10000, size=5000000)] # e.g. 'aaa9937'
    

    首先提取从标签到整数的映射:

    >>> labels = np.unique(y) # List of unique labels
    >>> mapping = {u:i for i,u in enumerate(labels)}
    >>> inv_mapping = {i:u for i,u in enumerate(labels)} # Only needed if you want to recover original labels at some point
    

    上述mapping 将每个标签映射到一个整数(基于它们存储在唯一集合labels 中的顺序)。

    然后再次创建稀疏矩阵:

    >>> N, M = len(y), labels.size
    >>> dtype = np.uint8 # change np.bool if you want boolean
    >>> rows = np.arange(N)
    >>> cols = [mapping[i] for i in y]
    >>> data = np.ones(N, dtype=dtype)
    >>> ynew = csc_matrix((data, (rows, cols)), shape=(N, M), dtype=dtype)
    

    如果将来您想知道label X 映射到哪个原始标签,您可以创建(尽管不是必需的)逆映射:

    >>> inv_mapping = {i:u for i,u in enumerate(labels)}
    >>> inv_mapping[10] # ---> something like 'aaaXXX'
    

    【讨论】:

    • 我真的很喜欢你处理这个问题的方式。不幸的是,这并不意味着字符串标签。
    • @MpizosDimitris 查看编辑。第二个版本现在可以通过映射(和逆映射)处理任何类型的标签数据类型。
    【解决方案2】:

    在提出问题时这可能不可用,但 LabelBinarizer 采用 sparse_output 参数。

    from sklearn.preprocessing import LabelBinarizer
    
    lb = LabelBinarizer(sparse_output=True)
    

    【讨论】: