2014-02-20 2 views
3

Я пытаюсь использовать классификатор Bernoulli Naive Bayes от scikit-learn. У меня был класс, который отлично работал на небольшом наборе данных, используя CountVectorizor, но столкнулся с трудностями, когда я попытался использовать HashingVectorizor для работы с большим набором данных. Сохранение всех других параметров (учебных документов, тестовых документов, классификаторов & настроек экстрактора) постоянный и просто переход от CountVectorizor к HashingVectorizor заставил мой классификатор всегда выплюнуть одну и ту же метку для всех документов.Почему мой scikit учит HashingVectorizor, давая мне поплавки с бинарным = True set?

Я написал следующий сценарий, чтобы выяснить, что будет отличаться от двух художественных экстракторов:

from sklearn.feature_extraction.text import HashingVectorizer, CountVectorizer 

cv = CountVectorizer(binary=True, decode_error='ignore') 
h = HashingVectorizer(binary=True, decode_error='ignore') 

with open('moby_dick.txt') as fp: 
    doc = fp.read() 

cv_result = cv.fit_transform([doc]) 
h_result = h.transform([doc]) 

print cv_result 
print repr(cv_result) 
print h_result 
print repr(h_result) 

(где «moby_dick.txt» является проект Гутенберга копия Moby Dick)

В (сокращенные) результаты:

(0, 17319) 1 
    (0, 17320) 1 
    (0, 17321) 1 
<1x17322 sparse matrix of type '<type 'numpy.int64'>' 
    with 17322 stored elements in Compressed Sparse Column format> 

    (0, 1048456) 0.00763203138591 
    (0, 1048503) 0.00763203138591 
    (0, 1048519) 0.00763203138591 
<1x1048576 sparse matrix of type '<type 'numpy.float64'>' 
    with 17168 stored elements in Compressed Sparse Row format> 

Как вы можете видеть, CountVectorizor в двоичном режиме, возвращает целое число 1 для значения каждой функции (мы только ожидаем увидеть 1, так как есть только один документ); HashVectorizor, с другой стороны, возвращает поплавки (все равно, но разные документы дают другое значение). Я подозреваю, что мои проблемы связаны с передачей этих поплавков на BernoulliNB.

В идеале, я хотел бы получить один и тот же двоичный формат данных из HashingVectorizor, как я получаю от CountVectorizor; в противном случае я мог бы использовать параметр binarize BernoulliNB, если бы я знал нормальный порог для установки этих данных, но я не понимаю, что представляют собой эти float (они явно не являются токенами, поскольку они все одинаковы и меньше чем 1).

Любая помощь будет оценена по достоинству.

ответ

5

В настройках по умолчанию, HashingVectorizer нормализует свои векторы признаков на единицу длины евклидовой:

>>> text = "foo bar baz quux bla" 
>>> X = HashingVectorizer(n_features=8).transform([text]) 
>>> X.toarray() 
array([[-0.57735027, 0.  , 0.  , 0.  , 0.57735027, 
     0.  , -0.57735027, 0.  ]]) 
>>> scipy.linalg.norm(np.abs(X.toarray())) 
1.0 

Установка binary=True только не отдаляет эту нормализацию, пока после преобразования к двоичному виду функции, т.е. установить все ненулевые одни к одному. Вы также должны установить norm=None, чтобы выключить его:

>>> X = HashingVectorizer(n_features=8, binary=True).transform([text]) 
>>> X.toarray() 
array([[ 0.5, 0. , 0. , 0. , 0.5, 0.5, 0.5, 0. ]]) 
>>> scipy.linalg.norm(X.toarray()) 
1.0 
>>> X = HashingVectorizer(n_features=8, binary=True, norm=None).transform([text]) 
>>> X.toarray() 
array([[ 1., 0., 0., 0., 1., 1., 1., 0.]]) 

Это также объясняет, почему это возвращение float массивов: нормализация требует от них. Хотя векторизатор может быть сфальсифицирован, чтобы вернуть другой тип dtype, для чего потребуется преобразование внутри метода transform и, вероятно, один назад, чтобы плавать в следующей оценке.

+0

Почему знак минус? –