“На глаз” - это значит натравливаю каждое сообщение на разные модели, и смотрю результат по каждой модели, а результат - “кто в лес, кто по дрова”.
В общем, разобрался. При обучении нужно скидывать матрицу TFiDF,
vectorizer = TfidfVectorizer(sublinear_tf=True, max_df=0.5, stop_words='english')
X_train = vectorizer.fit_transform(data_train.data)
joblib.dump(vectorizer, "vectorizer.dump")
а при тестировании ее загружать:
vectorizer = joblib.load("vectorizer.dump")
и эту штуку сразу и фитить:
X_test = vectorizer.transform(data_test)
Я же грузил только словарь из процедуры TFiDF
dict(zip(vectorizer.get_feature_names(), idf))
и на нем строил тестовый вектор. Видимо, при получении моделей словарь хешируется и порядок нарушается.
Как я понимаю, тестирование работает не с одним вектором (полученным из тестового сообщения), а с пучком векторов на весах из TFiDF по тематикам, выбирая самый близкий по косинусу.
В принципе, это правильно: результат получается на 0.5-1% выше, чем на просто одном частотном векторе сообщения, но и работает, соответственно, медленнее.