获取 ValueError:y 在使用 scikit learn 的 LabelEncoder 时包含新标签

Posted

技术标签:

【中文标题】获取 ValueError:y 在使用 scikit learn 的 LabelEncoder 时包含新标签【英文标题】:Getting ValueError: y contains new labels when using scikit learn's LabelEncoder 【发布时间】:2018-02-27 12:50:45 【问题描述】:

我有一个类似的系列:

df['ID'] = ['ABC123', 'IDF345', ...]

我正在使用 scikit 的 LabelEncoder 将其转换为数值以输入到 RandomForestClassifier

在训练期间,我做的事情如下:

le_id = LabelEncoder()
df['ID'] = le_id.fit_transform(df.ID) 

但是,现在为了测试/预测,当我传入新数据时,我想根据le_id 转换来自该数据的“ID”,即,如果存在相同的值,则根据上述标签编码器进行转换,否则分配一个新的数值。

在测试文件中,我是这样做的:

new_df['ID'] = le_dpid.transform(new_df.ID)

但是,我收到以下错误:ValueError: y contains new labels

我该如何解决这个问题?谢谢!

更新:

所以我的任务是使用以下(例如)作为训练数据并预测新 BankNum、ID 组合的 'High', 'Mod', 'Low' 值。模型应该从训练数据集中学习给出“高”和“低”的特征。例如,当有多个具有相同 BankNum 和不同 ID 的条目时,会在下方给出“高”。

df = 

BankNum   | ID    | Labels

0098-7772 | AB123 | High
0098-7772 | ED245 | High
0098-7772 | ED343 | High
0870-7771 | ED200 | Mod
0870-7771 | ED100 | Mod
0098-2123 | GH564 | Low

然后预测它:

BankNum   |  ID | 

00982222  | AB999 | 
00982222  | AB999 |
00981111  | AB890 |

我正在做这样的事情:

df['BankNum'] = df.BankNum.astype(np.float128)

    le_id = LabelEncoder()
    df['ID'] = le_id.fit_transform(df.ID)

X_train, X_test, y_train, y_test = train_test_split(df[['BankNum', 'ID'], df.Labels, test_size=0.25, random_state=42)
    clf = RandomForestClassifier(random_state=42, n_estimators=140)
    clf.fit(X_train, y_train)

【问题讨论】:

【参考方案1】:

我认为错误信息非常明确:您的测试数据集包含未包含在您的训练数据集中的ID 标签。对于此项,LabelEncoder 找不到合适的数值来表示。有几种方法可以解决这个问题。您可以尝试平衡您的数据集,以确保每个标签不仅存在于您的测试中,还存在于您的训练数据中。否则,您可以尝试遵循here 提出的想法之一。

其中一个可能的解决方案是,您在开始时搜索数据集,获取所有唯一 ID 值的列表,在此列表中训练 LabelEncoder,并将其余代码保留为就在此刻。

另一种可能的解决方案是,检查测试数据是否只有在训练过程中看到的标签。如果有新标签,则必须将其设置为一些后备值,例如 unknown_id(或类似的东西)。这样做,你把所有新的、未知的IDs 放在一个类中;对于这些项目,预测将失败,但您可以像现在一样使用其余代码。

【讨论】:

请阅读我的问题中的更新,我已经添加了我想要做的事情。我需要模型能够根据从训练数据中学到的特征来预测新的 ID 值。如果我将它们保留为 unknown_id,那么整个目的将失败。【参考方案2】:

您可以尝试“sklearn.LabelEncoder 中从未见过的值”https://***.com/a/48169252/9043549 的解决方案 问题是用类创建字典,而不是映射列并用一些“已知值”填充新类

from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
suf="_le"
col="a"
df[col+suf] = le.fit_transform(df[col])
dic = dict(zip(le.classes_, le.transform(le.classes_)))
col='b'
df[col+suf]=df[col].map(dic).fillna(dic["c"]).astype(int) 

【讨论】:

【参考方案3】:

我用过

       le.fit_transform(Col) 

我能够解决这个问题。它确实适合并改变了两者。我们不需要担心测试拆分中的未知值

【讨论】:

【参考方案4】:

如果你的数据是pd.DataFrame我建议你这个简单的解决方案...

我构建了一个自定义转换器,它可以整数映射每个分类特征。安装后,您可以转换所需的所有数据。您还可以计算简单的标签编码或 onehot 编码。

如果新数据中出现新的未见类别或 NaN:

1]对于标签编码,0 是为映射这些情况而保留的特殊标记。

2] 对于 onehot 编码,在这些情况下,所有 onehot 列都为零。

class FeatureTransformer:
    
    def __init__(self, categorical_features):
        self.categorical_features = categorical_features
        
    def fit(self, X):

        if not isinstance(X, pd.DataFrame):
            raise ValueError("Pass a pandas.DataFrame")
            
        if not isinstance(self.categorical_features, list):
            raise ValueError(
                "Pass categorical_features as a list of column names")
                    
        self.encoding = 
        for c in self.categorical_features:

            _, int_id = X[c].factorize()
            self.encoding[c] = dict(zip(list(int_id), range(1,len(int_id)+1)))
            
        return self

    def transform(self, X, onehot=True):

        if not isinstance(X, pd.DataFrame):
            raise ValueError("Pass a pandas.DataFrame")

        if not hasattr(self, 'encoding'):
            raise AttributeError("FeatureTransformer must be fitted")
            
        df = X.drop(self.categorical_features, axis=1)
        
        if onehot:  # one-hot encoding
            for c in sorted(self.categorical_features):            
                categories = X[c].map(self.encoding[c]).values
                for val in self.encoding[c].values():
                    df["_".format(c,val)] = (categories == val).astype('int16')
        else:       # label encoding
            for c in sorted(self.categorical_features):
                df[c] = X[c].map(self.encoding[c]).fillna(0)
            
        return df

用法:

X_train = pd.DataFrame(np.random.randint(10,20, (100,10)))
X_test = pd.DataFrame(np.random.randint(20,30, (100,10)))

ft = FeatureTransformer(categorical_features=[0,1,3])
ft.fit(X_train)

ft.transform(X_test, onehot=False).shape

【讨论】:

【参考方案5】:

在处理DataFrames 时,我能够更好地处理操作。下面的方法使用训练数据拟合和转换LabelEncoder(),然后使用一系列pd.merge 连接将经过训练的拟合/转换编码器值映射到测试数据。当有训练数据中没有看到的测试数据值时,代码默认为最大训练编码器值+1。

# encode class values as integers
import numpy as np
import pandas as pd
from sklearn.preprocessing import LabelEncoder
encoder = LabelEncoder()
encoder.fit(y_train)
encoded_y_train = encoder.transform(y_train)

# make a dataframe of the unique train values and their corresponding encoded integers
y_map = pd.DataFrame('y_train': y_train, 'encoded_y_train': encoded_y_train)
y_map = y_map.drop_duplicates()

# map the unique test values to the trained encoded integers
y_test_df = pd.DataFrame('y_test': y_test)
y_test_unique = y_test_df.drop_duplicates()
y_join = pd.merge(y_test_unique, y_map, 
                  left_on = 'y_test', right_on = 'y_train', 
                  how = 'left')

# if the test category is not found in the training category group, then make the 
# value the maximum value of the training group + 1                  
y_join['encoded_y_test'] = np.where(y_join['encoded_y_train'].isnull(), 
                                    y_map.shape[0] + 1, 
                                    y_join['encoded_y_train']).astype('int')

encoded_y_test = pd.merge(y_test_df, y_join, on = 'y_test', how = 'left') \
    .encoded_y_test.values

【讨论】:

【参考方案6】:

我希望这对最近的人有所帮助。

sklearn 使用 fit_transform 执行针对标签编码的拟合函数和变换函数。 要解决未见值的 Y 标签抛出错误的问题,请使用:

from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()     
le.fit_transform(Col) 

这样就解决了!

【讨论】:

以上是关于获取 ValueError:y 在使用 scikit learn 的 LabelEncoder 时包含新标签的主要内容,如果未能解决你的问题,请参考以下文章

ValueError:分类报告的未知标签类型

ValueError:在Python中创建KMeans模型时x和y的大小必须相同

绘制图像的傅立叶变换时出现问题。 “ValueError:x 和 y 不能大于 2-D,但具有 (2592,) 和 (2592, 1, 3) 形状”

ValueError: 时间数据 '' 与格式 '%Y-%m-%d %H:%M' 不匹配

ValueError:x 和 y 必须具有相同的第一维,但具有形状

Python机器学习库sciki-earn实践