【问题标题】:How to save a custom transformer in sklearn?如何在 sklearn 中保存自定义变压器?
【发布时间】:2018-02-15 02:19:12
【问题描述】:

我无法加载使用 sklearn.externals.joblib.dumppickle.dump 保存的自定义转换器的实例,因为当前 python 会话中缺少自定义转换器的原始定义。

假设在一个 python 会话中,我定义、创建并保存了一个自定义转换器,它也可以在同一个会话中加载:

from sklearn.base import TransformerMixin
from sklearn.base import BaseEstimator
from sklearn.externals import joblib

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

    def fit(self, X, y=None):
        return self

    def transform(self, X, y=None):
        return X


custom_transformer = CustomTransformer()    
joblib.dump(custom_transformer, 'custom_transformer.pkl')

loaded_custom_transformer = joblib.load('custom_transformer.pkl')

打开一个新的 python 会话并从 'custom_transformer.pkl' 加载

from sklearn.externals import joblib

joblib.load('custom_transformer.pkl')

引发以下异常:

AttributeError: module '__main__' has no attribute 'CustomTransformer'

如果将joblib 替换为pickle,也会出现同样的情况。在一个会话中保存自定义转换器

with open('custom_transformer_pickle.pkl', 'wb') as f:
    pickle.dump(custom_transformer, f, -1)

并将其加载到另一个中:

with open('custom_transformer_pickle.pkl', 'rb') as f:
    loaded_custom_transformer_pickle = pickle.load(f)

引发同样的异常。

在上面,如果CustomTransformer被替换为sklearn.preprocessing.StandardScaler,那么发现保存的实例可以在新的python会话中加载。

是否可以保存自定义转换器并稍后在其他地方加载它?

【问题讨论】:

    标签: python session scikit-learn pickle


    【解决方案1】:

    sklearn.preprocessing.StandardScaler 有效,因为类定义在 sklearn 包安装中可用,joblib 将在您加载 pickle 时查找。

    您必须通过重新定义或导入 CustomTransformer 类在新会话中可用。

    【讨论】:

    • 但是pickle模块也适用于StandardScaler,肯定不知道StandardScaler的定义吧?
    • picklejoblib 在这方面的工作方式相同。导入信息与腌制的对象一起存储,这就是为什么当您取消使用与当前安装的模块版本不同的模块制作的对象时会搞砸的原因。
    • 重新导入在我的情况下似乎不起作用,我正在导入自定义 FeatureUnion 子类。
    【解决方案2】:

    如果我在sklearn.preprocessing.FunctionTranformer() 中传递我的转换函数并且如果我使用dill.dump()dill.load 保存模型“.pk”文件,它对我有用。

    注意:我已将 transform 函数与我的分类器一起包含在 sklearn 管道中。

    【讨论】:

      【解决方案3】:

      我没有使用sklearn.externals.joblib,而只是使用joblib 模块,它可以工作:

      示例:

      from sklearn.base import BaseEstimator, TransformerMixin
      
      class CustomNgramVectorize(BaseEstimator, TransformerMixin):
          """Vectorizes texts as n-gram vectors"""
          def __init__(self, text, reduce=True):
              # Create keyword arguments to pass to the 'tf-idf' vectorizer.
              kwargs = {
                      'ngram_range': NGRAM_RANGE,  # Use 1-grams + 2-grams.
                      'dtype': 'int32',
                      'strip_accents': 'unicode',
                      'decode_error': 'replace',
                      'max_features' : 1000, #limit number of words
                      'sublinear_tf': True, # Apply sublinear tf scaling
                      'stop_words' : stopwords.words('french'),# drop french stopwords
                      'analyzer': TOKEN_MODE,  # Split text into word tokens.
                      'min_df': MIN_DOCUMENT_FREQUENCY,
              }
              self.tfidf_vectorizer = TfidfVectorizer(**kwargs)
              self.reduce = reduce
              if self.reduce:
                  self.svd = TruncatedSVD(n_components=25, n_iter=25, random_state=12)
          
          def fit(self, X, y=None):
              self.tfidf_vectorizer.fit(X)
                  
          def transform(self, X, y=None):
              X = self.tfidf_vectorizer.transform(X)
              # convert to dataframe
              X_df = pd.DataFrame(X.toarray(), columns=sorted(self.tfidf_vectorizer.vocabulary_))
              if self.reduce:
                  X_df = self.svd.fit_transform(X_df)
              return X_df
      

      然后使用joblib.dump函数保存它:

      # persist model
      import joblib
      joblib.dump(vectorizer, 'custom_tfidf_vectorizer.joblib')
      

      稍后使用joblib.load 函数检索它:

      var='route_of_administration'
      v = joblib.load('custom_tfidf_vectorizer.joblib')
      v.fit(train[var])
      X_df = v.transform(train[var])
      

      【讨论】:

      • 当您在转储所在的同一笔记本中加载时,它将起作用。但是,当您尝试将矢量化器加载到另一个文件中时,您可能会遇到相同的错误。
      • 实际上我在一个完全部署的管道中使用了这个矢量化器,它使用joblib.load 来获取转换器
      猜你喜欢
      • 2021-03-18
      • 2019-07-09
      • 1970-01-01
      • 2018-01-02
      • 2019-08-04
      • 2020-01-13
      • 2020-06-17
      • 2014-11-30
      相关资源
      最近更新 更多