scikit-learn v0.22 より前に作ったMultiLabelBinarizer
が、scikit-learn v0.24以降の入った環境でunpickleできないことを示します。
ちょっとハマった身から言えること:pickleする環境とunpickleする環境のバージョン違いにはご注意ください
環境
macOS
Python 3.7.3
手順
scikit-learn
0.22より前
scikit-learn-0.21.3
ドキュメントのExamplesを用います
https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.MultiLabelBinarizer.html#sklearn.preprocessing.MultiLabelBinarizer
experiment.py
import pickle
from sklearn.preprocessing import MultiLabelBinarizer
mlb = MultiLabelBinarizer()
mlb.fit_transform([{'sci-fi', 'thriller'}, {'comedy'}])
print(list(mlb.classes_))
with open("mlb_021.pkl", "wb") as fout:
pickle.dump(mlb, fout)
$ python experiment.py
['comedy', 'sci-fi', 'thriller']
$ python -q
対話モードでunpickleします。
>>> import pickle
>>> with open("mlb_021.pkl", "rb") as fin:
... mlb = pickle.load(fin)
...
>>> list(mlb.classes_)
['comedy', 'sci-fi', 'thriller']
>>> mlb.transform([['sci-fi', 'comedy']])
array([[1, 1, 0]])
>>> type(mlb)
<class 'sklearn.preprocessing.label.MultiLabelBinarizer'>
scikit-learn
0.24以降
pip install -U scikit-learn
で0.24.0が入りました。
対話モードでunpickleを試みます(エラーになります)。
>>> import pickle
>>> with open("mlb_021.pkl", "rb") as fin:
... mlb = pickle.load(fin)
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
ModuleNotFoundError: No module named 'sklearn.preprocessing.label'
原因
以下のIssueへの対応でモジュールをprivateにしています。
https://github.com/scikit-learn/scikit-learn/issues/9250
rename file.py into _file.py
それにより、sklearn/preprocessing/label.py(sklearn.preprocessing.label
)はsklearn/preprocessing/_label.py(sklearn.preprocessing._label
)とrenameされました。
https://github.com/scikit-learn/scikit-learn/commit/15d5ef04df21f1d8db6583c74d1869c3fad36970#diff-e4f17cabd1bed4babf2fbfb7a31a3d955563e0267e8c310fa61629e722a64488
対処法
0.24まで上げなければunpickleはできます(後述するように自己責任でお願いします)。
pip install -U 'scikit-learn<0.24'
で0.23.2をインストール。
>>> import pickle
>>> with open("mlb_021.pkl", "rb") as fin:
... mlb = pickle.load(fin)
...
このとき、バージョン0.24でremoveされるとwarningも出ています。
/.../env/lib/python3.7/site-packages/sklearn/utils/deprecation.py:143: FutureWarning: The sklearn.preprocessing.label module is deprecated in version 0.22 and will be removed in version 0.24. The corresponding classes / functions should instead be imported from sklearn.preprocessing. Anything that cannot be imported from sklearn.preprocessing is now part of the private API.
warnings.warn(message, FutureWarning)
ドキュメントでも通知されていました!
https://scikit-learn.org/dev/whats_new/v0.22.html#clear-definition-of-the-public-api
実際、MultiLabelBinarizer
のtype
を確認すると、renameされた_label.pyを使っています(0.23.2で確認)。
>>> from sklearn.preprocessing import MultiLabelBinarizer
>>> mlb = MultiLabelBinarizer()
>>> type(mlb)
<class 'sklearn.preprocessing._label.MultiLabelBinarizer'>
なお、scikit-learnのバージョンが違うことのWarningも出ますので、文面にあるように自己責任でお願いします。
/.../env/lib/python3.7/site-packages/sklearn/base.py:334: UserWarning: Trying to unpickle estimator MultiLabelBinarizer from version 0.21.3 when using version 0.23.2. This might lead to breaking code or invalid results. Use at your own risk.
UserWarning)
メモ
pip install -U
(docs)にバージョン込みで指定すると、パッケージのバージョンを自由に変えられます(--upgradeオプションですが、ダウングレードもできます)。
👉バージョン指定の仕方について
https://pip.pypa.io/en/stable/user_guide/#understanding-your-error-message
TODO:pickleの仕組みを今よりももう少し理解したいです