我遇到了这个错误,我理解它的含义,但不知道如何处理它。
这是我所做的:
class PreProcessing(BaseEstimator, TransformerMixin): def __init__(self): pass def transform(self, df): #在这里我选择特征并进行转换,例如: age_band=0 if age<=10 age_band=1 else #... 到90岁 age_band=9 .... 其他特征工程 .... encoder = ce.BinaryEncoder(cols=selectedCols) encoder.fit(df) df = encoder.transform(df) return df.as_matrix() def fit(self, df, y=None, **fit_params): return selfpipe = make_pipeline(PreProcessing(), SelectKBest(f_classif,k=23), RandomForestClassifier())param_grid = {"randomforestclassifier__n_estimators" : [100,400], "randomforestclassifier__max_depth" : [None], "randomforestclassifier__max_leaf_nodes": [2,3,5], "randomforestclassifier__min_samples_leaf":[3,5,8], "randomforestclassifier__class_weight":['balanced'], "randomforestclassifier__n_jobs":[-1] }grid_search = GridSearchCV(pipe,param_grid,cv=5,scoring='recall',verbose=1,n_jobs=15)X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)grid_search.fit(X_train,y_train)grid_search.predict(X_test)filename = 'myModel.pk'with open(filename, 'wb') as file: pickle.dump(grid_search, file)
所以在这种情况下,一切都运行得很顺利。但在实际数据上(不是训练测试文件):
modelfile = 'MyModel.pk'with open(modelfile,'rb') as f: loaded_model = pickle.load(f)print("模型已加载...现在进行预测...")predictions = loaded_model.predict(df)
我得到了错误:ValueError: X的形状与拟合时不同。
我理解的是,在我的“真实文件”中,并非所有模态都被表示,因为想象一下,在我的训练文件中,我有“couple”列,值为“yes, no, I don’t know”,那么ce.BinaryEncoder将创建所需的列数来以二进制形式存储所有模态。但在我的实际生活文件中,我需要进行预测的“couple”列只有“yes, no”这两个值。所以最终,X的形状与拟合时不同…所以我假设要做的唯一一件事是在PreProcessing中为所有缺失的模态创建值为0的列…
我觉得我错过了什么。
注意:训练和测试文件来自某个数据源。我需要预测的数据来自另一个源,所以我首先将这些实际数据“转换”为与X_train/Test相同的格式,然后我执行model.predict(df)。所以我确定在BinaryEncoder之前,我在Preprocessing.transform()中有相同数量的列(17),但在BinaryEncoder执行之后,如果我在运行model.predict(X_test)时记录df的形状,它显示df有41列,而在model.predict(realData)时只有31列。
回答:
这似乎是你的“特征选择/创建”过程中的一个问题。你每次向管道传递一组新的输入时,都会重新拟合一个BinaryEncoder
。这意味着每次你在指定的列中有不同数量的唯一值时,你的代码都会因为这个错误而崩溃。
我的猜测是,如果你将BinaryEncoder
作为PreProcessing
实例的一部分保存,这不会成为问题,假设你的训练数据包含了该列可能的所有值。
class PreProcessing(BaseEstimator, TransformerMixin): def __init__(self): self.encoder = ce.BinaryEncoder(cols=selectedCols) def fit(self, df, **kwargs): self.encoder.fit(df) def transform(self, df): # ... # 仅转换,不拟合 df = self.encoder.transform(df) return df
更好的是,你能否直接将BinaryEncoder插入到你的Pipeline中,完全不使用PreProcessing
?
pipe = make_pipeline(PreProcessing(), BinaryEncoder(cols=selectedCols), SelectKBest(f_classif,k=23), RandomForestClassifier())