省メモリOneHotEncoder
13253 ワード
OneHotEncoderは、エンコーディングを行う際に、入力データをnumpyに転送する.arrayオブジェクトを使用して、速度を最適化します.これにより、カラムの値が300000文字のテキストであると、メモリが不足するなど、中性子タイプのメモリが不足する可能性があります.これに対して、このバージョンのスーパーメモリを節約します.
OneHotEncoderとget_feature_namesは使えますので、TransformMixinクラスを継承してメモリを非常に節約したバージョンを書きました.400 Wサンプル27列の処理が必要なデータセットでOneHotEncoderは2分35秒、本プログラムは1分35秒かかります.
##本コードは、大規模なテキストが含まれている場合###本コードは、大規模なテキストが含まれている場合###本コードは、大規模なテキストが含まれている場合##に適用されます.
実際には,各列の各テキストの代わりにintを用いることで,OneHotEncoderに入力することでその速度を発揮できる.
OneHotEncoderとget_feature_namesは使えますので、TransformMixinクラスを継承してメモリを非常に節約したバージョンを書きました.400 Wサンプル27列の処理が必要なデータセットでOneHotEncoderは2分35秒、本プログラムは1分35秒かかります.
##本コードは、大規模なテキストが含まれている場合###本コードは、大規模なテキストが含まれている場合###本コードは、大規模なテキストが含まれている場合##に適用されます.
実際には,各列の各テキストの代わりにintを用いることで,OneHotEncoderに入力することでその速度を発揮できる.
from sklearn.base import TransformerMixin
import numpy as np
import scipy.sparse as sp
from collections import defaultdict as ddt
from itertools import chain
class LittleOntHotEncoder(TransformerMixin):
""" OneHotEncoder, """
def __init__(self, *args, **kwargs):
super(TransformerMixin, self).__init__(*args, **kwargs)
self._per_feature = ddt(lambda : set())
self._feat2idx = ddt(lambda : dict())
self._feat2default = {
}
self._all_feature_number = -1
def get_feature_names(self):
items = chain.from_iterable([[(f"{i}_{e}", idx) for e, idx in dic.items()] for i, dic in self._feat2idx.items()])
return [feat for feat, _ in sorted(items, key=lambda x:x[1])]
def fit(self, cate_smples):
per_feature = self._per_feature
for line in cate_smples:
for i, e in enumerate(line):
per_feature[i].add(e)
self._per_feature = per_feature
_all_feature_number = 0
feat2idx = self._feat2idx
items = sorted(per_feature.items(), key=lambda x:x[0])
for idx, feat_set in items:
for e in feat_set:
feat2idx[idx][e] = _all_feature_number
self._feat2default[idx] = _all_feature_number
_all_feature_number += 1
self._feat2idx = feat2idx
self._all_feature_number = _all_feature_number
def transform(self, cate_smples):
M = len(cate_smples)
n = len(cate_smples[0])
N = self._all_feature_number
feat2idx = self._feat2idx
feat2default = self._feat2default
_data = np.ones((M*n), dtype=np.int8)
_indices = np.array([[feat2idx[feat_idx].get(e, feat2default[feat_idx]) for feat_idx, e in enumerate(line)] for line in cate_smples])
_indptr = np.array([i*n for i in range(M)] + [M])
return sp.csr_matrix((_data, np.reshape(_indices, (M*n,)), _indptr), shape=(M, N))
def fit_transform(self, cate_smples):
self.fit(cate_smples)
return self.transform(cate_smples)