我可以在scikit-learn中安全地分配到`coef_`和其他估计参数吗?

时间:2017-09-20 07:39:58

标签: python scikit-learn

scikit-learn suggests使用pickle进行模型持久化。然而,他们注意到不同版本的scikit-learn或python时pickle的局限性。 (另见this stackoverflow question

在许多机器学习方法中,从大数据集中只学习了很少的参数。这些估算参数存储在trailing underscore的属性中,例如coef_

现在我的问题如下: 可以通过保留估计的属性并在以后分配它们来实现模型持久性吗? 对于scikit-learn中的所有估算器,此方法是否安全,或者在某些估算工具中是否存在潜在的副作用(例如必须设置的私有变量)?

它似乎适用于逻辑回归,如以下示例所示:

from sklearn import datasets
from sklearn.linear_model import LogisticRegression
try:
    from sklearn.model_selection import train_test_split
except ImportError:
    from sklearn.cross_validation import train_test_split
iris = datasets.load_iris()
tt_split = train_test_split(iris.data, iris.target, test_size=0.4)
X_train, X_test, y_train, y_test = tt_split

# Here we train the logistic regression
lr = LogisticRegression(class_weight='balanced')
lr.fit(X_train, y_train)
print(lr.score(X_test, y_test))     # prints 0.95

# Persisting
params = lr.get_params()
coef = lr.coef_
intercept = lr.intercept_
# classes_ is not documented as public member, 
# but not explicitely private (not starting with underscore)
classes = lr.classes_ 
lr.n_iter_ #This is meta-data. No need to persist


# Now we try to load the Classifier 
lr2 = LogisticRegression()
lr2.set_params(**params)
lr2.coef_ = coef
lr2.intercept_ = intercept
lr2.classes_ = classes
print(lr2.score(X_test, y_test)) #Prints the same: 0.95

1 个答案:

答案 0 :(得分:5)

单独设置估计属性是不够的 - 至少在所有估算器的一般情况下。

我至少知道一个会失败的例子。  LinearDiscriminantAnalysis.transform()使用私有属性_max_components

def transform(self, X):
        # ... code omitted
        return X_new[:, :self._max_components]

但是,它可能适用于某些估算工具。如果您只需要针对特定​​估算器,最佳方法是查看估算器源代码并保存__init__().fit()方法中设置的所有属性。

更通用的方法可能是保存估算工具.__dict__中的所有项目。 E.g:

from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
lda = LDA().fit([[1, 2, 3], [1, 2, 1], [4, 5, 6], [9, 9, 9]], [1, 2, 1, 2])
lda.__dict__
# {'_max_components': 1,
#  'classes_': array([1, 2]),
#  'coef_': array([[ -9.55555556,  21.55555556,  -9.55555556]]),
#  'explained_variance_ratio_': array([ 1.]),
#  'intercept_': array([-15.77777778]),
#  'means_': array([[ 2.5,  3.5,  4.5],
#         [ 5. ,  5.5,  5. ]]),
#  'n_components': None,
#  'priors': None,
#  'priors_': array([ 0.5,  0.5]),
#  'scalings_': array([[-2.51423299],
#         [ 5.67164186],
#         [-2.51423299]]),
#  'shrinkage': None,
#  'solver': 'svd',
#  'store_covariance': False,
#  'tol': 0.0001,
#  'xbar_': array([ 3.75,  4.5 ,  4.75])}

对于包含更复杂数据的估算器,例如包含多个估算器的集合,这不是一件容易的事。有关详细信息,请参阅博文Scikit-learn Pipeline Persistence and JSON Serialization

不幸的是,这不会安全地将估算器带到新版本的scikit-learn。私有属性本质上是一个实现细节,可以在不同版本之间随时更改。