Как ускорить работу классификатора knn?
Я делаю задание, где нужно написать свой аналог sklearn knn. Вот основной код класса:
def fit(self, X, y):
self.X_train = X
self.scaler = preprocessing.StandardScaler().fit(self.X_train)
self.X_train_st = self.scaler.transform(self.X_train)
self.y_train = y
self.min_length = np.unique(self.y_train)[-1]+1
def predict(self, X):
self.X_test = X
self.X_test_st = self.scaler.transform(self.X_test)
self.y_pred = np.zeros(self.X_test_st.shape[0],dtype='int64')
if(self.alg == 'brute'):
dist = distance.cdist(self.X_test_st, self.X_train_st, 'minkowski', p=2.)
ind = np.argsort(dist,axis=1)[:,:self.n]
self.y_pred = np.argmax(np.apply_along_axis(lambda x: np.bincount(x, minlength=self.min_length), 1, self.y_train[ind]), axis=1)
else:
self.KDTree = KDTree(self.X_train_st)
dist, ind = self.KDTree.query(self.X_test_st, k=self.n)
self.y_pred = np.argmax(np.apply_along_axis(lambda x: np.bincount(x, minlength=self.min_length), 1, self.y_train[ind]), axis=1)
return self.y_pred.ravel()
На всем известных ирисах работает достаточно быстро по сравнению с sklearn, но я хочу попробовать с fetch_20newsgroups и тут уже все плохо. Сначала я использовала
vectorizer = feature_extraction.text.CountVectorizer(max_df = 0.15, min_df=0.01)
X = vectorizer.fit_transform(data)
Попробовала посмотреть средний скор на кросс-валидации на трех фолдах, brute считается просто нереально долго, по сравнению с тем же sclearn, kdtree немного получше, но все равно очень долго. TfidfVectorizer и cosine метрика помогают немного с точностью(хотя все равно очень низкая, около 15-17%), но что делать со скоростью я не знаю, особенно учитывая, что косинусную метрику использовать на кд дереве нельзя.
UPD: на pairwise_distances и без стандартизации все взлетело и по точности, и по скорости)
Ответы (1 шт):
Но вы же понимаете, что в случае текста у вас получится как говорится 100500+ фич? И вам потом для всего этого хозяйства надо будет считать расстояния "каждый с каждым". Это реально долго. Тут может быть два выхода:
- Сильно ограничить число фич, при этом качество, которое у вас и так не очень, ещё упадёт.
- Использовать только методы, понимающие разреженные матрицы. Для этого нужно убрать
StandardScaler(его в случае текстов обычно и не используют - нет смысла, плюс к тому он делает из разреженных матриц обычные) и постараться найти замену функцииdistance.cdist, такую же быструю (или ещё быстрее), но при этом понимающую разреженные матрицы. Что-нибудь вродеNMSLIBили других подобных библиотек. Можно ещё попробовать вместоCountVectorizerиспользоватьHashingVectorizer, ему не нужно хранить состояние, он поэтому должен по идее быстрее работать.
Простых путей тут нет, поскольку считать расстояния "каждый с каждым" для строк, в каждой из которых сотни тысяч фич - это никак не может быть быстрым. Вот в случае разреженной матрицы значимых фич у каждого сэмпла довольно немного и подсчёты расстояний идут гораздо быстрее.