python 获取值错误:使用scikit learn的LabelEncoder时y包含新标签

vsmadaxz  于 2022-11-27  发布在  Python
关注(0)|答案(9)|浏览(236)

我有一个系列像:

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'值。模型应该学习从训练数据集中给定“High”和“Low”的特征。例如,当有多个条目具有相同BankNum和不同ID时,下面的“High”是给定的。

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)
yrwegjxp

yrwegjxp1#

我认为错误信息非常清楚:测试数据集包含定型数据集中尚未包含的ID标签。对于这些项,LabelEncoder找不到合适的数值来表示。有几种方法可以解决此问题。您可以尝试平衡数据集,以便确保每个标签不仅出现在测试中,而且出现在定型数据中。否则,您可以尝试遵循here中的一个思路。
一个可能的解决方案是,在开始时搜索数据集,获得所有唯一ID值的列表,在此列表上训练LabelEncoder,并保持代码的其余部分与当前相同。
另一个可能的解决方案是,检查测试数据是否只有在训练过程中看到的标签。如果有新标签,你必须将其设置为某个后备值,如unknown_id(或类似的值)。这样做,你将所有新的、未知的ID放在一个类中;对于这些项,预测将失败,但是您可以使用代码的其余部分。

368yc8dk

368yc8dk2#

你可以尝试解决方案从“sklearn.LabelEncoder与从未见过的值”https://stackoverflow.com/a/48169252/9043549的事情是创建字典与类,比Map列和填充新的类与一些“已知值”

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)
ltskdhd1

ltskdhd13#

如果您的数据是pd.DataFrame,我建议您这个简单的解决方案...
我建立了一个自定义的转换器,它可以对每个分类特征进行整数Map。当它被安装后,你可以转换所有你想要的数据。你也可以计算简单的标签编码或onehot编码。

如果新数据中存在新的未显示类别或NaN:
**1]**对于标签编码,0是为Map这些情况而保留的特殊标记。
**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
cwdobuhd

cwdobuhd4#

当处理DataFrames时,我能够更好地在大脑中处理运算。下面的方法使用训练数据拟合和转换LabelEncoder(),然后使用一系列pd.merge连接将训练过的拟合/转换编码器值Map到测试数据。当训练数据中没有测试数据值时,代码默认为最大训练编码器值+ 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
cu6pst1q

cu6pst1q5#

我找到了一个简单的破解方法来解决这个问题。
假设X是特征的 Dataframe ,
1.首先,我们需要创建一个字典列表,其中的键是从0开始的可迭代项,对应的值对是分类列名。
cat_cols_enum = list(enumerate(X.select_dtypes(include = ['O']).columns))
1.然后,想法是创建标签编码器的列表,其维度等于 Dataframe X中存在的定性(分类)列的数量。
le = [LabelEncoder() for i in range(len(cat_cols_enum))]
1.接下来也是最后一个部分将是使编码器列表中存在的每个标签编码器分别与字典列表中存在的每个分类列的唯一值相匹配。
for i in cat_cols_enum: le[i[0]].fit(X[i[1]].value_counts().index)
现在,我们可以使用以下代码将标签转换为各自的编码:

for i in cat_cols_enum:
X[i[1]] = le[i[0]].transform(X[i[1]])
gdx19jrr

gdx19jrr6#

transform函数获取LabelEncoder尝试编码的任何新值时会出现此错误,因为在训练样本中,当您使用fit_transform时,该特定值并不存在于语料库中。因此,有一个黑客,是否使用fit_transform函数的所有唯一值,如果您确定没有新值会进一步到来,或者尝试一些适合问题陈述的不同编码方法,如HashingEncoder
下面是测试中没有新值的示例

le_id.fit_transform(list(set(df['ID'].unique()).union(set(new_df['ID'].unique())))) 
new_df['ID'] = le_id.transform(new_df.ID)
bvjveswy

bvjveswy7#

这实际上是LabelEncoder上的一个已知错误:BUG for fit_transform...基本上你必须拟合它,然后转换。它会工作得很好!一个建议是保持你的编码器字典的每一列,以便在逆转换中,你能够检索原始的分类值。

nhn9ugyo

nhn9ugyo8#

我希望这对一些人有帮助,因为它是最近的。
sklearn使用fit_transform执行fit函数和transform函数,针对标签编码。要解决Y标签对看不见的值抛出错误的问题,用途:

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

这就解决了!

qlvxas9a

qlvxas9a9#

我以前

le.fit_transform(Col)

我能够解决这个问题。它确实适合和转换两者。我们不需要担心测试分割中的未知值

相关问题