我的数据由数值变量和分类变量组成。分类变量有很多类别,因此我使用嵌入来表示这些类别。我的模型是一个简单的神经网络。
我知道,当您定义嵌入层时,您需要传递 input_dim=number ofcategories + 1
以便考虑训练中看不见的类别。这就是我所做的。
此外,当将这些类别编码为数值以便将它们输入神经网络时,我做了以下操作:
1. 枚举训练集中中的所有唯一值并将其放入字典中。还保存一个名为 num_values
的变量,它是唯一类别的数量 + 1。
2. 对于验证集,如果该值不在字典中,那么我给它值 num_values
。
这引入了一个问题,因为当我想要评估模型(使用 model.predict()
)时,我收到如下错误:
tensorflow.python.framework.errors_impl.InvalidArgumentError: indices[0,0] = 118752 is not in [0, 118752)
这是因为我在某个变量的验证集中有一个前所未见的类别,它被映射到 num_values
,但 num_values
从未分配到训练集中的任何类别,因为字典构建是在训练集上进行的。我不知道如何解决这个问题。
我正在使用 Keras 2.3.1 和 Tensorflow 1.13.1
相关代码:
class EmbeddingMapping:
"""
An instance of this class should be defined
for each categorical variable you want to use.
"""
def __init__(self, series: pd.Series) -> None:
# get a list of unique values
values = series.unique().tolist()
# dictionary mapping
self.embedding_dict: Dict[str, int] = {value: int_value + 1 for int_value, value in enumerate(values)}
self.num_values: int = len(values) + 1 # +1 for unknown categories
def get_mapping(self, value: str) -> int:
# return value if it was seen in training
if value in self.embedding_dict:
return self.embedding_dict[value]
# else return num_values which is the same for all
# unseen values
else:
return self.num_values
# build mappings
res_dict_train: Dict[str, EmbeddingMapping] = {}
res_dict_val: Dict[str, EmbeddingMapping] = {}
for var in categorical_features:
embd_train = EmbeddingMapping(X_train_categorical[var])
temp_series_train = X_train_categorical[var].apply(embd_train.get_mapping)
temp_series_val = X_val_categorical[var].apply(embd_train.get_mapping)
res_dict_train[var] = temp_series_train
res_dict_val[var] = temp_series_val
X_train_categorical = X_train_categorical.assign(**res_dict_train)
X_val_categorical = X_val_categorical.assign(**res_dict_val)
# Keras
# Categorical vars
models_lst = []
inputs = []
for cat_feature in categorical_features:
print('---------------------------------------')
print(f'Info for categorical feature {cat_feature}')
input_i = Input(shape=(1,), dtype='int32')
inputs.append(input_i)
num_categories = EmbeddingMapping(X_train_categorical[cat_feature]).num_values
print(f"Number of categories: {num_categories}")
embedding_size = min(np.ceil(num_categories/2), 50) # rule of thumb
embedding_size = int(embedding_size)
print(f'Embedding size: {embedding_size}')
model_i = Embedding(input_dim=num_categories, output_dim=embedding_size, input_length=1, name=f'embedding_{cat_feature}')(input_i)
model_i2 = Reshape(target_shape=(embedding_size,))(model_i)
models_lst.append(model_i2)
# layer for numerical
input_numerical = Input(shape=(len(numerical_features),), dtype='float32')
numerical_model = Reshape(target_shape=(2,))(input_numerical)
models_lst.append(numerical_model)
inputs.append(input_numerical)
concatenated = concatenate(models_lst, axis=-1)
mymodel = Dense(50, activation="relu")(concatenated)
mymodel2 = Dense(15, activation="relu")(mymodel)
mymodel3 = Dense(1, activation='sigmoid')(mymodel2)
final_model = models.Model(inputs, mymodel3)
final_model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['acc', 'binary_accuracy'])
final_model.fit(x=train_input_list, validation_data=(val_input_list, y_val), y=y_train, epochs=1, batch_size=128)
当纪元结束并且模型尝试计算验证统计信息时,我收到错误。
最佳答案
用这一行:
self.embedding_dict: Dict[str, int] = {value: int_value + 1 for int_value, value in enumerate(values)}
您正在向所有整数编码添加+1,因此您将值从 [0,max_cat] 转换为 [1,max_cat+1] 并且它是正确的
但是这样做,对未见过的类别进行编码的最佳方法是使用 0,因此您必须修改:
def get_mapping(self, value: str) -> int:
# return value if it was seen in training
if value in self.embedding_dict:
return self.embedding_dict[value]
# else return 0 which is the same for all unseen values
else:
return 0
希望可以帮到你
关于python - 使用 Keras 时,验证集中未见的类别会出现错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61527381/