Архив метки: python

Реализация алгоритма кластеризации шумных данных 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.

Два примера Label Encoding или переводим строки в числа в pandas.

При решении задач машинного обучения, часто приходится иметь дело со строковыми параметрами. Чаще всего это категориальные фичи, например названия городов, цвета, должность итд. Некоторые библиотеки могут изначально работать со строковыми параметрами, но для большинства предварительно надо перевести буквы в цифры. Более того, это даже очень рекомендуется т.к. в числовом виде будет использоваться меньше оперативной памяти для хранения обучающей матрицы. Процесс перевода строковых фич (labels) в числовые фичи называется label encoding.

В данном посте будет предложено два практических способа label encoding (не путать с onehot encoding) для дата фреймов pandas. Таким образом у нас есть DataFrame train с категориальными фичами, которые надо преобразовать с помощью метода label encoding.

Способ 1.
Используя библиотеку sklearn.

from sklearn import preprocessing
import pandas as pd

train = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')
cat_cols = ['city', 'color', 'position']

for col in cat_cols:
    lbl = preprocessing.LabelEncoder()
    lbl.fit(list(train[col].values.astype('str')) + list(test[col].values.astype('str')))
    print(lbl.classes_)  # взглянем на категориальные классы
    train[col] = lbl.transform(list(train[col].values.astype('str')))
    test[col] = lbl.transform(list(test[col].values.astype('str')))

Способ 2.
Этот способ основан на методе factorize из библиотеки pandas, поэтому если Вы не используете sklearn — можно «cэкономить» на импортах

import pandas as pd
# Сначала покажем классический пример
labels, uniques = pd.factorize(['b', 'b', 'a', 'c', 'b'])
print(labels)  # array([0, 0, 1, 2, 0])
print(uniques)  # ['b', 'a', 'c']

# а теперь пройдемся по всем категориальным колонкам
cat_cols = ['city', 'color', 'position']
for col in cat_cols:
    train[col], _ = pd.factorize(train[col])

Таким образом в обоих способах все строковые значения фич будут заменены на соответсвующие целочисленные значения, что позволит использовать меньше памяти и без дополнительной обработки запускать обучение в разных библиотеках.

Важное замечание, если Вы планируете использовать только линейные модели то onehot encoding сделать всё-таки придется, иначе линейная разделимость будет недостаточной. Для методов же, основанных на деревьях и градиентном спуске label encoding будет достаточно.

Генератор фич на основе математических операций

(Статья не закончена)
Для быстрого поиска фич, коррелируемых с таргетом. Использует перебор по алгебраическим операциям. На новую фичу ставится условие, что абсолютное значение корреляции нового должно превосходить максимальную из двух составных фич более чем в 1.5 раза и быть больше 0.25

import pandas as pd
import numpy as np


def search_features_by_correlation(df: pd.DataFrame, target):
    # only 1000 rows taken for better speed
    mx = df.copy()
    mx['target'] = target
    mx = mx.sample(min(df.shape[0], 1000))
    target = mx.target.values
    mx = mx.drop('target', axis=1)

    # определяем корреляция отдельно для каждой фичи
    single_cc = {}
    real_columns = []
    for k1, c1 in enumerate(mx.columns):
        if not str(c1).startswith('number'):
            continue
        if np.unique(mx[c1].values).shape[0] < 50:
            continue
        single_cc[c1] = np.corrcoef(mx[c1], target)[0][1]
        real_columns.append(c1)

    if len(real_columns) > 100:
        real_columns = real_columns[:100]

    all_combinations = combinations(real_columns, 2)

    def is_cc(col_names: list) -> list:
        cc_base = 0.25
        cc_base_x = 1.5
        res = []
        # signs_to_check = ['*', '/', '-', '+']
        signs_to_check = ['*', '/']

        if len(col_names) == 2:
            for s in signs_to_check:
                if s == '*':
                    prod = mx[col_names[0]] * mx[col_names[1]]
                elif s == '/':
                    prod = mx[col_names[0]] / mx[col_names[1]]
                elif s == '-':
                    prod = mx[col_names[0]] - mx[col_names[1]]
                elif s == '+':
                    prod = mx[col_names[0]] + mx[col_names[1]]

                prod_c = np.corrcoef(prod, target)[0][1]

                if abs(prod_c) > cc_base and abs(prod_c) > cc_base_x * max(abs(single_cc[col_names[0]]),
                                                                           abs(single_cc[col_names[1]])):
                    res.append([s])


        return res

    all_combinations = list(all_combinations)
    corr_results = list(map(is_cc, all_combinations))

    corr_results = {all_combinations[k]: el for k, el in enumerate(corr_results) if el}

    return corr_results

Простой пример классификации текста на python sklearn

Классификация текста — классическая задача в области обработки естественного языка. Лет 10-15 назад тема классификации бурлила в научных журналах, однако со временем бум утих. Это связоно с тем, что подход на основе TF-IDF показал точность близкую к 95%-99.9%. При такой точности на качество классификации больше уже влияют методы предобработки и особенности текста, чем непосредственно выбор самого алгоритма. Появление ембеддингов в 2013 году сильно повлияло на методы в обработке текстов, открыв новую эпоху. Сейчас практически все «production» решения основываются на ембеддингах, но! Тут надо сделать оговорку — ембеддинги чрезвычайно хороши для анализа коротких текстов, которыми сейчас полон интернет, а вот для средних и больших текстов — TF-IDF по прежнему на высоте!

Ниже я приведу базовый подход классификации на основе библиотеки sklearn в python. Код максимально короткий и понятный

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.ensemble import RandomForestClassifier
from sklearn.pipeline import Pipeline


texts = ['текст номер один', 'текст номер два', 'комьютеры в лингвистике', 'компьютеры и обработка текстов']
texts_labels = [1, 1, 0, 0]

text_clf = Pipeline([
                     ('tfidf', TfidfVectorizer()),
                     ('clf', RandomForestClassifier())
                     ])

text_clf.fit(texts, texts_labels)

res = text_clf.predict(['текст номер три'])
print(res)  # [1]

На входе у нас список из текстов и список размеченных классов, далее делаем Pipeline, который включает в себя векторизацию слов на основе TfIdf и классификатор RandomForest . Далее обучаем «пайплайн-классификатор» и пытаемся предсказать новый текст. Как видим классификацию тексто на python сделать очень просто.

Если у Вас получилось запустить первый пример, то наверно вы зададитесь вопросом, как поднять качество существующей модели. Для этого я дам список улучшений, которые следует попробовать.

1. предобработка текста. Попробуйте нормализовать слова, тогда одно смысловое слово в разных склонениях/спряжениях будет интерпретироваться программой одинаково и возможно поднимет качество.
2. У TfIdf есть много разных параметров, наиболее существенные это
2.1 добавить список стоп слов: параметр stop_words
2.2 добавить n-gramm ы слов : параметр ngram_range, например ngram_range=(1,2)
2.3 ограничить список фич, взяв только самые важные и отрезав менее важные: параметр max_features
3. попробовать другой классификатор, например from sklearn.linear_model import SGDClassifier или SVM , XGB итд. соответсвенно подбирая в каждом из них свои гиперпараметры

С помощью перечисленных шагов, Вы достаточно быстро подберёте оптимальный вариант для классификации и получите точность более 90% (основываясь на моём опыте). Если не так, то возможно надо посмотреть внимательнее корректность входных данных.

DataFrame pandas базовые манипуляции с данными

Pandas — очень мощный инструмент для работы и манипуляций над данными с помощью python. Можно сказать, что pandas предоставляет возможности SQL базы данных, дополненные мощью python. Однако, работа с данной библиотекой иногда вызывает некоторые трудности, так как работать приходится по сути с матричными данными и объектами pandas да numpy, а переход к стандартным python типам и циклам неминуемо грозит кратной потерей функциональности. Поэтому для себя создал шпаргалку по работе с дата-фреймами:

Работа начинается с загрузки данных в DataFrame, поэтому для начала считаем данные:

df = pd.read_csv('some.csv')
# если Вам заранее известны типы, то чрезвычайно полезно задать типы колонок сразу - это сэкономит оперативную память.
# также можно использоть лишь несколько колонок, а не все колонки в файле
df = pd.read_csv('some.csv', usecols=["user_id", "id3"], dtype={"user_id": np.int64, "id3": np.uint16})

Возможно и самостоятельно создать DataFrame и добавить строки

# пример создания объекта дата-фрейм
pd.DataFrame(columns=['A', 'B'])
# пример добавления строки в дата-фрейм
df.append({'A':1, 'B':2}, ignore_index=True)

После создания или загрузки DF полезно посмотреть чтоже там за данные, для этого можно воспользоваться следующими операциями:

df.head()       # первые строки
df.tail()       # последние строки
df.sample(5)    # случайно выбранное кол-ва строк, полезно использовать для уменьшения матрицы для прогонки тестов
df.shape        # по аналогии с numpy - размерность матрицы
df.describe()   # математические данные
df.info()       # использование памяти

Возможно далее вам захочется получить точечное значение по координатам из дата фрема, тогда используйте ix

some_value = df.ix[2, 'som_col']  # похожие функции loc и iloc

Для фильтрации по колонкам пандас использует булевую логику, проще показать на примере:

filtered_data = df[df.some_col == 'apple']
filtered_data = df[(df.price > 10.0) & (df.some_col == 'apple')]

Далее приведём несколько примеров манипуляции с данными:

# пример удаления колонки:
df = df.drop("A", axis=1)
# удалит дубликаты
df = df.drop_duplicates()
# Создание новой колонки со значением по умолчанию
df['new_col'] = 1
# а вот так можно добавлять колонку с условием
df['new_col2'] = np.where(df['score']>=10.0, True, False)

Применение произвольной функции ко всей колонке

def get_score(s):
    return s * 0.21

df['score'] = df.some_col.apply(get_score)

Переименование колонки, сортировка

# переименовываем колонку A на колонку C
df = df.rename(columns={'A': 'C'})
# сортировка по одной колонке
df = df.sort_values('price', axis=0, ascending=False)
# сортировка сразу по нескольким колонкам
df = df.sort_values(['price', 'score'], ascending=[1, 0])

пример на соединение или конкатенацию дата-фреймов

df = pd.concat([df1, df2], ignore_index=True, axis=0)

группировка в дата-фрейме без мультииндекса

df.groupby(['A'], as_index=False).agg({'B': lambda series: series.iloc[0]})

После всех манипуляций, вас скорее всего надо будет данные куда-то выгрузить в другом формате или сохранить до следующего раза новый фрагмент таблицы дата-фрейма:

# в numpy массив
df.values
# в numpy массив, но сразу всю матрицу
df.as_matrix
# сохранить в файл
df.to_csv('submission.csv', index=False)

Примеры использования Random Forest из scikit-learn для классификации

Один из классических алгоритмов классификации является, алгоритм использования ансамбля решающих деревьев Random Forest (далее просто RF). Его выбирают по следующим причинам:

  • Random Forest хорош для не нормализованных данных, многие алгоритмы машинного обучения (ML) дают плохие результаты и данные предварительно надо обрабатывать. Для RF этот шаг можно попробовать опустить и быстро получить работающей прототип
  • Быстрота обучения классификатора, поэтому для обучения можно использовать большое количество данных не беспокоясь в времени (в отличии от SVM). Распараллеливание алгоритма.
  • Можно получить важность / веса параметров из пространства признаков а также вероятность предсказания

Из некоторых минусув можно выделить то, что обучившись на одних и тех-же данных несколько раз — подход будет предсказывать немного разные значения с разными вероятностями. Т.е. детерминированности вы не получите. От этого не уйдешь, т.к. выборка ансамбля решающих деревьев происходит случайным образом. Для заморозки случайности используйте random_seed.

Первый пример c RF: обучаем модель и предсказываем один элемент

from sklearn.ensemble import RandomForestClassifier

x_train = [
    [1, 2],
    [3, 4],
    [-1, 2],
    [-3, 4]
]
y_train = [1, 1, 0, 0]
clf_rf = RandomForestClassifier()
clf_rf.fit(x_train, y_train)

print(clf_rf.predict([[2, 2]]))  # [1] это предсказанный класс
print(clf_rf.predict_proba([[2, 2]]))  # [[0.2 0.8]] вероятности по классам

Пример второй: кросс-валидация или разбиение оценка точности с помощью разбиения на выборки для теста и для тренировки модели RF

from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import train_test_split


x_train = [
    [1, 2], [5, 6],
    [3, 4], [7, 8],
    [-1, 2], [-5, 6],
    [-3, 4], [-7, 8], [0, 0]
]
y_train = [1, 1, 1, 1, 0, 0, 0, 0, 1]
clf_rf = RandomForestClassifier()

# разбиваем на два подмножества / фолда, параметр cv и получаем точность для каждого
scores = cross_val_score(clf_rf, x_train, y_train, cv=2)
print(scores)  # [0.8  0.75]

# кстати рабить на обучающую выборку и тестовую можно функцией
X_train, X_test, Y_train, Y_test = train_test_split(x_train, y_train, test_size=0.2)
print(X_test, Y_test)  # [[5, 6], [-3, 4]] [1, 0]

Возможно вы уже задались вопросом, какие параметры подкрутить, чтобы как-то влиять на точность и адаптировать алгоритм для входных данных и для железа.
n_estimators — параметр, напрямую влияющий на качество, при увеличении пространства признаков, следует рассмотреть увеличение этого параметра
max_depth — поможет если модель получилась сильно переобученной
criterion — entropy или gini . Можно с ними поиграться)
n_jobs — когда можно использовать несколько ядер
Пример третий: использование параметров для настройки RF
Здесь показано как с помощью GridSearchCV найти оптимальные параметры для классификатора.

from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV


x_train = [
    [1, 2], [5, 6],
    [3, 4], [7, 8],
    [-1, 2], [-5, 6],
    [-3, 4], [-7, 8], [0, 0]
]
y_train = [1, 1, 1, 1, 0, 0, 0, 0, 1]

parameter_grid = {
            'criterion': ['entropy', 'gini'],
            'max_depth': [10, 20, 100],
            'n_estimators': [10, 20, 100]
        }
clf = RandomForestClassifier()
grid_searcher = GridSearchCV(clf, parameter_grid, verbose=2)
grid_searcher.fit(x_train, y_train)
clf_best = grid_searcher.best_estimator_

print('Best params = ', clf_best.get_params())

Пример четвертый — сохранение и распаковка обученной модели:

from sklearn.externals import joblib
# предполагаем что clf - обучен выше
joblib.dump(clf, path_to_pkl, compress=1)
clf = joblib.load(self.path_to_pkl)

Здесь параметр compress — влияет на то на сколько сильно будет сжат файл классификатора, чем больше тем сильнее, однако не советую увлекаться, т.к. это обратнопропорционально вляет на время распаковки.

Пример пятый — рисуем график важности параметров. Вполне может пригодиться для презентации результатов.

from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
import matplotlib.pyplot as plt
import numpy as np



x_train = [
    [1, 2], [5, 6],
    [3, 4], [7, 8],
    [-1, 2], [-5, 6],
    [-3, 4], [-7, 8], [0, 0]
]
y_train = [1, 1, 1, 1, 0, 0, 0, 0, 1]

parameter_grid = {
            'criterion': ['entropy', 'gini'],
            'max_depth': [10, 20, 100],
            'n_estimators': [10, 20, 100]
        }
clf_rf = RandomForestClassifier()
clf_rf.fit(x_train, y_train)

importances = clf_rf.feature_importances_
print(importances)
std = np.std([tree.feature_importances_ for tree in clf_rf.estimators_], axis=0)

indices = np.argsort(importances)[::-1]
names_indices = ['x_coor', 'y_coor']

# Plot the feature importances of the forest
plt.figure()
plt.title("Feature importances")

plt.bar(range(len(importances)), importances[indices], color="r")
plt.xticks(range(len(importances)), names_indices, rotation=90)

plt.tight_layout()
plt.xlim([-1, len(importances)])
plt.show()

Как видно из нарисованного графика, первая координа является более ключевой, что действительно так по выборке. важность параметров в random forest

Простой пример нейронной сети на keras и tensorflow с тремя слоями

В данном посте будет показано, как инициализировать нейроннуй сеть на python, задать слои, обучить и получить предсказанные результаты. Пример сделан на python3, а в прослойке между tensorflow установлена библиотека Keras. Чтобы было понятнее — все входные параметры будут подписаны.
И так, нейронные сети очень мощный и не тривиальный инструмент в руках дата-инженера. Однако большинство продвижений в области машинного обучения в последние годы связано именно с нейронными сетями.
Установка:
keras и tensorflow ставится через pip: pip3 install keras и pip3 install —upgrade tensorflow
Отмечу, что здесь мы установили tensorflow для CPU, использование GPU даёт существенный прирост скорости, но и поставить посложнее.

Общий путь
1) Создание модели
2) Компилирование модели
3) Загрузка/подготовка данных
4) Обучение нейронной сети
5) Предсказание

Импорт библиотек:
import numpy as np
# Для создания простых моделей используют Sequential,
# При использовании Sequential достаточно добавить несколько своих слоев.
# Для более сложных моделей уже надо будет использовать Functional API
from keras.models import Sequential
from keras.layers import Dense # Dense — один из типов слоёв в Keras для создания слоя нейронов

Использовать будем бинарную классификацию, т.е. по набору фич надо определить принадлежит ли объект классу или нет.
Данные можете взять свои или например из этого файла data.txt. В нём есть 8 фич, а последний столбец показывает принадлежность классу

from keras.models import Sequential
from keras.layers import Dense
import numpy as np

# загружаем данные с фичами
dataset = np.loadtxt("data.txt", delimiter=",")
# Первые 8 столбцов в примере отвечают за фичи, последний же за класс, разбиваем 
X = dataset[:,0:8]
Y = dataset[:,8]

# Создаём модель!
model = Sequential()
# Добавляем первый слой Dense, первое число 12 - это количество нейронов, 
# input_dim - количество фич на вход
# activation -  функция активации, полулинейная функция max(x, 0) 
# именно полулинейные функции позволяют получать нелинейные результаты с минимальными затратами
model.add(Dense(12, input_dim=8, activation='relu'))
# добавляем второй слой с 8ю нейронами
model.add(Dense(8, activation='relu'))
# на выходе при бинарной классификации, функцию активации чаще всего используют sigmoid , реже softmax
# Компилирование модели. binary_crossentropy - опять же не случайно, а т.к. у нас два класса.
# Метрика accuracy используется практически для всех задач классификации
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

# Наконец дошли до обучения модели, X и Y - понятно, 
# epoch - максимальное количество эпох до остановки
# batch_size - сколько объектов будет загружаться за итерацию
model.fit(X, Y, epochs=15, batch_size=10,  verbose=2)
# Предсказание
predictions = model.predict(X)

Создание высокоточной нейронной сети - непростое задание. Порой хорошо работающие сетки получают случайно, и сложно объснить почему именно они хорошо работают. Поэтому дальше можете поиграть с разными параметрами. Заглядывая наперед - один из способов подбора гиперпараметров нейронной сети - использование библиотеки hyperopt, которая пытается сделать предсказать результирующую функцию, вместо перебора всех параметров, т.к. перебор параметров может быть уж сильно долгим.
Таким образом на выходе мы получаем обученную нейронную сеть на keras . Для использования этой сети в будущем, проще всего использовать model.save(filepath) . Обращу внимание, что picke не рекомендуется. А для загрузки сохраненной ранее модели: keras.models.load_model(filepath).

Определение языка текста на python с помощью langdetect

В данном посте покажем, как с помощью библиотеки langdetect определить язык текстового фрагмента. Для начала необходимо поставить библиотеку

$ pip install langdetect

Заметим, что код портирован на питон из гугловской библиотеки language-detection, поэтому качество распознавания языка находится на уровне, во всяком случае у меня пока особых претензий не было.
Далее, всё весьма стандартно, импортируем библиотеку и вызываем функцию «детектирования языка», пример:

from langdetect import detect
detect("здесь произвольный фрагмент текста на вход")
# результат: ru

По умолчанию поддерживается 55 языков, двухбуквенные коды взяты из стандарта кодов языков, и если быть подробнее, то они такие: af, ar, bg, bn, ca, cs, cy, da, de, el, en, es, et, fa, fi, fr, gu, he, hi, hr, hu, id, it, ja, kn, ko, lt, lv, mk, ml, mr, ne, nl, no, pa, pl, pt, ro, ru, sk, sl, so, sq, sv, sw, ta, te, th, tl, tr, uk, ur, vi, zh-cn, zh-tw

Но давайте копнём чуть глубже, ведь часто встречаются интернациональные тексты, в которых встречаются слова из разных языков. В таком случае на выходе хотелось бы получать список языков. Определение нескольких языков может быть решено с помощью detect_langs .

from langdetect import detect, detect_langs
from langdetect import DetectorFactory
DetectorFactory.seed = 0

detect_langs("Otec matka syn.") 
# результат [sk:0.572770823327, pl:0.292872522702, cs:0.134356653968]

Как видим, detect_langs определил не только языки, использованные в тексте, но ещё и их вероятности. Также возможно у Вас возник вопрос, зачем я использовал DetectorFactory? Дело в том, что алгоритм не является детерминированным, т.е. при разных запусках он может выдавать разные результаты. Если Вы хотите избежать разнозначности при разных запусках, то советую использовать DetectorFactory.seed = 0, если же такой необходимости нет, то лучше сэкономить пару строк.

Далее подметим, что detect_langs вернул не просто языки, а лист объектов Language, и возникает вопрос, как же получить языки и вероятности из этого листа? Смотрите пример:

from langdetect import detect_langs

list_of_languages = detect_langs("Здесь некий текст") 
for l in list_of_languages:
    # используем атрибуты lang и prod
    print(l.lang, l.prob)
    # результат: ru , 0.99

Определение языка может быть полезно при реализации поиска (для выдачи более релевантных результатов), а также для запуска языко-зависимых программ. Как видите с помощью langdetect определить язык можно всего в 2 строки!

Пример использования CountVectorizer в sklearn

Одна из первых концепций обрабтки естественных языков Bag-of-Words — это статистический анализ, анализирующий количественное вхождение слов в документах. Не смотря на то, что подход сформирован весьма давно, он отлично подходит для первичной обработки текстов и быстрого прототипирования.

Модуль CountVectorizer в sklearn как раз подзволяет сконвертировать набор текстов в матрицу токенов, находящихся в тексте. Также имеется много полезных настроек, например можно задать минимальное количество необходимое для появления токена в матрице и даже получить статистику по n-граммам. Следует учитывать, что CountVectorizer по умолчанию сам производит токенизацию и выкидывает слова с длиной меньшей чем два.

Пример:

from sklearn.feature_extraction.text import CountVectorizer
import numpy as np

# инициализируем
vectorizer = CountVectorizer()
# составляем корпус документов
corpus = [
  'слово1 слово2 слово3',
  'слово2 слово3',
  'слово1 слово2 слово1',
  'слово4'
]
# подсчитываем
X = vectorizer.fit_transform(corpus)

# таким образом будет подсчитана следующая структура:
#        | слово1 | слово2 | слово3 | слово4
# текст1 |   1    |    1   |   1    |   0
# текст2 |   0    |    1   |   1    |   0
# текст3 |   2    |    1   |   0    |   0
# текст4 |   0    |    0   |   0    |   1

# чтобы получить сгенерированный словарь, из приведенной структуры CountVectorizer, стоит отметить что порядок совпадает с матрицей
vectorizer.get_feature_names()  # ['слово1', 'слово2', 'слово3', 'слово4']

# чтобы узнать индекс токена в словаре
vectorizer.vocabulary_.get('слово3') # вернет 2

# показать матрицу
X.toarray()

# теперь можно быстро подсчитать вектор для нового документа
vectorizer.transform(["слово1 слово4 слово4"])  # результат [[1 0 0 2]]

# чтобы узнать количественное вхождение каждого слова:
matrix_freq = np.asarray(X.sum(axis=0)).ravel()
final_matrix = np.array([np.array(vectorizer.get_feature_names()), matrix_freq])

Один из минусов, что добавлять новые слова в словарь не получится, необходимо сразу указать все документы.
Второй из минусов, отчасти идущий от первого — плохая масштабируемость на большой набор текстов. Есть вероятность натолкнуться на MemoryError уже при десятке тысяч документов. Поэтому либо надо ограничивать количество фич/токенов для попадания в словарь с помощью настройки max_features или же использовать другую библиотеку. Однако для нескольких тысяч можно весьма быстро получить результат и далее использовать фичи например для классификации или кластеризации документов.