Category: Data Science

25
Ноя
2021

🤖 Решаем задачи машинного обучения с помощью алгоритма градиентного бустинга

Градиентный бустинг (Gradient Boosting) – один из самых эффективных инструментов для решения задач машинного обучения, в особенности на соревнованиях Kaggle. Чтобы научиться правильно его применять, разберем подробнее лежащие в основе алгоритма процессы.

Градиентный бустинг – это продвинутый алгоритм машинного обучения для решения задач классификации и регрессии. Он строит предсказание в виде ансамбля слабых предсказывающих моделей, которыми в основном являются деревья решений. Из нескольких слабых моделей в итоге мы собираем одну, но уже эффективную. Общая идея алгоритма – последовательное применение предиктора (предсказателя) таким образом, что каждая последующая модель сводит ошибку предыдущей к минимуму.

Предположим, что вы играете в гольф. Чтобы загнать мяч в лунĸу, вам необходимо замахиваться клюшкой, каждый раз исходя из предыдущего удара. То есть перед новым ударом гольфист в первую очередь смотрит на расстояние между мячом и лунĸой после предыдущего удара, так как наша основная задача – при следующем ударе уменьшить это расстояние.

Бустинг строится таким же способом. Для начала, нам нужно ввести определение “лунĸи”, а именно цели, которая является конечным результатом наших усилий. Далее необходимо понимать, куда нужно “бить ĸлюшĸой”, для попадания ближе ĸ цели. С учётом всех этих правил нам необходимо составить правильную последовательность действий, чтобы ĸаждый последующий удар соĸращал расстояние между мячом и лунĸой.

Стоит отметить, что для задач классификации и регрессии реализация алгоритма в программировании будет различаться.

Больше полезной информации вы найдете на нашем телеграм-канале «Библиотека data scientist’а».

Параметры алгоритма

  • criterion – критерий выбора расщепления, Mean Absolute Error (MAE) или Mean Squared Error (MSE). Используется только при построении деревьев.
  • init – какой алгоритм мы будем использовать в качестве главного (именно его и улучшает техника бустинга).
  • learning_rate – скорость обучения.
  • n_estimators – число итераций в бустинге. Чем больше, тем лучше качество, однако слишком большой увеличение данного параметра может привести к ухудшению производительности и переобучению.
  • min_samples_split – минимальное число объектов, при котором происходит расщепление. С данным параметром мы можем избежать переобучение.
  • min_samples_leaf – минимальное число объектов в листе (узле). При увеличении данного параметра качество модели на обучении падает, в то время как время построения модели сокращается. Меньшие значения стоит выбирать для менее сбалансированных выборок.
  • max_depth – максимальная глубина дерева. Используется для того, чтобы исключить возможность переобучения.
  • max_features – количество признаков, учитываемых алгоритмом для построения расщепления в дереве.
  • max_leaf_nodes : Максимальное число верхних точек в дереве. При наличии данного параметра max_depth будет игнорироваться.

Реализация на языке python (библиотека sklearn)

        ### Загружаем библиотеки и данные
import pandas as pd
import numpy as np
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler,LabelEncoder
from sklearn.datasets import load_breast_cancer
from sklearn.metrics import mean_squared_error,r2_score 

import warnings
warnings.filterwarnings('ignore')
breast_cancer = load_breast_cancer()


### Обозначаем целевую переменную для нашей будущей модели
X = pd.DataFrame(breast_cancer['data'], columns=breast_cancer['feature_names'])
y = pd.Categorical.from_codes(breast_cancer['target'], breast_cancer['target_names'])

lbl = LabelEncoder() 
lbl.fit(y)

y_enc = lbl.transform(y)


### Разбираемся с признаками
scl = StandardScaler()
scl.fit(X)
X_scaled = scl.transform(X)

X_train, X_test, y_train, y_test = train_test_split(X, y_enc, test_size=0.20, random_state=42)


### Прописываем параметры для нашей модели 
params = {'n_estimators':200,
          'max_depth':12,
          'criterion':'mse',
          'learning_rate':0.03,
          'min_samples_leaf':16,
          'min_samples_split':16
          }


### Тренируем
gbr = GradientBoostingRegressor(**params)
gbr.fit(X_train,y_train)


### Вычисляем точность
train_accuracy_score=gbr.score(X_train,y_train)
print(train_accuracy_score)

test_accuracy_score=gbr.score(X_test,y_test)
print(test_accuracy_score)

### Предсказание
y_pred = gbr.predict(X_test)

### И среднеквадратичную ошибку
mse = mean_squared_error(y_test,y_pred)
print("MSE: %.2f" % mse)
print(r2_score(y_test,y_pred))
    

Результат работы кода:

        0.9854271477118486
0.8728770740774442
MSE: 0.03
0.8728770740774442
    

Базовая модель градиентного бустинга с несложной простой настройкой дает нам точность более чем в 95% на задаче регрессии.

Какие библиотеки использовать?

Помимо классической для машинного обучения sklearn, для алгоритма градиентного бустинга существуют три наиболее используемые библиотеки:

XGBoost – более регуляризованная форма градиентного бустинга. Основным преимуществом данной библиотеки является производительность и эффективная оптимизация вычислений (лучший результат с меньшей затратой ресурсов).

Вы можете установить XGBoost следующим образом:

        pip install xgboost
    

Библиотека XGBoost предоставляем нам разные классы для разных задач: XGBClassifier для классификации и XGBregressor для регрессии.

Примечание
Все приведенные ниже библиотеки имеют отдельные классы для задач как классификации, так и регрессии.

  • Пример использования XGBoost для классификации:
        # xgboost для классификации
from numpy import asarray
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from xgboost import XGBClassifier
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
# определяем датасет
X, y = make_classification(n_samples=1000, n_features=10, n_informative=5, n_redundant=5, random_state=1)
# и нашу модель вместе с кросс-валидацией
model = XGBClassifier()
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
print('Точность: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
# тренируем модель на всём наборе данных
model = XGBClassifier()
model.fit(X, y)
# предсказываем
row = [2.56999479, -0.13019997, 3.16075093, -4.35936352, -1.61271951, -1.39352057, -2.48924933, -1.93094078, 3.26130366, 2.05692145]
row = asarray(row).reshape((1, len(row)))
yhat = model.predict(row)
print('Предсказание (Предикт): %d' % yhat[0])
    
  • Пример использования XGBoost для регрессии:
        # xgboost для регрессии
from numpy import asarray
from numpy import mean
from numpy import std
from sklearn.datasets import make_regression
from xgboost import XGBRegressor
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedKFold
# определяем датасет
X, y = make_regression(n_samples=1000, n_features=10, n_informative=5, random_state=1)
# и нашу модель (в данном примере мы меняем метрику на MAE)
model = XGBRegressor(objective='reg:squarederror')
cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1, error_score='raise')
print('MAE (Средняя Абсолютная Ошибка): %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
# тренируем модель на всём наборе данных
model = XGBRegressor(objective='reg:squarederror')
model.fit(X, y)
# предсказываем
row = [2.02220122, 0.31563495, 0.82797464, -0.30620401, 0.16003707, -1.44411381, 0.87616892, -0.50446586, 0.23009474, 0.76201118]
row = asarray(row).reshape((1, len(row)))
yhat = model.predict(row)
print('Предсказание (Предикт): %.3f' % yhat[0])

    
LightGBM – библиотека от Microsoft. В ней идет добавление авто выбора объектов и фокуса на тех частях бустинга, в которых мы имеем больший градиент. Это способствует значительному ускорению в обучении модели и улучшению показателей предсказания. Основная сфера применения – соревнования с использованием табличных данных на Kaggle.

Вы можете установить LightGBM также при помощи pip:

        pip install lightgbm
    
  • LightGBM для классификации:
        # lightgbm для классификации
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from lightgbm import LGBMClassifier
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
# определяем датасет
X, y = make_classification(n_samples=1000, n_features=10, n_informative=5, n_redundant=5, random_state=1)
# и нашу модель
model = LGBMClassifier()
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
print('Точность: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
# тренируем модель на всём наборе данных
model = LGBMClassifier()
model.fit(X, y)
# предсказываем
row = [[2.56999479, -0.13019997, 3.16075093, -4.35936352, -1.61271951, -1.39352057, -2.48924933, -1.93094078, 3.26130366, 2.05692145]]
yhat = model.predict(row)
print('Предсказание (Предикт): %d' % yhat[0])
    
  • LightGBM для регрессии:
        # lightgbm для регрессии
from numpy import mean
from numpy import std
from sklearn.datasets import make_regression
from lightgbm import LGBMRegressor
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedKFold
# определяем датасет
X, y = make_regression(n_samples=1000, n_features=10, n_informative=5, random_state=1)
# и нашу модель (в данном примере мы меняем метрику на MAE)
model = LGBMRegressor()
cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1, error_score='raise')
print('MAE (Средняя Абсолютная Ошибка): %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
# тренируем модель на всём наборе данных
model = LGBMRegressor()
model.fit(X, y)
# предсказываем
row = [[2.02220122, 0.31563495, 0.82797464, -0.30620401, 0.16003707, -1.44411381, 0.87616892, -0.50446586, 0.23009474, 0.76201118]]
yhat = model.predict(row)
print('Предсказание (Предикт): %.3f' % yhat[0])
    
CatBoost – это библиотека градиентного бустинга, которую создали разработчики Яндекса. Здесь используются “забывчивые” (oblivious) деревья решений, при помощи которых мы растим сбалансированное дерево. Одни и те же функции используются для создания разделений (split) на каждом уровне дерева.

Более того, главным преимуществом CatBoost (помимо улучшения скорости вычислений) является поддержка категориальных входных переменных. Из-за этого библиотека получила свое название CatBoost, от “Category Gradient Boosting” (Категориальный Градиентный Бустинг).

Вы можете установить CatBoost проверенным ранее путем:

        pip install catboost
    
  • CatBoost в задаче классификации:
        # catboost для классификации
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from catboost import CatBoostClassifier
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from matplotlib import pyplot
# определяем датасет
X, y = make_classification(n_samples=1000, n_features=10, n_informative=5, n_redundant=5, random_state=1)
# evaluate the model
model = CatBoostClassifier(verbose=0, n_estimators=100)
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
print('Точность: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
# тренируем модель на всём наборе данных
model = CatBoostClassifier(verbose=0, n_estimators=100)
model.fit(X, y)
# предсказываем
row = [[2.56999479, -0.13019997, 3.16075093, -4.35936352, -1.61271951, -1.39352057, -2.48924933, -1.93094078, 3.26130366, 2.05692145]]
yhat = model.predict(row)
print('Предсказание (Предикт): %d' % yhat[0])
    
  • CatBoost в задаче регрессии:
        # catboost для регрессии
from numpy import mean
from numpy import std
from sklearn.datasets import make_regression
from catboost import CatBoostRegressor
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedKFold
from matplotlib import pyplot
# определяем датасет
X, y = make_regression(n_samples=1000, n_features=10, n_informative=5, random_state=1)
# и нашу модель (в данном примере мы меняем метрику на MAE)
model = CatBoostRegressor(verbose=0, n_estimators=100)
cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1, error_score='raise')
print('MAE (Средняя Абсолютная Ошибка): %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
# тренируем модель на всём наборе данных
model = CatBoostRegressor(verbose=0, n_estimators=100)
model.fit(X, y)
# предсказываем
row = [[2.02220122, 0.31563495, 0.82797464, -0.30620401, 0.16003707, -1.44411381, 0.87616892, -0.50446586, 0.23009474, 0.76201118]]
yhat = model.predict(row)
print('Предсказание (Предикт): %.3f' % yhat[0])
    

Когда использовать?

Вы можете использовать алгоритм градиентного бустинга при следующих условиях:

  • Наличие большого количества наблюдений (ближайшее сходство) в тренировочной выборке данных.
  • Количество признаков меньше количества наблюдений в обучающих данных. Бустинг хорошо работает, когда данные содержат смесь числовых и категориальных признаков или только числовые признаки.
  • Когда необходимо рассмотреть метрики производительности модели.

Когда НЕ следует использовать XGBoost:

  • В задачах распознавания изображений и компьютерного зрения (CV – Computer Vision).
  • В обработке и понимании естественного языка (NLP – Natural Language Processing).
  • Когда число обучающих выборок значительно меньше чем число признаков (фич).

Плюсы и минусы

Плюсы

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

Минусы

  • Алгоритм крайне чувствителен к выбросам и при их наличии будет тратить огромное количество ресурсов на эти моменты. Однако, стоит отметить, что использование Mean Absolute Error (MAE) вместо Mean Squared Error (MSE) значительно снижает влияние выбросов на вашу модель (выбор функции в параметре criterion).
  • Ваша модель будет склонна к переобучению при слишком большом количестве деревьев. Данная проблема присутствует в любом алгоритме, связанном с деревьями и справляется правильной настройкой параметра n_estimators.
  • Вычисления могут занять много времени. Поэтому, если у вас большой набор данных, всегда составляйте правильный размер выборки и не забывайте правильно настроить параметр min_samples_leaf.
***

Хотя градиентный бустинг широко используется во всех областях науки о данных, от соревнований Kaggle до практических задач, многие специалисты все еще используют его как черный ящик. В этой статье мы разбили метод на более простые шаги, чтобы помочь читателям понять лежащие в основе работы алгоритма процессы. Удачи!

19
Ноя
2021

«Чёрная пятница» в GeekBrains

На выбор есть факультеты, профессии, программы и курсы по 7 направлениям: программирование, IT-инфраструктура, аналитика, дизайн, маркетинг, менеджмент и школьникам.
— Читать дальше ««Чёрная пятница» в GeekBrains»

12
Ноя
2021

🤖 Наивный байесовский алгоритм классификации: преимущества и недостатки

Наивный байесовский классификатор (Naive Bayes classifier) – это очень популярный в машинном обучении алгоритм, который в основном используется для получения базовой точности набора данных. Изучим его преимущества и недостатки, а также реализацию на языке Python.

Что это такое?

Наивный Байес – это самый простой алгоритм, который вы можете применить к своим данным. Как следует из названия, этот алгоритм делает предположение, что все переменные в наборе данных “наивные”, т.е. не коррелируют друг с другом.

Предположим, что вы видите перед собой что-то зеленое. Этот зеленый объект может быть ежиком, собакой или мячом. Естественно, вы предположите, что это будет мяч. Но почему?

Вы создаете алгоритм и вашей целью является проблема выше: классифицировать объект между мячом, ежиком и собакой. Сначала вы подумаете об определении символов объекта, а затем об их сопоставлении с объектами классификации, например, если объект – круг, то это будет мяч, если объект – колючее живое существо, то это будет ежик, а если наш объект лает, то, вероятно, это будет собака.

Причина проста: мы с детства видим зеленый шар, но собака или ежик такого цвета крайне маловероятны для нас. Таким образом, в нашем случае мы можем классифицировать объект, сопоставив его признаки с нашим классификатором по отдельности. Зеленый цвет был сопоставлен с ежом, собакой и мячом, и в итоге мы получили наибольшую вероятность принадлежности зеленого объекта к мячу. Это и есть причина, почему мы классифицировали его как мяч.

Больше полезной информации вы можете найти на нашем телеграм-канале «Библиотека data scientist’а».

Теоретическая составляющая алгоритма

Теорема Байеса позволяет рассчитать апостериорную вероятность P(A | B) на основе P(A), P(B) и P(B | A).


Где:

  • P(A | B) – апостериорная вероятность (что A из B истинно)
  • P(A) – априорная вероятность (независимая вероятность A)
  • P(B | A) – вероятность данного значения признака при данном классе. (что B из A истинно)
  • P(B) – априорная вероятность при значении нашего признака. (независимая вероятность B)

Реализация на языке python

        ### Загружаем библиотеки и данные
import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from scipy.stats import norm
 
data = load_iris()
X, y, column_names = data['data'], data['target'], data['feature_names']
X = pd.DataFrame(X, columns = column_names)
 
### Разбиваем данные
from sklearn.model_selection import train_test_split
X_train, X_val, y_train, y_val = train_test_split(X, y, random_state=44)
 
means = X_train.groupby(y_train).apply(np.mean)
stds = X_train.groupby(y_train).apply(np.std)
 
### Вычисляем априорную вероятность класса
probs = X_train.groupby(y_train).apply(lambda x: len(x)) / X_train.shape[0]
 
### Вычисляем вероятность для Теоремы Байеса для каждого элемента
y_pred = []
# каждый элемент в валидационной части данных
for elem in range(X_val.shape[0]):
   p = {}
 
   # для каждого возможного класса
   for cl in np.unique(y_train):
 
       # априорная вероятность взятого ранее класса
       p[cl] = probs.iloc[cl]
 
       # для каждого столбца в датасете
       for index, param in enumerate(X_val.iloc[elem]):
 
           # умножаем вероятность того, что данное значение столбца
           # будет принадлежать распределению для выбранного класса
           p[cl] *= norm.pdf(param, means.iloc[cl, index], stds.iloc[cl, index])
  
   y_pred.append(pd.Series(p).values.argmax())
 
### Посмотрим точность нашего предсказания несколькими методами
# ручной классификатор
from sklearn.metrics import accuracy_score
accuracy1 = accuracy_score(y_val, y_pred)
 
# классификатор из библиотеки sklearn
from sklearn.naive_bayes import GaussianNB
model = GaussianNB()
model.fit(X_train, y_train)
accuracy2 = accuracy_score(y_val, model.predict(X_val))
 
print(accuracy1)
print(accuracy2)
    

Результат работы кода:

        0.9210526315789473
0.9210526315789473
    

Базовая модель с самой простой настройкой дает нам точность более чем в 90% на задаче классификации цветков ириса.

Плюсы и минусы

Плюсы

  • Алгоритм легко и быстро предсказывает класс тестового набора данных. Он также хорошо справляется с многоклассовым прогнозированием.
  • Производительность наивного байесовского классификатора лучше, чем у других простых алгоритмов, таких как логистическая регрессия. Более того, вам требуется меньше обучающих данных.
  • Он хорошо работает с категориальными признаками(по сравнению с числовыми). Для числовых признаков предполагается нормальное распределение, что может быть серьезным допущением в точности нашего алгоритма.

Минусы

  • Если переменная имеет категорию (в тестовом наборе данных), которая не наблюдалась в обучающем наборе данных, то модель присвоит 0 (нулевую) вероятность и не сможет сделать предсказание. Это часто называют нулевой частотой. Чтобы решить эту проблему, мы можем использовать технику сглаживания. Один из самых простых методов сглаживания называется оценкой Лапласа.
  • Значения спрогнозированных вероятностей, возвращенные методом predict_proba, не всегда являются достаточно точными.
  • Ограничением данного алгоритма является предположение о независимости признаков. Однако в реальных задачах полностью независимые признаки встречаются крайне редко.

В каких областях использовать?

Алгоритм наивного Байеса – это классификатор, обучение которого идет очень быстро. Следовательно, данный инструмент идеально подходит для составления прогнозов в реальном времени.

Также этот алгоритм также хорошо известен благодаря функции многоклассового прогнозирования. Мы можем предсказать вероятность нескольких классов целевой переменной.

Таким образом, идеальные области для применения наивного байесовского классификатора это:

  • Система рекомендаций. В сочетании алгоритма с методами коллаборативной фильтрации (Collaborative Filtering) мы можем создать рекомендательную систему, которая использует машинное обучение и методы добычи данных для учета невидимой информации (такой, как поиск фильмов пользователем и длительность просмотра). Цель – предсказание того, понравится ли пользователю данный ресурс/продукт или нет.
  • Фильтрация спама и классификация текста. Наивный байесовский классификатор в основном используются для классификации текстов (благодаря лучшему результату в многоклассовых проблемах и правилу независимости) и имеет более высокую точность по сравнению с другими алгоритмами. В результате он широко используется в фильтрации спама (в электронной почте) и анализе настроений (к примеру, социальных сетей, для выявления положительных и отрицательных настроений клиентов).
***

Из этого руководства вы узнали о наивном байесовском алгоритме классификации, его работе, проблемах, реализации, преимуществах и недостатках.

Параллельно вы также научились реализовывать его на языке Python. Наивный Байесовский классификатор – одих из самых простых и эффективных алгоритмов машинного обучения.

Несмотря на значительные успехи других методов за последние несколько лет, Байес все так же доказывает свою ценность. Он успешно применяется во многих приложениях, от текстовой аналитики и спам-фильтров до систем рекомендаций.

09
Ноя
2021

Хакатон WildHack

Хакатон от Wildberries с призовым фондом 500 000 рублей. Приглашают разработчиков, DataScience и ML-специалистов, аналитиков, маркетологов и дизайнеров
— Читать дальше «Хакатон WildHack»

25
Окт
2021

Хакатон AgroCode Weekend

Хакатон для веб-разработчиков, Data Science, Machine Learning и Computer Vision специалистов с призовым фондом в 2 220 000 рублей.
— Читать дальше «Хакатон AgroCode Weekend»

21
Окт
2021

🤖 Состояние дел в области синтеза речи на конец мая 2021 года

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

28
Сен
2021

📊 Kaggle за 30 минут: разбираемся с соревнованием House Prices

Из предыдущей статьи мы узнали, что такое Kaggle и какие разделы предлагает этот ресурс. Теперь разберемся с одним из самых базовых соревнований Kaggle – House Prices.

Для начала необходимо ознакомиться с целью соревнования, правилами и данными. Также стоит вспомнить основы работы с Kaggle из первой статьи.

Перед нами стоит задача предсказания стоимости дома на основе множества признаков (фич), вроде расположения, площади, количества комнат, наличия гаража и т.д.

Это состязание по решению задачи регрессии, исходя из чего мы и будем действовать.

Данные состоят из четырех файлов:

  • train.csv – обучающая (тренировочная) выборка.
  • test.csv – тестовые данные, на основе которых мы будем делать предсказания.
  • data_description.txt – полное описание каждого столбца.
  • sample_submission.csv – пример того, как должен выглядеть наш ответ (сабмит).

Весь код воспроизводится в ячейках jupyter notebook.

Для начала, загружаем тестовую и тренировочную выборки.

        import numpy as np
import pandas as pd

df_train = pd.read_csv('../input/train.csv')
df_test  = pd.read_csv('../input/test.csv')

# Просматриваем данные
train_df.head()
    

Определим размеры датасета. Для анализа будем использовать тренировочную часть.

        train_df.shape
    
Получаем (1460, 81), а именно 81 столбец и 1460 строк.
Получаем (1460, 81), а именно 81 столбец и 1460 строк.

Обзор данных – целевая переменная

Первое, что мы должны сделать – посмотреть на нашу целевую переменную SalePrice.

        train_df['SalePrice'].describe()
    

Создается впечатление, что цена дома существенно отклоняется от нормального распределения:

  • Стандартное отклонение слишком велико.
  • Минимум больше 0 (что логично для цен на недвижимость).
  • Существует большая разница между минимальным значением и 25-м процентилем.
  • Разница между 75-м процентилем и максимумом больше, чем 25-й процентиль и максимум.

Нам стоит создать гистограмму, чтобы окончательно убедиться в том, с каким распределением мы имеем дело.

        # Импортируем необходимые библиотеки для визуализации
import matplotlib.pyplot as plt
import seaborn as sns

# гистограмма
f, ax = plt.subplots(figsize=(8, 6))
sns.distplot(train_df['SalePrice'])
    

Как мы и полагали, распределение далеко от идеального. Проведем больше наблюдений:

        # Рассчитываем асимметрию и эксцесс
print("Ассиметрия: %f" % train_df['SalePrice'].skew())
print("Эксцесс: %f" % train_df['SalePrice'].kurt())
    
  • Ассиметрия: 1.882876.
  • Эксцесс: 6.536282.

С этим нужно что-то делать. Возможно, нам поможет логарифмическое преобразование целевой переменной? Создадим два графика: один с исходными данными, другой с применением упомянутой выше техники:

        from scipy import stats 

fig = plt.figure(figsize = (14,8))

# Распределение на необработанных данных
fig.add_subplot(1,2,1)
res = stats.probplot(train_df['SalePrice'], plot=plt)

# Распределение при условии, что мы прологарифмировали 'SalePrice'
fig.add_subplot(1,2,2)
res = stats.probplot(np.log1p(train_df['SalePrice']), plot=plt)
    

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

        train_df['SalePrice'] = np.log1p(train_df['SalePrice'])
    

Обзор данных – корреляция

Теперь посмотрим, с какими признаками коррелирует целевая переменная SalePrice:

        # Матрица корреляции
corrmat = train_df.corr()
f, ax = plt.subplots(figsize=(12, 9))
sns.heatmap(corrmat, vmax=.8, square=True);
    
На таком графике непросто отобрать нужные нам “фичи”.
На таком графике непросто отобрать нужные нам “фичи”.

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

        k = 10 # количество коррелирующих признаков, которое мы хотим увидеть
cols = corrmat.nlargest(k, 'SalePrice')['SalePrice'].index
cm = np.corrcoef(train_df[cols].values.T)
sns.set(font_scale=1.25)
hm = sns.heatmap(cm, cbar=True, annot=True, square=True, 
                 fmt='.2f', annot_kws={'size': 10}, 
                 yticklabels=cols.values, xticklabels=cols.values)
plt.show()
    

Теперь мы видим, что лучше всего SalePrice коррелирует с GrLivArea и OverallQual. Проверим эти два признака на наличие выбросов:

        fig, ax = plt.subplots()
ax.scatter(x = train_df['GrLivArea'], y = train_df['SalePrice'])
plt.ylabel('SalePrice', fontsize=13)
plt.xlabel('GrLivArea', fontsize=13)
plt.show()
    

        fig, ax = plt.subplots()
ax.scatter(x = train_df['OverallQual'], y = train_df['SalePrice'])
plt.ylabel('SalePrice', fontsize=13)
plt.xlabel('OverallQual', fontsize=13)
plt.show()
    

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

        # Ликвидируем 
# Только эти 2 удаления помогут нам улучшить наш показатель на таблице лидеров
train_df = train_df.drop(train[(train['OverallQual'] > 9) & (train['SalePrice'] < 220000)].index)
train_df = train_df.drop(train[(train['GrLivArea'] > 4000) & (train['SalePrice'] < 300000)].index)
    

Очистка данных и отбор признаков

Далее стоит провести исследование данных на наличие пропущенных данных и других моментов, которые могут испортить score (а значит и нашу позицию в таблице лидеров соревнования).

Эта строчка кода выведет топ-20 пропущенных значений:

        # Пропущенные значения
train_df.isnull().sum().sort_values(ascending=False).head(20)
    

На диаграмме масштаб пропущенных значений будет виден лучше:

        # Визуализируем
total = train_df.isnull().sum().sort_values(ascending=False)
percent = (train_df.isnull().sum() / train_df.isnull().count()).sort_values(ascending=False)
missing_data = pd.concat([total, percent], axis=1, keys=['Total', 'Percent'])

# Гистограмма
percent_data = percent.head(20)
percent_data.plot(kind="bar", figsize = (8,6), fontsize = 10)
plt.xlabel("Столбцы", fontsize = 20)
plt.ylabel("Count", fontsize = 20)
plt.title("Общее количество недостающих значений  (%)", fontsize = 20)
    

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

Исправим проблему на объединенных данных.

        # Удаляем строки, где целевое значение (target) пропущено
Target = 'SalePrice'
train_df.dropna(axis=0, subset=[Target], inplace=True)

# Соединяем тренировочный и тестовый датасеты, чтобы провести наши преобразования на всех данных
all_data = pd.concat([train_df.iloc[:,:-1], test_df],axis=0)

print('У тренировочного датасета {} рядов и {} признаков'.format(train_df.shape[0], train_df.shape[1]))
print('У тестового датасета {} рядов и {} признаков'.format(test_df.shape[0], test_df.shape[1]))
print('Объединённый датасет содержит в себе {} рядов и {} признаков'.format(all_data.shape[0], all_data.shape[1]))
    
        # Удаляем бесполезный столбец
all_data = all_data.drop(columns=['Id'], axis=1)
    

Теперь мы можем полноценно разобраться с пропущенными данными.

        # Функция для просмотра пропущенных данных
# При желании вместо 'train_df' вы можете забить 'all_data'

def missingValuesInfo(df):
    total = df.isnull().sum().sort_values(ascending = False)
    percent = round(df.isnull().sum().sort_values(ascending = False) / len(df)*100, 2)
    temp = pd.concat([total, percent], axis=1, keys=['Total', 'Percent'])
    return temp.loc[(temp['Total'] > 0)]

missingValuesInfo(train_df)
    
        # Разбираемся с пропущенными данными
# Числовые значения отбираем через принадлежность к формату ['int64', 'float64']
# Категориальные значения отбираем через принадлежность к формату ["object"]

def HandleMissingValues(df):
    num_cols = [cname for cname in df.columns if df[cname].dtype in ['int64', 'float64']]
    cat_cols = [cname for cname in df.columns if df[cname].dtype == "object"]
    values = {}
    for a in cat_cols:
        values[a] = 'UNKNOWN'

    for a in num_cols:
        values[a] = df[a].median()
        
    df.fillna(value=values, inplace=True)
    
    
HandleMissingValues(all_data)
all_data.head()
    
        # Проверим
all_data.isnull().sum().sum()
    

Результат – 0.

Отлично, мы справились с основной проблемой. Не стоит также забывать о категориальных признаках.

        # Разбираемся с категориальными признаками

def getObjectColumnsList(df):
    return [cname for cname in df.columns if df[cname].dtype == "object"]

def PerformOneHotEncoding(df, columnsToEncode):
    return pd.get_dummies(df, columns=columnsToEncode)

cat_cols = getObjectColumnsList(all_data)
all_data = PerformOneHotEncoding(all_data, cat_cols)
all_data.head()
    

Наша задача по базовой очистке данных и отбору признаков решена. Теперь мы можем снова разбить данные на тренировочный и тестовый датасеты. Это необходимо, так как предсказывать поведение будущей модели мы будем на тестовой выборке.

        train_data = all_data.iloc[:1460, :]
test_data = all_data.iloc[1460:, :]
print(train_df.shape)
print(test_df.shape)
    

Моделирование

Так как в соревновании House Prices перед участниками стоит задача регрессии, использовать мы будем соответствующие модели.

Ridge regression

        from sklearn.linear_model import RidgeCV

ridge_cv = RidgeCV(alphas = (0.01, 0.05, 0.1, 0.3, 1, 3, 5, 10))
ridge_cv.fit(X, y)
ridge_cv_preds = ridge_cv.predict(test_data)
    

И также XGBRegressor

        import xgboost as xgb

model_xgb = xgb.XGBRegressor(n_estimators=340, max_depth=2, learning_rate=0.2)
model_xgb.fit(X, y)
xgb_preds = model_xgb.predict(test_data)
    

Возьмем усредненное значение от обеих моделей:

        predictions = (ridge_cv_preds + xgb_preds) / 2

    

Создадим датафрейм, чтобы выложить наше решение.

        submission = {
    'Id': test_df.Id.values,
    'SalePrice': predictions
}
solution = pd.DataFrame(submission)
solution.to_csv('submission.csv',index=False)
    

Заключение

Цель этой статьи – предоставить вам базовое понимание “пайплайна”, который необходим для успешного покорения Kaggle. Сюда входят:

  • Загрузка данных, их тщательное изучение и последующая очистка.
  • Отбор признаков, при необходимости – создание новых.
  • Выбор правильной модели (в продвинутых случаях – ансамбль нескольких моделей), подбор приемлемых параметров.
  • Предсказание и успешный сабмит.
Исходя из этого, вы можете усовершенствовать описанное выше базовое решение. Например, разобраться с пропущенными данными по отдельности для каждого признака, а не циклом, создать новые “фичи” на основе имеющихся, или же найти параметры, которые увеличат score модели в таблице лидеров.

Поиск лучшего решения на соревновании Kaggle – это целое искусство, освоить которое вы сможете, комбинируя самые разнообразные техники с нестандартными методами.

***

Если вы только начинаете путь в профессию и еще не определились со специализацией, подумайте о применении методов науки о данных в медицинской отрасли: сейчас это одно из самых перспективных направлений. Образовательная онлайн-платформа GeekBrains проводит набор на факультет Data Science в медицине, на котором студенты научатся с нуля решать задачи в области медицины. Обучение длится 18 месяцев, плюс 6 месяцев занимает практика по медицинской специализации. По итогам получите 15 проектов в портфолио и гарантию трудоустройства.

28
Сен
2021

📊 Kaggle за 30 минут: разбираемся с соревнованием House Prices

Из предыдущей статьи мы узнали, что такое Kaggle и какие разделы предлагает этот ресурс. Теперь разберемся с одним из самых базовых соревнований Kaggle – House Prices.

Для начала необходимо ознакомиться с целью соревнования, правилами и данными. Также стоит вспомнить основы работы с Kaggle из первой статьи.

Перед нами стоит задача предсказания стоимости дома на основе множества признаков (фич), вроде расположения, площади, количества комнат, наличия гаража и т.д.

Это состязание по решению задачи регрессии, исходя из чего мы и будем действовать.

Данные состоят из четырех файлов:

  • train.csv – обучающая (тренировочная) выборка.
  • test.csv – тестовые данные, на основе которых мы будем делать предсказания.
  • data_description.txt – полное описание каждого столбца.
  • sample_submission.csv – пример того, как должен выглядеть наш ответ (сабмит).

Весь код воспроизводится в ячейках jupyter notebook.

Для начала, загружаем тестовую и тренировочную выборки.

        import numpy as np
import pandas as pd

df_train = pd.read_csv('../input/train.csv')
df_test  = pd.read_csv('../input/test.csv')

# Просматриваем данные
train_df.head()
    

Определим размеры датасета. Для анализа будем использовать тренировочную часть.

        train_df.shape
    
Получаем (1460, 81), а именно 81 столбец и 1460 строк.
Получаем (1460, 81), а именно 81 столбец и 1460 строк.

Обзор данных – целевая переменная

Первое, что мы должны сделать – посмотреть на нашу целевую переменную SalePrice.

        train_df['SalePrice'].describe()
    

Создается впечатление, что цена дома существенно отклоняется от нормального распределения:

  • Стандартное отклонение слишком велико.
  • Минимум больше 0 (что логично для цен на недвижимость).
  • Существует большая разница между минимальным значением и 25-м процентилем.
  • Разница между 75-м процентилем и максимумом больше, чем 25-й процентиль и максимум.

Нам стоит создать гистограмму, чтобы окончательно убедиться в том, с каким распределением мы имеем дело.

        # Импортируем необходимые библиотеки для визуализации
import matplotlib.pyplot as plt
import seaborn as sns

# гистограмма
f, ax = plt.subplots(figsize=(8, 6))
sns.distplot(train_df['SalePrice'])
    

Как мы и полагали, распределение далеко от идеального. Проведем больше наблюдений:

        # Рассчитываем асимметрию и эксцесс
print("Ассиметрия: %f" % train_df['SalePrice'].skew())
print("Эксцесс: %f" % train_df['SalePrice'].kurt())
    
  • Ассиметрия: 1.882876.
  • Эксцесс: 6.536282.

С этим нужно что-то делать. Возможно, нам поможет логарифмическое преобразование целевой переменной? Создадим два графика: один с исходными данными, другой с применением упомянутой выше техники:

        from scipy import stats 

fig = plt.figure(figsize = (14,8))

# Распределение на необработанных данных
fig.add_subplot(1,2,1)
res = stats.probplot(train_df['SalePrice'], plot=plt)

# Распределение при условии, что мы прологарифмировали 'SalePrice'
fig.add_subplot(1,2,2)
res = stats.probplot(np.log1p(train_df['SalePrice']), plot=plt)
    

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

        train_df['SalePrice'] = np.log1p(train_df['SalePrice'])
    

Обзор данных – корреляция

Теперь посмотрим, с какими признаками коррелирует целевая переменная SalePrice:

        # Матрица корреляции
corrmat = train_df.corr()
f, ax = plt.subplots(figsize=(12, 9))
sns.heatmap(corrmat, vmax=.8, square=True);
    
На таком графике непросто отобрать нужные нам “фичи”.
На таком графике непросто отобрать нужные нам “фичи”.

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

        k = 10 # количество коррелирующих признаков, которое мы хотим увидеть
cols = corrmat.nlargest(k, 'SalePrice')['SalePrice'].index
cm = np.corrcoef(train_df[cols].values.T)
sns.set(font_scale=1.25)
hm = sns.heatmap(cm, cbar=True, annot=True, square=True, 
                 fmt='.2f', annot_kws={'size': 10}, 
                 yticklabels=cols.values, xticklabels=cols.values)
plt.show()
    

Теперь мы видим, что лучше всего SalePrice коррелирует с GrLivArea и OverallQual. Проверим эти два признака на наличие выбросов:

        fig, ax = plt.subplots()
ax.scatter(x = train_df['GrLivArea'], y = train_df['SalePrice'])
plt.ylabel('SalePrice', fontsize=13)
plt.xlabel('GrLivArea', fontsize=13)
plt.show()
    

        fig, ax = plt.subplots()
ax.scatter(x = train_df['OverallQual'], y = train_df['SalePrice'])
plt.ylabel('SalePrice', fontsize=13)
plt.xlabel('OverallQual', fontsize=13)
plt.show()
    

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

        # Ликвидируем 
# Только эти 2 удаления помогут нам улучшить наш показатель на таблице лидеров
train_df = train_df.drop(train[(train['OverallQual'] > 9) & (train['SalePrice'] < 220000)].index)
train_df = train_df.drop(train[(train['GrLivArea'] > 4000) & (train['SalePrice'] < 300000)].index)
    

Очистка данных и отбор признаков

Далее стоит провести исследование данных на наличие пропущенных данных и других моментов, которые могут испортить score (а значит и нашу позицию в таблице лидеров соревнования).

Эта строчка кода выведет топ-20 пропущенных значений:

        # Пропущенные значения
train_df.isnull().sum().sort_values(ascending=False).head(20)
    

На диаграмме масштаб пропущенных значений будет виден лучше:

        # Визуализируем
total = train_df.isnull().sum().sort_values(ascending=False)
percent = (train_df.isnull().sum() / train_df.isnull().count()).sort_values(ascending=False)
missing_data = pd.concat([total, percent], axis=1, keys=['Total', 'Percent'])

# Гистограмма
percent_data = percent.head(20)
percent_data.plot(kind="bar", figsize = (8,6), fontsize = 10)
plt.xlabel("Столбцы", fontsize = 20)
plt.ylabel("Count", fontsize = 20)
plt.title("Общее количество недостающих значений  (%)", fontsize = 20)
    

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

Исправим проблему на объединенных данных.

        # Удаляем строки, где целевое значение (target) пропущено
Target = 'SalePrice'
train_df.dropna(axis=0, subset=[Target], inplace=True)

# Соединяем тренировочный и тестовый датасеты, чтобы провести наши преобразования на всех данных
all_data = pd.concat([train_df.iloc[:,:-1], test_df],axis=0)

print('У тренировочного датасета {} рядов и {} признаков'.format(train_df.shape[0], train_df.shape[1]))
print('У тестового датасета {} рядов и {} признаков'.format(test_df.shape[0], test_df.shape[1]))
print('Объединённый датасет содержит в себе {} рядов и {} признаков'.format(all_data.shape[0], all_data.shape[1]))
    
        # Удаляем бесполезный столбец
all_data = all_data.drop(columns=['Id'], axis=1)
    

Теперь мы можем полноценно разобраться с пропущенными данными.

        # Функция для просмотра пропущенных данных
# При желании вместо 'train_df' вы можете забить 'all_data'

def missingValuesInfo(df):
    total = df.isnull().sum().sort_values(ascending = False)
    percent = round(df.isnull().sum().sort_values(ascending = False) / len(df)*100, 2)
    temp = pd.concat([total, percent], axis=1, keys=['Total', 'Percent'])
    return temp.loc[(temp['Total'] > 0)]

missingValuesInfo(train_df)
    
        # Разбираемся с пропущенными данными
# Числовые значения отбираем через принадлежность к формату ['int64', 'float64']
# Категориальные значения отбираем через принадлежность к формату ["object"]

def HandleMissingValues(df):
    num_cols = [cname for cname in df.columns if df[cname].dtype in ['int64', 'float64']]
    cat_cols = [cname for cname in df.columns if df[cname].dtype == "object"]
    values = {}
    for a in cat_cols:
        values[a] = 'UNKNOWN'

    for a in num_cols:
        values[a] = df[a].median()
        
    df.fillna(value=values, inplace=True)
    
    
HandleMissingValues(all_data)
all_data.head()
    
        # Проверим
all_data.isnull().sum().sum()
    

Результат – 0.

Отлично, мы справились с основной проблемой. Не стоит также забывать о категориальных признаках.

        # Разбираемся с категориальными признаками

def getObjectColumnsList(df):
    return [cname for cname in df.columns if df[cname].dtype == "object"]

def PerformOneHotEncoding(df, columnsToEncode):
    return pd.get_dummies(df, columns=columnsToEncode)

cat_cols = getObjectColumnsList(all_data)
all_data = PerformOneHotEncoding(all_data, cat_cols)
all_data.head()
    

Наша задача по базовой очистке данных и отбору признаков решена. Теперь мы можем снова разбить данные на тренировочный и тестовый датасеты. Это необходимо, так как предсказывать поведение будущей модели мы будем на тестовой выборке.

        train_data = all_data.iloc[:1460, :]
test_data = all_data.iloc[1460:, :]
print(train_df.shape)
print(test_df.shape)
    

Моделирование

Так как в соревновании House Prices перед участниками стоит задача регрессии, использовать мы будем соответствующие модели.

Ridge regression

        from sklearn.linear_model import RidgeCV

ridge_cv = RidgeCV(alphas = (0.01, 0.05, 0.1, 0.3, 1, 3, 5, 10))
ridge_cv.fit(X, y)
ridge_cv_preds = ridge_cv.predict(test_data)
    

И также XGBRegressor

        import xgboost as xgb

model_xgb = xgb.XGBRegressor(n_estimators=340, max_depth=2, learning_rate=0.2)
model_xgb.fit(X, y)
xgb_preds = model_xgb.predict(test_data)
    

Возьмем усредненное значение от обеих моделей:

        predictions = (ridge_cv_preds + xgb_preds) / 2

    

Создадим датафрейм, чтобы выложить наше решение.

        submission = {
    'Id': test_df.Id.values,
    'SalePrice': predictions
}
solution = pd.DataFrame(submission)
solution.to_csv('submission.csv',index=False)
    

Заключение

Цель этой статьи – предоставить вам базовое понимание “пайплайна”, который необходим для успешного покорения Kaggle. Сюда входят:

  • Загрузка данных, их тщательное изучение и последующая очистка.
  • Отбор признаков, при необходимости – создание новых.
  • Выбор правильной модели (в продвинутых случаях – ансамбль нескольких моделей), подбор приемлемых параметров.
  • Предсказание и успешный сабмит.
Исходя из этого, вы можете усовершенствовать описанное выше базовое решение. Например, разобраться с пропущенными данными по отдельности для каждого признака, а не циклом, создать новые “фичи” на основе имеющихся, или же найти параметры, которые увеличат score модели в таблице лидеров.

Поиск лучшего решения на соревновании Kaggle – это целое искусство, освоить которое вы сможете, комбинируя самые разнообразные техники с нестандартными методами.

***

Если вы только начинаете путь в профессию и еще не определились со специализацией, подумайте о применении методов науки о данных в медицинской отрасли: сейчас это одно из самых перспективных направлений. Образовательная онлайн-платформа GeekBrains проводит набор на факультет Data Science в медицине, на котором студенты научатся с нуля решать задачи в области медицины. Обучение длится 18 месяцев, плюс 6 месяцев занимает практика по медицинской специализации. По итогам получите 15 проектов в портфолио и гарантию трудоустройства.

25
Сен
2021

📊 Построение и отбор признаков. Часть 2: feature selection

Мы уже знаем, что такое признаки и почему они важны в моделях машинного обучения. Попробуем разобраться со следующей после построения “фич” техникой – их отбором.

Что такое отбор признаков?

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

«Прогонка» всех признаков в модели, чтобы посмотреть, какие из них работают – плохая идея. На самом деле алгоритмы работают плохо, когда в них попадает слишком много “фич”. Как решить эту проблему? При помощи отбора признаков.

Отбор признаков (feature selection) – это оценка важности того или иного признака с помощью алгоритмов машинного обучения и отсечение ненужных.

Существует масса алгоритмов, которые преобразуют набор со слишком большим количеством признаков в управляемое подмножество. Как и в случае с построением признаков, для разных типов данных оптимальны разные способы. Более того, при выборе алгоритма необходимо учитывать наши цели, что мы хотим сделать с обрабатываемым датасетом.

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

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

1. Методы фильтрации (filter methods)

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

Сбор информации (Information Gain, IG)

Вычисляет уменьшение энтропии в результате преобразования набора данных. Его можно использовать для отбора признаков путем оценки информационного прироста каждой переменной в контексте целевой переменной.

        import pandas as pd
import numpy as np
from sklearn.feature_selection import mutual_info_classif
import matplotlib.pyplot as plt

importances = mutual_info_classif(X, y)
# Где data - ваш датасет; X, y – входные и выходные данные соответственно
feature_importances = pd.Series(importances, data.columns[0:len(data.columns)-1])
feature_importances.plot(kind='barh', color='teal')
plt.show()
    

Критерий хи-квадрат (Chi-square Test)

Используется для категориальных признаков в датасете. Мы вычисляем хи-квадрат между каждым признаком и целью, после выбираем желаемое количество “фич” с лучшими показателями. Чтобы правильно применить критерий для проверки связи между различными функциями в наборе данных и целевой переменной, должны быть выполнены следующие условия: категориальные переменные, которые выбираются независимо, и частота значений > 5.

        import pandas as pd
import numpy as np
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2

# Преобразование в категориальные данные путем преобразования в целые числа.
# Где X, y - входные и выходные данные соответственно.
X_categorical = X.astype(int)

# Выбираем 3 признака с наивысшим "хи-квадрат".
chi2_features = SelectKBest(chi2, k = 3)
X_kbest_features = chi2_features.fit_transform(X_categorical, y)

# Вывод "до и после"
print("Количество признаков до преобразования:", X_categorical.shape[1])
print("Количество признаков после преобразования:", X_kbest_features.shape[1])
    

Критерий Фишера (F-тест)

Критерий Фишера – один из наиболее широко используемых методов контролируемого выбора признаков. Алгоритм, который мы будем использовать, возвращает ранги переменных на основе оценки критерия в порядке убывания, после чего уже следует их отбор.

        import pandas as pd
import numpy as np
from skfeature.function.similarity_based import fisher_score
import matplotlib.pyplot as plt

# Вычисляем критерий
# Где X, y - входные и выходные данные соответственно.
ranks = fisher_score.fisher_score(X, y)

# Делаем график наших "фич"
# Где data - ваш датасет
feature_importances = pd.Series(ranks, data.columns[0:len(data.columns)-1])
feature_importances.plot(kind='barh', color='teal')
plt.show()
    

Коэффициент корреляции

Корреляция – это мера линейной связи двух или более переменных. При её помощи мы можем предсказать одну переменную через другую. Логика использования этого метода для выбора характеристик заключается в том, что “хорошие” переменные сильно коррелируют с нашей целью.

Стоит отметить, что переменные должны коррелировать с целевым показателем, но не должны между собой. В примере ниже мы будем использовать корреляцию Пирсона.

        import seaborn as sns
import matplotlib.pyplot as plt

# Матрица корреляции
# Где data - ваш датасет
correlation_matrix = data.corr()

# Выводим признаки на тепловую карту
plt.figure(figsize= (10, 6))
sns.heatmap(correlation_matrix, annot = True)
    

Абсолютное отклонение (Mean Absolute Difference, MAD)

Эта техника позволяет нам вычислить абсолютное отклонение от среднего.

        import pandas as pd
import numpy as np
import matplotlib as plt
# Вычисляем MAD
# Где X - входные данные
mean_absolute_difference = np.sum(np.abs(X - np.mean(X, axis = 0)), axis = 0) / X.shape[0]

# Наш график признаков
plt.bar(np.arange(X.shape[1]), mean_absolute_difference, color = 'teal')
    

2. Методы обертки (wrapper methods)

Особенность этих методов – поиск всех возможных подмножеств признаков и оценка их качества путем “прогонки” через модель.

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

Прямой отбор признаков

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

        from sklearn.linear_model import LogisticRegression
from mlxtend.feature_selection import SequentialFeatureSelector
 
lr = LogisticRegression(class_weight = 'balanced', solver = 'lbfgs', random_state=42, n_jobs=-1, max_iter=50e)
ffs = SequentialFeatureSelector(lr, k_features='best', forward = True, n_jobs=-1)
 
ffs.fit(X, Y)
# X, y – входные и выходные данные соответственно.
# X_train – входные данные с обучающейся выборки,
# y_pred – выходные данные предиктора
features = list(ffs.k_feature_names_)
features = list(map(int, features))
y_pred = lr.predict(X_train[features])
    

Последовательный отбор признаков

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

        from sklearn.linear_model import LogisticRegression
from mlxtend.feature_selection import SequentialFeatureSelector

lr = LogisticRegression(class_weight = 'balanced', solver = 'lbfgs', random_state=42, n_jobs=-1, max_iter=50e)
lr.fit(X, y)

bfs = SequentialFeatureSelector(lr, k_features='best', forward = False, n_jobs=-1)
bfs.fit(X, y)
features = list(bfs.k_feature_names_)
features = list(map(int, features))
lr.fit(X_train[features], y_train)
y_pred = lr.predict(x_train[features])
    

Исчерпывающий выбор признаков

Это самый надежный метод выбора функций из всех существующих. Его суть – оценка каждого подмножества функций методом перебора. Это означает, что метод пропускает все возможные комбинации переменных через алгоритм и возвращает наиболее эффективное подмножество.

        from mlxtend.feature_selection import ExhaustiveFeatureSelector
from sklearn.ensemble import RandomForestClassifier

# создаем ExhaustiveFeatureSeLlector объект.
efs = ExhaustiveFeatureSelector(RandomForestClassifier(),
        min_features=4,
        max_features=8,
        scoring='roc_auc',
        cv=2)

efs = efs.fit(X, Y)

# выводим выбранные признаки
selected_features = X_train.columns[list(efs.best_idx_)]
print(selected_features)

# выводим финальную оценку прогнозирования.
print(efs.best_score_)
    

Рекурсивное исключение признаков

Сначала модель обучается на начальной выборке признаков, и важность каждой функции определяется либо с помощью атрибута coef_ или feature_importances_. Затем наименее важные “фичи” удаляются из текущего набора. Процедура рекурсивно повторяется для сокращенного набора до тех пор, пока в конечном итоге не будет достигнуто желаемое количество признаков для выбора.

        from sklearn.linear_model import LogisticRegression
from sklearn.feature_selection import RFE

lr = LogisticRegression(class_weight = 'balanced', solver = 'lbfgs', random_state=42, n_jobs=-1, max_iter=50e)

rfe = RFE(lr, n_features_to_select=7)
rfe.fit(X_train, y_train)
# X_train, y_train - входные и выходные данные с обучающей выборки соответственно.
y_pred = rfe.predict(X_train)
    

3. Встроенные методы (embedded methods)

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

Регуляризация LASSO (L1)

Регуляризация состоит в добавлении штрафа (penalty) к различным параметрам модели во избежание чрезмерной подгонки. При регуляризации линейной модели штраф применяется к коэффициентам, умножающим каждый из предикторов. Lasso-регуляризация обладает свойством, позволяющим уменьшить некоторые коэффициенты до нуля. Следовательно, такие “фичи” можно будет просто удалить из модели.

        from sklearn.linear_model import LogisticRegression
from sklearn.feature_selection import SelectFromModel

# Устанавливаем наш параметр регуляризации C=1
logistic = LogisticRegression(C=1, penalty="l1", solver='liblinear', random_state=7).fit(X, y)
# Где X, y - входные и выходные данные соответственно.
model = SelectFromModel(logistic, prefit=True)

X_new = model.transform(X)

# Выбираем нужные нам столбцы из датасета без нулевых данных
# Где “selected_features” - предварительно выбранные нами признаки (см. по предыдущим методам)
selected_columns = selected_features.columns[selected_features.var() != 0]
print(selected_columns)

    

Метод с использованием Случайного Леса (Random Forest Importance)

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

        import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestClassifier

# создаем случайное дерево с вашими гипер параметрами
model = RandomForestClassifier(n_estimators=340)

# Обучаем модель на вашей выборке; Где X, y - входные и выходные данные соответственно.
model.fit(X, y)

# Подбираем самые важные признаки
importances = model.feature_importances_

# Создаем отдельный датасет для визуализации
final_df = pd.DataFrame({"Features" : pd.DataFrame(X).columns, "Importances" : importances})
final_df.set_index('Importances')

# Сортируем их по возрастанию для лучшей визуализации
final_df = final_df.sort_values('Importances')

# Выводим на график
final_df.plot.bar(color = 'teal')
    

Заключение

Эффективный отбор необходимых “фич” для модели приводит к наибольшему увеличению производительности. Это та проблема, за решением которой дата-сайентисты проводят большую часть времени. Разумеется, без построения признаков (feature engineering) у нас не будет материала для дальнейшего отбора.

Правильные преобразования зависят от многих факторов: типа и структуры данных, их объема. Не стоит также забывать о доступных ресурсах нашего компьютера или облака. Взяв на вооружение обе техники из этого цикла статей, вы будете чувствовать себя гораздо увереннее в мире науки о данных.

17
Сен
2021

📊 Kaggle за 30 минут: практическое руководство для начинающих

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

Что такое Kaggle?
Kaggle – это сообщество специалистов по Data Science. Изначально оно было соревновательной платформой, однако со временем обзавелось многими другими разделами (о них ниже). В результате мы имеем своеобразную соцсеть для дата-сайентистов, с полным циклом становления нового специалиста: от образовательных мини-курсов по основам машинного обучения до соревнований по исследованию данных.

Как начать?

Прежде чем начать покорение Kaggle, необходимо зарегистрироваться на сайте. Переходим по ссылке и нажимаем кнопку Register. У вас будет два варианта: зарегистрироваться через аккаунт Google или по адресу электронной почты. Получаем подтверждение на почту, логинимся – готово, теперь вы в Kaggle сообществе.

Важно:
На ресурсе есть система продвижения. Как только вы зарегистрируетесь, ваш аккаунт будет на самом низком уровне: Новичок (Novice).


Следующий уровень – Участник (Contributor). Достичь его можно несколькими простыми действиями:

  • Запустите 1 скрипт или notebook.
  • Сделайте 1 сабмит в любое соревнование.
  • Напишите 1 комментарий.
  • Сделайте 1 upvote (аналог лайка – стрелочка вверх).

Ниже вы найдете подробное руководство о том, как совершить эти действия и получить значок Contributor.


Что есть на Kaggle?

После регистрации мы оказываемся на главной странице ресурса и видим там несколько разделов.
После регистрации мы оказываемся на главной странице ресурса и видим там несколько разделов.
Competitions – те самые соревнования Kaggle
Они разделяются на несколько типов. Так, Getting Started и Playground представляют из себя соревнования с заранее обработанными данными и простыми задачами. Featured и Research – более сложные и полномасштабные состязания. Они охватывают весь цикл работ специалиста по Data Science (например, приведение данных в приемлемое состояние). Задача в подобных соревнованиях – решение нетривиальной проблемы, часто от таких крупных корпораций, как Google или Amazon, с солидным денежным вознаграждением для победителей.


Datasets – наборы данных на любой вкус и цвет
Здесь присутствует как дата для соревнований, так и пользовательская. Можно выкладывать собственные датасеты.

Code – пользовательский код
Онлайн-редактор, который позволяет создать Jupyter Notebook или простой скрипт на языках Python и R. Вы просто подключаете данные и работаете в браузере без необходимости устанавливать библиотеки и зависимости. Код выкладывается самый разнообразный: от EDA (Exploratory Data Analysis, он же подробный разбор) задач с соревнований, до простых методов, которые помогут оптимизировать ваши программы.


Ниже панели поиска находятся теги, по которым вы можете отобрать «нотбуки», которые вас интересуют.

Стрелочка под названием – это тот самый Upvote, по количеству которых определяется релевантность. Рекомендую выбрать интересующий вас notebook, лайкнуть его, прокомментировать и нажать кнопку Copy and Edit. Таким образом вы сохраните его у себя в профиле (аналог форка на GitHub), сможете запустить ячейки внутри него и получить описанную выше плашку Kaggle Contributor.

Discussions – обсуждение
Разделенный на несколько частей форум.


  • General – всё, что связано с самим Kaggle (анонсы, дискуссии по поводу прошедших соревнований) и жизненными циклами моделей машинного обучения.
  • Getting Started – аналог предыдущего раздела, но для новичков. Рекомендуется для посещения в первую очередь.
  • Product Feedback – отзывы о сайте. Если в процессе работы на Kaggle вы столкнулись с техническими проблемами, вам сюда.
  • Question & Answers – советы по технической составляющей от других дата-сайентистов.
  • Learn – вопросы и дискуссии, которые касаются раздела Courses на сайте.

Как принять участие в соревновании Kaggle?

Найдите приемлемое для вас соревнование. Потом нажмите Join Competition и согласитесь с условиями.


  • Overview – обзор соревнования. Здесь изложена суть проблемы, которую нужно решить. Также в этом разделе указана метрика, которая используется в состязании и другие требования (например, формат «сабмита»).
  • Data – данные, по которым нужно добиться наилучшего показателя метрики.
  • Code – тут участники соревнования выкладывают свои идеи и решения. Этот раздел рекомендуется для посещений в первую очередь, так как вы можете подсмотреть идеи для своих решений.
  • Discussion – обсуждение проблем соревнования, методов решения, нюансов.
  • Leaderboard – доска лидеров. В продвинутых соревнованиях на ней присутствуют золотая секция для денежных призов, серебряная для поощрительных и бронзовая для медалей Kaggle.
  • Rules – правила соревнования.
  • Team – есть не во всех состязаниях. Лучше всего создавать команды на более сложных этапах покорения Kaggle, для начала – пробуйте сами, чтобы обзавестись необходимыми навыками.

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

Чаще всего данные разбиваются на сеты train и test. При помощи первого вы обучаете модель, а уже на основе второго делаете предсказание (predict) перед сохранением решения (Submission).

Чтобы составить решение прямо на сайте, вам нужно:

  • Создать новый notebook в разделе Code.

  • Добавить туда данные соревнования, нажав кнопку Add data.

  • Сохранить notebook.

  • После этого у вас высветится меню, где нужно нажать Submit to Competition.

Теперь ваше решение появилось в турнирной таблице.

Самые простые соревнования для начинающих.

Примечание:
Данные соревнования входят в категории Getting Started и Playground. Вы не получите за них денежные призы и медали, однако, это отличный способ улучшить свои навыки и влиться в соревновательную среду Kaggle.

  • Titanic. Пожалуй, самое известное соревнование для новичков. Датасет «Титаника» содержит данные пассажиров одноименного корабля. Ваша цель – построение такой модели, которая наилучшим образом сможет предсказать, остался произвольный пассажир в живых или нет. Это типичная задача классификации.
  • House prices. Перед нами стоит задача предсказания стоимости дома на основе множества признаков (фич), вроде местоположения, площади, количества комнат, наличия гаража и т.д. Существует и более продвинутая версия этого соревнования – Advanced Regression Techniques. Здесь нужно решить задачу регрессии, поэтому вы можете наполнить модель линейными методами.
  • Tabular Playground Series. Запускается каждый месяц с января 2021 года. Ваша цель – предсказать столбец target на основе простых, табличных данных. В отличии от описанных выше бесконечных соревнований, Tabular Playground длится ровно месяц, что делает его более динамичным. Здесь будет меньше открытых нотбуков с готовыми ответами, но больше пространства для создания собственного, уникального решения.

Почему стоит участвовать в соревнованиях Kaggle?

Если вы еще не пробовали Kaggle, самое время начать. Соревнования помогут вам научиться решать реальные задачи из области Data Science и выбрать одно из ее многочисленных направлений. В режиме непрерывной практики за неделю вы узнаете больше, чем за 3 месяца изучения теории. Более того, медали с соревнований будут плюсом при трудоустройстве: работодатели обязательно обратят внимание на ваш практический опыт.

***

Если вы только начинаете путь в профессию и еще не определились со специализацией, подумайте о применении методов науки о данных в медицинской отрасли: сейчас это одно из самых перспективных направлений. Образовательная онлайн-платформа GeekBrains проводит набор на факультет Data Science в медицине, на котором студенты научатся с нуля решать задачи в области медицины. Обучение длится 18 месяцев, плюс 6 месяцев занимает практика по медицинской специализации. По итогам получите 15 проектов в портфолио и гарантию трудоустройства.

15
Сен
2021

📊 Построение и отбор признаков. Часть 1: feature engineering

Машинное обучение – это не просто подбор правильных параметров для модели. Рабочие процессы ML зависят от построения и отбора признаков. В сообществах специалистов по Data Science эти понятия ошибочно отождествляют. Разберемся, для чего нам нужны признаки, а также изучим особенности реализации техники feature engineering.

Что такое признаки (features) и для чего они нужны?

Признак, он же «фича» (от англ feature) – это переменная (столбец в таблице), которая описывает отдельную характеристику объекта. Признаки являются краеугольным камнем задач машинного обучения в целом: именно на их основании мы строим предсказания в моделях.

Признаки могут быть следующих видов:

  • Бинарные, которые принимают только два значения. Например, [true, false], [0,1], [“да”, “нет”].
  • Категориальные (или же номинальные). Они имеют конечное количество уровней, например, признак «день недели» имеет 7 уровней: понедельник, вторник и т. д. до воскресенья.
  • Упорядоченные. В некоторой степени похожи на категориальные признаки. Разница между ними в том, что данном случае существует четкое упорядочивание категорий. Например, «классы в школе» от 1 до 11. Сюда же можно отнести «время суток», которое имеет 24 уровня и является упорядоченным.
  • Числовые (количественные). Это значения в диапазоне от минус бесконечности до плюс бесконечности, которые нельзя отнести к предыдущим трем типам признаков.

Стоит отметить, что для задач машинного обучения нужны только те «фичи», которые на самом деле влияют на итоговый результат. Определить и сгенерировать такие признаки вам поможет эта статья.

Что такое построение признаков?

Построение признаков (Feature Engineering) – это процесс, во время которого мы извлекаем новые переменные для таблицы из необработанных данных. В жизни редко данные приходят в виде готовых матриц, потому любая задача начинается с извлечения признаков.

Например, в базе данных интернет-магазина есть таблица «Покупатели», содержащая одну строку для каждого посетившего сайт клиента.

В ней также может быть таблица «Взаимодействия», содержащая строку для каждого взаимодействия (клика или посещения страницы), которое клиент совершил на сайте. Эта таблица также содержит информацию о времени взаимодействия и типе события, которое представляло собой взаимодействие (событие «Покупка», событие «Поиск» или событие «Добавить в корзину»). Эти две таблицы связаны между собой столбцом Customer ID.



Чтобы предсказать, когда покупатель приобретет товар в следующий раз, мы хотели бы получить единую числовую матрицу признаков со строкой для каждого покупателя. Затем мы можем использовать ее в алгоритме машинного обучения. Однако таблица, которая больше всего похожа на эту («Покупатели»), не содержит практически никакой релевантной информации. Мы можем построить из нее несколько характеристик, например, количества дней, прошедших с момента регистрации клиента, но наши возможности на этом этапе ограничены.

Чтобы повысить предсказательную способность, нам необходимо воспользоваться данными в таблице взаимодействий. Отбор признаков делает это возможным. Мы можем рассчитать статистику для каждого клиента, используя все значения в таблице «Взаимодействия» с идентификатором этого клиента. Вот несколько потенциально полезных признаков, или же «фич», которые помогут нам в решении задачи:

  • Среднее время между прошлыми покупками.
  • Средняя сумма прошлых покупок.
  • Максимальная сумма прошлых покупок.
  • Время, прошедшее с момента последней покупки.
  • Общее количество покупок в прошлом.

Чтобы построить эти признаки, мы должны найти все связанные с конкретным клиентом взаимодействия. Затем мы проведем фильтрацию тех, чей Тип (Type) не является "Покупкой", и вычислим функцию, которая возвращает одно значение, используя имеющиеся данные.

Следует обратить внимание, что данный процесс уникален для каждого случая использования и набора данных.

Этот тип инжиниринга признаков необходим для эффективного использования алгоритмов машинного обучения и построения прогностических моделей.

Ниже будут перечислены основные и самые известные методы feature engineering с кратким описанием и кодом реализации.

Построение признаков на табличных данных

Удаление пропущенных значений

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

Самое простое решение для пропущенных значений – отбросить строки или весь столбец. Оптимального порога для отбрасывания не существует, но вы можете использовать 70% в качестве значения и отбросить строки со столбцами, в которых отсутствуют значения, превышающие этот порог.

        import pandas as pd
import numpy as np

threshold = 0.7
# Удаление столбцов с коэффициентом пропущенных значений выше порога
data = data[data.columns[data.isnull().mean() < threshold]]

# Удаление строк с коэффициентом отсутствия значений выше порога
data = data.loc[data.isnull().mean(axis=1) < threshold]
    

Заполнение пропущенных значений

Более предпочтительный вариант, чем отбрасывание, потому что он сохраняет размер данных. Очень важно, что именно вы относите к недостающим значениям. Например, если у вас есть столбец, с числами 1 и N/A , то вполне вероятно, что строки N/A соответствуют 0 .

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

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

        import pandas as pd
import numpy as np

# Заполнение всех пропущенных значений 0
 data = data.fillna (0)
# Заполнение пропущенных значений медианами столбцов
 data = data.fillna (data.median ())
    

Замена пропущенных значений максимальными

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

        import pandas as pd
import numpy as np

data['column_name'].fillna(data['column_name'].value_counts() .idxmax(), inplace=True) 
    

Обнаружение выбросов

Прежде чем упомянуть, как можно обрабатывать выбросы, я хочу заявить, что лучший способ обнаружить выбросы – провести визуализацию вашего датасета. В этом вам помогут библиотеки seaborn и matplotlib.

Что касается обнаружения выбросов: один из лучших способов это сделать – рассчитать стандартное отклонение. Если значение отклоняется больше, чем на x * стандартное отклонение, его можно принять, как выброс. Наиболее используемое значение для x – в пределах [2, 4].

        import pandas as pd
import numpy as np

# Удаление неподходящих строк
x = 3
upper_lim = data['column'].mean () + data['column'].std () * x 
lower_lim = data['column'].mean () - data['column'].std () * x
data = data[(data['column'] < upper_lim) & (data['column'] > lower_lim)]
    

Другой математический метод обнаружения выбросов – использование процентилей. Вы принимаете определенный процент значения сверху или снизу за выброс.

Ключевым моментом здесь является повторная установка процентного значения, и это зависит от распределения ваших данных, как упоминалось ранее.

Кроме того, распространенной ошибкой является использование процентилей в соответствии с диапазоном данных. Другими словами, если ваши данные находятся в диапазоне от 0 до 100 , ваши лучшие 5% – это не значения между 96 и 100 . Верхние 5% означают здесь значения, выходящие за пределы 95-го процентиля данных.

        import pandas as pd
import numpy as np

# Избавляемся от лишних строк при помощи процентилей
upper_lim = data['column'].quantile(.95)
lower_lim = data['column'].quantile(.05)
data = data[(data['column'] < upper_lim) & (data['column'] > lower_lim)]
    

Ограничение выбросов

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

С другой стороны, ограничение может повлиять на распределение данных и качество модели, поэтому лучше придерживаться золотой середины.

        import pandas as pd
import numpy as np

upper_lim = data['column'].quantile(.95)
lower_lim = data['column'].quantile(.05)
data.loc[(df[column] > upper_lim),column] = upper_lim
data.loc[(df[column] < lower_lim),column] = lower_lim
    

Логарифмическое преобразование

Логарифмическое преобразование – одно из наиболее часто используемых во время построения признаков математических преобразований.

  • Оно помогает обрабатывать искаженные данные, и после преобразования распределение становится более приближенным к нормальному.
  • В большинстве случаев порядок величины данных изменяется в пределах диапазона данных. Например, разница между возрастом от 15 до 20 лет не равна возрасту от 65 до 70 лет, так как по всем остальным аспектам разница в 5 лет в молодом возрасте означает большую разницу в величине. Этот тип данных поступает в результате мультипликативного процесса, и логарифмическое преобразование нормализует подобные различия величин.
  • Это также снижает влияние выбросов за счет нормализации разницы величин, и модель становится более надежной.

Важное примечание: данные, которые вы применяете, должны иметь только положительные значения, иначе вы получите ошибку.

        import pandas as pd
import numpy as np

# Пример логарифмической трансформации
data = pd.DataFrame({'value':[2,45, -23, 85, 28, 2, 35, -12]})
data['log+1'] = (data['value']+1).transform(np.log)

# Обработка отрицательных значений
# (Обратите внимание, что значения разные)
data['log'] = (data['value']-data['value'].min()+1) .transform(np.log)
    

Быстрое кодирование (One-Hot encoding)

Этот метод распределяет значения в столбце по нескольким столбцам флагов и присваивает им 0 или 1. Бинарные значения выражают связь между сгруппированным и закодированным столбцом. Этот метод изменяет ваши категориальные данные, которые сложно понять алгоритмам, в числовой формат. Группировка происходит без потери какой-либо информации, например:


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

        encoded_columns = pd.get_dummies(data['column'])
data = data.join(encoded_columns).drop('column', axis=1)
    

Масштабирование признаков

В большинстве случаев числовые характеристики набора данных не имеют определенного диапазона и отличаются друг от друга.

Например, столбцы возраста и месячной зарплаты будут иметь совершенно разный диапазон.

Как сравнить эти два столбца, если это необходимо в нашей задаче? Масштабирование решает эту проблему, так как после данной операции элементы становятся идентичными по диапазону.

Существует два распространенных способа масштабирования:

  • Нормализация.

В данном случае все значения будут находиться в диапазоне от 0 до 1. Дискретные бинарные значения определяются как 0 и 1.


        import pandas as pd
import numpy as np

data = pd.DataFrame({'value':[2,45, -23, 85, 28, 2, 35, -12]})

data['normalized'] = (data['value'] - data['value'].min()) / (data['value'].max() - data['value'].min())
    
  • Стандартизация.

Масштабирует значения с учетом стандартного отклонения. Если стандартное отклонение функций другое, их диапазон также будет отличаться друг от друга. Это снижает влияние выбросов в элементах. В следующей формуле стандартизации среднее значение показано как μ, а стандартное отклонение показано как σ.


        import pandas as pd
import numpy as np

data = pd.DataFrame({'value':[2,45, -23, 85, 28, 2, 35, -12]})

data['standardized'] = (data['value'] - data['value'].mean()) / data['value'].std()
    

Работа с текстом

Методов работы с текстом слишком много, чтобы они уместились в один тезис статьи. Тем не менее, ниже будет описан самый популярный подход.

Перед тем как работать с текстом, его необходимо разбить на токены – отдельные слова. Однако делая это слишком просто, мы можем потерять часть смысла. Например, «Великие Луки» это не два токена, а один.

После превращения документа в последовательность слов, можно начинать превращать их в векторы. Самый простой метод – Bag of Words. Мы создаем вектор длиной в словарь, для каждого слова считаем количество его вхождений в текст и подставляем это число на соответствующую позицию в векторе.

В коде алгоритм выглядит гораздо проще, чем на словах:

        from functools import reduce
import numpy as np

texts = [['i', 'have', 'a', 'cat'],
         ['he', 'have', 'a', 'dog'],
         ['he', 'and', 'i', 'have', 'a', 'cat', 'and', 'a', 'dog']]

dictionary = list(enumerate(set(reduce(lambda x, y: x + y, texts))))

def vectorize(text):
    vector = np.zeros(len(dictionary))
    for i, word in dictionary:
        num = 0
        for w in text:
            if w == word:
                num += 1
        if num:
            vector[i] = num
    return vector
for t in texts:
    print(vectorize(t))
    

Работа с изображениями

Что касается изображений, то методы построения и извлечения признаков для этого типа данных – одни из самых простых.

Часто для задач с изображениями используется определенная сверточная сеть. Необязательно продумывать архитектуру сети и обучать ее с нуля. Можно взять уже обученную нейросеть из открытых источников.

Чтобы адаптировать ее под свою задачу, работающие в области науки о данных инженеры практикуют fine tuning (тонкую настройку). Ликвидируются последние слои нейросети, вместо них добавляются новые, подобранные под нашу конкретную задачу, и сеть дообучается на новых данных.

Пример подобного шаблона:

        from keras.applications.resnet50 import ResNet50
from keras.preprocessing import image
from scipy.misc import face
import numpy as np

resnet_settings = {'include_top': False, 'weights': 'imagenet'}
resnet = ResNet50(**resnet_settings)

img = image.array_to_img(face())
img = img.resize((224, 224))
# в реальной жизни может понадобиться внимательнее относиться к ресайзу
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
# нужно дополнительное измерение, т.к. модель рассчитана на работу с массивом изображений

features = resnet.predict(x)
    

Заключение

Правильное построение признаков крайне важно в улучшении наших моделей машинного обучения. К тому же без этого этапа мы не сможем осуществить последующую технику отбора признаков.

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

Следующая статья будет посвящена отбору признаков.

14
Сен
2021

📊 Обучение на Data Scientist: как составить резюме, пройти собеседование и найти работу?

Читайте обзор ресурсов для составления резюме, поиска вакансий и прохождения собеседования на позицию Data Scientist.

Независимо от того, являетесь ли вы опытным специалистом по Data Science или новичком, вы можете столкнуться с трудностями при поиске работы. В небольшом обзоре мы разберемся, какие стратегии, ресурсы и инструменты помогут продать себя на рынке труда, и как получить лучшие офферы.

Составляем резюме

Контент

Наряду с навыками и знаниями, которыми должны обладать Data Scientist, узнайте о последних тенденциях отрасли: как работает корпорация, каковы востребованные рабочие роли, каковы новейшие языки программирования и т.д. Работа в Data Science – это прежде всего умение учиться самостоятельно и постоянно обновлять набор навыков.


Не забудьте включить в резюме ссылки на GitHub, Twitter, Linkedin и другие ресурсы, позволяющие продемонстрировать ваш опыт. Опубликуйте проекты, над которыми вы работали во время учебы и стажировок. Таким образом работодатель сможет заметить вас и оценить ваши навыки, отточенные на реальных задачах. Если вы являетесь новичком в науке данных и хотите найти первую работу, но у вас еще нет опыта, создайте собственные проекты! Для поиска первого оффера достаточно двух-трех примеров:

  • Опубликуйте результаты соревнований Kaggle и код;
  • Создайте проект, который покажет ваши личные интересы или примите участие в хакатоне;
  • Включите проекты и код, созданные во время прохождения курсов Data Science.

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

  • Почему вы это сделали? Какую проблему вы хотели решить? Покажите, какова была конечная цель проекта.
  • Что вы сделали? Объясните, как вы подошли к проблеме. Если вы можете показать код, статью, сообщение в блоге или презентацию на конференции – сделайте это!
  • Как вы это сделали? Представьте инструменты и ресурсы, которые вы использовали.
  • Чего вы добились? Отразите количественные результаты вашей работы в технических и бизнес-показателях.
Если вы начинаете карьеру специалиста по Data Science, будьте предельно настойчивы в поиске контрактов. Создайте личный веб-сайт с демонстрацией примеров вашей работы и убедитесь, что он прост в навигации, лаконичен и постоянно обновляется. Потенциальные работодатели обязательно захотят заглянуть в ваше портфолио, поэтому приступите к его оформлению в первую очередь.

Сбалансируйте ваше резюме: наряду с техническими навыками важно показать применение навыков визуализации и презентации данных, story telling, soft skills и умение работать в команде.

Стиль

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

  • Постарайтесь разместить всю информацию на одной странице. Если у вас большой опыт, много проектов или публикаций – упомяните несколько из них в резюме и предоставьте ссылку на Github или личный веб-сайт.
  • Выделите ссылки, используя Bold или Underline. Это позволит сотрудникам HR быстрее их обнаружить.
  • Соблюдайте единый стиль ссылок, дат, названий компаний и университетов, знаков пунктуации и т.д. Эти маленькие детали играют большую роль в общей визуальной картине вашего резюме.
  • Сделать хорошую профессиональную фотографию для резюме – сложная задача. Это необязательно, и никто на самом деле не ожидает, что у вас будет фотография. Многие компании предпочитают лаконичные резюме без фото, таким образом отбор кандидатов проходит более объективно.
  • Проверьте орфографию и пунктуацию. Ошибки и опечатки в резюме раздражают и указывают на недостаточное внимание к деталям. Перечитайте свои тексты с Text.ru, Advego (на русском) или Grammarly, ReversoSpeller (на английском) прежде чем отправлять их. Попросите друзей проверить ваше резюме: они могут заметить ошибки, которые вы упустили.

Обзор ресурсов


Canva – платформа для графического дизайна и создания резюме, постеров и разнообразного визуального контента.

Примеры:

Overleaf – редактор LaTeX, используемый для написания, редактирования и публикации научных документов, резюме и т.д. Платформа сотрудничает с широким кругом издателей, предоставляя официальные шаблоны журнала LaTeX и прямые ссылки для отправки.

Примеры:

CVmaker – платформа для создания профессионального резюме за 10 минут. Интегрированные в CVmaker шаблоны позволяют легко изменять контент или цвета вашего резюме.

Поиск вакансий

Стратегии поиска

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

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


Не бойтесь вести переговоры! Если вы готовы освоить дополнительные навыки в ходе работы, не спешите отказываться от офферов, которые их требуют. Работа в Data Science – это постоянное самообучение. Если же вы не уверены, что сможете выполнить заказ качественно и в срок, стоит задуматься, стоит ли вознаграждение риска потерять репутацию.

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

Попробуйте найти кого-нибудь, кто работает в компании, и кто может направить вас и предоставить рекомендацию. Это увеличит ваши шансы на прохождение первого этапа отбора. Обычно, если кандидата нанимают на работу, порекомендовавший его человек получает денежный бонус. Это беспроигрышная ситуация.

Всегда лучше попросить рекомендации у своих друзей или слабых связей, но также можно сначала написать в Linkedin. Найдите профиль сотрудника компании в Linkedin, свяжитесь с ним или с ней и напишите сообщение. Не бойтесь попросить рекомендации у незнакомца. Если вы покажете свою мотивацию и приложенные усилия, вам обязательно помогут. Будьте уважительны: не отправляйте разным людям одно и то же сообщение с измененным названием компании. Уважайте время других, будучи кратким и конкретным. Убедите других помочь вам, будучи честным.

Обзор ресурсов

При поиске офферов и проектов обратите внимание на самые крупные и авторитетные российские и международные онлайн-платформы: HH, Jooble, Работа.ру, Linkedin, Яндекс Работа, Upwork, AngelList, Freelancer, Kaggle, Indeed, Peopleperhour, Freelance.ru, Freelancehunt, Weblancer, Workzilla.

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

Это один из наиболее энергозатратных этапов, поэтому уделите достаточное количество времени созданию хорошего профиля с подробным описанием вашего образования и опыта, а также с информацией о предыдущих проектах. Включите в него ссылки на примеры работы: личный веб-сайт, GitHub, интерактивное портфолио, студенческие проекты или соревнования Kaggle.

Собеседование


Подготовка к собеседованиям на вакансии в Data Science – трудоемкое занятие. Время подготовки может быть значительно сокращено, если у вас есть предыдущий опыт работы в этой области и/или есть список подходящих ресурсов для каждой темы, которые потенциально возникнут во время интервью.

Если у вас ограниченное время для подготовки к собеседованиям, важно определить приоритеты и на каких темах следует сосредоточиться. Набор тем, которые будут обсуждаться, во многом зависит от описания должности.

Самые распространенные типы интервью:

  • Интервью по кодированию (Python, R и т.д.);
  • Статистическое/Математическое интервью (проверка знаний концепций и навыков решения задач);
  • A/B проверка знаний.

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

  • Коммуникативные навыки: всем специалистам Data Science необходимо умения общаться, строить коммуникации и презентовать проекты;
  • Знакомство с облачными платформам и хранилищами данных является плюсом, поскольку большинство компаний их использует;
  • Владение инструментами визуализации данных, например, Looker, Tableau и Microsoft Power BI.
Подробнее о том, чего ожидать и к чему готовиться, можно прочесть в материале «Собеседование на вашу первую работу Data Scientist’ом».

Заключение

Освоить профессию Data Scientist можно даже в самые краткие сроки. Разработанная в США методика Bootcamp предполагает интенсивное очное обучение с полным погружением в процесс. В России этот формат практикует образовательный проект Elbrus Bootcamp: студенты обучаются в московском кампусе, посвящая науке о данных все будние дни с 9 до 18 часов. Заниматься в онлайне без отрыва от производства не получится, формат буткампа обеспечивает высочайшую вовлеченность всех участников в учебный процесс. В течение 12 недель под руководством практикующего Data Scientist студенты осваивают сбор и анализ данных, нейронные сети, машинное обучение и другие hard и soft skills: количество практических занятий при этом сравнимо со стажировкой в крупной ИТ-компании. Успешно завершив курс, вы получите не только ценные знания, но и возможность их применить, а также добавите несколько проектов портфолио. Удачи!

31
Авг
2021

📊 Путеводитель по Big Data для начинающих: методы и техники анализа больших данных

Методы и техники анализа Big Data: Machine Learning, Data mining, краудсорсинг, нейросети, предиктивный и статистический анализ, визуализация, смешение и интеграция данных, имитационные модели. Как разобраться во множестве названий и аббревиатур? Читайте наш путеводитель.

Machine Learning

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

Как методы машинного обучения применяют при анализе больших данных:

  • Осуществление маркетинговых исследований и сегментации информации. Это дает возможность предприятию понимать рынок, узнавая потребности целевой аудитории. В СМИ машинное обучение помогает определить, какой контент нравится аудитории, а какой нет.
  • Изучение поведения клиентов.
В особенности преимущества машинного обучения в Big Data видны в процессе построения IoT-систем. Технологию используют Tesla Motors и Nest, а также IoT-платформы: AWS IoT Greengrass ML Inference, SageMaker, Google Cloud IoT.
В особенности преимущества машинного обучения в Big Data видны в процессе построения IoT-систем. Технологию используют Tesla Motors и Nest, а также IoT-платформы: AWS IoT Greengrass ML Inference, SageMaker, Google Cloud IoT.

Нейронные сети и распознавание образов

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

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

Вариант использования нейросетей с распознаванием образов – различать фото мужчин и женщин.

Для этого потребуется:

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

Data mining

Термин Data mining появился благодаря математику Григорию Пятецкому-Шапиро в 1989 году. Добыча данных – это интеллектуальный анализ, необходимый для выявления закономерностей в массиве разнородной информации.

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

Основные задачи, решаемые Data mining:

  • Анализ отклонений выявляет резко отличающиеся данные, нетипичные для потока.
  • Ассоциации предназначены для поиска повторяющейся информации из различных источников.
  • Регрессионный анализ позволяет найти факторы, которые влияют на какой-то заданный параметр.
  • Классификация предназначена для разделения сведений по группам, где находятся схожие элементы.
  • Кластеризация выполняет распределение полученных записей по ранее составленным классам.

Краудсорсинг

Для обработки данных иногда привлекают большие группы людей. В какой ситуации это необходимо? Краудсорсинг поможет, например, собрать и обработать соцопрос из нескольких источников или решить другую задачу, с которой компьютер не справится в одиночку. Подобные материалы могут быть в нецифровом виде, содержать сокращения и ошибки, которые человек может быстро выявить и привести сведения в структурированный вид, понятный для программных алгоритмов.

Для разового опроса или сбора/обработки отзывов покупателей невыгодно разрабатывать систему искусственного интеллекта. Однако для регулярной обработки данных и их анализа стоит использовать системы, которые основаны на машинном обучении или Data Mining. Машины способны выполнять сложный анализ, который основан на математических методах (имитационное моделирование или статистика).

Предиктивная аналитика

Прогнозная, предсказательная или предиктивная аналитика составляет прогноз на основании накопившейся информации, отвечая на вопрос «Что может произойти?». Данные получают методами моделирования, математической статистики, машинного обучения, Data mining и т.д.


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

Принцип работы Predictive analytics:

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

Имитационное моделирование

Отличие имитационного моделирования от предиктивной аналитики в том, что прогнозы делаются не на реальных, а на теоретически возможных или желаемых данных. Построение моделей происходит с использованием методов Big Data, при помощи которых эксперимент проводят, если можно так выразиться, в виртуальной реальности.

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

Статистический анализ

Метод предполагает сбор материалов, а также расчет по заданным критериям для получения результата. Недостаток статистики в том, что в выборку могут попасть недостоверные результаты из маленького опроса, поэтому для более достоверных результатов необходимо увеличить количество исходной информации для обработки.

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

К статистике относят анализ временных рядов и А/В тестирование. A/B testing или split testing – это маркетинговый метод исследования, при котором сравнивают контрольную группу элементов с наборами тестовых групп с измененными параметрами, чтобы определить, какие факторы улучшают целевые показатели.
К статистике относят анализ временных рядов и А/В тестирование. A/B testing или split testing – это маркетинговый метод исследования, при котором сравнивают контрольную группу элементов с наборами тестовых групп с измененными параметрами, чтобы определить, какие факторы улучшают целевые показатели.

Методы для получения статистических результатов:

  • Корреляционный анализ для выявления взаимосвязей и того, как изменение одних показателей влияет на другие.
  • Подсчет процентного соотношения результатов исследования.
  • Динамические ряды для оценивания частоты и интенсивности изменений условий на протяжении времени.
  • Вычисление среднего показателя.

Визуализация аналитических данных

Для упрощения процесса анализа информации используют метод визуализации данных. Выполнить визуализацию Big Data можно при помощи средств виртуальной реальности и «больших экранов». Визуальные образы воспринимаются лучше текста, поскольку 90% информации человек получает через зрение.

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

Результаты выводят в виде диаграмм, карт, графиков, гистограмм, 3-D моделей, либо пиктограмм. Инструменты для визуализации больших данных: Qlik, Microsoft (Excel, Power BI), Tableau (tableau desktop, tableau public), Orange и Microstrategy.
Результаты выводят в виде диаграмм, карт, графиков, гистограмм, 3-D моделей, либо пиктограмм. Инструменты для визуализации больших данных: Qlik, Microsoft (Excel, Power BI), Tableau (tableau desktop, tableau public), Orange и Microstrategy.

Смешение и интеграция данных

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

Методы, благодаря которым можно использовать записи из разных источников:

  • Записи переводят в один формат при помощи конвертации документов, распознавания текста, перевода текста в цифры.
  • Дополнение информации происходит при сборе показателей для одного объекта из нескольких источников.
  • Избыточные данные фильтруют, т.е. сначала происходит сбор лишней информации, а та, что недоступна для анализа, подлежит удалению.

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

Для интеграции можно использовать стандартный метод, основанный на ETL-процессе (извлечение данных из источника, преобразование к единому формату и очищение от избыточной информации, загрузка в хранилище). Экосистема Hadoop и БД NoSQL имеют свои инструменты для извлечения, преобразования и загрузки информации. После процедуры интеграции, происходит анализ и дальнейшая обработка материалов.

***

Если вы только начинаете путь в профессии, обратите внимание на Факультет аналитики Big Data образовательной онлайн-платформы GeekBrains. Вы научитесь собирать и анализировать данные, извлекать полезную информацию и находить закономерности. После обучения сможете проверять гипотезы и помогать бизнесу принимать взвешенные решения. Занятия под руководством опытных наставников и поддержка опытных HR помогут вам продвинуться по карьерной лестнице. Специализированный опыт не потребуется: программа предполагает освоение профессиональных навыков с нуля.

31
Авг
2021

📊 С чего начать погружение в Big Data?

Как стать специалистом по Big Data? Какое направление выбрать: Data Scientist, Data Analyst или Data Engineer? С чего начать изучение этого направления, разберем информацию для начинающих IT-шников.

Генерация и обмен большими данными между устройствами происходит практически в каждой социальной сфере. С Big Data работают такие гиганты Google, Uber, IBM, Amazon, оптимизируя работу с клиентами, снижая риск мошенничества и угроз безопасности данных. Специалисты по Big Data необходимы в сферах: маркетинга, поисковых технологий, ритейла, социальных сетях, играх, персонализации, речевых технологиях, финансовых учреждениях и в рекомендательных системах.

Вакансии Data Scientist, Data Engineer и Data Analyst все чаще встречаются в объявлениях с привлекательно высокими зарплатами. С чего начать погружение в Big Data? Чтобы влиться в это направление, рассмотрим основные знания, навыки и технологии, которые стоит изучить новичку для поиска работы.


Направления в Big Data

Существует три основных направления специалистов по Big Data: Data Science, Data Engineer, Data Analyst. Всем им желательно иметь высшее образование (бакалавр, магистр) по техническим специальностям: компьютерные системы, информационные технологии, экономическая кибернетика или подобным.

Разберем направления работы экспертов по большим данным:

  • Аналитикой занимаются Data Scientist и Data Analyst, в их обязанности входит формирование гипотез, поиск закономерностей в наборах данных (dataset), визуализация информации, подготовка данных к моделированию, разработка алгоритмов Machine Learning (машинного обучения), интерпретация полученных данных, а также изучение предметной области или бизнес-процесса.
  • Инженерия относится к профессиям Data Engineer и администратор. Такие специалисты занимаются поддержкой, созданием и настройкой программной и аппаратной инфраструктуры системы сбора, хранения и обработки информации, а также аналитикой массивов и информационных потоков, в том числе конфигурированием облачных (Cloud) и локальных кластеров.

Специалист по Big Data должен знать, что такое самодисциплина и уметь следовать рабочему процессу, который бывает монотонным и однообразным.

Для работы с большими данными, необходимо иметь хотя бы базовые знания:


Что нужно знать Data Scientist?

Исследователь, ученый по данных (Data Scientist) в основном занимается извлечением полезной информации из массивов сведений.

Основные знания, которыми должен обладать специалист Data Scientist:

  • Математика, а точнее теория вероятностей, статистика и дискретная математика. Знания математики необходимы и для машинного обучения, что предполагает также использование линейной алгебры.
  • Различные информационные технологии, средства и методы для интеллектуального анализа данных (Data Mining): языки программирования (Haskell, R, Julia, Python), среды для статического анализа данных (MatLab, R-Studio, Jupyter Notebook), структуры и алгоритмы данных, машинное обучение и иные ветви искусственного интеллекта (генетические алгоритмы, искусственные нейронные сети, deep learning).
  • Понимание предметной области.

Что следует изучать Data Engineer?

Роли в Data Engineering:

  • Database Administrator должен обладать обширными знаниями по базам данным, уметь настраивать СУБД и уровни доступа пользователей, обслуживать и обеспечивать бесперебойную работу системы.
  • Data Architect создает основу для управления данными, их прием из разных источников, интеграцию и обслуживание. Для этого стоит использовать Apache Pig, SQL, Apache Spark, Hive, XML, Apache Zookeeper, Apache Kafka и тому подобные инструменты.
  • Data Engineer должен уметь пользоваться инструментами для работы с базами данных, знать языки программирования (Python или Java), уметь пользоваться системами AWS, HDFS (Hadoop S3 Buckets, MapReduce).

Каждому из перечисленных специалистов важно понимать, как работают операционные системы, а также обладать навыками машинного обучения.


Какой базой должен обладать Data Analyst

Для аналитика не обязательно высшее образование в области информационных технологий. Однако Data Analyst должен разбираться в бизнес-процессах, понимать статистику, выполнять машинное обучение, уметь работать с инструментами.

Типа анализа данных:

  • Описательный – для сбора характеристик, обработки полученной информации.
  • Прогнозный направлен на прогнозирование будущих результатов.
  • Диагностический помогает обнаружить ошибки в данных.
  • Предписательный включает перечисленные выше типы анализа информации.
В обязанности аналитика также входят задачи по Business Inteligence (BI) и оптимизации процессов на производстве. Специалист должен знать методы анализа бизнес-процессов: SWOT, ABC, IDEF, BPMN, ССП, PDCA, EPC и прочие.

Базовые навыки Data Analyst:

  • Умение извлекать данные из различных источников (Hadoop, MS SQL, MySQL и др.).
  • Обработка информации с использованием Scala, R, Python или Java.
  • Визуализация структурированных данных с применением Qlik, Plotly или Tableau.
  • Формирование исследования, которое соответствует категории бизнес-задачи.
  • Предоставление гипотез в соответствии с задачами бизнеса.

Дополнительно аналитик может использовать Apache Storm, Apache Kinesis, Apache Spark Streaming.

Специалистам по Big Data нужно уметь строить графические модели, используя байесовские и нейронные сети, кластеризацию и виды анализа. Data Scientist, Data Analyst или Data Engineer должны обладать навыками работы с Data Lakes (озерами данных), а также разбираться в вопросах безопасности и управления данными (Data Governance). Стать экспертом поможет углубленная проработка каждого из навыков.

***

Если вы только начинаете путь в профессии, обратите внимание на Факультет аналитики Big Data образовательной онлайн-платформы GeekBrains. Вы научитесь собирать и анализировать данные, извлекать полезную информацию и находить закономерности. После обучения сможете проверять гипотезы и помогать бизнесу принимать взвешенные решения. Занятия под руководством опытных наставников и поддержка опытных HR помогут вам продвинуться по карьерной лестнице. Специализированный опыт не потребуется: программа предполагает освоение профессиональных навыков с нуля.

29
Авг
2021

🤖 Машинное обучение для начинающих: основные понятия, задачи и сфера применения

Читайте в нашем обзоре детальное описание основных принципов, понятий и разновидностей машинного обучения.

Машинное обучение позволяет компьютерам справляться с задачами, которые до недавнего времени могли решать только люди: водить автомобили, распознавать речь и переводить ее, играть в шахматы, и многое другое. Но что же именно понимается под словами “машинное обучение”, и что сделало возможным современный бум машинного обучения?

Что такое машинное обучение?

Для решения каждой задачи создается модель, теоретически способная приблизиться к человеческому уровню решения данной задачи при правильных значениях параметров. Обучение этой модели – это постоянное изменение ее параметров, чтобы модель выдавала все лучшие и лучшие результаты.

Разумеется, это лишь общее описание. Как правило, вы не придумываете модель с нуля, а пользуетесь результатами многолетних исследований в этой области, поскольку создание новой модели, превосходящей существующие хотя бы на одном виде задач – это настоящее научное достижение. Методы задания целевой функции, определяющей, насколько хороши выдаваемые моделью результаты (функции потерь), также занимают целые тома исследований. То же самое относится к методам изменения параметров модели, ускорения обучения и многим другим. Даже начальная инициализация этих параметров может иметь большое значение!

В процессе обучения модель усваивает признаки, которые могут оказаться важными для решения задачи. Например, модель, отличающая изображения кошек и собак, может усвоить признак “шерсть на ушах”, наличие которого скорее свойственно собакам, чем кошкам. Большинство таких признаков нельзя описать словами: вы же не сможете объяснить, как вы отличаете кошку от собаки, правда? Выделение таких признаков зачастую не менее, а иногда намного более ценно, чем решение основной задачи.

Чем машинное обучение отличается от искусственного интеллекта?

Термин “искусственный интеллект” был введен еще в 50-е годы прошлого века. К нему относится любая машина или программа, выполняющая задачи, “обычно требующие интеллекта человека”. Со временем компьютеры справлялись все с новыми и новыми задачами, которые прежде требовали интеллекта человека, то есть то, что прежде считалось “искусственным интеллектом” постепенно перестало с ним ассоциироваться.


Машинное обучение – один из методов реализации приложений искусственного интеллекта, и с его помощью искусственный интеллект значительно продвинулся вперед. Но, хотя этот метод действительно очень важен, это далеко не первый значительный шаг в истории искусственного интеллекта: когда-то не менее важными казались экспертные системы, логический вывод и многое другое. Несомненно, в будущем появятся и новые технологии искусственного интеллекта, которые не будут относиться к машинному обучению.

Модели и параметры

Самая простая модель имеет всего два параметра. Если нужно предсказать результат, линейно зависящий от входного признака, достаточно найти параметры a и b в уравнении прямой линии y=ax+b. Такая модель строится с помощью линейной регрессии. На следующем рисунке показана модель, предсказывающая “уровень счастья” человека по его собственной оценке в зависимости от уровня его дохода (красная линия):

Модель, предсказывающая уровень счастья человека по уровню его дохода
Модель, предсказывающая уровень счастья человека по уровню его дохода

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

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

Архитектура нейронной сети
Архитектура нейронной сети

Хотя алгоритм обратного распространения ошибки (backropagation) был придуман довольно давно, до недавнего времени не было технических возможностей для реализации глубоких нейронных сетей, содержащих большое количество слоев. Быстрое развитие микроэлектроники привело к появлению высокопроизводительных GPU и TPU, способных обучать глубокие нейронные сети без суперкомпьютеров. Именно широкое распространение глубокого обучения стоит за тем бумом искусственного интеллекта, о котором вы слышите отовсюду.

Учиться, учиться и учиться

Машинное обучение требует много данных. В идеале, тренировочные данные должны описывать все возможные ситуации, чтобы модель могла подготовиться ко всему. Конечно, на практике добиться этого невозможно, но нужно стараться, чтобы тренировочный набор был достаточно разнообразным.

Стратегия обучения выбирается в зависимости от поставленной задачи и имеющихся данных для обучения. Выделяют обучение с учителем (supervised learning), обучение без учителя (unsupervised learning) и обучение с подкреплением (reinforcement learning).


Обучение с учителем

Это обучение на примерах, при котором “учителем” называются правильные ответы, которые, в идеале, должна выдавать модель для каждого случая. Эти ответы называются метками (название происходит из задач классификации, модели которых практически всегда обучаются с учителем – там эти ответы являются метками классов), а данные с метками – размеченными.

Обучение с учителем – это обучение на примерах. Представьте, что школьнику показали несколько методов решения задач, а потом заставили решить огромное количество таких задач, предоставив правильные ответы для каждой. Если школьник решит все эти задачи, и в каждой получит правильный ответ, то можно считать, что он усвоил методы решения таких задач.

К сожалению, с моделями машинного обучения все не так просто, поскольку мы сами не знаем, какой ответ будет “правильным” для каждого случая! Ведь именно для получения этих ответов нам и нужна модель. И практически всегда нам нужно, чтобы модель хорошо усвоила зависимость результата от входных признаков, а не точно повторяла результаты тренировочного набора, который в реальной жизни может содержать и ошибочные результаты (шум). Если модель выдает верные результаты на всем тренировочном наборе, но часто ошибается на новых данных, говорят, что она переобучена на этом наборе.

Переобученная модель классификации (зеленая линия) выдает верные результаты на всем тренировочном наборе, но правильно обученная модель (черная линия), скорее всего, будет не так сильно ошибаться на новых данных
Переобученная модель классификации (зеленая линия) выдает верные результаты на всем тренировочном наборе, но правильно обученная модель (черная линия), скорее всего, будет не так сильно ошибаться на новых данных

Обучение без учителя

Некоторые задачи можно решить и без размеченных тренировочных данных – например, задачи кластеризации. Модель сама решает, как надо сгруппировать данные в кластеры, чтобы похожие экземпляры данных попадали в один кластер, а непохожие – не попадали.

Такую стратегию обучения, использует, например, Airbnb, объединяя в группы похожие дома, и Google News, группируя новости по их темам.

Частичное привлечение учителя

Как и предполагает название, обучение с частичным привлечение учителя (semi-supervised learning) – это смесь обучения с учителем и без него. Этот метод использует небольшое количество размеченных данных и множество данных без меток. Сначала модель обучается на размеченных данных, а затем эта частично обученная модель используется для разметки остальных данных (псевдо-разметка). Затем вся модель обучается на смеси размеченных и псевдо-размеченных данных.

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

Обучение с подкреплением

Это обучение методом проб и ошибок. Каждый раз, когда модель достигает поставленной цели, она получает “поощрение”, а если не получает – “наказание”. Эта стратегия обычно используется для обучения моделей, непосредственно взаимодействующих с реальным миром: моделей автоматического вождения автомобилей, игры в различные игры и т.д.

Отличный пример модели, обученной с подкреплением – нейронная сеть Deep Q от Google, победившая людей во множестве старых видеоигр. После длительного обучения модель усваивает правильную стратегию поведения, приводящую к победе.

Лучшие курсы для изучения машинного обучения

  • Самый популярный курс основ машинного обучения для новичков – бесплатная серия лекций Стэнфордского университета на Coursera от легендарного эксперта в ИИ и основателя Google Brain Эндрю Ына (Andrew Ng). Недавно Эндрю Ын выпустил курс специализации в глубоком обучении, который рассматривает различные архитектуры нейронных сетей и прочие темы машинного обучения.

  • Если вы предпочитаете подход “сверху вниз”, при котором вы сначала запускаете обученные модели машинного обучения, и только потом углубляетесь в их внутренности, обратите внимание на курс “Практическое глубокое обучение для кодировщиков” от fast.ai. Этот курс особенно рекомендуется программистам, имеющим не менее года опыта работы на Python. Курс Эндрю Ына предоставляет обзор теоретических основ машинного обучения, а курс fast.ai построен вокруг Python’а – языка программирования, широко используемого в машинном обучении.
  • Еще один курс, высоко оцениваемый не только за уровень преподавания, но и за широкий обзор рассматриваемых тем – “Введение в машинное обучение” от EdX и Колумбийского университета, хотя он и требует знания математики на университетском уровне.
  • На русском языке, пожалуй, лучший курс машинного обучения предлагает факультет искусственного интеллекта GeekBrains. Этот курс занимает целых полтора года и при успешном освоении выведет вас на довольно высокий уровень, достаточный для трудоустройства.

Сферы применения машинного обучения

Машинное обучение имеет огромное количество применений, но особенно выделяются два крупных и важных направления: машинное зрение (computer vision, CV) и обработка естественного языка (natural language processing, NLP), каждое из которых объединяет множество различных задач.


Машинное зрение

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

  • Выделение сущностей определенных классов в изображении. Например, модель YOLO помечает рамками найденные объекты и выводит метки их классов.
  • Распознавание людей по их лицам (служит для обнаружения преступников, идентификации для безопасного доступа к охраняемым объектам, введения ограничений по возрасту и т.п.)
  • Медицинская диагностика. Современные модели способны распознавать многие виды заболеваний по фотографиям пациентов, особенно если к ним добавляются снимки рентгенографии и МРТ.
  • Автоматическое вождение автомобиля. Эта задача состоит из многих подзадач: идентификация других автомобилей, пешеходов и прочих объектов на дороге, определение скорости и направления движения других объектов, принятие правильных решений в различных ситуациях, и так далее.
  • Воздушная разведка. Современные дроны могут намного больше, чем подчиняться командам человека, передаваемым по радио. Они могут не только распознавать военную технику и направление ее передвижения, но и ее маркировку.
  • Автоматическая генерация изображений – в том числе, человеческих лиц и тел.

Обработка естественного языка

Обработка естественного языка – это революция в области интерфейса между человеком и компьютером. Она включает в себя следующие задачи:

  • Распознавание речи. Современные модели способны распознавать человеческую речь практически с такой же точностью, как другие люди.
  • Машинный перевод с одного языка на другой. Одна из самых старых и самых известных задач искусственного интеллекта вышла на новый уровень благодаря машинному обучению.
  • Анализ тональности текста. Определение эмоционального отношения автора текста к описываемым объектам или сущностям.
  • Поиск ответов на вопросы. Современные поисковые системы практически всегда находят документы с ответами на заданные людьми вопросы, если они существуют.
  • Выделение заданных сущностей из текста (например, поиск текста, имеющего отношение к чистоте атмосферы).
  • Автоматическая генерация текста. Современные модели умеют генерировать тексты разных стилей и направлений, которые далеко не всегда можно отличить от текстов, написанных человеком.
  • Синтез речи. Компьютеры уже давно не разговаривают “как роботы” – синтезированную ими речь практически невозможно отличить от человеческой.
***

Если вы хотите освоить востребованную профессию, стоит обратить внимание на курс факультета искусственного интеллекта образовательной онлайн-платформы GeekBrains. Одна из самых объемных и содержательных на рынке учебных программ включает основательную математическую подготовку, изучение программирования и статистического анализа, а также работу с базами данных, нейронные сети и машинное обучение. Курс построен на основе практической работы с ведущими специалистами технологических компаний и личным помощником-куратором. Выпускники получат диплом о профессиональной подготовке и помощь в трудоустройстве, а также смогут добавить в портфолио реализованные проекты.

28
Авг
2021

🤖 Практическое руководство по NLP: изучаем классификацию текстов с помощью библиотеки fastText

Рассматриваем практическое применение supervised NLP модели fastText для обнаружения сарказма в новостных заголовках.

Около 80% всей информации не структурировано, а текст является одним из наиболее распространенных типов неструктурированных данных. Из-за ее беспорядочной природы, анализ, понимание, организация и сортировка текстовой информации становятся сложными и трудоемкими задачами. Здесь на помощь приходят NLP и классификация текста.

Классификация текстов – метод машинного обучения, используемый для их фрагментации на категории. Классификация текста является одной из фундаментальных задач в обработке естественного языка с широким применением: анализ сентиментов, маркировка тем, обнаружение спама, намерений клиентов и т.д. Обученные модели классификации текстов также нужны для исследовательских целей.

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

fastText – популярная библиотека с открытым исходным кодом для классификации текстов, которая была опубликована в 2015 году исследовательской лабораторией искусственного интеллекта Facebook. Компания также предоставляет модели: English word vectors (предварительно обучена английскому webcrawl и Википедии) и Multi-lingual word vectors (обученные модели для 157 различных языков), которые позволяют создать алгоритмы Supervised и Unsupervised learning для получения векторных представлений слов. Библиотеку можно использовать как инструмент командной строки или как пакет Python. В этой статье мы рассмотрим ее применение для классификации новостных заголовков.

Подготовка среды и данных

Загружаем необходимые библиотеки

        import pandas as pd
import fasttext
from sklearn.model_selection import train_test_split
import re
from gensim.parsing.preprocessing import STOPWORDS
from gensim.parsing.preprocessing import remove_stopwords

pd.options.display.max_colwidth = 1000
    
TIP
для ознакомления с документацией библиотеки:

        help(fasttext.FastText)
    

Данные

Датасет представляет собой коллекцию заголовков новостных статей и их аннотацию как сарказм (статьи из новостного издания The Onion) и не сарказм (из HuffPost). Ссылка на данные: https://www.kaggle.com/rmisra/news-headlines-dataset-for-sarcasm-detection

Переменные

  • is_sarcastic: 1 если заголовок с сарказмом, в противном случае 0
  • headline: заголовок новостной статьи
  • article_link: ссылка на оригинальную статью
        # Загружаем данные
df_headline = pd.read_json("Sarcasm_Headlines_Dataset.json", lines=True)
# Проверяем количество переменных и наблюдений
df_headline.shape
(26709, 3)
# Отобразим примеры заголовков
df_headline.head(3)
    
article_link headline is_sarcastic
https://www.huffingtonpost.com/entry/versace-black-code_us_5861fbefe4b0de3a08f600d5 former versace store clerk sues over secret ‘black code’ for minority shoppers 0
https://www.huffingtonpost.com/entry/roseanne-revival-review_us_5ab3a497e4b054d118e04365the the ‘roseanne’ revival catches up to our thorny political mood, for better and worse 0
https://local.theonion.com/mom-starting-to-fear-son-s-web-series-closest-thing-she-1819576697 mom starting to fear son’s web series closest thing she will have to grandchild 1
        # Отобразим количество саркастических и несаркастических статей в датасете и их процентное соотношение
df_headline.is_sarcastic.value_counts()
0    14985
1    11724
df_headline.is_sarcastic.value_counts(normalize=True)
0    0.561047
1    0.438953
    

Приведем несколько примеров саркастических и не саркастических заголовков:

        df_headline[df_headline['is_sarcastic']==1].head(3)

    
article_link headline is_sarcastic
https://local.theonion.com/mom-starting-to-fear-son-s-web-series-closest-thing-she-1819576697 mom starting to fear son’s web series closest thing she will have to grandchild 1
https://politics.theonion.com/boehner-just-wants-wife-to-listen-not-come-up-with-alt-1819574302 boehner just wants wife to listen, not come up with alternative debt-reduction ideas 1
https://politics.theonion.com/top-snake-handler-leaves-sinking-huckabee-campaign-1819578231 top snake handler leaves sinking huckabee campaign 1
        df_headline[df_headline['is_sarcastic']==0].head(3)
    
article_link headline is_sarcastic
https://www.huffingtonpost.com/entry/versace-black-code_us_5861fbefe4b0de3a08f600d5 former versace store clerk sues over secret ‘black code’ for minority shoppers 0
https://www.huffingtonpost.com/entry/roseanne-revival-review_us_5ab3a497e4b054d118e04365 the ‘roseanne’ revival catches up to our thorny political mood, for better and worse0 0
https://www.huffingtonpost.com/entry/jk-rowling-wishes-snape-happy-birthday_us_569117c4e4b0cad15e64fdcb j.k. rowling wishes snape happy birthday in the most magical way 0

Подготовка данных

Предварительная обработка текста

Один из первых шагов для повышения производительности модели – применение простой предварительной обработки текста. Прежде чем приступить к построению классификатора, нам необходимо подготовить текст: привести все слова к нижнему регистру, удалить пунктуацию, специальные знаки и цифры. Для этого создадим функцию очистки и применим ее к переменной headline.

        # Создадим функцию очистки текста
def clean_text(text):
    text = text.lower()
    text = re.sub(r'[^\[email protected]\[\]]',' ',text) # Удаляет пунктцацию
    text = re.sub(r'\w*\d+\w*', '', text) # Удаляет цифры
    text = re.sub('\s{2,}', " ", text) # Удаляет ненужные пробелы
    return text

# Применяем ее к заголовку
df_headline['headline'] = df_headline['headline'].apply(clean_text)
    

Разделение данных на обучающие и тестовые

Прежде чем мы начнем обучение модели, нужно разделить данные так. Чаще всего для обучения модели используется 80% информации (в зависимости от объема данных размер выборки может варьироваться) и 20% – для тестирования (проверки точности).

        # Разделяем данные на обучающие и текстовые
train, test = train_test_split(df_headline, test_size = 0.2)

    

Создание текстового файла

Далее нам нужно подготовить файлы в формате txt. Формат файла по умолчанию должен включать __label__ <Label> <Text>. Мы можем использовать другой префикс вместо __label__, соответствующим образом изменив параметр во время обучения. В нашем датасете __ label __0 подразумевает отсутствие сарказма, а __label __1 подразумевает сарказм.

        # Создадим текстовые файля для обучения модели с лейблом и текстом
with open('train.txt', 'w') as f:
    for each_text, each_label in zip(train['headline'], train['is_sarcastic']):
        f.writelines(f'__label__{each_label} {each_text}\n')
        
with open('test.txt', 'w') as f:
    for each_text, each_label in zip(test['headline'], test['is_sarcastic']):
        f.writelines(f'__label__{each_label} {each_text}\n')

# Отобразим, как теперь выглядят наши данные для обучения
!head -n 10 train.txt

__label__0 singapore airlines flight catches fire no casualties
__label__1 area man wins conversation
__label__0 stephen colbert explains the conspiracies against donald trump in nsfw diagram
__label__1 turkey sandwich given locally relevant name
__label__1 quiet riot speaks out against nation s poor metal health care
    

Построение модели

Для обучения модели необходимо задать fastText входной файл и ее имя:

        # Первая модель без оптимизации гиперпараметров
model1 = fasttext.train_supervised('train.txt')

# Создадим функцую для отображения результатов обучения модели
def print_results(sample_size, precision, recall):
    precision   = round(precision, 2)
    recall      = round(recall, 2)
    print(f'{sample_size=}')
    print(f'{precision=}')
    print(f'{recall=}')

# Применяем функцию
print_results(*model1.test('test.txt'))

sample_size=5342
precision=0.85
recall=0.85
    

Результаты, хотя и не идеальные, выглядят многообещающими.

Оптимизация гиперпараметров

Поиск наилучших гиперпараметров вручную может занять много времени. По умолчанию модель fastText во время обучения включает каждый обучающий пример только пять раз, что довольно мало, учитывая, что в нашем наборе всего 12 тыс. примеров. Количество просмотров каждого примера (также известное как количество эпох) может быть увеличено с помощью ручной оптимизации epoch:

        # Вторая модель с количеством эпох равной 25
model2 = fasttext.train_supervised('train.txt', epoch=25)

print_results(*model2.test('test.txt'))

sample_size=5342
precision=0.83
recall=0.83

    

Как можно заметить, точность модели не возрасла. Еще один способ изменить скорость процесса – увеличить (или уменьшить) скорость обучения алгоритма. Это соответствует тому, насколько сильно меняется модель после обработки каждого примера. Скорость обучения равная 0 будет означать, что модель вообще не меняется и, следовательно, ничему не учится. Хорошие значения скорости обучения находятся в диапазоне 0.1 – 1.0. Мы также можем вручную оптимизировать этот гиперпараметр с помощью аргумента lr:

        # Третья модель с количеством эпох равной 10 и скоростью обучния равной 1
model3 = fasttext.train_supervised('train.txt', epoch=10, lr=1.0)

print_results(*model3.test('test.txt'))

sample_size=5342
precision=0.83
recall=0.83
    

Наконец, мы можем улучшить производительность модели, используя биграммы слов, а не просто юниграммы. Это особенно значимо для задач классификации, где важен порядок слов, например, анализ сентиментов, определение критики, сарказма и т. д. Для этого мы включим в модель аргумент wordNgrams равный 2.

        model4 = fasttext.train_supervised('train.txt', epoch=10, lr=1.0, wordNgrams =2)

print_results(*model4.test('test.txt'))

sample_size=5342
precision=0.86
recall=0.86

    

Благодаря этой последовательности шагов мы смогли перейти от точности в 86%:

  • предварительная обработка текста;
  • изменение количества эпох (с использованием аргумента epoch, стандартный диапазон [5 – 50]) ;
  • изменение скорости обучения (с использованием аргумента lr, стандартный диапазон [0,1 – 1,0]) ;
  • используя n-граммы слов (используя аргумента wordNgrams, стандартный диапазон [1-5]).

Вы также можете адаптировать поиск гиперпараментров через оценку определенного лейбла, добавив аргумент autotuneMetric:

        model5 = fasttext.train_supervised('train.txt', autotuneValidationFile='test.txt')

print_results(*model5.test('test.txt'))

sample_size=5342
precision=0.87
recall=0.87
    

Функция автоматической настройки fastText позволяет оптимизировать гиперпараметры для получения наивысшего показателя F1. Для этого необходимо включить модель аргумент autotuneValidationFile и тестовый датасет:

        
model6 = fasttext.train_supervised('train.txt', autotuneValidationFile='test.txt', autotuneMetric="f1:__label__1")

print_results(*model6.test('test.txt'))

sample_size=5342
precision=0.87
recall=0.87
    

Сохраним результаты модели и создадим функцию для классификации новых данных:

        # Сохраним модель с оптимизированными гиперпараметрами и самой высокой точностью 
model6.save_model('optimized.model')

    

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

        model.quantize(input='train.txt', retrain=True)
    

Результаты

Мы можем проверить результаты на новых данных, введя любое предложение:

        # Загружаем, сохраненную ранее модель
model = fasttext.load_model("optimized.model")

# Пример классификации одного заголовка
model.predict("Fed official says weak data caused by weather, should not slow taper")

(('__label__0',), array([0.99874038]))
    

Метка результата с максимальной вероятностью равна __label__0. Это означает, что заголовок не является саркастическим. В model.predict() значение k обозначает количество лейблов, которые вы хотите показать вместе с их показателями вероятности. Поскольку мы использовали активацию softmax (по умолчанию в fastText), сумма вероятностей двух меток равна 1.

Мы также можем симулировать новые данные и проверить модели на реальных заголовках. Для этого будет использовать News Aggregator Dataset из Kaggle:

        # Загружаем данные
df_headline_test = pd.read_csv('uci-news-aggregator.csv')
# Отобразим заголовки 
df_headline_test.TITLE.head(3)

0     Fed official says weak data caused by weather, should not slow taper
1       Fed's Charles Plosser sees high bar for change in pace of tapering
2    US open: Stocks fall after Fed official hints at accelerated tapering
3               Fed risks falling 'behind the curve', Charles Plosser says
4                       Fed's Plosser: Nasty Weather Has Curbed Job Growth
    

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

        # Подготовим новые данные для классификации
df_headline_test['TITLE'] = df_headline_test['TITLE'].apply(clean_text)
# Создадим функцию для классификации текста
def predict_sarcasm(text):
    return model.predict(text, k=1)
# Трансформируем переменные в удобный формат 
df_headline_test['predict_score'] = df_headline_test.TITLE.apply(predict_sarcasm)
df_headline_test['predict_score'] = df_headline_test['predict_score'].astype(str)
df_headline_test[['label','probability']] = df_headline_test.predict_score.str.split(" ",expand=True)
df_headline_test['label'] = df_headline_test['label'].str.replace("(", '')
df_headline_test['label'] = df_headline_test['label'].str.replace(")", '')
df_headline_test['label'] = df_headline_test['label'].str.replace("__", ' ')
df_headline_test['label'] = df_headline_test['label'].str.replace(",", '')
df_headline_test['label'] = df_headline_test['label'].str.replace("'", '')
df_headline_test['label'] = df_headline_test['label'].str.replace("label", '')
df_headline_test['probability'] = df_headline_test['probability'].str.replace("array", '')
df_headline_test['probability'] = df_headline_test['probability'].str.replace("(", '')
df_headline_test['probability'] = df_headline_test['probability'].str.replace(")", '')
df_headline_test['probability'] = df_headline_test['probability'].str.replace("[", '')
df_headline_test['probability'] = df_headline_test['probability'].str.replace("]", '')

# Удаляем ненужную переменную
df_headline_test = df_headline_test.drop(columns=['predict_score'])

# Отобразим количество спрогнозированых саркастических и несаркастических заголовков
df_headline_test.label.value_counts(normalize=True)

0    0.710827
1    0.289173
    

Мы видим, что 28% заголовков были классифицированы как сарказм.

Заключение

В заключение следует отметить, что fastText не является одной из самых последних разработок классификации текстов (библиотека была опубликована в 2015 году). В то же время это хорошая основа для новичков: при выполнении NLP-классификации текстов любой сложности, модель имеет существенное преимущество из-за простоты ее использования, скорости обучения и автоматической настройки гиперпараметров. Подробнее с документацией fastText можно ознакомится по ссылке.

28
Авг
2021

🤖 Практическое руководство по NLP: изучаем классификацию текстов с помощью библиотеки fastText

Рассматриваем практическое применение supervised NLP модели fastText для обнаружения сарказма в новостных заголовках.

Около 80% всей информации не структурировано, а текст является одним из наиболее распространенных типов неструктурированных данных. Из-за ее беспорядочной природы, анализ, понимание, организация и сортировка текстовой информации становятся сложными и трудоемкими задачами. Здесь на помощь приходят NLP и классификация текста.

Классификация текстов – метод машинного обучения, используемый для их фрагментации на категории. Классификация текста является одной из фундаментальных задач в обработке естественного языка с широким применением: анализ сентиментов, маркировка тем, обнаружение спама, намерений клиентов и т.д. Обученные модели классификации текстов также нужны для исследовательских целей.

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

fastText – популярная библиотека с открытым исходным кодом для классификации текстов, которая была опубликована в 2015 году исследовательской лабораторией искусственного интеллекта Facebook. Компания также предоставляет модели: English word vectors (предварительно обучена английскому webcrawl и Википедии) и Multi-lingual word vectors (обученные модели для 157 различных языков), которые позволяют создать алгоритмы Supervised и Unsupervised learning для получения векторных представлений слов. Библиотеку можно использовать как инструмент командной строки или как пакет Python. В этой статье мы рассмотрим ее применение для классификации новостных заголовков.

Подготовка среды и данных

Загружаем необходимые библиотеки

        import pandas as pd
import fasttext
from sklearn.model_selection import train_test_split
import re
from gensim.parsing.preprocessing import STOPWORDS
from gensim.parsing.preprocessing import remove_stopwords

pd.options.display.max_colwidth = 1000
    
TIP
для ознакомления с документацией библиотеки:

        help(fasttext.FastText)
    

Данные

Датасет представляет собой коллекцию заголовков новостных статей и их аннотацию как сарказм (статьи из новостного издания The Onion) и не сарказм (из HuffPost). Ссылка на данные: https://www.kaggle.com/rmisra/news-headlines-dataset-for-sarcasm-detection

Переменные

  • is_sarcastic: 1 если заголовок с сарказмом, в противном случае 0
  • headline: заголовок новостной статьи
  • article_link: ссылка на оригинальную статью
        # Загружаем данные
df_headline = pd.read_json("Sarcasm_Headlines_Dataset.json", lines=True)
# Проверяем количество переменных и наблюдений
df_headline.shape
(26709, 3)
# Отобразим примеры заголовков
df_headline.head(3)
    
article_link headline is_sarcastic
https://www.huffingtonpost.com/entry/versace-black-code_us_5861fbefe4b0de3a08f600d5 former versace store clerk sues over secret ‘black code’ for minority shoppers 0
https://www.huffingtonpost.com/entry/roseanne-revival-review_us_5ab3a497e4b054d118e04365the the ‘roseanne’ revival catches up to our thorny political mood, for better and worse 0
https://local.theonion.com/mom-starting-to-fear-son-s-web-series-closest-thing-she-1819576697 mom starting to fear son’s web series closest thing she will have to grandchild 1
        # Отобразим количество саркастических и несаркастических статей в датасете и их процентное соотношение
df_headline.is_sarcastic.value_counts()
0    14985
1    11724
df_headline.is_sarcastic.value_counts(normalize=True)
0    0.561047
1    0.438953
    

Приведем несколько примеров саркастических и не саркастических заголовков:

        df_headline[df_headline['is_sarcastic']==1].head(3)

    
article_link headline is_sarcastic
https://local.theonion.com/mom-starting-to-fear-son-s-web-series-closest-thing-she-1819576697 mom starting to fear son’s web series closest thing she will have to grandchild 1
https://politics.theonion.com/boehner-just-wants-wife-to-listen-not-come-up-with-alt-1819574302 boehner just wants wife to listen, not come up with alternative debt-reduction ideas 1
https://politics.theonion.com/top-snake-handler-leaves-sinking-huckabee-campaign-1819578231 top snake handler leaves sinking huckabee campaign 1
        df_headline[df_headline['is_sarcastic']==0].head(3)
    
article_link headline is_sarcastic
https://www.huffingtonpost.com/entry/versace-black-code_us_5861fbefe4b0de3a08f600d5 former versace store clerk sues over secret ‘black code’ for minority shoppers 0
https://www.huffingtonpost.com/entry/roseanne-revival-review_us_5ab3a497e4b054d118e04365 the ‘roseanne’ revival catches up to our thorny political mood, for better and worse0 0
https://www.huffingtonpost.com/entry/jk-rowling-wishes-snape-happy-birthday_us_569117c4e4b0cad15e64fdcb j.k. rowling wishes snape happy birthday in the most magical way 0

Подготовка данных

Предварительная обработка текста

Один из первых шагов для повышения производительности модели – применение простой предварительной обработки текста. Прежде чем приступить к построению классификатора, нам необходимо подготовить текст: привести все слова к нижнему регистру, удалить пунктуацию, специальные знаки и цифры. Для этого создадим функцию очистки и применим ее к переменной headline.

        # Создадим функцию очистки текста
def clean_text(text):
    text = text.lower()
    text = re.sub(r'[^\[email protected]\[\]]',' ',text) # Удаляет пунктцацию
    text = re.sub(r'\w*\d+\w*', '', text) # Удаляет цифры
    text = re.sub('\s{2,}', " ", text) # Удаляет ненужные пробелы
    return text

# Применяем ее к заголовку
df_headline['headline'] = df_headline['headline'].apply(clean_text)
    

Разделение данных на обучающие и тестовые

Прежде чем мы начнем обучение модели, нужно разделить данные так. Чаще всего для обучения модели используется 80% информации (в зависимости от объема данных размер выборки может варьироваться) и 20% – для тестирования (проверки точности).

        # Разделяем данные на обучающие и текстовые
train, test = train_test_split(df_headline, test_size = 0.2)

    

Создание текстового файла

Далее нам нужно подготовить файлы в формате txt. Формат файла по умолчанию должен включать __label__ <Label> <Text>. Мы можем использовать другой префикс вместо __label__, соответствующим образом изменив параметр во время обучения. В нашем датасете __ label __0 подразумевает отсутствие сарказма, а __label __1 подразумевает сарказм.

        # Создадим текстовые файля для обучения модели с лейблом и текстом
with open('train.txt', 'w') as f:
    for each_text, each_label in zip(train['headline'], train['is_sarcastic']):
        f.writelines(f'__label__{each_label} {each_text}\n')
        
with open('test.txt', 'w') as f:
    for each_text, each_label in zip(test['headline'], test['is_sarcastic']):
        f.writelines(f'__label__{each_label} {each_text}\n')

# Отобразим, как теперь выглядят наши данные для обучения
!head -n 10 train.txt

__label__0 singapore airlines flight catches fire no casualties
__label__1 area man wins conversation
__label__0 stephen colbert explains the conspiracies against donald trump in nsfw diagram
__label__1 turkey sandwich given locally relevant name
__label__1 quiet riot speaks out against nation s poor metal health care
    

Построение модели

Для обучения модели необходимо задать fastText входной файл и ее имя:

        # Первая модель без оптимизации гиперпараметров
model1 = fasttext.train_supervised('train.txt')

# Создадим функцую для отображения результатов обучения модели
def print_results(sample_size, precision, recall):
    precision   = round(precision, 2)
    recall      = round(recall, 2)
    print(f'{sample_size=}')
    print(f'{precision=}')
    print(f'{recall=}')

# Применяем функцию
print_results(*model1.test('test.txt'))

sample_size=5342
precision=0.85
recall=0.85
    

Результаты, хотя и не идеальные, выглядят многообещающими.

Оптимизация гиперпараметров

Поиск наилучших гиперпараметров вручную может занять много времени. По умолчанию модель fastText во время обучения включает каждый обучающий пример только пять раз, что довольно мало, учитывая, что в нашем наборе всего 12 тыс. примеров. Количество просмотров каждого примера (также известное как количество эпох) может быть увеличено с помощью ручной оптимизации epoch:

        # Вторая модель с количеством эпох равной 25
model2 = fasttext.train_supervised('train.txt', epoch=25)

print_results(*model2.test('test.txt'))

sample_size=5342
precision=0.83
recall=0.83

    

Как можно заметить, точность модели не возрасла. Еще один способ изменить скорость процесса – увеличить (или уменьшить) скорость обучения алгоритма. Это соответствует тому, насколько сильно меняется модель после обработки каждого примера. Скорость обучения равная 0 будет означать, что модель вообще не меняется и, следовательно, ничему не учится. Хорошие значения скорости обучения находятся в диапазоне 0.1 – 1.0. Мы также можем вручную оптимизировать этот гиперпараметр с помощью аргумента lr:

        # Третья модель с количеством эпох равной 10 и скоростью обучния равной 1
model3 = fasttext.train_supervised('train.txt', epoch=10, lr=1.0)

print_results(*model3.test('test.txt'))

sample_size=5342
precision=0.83
recall=0.83
    

Наконец, мы можем улучшить производительность модели, используя биграммы слов, а не просто юниграммы. Это особенно значимо для задач классификации, где важен порядок слов, например, анализ сентиментов, определение критики, сарказма и т. д. Для этого мы включим в модель аргумент wordNgrams равный 2.

        model4 = fasttext.train_supervised('train.txt', epoch=10, lr=1.0, wordNgrams =2)

print_results(*model4.test('test.txt'))

sample_size=5342
precision=0.86
recall=0.86

    

Благодаря этой последовательности шагов мы смогли перейти от точности в 86%:

  • предварительная обработка текста;
  • изменение количества эпох (с использованием аргумента epoch, стандартный диапазон [5 – 50]) ;
  • изменение скорости обучения (с использованием аргумента lr, стандартный диапазон [0,1 – 1,0]) ;
  • используя n-граммы слов (используя аргумента wordNgrams, стандартный диапазон [1-5]).

Вы также можете адаптировать поиск гиперпараментров через оценку определенного лейбла, добавив аргумент autotuneMetric:

        model5 = fasttext.train_supervised('train.txt', autotuneValidationFile='test.txt')

print_results(*model5.test('test.txt'))

sample_size=5342
precision=0.87
recall=0.87
    

Функция автоматической настройки fastText позволяет оптимизировать гиперпараметры для получения наивысшего показателя F1. Для этого необходимо включить модель аргумент autotuneValidationFile и тестовый датасет:

        
model6 = fasttext.train_supervised('train.txt', autotuneValidationFile='test.txt', autotuneMetric="f1:__label__1")

print_results(*model6.test('test.txt'))

sample_size=5342
precision=0.87
recall=0.87
    

Сохраним результаты модели и создадим функцию для классификации новых данных:

        # Сохраним модель с оптимизированными гиперпараметрами и самой высокой точностью 
model6.save_model('optimized.model')

    

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

        model.quantize(input='train.txt', retrain=True)
    

Результаты

Мы можем проверить результаты на новых данных, введя любое предложение:

        # Загружаем, сохраненную ранее модель
model = fasttext.load_model("optimized.model")

# Пример классификации одного заголовка
model.predict("Fed official says weak data caused by weather, should not slow taper")

(('__label__0',), array([0.99874038]))
    

Метка результата с максимальной вероятностью равна __label__0. Это означает, что заголовок не является саркастическим. В model.predict() значение k обозначает количество лейблов, которые вы хотите показать вместе с их показателями вероятности. Поскольку мы использовали активацию softmax (по умолчанию в fastText), сумма вероятностей двух меток равна 1.

Мы также можем симулировать новые данные и проверить модели на реальных заголовках. Для этого будет использовать News Aggregator Dataset из Kaggle:

        # Загружаем данные
df_headline_test = pd.read_csv('uci-news-aggregator.csv')
# Отобразим заголовки 
df_headline_test.TITLE.head(3)

0     Fed official says weak data caused by weather, should not slow taper
1       Fed's Charles Plosser sees high bar for change in pace of tapering
2    US open: Stocks fall after Fed official hints at accelerated tapering
3               Fed risks falling 'behind the curve', Charles Plosser says
4                       Fed's Plosser: Nasty Weather Has Curbed Job Growth
    

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

        # Подготовим новые данные для классификации
df_headline_test['TITLE'] = df_headline_test['TITLE'].apply(clean_text)
# Создадим функцию для классификации текста
def predict_sarcasm(text):
    return model.predict(text, k=1)
# Трансформируем переменные в удобный формат 
df_headline_test['predict_score'] = df_headline_test.TITLE.apply(predict_sarcasm)
df_headline_test['predict_score'] = df_headline_test['predict_score'].astype(str)
df_headline_test[['label','probability']] = df_headline_test.predict_score.str.split(" ",expand=True)
df_headline_test['label'] = df_headline_test['label'].str.replace("(", '')
df_headline_test['label'] = df_headline_test['label'].str.replace(")", '')
df_headline_test['label'] = df_headline_test['label'].str.replace("__", ' ')
df_headline_test['label'] = df_headline_test['label'].str.replace(",", '')
df_headline_test['label'] = df_headline_test['label'].str.replace("'", '')
df_headline_test['label'] = df_headline_test['label'].str.replace("label", '')
df_headline_test['probability'] = df_headline_test['probability'].str.replace("array", '')
df_headline_test['probability'] = df_headline_test['probability'].str.replace("(", '')
df_headline_test['probability'] = df_headline_test['probability'].str.replace(")", '')
df_headline_test['probability'] = df_headline_test['probability'].str.replace("[", '')
df_headline_test['probability'] = df_headline_test['probability'].str.replace("]", '')

# Удаляем ненужную переменную
df_headline_test = df_headline_test.drop(columns=['predict_score'])

# Отобразим количество спрогнозированых саркастических и несаркастических заголовков
df_headline_test.label.value_counts(normalize=True)

0    0.710827
1    0.289173
    

Мы видим, что 28% заголовков были классифицированы как сарказм.

Заключение

В заключение следует отметить, что fastText не является одной из самых последних разработок классификации текстов (библиотека была опубликована в 2015 году). В то же время это хорошая основа для новичков: при выполнении NLP-классификации текстов любой сложности, модель имеет существенное преимущество из-за простоты ее использования, скорости обучения и автоматической настройки гиперпараметров. Подробнее с документацией fastText можно ознакомится по ссылке.

21
Авг
2021

👨‍💼 Профессия системного аналитика в 2021 году: что нужно знать и где учиться?

Освоить эту профессию непросто. Порог входа довольно высок, да и изучить придется немало. Однако если разработчик не хочет идти в тимлиды или становиться менеджером, системная аналитика – перспективный вариант дальнейшей карьеры.

Системный аналитик выступает в роли посредника между IT-специалистами (разработчиками) компании и представителями заказчика, добиваясь полного взаимопонимания между ними.

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

Базовые требования к профессии

Два главных качества системного аналитика – техническое мышление и стрессоустойчивость. Нелишним будет знание основ автоматизации, программирования и схемотехники.

Теперь чуть подробнее:

  • Системный аналитик знает методологии моделирования (IDEFO, IDEF1X, EPC), умеет расставить приоритеты в выполнении требований, а также может защитить свою позицию перед заказчиком, объяснив ее на доступном тому языке.
  • Разобравшись с требованиями, аналитик начинает работать с базами данных, для чего ему нужно владеть SQL и знать стек используемых в компании технологий. Также необходимо умение правильно оформлять документы (этим придется заниматься постоянно).

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

Войти в профессию IT-аналитика можно двумя способами: прийти из бизнес-среды или переквалифицироваться из разработчиков/тестировщиков. В первом случае вам будет хватать бизнес-экспертизы, но недоставать технических навыков. Во втором – наоборот, нужно подтянуть знания в области бизнес-процессов. Для этого существуют комплексные онлайн-курсы, отдельные курсы по различным дисциплинам, книги, блоги, подкасты и прочие ресурсы.

Онлайн-курсы


Если есть деньги – это хороший вариант с готовой комплексной программой и помощью квалифицированных преподавателей.

  • GeekBrains. Русскоязычный онлайн-университет в конце обучения предлагает диплом и помощь с трудоустройством (созданием резюме и его размещением на сайтах поиска работы, а также советы по прохождению собеседований). Есть много бонусов: возврат денег за курс, если не удалось найти работу; подписка на 3 месяца на Lingualeo, подписка на JetBrains и подписка на внутреннюю библиотеку полезных курсов.
  • Нетология. Русскоязычная онлайн-площадка обещает научить основам и выдать диплом о профессиональной переподготовке. Есть возможность подать заявку на обучение составлению резюме и бесплатную подготовку к собеседованиям.
  • Skillbox. Еще одна русскоязычная площадка также выдает диплом о профессиональной переподготовке. Успешно завершивший программу студент получает 3 проекта в портфолио.
  • Яндекс.Практикум. Русскоязычный курс посвящён аналитике данных в целом без привязки к конкретной сфере. Выпускники получают диплом о профессиональной переподготовке и проекты в портфолио. Есть поддержка студентов: составление резюме и советы по прохождению собеседований.
  • Coursera. Англоязычная онлайн-платформа предлагает множество партнерских курсов (от компаний и учебных заведений) по различным профессиям, включая системную аналитику.

Книги


Хорошая теория – хороший базис в подготовке. К тому же никогда не мешает взглянуть на ситуацию под другим углом.

Дин Лэффенгуэлл, Дон Уидриг, «Принципы работы с требованиями к программному обеспечению»


Карл Вигерс и Джой Битти, «Разработка требований к программному обеспечению», 3 издание


Алистер Коберн, «Современные методы описания функциональных требований к системам»


Илья Корнипаев, «Требования для программного обеспечения: рекомендации по сбору и документированию»


Алан Купер, «Психбольница в руках пациентов»

Актуальность книги сейчас невысока, но для общего развития ее можно прочесть.
Актуальность книги сейчас невысока, но для общего развития ее можно прочесть.

Карл Андерсон, «Аналитическая культура»


При выборе книги решающими факторами будут уровень ее сложности книги и цена.

Подкасты, блоги и прочие полезные ресурсы


В подобных сообществах всегда можно найти самую свежую информацию, которая постоянно обновляется.

  • Mastering Business Analysis. Подкаст Дэйва Сабоэ предлагает в основном интервью с лидерами индустрии, также есть эпизоды про полезные технологии и эффективные практики.
  • BA Academy Voice of the Community. Ведущая Лаура Патон использует свой подкаст в роли небольшого форума, где приглашённые гости обсуждают конкретную тему.

Есть сообщества, где можно почувствовать себя в кругу товарищей и коллег.

  • uml2 – здесь русскоязычные аналитики обсуждают последние новости.
  • Чат Business Analysis Magazine_chat в Телеграме и основной канал Бизнес-анализ (эта профессия тесно связана с системной аналитикой).
  • Аналитические игры – интересный кооперативный проект, посвященный решению кейсов на необычные темы, выбранные с учетом актуальных отраслевых трендов.
  • ModernAnalyst – огромный сборник полезной информации для аналитиков. На английском.
***
Новичкам самостоятельно освоить большой объем информации бывает непросто даже при высоком уровне мотивации, не говоря уже про сложность получения практических навыков. Наиболее эффективный путь – получить инструкцию по изучению профессии от специалистов, которые могут подсказать верное направление развития.

Лучшим решением станет программа обучения, во время прохождения которой опытные преподаватели расскажут, как все работает в теории и на практике. Важно выбрать курс, создатели которого заинтересованы в вашей будущей работе в сфере и имеют успешные кейсы трудоустройства своих учеников в известных компаниях. Обратите внимание на «Факультет системной и бизнес-аналитики» образовательной онлайн-платформы GeekBrains, предлагающий одну из самых объемных и содержательных программ, а также гарантирующий выпускникам год практического опыта и трудоустройство.

17
Авг
2021

🤖 Введение в машинное обучение: решаем Titanic на платформе Kaggle

Знакомим читателей с основами Machine Learnng и платформой Kaggle, а также пробуем решить учебный датасет Titanic.

Что такое Kaggle?

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

Перед тем, как начать работать, необходимо зарегистрироваться на сайте. Заходим по ссылке, находим кнопку Register и заполняем поля. Уверен, что вы сами с этим отлично справитесь. После регистрации, подтверждения и логина попадаем на главную страницу ресурса.

Интерфейс Kaggle
Интерфейс Kaggle

Слева в столбце мы видим разделы:

  • Home – новостная лента, в которую попадают публикации, которые могут вас заинтересовать. Чем выше активность пользователя на сайте, тем точнее рекомендации.
  • Competitions – соревнования в области анализа данных. Здесь же находятся учебные соревнования, которые помечены словом Knowledge.
  • Datasets – различные наборы данных, с которыми можно поиграться. Также можно выкладывать собственные датасеты.
  • Code – раздел, в котором можно создать Jupyter Notebook или посмотреть чужой.
  • Discussions – местный аналог форумов.
  • Courses – учебные курсы. Довольно приличный объем и приемлемое качество. Раскрыты основные базовые разделы ML.

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

Теоретический минимум о Machine Learning

Машинное обучение – набор математических, статистических и вычислительных методов, с помощью которых возможно решить задачу путем поиска закономерностей в представленных данных.

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

Все методы ML можно разделить на несколько крупных групп:

  • Обучение с учителем (от англ. Supervised learning) – алгоритмы из этой группы обучаются с помощью заранее подготовленных данных, которые содержат как наборы входных исследуемых признаков, так и “ответы” на эти наборы. “Ответом” является выходное значение, которое должен выдать алгоритм в результате своей работы, т.е. алгоритм “обучается”. К этой группе, например, можно отнести задачи классификации и регрессии.
  • Обучение без учителя (от англ. Unsupervised learning) – группа алгоритмов, в которых система спонтанно обучается на входных данных без вмешательства извне. К этой группе можно отнести задачи кластеризации, понижения размерности.
  • Обучение с подкреплением (от англ. Reinforcement learning) – группа алгоритмов, в которых система обучается с помощью взаимодействия со средой, в которой она находится. Подробнее можно ознакомиться хотя бы в вики. В моей статье алгоритмы этой группы не рассматриваются.

Задачи машинного обучения

Классификация

Вероятно, это самая популярная задача машинного обучения. Ее суть состоит в присвоении какому-то набору признаков (т.е. свойств объекта) какому-то классу. Например, стоит задача автоматической модерации токсичных комментариев на сайте. Алгоритм получает на вход текст комментария, а на выходе присваивает ему метку: токсичный или нетоксичный. Это пример бинарной классификации. К этому же типу классификации можно отнести задачу выявления сердечно-сосудистых проблем по анализам человека, определение спама в письмах и т.п. Второй тип классификации – множественная (многоклассовая). В ней классов больше двух. Примером может служить классификация жанра книги.

Для демонстрации посмотрим графической решение задачи бинарной классификации. Алгоритм разделяет пространство признаков на две группы.

Задача классификации
Задача классификации

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

Регрессия

Задача регрессии – предсказание (прогнозирование) целевого признака по входным параметрам. Например, предсказание загруженности дороги в зависимости от времени суток, дня недели, погоды, предсказание цены квартиры от количества комнат, этажа, района. Предсказание времени на путь из пункта А в пункт Б в зависимости от пробок и т.п. Т.е. задача регрессии это задача получения неизвестного числа по известным параметрам.

Посмотрим на рисунок. По ряду известных значений y(x) была предсказана кривая – линия регрессии. Ее можно продлить, чтобы предсказывать значения y для неизвестных x.

Задача регрессии
Задача регрессии

Для решения задачи применяются следующие алгоритмы и методы: линейная и полиномиальная регрессии, KNN, деревья решений.

Кластеризация

Задача кластеризации состоит в разделении заданной выборки объектов таким образом, чтобы похожие объекты попали в один кластер, а кластеры сильно бы различались между собой. Кластеризацию применяют для анализа и поиска признаков по которым можно объединить объекты, сжатия данных и поиска новизны (что не входит ни в один кластер).

Возникает логичный вопрос: а чем различаются классификация и кластеризация, ведь они решают похожие задачи? При классификации есть набор предопределенных классов, которым обучается алгоритм на наборе примеров. Далее алгоритм предсказывает, к какому классу принадлежит новый объект. При кластеризации используется алгоритм, который пытается сгруппировать набор объектов и определить, существует ли какая-либо взаимосвязь между объектами, т.е. машина учится сама.

Графическим примером кластеризации может быть следующая иллюстрация.

Задача кластеризации
Задача кластеризации

Для решения задачи применяются следующие алгоритмы и методы: K-Means, DBSCAN.

Метрики качества регрессии

Начнем с регрессии. При оценке качества работают с таблицей, содержащей два столбца (помимо индекса): правильные значения и предсказанные. Для простоты рассмотрим четыре строки, и пусть объектами будет количество килограмм картошки для сети ресторанов. Для простоты расчетов возьмем кратные десяти значения.

Номер Значение из выборки (сколько в реальности потребовалось кг картошки) Предсказанное значение (кг)
1 200 180
2 150 190
3 140 120
4 160 220

При таком количестве данных даже визуально можно оценить качество предсказанных данных. Предсказания под номерами 1 и 3 были достаточно точны, номер 2 показал бОльшую ошибку, а в строке номер 4 ошибка оказалась очень большой.

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

Mean Absolute Error (MAE) – средняя абсолютная ошибка

Довольно интуитивный способ – сложить ошибки каждого из предсказаний и разделить на количество предсказаний. Посчитаем для нашей таблицы:

кг40+20+40+604=35кг

В среднем наш алгоритм ошибается на 35 кг картошки. Где-то в плюс, где-то в минус. Такая метрика называется средней абсолютной ошибкой, mean absolute error или MAE.

MAE=1n∑i=1n|yi−xi|=1n∑i=1n|ei|

где yi – предсказанные значения, а xi – реальные известные значения, ei – ошибка i-го предсказания.

Mean Square Error (MSE) – Средняя квадратичная ошибка

Достаточно часто используется похожая метрика, MSE. Она рассчитывается почти так же, только берется не модуль ошибки ei, а ее квадрат.

MSE=1n∑i=1n(yi−xi)2=1n∑i=1nei2

Для нашего примера:

кгMSE=400+1600+400+36004=1500кг2

Но мы получили не ошибку в килограммах, а “кг в квадрате”. Чтобы вернуться к исходной величине, необходимо извлечь из MSE квадратный корень:

кгRMSE=MSE=1500=38.72кг

По сравнению с RMSE, метрика MAE более интуитивна, т.к. усредняются сами отклонения, но RMSE удобнее использовать при обучении алгоритмов. Хотя для MAE обучение тоже успешно выполняется.

Еще одна особенность метрики MAE — она более устойчива к выбросам, чем RMSE. Это означает, что если для одного объекта ошибка очень большая (объект-выброс), а для остальных объектов – маленькая, то значение MAE подскочит от этого одного объекта меньше, чем RMSE, т.к. в RMSE ошибки возводятся в квадрат. В нашем примере объектом-выбросом является четвертое предсказание.

Quantile loss

Иногда ошибка в меньшую или большую сторону может иметь разное влияние на бизнес. Например, если мы предскажем на одну тысячу единиц товара меньше, чем реально потребуется, то потеряем прибыль: некоторым клиентам не достанется товара. А если мы предскажем на одну тысячу единиц больше товара, чем реально потребуется, то появятся дополнительные издержки на хранение товара.

Предположим, что товар занимает мало места (т.к. площади хранения в ресторанах велики) и расходы на хранение невелики, тогда лучше ошибиться в большую сторону, чем в меньшую. В этом случае отрицательную и положительную разницу домножают на разные коэффициенты, например, возьмем 0.5 и 1.5.

В нашем примере, коэффициент 1.5 будет применен к предсказаниям 1 и 3 (180 < 200 и 120 < 140), а коэффициент 0.5 к остальным. Тогда значение метрики будет равно:

кг1,5⋅20+0,5⋅40+1.5⋅20+0.5⋅604=27.5кг

Данная метрика называется квантильной ошибкой.

Само по себе значение метрик MSE или MAE можно сравнивать со средним значением целевой переменной: например, нам нужно предсказывать десятки, при этом допустимы ошибки порядка единиц. Если хочется получать значения ошибки в процентах («алгоритм в среднем ошибается на столько-то процентов»), можно использовать метрики с нормировками.

К примеру, метрика MAPE (mean average percentage error) усредняет значения ошибок, деленных на значение целевой переменной:

MAPE=20200+40150+20140+601604=22.1

В нашем случае, алгоритм в среднем ошибается на 22.1%.

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

Метрики качества классификации

Accuracy – доля правильных ответов

В задаче классификации самой простой метрикой качества является доля правильных ответов (accuracy). Она показывает, в каком проценте случаев алгоритм правильно указал класс объекта.

Для примера будет рассматривать задачу предсказания токсичности комментариев. Т.е. имеем задачу бинарной классификации, где 0 – комментарий нетоксичен, 1 – комментарий токсичен. Возьмем для простоты пять комментариев и сведем все в таблицу.

ID комментария Значение в данных (токсичен ли комментарий в действительности) Предсказанное значение
1 1 1
2 1 1
3 0 0
4 0 1
5 0 0

В нашем примере, алгоритм выдал правильные ответы для комментариев 1,2,3,5, т.е. в 80% случаев. Это и есть значение accuracy.

Accuracy – простая и интерпретируемая метрика, но она не отражает полную картину, в частности, в какую сторону алгоритм ошибается чаще. Кроме того, использовать эту метрику может быть неудобно в ситуации с несбалансированными классами, то есть, когда объектов одного класса много больше, чем объектов другого. К примеру, если в данных 95% объектов из класса 0 и 5% из класса 1, а алгоритм всегда предсказывает, что объект относится к классу 0, то его accuracy будет равно 95%, хотя алгоритм совершенно бесполезный! В таких случаях часто используют другие метрики.

Precision and Recall – Точность и полнота

Чтобы понять, что такое точность и полнота, разберемся сначала с возможными типами ошибок. Для этого отлично подходит картинка из википедии.

Ошибки первого и второго рода
Ошибки первого и второго рода

В нашем примере, если алгоритм пометит нормальный комментарий как токсичный, то ничего особо страшного не произойдет. Этот коммент будет в дальнейшей проверен модератором. Такая ошибка называется ошибкой первого рода (false positive). Если же комментарий будет распознан как нормальный, но он токсичный, то такая ошибка называется ошибкой второго рода (false negative). На мой взгляд, в нашем примере ошибка второго рода страшнее, чем ошибка первого. Но бывает и наоборот.

Для отслеживания двух видов ошибок используют метрики точность (Precision) и полнота (Recall).

  • Точность измеряет, какой процент объектов, для которых алгоритм предсказал класс 1, действительно относится к классу 1. В нашем примере, точность – это отношение количества реально токсичных комментариев к количеству помеченных как токсичные. И эта метрика составляет ⅔ = 66%.
  • Полнота измеряет, для какого процента объектов класса 1 алгоритм предсказал класс 1. Для нашего примера полнота составляет 100%. Для простоты понимания, в вики формулы расчеты показаны визуально.
Расчет точности и полноты
Расчет точности и полноты

Отслеживать обе метрики сразу может быть неудобно, и может понадобиться скомбинировать их в одной. Для этого используют F-меру – среднее гармоническое точности P и полноты R:

F=2⋅P⋅RP+R

Такой способ усреднения был выбран потому, что F-мера принимает высокие значения, только когда обе метрики принимают высокие значения. Иными словами, если хотя бы одна из двух метрик близка к 0, F-мера тоже будет близка к 0. Это свойство не выполняется, например, для среднего арифметического из точности и полноты.

Ансамблевые методы

В этом разделе поговорим про ансамбли – методы, наиболее часто используемые в машинном обучении при работе с табличными данными. Ансамбли обычно применяют в задачах классификации и регрессии, но они годятся и для других задач, которые сводятся к этим двум. Стоит сказать, что это только вершина айсберга и методов машинного обучения очень много. Их обзор можно найти в этой статье.

Вспомним постановку задач регрессии и классификации. В обеих требуется набор табличных данных: по строкам таблицы заданы объекты (например, клиенты), а по столбцам – признаки, то есть некоторые характеристики объектов (возраст, заработная плата, стаж работы клиента и т. д.). Кроме того, нужна разметка данных: для каждого объекта должно быть известно значение целевой переменной (класс в задаче классификации или число в задаче регрессии). Имея набор размеченных данных, мы обучаем алгоритм, который будет предсказывать значение целевой переменной для новых объектов на стадии внедрения.

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

Решающее дерево – это алгоритм, который делает предсказания на основе серии вопросов об объекте.

Например, покажем решающее дерево, которое определяет возможность проставления оценки по какому-то предмету студенту.

Пример решающего дерева
Пример решающего дерева

Ансамблирование заключается в том, чтобы обучить несколько алгоритмов и усреднять их предсказания.

Например, строится несколько разных решающих деревьев, и берется среднее результатов их работы. Подробно про ансаблирование в машинном обучении можно почитать тут.

Решаем Titanic на Kaggle

Для начала неплохо было бы ознакомиться с задачей и данными, которые нам предоставляют. Идем на kaggle.com/c/titanic/overview. Изучив описание, узнаем, что нам предстоит решить задачу классификации: по заданным признакам необходимо определить, выживет ли пассажир при крушении Титаника или нет. Предлагаемые данные (раздел Data) состоят из трех файлов .csv: train.csv – обучающая выборка, в которой содержатся метки, выжил ли каждый конкретный пассажир или нет; test.csv – собственно данные для решения, именно в этом файле нам нужно определить выживаемость; gender_submission.csv – пример того, как должен выглядит файл-ответ.

Что нужно делать – понятно. Начинаем смотреть наши данные. Переходим на вкладку Code и нажимаем New notebook.


Таким образом, мы получаем продвинутый jupyter notebook. Чтобы активировать систему, нажмем на значок Play слева от верхней ячейки ноутбука. Система будет запущена и в результате, под ячейкой увидим пути до csv файлов.


Можно приступать. Если вы не знакомы с jupyter notebook и pandas, то рекомендую сначала прочитать данный материал.

Чтение и анализ датасета Titanic

Первым делом, загружаем в датафреймы файлы .csv.

        train_data = pd.read_csv('/kaggle/input/titanic/train.csv')
test_data = pd.read_csv('/kaggle/input/titanic/test.csv')

    

Проверим, что все у нас удачно и взглянем на эти датафреймы. Для примера приведу train_data.

        train_data.head()
    

Первым делом оценим размеры датафрейма. Для этого используем свойство shape.

        train_data.shape
    

В результате получаем (891, 12), т.е. 12 столбцов и 891 строку.

Следующим этапом неплохо было бы оценить количество пустых ячеек в столбцах обучающей выборки. Для этого вызовем:

        train_data.isnull().sum()
    

Получаем, что в столбце Age у нас 177 пропусков, а в Cabin аж 687, что сильно больше половины.

Далее, оценим выживаемость. Для простоты визуализации будем использовать библиотеку seaborn. Для этого подключить ее и matplotlib.

        import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
sns.countplot(x='Survived', data=train_data)

    

Как видим, выжило людей меньше, чем погибло.

Теперь посмотрим, как с выживаемостью у мужчин и женщин отдельно.

        sns.countplot(x='Survived', hue='Sex', data=train_data)

    

Видим, что мужчин погибло гораздо больше, чем выжило. И большая часть женщин выжила.

Далее взглянем, как зависела выживаемость от класса каюты.

        sns.countplot(x='Survived', hue='Pclass', data=train_data) 

    

Видим всплеск среди погибших пассажиров 3 класса.

Не закапываясь глубоко в датасет, видим явную зависимость выживаемости от пола и класса каюты.

В качестве признаков кроме выбранных пола и класса каюты, возьмем количество родителей\детей и количество братьев\сестер на борту. Итоговый список признаков будет выглядеть следующим образом:

        features = ['Sex', 'Pclass', 'SibSp', 'Parch']
    

Информацию о выживших и погибших пассажирах поместим в переменную y:

        y = train_data['Survived']

    

Если вы немного отмотаете назад, то увидите, что в столбце Sex находятся не числа, а строки, когда остальные отобранные нами признаки являются числами. Давайте превратим этот столбец в пару фиктивных переменных. Для этого в Pandas есть специальный метод, который называется get_dummies(). Сделаем эту операцию как для обучающей выборки, так и для тестовой.

        X = pd.get_dummies(train_data[features])
X_test = pd.get_dummies(test_data[features])

    

Обратите внимание, что столбец Sex исчез, а вместо него появилось два столбца Sex_female и Sex_male.

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

        from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier(n_estimators=100, max_depth=5, random_state=1)
model.fit(X, y)  # обучаем модель
prediction = model.predict(X_test)  # делаем предсказание
output = pd.DataFrame({'PassengerId':test_data.PassengerId, 'Survived':prediction})
output.to_csv('my_submission.csv', index=False)  # формируем итоговый датафрейм и сохраняем его в csv файл

    

Вот и все. Осталось отправить результат в соревнование. Для этого в правом верхнем углу наживаем кнопку Save version. После того, как блокнот сохранится, нажимаем на цифру возле этой кнопки.


Откроется окно Version history. В правом списке, нажимаем на многоточие около только что сохраненной версии и нажимаем Submit to competition.


Появляется окошко, в котором нажимаем submit.

Поздравляю! Вы закончили свое первое соревнование на kaggle. Нажмите на view my submission, чтобы взглянуть на результат.


Чем ближе число к 1, тем лучше. Но 0.775, согласитесь, неплохо для первого раза.

Путями улучшения результата могут быть: введение дополнительных признаков, введение своих новых признаков, выбор другого алгоритма, выбор другим параметров алгоритма RandomForestClassifier. Для начала, попробуйте поиграть с числами в этой строке (называются эти числа гиперпараметрами).

        model = RandomForestClassifier(n_estimators=100, max_depth=5, random_state=1)

    

Дополнительные материалы для изучения:

При подготовке были использованы материала из Википедии и Летней школы Сбера.

12
Авг
2021

Онлайн-хакатон «Цифровой форсаж атомных городов»

Командам предстоит решать задачи и предлагать идеи по улучшению цифрового сервиса в «атомных» городах. Призовой фонд — 1 млн рублей.
— Читать дальше «Онлайн-хакатон «Цифровой форсаж атомных городов»»

12
Авг
2021

🤖 Машинное обучение для начинающих: алгоритм случайного леса (Random Forest)

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

Алгоритм случайного леса (Random Forest) — универсальный алгоритм машинного обучения, суть которого состоит в использовании ансамбля решающих деревьев. Само по себе решающее дерево предоставляет крайне невысокое качество классификации, но из-за большого их количества результат значительно улучшается. Также это один из немногих алгоритмов, который можно использовать в абсолютном большинстве задач.

В каких задачах используется?

Благодаря своей гибкости Random Forest применяется для решения практически любых проблем в области машинного обучения. Сюда относятся классификации (RandomForestClassifier) и регрессии (RandomForestRegressor), а также более сложные задачи, вроде отбора признаков, поиска выбросов/аномалий и кластеризации.

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

        import pandas as pd 
from sklearn.ensemble  import RandomForestClassfier 
from sklearn.feature_selection import SelectFromModel 
X_train,y_train,X_test,y_test = train_test_split(data,test_size=0.3)
 sel = SelectFromModel(RandomForestClassifier(n_estimators = 100)) 
sel.fit(X_train, y_train)
    

Здесь мы на основе классификации просто добавляем метод для отбора признаков.

Порядок действий в алгоритме

  • Загрузите ваши данные.
  • В заданном наборе данных определите случайную выборку.
  • Далее алгоритм построит по выборке дерево решений.
  • Дерево строится, пока в каждом листе не более n объектов, или пока не будет достигнута определенная высота.
  • Затем будет получен результат прогнозирования из каждого дерева решений.
  • На этом этапе голосование будет проводиться для каждого прогнозируемого результата: мы выбираем лучший признак, делаем разбиение в дереве по нему и повторяем этот пункт до исчерпания выборки.
  • В конце выбирается результат прогноза с наибольшим количеством голосов. Это и есть окончательный результат прогнозирования.

Теоретическая составляющая алгоритма случайного дерева

По сравнению с другими методами машинного обучения, теоретическая часть алгоритма Random Forest проста. У нас нет большого объема теории, необходима только формула итогового классификатора a(x):


Где

  • N – количество деревьев;
  • i – счетчик для деревьев;
  • b – решающее дерево;
  • x – сгенерированная нами на основе данных выборка.

Стоит также отметить, что для задачи классификации мы выбираем решение голосованием по большинству, а в задаче регрессии – средним.

Реализация алгоритма Random Forest

Реализуем алгоритм на простом примере для задачи классификации, используя библиотеку scikit-learn:

        class sklearn.ensemble.RandomForestClassifier(n_estimators=10, criterion='gini', max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features='auto', max_leaf_nodes=None, min_impurity_split=1e-07, bootstrap=True, oob_score=False, n_jobs=1, random_state=None, verbose=0, warm_start=False, class_weight=None)
    

Работаем с алгоритмом по стандартному порядку действий, принятому в scikit-learn. Вычисляем AUC-ROC (площадь под кривой ошибок) для тренировочной и тестовой частей модели, чтобы определить ее качество:

        from sklearn.ensemble import RandomForestRegressor 
from sklearn.metrics import roc_auc_score 
# далее - (X, y) - для обучения, (X2, y2) - для контроля
# модель - регрессор 
model =  RandomForestRegressor(n_estimators=10,                              
                               oob_score=True,
                               random_state=1) 
model.fit(X, y) # обучение 
a = model.predict(X2) # предсказание  
print ("AUC-ROC (oob) = ", roc_auc_score(y, model.oob_prediction_)) 
print ("AUC-ROC (test) = ", roc_auc_score(y2, a))
    

Необходимые параметры алгоритма

Число деревьев – n_estimators

Чем больше деревьев, тем лучше качество. Стоит отметить, что время настройки и работы Random Forest будут пропорционально увеличиваться, что может сказаться на производительности.

Часто при большом увеличении n_estimators качество на обучающей выборке может даже доходить до 100%, в то время как качество на тесте выходит на асимптоту, что сигнализирует о переобучении нашей модели. Лучший способ избежать этого – прикинуть, сколько деревьев вам достаточно, зафиксировав момент, когда качество теста еще не становится стабильно-неизменным.

Критерий расщепления – criterion

Также один из самых важных параметров для построения, но без значительной возможности выбора. В библиотеке sklearn для задач классификации реализованы критерии gini и entropy. Они соответствуют классическим критериям расщепления: джини и энтропии.

В свою очередь, для задач регрессии реализованы два критерия (mse и mae), которые являются функциями ошибок Mean Square Error и Mean Absolute Error соответственно. Практически во всех задачах используется критерий mse.

Простой метод перебора поможет выбрать, что использовать для решения конкретной проблемы.

Число признаков для выбора расщепления – max_features

При увеличении max_features увеличивается время построения леса, а деревья становятся похожими друг на друга. В задачах классификации он по умолчанию равен sqrt(n), в задачах регрессии – n/3.

Является одним из самых важных параметров в алгоритме. Он настраивается в первую очередь, после того, как мы определили тип нашей задачи.

Минимальное число объектов для расщепления – min_samples_split

Второстепенный по своему значению параметр, его можно оставить в состоянии по умолчанию.

Ограничение числа объектов в листьях – min_samples_leaf

Аналогично с min_samples_split, но при увеличении данного параметра качество модели на обучении падает, в то время как время построения модели сокращается.

Максимальная глубина деревьев – max_depth

Чем меньше максимальная глубина, тем быстрее строится и работает алгоритм случайного дерева.

При увеличении глубины резко возрастает качество как на обучении модели, так и на ее тестировании. Если у вас есть возможность и время для построения глубоких деревьев, то рекомендуется использовать максимальное значение данного параметра.

Неглубокие деревья рекомендуется использовать в задачах со значительным количеством шумовых объектов (выбросов).

Преимущества алгоритма


  • Имеет высокую точность предсказания, которая сравнима с результатами градиентного бустинга.
  • Не требует тщательной настройки параметров, хорошо работает из коробки.
  • Практически не чувствителен к выбросам в данных из-за случайного семплирования (random sample).
  • Не чувствителен к масштабированию и к другим монотонным преобразованиям значений признаков.
  • Редко переобучается. На практике добавление деревьев только улучшает композицию.
  • В случае наличия проблемы переобучения, она преодолевается путем усреднения или объединения результатов различных деревьев решений.
  • Способен эффективно обрабатывать данные с большим числом признаков и классов.
  • Хорошо работает с пропущенными данными – сохраняет хорошую точность даже при их наличии.
  • Одинаково хорошо обрабатывает как непрерывные, так и дискретные признаки
  • Высокая параллелизуемость и масштабируемость.

Недостатки алгоритма


  • Для реализации алгоритма случайного дерева требуется значительный объем вычислительных ресурсов.
  • Большой размер моделей.
  • Построение случайного леса отнимает больше времени, чем деревья решений или линейные алгоритмы.
  • Алгоритм склонен к переобучению на зашумленных данных.
  • Нет формальных выводов, таких как p-values, которые используются для оценки важности переменных.
  • В отличие от более простых алгоритмов, результаты случайного леса сложнее интерпретировать.
  • Когда в выборке очень много разреженных признаков, таких как тексты или наборы слов (bag of words), алгоритм работает хуже чем линейные методы.
  • В отличие от линейной регрессии, Random Forest не обладает возможностью экстраполяции. Это можно считать и плюсом, так как в случае выбросов не будет экстремальных значений.
  • Если данные содержат группы признаков с корреляцией, которые имеют схожую значимость для меток, то предпочтение отдается небольшим группам перед большими, что ведет к недообучению.
  • Процесс прогнозирования с использованием случайных лесов очень трудоемкий по сравнению с другими алгоритмами.

Заключение

Метод случайного дерева (Random Forest) – это универсальный алгоритм машинного обучения с учителем. Его можно использовать во множестве задач, но в основном он применяется в проблемах классификации и регрессии.

Действенный и простой в понимании, алгоритм имеет значительный недостаток – заметное замедление работы при определенной настройке параметров внутри него.

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

Дополнительные материалы:

25
Июл
2021

📊 Как стать дата-инженером в 2021 году?

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

Мир науки о данных быстро меняется, и это открыло новые возможности и вакансии в области инженерии данных. Давно хотели разобраться, как стать дата-инженером, но не знали с чего начать? Тогда эта статья для вас.

Типичные обязанности дата-инженера:

  • Исследовательский анализ данных.
  • Извлечение данных из массивов разнородной информации.
  • Оценка и очистка наборов данных.
  • Подготовка и написание логики ETL (процессов обработки/преобразования информации).
  • Построение конвейеров данных для распределения по нескольким серверам.
  • Сбор и запрос данных.
  • Объединение данных.
  • Создание хранилищ данных.
  • Оптимизация доставки данных.
  • Нормализация и моделирование данных.
  • Перепроектирование инфраструктуры данных для масштабируемости.
  • Использование инструментов для обслуживания данных.
  • Помощь специалистам по исследованию данных в оптимизации продуктов.

Главные технические компетенции дата-инженера:

  • Языки программирования Python, C++, Java и Scala.
  • Знание алгоритмов и структур данных.
  • Системы управления базами данных (SQL и NoSQL).
  • Инфраструктура – облачные вычисления.
  • Потоковая передача данных – Apache Beam.

Как стать успешным дата-инженером в 2021 году?


Изучите языки программирования

Требования индустрии вращаются вокруг Python и Scala. Чтобы создавать качественное ПО, вам потребуется подтянуть навыки владения этими языками и получить практический опыт работы с инструментами для инженерии данных. Также желательно владеть такими языками, как Java и C++.

Освойте SQL

Все компании используют базы данных, чаще всего с SQL (языком структурированных запросов). Вам нужно изучить его, чтобы быстро добавлять, изменять или извлекать данные из этих баз. Один из лучших ресурсов для изучения − SQL Exercises. Другой вариант − наши статьи. Вы также можете использовать бесплатные шпаргалки по SQL, потому что запомнить все функции сразу будет тяжело.


Изучите облачные технологии

В наше время очень важно уметь работать с облачными средами. Изучите различные виды услуг, предоставляемых облачными платформами: хранение данных, управление кластерами, управление обработкой данных, вычисления и т.д.

Придется также изучить инструменты, вроде Kafka или Hadoop для планирования рабочих процессов в экосистеме больших данных.

Soft skills
Чтобы добиться успеха, технических навыков недостаточно. Вы также должны иметь навыки общения, презентации и командной работы.

Лучший способ профессионального роста – следить за последними тенденциями и инновациями в области науки о данных. Следите за выходом нового программного обеспечения и появлением новых инструментов для работы с данными. Работайте над большим количеством проектов и создавайте портфолио, чтобы продемонстрировать свои технические навыки и получить хорошую должность в известной компании.

Обзор ресурсов для изучения

Алгоритмы и структуры данных

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

Python

С помощью этих двух курсов вы освоите основы Python: изучите синтаксис языка, получите базовые навыки структурного и процедурного программирования, познакомитесь со структурами данных языка.

SQL

Облачные технологии

  • Hadoop. Система для обработки больших объемов данных. Курс посвящен методам обработки больших объемов данных с помощью системы Hadoop. Завершив обучение, вы получите базовые знания об основных способах хранения и методов обработки больших объемов данных, а также поймете принципы работы распределенных систем в контексте фреймворка Hadoop.
Из более продвинутых курсов хочется отметить англоязычный GCP: Complete Google Data Engineer and Cloud Architect Guide на Udemy, где 28 часов контента дополняются 25 статьями и 48 ресурсами для скачивания. Программа обучения дает полное представление о дисциплине.

Итог

Если вам нравится работать в спокойной обстановке и проводить чистку необработанных данных, карьера в области дата-инженерии – правильный выбор. Самое трудное – создать портфолио и накопить опыт для получения первой работы. Значительное увеличение объема облачных услуг стало одной из основных причин столь высокого спроса на инженеров по обработке данных.

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

***

Если вы только начинаете путь в профессии, обратите внимание на курс Data Engineering образовательной онлайн-платформы GeekBrains. Занятия под руководством опытных наставников и поддержка опытных HR помогут вам продвинуться по карьерной лестнице. Вы научитесь собирать и обрабатывать данные, проектировать хранилища и работать с инфраструктурой. Специализированный опыт для этого не потребуется: программа предполагает освоение профессиональных навыков с нуля.

19
Июл
2021

🤖 Метод k-ближайших соседей (k-nearest neighbour)

Метод k-ближайших соседей (k Nearest Neighbors, или kNN) – популярный алгоритм классификации, который используется в разных типах задач машинного обучения. Наравне с деревом решений это один из самых понятных подходов к классификации.

Что это такое?
На интуитивном уровне суть метода проста: посмотри на соседей вокруг, какие из них преобладают, таковым ты и являешься. Формально основой метода является гипотеза компактности: если метрика расстояния между примерами введена удачно, то схожие примеры гораздо чаще лежат в одном классе, чем в разных.

  • В случае использования метода для классификации объект присваивается тому классу, который является наиболее распространённым среди k соседей данного элемента, классы которых уже известны.
  • В случае использования метода для регрессии, объекту присваивается среднее значение по k ближайшим к нему объектам, значения которых уже известны.

Пример классификации k-ближайших соседей.


  • У нас есть тестовый образец в виде зеленого круга. Синие квадраты мы обозначим как класс 1, красные треугольники – класс 2.
  • Зеленый круг должен быть классифицирован как класс 1 или класс 2. Если рассматриваемая нами область является малым кругом, то объект классифицируется как 2-й класс, потому что внутри данного круга 2 треугольника и только 1 квадрат.
  • Если мы рассматриваем большой круг (с пунктиром), то круг будет классифицирован как 1-й класс, так как внутри круга 3 квадрата в противовес 2 треугольникам.

Теоретическая составляющая алгоритма k-NN

Помимо простого объяснения, необходимо понимание основных математических составляющих алгоритма k-ближайших соседей.

  • Евклидова метрика (евклидово расстояние, или же Euclidean distance) – метрика в евклидовом пространстве, расстояние между двумя точками евклидова пространства, вычисляемое по теореме Пифагора. Проще говоря, это наименьшее возможное расстояние между точками A и B. Хотя евклидово расстояние полезно для малых измерений, оно не работает для больших измерений и для категориальных переменных. Недостатком евклидова расстояния является то, что оно игнорирует сходство между атрибутами. Каждый из них рассматривается как полностью отличный от всех остальных.

Формула вычисления Евклидова расстояния:

        d(p, q) = d(q, p) = \sqrt{(q_1 - p_1)^2 + (q_2 - p_2)^2 + ...+ (q_n - p_n)^2} =\sqrt{\sum_{i=1}^n(q_i - p_i)^2}
    
  • Другой важной составляющей метода является нормализация. Разные атрибуты обычно обладают разным диапазоном представленных значений в выборке. К примеру, атрибут А представлен в диапазоне от 0.01 до 0.05, а атрибут Б представлен в диапазоне от 500 до 1000). В таком случае значения дистанции могут сильно зависеть от атрибутов с бо́льшими диапазонами. Поэтому данные в большинстве случаев проходят через нормализацию. При кластерном анализе есть два основных способа нормализации данных: MinMax-нормализация и Z-нормализация.

MinMax-нормализация осуществляется следующим образом:

        x' = (x - min[X])/(max[X] - min[X])
    

в данном случае все значения будут находиться в диапазоне от 0 до 1; дискретные бинарные значения определяются как 0 и 1.

Z-нормализация:

        x' = (x - M[X])/σ[X]
    

где σ – среднеквадратичное отклонение. В данном случае большинство значений попадает в диапазон.

Каков порядок действий?

  • Загрузите ваши данные.
  • Инициализируйте k путем выбора оптимального числа соседей.
  • Для каждого образца в данных:
  1. Вычислите расстояние между примером запроса и текущим примером из данных.
  2. Добавьте индекс образца в упорядоченную коллекцию, как и его расстояние.
  • Отсортируйте упорядоченную коллекцию расстояний и индексов от наименьшего до наибольшего, в порядке возрастания.
  • Выберите первые k записей из отсортированной коллекции.
  • Возьмите метки выбранных k записей.
  • Если у вас задача регрессии, верните среднее значение выбранных ранее k меток.
  • Если у вас задача классификации, верните наиболее часто встречающееся значение выбранных ранее меток k.

Реализация на языке Python

Для демонстрации мы будем использовать самое распространенное соревнованию-песочницу на Kaggle: Titanic. Данные вы можете найти здесь. Мы стремимся использовать python-библиотеку для машинного обучения scikit-learn. Мы используем набор данных «Титаник» для логистической регрессии.

Набор данных состоит из 15 столбцов, таких как sex (пол), fare (плата за проезд), p_class (класс каюты), family_size (размер семьи), и т. д. Главным признаком, который мы и должны предсказать в соревновании, является survived (выжил пассажир или нет).

Дополнительный анализ показал, что находящиеся в браке люди имеют больший шанс на то, чтобы быть спасенными с корабля. Поэтому были добавлены еще 4 столбца, переименованные из Name (Имя), которые обозначают мужчин и женщин в зависимости от того, были они женаты или нет (Mr, Mrs, Mister, Miss).

Полный набор данных можно загрузить отсюда, а полный код для этой статьи вы найдете здесь.

Чтобы наглядно продемонстрировать функциональность k-NN для предсказания выживания пассажира, мы рассматриваем только два признака: age (возраст), fare (плата за проезд).

        # Загружаем данные
train_df = pd.read_csv('/kaggle/input/titanic/train_data.csv') 
# Избавляемся от двух столбцов без нужной информации
train_df = train_df.drop(columns=['Unnamed: 0', 'PassengerId']) 
from sklearn.neighbors import KNeighborsClassifier 
predictors = ['Age', 'Fare'] 
outcome = 'Survived' 

new_record = train_df.loc[0:0, predictors] 
X = train_df.loc[1:, predictors] 
y = train_df.loc[1:, outcome] 

kNN = KNeighborsClassifier(n_neighbors=20) 
kNN.fit(X, y) 
kNN.predict(new_record)
print(kNN.predict_proba(new_record)) 

#[результат/вывод]: [[0.7 0.3]]
    

Здесь вероятность выживания составляет 0.3 – 30%.

Далее мы настраиваем алгоритм k-NN на поиск и использование 20 ближайших соседей, чтобы оценить состояние пассажира. Для наглядности выводим 20 первых соседей новой записи с помощью импортированного метода kneighbors. Реализация выглядит следующим образом:

        nbrs = knn.kneighbors(new_record)
maxDistance = np.max(nbrs[0][0])

fig, ax = plt.subplots(figsize=(10, 8))
sns.scatterplot(x = 'Age', y = 'Fare', style = 'Survived', 
                hue='Survived', data=train_df, alpha=0.3, ax=ax)
sns.scatterplot(x = 'Age', y = 'Fare', style = 'Survived', 
                hue = 'Survived', 
                data = pd.concat([train_df.loc[0:0, :], train_df.loc[nbrs[1][0] + 1,:]]), 
                ax = ax, legend=False)
ellipse = Ellipse(xy = new_record.values[0], 
                  width = 2 * maxDistance, height = 2 * maxDistance,
                  edgecolor = 'black', fc = 'None', lw = 1)
ax.add_patch(ellipse)
ax.set_xlim(.25, .29)
ax.set_ylim(0, .03)

plt.tight_layout()
plt.show()
    

Результат работы кода:


Как видите, на графике показаны 20 ближайших соседей, 14 из которых связаны с теми, кто не выжил (вероятность 0,7 – 70%), а 6 связаны с выжившими (вероятность 0,3 – 30%).

Мы можем просмотреть первые 20 ближайших соседей для заданных параметров при помощью следующего кода:

        nbrs = knn.kneighbors(new_record)
nbr_df = pd.DataFrame({'Age': X.iloc[nbrs[1][0], 0], 
                         'Fare': X.iloc[nbrs[1][0], 1],
                         'Survived': y.iloc[nbrs[1][0]]})
nbr_df
    

Результатом будет таким:


Выбор Оптимального значения для k-NN

Не существует конкретного способа определить наилучшее значение для k, поэтому нам нужно попробовать несколько значений, чтобы найти лучшее из них. Но чаще всего наиболее предпочтительным значением для k является 5:

  • Низкое значение k, например, 1 или 2, может привести к эффекту недообучения модели.
  • Высокое значение k на первый взгляд выглядит приемлемо, однако возможны трудности с производительностью модели, а также повышается риск переобучения.

Преимущества и Недостатки

Преимущества:

  • Алгоритм прост и легко реализуем.
  • Не чувствителен к выбросам.
  • Нет необходимости строить модель, настраивать несколько параметров или делать дополнительные допущения.
  • Алгоритм универсален. Его можно использовать для обоих типов задач: классификации и регрессии.

Недостатки:

  • Алгоритм работает значительно медленнее при увеличении объема выборки, предикторов или независимых переменных.
  • Из аргумента выше следуют большие вычислительные затраты во время выполнения.
  • Всегда нужно определять оптимальное значение k.

В заключение

Метод k-ближайших соседей (k-nearest neighbors) – это простой алгоритм машинного обучения с учителем, который можно использовать для решения задач классификации и регрессии. Он прост в реализации и понимании, но имеет существенный недостаток – значительное замедление работы, когда объем данных растет.

Алгоритм находит расстояния между запросом и всеми примерами в данных, выбирая определенное количество примеров (k), наиболее близких к запросу, затем голосует за наиболее часто встречающуюся метку (в случае задачи классификации) или усредняет метки (в случае задачи регрессии).

16
Июл
2021

🤖 Генеративная состязательная сеть (GAN) для чайников – пошаговое руководство

Лучшее руководство для новичков по пониманию, созданию и обучению GAN с надежным кодом на Python.

Текст публикуется в переводе, автор статьи – Мишель Кана.

Эта статья познакомит вас со всем необходимым для вхождения в мир генеративных состязательных сетей. Никакого предварительного знакомства с GANами не требуется. Мы предоставим пошаговое руководство по обучению GANов на наборах данных с большими изображениями и по их использованию для генерации новых лиц знаменитостей с помощью Keras.

Генеративная Состязательная Сеть – самая интересная идея в машинном обучении за последние десять лет.
Янн ЛеКун, вице-президент и Глава исследований по ИИ в Facebook, отец-основатель ИИ.

Хотя генеративная состязательная сеть – это старая идея, происходящая из теории игр, они были введены в коммьюнити машинного обучения в 2014-м Йэном Гудфеллоу и соавторами в статье “Генеративные состязательные сети“. Как же работают GAN и для чего они хороши?

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

Фейковые фотореалистичные лица, созданные GANом (<a href="https://research.nvidia.com/sites/default/files/pubs/2017-10_Progressive-Growing-of/karras2018iclr-paper.pdf" target="_blank" rel="noopener noreferrer nofollow">источник</a>)
Фейковые фотореалистичные лица, созданные GANом (источник)

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

Пример изображения и его восстановления с помощью нашего кода VAE
Пример изображения и его восстановления с помощью нашего кода VAE

VAE обычно генерируют размытые и не фотореалистичные изображения. Это и является стимулом к созданию генеративных состязательных сетей (GANов).

В этой статье мы увидим, как GANы предлагают совершенно иной подход к генерации данных, похожих на тренировочные данные.

Игра вероятностей

Генерация новых данных – это игра вероятностей. Когда мы наблюдаем мир вокруг себя и собираем данные, мы производим эксперимент. Простой пример – это фотографирование лиц знаменитостей.

Это можно считать вероятностным экспериментом с неизвестным результатом X, также называемого случайной переменной.

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

Например, мы можем определить вероятность того, что наше лицо будет лицом Тайриза, знаменитого певца.

Тайриз Гибсон
Тайриз Гибсон

Набор всех возможных результатов такого эксперимента образует так называемое пространство выборки, обозначаемое символом “омега” (в нашем случае – все возможные лица знаменитостей).


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

Мы также называем это функцией распределения вероятности P(X). Если мы знаем пространство выборки (все возможные лица знаменитостей) и распределение вероятности (вероятность появления каждого лица), у нас есть полное описание эксперимента, и мы можем делать выводы о его результатах.

Вы можете освежить свои знания о вероятностях, прочитав нашу статью.

Распределение вероятностей лиц знаменитостей

Генерацию новых лиц можно определить как задачу генерации случайной переменной. Лицо описывается случайными переменными, при этом значения RGB его пикселей “сплющиваются” в вектор из N чисел.

Наши лица знаменитостей имеют ширину 218 пикселей, высоту 178 пикселей и 3 цветовых канала. Таким образом, каждый вектор будет иметь 116412 измерений.

Если мы построим пространство со 116412 (N) измерениями, каждое лицо будет точкой в этом пространстве. Функция распределения вероятности лиц знаменитостей P(X) поставит каждому лицу в соответствие неотрицательное целое число, чтобы сумма этих чисел была равна 1.

Некоторые точки этого пространства, скорее всего, представляют лица знаменитостей, а многие другие, скорее всего, не представляют.

Функция распределения вероятности лиц знаменитостей
Функция распределения вероятности лиц знаменитостей

GAN генерирует новое лицо знаменитости, генерируя новый вектор, следуя распределению вероятности лиц знаменитостей в векторном пространстве размерности N.

Проще говоря, GAN генерирует случайную переменную в соответствии с заданным распределением вероятности.

Как генерировать случайные переменные со сложными распределениями?

Распределение вероятности лиц знаменитостей в N-мерном векторном пространстве очень сложное, и мы не знаем, как напрямую генерировать сложные случайные переменные.

К счастью, мы можем представить нашу сложную случайную переменную в виде функции, примененной к равномерной случайной переменной. В этом заключается идея метода трансформации. Он сначала генерирует N независимых друг от друга равномерных случайных переменных, что просто. Затем она применяет е этой простой случайной переменной очень сложную функцию! Очень сложные функции естественно аппроксимируются нейронной сетью. После обучения нейронная сеть сможет принимать в качестве входа простую N-мерную равномерную случайную переменную и вернет другую N-мерную случайную переменную, имеющую наше распределение вероятности лиц знаменитостей. Это – основная идея, лежащая в основе генеративных состязательных сетей.

Почему “генеративные состязательные сети”?

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

Теоретически, мы могли бы использовать эти выборки для сравнения истинного распределения со сгенерированным распределением, используя подход максимального среднего расхождения (Maximum Mean Discrepancy, MMD). Он предоставил бы нам ошибку несоответствия распределения, которую можно было бы использовать для обновления весов методом обратного распространения ошибки (backpropagation). На практике этот прямой метод очень трудно реализовать.

Вместо прямого сравнения истинного и сгенерированного распределений, GANы решают не-дискриминационную задачу между истинной и сгенерированной выборками.

GAN имеет три основных компонента: модель генератора для генерации новых данных, модель дискриминатора для определения, являются ли сгенерированные данные реальными лицами, и состязательная сеть, которая сталкивает их друг против друга.

Генеративная часть отвечает за ввод N-мерных равномерно распределенных случайных чисел (шума) и генерацию ложных лиц. Генератор усваивает вероятность P(X), где X – это входные данные.

Дискриминационная часть – это простой классификатор, оценивающий и отделяющий сгенерированные лица от истинных лиц знаменитостей. Дискриминатор усваивает условную вероятность P(Y | X), где X – это входные данные, а Y – метка.

Генеративная состязательная сеть для лиц знаменитостей
Генеративная состязательная сеть для лиц знаменитостей

Обучение генеративных состязательных сетей

Генеративная сеть обучается с целью максимизации итоговой ошибки классификации (между истинными и сгенерированными данными), а дискриминационная сеть обучается с целью минимизации этой ошибки. Вот откуда происходит термин “состязательная сеть”.

С точки зрения теории игр, равновесие достигается, когда генератор создает изображения, соответствующие распределению лиц знаменитостей с той же вероятностью, с которой дискриминатор предсказывает, истинное изображение или ложное, как если бы он просто бросал монетку.

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

При обучении дискриминатора мы игнорируем потери генератора и используем только функцию потерь дискриминатора, которая штрафует дискриминатор за неверную классификацию сгенерированных лиц как истинных или истинных лиц как фейковых. Веса дискриминатора обновляются методом обратного распространения (backpropagation). Веса генератора не обновляются.

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

Это и есть магия, синтезирующая лица знаменитостей с помощью GAN. Сходимость часто выглядит мимолетной, а не стабильной. Если вы все сделали правильно, GANы выдают невероятные результаты, как показано ниже.

Приложение, синтезирующее изображения на основе GAN от Streamlit (<a href="https://towardsdatascience.com/build-an-app-to-synthesize-photorealistic-faces-using-tensorflow-and-streamlit-dd2545828021" target="_blank" rel="noopener noreferrer nofollow">источник</a>)
Приложение, синтезирующее изображения на основе GAN от Streamlit (источник)

Построение и обучение модели DCGAN

В этом разделе мы пройдем через все шаги, необходимые для создания, компиляции и обучения модели DCGAN (Deep Convolution GAN, то есть GAN с применением сверточных слоев).

Дискриминатор

Дискриминатором может быть любой классификатор изображений, даже дерево решений. Мы используем вместо него сверточную нейронную сеть с четырьмя блоками слоев. Каждый блок включает сверточный слой, слой нормализации пакета, еще один сверточный слой с шагом, чтобы уменьшить изображение в 2 раза, и еще один слой нормализации пакета. Результат проходит через группировку усреднения (average pooling), за которой следует полносвязный сигмоидный слой, возвращающий единственную выходную вероятность.

gan_discriminator.py
        from keras.layers import Conv2D, BatchNormalization, Input, GlobalAveragePooling2D, Dense
from keras.models import Model
from keras.layers.advanced_activations import LeakyReLU

# функция для создания слоев дискриминатора 
def build_discriminator(start_filters, spatial_dim, filter_size):
    
    # функция создания блока CNN block для уменьшения размера изображения
    def add_discriminator_block(x, filters, filter_size):
      x = Conv2D(filters, filter_size, padding='same')(x)
      x = BatchNormalization()(x)
      x = Conv2D(filters, filter_size, padding='same', strides=2)(x)
      x = BatchNormalization()(x)
      x = LeakyReLU(0.3)(x)
      return x
    
    # ввод - это изображение с размерами spatial_dim x spatial_dim и 3 каналами
    inp = Input(shape=(spatial_dim, spatial_dim, 3))

    # строим дискриминатор для уменьшения изображения в 4 раза
    x = add_discriminator_block(inp, start_filters, filter_size)
    x = add_discriminator_block(x, start_filters * 2, filter_size)
    x = add_discriminator_block(x, start_filters * 4, filter_size)
    x = add_discriminator_block(x, start_filters * 8, filter_size)
    
    # усреднение и возврат бинарного вывода
    x = GlobalAveragePooling2D()(x)
    x = Dense(1, activation='sigmoid')(x)
    
    return Model(inputs=inp, outputs=x)
    

Генератор

Генератор принимает вектор шума с размерностью скрытого пространства и генерирует изображение. Размеры этого изображения должны совпадать с размерами входа дискриминатора (spatial_dim * spatial_dim).

Сначала генератор размножает вектор шума с помощью полносвязного слоя, чтобы получить достаточно данных для преобразования в форму, необходимую для первого блока генератора. Цель этой проекции – получить такие же размеры, как в последнем блоке архитектуры дискриминатора. Как мы покажем ниже, это эквивалентно форме 4 * 4 * количество фильтров в последнем сверточном слое дискриминатора.

Каждый блок генератора применяет развертку (deconvolution) для увеличения изображения и нормализацию пакета. Мы используем 4 блока декодирования и финальный сверточный слой для получения 3-мерного тензора, представляющего фейковое изображение с 3 каналами.

gan_generator.py
        from keras.layers import Deconvolution2D, Reshape

def build_generator(start_filters, filter_size, latent_dim):
  
  # функция для создания блока CNN, увеличивающего размеры изображения
  def add_generator_block(x, filters, filter_size):
      x = Deconvolution2D(filters, filter_size, strides=2, padding='same')(x)
      x = BatchNormalization()(x)
      x = LeakyReLU(0.3)(x)
      return x

  # вход - это вектор шума 
  inp = Input(shape=(latent_dim,))

  # проекция вектора шума в тензор с такой же размерностью, 
  # как последний сверточный слой дискриминатора
  x = Dense(4 * 4 * (start_filters * 8), input_dim=latent_dim)(inp)
  x = BatchNormalization()(x)
  x = Reshape(target_shape=(4, 4, start_filters * 8))(x)

  # строим генератор для увеличения изображения в 4 раза
  x = add_generator_block(x, start_filters * 4, filter_size)
  x = add_generator_block(x, start_filters * 2, filter_size)
  x = add_generator_block(x, start_filters, filter_size)
  x = add_generator_block(x, start_filters, filter_size)    

  # превращаем вывод в трехмерный тензор, изображение с 3 каналами  
  x = Conv2D(3, kernel_size=5, padding='same', activation='tanh')(x)
  
  return Model(inputs=inp, outputs=x)
    

Собственно GAN

Объединенная DCGAN создается добавлением дискриминатора над генератором.

Перед компиляцией полной модели мы должны установить, что модель дискриминатора не обучается. Это заморозит ее веса и сообщит, что единственная обучаемая часть общей сети – это генератор.

Хотя мы и компилируем дискриминатор, нам не нужно компилировать модель генератора, поскольку мы не используем генератор сам по себе.

Этот порядок обеспечивает, что дискриминатор будет обновляться в нужное время, а в остальное время будет заморожен. Таким образом, если мы обучаем всю модель, она обновляет только генератор, а когда мы обучаем дискриминатор, обновляется только дискриминатор.

gan_full_model.py
        import pandas as pd
import os
from keras.optimizers import Adam

# загружаем атрибуты изображений знаменитостей 
df_celeb = pd.read_csv('list_attr_celeba.csv')
TOTAL_SAMPLES = df_celeb.shape[0]

# мы будем уменьшать изображения
SPATIAL_DIM = 64 
# размер вектора шума 
LATENT_DIM_GAN = 100 
# размер фильтра в сверточных слоях 
FILTER_SIZE = 5
# количество фильтров в сверточном слое 
NET_CAPACITY = 16
# размер пакета 
BATCH_SIZE_GAN = 32
# интервал для отображения сгенерированных изображений 
PROGRESS_INTERVAL = 80 
# директория для хранения сгенерированных изображений 
ROOT_DIR = 'visualization'
if not os.path.isdir(ROOT_DIR):
    os.mkdir(ROOT_DIR)
    
def construct_models(verbose=False):
    ### дискриминатор
    discriminator = build_discriminator(NET_CAPACITY, SPATIAL_DIM, FILTER_SIZE)
    # компилируем дискриминатор
    discriminator.compile(loss='binary_crossentropy', optimizer=Adam(lr=0.0002), metrics=['mae'])

    ### генератор
    # не компилируем генератор
    generator = build_generator(NET_CAPACITY, FILTER_SIZE, LATENT_DIM_GAN)

    ### DCGAN 
    gan = Sequential()
    gan.add(generator)
    gan.add(discriminator)
    discriminator.trainable = False 
    gan.compile(loss='binary_crossentropy', optimizer=Adam(lr=0.0002), metrics=['mae'])

    if verbose: 
        generator.summary()
        discriminator.summary()
        gan.summary()
        
    return generator, discriminator, gan
  
generator_celeb, discriminator_celeb, gan_celeb = construct_models(verbose=True)
    
Архитектура генератора
Архитектура генератора
Архитектура DCGAN
Архитектура DCGAN

Обучение GAN

Теперь мы приступаем к сложной и длительной части: обучению генеративной состязательной сети. Поскольку GAN состоит из двух раздельно обучаемых сетей, определить сходимость трудно.


Следующие шаги выполняются в прямом и обратном направлении, позволяя GAN справиться с проблемами генерации, которые иначе оказались бы неразрешимыми:

Шаг 1. Выбираем несколько реальных изображений из тренировочного набора

Шаг 2. Генерируем несколько фейковых изображений. Для этого мы создаем несколько случайных векторов шума и создаем из них изображения с помощью генератора.

Шаг 3. Обучаем дискриминатор на протяжении одной или большего количества эпох, используя как реальные, так и фейковые изображения. При этом будут обновляться только веса дискриминатора, поскольку мы пометим все реальные изображения как 1, а фейковые как 0.

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

Шаг 4. Создаем еще несколько фейковых изображений.

Шаг 5. Обучаем полную модель GAN на протяжении одной или большего количества эпох, используя только фейковые изображения. При этом будут обновляться только веса генератора, а всем фейковым изображениям будет назначена метка 1.

Схема обучения генератора. Веса дискриминатора не обновляются, изменяются только веса генератора. Генератор учится обманывать дискриминатор.
Схема обучения генератора. Веса дискриминатора не обновляются, изменяются только веса генератора. Генератор учится обманывать дискриминатор.
gan_training.py
        import cv2
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
from IPython.display import clear_output
 
# количество обновлений дискриминатора на каждую итерацию смены порядка обучения 
DISC_UPDATES = 1  
# количество обновлений генератора на каждую итерацию смены порядка обучения
GEN_UPDATES = 1 

# функция для обучения GAN
def run_training(generator, discriminator, gan, df=df_celeb, start_it=0, num_epochs=1000, 
                 get_real_images=get_real_celebrity):

  # вспомогательная функция для выбора 'size' реальных изображений 
  # и их сжатия до меньшего размера SPATIAL_DIM
  def get_real_celebrity(df, size, total):
      cur_files = df.sample(frac=1).iloc[0:size]
      X = np.empty(shape=(size, SPATIAL_DIM, SPATIAL_DIM, 3))
      for i in range(0, size):
          file = cur_files.iloc[i]
          img_uri = 'img_align_celeba/' + file.image_id
          img = cv2.imread(img_uri)
          img = cv2.resize(img, (SPATIAL_DIM, SPATIAL_DIM))
          img = np.flip(img, axis=2)
          img = img.astype(np.float32) / 127.5 - 1.0
          X[i] = img
      return X
  
  # список для хранения потерь 
  avg_loss_discriminator = []
  avg_loss_generator = []
  total_it = start_it

  # основной цикл обучения
  for epoch in range(num_epochs):

      # поочередный цикл обучения 
      loss_discriminator = []
      loss_generator = []
      for it in range(200): 

          #### Цикл обучения дискриминатора ####
          for i in range(DISC_UPDATES): 
              # выбираем случайный набор реальных изображений
              imgs_real = get_real_images(df, BATCH_SIZE_GAN, TOTAL_SAMPLES)
              # генерируем набор случайных векторов шума 
              noise = np.random.randn(BATCH_SIZE_GAN, LATENT_DIM_GAN)
              # генерируем набор фейковых изображений с помощью нашего генератора 
              imgs_fake = generator.predict(noise)
              # обучаем дискриминатор на реальных изображениях с меткой 1
              d_loss_real = discriminator.train_on_batch(imgs_real, np.ones([BATCH_SIZE_GAN]))[1]
              # обучаем дискриминатор на фейковых изображениях с меткой 0 
              d_loss_fake = discriminator.train_on_batch(imgs_fake, np.zeros([BATCH_SIZE_GAN]))[1]

          # выводим несколько фейковых изображений для визуального контроля сходимости
          if total_it % PROGRESS_INTERVAL == 0:
              plt.figure(figsize=(5,2))
              num_vis = min(BATCH_SIZE_GAN, 5)
              imgs_real = get_real_images(df, num_vis, TOTAL_SAMPLES)
              noise = np.random.randn(num_vis, LATENT_DIM_GAN)
              imgs_fake = generator.predict(noise)
              for obj_plot in [imgs_fake, imgs_real]:
                  plt.figure(figsize=(num_vis * 3, 3))
                  for b in range(num_vis):
                      disc_score = float(discriminator.predict(np.expand_dims(obj_plot[b], axis=0))[0])
                      plt.subplot(1, num_vis, b + 1)
                      plt.title(str(round(disc_score, 3)))
                      plt.imshow(obj_plot[b] * 0.5 + 0.5) 
                  if obj_plot is imgs_fake:
                      plt.savefig(os.path.join(ROOT_DIR, str(total_it).zfill(10) + '.jpg'), format='jpg', bbox_inches='tight')
                  plt.show()  

          #### Цикл обучения генератора ####
          loss = 0
          y = np.ones([BATCH_SIZE_GAN, 1]) 
          for j in range(GEN_UPDATES):
              # создаем набор случайных векторов шума 
              noise = np.random.randn(BATCH_SIZE_GAN, LATENT_DIM_GAN)
              # обучаем генератор на фейковых изображениях с меткой 1 
              loss += gan.train_on_batch(noise, y)[1]

          # сохраняем потери
          loss_discriminator.append((d_loss_real + d_loss_fake) / 2.)        
          loss_generator.append(loss / GEN_UPDATES)
          total_it += 1

      # визуализируем потери
      clear_output(True)
      print('Epoch', epoch)
      avg_loss_discriminator.append(np.mean(loss_discriminator))
      avg_loss_generator.append(np.mean(loss_generator))
      plt.plot(range(len(avg_loss_discriminator)), avg_loss_discriminator)
      plt.plot(range(len(avg_loss_generator)), avg_loss_generator)
      plt.legend(['discriminator loss', 'generator loss'])
      plt.show()

  return generator, discriminator, gan

generator_celeb, discriminator_celeb, gan_celeb = run_training(generator_celeb, 
                                                               discriminator_celeb, 
                                                               gan_celeb, 
                                                               num_epochs=500, 
                                                               df=df_celeb)
    
Фейковые лица, сгенерированные нашим генератором в процессе обучения GAN
Фейковые лица, сгенерированные нашим генератором в процессе обучения GAN

Как мы видим, наш генератор работает неплохо. Сгенерированные лица выглядят неплохо, хотя качество фото не такое хорошее, как в наборе данных CelebA. Это произошло потому, что мы обучили наш GAN на уменьшенных изображениях 64 * 64, которые гораздо более размыты, чем исходные изображения 218 * 178.

Разница между VAE и GAN

По сравнению с лицами, сгенерированными Вариационным АвтоЭнкодером из нашей прошлой статьи, лица, сгенерированные DCGAN, выглядят достаточно яркими, чтобы представлять лица, близкие к реальности.

Фейковые лица, сгенерированные Вариационным АвтоЭнкодером в процессе обучения
Фейковые лица, сгенерированные Вариационным АвтоЭнкодером в процессе обучения

GAN’ы, как правило, намного лучшие глубокие генеративные модели, чем VAE. Хотя VAE работают только в скрытом пространстве, их легче создавать и проще обучать. Можно считать, что VAE обучаются с частичным привлечением учителя (semi-supervised learning), поскольку они обучаются минимизировать потери при воспроизведении конкретных изображений. С другой стороны, GAN’ы – это уже задача обучения без учителя.

Заключение

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

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

Вы можете больше узнать о GANах на Google Developers или из статьи Джозефа Рокка. Вариационные автоэнкодеры были рассмотрены в моей прошлой статье.

12
Июл
2021

🛠 Сложноструктурные аналитические отчеты с Python и LaTeX

В руководстве подробно рассматривается пример использования Python-библиотеки облачного представления приложений Streamlit и системы компьютерной вёрстки LaTeX для подготовки сложных аналитических отчетов с математическими, программными и графическими вставками.

Экосистема LaTeX. Быстрый старт

  • TeX (произносится как «тех») – система компьютерной верстки, предназначенная для подготовки научно-технических материалов высокого полиграфического качества.
  • LaTeX (произносится «латех») – это, строго говоря, набор макросов на языке разметки TeX, но в зависимости от контекста под LaTeX может пониматься макропакет, издательская система или язык, служащий для разметки документа. LaTeX 2e – наиболее полная, стабильная версия LaTeX.
  • MikTеX – свободно распространяемая реализация TeX под основные операционные системы – Windows, macOS, Linux (Ubuntu, Debian, CentOS и пр.) – включающая в себя практически все наиболее значимые расширения.

Установить реализацию MikTеX под нужную операционную систему можно по инструкциям на странице проекта. При желании с системой можно взаимодействовать и без установки дистрибутива, просто запустив Docker-образ:

miktex_install.sh
        $ docker pull miktex/miktex
$ docker volume create --name miktex
$ docker run -it \
  -v miktex:/miktex/.miktex \
  -v $(pwd):/miktex/work \
  miktex/miktex \
  pdflatex main.tex
    

Здесь с помощью команды docker pull в локальное хранилище образов скачивается Docker-образ miktex/miktex. Затем командой docker volume в файловой системе хоста создается директория miktex/. Последним шагом с помощью команды docker run остается запустить контейнер Docker на базе образа miktex/miktex. Флаг -it создает сеанс интерактивной работы на подключаемом терминальном устройстве, а флаг -v отображает директорию файловой системы хоста на директорию внутри контейнера.

Контейнер ожидает получить аргументы командной строки указывающие на выбранный компилятор (в данном случае PDFLaTeX) и собственно tex-файл (размеченный документ, на основании которого позже будет создан pdf-файл).

В качестве альтернативы MikTEX можно использовать TeX Live – это еще один свободно распространяемый и наиболее полный дистрибутив TeX. Для операционной системы MacOS X можно пользоваться специализированным решением MacTeX.

Опорный документ LaTeX (tex-файл) представляет собой обычный текстовый файл с разметкой. Для редактирования такого рода файлов можно пользоваться и обычным текстовым Unix-редактором Vim, но практичнее использовать специальные решения, например, открытую среду разработки TeXstudio (поддерживает все основные операционные системы). Однако TeXstudio не единственный вариант. Вот наиболее распространенные альтернативы: TeXmaker, Kile, TeXCenter.

LaTeX состоит из пакетов, получить доступ к которым можно на странице CTAN (The Comprehensive TeX Archive Network). CTAN – центральный репозиторий, в который стекаются все сколько-нибудь стоящие наработки, имеющие отношение к TeX.

Каждый пакет репозитория содержит документацию (с описанием зависимостей, примерами и контекстом использования, деталями реализации и пр.), исходные файлы, описание синтаксических особенностей, макродемонстрацию и другие компоненты, позволяющие быстро понять устройство пакета и порядок работы с ним. С общей структурой пакетов CTAN можно познакомиться на примере пакета для оформления программного кода listings.

Итак, для запуска примеров из настоящего руководства потребуется установить дистрибутив TeX (например, MikTеX) и LaTeX-редактор (например, TeXstudio).

Введение в язык разметки LaTeX

В текстовых процессорах, которые позволяют в момент набора текста видеть его на экране дисплея точно таким, как он будет выглядеть на бумаге, используется концепция визуального проектирования (WYSIWYG – What You See Is What You Get). В LaTeX же используется концепция логического проектирования, когда внешний вид документа становится понятен только после компиляции.

Внешний вид документа определяется инструкциями, описанными на языке разметки TeX или LaTeX. Между этими языками сложно провести четкую границу. Сам LaTeX написан в командах TeX и в LaTeX-документе можно использовать практические любые TeX-команды. Упрощенно можно считать, что язык разметки LaTeX это высокоуровневая «синтаксически-сахарная» обертка для низкоуровневого языка TeX. Таким образом, TeX в основном применяется при разработке классов и пакетов, в то время как LaTeX – для подготовки печатного документа.

Теперь рассмотрим общий синтаксис языка LaTeX и познакомимся с базовой структурой tex-документа.

  • LaTeX-файл должен начинаться с команды \documentclass, задающей стиль оформления документа, например, \documentclass{article}. Аргумент команды article означает, что документ будет оформлен в соответствии с наиболее общими правилами оформления статей. При желании можно изменить (с незначительными оговорками) любой элемент макета документа.
  • Команда \documentclass поддерживает и другие классы, доступные «из коробки»: book (для оформления книг), report (для оформления отчетов – нечто среднее между book и article), proc (для оформления трудов конференций) и letter (для деловых писем со сложной структурой).
  • После команды \documentclass могут следовать команды, относящиеся ко всему документу. Далее с помощью окружения\begin{document}\end{document} (условимся называть его документарным окружением) указывается тело документа. В общем случае окружением называют сложные конструкции вида \begin{}\end{}.
  • Часть tex-файла между командой \documentclass и \begin{document}\end{document} называют преамбулой. Команды указанные после закрывающей скобки окружения документа \end{document} LaTeX проигнорирует.

В итоге наипростейший шаблон документа будет выглядеть так:

base_example.tex
        \documentclass{article}
% область преамбулы
\begin{document} % тело документа: начало
% текст
\end{document} % тело документа: конец
% команды в этой части документа не будут учитываться при сборке документа
    

Инструкции, управляющие макетом страницы и прочие настройки tex-документа, могут быть размещены и в преамбуле, но когда инструкций становится много, будет удобнее вынести их в отдельный стилевой файл с расширением *.sty. Позже стилевой файл можно будет подключить командой \usepackage{}, принимающей в качестве аргумента путь до этого файла.

Сам стилевой файл содержит импорты пакетов \RequirePackage{}, пользовательские команды \newcommand{}, псевдонимы математических операторов \DeclareMathOperator и прочие элементы кастомизации:

style_template.sty
        % начало стилевого файла
\RequirePackage[english,russian]{babel}
\RequirePackage[utf8]{inputenc}
\RequirePackage{amsmath, amsfonts, amssymb, latexsym}
\RequirePackage[
	left=2cm,
	right=2cm,
	top=2cm,
	bottom=2cm
		]{geometry}
... 
\newcommand{\str}[1]{cтр.~\pageref{#1}}
\newcommand{\strbook}[1]{стр.~{#1}}
...
\DeclareMathOperator*{\argmin}{arg\,min}
\DeclareMathOperator*{\argmax}{arg\,max}
\DeclareMathOperator*{\sign}{sign}
\DeclareMathOperator*{\const}{const}
...
    

С подключенным стилевым файлом tex-документ будет выглядеть так:

base_example_with_usepackage.tex
        \documentclass{article}
\usepackage{style_template} % подключаем стилевой файл style_template.sty, расположенный в той же директории, что и tex-файл
\begin{document}
% текст
\end{document}
    

Аргумент команды \usepackage может включать не только имя стилевого файла, но и путь до него относительно корня проекта (без указания расширения файла).

Далее предполагается, что все настройки макета документа описаны в стилевом файле style_template.sty, который расположен в той же директории, что и tex-файл.

К сожалению, в настоящем руководстве нет возможности рассмотреть все элементы и тонкости подготовки LaTeX-файлов, но в github-репозитории доступен полный код рассматриваемого примера с пояснениями, включая опорный стилевой файл, адаптированный для работы с кириллицей и содержащий декоративные настройки окружений, которые могут пригодиться при подготовке сложноструктурных аналитических отчетов.

Разобравшись с базовыми структурными элементами tex-файла, можно сосредоточиться на содержательной части и перейти к наполнению документа.

Наберем в документарном окружении следующие строки:

simple_onepage_template.tex
        ...
\begin{document}

\title{Аналитический отчет по ...} % заголовок отчета
\author{\itshape Иванов И.И.} % автор работы
\date{} % просим LaTeX не указывать дату, так как будет
        % использован наш вариант оформления даты, описанный в стилевом файле
\maketitle % создает заголовок

\thispagestyle{fancy} % задает стиль страницы

В этой части можно разместить аннотацию к отчету. \TeX -- это издательская система компьютерной верстки, предназначенная для набора ...

\tableofcontents % создает оглавление

\section{Пример многострочной формулы}
    Для набора сложных многострочных формул используются различные окружения, например, окружение \texttt{multline}
	\begin{multline}
		F_{\zeta}(z)=P[\,\zeta\leqslant z\,] = \int\!\!\!\int_{x/y\leqslant z}f_X(x;n)f_Y(y;m)\,dxdy =\\ \dfrac{1}{2^{(n+m)/2}\Gamma(n/2)\Gamma(m/2)}\int\!\!\!\int_{x/y\leqslant z}x^{n/2-1}y^{m/2-1}\exp\left( -\frac{x}{2} \right) \exp\left( -\frac{y}{2} \right) \,\mathrm{d}x \, \mathrm{d}y.
	\end{multline}

\section{Пример группового размещения формул}

Несколько формул можно разместить в одной группе с помощью окружения \texttt{gather}
\begin{gather}
	\sum_{j \in \mathbf{N}} b_{ij} \hat{y}_{j} = \sum_{j \in \mathbf{N}} b_{ij}^\lambda \hat{y}_j + (b_{ii} - \lambda_i)\hat{y}_i \hat{y},\notag \\
	\det \mathbf{K}(t=1, t_1, \ldots, t_n) = \sum_{I \in \mathbf{n} } (-1)^{|I|} \prod_{i \in I} t_i \prod_{j \in I} (D_j + \lambda_j t_j) \det \mathbf{A}^{(\lambda)} (\, \overline{I} | \overline{I} \,) = 0,\tag{$a$} \\
	\mathbb{F} = \sum_{i=1}^{\left[ \frac{n}{2}\right] } \binom{ x_{i,i+1}^{i^2}}{ \left[ \frac{i+3}{3} \right]} {{\sqrt{\mu(i)^\frac{3}{2} (i^2-1)}} \over\displaystyle {\sqrt[3]{\rho(i)-2} + \sqrt[3]{\rho(i)-1}} }, \tag{$b$}
\end{gather}

\section{Простая однострочная формула}

Теорема Хинчина-Винера утверждает, что спектральная плотность мощности стационарного в широком смысле случайного процесса представляет собой преобразование Фурье от соответствующей автокорреляционной функции
\begin{equation*} % без нумерации
    S_{xx}(f) = \int\limits_{-\infty}^{\infty}  \, r_{xx} (\tau) e^{-j 2 \pi f \tau} \mathrm{d} \tau,\ \text{где}\ r_{xx}(\tau) = \mathbb{E}[\,x(t) \, x^{*}(t - \tau)\,].
\end{equation*}

\end{document}
    

Теперь можно вызвать компилятор PDFLaTeX через командную оболочку и передать ему имя tex-файла. Результат компиляции приведен на рисунке ниже.

Результат компиляции файла <code class="inline-code">analyt_report_template.tex</code>
Результат компиляции файла analyt_report_template.tex

Рассмотрим более подробно код файла analyt_report_template.tex.

  • В первых строках файла с помощью команд \title и \author мы объявляем заголовок отчета и имя автора работы соответственно, а с помощью команды \maketitleсоздаем заголовок.
  • Затем с помощью команды \date, вызванной без аргументов, подавляем вывод временной метки. Здесь для привязки ко времени будет использоваться специальная низкоуровневая командная вставка в стилевом файле style_template.sty (этот фрагмент кода приводится только для справки, так как конечному пользователю приложения нет необходимости вносить в стилевой файл изменения напрямую):
fragment_style_template.sty
        ... 
\def\@maketitle{
    \begin{flushright}
	\footnotesize\itshape
	Дата последней сборки документа:\\ \today\ в \currenttime
    \end{flushright}

    \begin{center}
	\let \footnote \thanks
	\begin{spacing}{1.5}
	    {\Large\bfseries\@title}
	\end{spacing}\vskip 1mm

	{\normalsize
	    \begin{tabular}[t]{l}
		\@author
	    \end{tabular}\par	
	}
    \end{center}
    \par
    \vskip 1.5em
}
...
    

Команда \thispagestyle задает стиль страницы, а команда \tableofcontents создает оглавление документа. С помощью команды \section создаются разделы документа высшего уровня (с учетом класса документа). Для того чтобы создать раздел более низкого уровня следующей ступени можно воспользоваться командой \subsection.

LaTeX обладает широким набором окружений для оформления математических конструкций произвольной сложности, однако здесь мы ограничимся рассмотрением только трех типов окружения: equation, multline и gather.

Как должно быть понятно из приведенного выше рисунка, equation используется для однострочных формул, multline – для многострочных, а gather – для группового размещения формул. Звездочка после имени окружения означает, что LaTeX не станет присваивать номера формулам, попавшим в это окружение.

При наборе формул используются специальные LaTeX-команды с названиями созвучными набираемому элементу, например, для того чтобы добавить в формулу знак суммы с нижним lowindex и верхним upindex индексом используется команда \sum_{lowindex}^{upindex}, чтобы вставить символ большой омеги – \Omega, а для вставки символа гамма потребуется \gamma и т.д.

Для быстрого поиска нужных математических LaTeX-команд, специальных символов, приемов оформления псевдокода и пр. удобно пользоваться компактным, но очень содержательным сборником Константина Воронцова «LaTeX 2e в примерах».

Прочие детали работы с издательской системой LaTeX можно выяснить из следующих работ:

Введение в Python-библиотеку Streamlit

Библиотека Streamlit – это простая, лаконичная и в тоже время очень мощная библиотека для прототипирования браузерных решений с графическим интерфейсом. Streamlit включает поддержку всех основных элементов стека, ориентированных на компьютерное зрение, машинное и глубокое обучение.

Установить библиотеку проще всего с помощью менеджера пакетов pip: pip install streamlit.

Запускается приложение командой streamlit run:

streamlit_run.sh
        $ streamlit run streamlit_simple_example.py

  You can now view your Streamlit app in your browser.

  Local URL: http://localhost:8502 # <-- 
  Network URL: http://192.168.1.247:8502
    

После запуска сценария в браузере (http://localhost:8502) откроется вкладка с приложением. Завершить работу приложения можно, закрыв вкладку браузера и набрав Ctrl+C в командной оболочке.

В Streamlit реализован сравнительно небольшой набор «выразительных средств», но все элементы продуманы и покрывают значительную часть требований к «гибкому динамическому прототипу».

Начать работу со Streamlit можно с вводного руководства, которое подробно описывает все возможности библиотеки, включая Markdown-разметку, аудио и видео объекты, различные графические объекты (Bokeh, Altair, Plotly и др.), а также оптимизацию загрузки объемных наборов данных.

Ниже приводится пример использования библиотеки Streamlit для построения двух интерактивных графиков (на базе библиотеки Plotly) гауссовских процессов с автокорреляционной функцией экспоненциального типа.

streamlit_simple_example.py
        import streamlit as st
import math
import pandas as pd
from pandas import Series
import plotly.graph_objects as go
import numpy as np
import numpy.random as rnd

title_app = "Простой пример использования библиотеки Streamlit"
# чтобы на вкладке браузера отображалось имя приложения, а не имя файла
st.set_page_config(
    layout="wide",
    page_title=title_app,
    initial_sidebar_state="expanded",
)


def gauss_with_exp_acf_gen(
    *,
    sigma: float = 2,
    w_star: float = 1.25,
    delta_t: float = 0.05,
    N: int = 1000,
) -> np.array:
    """
    Описание
    --------
    Генерирует дискретную реализацию
    стационарного гауссовского ПСП
    с КФ экспоненциального типа

    Параметры
    ---------
    sigma : стандартное отклонение ординат ПСП.
    w_star : параметр модели ПСП.
    delta_t : шаг по времени.
    N : число отсчетов ПСП.

    Возвращает
    ----------
    xi : массив элементов ПСП с заданной КФ
    """
    gamma_star = w_star * delta_t
    rho = math.exp(-gamma_star)
    b1 = rho
    a0 = sigma * math.sqrt(1 - rho ** 2)

    xi = np.zeros(N)
    xi[0] = rnd.rand()
    x = rnd.randn(N)

    for n in range(1, N):
        xi[n] = a0 * x[n] + b1 * xi[n - 1]

    return xi


def main(N: int = 100):
    timestmp = np.arange(N)
    # временной ряд №1
    time_series_1 = gauss_with_exp_acf_gen(sigma=5, w_star=1.25, N=N)
    # временной ряд №2
    time_series_2 = gauss_with_exp_acf_gen(sigma=6.5, w_star=1.75, N=N)

    fig = go.Figure()

    fig.add_trace(
        go.Scatter(
            x=timestmp,
            y=time_series_1,
            name="Временной ряд (объект-1)",
            opacity=0.8,
            mode="lines",
            line=dict(
                color="#E84A5F",
            ),
        )
    )

    fig.add_trace(
        go.Scatter(
            x=timestmp,
            y=Series(time_series_1).rolling(window=7).mean(),
            name="Скользящее среднее (объект-1)",
            mode="lines",
            opacity=0.6,
            line=dict(
                color="#FF847C",
            ),
        )
    )

    fig.add_trace(
        go.Scatter(
            x=timestmp,
            y=time_series_2,
            name="Временной ряд (объект-2)",
            mode="lines",
            opacity=0.8,
            line=dict(
                color="#5E63B6",
            ),
        )
    )

    fig.add_trace(
        go.Scatter(
            x=timestmp,
            y=Series(time_series_2).rolling(window=7).mean(),
            name="Скользящее среднее (объект-2)",
            mode="lines",
            opacity=0.6,
            line=dict(
                color="#6EB6FF",
            ),
        )
    )

    fig.update_layout(
        title=dict(
            # text="<i>Временной ряд</i>",
            font=dict(
                family="Arial",
                size=18,
                color="#07689F",
            ),
        ),
        xaxis_title=dict(
            text="<i>Временная метка</i>",
            font=dict(
                family="Arial",
                size=13,
                color="#537791",
            ),
        ),
        yaxis_title=dict(
            text="<i>Продолжительность простоя, час</i>",
            font=dict(
                family="Arial",
                size=13,
                color="#537791",
            ),
        ),
        xaxis=dict(
            showline=True,
        ),
        yaxis=dict(
            showline=True,
        ),
        autosize=False,
        showlegend=True,
        margin=dict(
            autoexpand=False,
            l=70,
            r=10,
            t=50,
        ),
        legend=dict(
            orientation="v",
            yanchor="bottom",
            y=0.01,
            xanchor="right",
            x=0.99,
            font=dict(family="Arial", size=12, color="black"),
        ),
        plot_bgcolor="white",
    )

    st.plotly_chart(fig, use_container_width=True)


if __name__ == "__main__":
    main(N=350)
    

В этом примере к библиотеке Streamlit имеет отношение только:

  • функция st.set_page_config(), которая переопределяет имя вкладки браузера – отображается не имя файла, а имя приложения;
  • функция st.plotly_chart(), которая принимает сконфигурированный Plotly-объект и выводит его в окно браузера.
Результат работы сценария <code class="inline-code">streamlit_simple_example.py</code>
Результат работы сценария streamlit_simple_example.py

Прочие элементы сценария streamlit_simple_example.py играют лишь вспомогательную роль.

Пример-шаблон аналитического отчета

Предлагается в качестве примера, сочетающего приемы работы с библиотекой Streamlit (браузерный интерфейс приложения) и LaTeX-разметку (опорный tex-файл), рассмотреть подготовку отчета на тему «Оценка усталостной долговечности силовых элементов транспортных машин под воздействием стационарных гауссовских процессов с автокорреляционной функцией экспоненциально-косинусного семейства».

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

Подробности реализации обсуждаемого решения можно узнать из github-репозитория, сейчас же кратко остановимся на нескольких нюансах.

Часто возникает необходимость выгрузить подготовленный с помощью Streamlit файл результатов (например, табличных объект Pandas), но сам Streamlit не предлагает никаких решений. Тем не менее это ограничение можно обойти с помощью следующей функции:

downloader_for_streamlit.py
        def text_downloader(multiline: str) -> NoReturn:
    """
    Принимает LaTeX-шаблон документа в виде многострочной строки и
    создает на странице ссылку для скачивания шаблона
    """
    OUTPUT_TEX_FILENAME = "base_template_for_latex.tex"
    
    b64 = base64.b64encode(multiline.encode()).decode()
    # создает ссылку для скачивания файла
    href = (f'<a href="data:file/txt;base64,{b64}" '
            f'download="{OUTPUT_TEX_FILENAME}">Скачать ...</a>')
    st.markdown(href, unsafe_allow_html=True)
    

Функция читает текстовый файл, переданный в виде строки, кодирует его с помощью стандарта base64 и передает тег-ссылку методу markdown. В итоге файл можно будет скачать, кликнув на созданную ссылку.

При наборе текстового шаблона для Python (latex_template_for_python.txt) – по сути файл представляет собой каркас документа с заглушками под строковую интерполяцию – важно помнить о синтаксических особенностях LaTeX. Дело в том, что в контексте строковой интерполяции фигурные скобки означают «место подстановки», а в контексте LaTeX – обязательный аргумент команды. То есть, чтобы Python корректно «прочитал» строку следует фигурные скобки, относящиеся к синтаксису LaTeX, удвоить.

В результате получится текстовый файл вида:

fragment_latex_template_for_python.txt
        \documentclass[
    11pt,
    a4paper,
    utf8,
]{{article}}

\usepackage{{style_template}}

\begin{{document}}
...
Усталостная долговечность по модели \eqref{{eq:miles}} составляет $ Y_{{NB}} = {Y_NB:.2f} $, сек.

\section{{Оценка усталостной долговечности по модели P.H. Wirsching и C.L.~Light}}
...
    

Ниже на рисунках приводится общий вид приложения.

Стартовая страница приложения
Стартовая страница приложения

Скачав подготовленный tex-файл в директорию проекта, останется только запустить компилятор (дважды!).

pdflatex_start.sh
        # для сборки каркаса
$ pdflatex base_template_for_latex.tex
# для вычисления конечных ссылок на страницы, формулы и пр.
$ pdflatex base_template_for_latex.tex

    

После сборки документа в рабочей директории проекта будет создан pdf-файл.

Выгрузка подготовленного LaTeX-шаблона
Выгрузка подготовленного LaTeX-шаблона
Результат работы <code class="inline-code">pdflatex base_template_for_latex.tex</code>. Фрагмент собранного аналитического отчета
Результат работы pdflatex base_template_for_latex.tex. Фрагмент собранного аналитического отчета

Чтобы развернуть приложение на свободной облачной платформе Streamlit, достаточно кликнуть на Deploy this app в правой верхней части панели запущенного приложения, как изображено на рисунке. Однако предварительно необходимо зарегистрироваться на Streamlit и отправить заявку на допуск к ресурсам (обычно обработка заявки занимает несколько дней).

Развертывание приложения на облачной платформе Streamlit
Развертывание приложения на облачной платформе Streamlit

После успешного развертывания на платформе приложение будет доступно конечному пользователю по ссылке, как в данном случае.

Заключение

Из руководства вы узнали:

  • что собой представляет система компьютерной вёрстки LaTeX, где найти ее дистрибутивы и пакеты, как правильно читать документацию, как начать работать с системой;
  • как разрабатывать гибкие, масштабируемые шаблоны документов с помощью языка разметки TeX/LaTeX;
  • как использовать приемы разработки приложений с помощью Python-библиотеки Streamlit;
  • как может выглядеть пример связки «LaTeX + Streamlit»;
  • и, наконец, как развернуть приложение на облачной платформе Streamlit.

Полезные источники:

Связные материалы с платформы Proglib:

12
Июл
2021

🛠 Сложноструктурные аналитические отчеты с Python и LaTeX

В руководстве подробно рассматривается пример использования Python-библиотеки облачного представления приложений Streamlit и системы компьютерной вёрстки LaTeX для подготовки сложных аналитических отчетов с математическими, программными и графическими вставками.

Экосистема LaTeX. Быстрый старт

  • TeX (произносится как «тех») – система компьютерной верстки, предназначенная для подготовки научно-технических материалов высокого полиграфического качества.
  • LaTeX (произносится «латех») – это, строго говоря, набор макросов на языке разметки TeX, но в зависимости от контекста под LaTeX может пониматься макропакет, издательская система или язык, служащий для разметки документа. LaTeX 2e – наиболее полная, стабильная версия LaTeX.
  • MikTеX – свободно распространяемая реализация TeX под основные операционные системы – Windows, macOS, Linux (Ubuntu, Debian, CentOS и пр.) – включающая в себя практически все наиболее значимые расширения.

Установить реализацию MikTеX под нужную операционную систему можно по инструкциям на странице проекта. При желании с системой можно взаимодействовать и без установки дистрибутива, просто запустив Docker-образ:

miktex_install.sh
        $ docker pull miktex/miktex
$ docker volume create --name miktex
$ docker run -it \
  -v miktex:/miktex/.miktex \
  -v $(pwd):/miktex/work \
  miktex/miktex \
  pdflatex main.tex
    

Здесь с помощью команды docker pull в локальное хранилище образов скачивается Docker-образ miktex/miktex. Затем командой docker volume в файловой системе хоста создается директория miktex/. Последним шагом с помощью команды docker run остается запустить контейнер Docker на базе образа miktex/miktex. Флаг -it создает сеанс интерактивной работы на подключаемом терминальном устройстве, а флаг -v отображает директорию файловой системы хоста на директорию внутри контейнера.

Контейнер ожидает получить аргументы командной строки указывающие на выбранный компилятор (в данном случае PDFLaTeX) и собственно tex-файл (размеченный документ, на основании которого позже будет создан pdf-файл).

В качестве альтернативы MikTEX можно использовать TeX Live – это еще один свободно распространяемый и наиболее полный дистрибутив TeX. Для операционной системы MacOS X можно пользоваться специализированным решением MacTeX.

Опорный документ LaTeX (tex-файл) представляет собой обычный текстовый файл с разметкой. Для редактирования такого рода файлов можно пользоваться и обычным текстовым Unix-редактором Vim, но практичнее использовать специальные решения, например, открытую среду разработки TeXstudio (поддерживает все основные операционные системы). Однако TeXstudio не единственный вариант. Вот наиболее распространенные альтернативы: TeXmaker, Kile, TeXCenter.

LaTeX состоит из пакетов, получить доступ к которым можно на странице CTAN (The Comprehensive TeX Archive Network). CTAN – центральный репозиторий, в который стекаются все сколько-нибудь стоящие наработки, имеющие отношение к TeX.

Каждый пакет репозитория содержит документацию (с описанием зависимостей, примерами и контекстом использования, деталями реализации и пр.), исходные файлы, описание синтаксических особенностей, макродемонстрацию и другие компоненты, позволяющие быстро понять устройство пакета и порядок работы с ним. С общей структурой пакетов CTAN можно познакомиться на примере пакета для оформления программного кода listings.

Итак, для запуска примеров из настоящего руководства потребуется установить дистрибутив TeX (например, MikTеX) и LaTeX-редактор (например, TeXstudio).

Введение в язык разметки LaTeX

В текстовых процессорах, которые позволяют в момент набора текста видеть его на экране дисплея точно таким, как он будет выглядеть на бумаге, используется концепция визуального проектирования (WYSIWYG – What You See Is What You Get). В LaTeX же используется концепция логического проектирования, когда внешний вид документа становится понятен только после компиляции.

Внешний вид документа определяется инструкциями, описанными на языке разметки TeX или LaTeX. Между этими языками сложно провести четкую границу. Сам LaTeX написан в командах TeX и в LaTeX-документе можно использовать практические любые TeX-команды. Упрощенно можно считать, что язык разметки LaTeX это высокоуровневая «синтаксически-сахарная» обертка для низкоуровневого языка TeX. Таким образом, TeX в основном применяется при разработке классов и пакетов, в то время как LaTeX – для подготовки печатного документа.

Теперь рассмотрим общий синтаксис языка LaTeX и познакомимся с базовой структурой tex-документа.

  • LaTeX-файл должен начинаться с команды \documentclass, задающей стиль оформления документа, например, \documentclass{article}. Аргумент команды article означает, что документ будет оформлен в соответствии с наиболее общими правилами оформления статей. При желании можно изменить (с незначительными оговорками) любой элемент макета документа.
  • Команда \documentclass поддерживает и другие классы, доступные «из коробки»: book (для оформления книг), report (для оформления отчетов – нечто среднее между book и article), proc (для оформления трудов конференций) и letter (для деловых писем со сложной структурой).
  • После команды \documentclass могут следовать команды, относящиеся ко всему документу. Далее с помощью окружения\begin{document}\end{document} (условимся называть его документарным окружением) указывается тело документа. В общем случае окружением называют сложные конструкции вида \begin{}\end{}.
  • Часть tex-файла между командой \documentclass и \begin{document}\end{document} называют преамбулой. Команды указанные после закрывающей скобки окружения документа \end{document} LaTeX проигнорирует.

В итоге наипростейший шаблон документа будет выглядеть так:

base_example.tex
        \documentclass{article}
% область преамбулы
\begin{document} % тело документа: начало
% текст
\end{document} % тело документа: конец
% команды в этой части документа не будут учитываться при сборке документа
    

Инструкции, управляющие макетом страницы и прочие настройки tex-документа, могут быть размещены и в преамбуле, но когда инструкций становится много, будет удобнее вынести их в отдельный стилевой файл с расширением *.sty. Позже стилевой файл можно будет подключить командой \usepackage{}, принимающей в качестве аргумента путь до этого файла.

Сам стилевой файл содержит импорты пакетов \RequirePackage{}, пользовательские команды \newcommand{}, псевдонимы математических операторов \DeclareMathOperator и прочие элементы кастомизации:

style_template.sty
        % начало стилевого файла
\RequirePackage[english,russian]{babel}
\RequirePackage[utf8]{inputenc}
\RequirePackage{amsmath, amsfonts, amssymb, latexsym}
\RequirePackage[
	left=2cm,
	right=2cm,
	top=2cm,
	bottom=2cm
		]{geometry}
... 
\newcommand{\str}[1]{cтр.~\pageref{#1}}
\newcommand{\strbook}[1]{стр.~{#1}}
...
\DeclareMathOperator*{\argmin}{arg\,min}
\DeclareMathOperator*{\argmax}{arg\,max}
\DeclareMathOperator*{\sign}{sign}
\DeclareMathOperator*{\const}{const}
...
    

С подключенным стилевым файлом tex-документ будет выглядеть так:

base_example_with_usepackage.tex
        \documentclass{article}
\usepackage{style_template} % подключаем стилевой файл style_template.sty, расположенный в той же директории, что и tex-файл
\begin{document}
% текст
\end{document}
    

Аргумент команды \usepackage может включать не только имя стилевого файла, но и путь до него относительно корня проекта (без указания расширения файла).

Далее предполагается, что все настройки макета документа описаны в стилевом файле style_template.sty, который расположен в той же директории, что и tex-файл.

К сожалению, в настоящем руководстве нет возможности рассмотреть все элементы и тонкости подготовки LaTeX-файлов, но в github-репозитории доступен полный код рассматриваемого примера с пояснениями, включая опорный стилевой файл, адаптированный для работы с кириллицей и содержащий декоративные настройки окружений, которые могут пригодиться при подготовке сложноструктурных аналитических отчетов.

Разобравшись с базовыми структурными элементами tex-файла, можно сосредоточиться на содержательной части и перейти к наполнению документа.

Наберем в документарном окружении следующие строки:

simple_onepage_template.tex
        ...
\begin{document}

\title{Аналитический отчет по ...} % заголовок отчета
\author{\itshape Иванов И.И.} % автор работы
\date{} % просим LaTeX не указывать дату, так как будет
        % использован наш вариант оформления даты, описанный в стилевом файле
\maketitle % создает заголовок

\thispagestyle{fancy} % задает стиль страницы

В этой части можно разместить аннотацию к отчету. \TeX -- это издательская система компьютерной верстки, предназначенная для набора ...

\tableofcontents % создает оглавление

\section{Пример многострочной формулы}
    Для набора сложных многострочных формул используются различные окружения, например, окружение \texttt{multline}
	\begin{multline}
		F_{\zeta}(z)=P[\,\zeta\leqslant z\,] = \int\!\!\!\int_{x/y\leqslant z}f_X(x;n)f_Y(y;m)\,dxdy =\\ \dfrac{1}{2^{(n+m)/2}\Gamma(n/2)\Gamma(m/2)}\int\!\!\!\int_{x/y\leqslant z}x^{n/2-1}y^{m/2-1}\exp\left( -\frac{x}{2} \right) \exp\left( -\frac{y}{2} \right) \,\mathrm{d}x \, \mathrm{d}y.
	\end{multline}

\section{Пример группового размещения формул}

Несколько формул можно разместить в одной группе с помощью окружения \texttt{gather}
\begin{gather}
	\sum_{j \in \mathbf{N}} b_{ij} \hat{y}_{j} = \sum_{j \in \mathbf{N}} b_{ij}^\lambda \hat{y}_j + (b_{ii} - \lambda_i)\hat{y}_i \hat{y},\notag \\
	\det \mathbf{K}(t=1, t_1, \ldots, t_n) = \sum_{I \in \mathbf{n} } (-1)^{|I|} \prod_{i \in I} t_i \prod_{j \in I} (D_j + \lambda_j t_j) \det \mathbf{A}^{(\lambda)} (\, \overline{I} | \overline{I} \,) = 0,\tag{$a$} \\
	\mathbb{F} = \sum_{i=1}^{\left[ \frac{n}{2}\right] } \binom{ x_{i,i+1}^{i^2}}{ \left[ \frac{i+3}{3} \right]} {{\sqrt{\mu(i)^\frac{3}{2} (i^2-1)}} \over\displaystyle {\sqrt[3]{\rho(i)-2} + \sqrt[3]{\rho(i)-1}} }, \tag{$b$}
\end{gather}

\section{Простая однострочная формула}

Теорема Хинчина-Винера утверждает, что спектральная плотность мощности стационарного в широком смысле случайного процесса представляет собой преобразование Фурье от соответствующей автокорреляционной функции
\begin{equation*} % без нумерации
    S_{xx}(f) = \int\limits_{-\infty}^{\infty}  \, r_{xx} (\tau) e^{-j 2 \pi f \tau} \mathrm{d} \tau,\ \text{где}\ r_{xx}(\tau) = \mathbb{E}[\,x(t) \, x^{*}(t - \tau)\,].
\end{equation*}

\end{document}
    

Теперь можно вызвать компилятор PDFLaTeX через командную оболочку и передать ему имя tex-файла. Результат компиляции приведен на рисунке ниже.

Результат компиляции файла <code class="inline-code">analyt_report_template.tex</code>
Результат компиляции файла analyt_report_template.tex

Рассмотрим более подробно код файла analyt_report_template.tex.

  • В первых строках файла с помощью команд \title и \author мы объявляем заголовок отчета и имя автора работы соответственно, а с помощью команды \maketitleсоздаем заголовок.
  • Затем с помощью команды \date, вызванной без аргументов, подавляем вывод временной метки. Здесь для привязки ко времени будет использоваться специальная низкоуровневая командная вставка в стилевом файле style_template.sty (этот фрагмент кода приводится только для справки, так как конечному пользователю приложения нет необходимости вносить в стилевой файл изменения напрямую):
fragment_style_template.sty
        ... 
\def\@maketitle{
    \begin{flushright}
	\footnotesize\itshape
	Дата последней сборки документа:\\ \today\ в \currenttime
    \end{flushright}

    \begin{center}
	\let \footnote \thanks
	\begin{spacing}{1.5}
	    {\Large\bfseries\@title}
	\end{spacing}\vskip 1mm

	{\normalsize
	    \begin{tabular}[t]{l}
		\@author
	    \end{tabular}\par	
	}
    \end{center}
    \par
    \vskip 1.5em
}
...
    

Команда \thispagestyle задает стиль страницы, а команда \tableofcontents создает оглавление документа. С помощью команды \section создаются разделы документа высшего уровня (с учетом класса документа). Для того чтобы создать раздел более низкого уровня следующей ступени можно воспользоваться командой \subsection.

LaTeX обладает широким набором окружений для оформления математических конструкций произвольной сложности, однако здесь мы ограничимся рассмотрением только трех типов окружения: equation, multline и gather.

Как должно быть понятно из приведенного выше рисунка, equation используется для однострочных формул, multline – для многострочных, а gather – для группового размещения формул. Звездочка после имени окружения означает, что LaTeX не станет присваивать номера формулам, попавшим в это окружение.

При наборе формул используются специальные LaTeX-команды с названиями созвучными набираемому элементу, например, для того чтобы добавить в формулу знак суммы с нижним lowindex и верхним upindex индексом используется команда \sum_{lowindex}^{upindex}, чтобы вставить символ большой омеги – \Omega, а для вставки символа гамма потребуется \gamma и т.д.

Для быстрого поиска нужных математических LaTeX-команд, специальных символов, приемов оформления псевдокода и пр. удобно пользоваться компактным, но очень содержательным сборником Константина Воронцова «LaTeX 2e в примерах».

Прочие детали работы с издательской системой LaTeX можно выяснить из следующих работ:

Введение в Python-библиотеку Streamlit

Библиотека Streamlit – это простая, лаконичная и в тоже время очень мощная библиотека для прототипирования браузерных решений с графическим интерфейсом. Streamlit включает поддержку всех основных элементов стека, ориентированных на компьютерное зрение, машинное и глубокое обучение.

Установить библиотеку проще всего с помощью менеджера пакетов pip: pip install streamlit.

Запускается приложение командой streamlit run:

streamlit_run.sh
        $ streamlit run streamlit_simple_example.py

  You can now view your Streamlit app in your browser.

  Local URL: http://localhost:8502 # <-- 
  Network URL: http://192.168.1.247:8502
    

После запуска сценария в браузере (http://localhost:8502) откроется вкладка с приложением. Завершить работу приложения можно, закрыв вкладку браузера и набрав Ctrl+C в командной оболочке.

В Streamlit реализован сравнительно небольшой набор «выразительных средств», но все элементы продуманы и покрывают значительную часть требований к «гибкому динамическому прототипу».

Начать работу со Streamlit можно с вводного руководства, которое подробно описывает все возможности библиотеки, включая Markdown-разметку, аудио и видео объекты, различные графические объекты (Bokeh, Altair, Plotly и др.), а также оптимизацию загрузки объемных наборов данных.

Ниже приводится пример использования библиотеки Streamlit для построения двух интерактивных графиков (на базе библиотеки Plotly) гауссовских процессов с автокорреляционной функцией экспоненциального типа.

streamlit_simple_example.py
        import streamlit as st
import math
import pandas as pd
from pandas import Series
import plotly.graph_objects as go
import numpy as np
import numpy.random as rnd

title_app = "Простой пример использования библиотеки Streamlit"
# чтобы на вкладке браузера отображалось имя приложения, а не имя файла
st.set_page_config(
    layout="wide",
    page_title=title_app,
    initial_sidebar_state="expanded",
)


def gauss_with_exp_acf_gen(
    *,
    sigma: float = 2,
    w_star: float = 1.25,
    delta_t: float = 0.05,
    N: int = 1000,
) -> np.array:
    """
    Описание
    --------
    Генерирует дискретную реализацию
    стационарного гауссовского ПСП
    с КФ экспоненциального типа

    Параметры
    ---------
    sigma : стандартное отклонение ординат ПСП.
    w_star : параметр модели ПСП.
    delta_t : шаг по времени.
    N : число отсчетов ПСП.

    Возвращает
    ----------
    xi : массив элементов ПСП с заданной КФ
    """
    gamma_star = w_star * delta_t
    rho = math.exp(-gamma_star)
    b1 = rho
    a0 = sigma * math.sqrt(1 - rho ** 2)

    xi = np.zeros(N)
    xi[0] = rnd.rand()
    x = rnd.randn(N)

    for n in range(1, N):
        xi[n] = a0 * x[n] + b1 * xi[n - 1]

    return xi


def main(N: int = 100):
    timestmp = np.arange(N)
    # временной ряд №1
    time_series_1 = gauss_with_exp_acf_gen(sigma=5, w_star=1.25, N=N)
    # временной ряд №2
    time_series_2 = gauss_with_exp_acf_gen(sigma=6.5, w_star=1.75, N=N)

    fig = go.Figure()

    fig.add_trace(
        go.Scatter(
            x=timestmp,
            y=time_series_1,
            name="Временной ряд (объект-1)",
            opacity=0.8,
            mode="lines",
            line=dict(
                color="#E84A5F",
            ),
        )
    )

    fig.add_trace(
        go.Scatter(
            x=timestmp,
            y=Series(time_series_1).rolling(window=7).mean(),
            name="Скользящее среднее (объект-1)",
            mode="lines",
            opacity=0.6,
            line=dict(
                color="#FF847C",
            ),
        )
    )

    fig.add_trace(
        go.Scatter(
            x=timestmp,
            y=time_series_2,
            name="Временной ряд (объект-2)",
            mode="lines",
            opacity=0.8,
            line=dict(
                color="#5E63B6",
            ),
        )
    )

    fig.add_trace(
        go.Scatter(
            x=timestmp,
            y=Series(time_series_2).rolling(window=7).mean(),
            name="Скользящее среднее (объект-2)",
            mode="lines",
            opacity=0.6,
            line=dict(
                color="#6EB6FF",
            ),
        )
    )

    fig.update_layout(
        title=dict(
            # text="<i>Временной ряд</i>",
            font=dict(
                family="Arial",
                size=18,
                color="#07689F",
            ),
        ),
        xaxis_title=dict(
            text="<i>Временная метка</i>",
            font=dict(
                family="Arial",
                size=13,
                color="#537791",
            ),
        ),
        yaxis_title=dict(
            text="<i>Продолжительность простоя, час</i>",
            font=dict(
                family="Arial",
                size=13,
                color="#537791",
            ),
        ),
        xaxis=dict(
            showline=True,
        ),
        yaxis=dict(
            showline=True,
        ),
        autosize=False,
        showlegend=True,
        margin=dict(
            autoexpand=False,
            l=70,
            r=10,
            t=50,
        ),
        legend=dict(
            orientation="v",
            yanchor="bottom",
            y=0.01,
            xanchor="right",
            x=0.99,
            font=dict(family="Arial", size=12, color="black"),
        ),
        plot_bgcolor="white",
    )

    st.plotly_chart(fig, use_container_width=True)


if __name__ == "__main__":
    main(N=350)
    

В этом примере к библиотеке Streamlit имеет отношение только:

  • функция st.set_page_config(), которая переопределяет имя вкладки браузера – отображается не имя файла, а имя приложения;
  • функция st.plotly_chart(), которая принимает сконфигурированный Plotly-объект и выводит его в окно браузера.
Результат работы сценария <code class="inline-code">streamlit_simple_example.py</code>
Результат работы сценария streamlit_simple_example.py

Прочие элементы сценария streamlit_simple_example.py играют лишь вспомогательную роль.

Пример-шаблон аналитического отчета

Предлагается в качестве примера, сочетающего приемы работы с библиотекой Streamlit (браузерный интерфейс приложения) и LaTeX-разметку (опорный tex-файл), рассмотреть подготовку отчета на тему «Оценка усталостной долговечности силовых элементов транспортных машин под воздействием стационарных гауссовских процессов с автокорреляционной функцией экспоненциально-косинусного семейства».

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

Подробности реализации обсуждаемого решения можно узнать из github-репозитория, сейчас же кратко остановимся на нескольких нюансах.

Часто возникает необходимость выгрузить подготовленный с помощью Streamlit файл результатов (например, табличных объект Pandas), но сам Streamlit не предлагает никаких решений. Тем не менее это ограничение можно обойти с помощью следующей функции:

downloader_for_streamlit.py
        def text_downloader(multiline: str) -> NoReturn:
    """
    Принимает LaTeX-шаблон документа в виде многострочной строки и
    создает на странице ссылку для скачивания шаблона
    """
    OUTPUT_TEX_FILENAME = "base_template_for_latex.tex"
    
    b64 = base64.b64encode(multiline.encode()).decode()
    # создает ссылку для скачивания файла
    href = (f'<a href="data:file/txt;base64,{b64}" '
            f'download="{OUTPUT_TEX_FILENAME}">Скачать ...</a>')
    st.markdown(href, unsafe_allow_html=True)
    

Функция читает текстовый файл, переданный в виде строки, кодирует его с помощью стандарта base64 и передает тег-ссылку методу markdown. В итоге файл можно будет скачать, кликнув на созданную ссылку.

При наборе текстового шаблона для Python (latex_template_for_python.txt) – по сути файл представляет собой каркас документа с заглушками под строковую интерполяцию – важно помнить о синтаксических особенностях LaTeX. Дело в том, что в контексте строковой интерполяции фигурные скобки означают «место подстановки», а в контексте LaTeX – обязательный аргумент команды. То есть, чтобы Python корректно «прочитал» строку следует фигурные скобки, относящиеся к синтаксису LaTeX, удвоить.

В результате получится текстовый файл вида:

fragment_latex_template_for_python.txt
        \documentclass[
    11pt,
    a4paper,
    utf8,
]{{article}}

\usepackage{{style_template}}

\begin{{document}}
...
Усталостная долговечность по модели \eqref{{eq:miles}} составляет $ Y_{{NB}} = {Y_NB:.2f} $, сек.

\section{{Оценка усталостной долговечности по модели P.H. Wirsching и C.L.~Light}}
...
    

Ниже на рисунках приводится общий вид приложения.

Стартовая страница приложения
Стартовая страница приложения

Скачав подготовленный tex-файл в директорию проекта, останется только запустить компилятор (дважды!).

pdflatex_start.sh
        # для сборки каркаса
$ pdflatex base_template_for_latex.tex
# для вычисления конечных ссылок на страницы, формулы и пр.
$ pdflatex base_template_for_latex.tex

    

После сборки документа в рабочей директории проекта будет создан pdf-файл.

Выгрузка подготовленного LaTeX-шаблона
Выгрузка подготовленного LaTeX-шаблона
Результат работы <code class="inline-code">pdflatex base_template_for_latex.tex</code>. Фрагмент собранного аналитического отчета
Результат работы pdflatex base_template_for_latex.tex. Фрагмент собранного аналитического отчета

Чтобы развернуть приложение на свободной облачной платформе Streamlit, достаточно кликнуть на Deploy this app в правой верхней части панели запущенного приложения, как изображено на рисунке. Однако предварительно необходимо зарегистрироваться на Streamlit и отправить заявку на допуск к ресурсам (обычно обработка заявки занимает несколько дней).

Развертывание приложения на облачной платформе Streamlit
Развертывание приложения на облачной платформе Streamlit

После успешного развертывания на платформе приложение будет доступно конечному пользователю по ссылке, как в данном случае.

Заключение

Из руководства вы узнали:

  • что собой представляет система компьютерной вёрстки LaTeX, где найти ее дистрибутивы и пакеты, как правильно читать документацию, как начать работать с системой;
  • как разрабатывать гибкие, масштабируемые шаблоны документов с помощью языка разметки TeX/LaTeX;
  • как использовать приемы разработки приложений с помощью Python-библиотеки Streamlit;
  • как может выглядеть пример связки «LaTeX + Streamlit»;
  • и, наконец, как развернуть приложение на облачной платформе Streamlit.

Полезные источники:

Связные материалы с платформы Proglib:

05
Июл
2021

🤖 Вариационные автоэнкодеры (VAE) для чайников – пошаговое руководство

Практическое руководство в стиле “сделай сам” с работающим кодом создания и обучения VAE для лиц знаменитостей на Keras.

Текст публикуется в переводе, автор статьи – Мишель Кана.

Эта статья познакомит вас со всем необходимым для начала работы с генеративными моделями. Мы предоставим пошаговое руководство по обучению условных VAE на наборах данных с большими изображениями и их применению для генерации новых размеченных изображений.

Мотивация

Зачем нужно генерировать новые данные, если в мире и так огромное количество данных? Согласно IDC, в мире более 18 зеттабайтов данных.

Большинство задач машинного обучения требуют размеченных данных, а получить высококачественные размеченные данные сложно. Если мы генерируем данные сами, мы всегда можем сделать их столько, сколько потребуется. Новые данные могут натолкнуть вас на новые идеи и предоставить новые возможности.

Как сгенерировать изображения, которых никто не видел?

Прочитав эту статью, вы узнаете, что такое Вариационный Автоэнкодер, и как создать ваш собственный для генерации новых изображений, которые никто никогда не видел. Мы объясним идеи и концепции, лежащие в его основе, без какой-либо математики.

Пример изображения и его реконструкции с помощью нашего кода VAE
Пример изображения и его реконструкции с помощью нашего кода VAE

Данные

Мы используем подмножество широко известного набора данных Знаменитостей, который поможет нам создать модель генерации лиц. Этот набор можно скачать с сайта CelebFacesA. Он предоставляет большой набор атрибутов лиц, содержащий более 200 тысяч изображений знаменитостей, для каждого из которых указано значение 40 атрибутов.

  • 10.177 личностей;
  • 202.599 изображений;
  • 5 важнейших локаций;
  • 40 бинарных атрибутов для каждого изображения.
        import pandas as pd

df_celeb = pd.read_csv('list_attr_celeba.csv')
df_celeb.head()
    

Ниже мы выбираем случайные лица и выводим их метаданные (атрибуты). Изображения имеют высоту 218 пикселей, ширину 178 пикселей и 3 цветовых канала.

        import matplotlib.pyplot as plt
import random
from skimage.io import imread

def show_sample_image(nb=3, df=df_celeb, verbose=True):
    f, ax = plt.subplots(1, nb, figsize=(10,5))
    for i in range(nb):
        idx = random.randint(0, df.shape[0]-1)
        img_id = df.loc[idx].image_id
        img_uri = 'img_align_celeba/' + img_id
        img = skimage.io.imread(img_uri)  
        if verbose:
            label = img_id
            for col in df.columns:
                if df.loc[idx][col]==1:
                    label = label + '\n' + col  
            if nb > 1:
                ax[i].imshow(img)
                ax[i].set_title(label)
            else:
                ax.imshow(img) 
                ax.set_title(label)
        
    return img, list(df.loc[idx][1:df.shape[1]])
  
sample_img, sample_img_meta = show_sample_image()
    

Что такое автоэнкодер (AE)?

Просмотрев лица тысяч знаменитостей, нейронная сеть может научиться генерировать лица людей, которых не существует.

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

Иногда этих меток у нас нет. Тем не менее, мы можем обучить две нейронные сети – одна будет усваивать представление, а вторая – восстанавливать исходное изображение из этого представления, минимизируя функцию потерь реконструкции. Это автоэнкодер (автокодировщик). Он так называется потому, что автоматически находит лучший способ закодировать данные так, чтобы декодированная версия была как можно ближе к исходной.

Автоэнкодер состоит из двух соединенных нейронных сетей: модели энкодера (кодировщика) и модели декодера (декодировщика). Его цель – нахождение метода кодирования лиц знаменитостей в сжатую форму (скрытое пространство) таким образом, чтобы восстановленная версия была как можно ближе к входной.

Как работают компоненты автоэнкодера
Как работают компоненты автоэнкодера
  • Модель энкодера переводит входное значение X в маленькое плотное представление Z, примерно так же, как работает сверточная нейронная сеть, используя фильтры для усвоения представлений.
  • Модель декодера можно считать генеративной моделью, способной генерировать специфические признаки X’.
  • Энкодер и декодер обычно обучаются вместе. Функция потерь штрафует объединенную сеть за создание выходных лиц, отличающихся от входных лиц.

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

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

Что такое вариационный автоэнкодер (VAE)?

Как правило, скрытое пространство Z, создаваемое энкодером, редко заселено, то есть трудно предсказать, распределение значений в этом пространстве. Значения разбросаны, и пространство обычно хорошо визуализируется в двухмерном представлении.

Это очень полезная особенность для систем сжатия (компрессии). Однако для генерации новых изображений знаменитостей эта разреженность – проблема, поскольку найти скрытое значение, для которого декодер будет знать, как произвести нормальное изображение, почти невозможно.

Более того, если в пространстве есть промежутки между кластерами, и декодер получит вариацию из такого промежутка, ему не хватит знаний, чтобы сгенерировать что-нибудь полезное.

Вариационный автоэнкодер делает внутреннее пространство более предсказуемым, более непрерывным и менее разреженным. Заставляя скрытые переменные соответствовать нормальному распределению, VAE получают контроль над скрытым пространством.

Переход от AE к VAE, используя случайные переменные
Переход от AE к VAE, используя случайные переменные

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

В процессе обучения VAE заставляет это нормальное распределение быть как можно более близким к стандартному нормальному распределению, включая в функцию потерь расстояние Кульбака-Лейблера. VAE будет изменять, или исследовать вариации на гранях, и не случайным образом, а в определенном, желаемом направлении.

Условные вариационные автоэнкодеры позволяют моделировать вход на основе не только скрытой переменной z, но и дополнительной информации вроде метаданных изображения (улыбка, очки, цвет кожи и т.п.)

Генератор данных изображений

Давайте создадим (условный) VAE, который сможет обучаться на лицах знаменитостей. Мы используем пользовательский эффективный по памяти генератор Keras, чтобы справиться с нашим большим набором данных (202599 изображений, примерно по 10Кб каждое). Его цель – получать пакеты изображений на лету в процессе обучения.

        import numpy as np

class CustomCelebrityFaceGenerator(Sequence):
    # инициализируем пользовательский генератор
    def __init__(self, df, batch_size, target_height, target_width, conditioning_dim=0):
        self.df = df
        self.batch_size = batch_size
        self.target_height = target_height
        self.target_width = target_width
        self.conditioning_dim = conditioning_dim
        
    # перетасуем данные после каждой эпохи 
    def on_epoch_end(self):
        self.df = self.df.sample(frac=1)
    
    # выберем пакет в виде тензора
    def __getitem__(self, index):
        cur_files = self.df.iloc[index*self.batch_size:(index+1)*self.batch_size]
        X, y = self.__data_generation(cur_files)
        return X, y
    
    # 
    def __data_generation(self, cur_files):
        # инициализируем пустые тензоры для хранения изображений  
        X = np.empty(shape=(self.batch_size, self.target_height, self.target_width, 3))
        Y = np.empty(shape=(self.batch_size, self.target_height, self.target_width, 3))
        # инициализируем пустой тензор для хранения условных переменных
        if self.conditioning_dim > 0:
            C = np.empty(shape=(self.batch_size, self.conditioning_dim))
        
        # проходим циклом по текущему пакету и создаем тензоры 
        for i in range(0, self.batch_size):
            # читаем изображение
            file = cur_files.iloc[i]
            img_uri = 'img_align_celeba/' + file.image_id
            img = skimage.io.imread(img_uri)
            # изменяем размеры изображения
            if img.shape[0] != self.target_height or img.shape[1] != self.target_width:
                img = skimage.transform.resize(img, (self.target_height, self.target_width)) 
            # сохраняем изображение в тензорах 
            img = img.astype(np.float32) / 255.
            X[i] = img
            Y[i] = img
            # сохраняем условные параметры в тензорах
            if self.conditioning_dim > 0:
                C[i] = list(file[1:file.shape[0]])
            
        if self.conditioning_dim > 0:
            return [X, C], Y
        else:
            return X, Y
    
    # получить количество пакетов
    def __len__(self):
        return int(np.floor(self.df.shape[0] / self.batch_size))
    

Нейронная сеть VAE

Мы хотим, чтобы наш энкодер был сверточной нейронной сетью, принимающей изображение и выдающей параметры распределения Q(z | [x,c]), где x – входное изображение лица, c – условная переменная (атрибуты лица), а z – скрытая переменная. В этой статье мы используем простую архитектуру, состоящую из двух сверточных слоев и слоя группировки (pooling).

Декодер – это сверточная нейронная сеть, построенная по-другому. Это генеративная нейронная сеть, выдающая параметры распределения похожести P([x,z] | c).

        from keras.layers import Conv2D, MaxPooling2D, UpSampling2D

def get_encoder_network(x, num_filters):  
    x = Conv2D(num_filters, 3, activation='relu', padding='same', kernel_initializer='he_normal')(x)
    x = Conv2D(num_filters, 3, activation='relu', padding='same', kernel_initializer='he_normal')(x)
    x = MaxPooling2D()(x)
    return x

def get_decoder_network(x, num_filters):
    x = UpSampling2D()(x)
    x = Conv2D(num_filters, 3, activation='relu', padding = 'same', kernel_initializer = 'he_normal')(x)
    x = Conv2D(num_filters, 3, activation='relu', padding = 'same', kernel_initializer = 'he_normal')(x)
    return x
    

Вот так выглядит архитектура всей сети VAE:

        from keras.layers import Input, Dense, Reshape, Concatenate, Flatten, Lambda, Reshape
from keras.models import Model
from keras import backend as K
from keras.optimizers import Adam

# функция для создания нейронной сети автоэнкодера 
def get_vae(height, width, batch_size, latent_dim, 
            is_variational=True, conditioning_dim=0,
            start_filters=8, nb_capacity=3, 
            optimizer=Adam(lr=0.001)):
    
    # ВХОД ##
    
    # создаем слой для входного изображения 
    # объединяем метаданные изображений 
    inputs = Input((height, width, 3))
    if conditioning_dim > 0:
        condition = Input([conditioning_dim])
        condition_up = Dense(height * width)(condition)
        condition_up = Reshape([height, width, 1])(condition_up)
        inputs_new = Concatenate(axis=3)([inputs, condition_up])
    else:
        inputs_new = inputs
    
    
    # ЭНКОДЕР ##
    
    # создаем кодирующие слои 
    # дублируем кодирующие слои, увеличивая фильтры 
    eblock = get_encoder_network(inputs_new, start_filters)
    for i in range(1, nb_capacity+1):
        eblock = get_encoder_network(eblock, start_filters*(2**i))
        
    # создаем слой скрытого пространства
    _, *shape_spatial = eblock.get_shape().as_list()
    eblock_flat = Flatten()(eblock)    
    if not is_variational:
        z = Dense(latent_dim)(eblock_flat)
    else:
        # выборка скрытых значений из нормального распределения
        def sampling(args):
            z_mean, z_log_sigma = args
            epsilon = K.random_normal(shape=(batch_size, latent_dim), mean=0., stddev=1.)
            return z_mean + K.exp(z_log_sigma) * epsilon
        
        z_mean = Dense(latent_dim)(eblock_flat)
        z_log_sigma = Dense(latent_dim)(eblock_flat)
        z = Lambda(sampling, output_shape=(latent_dim,))([z_mean, z_log_sigma])
    
    if conditioning_dim > 0:
        z_ext = Concatenate()([z, condition])

        
    ## ДЕКОДЕР ##
    
    # создаем декодирующие статьи
    inputs_embedding = Input([latent_dim + conditioning_dim])
    embedding = Dense(np.prod(shape_spatial), activation='relu')(inputs_embedding)
    embedding = Reshape(eblock.shape.as_list()[1:])(embedding)
    
    # дублируем кодирующие слои, увеличивая фильтры 
    dblock = get_decoder_network(embedding, start_filters*(2**nb_capacity))
    for i in range(nb_capacity-1, -1, -1):
        dblock = get_decoder_network(dblock, start_filters*(2**i))
        
    output = Conv2D(3, 1, activation = 'tanh')(dblock)
    
    ## VAE ##
    
    # объединяем энкодер с декодером 
    decoder = Model(input = inputs_embedding, output = output)
    if conditioning_dim > 0:
        encoder_with_sampling = Model(input = [inputs, condition], output = z)
        encoder_with_sampling_ext = Model(input = [inputs, condition], output = z_ext)
        vae_out = decoder(encoder_with_sampling_ext([inputs, condition]))
        vae = Model(input = [inputs, condition], output = vae_out)
    else:
        encoder_with_sampling = Model(input = inputs, output = z)
        vae_out = decoder(encoder_with_sampling(inputs))
        vae = Model(input = inputs, output = vae_out)
    
    # определяем потери VAE как сумму MSE and потерь расстояния Кульбака-Лейблера
    def vae_loss(x, x_decoded_mean):
        mse_loss = K.mean(mse(x, x_decoded_mean), axis=(1,2)) * height * width
        kl_loss = - 0.5 * K.mean(1 + z_log_sigma - K.square(z_mean) - K.exp(z_log_sigma), axis=-1)
        return mse_loss + kl_loss
        
    if is_variational:
        vae.compile(loss=vae_loss, optimizer=optimizer)
    else:
        vae.compile(loss='mse', optimizer=optimizer)    
        
    return vae, encoder_with_sampling, decoder

# гиперпараметры
VARIATIONAL = True
HEIGHT = 128 
WIDTH = 128 
BATCH_SIZE = 16 
LATENT_DIM = 16
START_FILTERS = 32 
CAPACITY = 3 
CONDITIONING = True 
OPTIMIZER = Adam(lr=0.01)

vae, encoder, decoder = get_vae(is_variational=VARIATIONAL,
                                   height=HEIGHT, 
                                   width=WIDTH, 
                                   batch_size=BATCH_SIZE, 
                                   latent_dim=LATENT_DIM,
                                   conditioning_dim=df_celeb.shape[1]-1, 
                                   start_filters=START_FILTERS,
                                   nb_capacity=CAPACITY,
                                   optimizer=OPTIMIZER)
    

Обучение

Ниже представлен процесс обучения моделей VAE на наборе данных celebA. Этот код выполнялся около 8 часов на инстансе AWS с использованием 1 GPU.

        # делим изображения на тренировочный набор и набор валидации
msk = np.random.rand(len(df_celeb)) < 0.5
df_celeb_train = df_celeb[msk]
df_celeb_val = df_celeb[~msk]

# создаем генераторы изображений для обучения
gen = CustomCelebrityFaceGenerator(df_celeb_train, 
                          batch_size=BATCH_SIZE, 
                          target_height=HEIGHT, 
                          target_width=WIDTH, 
                          conditioning_dim=df_celeb.shape[1]-1)

# создаем генераторы изображений для валидации
gen_val = CustomCelebrityFaceGenerator(df_celeb_val, 
                          batch_size=BATCH_SIZE, 
                          target_height=HEIGHT, 
                          target_width=WIDTH, 
                          conditioning_dim=df_celeb.shape[1]-1)

# обучаем вариационный автоэнкодер
vae.fit_generator(gen, verbose=1, epochs=20, validation_data=gen_val)
    

Визуализируем скрытые представления

После обучения мы можем выбрать случайное изображение из нашего набора данных и использовать обученный энкодер для создания скрытого представления изображения.

        # выбираем случайное изображение
sample_img, sample_img_meta = show_sample_image(nb=1)

# функция для кодирования одного изображения, возвращающая его скрытое представление
def encode_image(img, conditioning, encoder, height, width, batch_size):
    # изменяем размеры изображения
    if img.shape[0] != height or img.shape[1] != width:
        img = skimage.transform.resize(img, (height, width))
    # заполняем изображение, чтобы оно соответствовало размеру пакета
    img_single = np.expand_dims(img, axis=0)
    img_single = img_single.astype(np.float32)
    img_single = np.repeat(img_single, batch_size, axis=0)
    # используем энкодер для вычисления представления в скрытом пространстве
    if conditioning is None:
        z = encoder.predict(img_single)
    else:
        z = encoder.predict([img_single, np.repeat(np.expand_dims(conditioning, axis=0), batch_size, axis=0)])
    return z

# выводим представление в скрытом пространстве, созданное энкодером
z = encode_image(sample_img.astype(np.float32) / 255., 
                 np.array(sample_img_meta), 
                 encoder, HEIGHT, WIDTH, BATCH_SIZE)
print('latent sample:\n', z[0])
    


Используя это скрытое представление, вектор из 16 действительных чисел, мы можем визуализировать, как декодер восстановил исходное изображение.

        def decode_embedding(z, conditioning, decoder):
    if z.ndim < 2:
        z = np.expand_dims(z, axis=0)
    if conditioning is not None:
        z = np.concatenate((z, np.repeat(np.expand_dims(conditioning, axis=0), z.shape[0], axis=0)), axis=1)
    return decoder.predict(z)

# восстановим исходное изображение, используя представление скрытого пространства 
ret = decode_embedding(z, sample_img_meta, decoder)
plt.imshow(ret[0])
plt.show()
    

Хотя реконструированное изображение и размыто, мы можем заметить, что оно очень похоже на исходное изображение: пол, цвет одежды, волосы, улыбка, цвет кожи.

Генерируем новые лица

Условные VAE могут изменять скрытое пространство, чтобы генерировать новые данные. А это значит, что мы можем сгенерировать случайное количество новых изображений с помощью декодера, определяя разные значения заданных атрибутов.

        def generate_new_images_vae(nb=16, smiling=None, male=None, no_beard=None, attractive=None, 
                        bald=None, chubby=None, eyeglasses=None, young = None):
    sample_training_img, sample_training_img_meta = show_sample_image(nb=1, verbose=False)
    plt.clf();
    f, ax = plt.subplots(2, nb//2, figsize=(20,7));
    for i in range(nb):
        meta=2*np.random.rand(meta_cols.shape[0])-1
        meta[2] = attractive if attractive else meta[2]
        meta[4] = bald if bald else meta[4]
        meta[13] = chubby if chubby else meta[13]
        meta[15] = eyeglasses if eyeglasses else meta[15]
        meta[20] = male if male else meta[20]
        meta[24] = no_beard if no_beard else meta[24]
        meta[31] = smiling if smiling else meta[31]
        meta[39] = young if young else meta[39]
        z1 = np.random.rand(LATENT_DIM, LATENT_DIM)
        ret = decode_embedding(z1, meta, decoder)
        ax[i%2][i//2].imshow(ret[0])
        ax[i%2][i//2].set_title('generated img {}'.format(i))
    ax[0][0].imshow(sample_training_img)
    ax[0][0].set_title('training img')
    
 generate_new_images_vae()
    

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

От улыбки станет мир светлей

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

        # интерполяция скрытого пространства, чтобы изменить исходное изображение
def display_manifold(decoder, height, width, base_vec, 
                     bound_x=15, bound_y=15, 
                     axis_x=0, axis_y=1, n=15,
                     desc_x = 'x', desc_y = 'y', 
                     file_out=None):
 
    figure = np.zeros((height * (n if bound_y > 0 else 1), width * (n if bound_x > 0 else 1), 3))
    grid_x = np.linspace(-bound_x, bound_x, n) if bound_x > 0 else [0]
    grid_y = np.linspace(-bound_y, bound_y, n) if bound_y > 0 else [0]
    individual_outputs = []

    for i, yi in enumerate(grid_y):
        for j, xi in enumerate(grid_x):
            z_sample = base_vec.copy()
            z_sample[axis_x] = xi 
            z_sample[axis_y] = yi 

            x_decoded = decoder.predict(np.expand_dims(z_sample, axis=0))
            sample = np.clip(x_decoded[0], 0, 1)
            figure[i * height: (i + 1) * height, j * width: (j + 1) * width] = sample
            individual_outputs.append(sample)

    plt.figure(figsize=(10, 10))
    plt.imshow(figure)
    plt.xlabel(desc_x)
    plt.ylabel(desc_y)
    if file_out is not None:
        plt.savefig(file_out, dpi=200, bbox_inches='tight')
    return figure, individual_outputs

# доступные атрибуты
meta_cols = df_celeb.columns[1:].values

# изменяемые атрибуты
dim1 = 'Male'
dim2 = 'Smiling'

# используемое скрытое пространство 
base_vec = np.array(list(z[0]) + sample_img_meta)

# создаем изменения
rendering, _ = display_manifold(
                                decoder, 
                                HEIGHT, 
                                WIDTH, 
                                base_vec, 
                                bound_x=15, 
                                bound_y=15, 
                                axis_x=LATENT_DIM + np.where(meta_cols==dim1)[0][0], 
                                axis_y=LATENT_DIM + np.where(meta_cols==dim2)[0][0], 
                                n=10,
                                desc_x = dim1,
                                desc_y = dim2,
                                file_out = 'rendering_celeba_' + dim1.lower() + '_' + dim2.lower() + '.png'
                                )
    

Заключение

В этой статье мы представили условные вариационные автоэнкодеры и продемонстрировали, как их можно обучить генерации новых размеченных данных. Мы предоставили код на Python для обучения VAE на больших наборах данных изображений знаменитостей. Этот подход и код можно использовать и для многих других задач.

Генеративные состязательные сети (GAN), как правило, выдают изображения, которые выглядят еще лучше, поскольку они обучаются распознавать, что люди считают фотореалистичным, а что нет.

Этический аспект использования технологий VAE/GAN для создания фейковых изображений, видео и новостей следует рассматривать серьезно, и они должны применяться ответственно.

Огромное спасибо Винсенту Кассеру (Vincent Casser) за его замечательный код, содержащий более продвинутый подход к реализации сверточных автоэнкодеров для обработки изображений, приведенный в его блоге. Винсент разрешил мне адаптировать его код VAE для этой статьи. Создание работающего VAE с нуля довольно сложно, так что за код следует благодарить Винсента.

Если вы хотите узнать больше об автоэнкодерах, читайте статью Джозефа Рокка «Разбираемся с вариационными автоэнкодерами (VAE)».

30
Июн
2021

👨‍🎓️ Школа анализа данных – плюсы и минусы

Школа анализа данных – двухгодичная программа обучения от Яндекса. Основной упор в ней делается на данные и методы работы с ними. В небольшом обзоре мы разберём плюсы и минусы учёбы в ШАД.

Как поступить?

Итак, ШАД – полноценное обучение на протяжении двух лет, с нагрузкой по 30 часов в неделю. Обучение бесплатное, но сначала требуется пройти онлайн-тестирование, затем экзамен и собеседование в филиалах ШАД.

Как и в университете, здесь есть возможность платного поступления, но для этого нужно хорошо показать себя на собеседовании. Стоит учёба 150 000 рублей в семестр. Если закончить семестр на хорошо и отлично, цена уменьшится наполовину. А если два раза подряд закончить хорошистом или отличником, обучение станет бесплатным.

Онлайн-тестирование – обычное заполнение анкеты с тестовыми вариантами задач. После него есть два варианта: для москвичей следует прибыть в отделение ШАД и сдать экзамен по математике, алгоритмам, а затем по программированию и основам анализа данных. Заочники или учащиеся в региональных отделениях сдают онлайн-экзамен.

В конце пройдёт собеседование – очный экзамен по тому же программированию, математике и алгоритмам.

Все задачи выбираются в рамках общей программы (в документе даже указаны все необходимые книги для подготовки). Кстати, у нас есть статья, полностью посвящённая подготовке к поступлению в ШАД.

В 2020 году появился вариант поступления для тех, кто уже давно в программировании. В этом случае потребуется вместо математики продемонстрировать умение программировать, а также участие в проектах, различных статьях и прочем.

Кому это нужно?

Во-первых, выпускники получают диплом о профессиональной переподготовке. Во-вторых, любовь к Data Science и желание глубоко-глубоко нырнуть в эту отрасль. При этом, если вас интересует чистая научная теория, то место найдётся – регулярные семинары и различные исследовательские проекты.

В целом, целевую аудиторию можно описать так: хочется попасть в сферу Data Science, сделать это максимально эффективно и интересно. К тому же, обучение проходит по вечерам.

ШАД: Плюсы обучения

  • Знания. Преподаватели в ШАДе частенько в “первую смену” работают в различных вузах Москвы, а затем читают лекции на свою любимую тему в школе Яндекса. Квалификация у них точно на высоте.
  • Вечерняя программа. Учёба по вечерам отлично стимулирует освоение тайм-менеджмента: нужно и задания успеть выполнить, и подготовиться к следующему дню, и время на сон оставить.
  • Математика, данные и программирование. Здесь всё сосредоточено на этих предметах. Нужно знать математику, чтобы с помощью математической же культуры уметь работать с данными. Нужно знать и понимать данные, выявляя среди них закономерности и прочее. И программирование потребуется, чтобы это всё автоматизировать.
  • Интенсивная нагрузка. Слоган ШАДа: «Будет сложно, но интересно». Стимул к обучению студенты получают за счёт интересных задач. Им также предоставляют все необходимые инструменты для подготовки. Можно даже постоянно мучить преподавателей вопросами.

ШАД: Минусы обучения

  • Вечерняя программа. Если ваша жизнь уже загружена, то добавлять к ней вечерние курсы – стрелять себе в ногу. При этом, обучение действительно интенсивное и требует внимательности.
  • Серьёзная нагрузка. Так как здесь учат анализировать, то мозги будут работать на полную катушку. А то потребуется их перегружать их. Следует заранее прокачать выносливость и… умение отдыхать.
***

Зачем стремиться в ШАД? Первое – возможность целиком погрузиться в пучину данных, математических идей и алгоритмов целиком. Второе – полноценная программа обучения в сфере Data Science, диплом и рекомендации, которые помогут получить желанную работу (или сразу отправиться в Яндекс). Третье – высокий уровень самоорганизованности (в основном, для молодых людей), который обязательно разовьётся в ШАДе и при любом исходе будет очень ценным навыком во всей жизни.

«Библиотека программиста» желает вам удачного поступления! Для подготовки к экзаменам записывайтесь на наши курсы по математике в Data Science.