Архив за месяц: Январь 2019

Реализация алгоритма кластеризации шумных данных DBSCAN на python

Самым известным алгоритмом кластеризации является k-means, с него начинаются все обучающие примеры по кластеризации. Но несмотря на простоту и скорость k-means, у него есть одна очень большая проблема — это наперед заданное количество кластеров. В реальном же мире чаще всего нам не известно на сколько групп следует разбить данные, более того часть данных могут быть вредными выбросами. DBSCAN отлично разбивает множество на оптимальное количество кластеров и не учитывает выбросы, неудивительно что в 2014ом году алгоритм получил метку «проверено временем» на одной из конференций по анализу данных.
Мы будет рассматривать реализация на основе библиотеки sklearn
* В алгоритма два входных параметра min_samples и eps. Если в заданной окрестности eps есть минимальное необходимое количество объектов min_samples, то данная окрестность будет считаться кластером.
* Если в заданной области нет необходимого количества объектов, то инициирующая эту область точка считается выбросом
Кластеры, найденные DBSCAN могут иметь любую форму, в отличии от алгоритма k-means (которые предполагают только выпуклую форму)

Ниже приведём простой пример кластеризации с помощью DBSCAN.

from sklearn.datasets import load_iris
from sklearn.cluster import DBSCAN

iris = load_iris()
dbscan = DBSCAN(eps=0.5, min_samples=5)

dbscan.fit(iris.data)

# Готово! Распечатаем метки принадлежности к кластерам
print(dbscan.labels_)

Теперь давайте визуализируем полученный результат

from sklearn.decomposition import PCA
import matplotlib.pyplot as pl

pca = PCA(n_components=2).fit(iris.data)
pca_2d = pca.transform(iris.data)
for i in range(0, pca_2d.shape[0]):
    if dbscan.labels_[i] == 0:
        c1 = pl.scatter(pca_2d[i, 0], pca_2d[i, 1], c='r', marker='+')
    elif dbscan.labels_[i] == 1:
        c2 = pl.scatter(pca_2d[i, 0], pca_2d[i, 1], c='g', marker='o')
    elif dbscan.labels_[i] == -1:
        c3 = pl.scatter(pca_2d[i, 0], pca_2d[i, 1], c='b', marker='*')

pl.legend([c1, c2, c3], ['Cluster 1', 'Cluster 2', 'Noise'])
pl.title('DBSCAN finds 2 clusters and noise')
pl.show()

В результате получим вот такое разбиение по кластерам и шум
кластеризация dbscan

Hyperopt и xgboost: Пример поиска гиперпараметров с помощью Hyperopt для xgboost

Xgboost пожалуй самая популярная библиотека градиентного бустинга, поэтому именно на её примере покажу как можно улучшить качество простым техническим приёмом — автоматическим подбором параметров. Чтобы не усложнять поиск оптимальных гиперпараметров, возьмем лишь несколько основных: n_estimators, eta и max_depth. Основная идея библиотеки hyperopt — это построение математической гипотезы о том как выглядит функция результа на множества параметров и проверка этой гипотезы с каждой итерацией. Т.к. перебор и обучение может быть весьма продолжительны — то на вход задается количество итерации, после которого происходит остановка поиска. Но все равно предсказать, когда закончится поиск проблематично т.к. при разных гиперпараметрах обучение и предсказание занимает разное время. Поэтому я и советую начинать с небольшого количества итерации и небольшого количества параметров. К сожалению останова по истечению заранее заданного времени нет, поэтому мощный комьютер для data-sciece вам в руки и вперед!

import numpy as np
from sklearn import datasets
from sklearn.model_selection import cross_val_score
from xgboost import XGBClassifier

from hyperopt import hp, tpe
from hyperopt.fmin import fmin

# Для теста возьмем классический сет "ирисы Фишера"
# Разумеется вместо X и y Вам следует взять свои фичи и таргет
iris = datasets.load_iris()
X = iris.data
y = iris.target


def hyperopt_xgb_score(params):
    clf = XGBClassifier(**params)
    # усреднение по 3ем фолдам, для уменьшения влияния стахостичности
    # для ускорения можно использовать train_test_split один раз
    current_score = cross_val_score(clf, X, y, cv=3).mean()
    print(current_score, params)
    return -current_score


simple_space_xgb = {
            'n_estimators': hp.choice('n_estimators', range(100, 1000)),
            'eta': hp.quniform('eta', 0.025, 0.5, 0.025),
            'max_depth':  hp.choice('max_depth', np.arange(1, 14, dtype=int)),
}

best = fmin(fn=hyperopt_xgb_score, space=simple_space_xgb, algo=tpe.suggest, max_evals=10)
print('best:')
print(best)

Как видимо нет ничего сложного, главное определить:
1) пространство параметров, внутри которых hyperopt будет оптимизировать
2) функцию оценки.
Обратите внимание, что в функции оценки возвращается результат со знаком минус — это сделано специально, т.к. гиперопт минимизирует функционал, а нам надо максимизировать точность.
Для построения пространства в основном используется либо набор возможных значений (hp.choice) либо отрезок в пространстве R hp.quniform(label, low, high, q), где q округление.
Для тех, кто планирует более мощную настройку, оставлю space более мощный для XGB.

space_xgb2 = {
            'n_estimators': hp.choice('n_estimators', range(100, 1000)),
            'eta': hp.quniform('eta', 0.025, 0.5, 0.025),
            'max_depth':  hp.choice('max_depth', np.arange(1, 14, dtype=int)),
            'min_child_weight': hp.quniform('min_child_weight', 1, 6, 1),
            'subsample': hp.quniform('subsample', 0.5, 1, 0.05),
            'gamma': hp.quniform('gamma', 0.5, 1, 0.05),
            'colsample_bytree': hp.quniform('colsample_bytree', 0.5, 1, 0.05),
            'eval_metric': 'auc',
            'objective': 'binary:logistic',
            # Increase this number if you have more cores. Otherwise, remove it and it will default
            # to the maxium number.
            'nthread': 4,
            'booster': 'gbtree',
            'tree_method': 'exact',
            'silent': 1
        }

Теперь с помощью данного поста Вы можете построить оптимизацию гиперпараметров не ограничиваясь xgboost.