管道预测 X 的形状与拟合期间的形状不同

Pipeline predict X has a different shape than during fitting

我遇到了这个我明白意思但不知道如何处理的错误。

我是这样做的:

class PreProcessing(BaseEstimator, TransformerMixin):
  def __init__(self):
    pass

  def transform(self, df):

   #Here i select the features and transform them for exemple:
   age_band=0
   if age<=10
     age_band=1
   else #... etc to 90
     age_band=9
   ....
   other feature engineering
   ....
   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 self

pipe = 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("The model has been loaded...doing predictions now...")
predictions = loaded_model.predict(df)

我收到错误:ValueError:X 的形状与拟合期间的形状不同。

我的理解是,并非所有模态都在我的 "real file" 上表示,因为想象一下在我的火车文件中,我有 "couple" 列,其值 "yes, no, I don't know" 然后是 ce.BinaryEncoder 将创建将所有模态存储为二进制所需的尽可能多的列。 但是在我必须做出预测的现实生活文件中,我只有这些列 "couple" 值 "yes, no" 所以最后,X 的形状与拟合期间的形状不同...... 所以我唯一要做的就是在 PreProcessing 中创建所有缺失的模态,cols 值为 0...

我想我错过了什么。

注:训练和测试文件来自某个数据源。我需要预测的数据来自其他来源,所以我首先 "transform" 将那些真实数据转换为相同的 X_train/Test 格式,然后我执行 model.predit(df)。所以我确定 before BinaryEncoder 我在 Preprocessing.transform() 上有相同数量的 cols (17) 但是 after BinaryEncoder 执行如果我记录 df 的形状,而 运行 model.predict(X_test) 它显示 df 是 41 列,而在 model.predict(realData) 上只有 31 列。

这似乎是您的 "feature selection/creation" 流程的问题。每次将一组新的输入传递到您的管道时,您都会重新安装 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):
    # ...
    # No fitting, just transform
    df = self.encoder.transform(df)
    return df

更好的是,您能否将 BinaryEncoder 插入您的管道,而将其完全排除在 PreProcessing 之外?

pipe = make_pipeline(PreProcessing(),
                     BinaryEncoder(cols=selectedCols),
                     SelectKBest(f_classif,k=23),
                     RandomForestClassifier())