Méthode plus efficace en mémoire pour encoder à chaud des colonnes - Python 3.6.x
J'ai une méthode qui consiste à encoder à chaud une liste de colonnes à partir d'une pandastrame de données et à supprimer la colonne d'origine. Bien que cela fonctionne très rapidement pour certains domaines, pour d'autres, ce processus prend un temps incroyablement long. Par exemple, je travaille actuellement sur des ensembles de données hautement catégoriques (c'est-à-dire plus de 80 entités catégoriques) où une seule entité me pousse à des 100,000surdimensionnements.
Je recherche une routine plus optimisée et plus efficace en mémoire pour encoder à chaud des données de haute dimension.
Voici mon approche actuelle:
# For each column to encode
for col in encode_cols:
col_name = str(col)
if col not in ('PRICE_AMOUNT', 'CHECKSUM_VALUE'):
old_cols = df.shape[1]
print("Now testing: {}".format(col_name))
# Use pandas get_dummies function
temp = pd.get_dummies(df[col], prefix=col_name, prefix_sep='_')
df.drop(col, axis=1, inplace=True)
df = pd.concat([df, temp], axis=1, join='inner')
print("New Size: {}".format(df.shape))
sizes[col] = df.shape[1] - old_cols
else:
continue
del(temp)
gc.collect()
Pour mon cas, ce encode_colsn'est qu'environ 75 éléments, mais le vecteur passe des 100dimensions à une 107,000fois terminé. Comment optimiser cette routine?
Réponses
Sans avoir accès à vos données, je ne peux pas vous fournir un code entièrement exploitable, bien que voici mes pensées. Lorsqu'il s'agit de fonctionnalités binaires très rares, des matrices éparses peuvent être utilisées, ce qui est une manière intelligente (et très efficace en mémoire) de stocker des données.
Vous pouvez ensuite utiliser OneHotEncoderfrom sklearn, comme expliqué ici , pour générer des entités catégoriques clairsemées codées à chaud . Donc, dans votre cas, vous devrez calculer, pour chaque caractéristique catégorielle - tous ses niveaux, et l'utiliser pour encoder les vecteurs épars.
vec = OneHotEncoder(n_values=n_of_levels_among_all_features)
X = vec.fit_transform(level_ids_data)
X.toarray() # To get it back to an "normal" nd-array.
Ensuite, vous pouvez utiliser hstackcomme décrit ici afin de fusionner vos fonctionnalités denses ( PRICE_AMOUNT, CHECKSUM_VALUE) avec vos fonctionnalités clairsemées.
from scipy.sparse import hstack
X = hstack((sparse_ohe_categorical_features, dense_features), format='csr')
Xest maintenant une matrice clairsemée, avec toutes vos données. Modifiez le format, csrselon le cas d'utilisation. Par exemple, en utilisant la régression logistique à partir de sklearn, les matrices éparses doivent être au csrformat pour que la méthode d'ajustement fonctionne.
Je suggérerais d'utiliser l'outil OneHotEncoder de scikit-learn.
from sklearn.preprocessing import OneHotEncoder
features_to_one_hot = ['feature1','feature2']
to_one_hot_df = df.loc[:,features_to_one_hot]
categorical_encoder = OneHotEncoder()
new_one_hot = cat_encoder.fit_transform(to_one_hot_df)
Si vous souhaitez que l'encodeur effectue des actions plus spécifiques, Scikit-learn utilise le typage canard. Ce qui signifie que vous pouvez implémenter votre propre classe. Ici, je montre comment vous pouvez en créer un pour que l'encodeur supprime les anciennes colonnes:
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.preprocessing import OneHotEncoder
class OneHotAndDrop(BaseEstimator, TransformerMixin):
def __init__(self, operate=True):
self.operate = operate
def fit(self, X, y=None):
return self
def transform(self, X):
if self.operate:
old_columns = list(X.columns)
new_one_hot = OneHotEncoder().fit_transform(X)
X = new_one_hot.drop(old_columns, axis=1)
return X
one_hot_costum = OneHotAndDrop()
new_one_hot = one_hot_costum.fit_transform(to_one_hot_df)
Vous pouvez ensuite utiliser cette classe comme vous l'avez fait pour le premier exemple. Cette méthode utilise une matrice clairsemée, elle sera probablement beaucoup plus efficace que votre fonction d'origine et nommera automatiquement les nouvelles fonctionnalités.
En outre, un encodage à chaud n'est peut-être pas la meilleure idée selon la raison pour laquelle vous devez les encoder. Si c'est pour l'apprentissage automatique, cela créera beaucoup trop de fonctionnalités et sera probablement surajusté. Je recommanderais de les regrouper d'abord, puis de les catégoriser pour réduire le nombre de nouvelles fonctionnalités.