web-dev-qa-db-fra.com

ajouter un support de stemming à CountVectorizer (sklearn)

J'essaie d'ajouter stemming à mon pipeline en PNL avec sklearn.

from nltk.stem.Snowball import FrenchStemmer

stop = stopwords.words('french')
stemmer = FrenchStemmer()


class StemmedCountVectorizer(CountVectorizer):
    def __init__(self, stemmer):
        super(StemmedCountVectorizer, self).__init__()
        self.stemmer = stemmer

    def build_analyzer(self):
        analyzer = super(StemmedCountVectorizer, self).build_analyzer()
        return lambda doc:(self.stemmer.stem(w) for w in analyzer(doc))

stem_vectorizer = StemmedCountVectorizer(stemmer)
text_clf = Pipeline([('vect', stem_vectorizer), ('tfidf', TfidfTransformer()), ('clf', SVC(kernel='linear', C=1)) ])

Lorsque vous utilisez ce pipeline avec le CountVectorizer de sklearn, cela fonctionne. Et si je crée manuellement des fonctionnalités comme celle-ci, cela fonctionne également.

vectorizer = StemmedCountVectorizer(stemmer)
vectorizer.fit_transform(X)
tfidf_transformer = TfidfTransformer()
X_tfidf = tfidf_transformer.fit_transform(X_counts)

MODIFIER :

Si j'essaie ce pipeline sur mon ordinateur portable IPython, il affiche le [*] et rien ne se passe. Lorsque je regarde mon terminal, il donne cette erreur:

Process PoolWorker-12:
Traceback (most recent call last):
  File "C:\Anaconda2\lib\multiprocessing\process.py", line 258, in _bootstrap
    self.run()
  File "C:\Anaconda2\lib\multiprocessing\process.py", line 114, in run
    self._target(*self._args, **self._kwargs)
  File "C:\Anaconda2\lib\multiprocessing\pool.py", line 102, in worker
    task = get()
  File "C:\Anaconda2\lib\site-packages\sklearn\externals\joblib\pool.py", line 360, in get
    return recv()
AttributeError: 'module' object has no attribute 'StemmedCountVectorizer'

Exemple

Voici l'exemple complet

from sklearn.pipeline import Pipeline
from sklearn import grid_search
from sklearn.svm import SVC
from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer
from nltk.stem.Snowball import FrenchStemmer

stemmer = FrenchStemmer()
analyzer = CountVectorizer().build_analyzer()

def stemming(doc):
    return (stemmer.stem(w) for w in analyzer(doc))

X = ['le chat est beau', 'le ciel est nuageux', 'les gens sont gentils', 'Paris est magique', 'Marseille est tragique', 'JCVD est fou']
Y = [1,0,1,1,0,0]

text_clf = Pipeline([('vect', CountVectorizer()), ('tfidf', TfidfTransformer()), ('clf', SVC())])
parameters = { 'vect__analyzer': ['Word', stemming]}

gs_clf = grid_search.GridSearchCV(text_clf, parameters, n_jobs=-1)
gs_clf.fit(X, Y)

Si vous supprimez la racine des paramètres, cela fonctionne, sinon cela ne fonctionne pas.

MISE À JOUR :

Le problème semble être dans le processus de parallélisation car lors de la suppression n_jobs = -1 le problème disparaît.

18
dooms

Vous pouvez passer un appelable en tant que analyzer au constructeur CountVectorizer pour fournir un analyseur personnalisé. Cela semble fonctionner pour moi.

from sklearn.feature_extraction.text import CountVectorizer
from nltk.stem.Snowball import FrenchStemmer

stemmer = FrenchStemmer()
analyzer = CountVectorizer().build_analyzer()

def stemmed_words(doc):
    return (stemmer.stem(w) for w in analyzer(doc))

stem_vectorizer = CountVectorizer(analyzer=stemmed_words)
print(stem_vectorizer.fit_transform(['Tu marches dans la rue']))
print(stem_vectorizer.get_feature_names())

Imprime:

  (0, 4)    1
  (0, 2)    1
  (0, 0)    1
  (0, 1)    1
  (0, 3)    1
[u'dan', u'la', u'march', u'ru', u'tu']
26
joeln

Je sais que je suis un peu en retard pour poster ma réponse. Mais voilà, au cas où quelqu'un aurait encore besoin d'aide.

Voici l'approche la plus propre pour ajouter un stemmer de langue pour compter le vectoriseur en remplaçant build_analyser()

from sklearn.feature_extraction.text import CountVectorizer
import nltk.stem

french_stemmer = nltk.stem.SnowballStemmer('french')
class StemmedCountVectorizer(CountVectorizer):
    def build_analyzer(self):
        analyzer = super(StemmedCountVectorizer, self).build_analyzer()
        return lambda doc: ([french_stemmer.stem(w) for w in analyzer(doc)])

vectorizer_s = StemmedCountVectorizer(min_df=3, analyzer="Word", stop_words='french')

Vous pouvez appeler librement les fonctions fit et transform de la classe CountVectorizer sur votre vectorizer_s objet

15
Parth Gupta

Tu peux essayer:

def build_analyzer(self):
    analyzer = super(CountVectorizer, self).build_analyzer()
    return lambda doc:(stemmer.stem(w) for w in analyzer(doc))

et supprimez le __init__ méthode.

1
Till