J'ai du mal à comprendre comment réparer un Pipeline que j'ai créé (lire: largement collé à partir d'un tutoriel). C'est python 3.4.2:
df = pd.DataFrame
df = DataFrame.from_records(train)
test = [blah1, blah2, blah3]
pipeline = Pipeline([('vectorizer', CountVectorizer()), ('classifier', RandomForestClassifier())])
pipeline.fit(numpy.asarray(df[0]), numpy.asarray(df[1]))
predicted = pipeline.predict(test)
Quand je le lance, j'obtiens:
TypeError: A sparse matrix was passed, but dense data is required. Use X.toarray() to convert to a dense numpy array.
C'est pour la ligne pipeline.fit(numpy.asarray(df[0]), numpy.asarray(df[1]))
.
J'ai beaucoup expérimenté avec des solutions via numpy, scipy, etc., mais je ne sais toujours pas comment y remédier. Et oui, des questions similaires se sont posées auparavant, mais pas à l'intérieur d'un pipeline. Où dois-je appliquer toarray
ou todense
?
Malheureusement, ces deux sont incompatibles. Un CountVectorizer
produit une matrice clairsemée et le RandomForestClassifier nécessite une matrice dense. Il est possible de convertir en utilisant X.todense()
. Cela augmentera considérablement votre empreinte mémoire.
Voici un exemple de code pour ce faire basé sur http://zacstewart.com/2014/08/05/pipelines-of-featureunions-of-pipelines.html qui vous permet d'appeler .todense()
en phase de pipeline.
class DenseTransformer(TransformerMixin):
def fit(self, X, y=None, **fit_params):
return self
def transform(self, X, y=None, **fit_params):
return X.todense()
Une fois que vous avez votre DenseTransformer
, vous pouvez l'ajouter en tant qu'étape de pipeline.
pipeline = Pipeline([
('vectorizer', CountVectorizer()),
('to_dense', DenseTransformer()),
('classifier', RandomForestClassifier())
])
Une autre option consisterait à utiliser un classificateur destiné aux données éparses comme LinearSVC
.
from sklearn.svm import LinearSVC
pipeline = Pipeline([('vectorizer', CountVectorizer()), ('classifier', LinearSVC())])
Les forêts aléatoires en 0.16-dev acceptent désormais des données rares.
La solution la plus laconique serait d'utiliser un FunctionTransformer
pour convertir en dense: cela implémentera automatiquement les fit
, transform
et fit_transform
méthodes comme dans la réponse de David. De plus, si je n'ai pas besoin de noms spéciaux pour mes étapes de pipeline, j'aime utiliser le sklearn.pipeline.make_pipeline
fonction de commodité pour activer un langage plus minimaliste pour décrire le modèle:
from sklearn.preprocessing import FunctionTransformer
pipeline = make_pipeline(
CountVectorizer(),
FunctionTransformer(lambda x: x.todense(), accept_sparse=True),
RandomForestClassifier()
)
vous pouvez changer pandas Series
en tableaux en utilisant la méthode .values
.
pipeline.fit(df[0].values, df[1].values)
Cependant, je pense que le problème se produit ici parce que CountVectorizer()
renvoie une matrice clairsemée par défaut et ne peut pas être redirigée vers le classificateur RF. CountVectorizer()
a un dtype
paramètre pour spécifier le type de tableau renvoyé. Cela dit, vous devez généralement effectuer une sorte de réduction de la dimensionnalité pour utiliser des forêts aléatoires pour la classification de texte, car le sac de mots contient des vecteurs de fonctionnalités très longs