diff --git a/fig-ml/lin-class.png b/fig-ml/lin-class.png
new file mode 100644
index 0000000..abebfa6
Binary files /dev/null and b/fig-ml/lin-class.png differ
diff --git a/ml.ipynb b/ml.ipynb
new file mode 100644
index 0000000..f93bb37
--- /dev/null
+++ b/ml.ipynb
@@ -0,0 +1,2757 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "# Машинное обучиение с использованием библиотек Python\n",
+ "\n",
+ " \n",
+ "**С.В. Лемешевский** (email: `sergey.lemeshevsky@gmail.com`), Институт математики НАН Беларуси\n",
+ "\n",
+ "Date: **May 4, 2020**\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "# Основные определения и постановки задач машинного обучения\n",
+ "
\n",
+ "\n",
+ "*Машинное обучение* — это раздел математики, изучающий способы\n",
+ "извлечения закономерностей из ограниченного числа примеров. \n",
+ "\n",
+ "\n",
+ "## Примеры задач машинного обучения\n",
+ "\n",
+ "\n",
+ "Рассмотрим несколько примеров задач, которые решаются с помощью\n",
+ "машинного обучения.\n",
+ "\n",
+ "** Кредитный скоринг.**\n",
+ "\n",
+ " *Задача*: выяснить, какие заявки на кредит можно одобрить.\n",
+ "\n",
+ "**Лента Facebook/Дзен по интересности (вместо сортировки по времени).**\n",
+ "\n",
+ " *Задача*: показать посты, наиболее интересные для конкретного человека.\n",
+ "\n",
+ "**Детектирование некорректной работы.**\n",
+ "\n",
+ " Предположим, что у нас есть завод, на котором происходят некоторые\n",
+ " процессы (стоят какие-то котлы, станки, работают сотрудники). На\n",
+ " предприятии может произойти поломка, например, сломается датчик\n",
+ " уровня жидкости в баке, из-за чего насос не остановится при\n",
+ " достижении нужного уровня и нефть начнёт разливаться по полу, что\n",
+ " может привести к неизвестным последствиям. Или же сотрудники объявят\n",
+ " забастовку и вся работа остановится. Мы хотим, чтобы завод работал\n",
+ " исправно, а обо всех проблемах узнавать как можно раньше. \n",
+ "\n",
+ " *Задача*: предсказать поломки/нештатные ситуации на заводе.\n",
+ "\n",
+ "**Вопросно-ответная система (как Siri).**\n",
+ "\n",
+ " *Задача*: ответить голосом на вопрос, заданный голосом.\n",
+ "\n",
+ "**Self-driving cars.**\n",
+ "\n",
+ " *Задача*: доехать из точки $А$ в точку $В$.\n",
+ "\n",
+ "**Перенос стиля изображения.**\n",
+ "\n",
+ " *Задача*: перенести стиль одного изображения на другое (смешать\n",
+ " стиль одного с контекстом другого). \n",
+ "\n",
+ "\n",
+ "Как видим, задачи очень разнообразны. Мы начнем наш путь со следующей\n",
+ "классической постановки (к которой, кстати, сводятся многие\n",
+ "вышеперечисленные задачи): по имеющемуся признаковому описанию объекта\n",
+ "$x \\in \\mathbb{R}^m$ предсказать значение целевой переменной $y \\in\n",
+ "\\mathbb{R}^k$ для данного объекта. Обычно $k=1$. \n",
+ "\n",
+ "Например, в случае кредитного скоринга $x$-ом являются все известные о\n",
+ "клиенте данные (доход, пол, возраст, кредитная история и т.д.), а\n",
+ "$y$-ом одобрение или неодобрение заявки на кредит.\n",
+ "\n",
+ "Библиотеки с алгоритмами машинного обучения, которые будем изучать:\n",
+ "* [scikit-learn](http://scikit-learn.github.io/stable),\n",
+ "\n",
+ "* [XGBoost](https://xgboost.readthedocs.io/en/latest/) и\n",
+ "\n",
+ "* [pytorch](https://pytorch.org). \n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "## Линейная регрессия\n",
+ "\n",
+ "\n",
+ "Начнем с подключения необходимых библиотек"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "%matplotlib inline\n",
+ "\n",
+ "import matplotlib.pyplot as plt\n",
+ "import seaborn as sns\n",
+ "import pandas as pd\n",
+ "import numpy as np"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "*Линейная регрессия* — это модель следующего вида:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "\n",
+ "\n",
+ "$$\n",
+ "\\begin{equation}\n",
+ "\\label{ml:linear-regression:eq:lin-reg} \\tag{1}\n",
+ "a(x) = \\langle a, w \\rangle + w_0 = \\sum_{i = 1}^{d} w_i x_i + w_0,\n",
+ "\\end{equation}\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "где $w \\in \\mathbb{R}^d$, $w_0 \\in \\mathbb{R}$. Параметрами модели\n",
+ "являются *веса* или *коэффициенты* $w_i$. Вес $w_0$ также называется \n",
+ "*свободным коэффициентом* или *сдвигом* (bias). Обучить линейную\n",
+ "регрессию — значит найти $w$ и $w_0$.\n",
+ "\n",
+ "В машинном обучении часто говорят об *обобщающей способности модели*,\n",
+ "то есть о способности модели работать на новых, тестовых данных\n",
+ "хорошо. Если модель будет идеально предсказывать выборку, на которой\n",
+ "она обучалась, но при этом просто ее запомнит, не «вытащив» из данных\n",
+ "никакой закономерности, от нее будет мало толку. Такую модель\n",
+ "называют *переобученной*: она слишком подстроилась под обучающие\n",
+ "примеры, не выявив никакой полезной закономерности, которая позволила\n",
+ "бы ей совершать хорошие предсказания на данных, которые она ранее не\n",
+ "видела. \n",
+ "\n",
+ "Рассмотрим следующий пример, на котором будет хорошо видно, что значит\n",
+ "переобучение модели. Для этого нам понадобится сгенерировать\n",
+ "синтетические данные. Рассмотрим зависимость $y(x) = \\cos(1.5\\pi x)$,\n",
+ "$y$ — целевая переменная (таргет), а $x$ — объект (просто число от $0$ до\n",
+ "$1$). В жизни мы наблюдаем какое-то конечное количество пар\n",
+ "объект-таргет, поэтому смоделируем это, взяв $30$ случайных точек $x_i$\n",
+ "в отрезке $[0;1]$. Более того, в реальной жизни целевая переменная\n",
+ "может быть зашумленной (измерения в жизни не всегда точны),\n",
+ "смоделируем это, зашумив значение функции нормальным шумом:\n",
+ "$\\tilde{y}_i = y(x_i) + \\mathcal{N}(0, 0.01)$:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "np.random.seed(36)\n",
+ "x = np.linspace(0, 1, 100)\n",
+ "y = np.cos(1.5 * np.pi * x)\n",
+ "\n",
+ "x_objects = np.random.uniform(0, 1, size=30)\n",
+ "y_objects = np.cos(1.5 * np.pi * x_objects) + np.random.normal(scale=0.1, size=x_objects.shape)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Попытаемся обучить три разных линейных модели: признаки для первой\n",
+ "--- $\\{x\\}$, для второй --- $\\{x, x^2, x^3, x^4\\}$, для\n",
+ "третьей --- $\\{x, \\dots, x^{20}\\}$:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.linear_model import LinearRegression\n",
+ "from sklearn.preprocessing import PolynomialFeatures\n",
+ "\n",
+ "\n",
+ "fig, axs = plt.subplots(figsize=(16, 4), ncols=3)\n",
+ "for i, degree in enumerate([1, 4, 20]):\n",
+ " X_objects = PolynomialFeatures(degree).fit_transform(x_objects[:, None])\n",
+ " X = PolynomialFeatures(degree).fit_transform(x[:, None])\n",
+ " regr = LinearRegression().fit(X_objects, y_objects)\n",
+ " y_pred = regr.predict(X)\n",
+ " axs[i].plot(x, y, label=\"Real function\")\n",
+ " axs[i].scatter(x_objects, y_objects, label=\"Data\")\n",
+ " axs[i].plot(x, y_pred, label=\"Prediction\")\n",
+ " if i == 0:\n",
+ " axs[i].legend()\n",
+ " axs[i].set_title(\"Degree = %d\" % degree)\n",
+ " axs[i].set_xlabel(\"$x$\")\n",
+ " axs[i].set_ylabel(\"$f(x)$\")\n",
+ " axs[i].set_ylim(-2, 2)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Чтобы избежать переобучения, модель регуляризуют. Обычно переобучения\n",
+ "в линейных моделях связаны с большими весами, а поэтому модель часто\n",
+ "штрафуют за большие значения весов, добавляя к функционалу качества,\n",
+ "например, квадрат $\\ell^2$-нормы вектора $w$:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "\n",
+ "\n",
+ "$$\n",
+ "\\label{ml:linear-regression:eq:2} \\tag{2}\n",
+ "Q_{reg}(X, y, a) = Q(X, y, a) + \\lambda \\|w\\|_2^2\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Это слагаемое называют $\\ell_2$-регуляризатором, а коэффициент\n",
+ "$\\lambda$ --- коэффициентом регуляризации.\n",
+ "\n",
+ "## Загрузка данных\n",
+ "\n",
+ "\n",
+ "Мы будем работать с данными из соревнования\n",
+ "[House Prices: Advanced Regression Techniques](https://www.kaggle.com/c/house-prices-advanced-regression-techniques/overview),\n",
+ "в котором требовалось предсказать стоимость жилья. Давайте сначала\n",
+ "загрузим и немного изучим данные (`train.csv` со страницы соревнования)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "data = pd.read_csv(\"train.csv\")\n",
+ "data.head()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Первое, что стоит заметить — у нас в данных есть уникальное для\n",
+ "каждого объекта поле `id`. Обычно такие поля только мешают и\n",
+ "способствуют переобучению. Удалим это поле из данных:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "data = data.drop(columns=[\"Id\"])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Разделим данные на обучающую и тестовую выборки. Для простоты не будем\n",
+ "выделять дополнительно валидационную выборку (хотя это обычно стоит\n",
+ "делать, она нужна для подбора гиперпараметров модели, то есть\n",
+ "параметров, которые нельзя подбирать по обучающей\n",
+ "выборке). Дополнительно нам придется отделить значения целевой\n",
+ "переменной от данных."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.model_selection import train_test_split\n",
+ "\n",
+ "y = data[\"SalePrice\"]\n",
+ "X = data.drop(columns=[\"SalePrice\"])\n",
+ "\n",
+ "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=10)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Посмотрим сначала на значения целевой переменной:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "sns.distplot(y_train)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Судя по гистограмме, у нас есть примеры с нетипично большой\n",
+ "стоимостью, что может помешать нам, если наша функция потерь слишком\n",
+ "чувствительна к выбросам. В дальнейшем мы рассмотрим способы, как\n",
+ "минимизировать ущерб от этого.\n",
+ "\n",
+ "Так как для решения нашей задачи мы бы хотели обучить линейную\n",
+ "регрессию, было бы хорошо найти признаки, «наиболее линейно» связанные\n",
+ "с целевой переменной, иначе говоря, посмотреть на коэффициент\n",
+ "корреляции Пирсона между признаками и целевой переменной. Заметим, что\n",
+ "не все признаки являются числовыми, пока что мы не будем рассматривать\n",
+ "такие признаки.\n",
+ "\n",
+ "> **Коэффициент корреляции Пирсона.**\n",
+ ">\n",
+ "> Коэффициент корреляции Пирсона характеризует существование линейной\n",
+ "> зависимости между двумя величинами.\n",
+ "> \n",
+ "> Пусть даны две выборки $x = (x_1, x_2, \\ldots, x_m)$ и $y = (y_1, y_2,\n",
+ "> \\ldots, y_m$; коэффициент корреляции Пирсона по формуле:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "r_{xy} = \\frac{\\sum_{i=1}^{m}(x_i-\\bar{x})(y_i -\n",
+ "\\bar{y})}{\\sqrt{\\sum_{i=1}^{m}(x_i - \\bar{x})^2 \\sum_{i=1}^{m}(y_i -\n",
+ "\\bar{y})^2}} = \\frac{cov(x, y)}{\\sqrt{s_x^2s_y^2}},\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "> где $\\bar{x}$, $\\bar{y}$ — выборочные средние, $s_x^2$, $s_y^2$ —\n",
+ "> выборочные дисперсии, $r_{xy} \\in [-1, 1]$.\n",
+ "> * $|r_{xy}| = 1 \\Rightarrow$ $x$, $y$ — линейно зависимы,\n",
+ "> \n",
+ "> * $|r_{xy}| = 0 \\Rightarrow$ $x$, $y$ — линейно не зависимы."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "numeric_data = X_train.select_dtypes([np.number])\n",
+ "numeric_data_mean = numeric_data.mean()\n",
+ "numeric_features = numeric_data.columns\n",
+ "\n",
+ "X_train = X_train.fillna(numeric_data_mean)\n",
+ "X_test = X_test.fillna(numeric_data_mean)\n",
+ "\n",
+ "correlations = {\n",
+ " feature: np.corrcoef(X_train[feature], y_train)[0][1]\n",
+ " for feature in numeric_features\n",
+ "}\n",
+ "sorted_correlations = sorted(correlations.items(), key=lambda x: x[1], reverse=True)\n",
+ "features_order = [x[0] for x in sorted_correlations]\n",
+ "correlations = [x[1] for x in sorted_correlations]\n",
+ "\n",
+ "plot = sns.barplot(y=features_order, x=correlations)\n",
+ "plot.figure.set_size_inches(15, 10)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Посмотрим на признаки из начала списка. Для этого нарисуем график\n",
+ "зависимости целевой переменной от каждого из признаков. На этом\n",
+ "графике каждая точка соответствует паре признак-таргет (такие графики\n",
+ "называются `scatter-plot`)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "fig, axs = plt.subplots(figsize=(16, 5), ncols=3)\n",
+ "for i, feature in enumerate([\"GrLivArea\", \"GarageArea\", \"TotalBsmtSF\"]):\n",
+ " axs[i].scatter(X_train[feature], y_train, alpha=0.2)\n",
+ " axs[i].set_xlabel(feature)\n",
+ " axs[i].set_ylabel(\"SalePrice\")\n",
+ "plt.tight_layout()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Видим, что между этими признаками и целевой переменной действительно\n",
+ "наблюдается линейная зависимость. \n",
+ "\n",
+ "## Первая модель\n",
+ "\n",
+ "\n",
+ "В арсенале дата-саентиста кроме `pandas` и `matplotlib` должны быть\n",
+ "библиотеки, позволяющие обучать модели. Для простых моделей (линейные\n",
+ "модели, решающее дерево, ...) отлично подходит `sklearn`: в нем очень\n",
+ "понятный и простой интерфейс. Несмотря на то, что в `sklearn` есть\n",
+ "реализация бустинга и простых нейронных сетей, ими все же не\n",
+ "пользуются и предпочитают специализированные библиотеки: `XGBoost`,\n",
+ "`LightGBM` и пр. для градиентного бустинга над деревьями, `PyTorch`,\n",
+ "`Tensorflow` и пр. для нейронных сетей. Так как мы будем обучать\n",
+ "линейную регрессию, нам подойдет реализация из `sklearn`. \n",
+ "\n",
+ "\n",
+ "Попробуем обучить линейную регрессию на числовых признаках из нашего\n",
+ "датасета. В `sklearn` есть несколько классов, реализующих линейную\n",
+ "регрессию: \n",
+ "\n",
+ "* [`LinearRegression`](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html) — «классическая» линейная регрессия с оптимизацией MSE. Веса находятся как точное решение: $w^* = (X^TX)^{-1}X^Ty$\n",
+ "\n",
+ "* [`Ridge`](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.Ridge.html) — линейная регрессия с оптимизацией MSE и $\\ell_2$-регуляризацией\n",
+ "\n",
+ "* [`Lasso`](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.Lasso.html) — линейная регрессия с оптимизацией MSE и $\\ell_1$-регуляризацией\n",
+ "\n",
+ "У моделей из `sklearn` есть методы `fit` и `predict`. Первый принимает\n",
+ "на вход обучающую выборку и вектор целевых переменных и обучает\n",
+ "модель, второй, будучи вызванным после обучения модели, возвращает\n",
+ "предсказание на выборке. Попробуем обучить нашу первую модель на\n",
+ "числовых признаках, которые у нас сейчас есть:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.linear_model import Ridge\n",
+ "from sklearn.metrics import mean_squared_error\n",
+ "\n",
+ "model = Ridge()\n",
+ "model.fit(X_train[numeric_features], y_train)\n",
+ "y_pred = model.predict(X_test[numeric_features])\n",
+ "y_train_pred = model.predict(X_train[numeric_features])\n",
+ "\n",
+ "print(\"Test MSE = %.4f\" % mean_squared_error(y_test, y_pred))\n",
+ "print(\"Train MSE = %.4f\" % mean_squared_error(y_train, y_train_pred))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Мы обучили первую модель и даже посчитали ее качество на отложенной\n",
+ "выборке! Давайте теперь посмотрим на то, как можно оценить качество\n",
+ "модели с помощью кросс-валидации. Принцип кросс-валидации изображен на\n",
+ "рисунке\n",
+ "\n",
+ "
\n",
+ "\n",
+ "При кросс-валидации мы делим обучающую выборку на $n$ частей\n",
+ "(fold). Затем мы обучаем $n$ моделей: каждая модель обучается при\n",
+ "отсутствии соответствующего фолда, то есть $i$-ая модель обучается на\n",
+ "всей обучающей выборке, кроме объектов, которые попали в $i$-ый фолд\n",
+ "(out-of-fold). Затем мы измеряем качество $i$-ой модели на $i$-ом\n",
+ "фолде. Так как он не участвовал в обучении этой модели, мы получим\n",
+ "«честный результат». После этого, для получения финального значения\n",
+ "метрики качества, мы можем усреднить полученные нами $n$ значений."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.model_selection import cross_val_score\n",
+ "\n",
+ "cv_scores = cross_val_score(model, X_train[numeric_features], y_train, cv=10, scoring=\"neg_mean_squared_error\")\n",
+ "print(\"Cross validation scores:\\n\\t\", \"\\n\\t\".join(\"%.4f\" % x for x in cv_scores))\n",
+ "print(\"Mean CV MSE = %.4f\" % np.mean(-cv_scores))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Обратите внимание на то, что результаты `cv_scores` получились\n",
+ "отрицательными. Это соглашение в `sklearn` (скоринговую функцию нужно\n",
+ "максимизировать). Поэтому все стандартные скореры называются `neg_*`,\n",
+ "например, `neg_mean_squared_error`.\n",
+ "\n",
+ "В качестве метрики качества в соревновании использовалось RMSE (\n",
+ "Root Mean Squared Error), а не MSE, которое мы считали выше (и по\n",
+ "отложенной выборке и при кросс-валидации):"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\text{RMSE}(X, y, a) = \\sqrt{\\frac{1}{\\ell}\\sum_{i=1}^{\\ell} (y_i -\n",
+ "a(x_i))^2}\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "RMSE в чистом виде не входит в стандартные метрики `sklearn`, но мы\n",
+ "всегда можем определить свою метрику и использовать ее в некоторых\n",
+ "функциях `sklearn`, например, `cross_val_score`. Для этого нужно\n",
+ "воспользоваться `sklearn.metrics.make_scorer`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.metrics import make_scorer\n",
+ "\n",
+ "def rmse(y_true, y_pred):\n",
+ " error = (y_true - y_pred) ** 2\n",
+ " return np.sqrt(np.mean(error))\n",
+ "\n",
+ "rmse_scorer = make_scorer(\n",
+ " rmse,\n",
+ " greater_is_better=False\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.linear_model import Ridge\n",
+ "\n",
+ "model = Ridge()\n",
+ "model.fit(X_train[numeric_features], y_train)\n",
+ "y_pred = model.predict(X_test[numeric_features])\n",
+ "y_train_pred = model.predict(X_train[numeric_features])\n",
+ "\n",
+ "print(\"Test RMSE = %.4f\" % rmse(y_test, y_pred))\n",
+ "print(\"Train RMSE = %.4f\" % rmse(y_train, y_train_pred))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.model_selection import cross_val_score\n",
+ "\n",
+ "cv_scores = cross_val_score(model, X_train[numeric_features], y_train, cv=10, scoring=rmse_scorer)\n",
+ "print(\"Cross validation scores:\\n\\t\", \"\\n\\t\".join(\"%.4f\" % x for x in cv_scores))\n",
+ "print(\"Mean CV RMSE = %.4f\" % np.mean(-cv_scores))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Для того, чтобы иметь некоторую точку отсчета, удобно посчитать\n",
+ "оптимальное значение функции потерь при константном предсказании."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "best_constant = y_train.mean()\n",
+ "print(\"Test RMSE with best constant = %.4f\" % rmse(y_test, best_constant))\n",
+ "print(\"Train RMSE with best constant = %.4f\" % rmse(y_train, best_constant))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Давайте посмотрим на то, какие же признаки оказались самыми\n",
+ "«сильными». Для этого визуализируем веса, соответствующие\n",
+ "признакам. Чем больше вес — тем более сильным является признак."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "def show_weights(features, weights, scales):\n",
+ " fig, axs = plt.subplots(figsize=(14, 10), ncols=2)\n",
+ " sorted_weights = sorted(zip(weights, features, scales), reverse=True)\n",
+ " weights = [x[0] for x in sorted_weights]\n",
+ " features = [x[1] for x in sorted_weights]\n",
+ " scales = [x[2] for x in sorted_weights]\n",
+ " sns.barplot(y=features, x=weights, ax=axs[0])\n",
+ " axs[0].set_xlabel(\"Weight\")\n",
+ " sns.barplot(y=features, x=scales, ax=axs[1])\n",
+ " axs[1].set_xlabel(\"Scale\")\n",
+ " plt.tight_layout()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "show_weights(numeric_features, model.coef_, X_train[numeric_features].std())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Будем масштабировать наши признаки перед обучением модели. Это, среди,\n",
+ "прочего, сделает нашу регуляризацию более честной: теперь все признаки\n",
+ "будут регуляризоваться в равной степени.\n",
+ "\n",
+ "Для этого воспользуемся трансформером\n",
+ "[`StandardScaler`](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.StandardScaler.html).\n",
+ "Трансформеры в `sklearn` имеют методы `fit` и `transform` (а еще\n",
+ "`fit_transform`). Метод `fit` принимает на вход обучающую выборку и\n",
+ "считает по ней необходимые значения (например статистики, как\n",
+ "`StandardScaler`: среднее и стандартное отклонение каждого из\n",
+ "признаков); `transform` применяет преобразование к переданной\n",
+ "выборке."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.preprocessing import StandardScaler\n",
+ "\n",
+ "scaler = StandardScaler()\n",
+ "X_train_scaled = scaler.fit_transform(X_train[numeric_features])\n",
+ "X_test_scaled = scaler.transform(X_test[numeric_features])\n",
+ "\n",
+ "model = Ridge()\n",
+ "model.fit(X_train_scaled, y_train)\n",
+ "y_pred = model.predict(X_test_scaled)\n",
+ "y_train_pred = model.predict(X_train_scaled)\n",
+ "\n",
+ "print(\"Test RMSE = %.4f\" % rmse(y_test, y_pred))\n",
+ "print(\"Train RMSE = %.4f\" % rmse(y_train, y_train_pred))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "scales = pd.Series(data=X_train_scaled.std(axis=0), index=numeric_features)\n",
+ "show_weights(numeric_features, model.coef_, scales)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Наряду с параметрами (веса $w$, $w_0$), которые модель оптимизирует на\n",
+ "этапе обучения, у модели есть и гиперпараметры. У нашей модели это\n",
+ "`alpha` — коэффициент регуляризации. Подбирают его обычно по\n",
+ "сетке, измеряя качество на валидационной (не тестовой) выборке или с\n",
+ "помощью кросс-валидации. Посмотрим, как это можно сделать (заметьте,\n",
+ "что мы перебираем `alpha` по логарифмической сетке, чтобы узнать\n",
+ "оптимальный порядок величины)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.model_selection import GridSearchCV\n",
+ "\n",
+ "alphas = np.logspace(-2, 3, 20)\n",
+ "searcher = GridSearchCV(Ridge(), [{\"alpha\": alphas}], scoring=rmse_scorer, cv=10)\n",
+ "searcher.fit(X_train_scaled, y_train)\n",
+ "\n",
+ "best_alpha = searcher.best_params_[\"alpha\"]\n",
+ "print(\"Best alpha = %.4f\" % best_alpha)\n",
+ "\n",
+ "plt.plot(alphas, -searcher.cv_results_[\"mean_test_score\"])\n",
+ "plt.xscale(\"log\")\n",
+ "plt.xlabel(\"alpha\")\n",
+ "plt.ylabel(\"CV score\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Попробуем обучить модель с подобранным коэффициентом\n",
+ "регуляризации. Заодно воспользуемся очень удобным классом\n",
+ "[`Pipeline`](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html):\n",
+ "обучение модели часто представляется как последовательность некоторых\n",
+ "действий с обучающей и тестовой выборками (например, сначала нужно\n",
+ "отмасштабировать выборку (причем для обучающей выборки нужно применить\n",
+ "метод `fit`, а для тестовой --- `transform`), а затем\n",
+ "обучить/применить модель (для обучающей `fit`, а для тестовой ---\n",
+ "`predict`). `Pipeline` позволяет хранить эту последовательность шагов\n",
+ "и корректно обрабатывает разные типы выборок: и обучающую, и\n",
+ "тестовую."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.pipeline import Pipeline\n",
+ "\n",
+ "simple_pipeline = Pipeline([\n",
+ " ('scaling', StandardScaler()),\n",
+ " ('regression', Ridge(best_alpha))\n",
+ "])\n",
+ "\n",
+ "model = simple_pipeline.fit(X_train[numeric_features], y_train)\n",
+ "y_pred = model.predict(X_test[numeric_features])\n",
+ "print(\"Test RMSE = %.4f\" % rmse(y_test, y_pred))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Работа с категориальными признаками\n",
+ "\n",
+ "\n",
+ "Сейчас мы явно вытягиваем из данных не всю информацию, что у нас есть,\n",
+ "просто потому, что мы не используем часть признаков. Эти признаки в\n",
+ "датасете закодированы строками, каждый из них обозначает некоторую\n",
+ "категорию. Такие признаки называются категориальными. Давайте выделим\n",
+ "такие признаки и сразу заполним пропуски в них специальным значением\n",
+ "(то, что у признака пропущено значение, само по себе может быть\n",
+ "хорошим признаком)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "categorical = list(X_train.dtypes[X_train.dtypes == \"object\"].index)\n",
+ "X_train[categorical] = X_train[categorical].fillna(\"NotGiven\")\n",
+ "X_test[categorical] = X_test[categorical].fillna(\"NotGiven\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "X_train[categorical].sample(5)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Сейчас нам нужно как-то закодировать эти категориальные признаки\n",
+ "числами, ведь линейная модель не может работать с такими\n",
+ "абстракциями. Два стандартных трансформера из `sklearn` для работы с\n",
+ "категориальными признаками\n",
+ "* [`LabelEncoder`](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.LabelEncoder.html) просто перенумеровывает значения признака натуральными числами\n",
+ "\n",
+ "* [`OneHotEncoder`](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html) ставит в соответствие каждому признаку целый вектор, состоящий из нулей и одной единицы (которая стоит на месте, соответствующем принимаемому значению, таким образом кодируя его)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.preprocessing import OneHotEncoder\n",
+ "from sklearn.compose import ColumnTransformer\n",
+ "\n",
+ "column_transformer = ColumnTransformer([\n",
+ " ('ohe', OneHotEncoder(handle_unknown=\"ignore\"), categorical),\n",
+ " ('scaling', StandardScaler(), numeric_features)\n",
+ "])\n",
+ "\n",
+ "pipeline = Pipeline(steps=[\n",
+ " ('ohe_and_scaling', column_transformer),\n",
+ " ('regression', Ridge())\n",
+ "])\n",
+ "\n",
+ "model = pipeline.fit(X_train, y_train)\n",
+ "y_pred = model.predict(X_test)\n",
+ "print(\"Test RMSE = %.4f\" % rmse(y_test, y_pred))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Посмотрим на размеры матрицы после OneHot-кодирования:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "print(\"Size before OneHot:\", X_train.shape)\n",
+ "print(\"Size after OneHot:\", column_transformer.transform(X_train).shape)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Как видим, количество признаков увеличилось более, чем в 3 раза. Это\n",
+ "может повысить риски переобучиться: соотношение количества объектов к\n",
+ "количеству признаков сильно сократилось. \n",
+ "\n",
+ "Попытаемся обучить линейную регрессию с $\\ell_1$-регуляризатором. На\n",
+ "лекциях вы узнаете, что $\\ell_1$-регуляризатор разреживает признаковое\n",
+ "пространство, иными словами, такая модель зануляет часть весов."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.linear_model import Lasso\n",
+ "\n",
+ "column_transformer = ColumnTransformer([\n",
+ " ('ohe', OneHotEncoder(handle_unknown=\"ignore\"), categorical),\n",
+ " ('scaling', StandardScaler(), numeric_features)\n",
+ "])\n",
+ "\n",
+ "lasso_pipeline = Pipeline(steps=[\n",
+ " ('ohe_and_scaling', column_transformer),\n",
+ " ('regression', Lasso())\n",
+ "])\n",
+ "\n",
+ "model = lasso_pipeline.fit(X_train, y_train)\n",
+ "y_pred = model.predict(X_test)\n",
+ "print(\"RMSE = %.4f\" % rmse(y_test, y_pred))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "ridge_zeros = np.sum(pipeline.steps[-1][-1].coef_ == 0)\n",
+ "lasso_zeros = np.sum(lasso_pipeline.steps[-1][-1].coef_ == 0)\n",
+ "print(\"Zero weights in Ridge:\", ridge_zeros)\n",
+ "print(\"Zero weights in Lasso:\", lasso_zeros)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Подберем для нашей модели оптимальный коэффициент\n",
+ "регуляризации. Обратите внимание, как перебираются параметры у\n",
+ "`Pipeline`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "alphas = np.logspace(-2, 4, 20)\n",
+ "searcher = GridSearchCV(lasso_pipeline, [{\"regression__alpha\": alphas}], scoring=rmse_scorer, cv=10)\n",
+ "searcher.fit(X_train, y_train)\n",
+ "\n",
+ "best_alpha = searcher.best_params_[\"regression__alpha\"]\n",
+ "print(\"Best alpha = %.4f\" % best_alpha)\n",
+ "\n",
+ "plt.plot(alphas, -searcher.cv_results_[\"mean_test_score\"])\n",
+ "plt.xscale(\"log\")\n",
+ "plt.xlabel(\"alpha\")\n",
+ "plt.ylabel(\"CV score\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "column_transformer = ColumnTransformer([\n",
+ " ('ohe', OneHotEncoder(handle_unknown=\"ignore\"), categorical),\n",
+ " ('scaling', StandardScaler(), numeric_features)\n",
+ "])\n",
+ "\n",
+ "pipeline = Pipeline(steps=[\n",
+ " ('ohe_and_scaling', column_transformer),\n",
+ " ('regression', Lasso(best_alpha))\n",
+ "])\n",
+ "\n",
+ "model = pipeline.fit(X_train, y_train)\n",
+ "y_pred = model.predict(X_test)\n",
+ "print(\"Test RMSE = %.4f\" % rmse(y_test, y_pred))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "lasso_zeros = np.sum(pipeline.steps[-1][-1].coef_ == 0)\n",
+ "print(\"Zero weights in Lasso:\", lasso_zeros)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Иногда очень полезно посмотреть на распределение остатков. Нарисуем\n",
+ "гистограмму распределения квадратичной ошибки на обучающих объектах:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "error = (y_train - model.predict(X_train)) ** 2\n",
+ "sns.distplot(error)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Как видно из гистограммы, есть примеры с очень большими\n",
+ "остатками. Попробуем их выбросить из обучающей выборки. Например,\n",
+ "выбросим примеры, остаток у которых больше 0.95-квантили."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 32,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "mask = (error < np.quantile(error, 0.95))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 33,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "column_transformer = ColumnTransformer([\n",
+ " ('ohe', OneHotEncoder(handle_unknown=\"ignore\"), categorical),\n",
+ " ('scaling', StandardScaler(), numeric_features)\n",
+ "])\n",
+ "\n",
+ "pipeline = Pipeline(steps=[\n",
+ " ('ohe_and_scaling', column_transformer),\n",
+ " ('regression', Lasso(best_alpha))\n",
+ "])\n",
+ "\n",
+ "model = pipeline.fit(X_train[mask], y_train[mask])\n",
+ "y_pred = model.predict(X_test)\n",
+ "print(\"Test RMSE = %.4f\" % rmse(y_test, y_pred))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 34,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "X_train = X_train[mask]\n",
+ "y_train = y_train[mask]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 35,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "error = (y_train - model.predict(X_train)) ** 2\n",
+ "sns.distplot(error)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Видим, что качество модели заметно улучшилось! Также бывает очень\n",
+ "полезно посмотреть на примеры с большими остатками и попытаться\n",
+ "понять, почему же модель на них так сильно ошибается: это может дать\n",
+ "понимание, как модель можно улучшить. \n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "# Предобработка данных\n",
+ "\n",
+ "\n",
+ "\n",
+ "Начнем с подключения необходимых библиотек и модулей:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 36,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "import pandas as pd\n",
+ "import seaborn as sns\n",
+ "from tqdm import tqdm\n",
+ "from sklearn.datasets import fetch_20newsgroups\n",
+ "\n",
+ "from sklearn.model_selection import train_test_split\n",
+ "from sklearn.linear_model import Ridge\n",
+ "from sklearn.metrics import mean_squared_error"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Работа с текстовыми данными\n",
+ "\n",
+ "\n",
+ "\n",
+ "Как правило, модели машинного обучения действуют в предположении, что\n",
+ "матрица «объект-признак» является вещественнозначной, поэтому при\n",
+ "работе с текстами сперва для каждого из них необходимо составить его\n",
+ "признаковое описание. Для этого широко используются техники\n",
+ "векторизации, tf-idf и пр.\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "Сперва загрузим данные:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 37,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "data = fetch_20newsgroups(subset='all', categories=['comp.graphics', 'sci.med'])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Данные содержат тексты новостей, которые надо классифицировать на разделы."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 38,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "data['target_names']"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 39,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "texts = data['data']\n",
+ "target = data['target']"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Например:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 40,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "texts[0]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 41,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "data['target_names'][target[0]]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Bag-of-words\n",
+ "\n",
+ "\n",
+ "\n",
+ "Самый очевидный способ формирования признакового описания текстов —\n",
+ "векторизация. Простой способ заключается в подсчёте, сколько раз встретилось каждое слово\n",
+ "в тексте. Получаем вектор длиной в количество уникальных слов, встречающихся во\n",
+ "всех объектах выборки. В таком векторе много нулей, поэтому его удобнее хранить\n",
+ "в разреженном виде. \n",
+ "\n",
+ "Пусть у нас имеется коллекция текстов $D = \\{d_i\\}_{i=1}^l$\n",
+ "и словарь всех слов, встречающихся в выборке $V = \\{v_j\\}_{j=1}^d.$ В\n",
+ "этом случае некоторый текст $d_i$ описывается вектором\n",
+ "$(x_{ij})_{j=1}^d,$ где"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "x_{ij} = \\sum_{v \\in d_i} [v = v_j].\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Таким образом, текст $d_i$ описывается вектором количества вхождений\n",
+ "каждого слова из словаря в данный текст."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 42,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.feature_extraction.text import CountVectorizer\n",
+ "\n",
+ "vectorizer = CountVectorizer(encoding='utf8', min_df=1)\n",
+ "_ = vectorizer.fit(texts)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Результатом является разреженная матрица."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 43,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "vectorizer.transform(texts[:1])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 44,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "print(vectorizer.transform(texts[:1]).indptr)\n",
+ "print(vectorizer.transform(texts[:1]).indices)\n",
+ "print(vectorizer.transform(texts[:1]).data)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Такой способ представления текстов называют *мешком слов* (bag-of-words).\n",
+ "\n",
+ "### TF-IDF\n",
+ "\n",
+ "\n",
+ "\n",
+ "Очевидно, что не все слова полезны в задаче прогнозирования. Например, мало\n",
+ "информации несут слова, встречающиеся во всех текстах. Это могут быть\n",
+ "как стоп-слова, так и слова, свойственные всем текстам выборки (в\n",
+ "текстах про автомобили употребляется слово «автомобиль»). Эту проблему\n",
+ "решает TF-IDF (*T*erm *F*requency–*I*nverse *D*ocument *F*requency)\n",
+ "преобразование текста.\n",
+ "\n",
+ "Рассмотрим коллекцию текстов $D$. Для каждого уникального слова $t$\n",
+ "из документа $d \\in D$ вычислим следующие величины: \n",
+ "\n",
+ "* TD (Term Frequency) – количество вхождений слова в отношении к общему числу слов в тексте:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\textrm{tf}(t, d) = \\frac{n_{td}}{\\sum_{t \\in d} n_{td}},\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "где $n_{td}$ — количество вхождений слова $t$ в текст $d$.\n",
+ "\n",
+ "* IDF (Inverse Document Frequency):"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\textrm{idf}(t, D) = \\log \\frac{\\left| D \\right|}{\\left| \\{d\\in D: t \\in d\\} \\right|},\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "где $\\left| \\{d\\in D: t \\in d\\} \\right|$ – количество текстов в коллекции, содержащих слово $t$.\n",
+ "\n",
+ "Тогда для каждой пары (слово, текст) $(t, d)$ вычислим величину:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\textrm{tf-idf}(t,d, D) = \\text{tf}(t, d)\\cdot \\text{idf}(t, D).\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Отметим, что значение $\\text{tf}(t, d)$ корректируется для часто\n",
+ "встречающихся общеупотребимых слов при помощи значения\n",
+ "$\\textrm{idf}(t, D)$."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 45,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.feature_extraction.text import TfidfVectorizer\n",
+ "\n",
+ "vectorizer = TfidfVectorizer(encoding='utf8', min_df=1)\n",
+ "_ = vectorizer.fit(texts)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "На выходе получаем разреженную матрицу."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 46,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "vectorizer.transform(texts[:1])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 47,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "print(vectorizer.transform(texts[:1]).indptr)\n",
+ "print(vectorizer.transform(texts[:1]).indices)\n",
+ "print(vectorizer.transform(texts[:1]).data)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Заметим, что оба метода возвращают вектор длины 32548 (размер нашего словаря).\n",
+ "\n",
+ "Заметим, что одно и то же слово может встречаться в различных формах\n",
+ "(например, «сотрудник» и «сотрудника»), но описанные выше методы\n",
+ "интерпретируют их как различные слова, что делает признаковое описание\n",
+ "избыточным. Устранить эту проблему можно при помощи **лемматизации** и\n",
+ "**стемминга**. \n",
+ "\n",
+ "\n",
+ "### Стемминг\n",
+ "\n",
+ "\n",
+ "\n",
+ "*Стемминг* — это процесс нахождения основы слова. В результате применения\n",
+ "данной процедуры однокоренные слова, как правило, преобразуются к одинаковому\n",
+ "виду. \n",
+ "\n",
+ "\n",
+ "## Таблица 1 : Примеры стемминга\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "| Слово | Основа |
\n",
+ "\n",
+ "\n",
+ "| вагон | вагон |
\n",
+ "| вагона | вагон |
\n",
+ "| вагоне | вагон |
\n",
+ "| вагонов | вагон |
\n",
+ "| вагоном | вагон |
\n",
+ "| вагоны | вагон |
\n",
+ "| важная | важн |
\n",
+ "| важнее | важн |
\n",
+ "| важнейшие | важн |
\n",
+ "| важнейшими | важн |
\n",
+ "| важничал | важнича |
\n",
+ "| важно | важн |
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "\n",
+ "\n",
+ "[Snowball](http://snowball.tartarus.org/) — фрэймворк для написания\n",
+ "алгоритмов стемминга (библиотека `nltk`). Алгоритмы стемминга отличаются для разных языков\n",
+ "и используют знания о конкретном языке — списки окончаний для разных\n",
+ "чистей речи, разных склонений и т.д. Пример алгоритма для русского\n",
+ "языка – [Russian stemming](http://snowballstem.org/algorithms/russian/stemmer.html)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 48,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "import nltk\n",
+ "stemmer = nltk.stem.snowball.RussianStemmer()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 49,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "print(stemmer.stem(u'машинное'), stemmer.stem(u'обучение'))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 50,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "stemmer = nltk.stem.snowball.EnglishStemmer()\n",
+ "\n",
+ "def stem_text(text, stemmer):\n",
+ " tokens = text.split()\n",
+ " return ' '.join(map(lambda w: stemmer.stem(w), tokens))\n",
+ "\n",
+ "stemmed_texts = []\n",
+ "for t in tqdm(texts[:1000]):\n",
+ " stemmed_texts.append(stem_text(t, stemmer))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 51,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "print(texts[0])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 52,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "print(stemmed_texts[0])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Как видим, стеммер работает не очень быстро и запускать его для всей\n",
+ "выборки достаточно накладно. \n",
+ "\n",
+ "\n",
+ "### Лематизация\n",
+ "\n",
+ "\n",
+ "\n",
+ "*Лемматизация* — процесс приведения слова к его нормальной форме (лемме):\n",
+ "* для существительных — именительный падеж, единственное число;\n",
+ "\n",
+ "* для прилагательных — именительный падеж, единственное число, мужской род;\n",
+ "\n",
+ "* для глаголов, причастий, деепричастий — глагол в инфинитиве.\n",
+ "\n",
+ "Лемматизация — процесс более сложный по сравнению со стеммингом. Стеммер\n",
+ "просто «режет» слово до основы.\n",
+ "\n",
+ "Например, для русского языка есть библиотека `pymorphy2`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 53,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "import pymorphy2\n",
+ "morph = pymorphy2.MorphAnalyzer()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 54,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "morph.parse('играющих')[0]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Сравним работу стеммера и лемматизатора на примере:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 55,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "stemmer = nltk.stem.snowball.RussianStemmer()\n",
+ "print(stemmer.stem('играющих'))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 56,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "print(morph.parse('играющих')[0].normal_form)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Трансформация признаков и целевой переменной\n",
+ "\n",
+ "\n",
+ "Разберёмся, как может влиять трансформация признаков или целевой\n",
+ "переменной на качество модели.\n",
+ "\n",
+ "### Логарифмирование\n",
+ "\n",
+ "\n",
+ "\n",
+ "Воспользуется датасетом с ценами на дома, с которым мы уже\n",
+ "сталкивались ранее\n",
+ "([House Prices: Advanced Regression Techniques](https://www.kaggle.com/c/house-prices-advanced-regression-techniques/overview))."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 57,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "!wget https://slemeshevsky.github.io/python-course/ml/html/src-ml/train.csv"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 58,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "data = pd.read_csv('train.csv')\n",
+ "\n",
+ "data = data.drop(columns=[\"Id\"])\n",
+ "y = data[\"SalePrice\"]\n",
+ "X = data.drop(columns=[\"SalePrice\"])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Посмотрим на распределение целевой переменной"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 59,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "plt.figure(figsize=(12, 5))\n",
+ "\n",
+ "plt.subplot(1, 2, 1)\n",
+ "sns.distplot(y, label='target')\n",
+ "plt.title('target')\n",
+ "\n",
+ "plt.subplot(1, 2, 2)\n",
+ "sns.distplot(data.GrLivArea, label='area')\n",
+ "plt.title('area')\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Видим, что распределения несимметричные с тяжёлыми правыми хвостами.\n",
+ "\n",
+ "Оставим только числовые признаки, пропуски заменим средним значением."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 60,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "X_train, X_test, y_train, y_test = train_test_split(\n",
+ " X, y, test_size=0.3, random_state=10)\n",
+ "\n",
+ "numeric_data = X_train.select_dtypes([np.number])\n",
+ "numeric_data_mean = numeric_data.mean()\n",
+ "numeric_features = numeric_data.columns\n",
+ "\n",
+ "X_train = X_train.fillna(numeric_data_mean)[numeric_features]\n",
+ "X_test = X_test.fillna(numeric_data_mean)[numeric_features]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Если разбирать линейную регрессия с\n",
+ "вероятностной точки зрения, то можно получить, что шум должен быть\n",
+ "распределён нормально. Поэтому лучше, когда целевая переменная\n",
+ "распределена также нормально.\n",
+ "\n",
+ "Если прологарифмировать целевую переменную, то её распределение станет\n",
+ "больше похоже на нормальное:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 61,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "sns.distplot(np.log(y+1), label='target')\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Сравним качество линейной регрессии в двух случаях:\n",
+ "* Целевая переменная без изменений.\n",
+ "\n",
+ "* Целевая переменная прологарифмирована.\n",
+ "\n",
+ "> **Предупреждение.**\n",
+ ">\n",
+ "> Не забудем во втором случае взять экспоненту от предсказаний!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 62,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "model = Ridge()\n",
+ "model.fit(X_train, y_train)\n",
+ "y_pred = model.predict(X_test)\n",
+ "\n",
+ "print(\"Test RMSE = %.4f\" % mean_squared_error(y_test, y_pred) ** 0.5)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 63,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "model = Ridge()\n",
+ "model.fit(X_train, np.log(y_train+1))\n",
+ "y_pred = np.exp(model.predict(X_test))-1\n",
+ "\n",
+ "print(\"Test RMSE = %.4f\" % mean_squared_error(y_test, y_pred) ** 0.5)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Попробуем аналогично логарифмировать один из признаков, имеющих также\n",
+ "смещённое распределение (этот признак был вторым по важности!)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 64,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "X_train.GrLivArea = np.log(X_train.GrLivArea + 1)\n",
+ "X_test.GrLivArea = np.log(X_test.GrLivArea + 1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 65,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "model = Ridge()\n",
+ "model.fit(X_train[numeric_features], y_train)\n",
+ "y_pred = model.predict(X_test[numeric_features])\n",
+ "\n",
+ "print(\"Test RMSE = %.4f\" % mean_squared_error(y_test, y_pred) ** 0.5)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 66,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "model = Ridge()\n",
+ "model.fit(X_train[numeric_features], np.log(y_train+1))\n",
+ "y_pred = np.exp(model.predict(X_test[numeric_features]))-1\n",
+ "\n",
+ "print(\"Test RMSE = %.4f\" % mean_squared_error(y_test, y_pred) ** 0.5)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Как видим, преобразование признаков влияет слабее. Признаков много, а\n",
+ "вклад размывается по всем. К тому же, проверять распределение\n",
+ "множества признаков технически сложнее, чем одной целевой переменной. \n",
+ "\n",
+ "## Бинаризация\n",
+ "\n",
+ "\n",
+ "Мы уже смотрели, как полиномиальные признаки могут помочь при\n",
+ "восстановлении нелинейной зависимости линейной моделью. Альтернативный\n",
+ "подход заключается в бинаризации признаков. Мы разбиваем ось значений\n",
+ "одного из признаков на куски (бины) и добавляем для каждого куска-бина\n",
+ "новый признак-индикатор попадения в этот бин."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 67,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.linear_model import LinearRegression\n",
+ "\n",
+ "np.random.seed(36)\n",
+ "X = np.random.uniform(0, 1, size=100)\n",
+ "y = np.cos(1.5 * np.pi * X) + np.random.normal(scale=0.1, size=X.shape)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 68,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "plt.scatter(X, y)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 69,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "X = X.reshape((-1, 1))\n",
+ "thresholds = np.arange(0.2, 1.1, 0.2).reshape((1, -1))\n",
+ "\n",
+ "X_expand = np.hstack((\n",
+ " X,\n",
+ " ((X > thresholds[:, :-1]) & (X <= thresholds[:, 1:])).astype(int)))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 70,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.model_selection import KFold\n",
+ "from sklearn.model_selection import cross_val_score"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 71,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "-np.mean(cross_val_score(\n",
+ " LinearRegression(), X, y, cv=KFold(n_splits=3, random_state=123),\n",
+ " scoring='neg_mean_squared_error'))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 72,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "-np.mean(cross_val_score(\n",
+ " LinearRegression(), X_expand, y, cv=KFold(n_splits=3, random_state=123),\n",
+ " scoring='neg_mean_squared_error'))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Так линейная модель может лучше восстанавливать нелинейные зависимости.\n",
+ "\n",
+ "## Транзакционные данные\n",
+ "\n",
+ "\n",
+ "Напоследок посмотрим, как можно извлекать признаки из транзакционных данных.\n",
+ "\n",
+ "Транзакционные данные характеризуются тем, что есть много строк,\n",
+ "характеризующихся моментов времени и некоторым числом (суммой денег,\n",
+ "например). При этом если это банк, то каждому человеку принадлежит не\n",
+ "одна транзакция, а чаще всего надо предсказывать некоторые сущности\n",
+ "для клиентов. Таким образом, надо получить признаки для пользователей\n",
+ "из множества их транзакций. Этим мы и займёмся. \n",
+ "\n",
+ "Для примера возьмём данные [отсюда](https://www.kaggle.com/regivm/retailtransactiondata/). Задача\n",
+ "детектирования фродовых клиентов."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 73,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "!wget https://slemeshevsky.github.io/python-course/ml/html/src-ml/Retail_Data_Response.csv\n",
+ "!wget https://slemeshevsky.github.io/python-course/ml/html/src-ml/Retail_Data_Transactions.csv"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 74,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "customers = pd.read_csv('Retail_Data_Response.csv')\n",
+ "transactions = pd.read_csv('Retail_Data_Transactions.csv')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 75,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "customers.head()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 76,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "transactions.head()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 77,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "transactions.trans_date = transactions.trans_date.apply(\n",
+ " lambda x: datetime.datetime.strptime(x, '%d-%b-%y'))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Посмотрим на распределение целевой переменной:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 78,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "customers.response.mean()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Получаем примерно 1 к 9 положительных примеров. Если такие данные\n",
+ "разбивать на части для кросс валидации, то может получиться так, что в\n",
+ "одну из частей попадёт слишком мало положительных примеров, а в другую\n",
+ "— наоборот. На случай такого неравномерного баланса классов есть\n",
+ "`StratifiedKFold`, который бьёт данные так, чтобы баланс классов во всех\n",
+ "частях был одинаковым."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 79,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.model_selection import StratifiedKFold"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Когда строк на каждый объект много, можно считать различные\n",
+ "статистики. Например, средние, минимальные и максимальные суммы,\n",
+ "потраченные клиентом, количество транзакий, ..."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 80,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "agg_transactions = transactions.groupby('customer_id').tran_amount.agg(\n",
+ " ['mean', 'std', 'count', 'min', 'max']).reset_index()\n",
+ "\n",
+ "data = pd.merge(customers, agg_transactions, how='left', on='customer_id')\n",
+ "\n",
+ "data.head()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 81,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.linear_model import LogisticRegression\n",
+ "\n",
+ "np.mean(cross_val_score(\n",
+ " LogisticRegression(),\n",
+ " X=data.drop(['customer_id', 'response'], axis=1),\n",
+ " y=data.response,\n",
+ " cv=StratifiedKFold(n_splits=3, random_state=123),\n",
+ " scoring='roc_auc'))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Но каждая транзакция снабжена датой! Можно посчитать статистики только\n",
+ "по свежим транзакциям. Добавим их."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 82,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "transactions.trans_date.min(), transactions.trans_date.max()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 83,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "agg_transactions = transactions.loc[transactions.trans_date.apply(\n",
+ " lambda x: x.year == 2014)].groupby('customer_id').tran_amount.agg(\n",
+ " ['mean', 'std', 'count', 'min', 'max']).reset_index()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 84,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "data = pd.merge(data, agg_transactions, how='left', on='customer_id', suffixes=('', '_2014'))\n",
+ "data = data.fillna(0)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 85,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "np.mean(cross_val_score(\n",
+ " LogisticRegression(),\n",
+ " X=data.drop(['customer_id', 'response'], axis=1),\n",
+ " y=data.response,\n",
+ " cv=StratifiedKFold(n_splits=3, random_state=123),\n",
+ " scoring='roc_auc'))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Можно также считать дату первой и последней транзакциями\n",
+ "пользователей, среднее время между транзакциями и прочее. \n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "# Простые модели классификации\n",
+ "\n",
+ "\n",
+ "*Классификация* — отнесение объекта к одной из категорий на основании его признаков.\n",
+ "\n",
+ "Рассмотрим задачу бинарной классификации. Пусть $X = \\mathbb{R}^d$ —\n",
+ "пространство объектов, $Y = {−1, +1}$ — множество допустимых ответов,\n",
+ "$X = {(x_i , y_i )}_{i=1}^{\\ell}$ — обучающая выборка. Иногда мы будем \n",
+ "класс «+1» называть положительным, а класс «−1» — отрицательным.\n",
+ "\n",
+ "Будем считать, что классификатор имеет вид"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "a(x) = \\mathrm{sign}(b(x)−t) = 2[b(x) > t] − 1.\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "В такого рода задачах возникает необходимость в изучении различных\n",
+ "аспектов качества уже обученного классификатора. Сначала обсудим один\n",
+ "из подходов к измерению качества таких моделей.\n",
+ "\n",
+ "## Матрица ошибок\n",
+ "\n",
+ "\n",
+ "*Матрица ошибок* — это способ разбить объекты на четыре категории в\n",
+ "зависимости от комбинации истинного ответа и ответа алгоритма\n",
+ "(см. таблицу [ml:class:tbl:2](#ml:class:tbl:2)). Через элементы этой матрицы можно,\n",
+ "например, выразить долю правильных ответов:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\text{accuracy} = \\frac{\\mathrm{TP} + \\mathrm{TN}}{\\mathrm{TP} +\n",
+ "\\mathrm{FP} +\\mathrm{FN} + \\mathrm{TN}}.\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Таблица 2 : Матрица ошибок \n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "| $y=1$ | $y = -1$ |
\n",
+ "\n",
+ "\n",
+ "| TP (True Positive) | FP (False Positive) |
\n",
+ "| FN (False Negative) | TN (True Negatiive) |
\n",
+ "\n",
+ "
\n",
+ "\n",
+ "\n",
+ "Данная матрика имеет существенный недостаток — её значение необходимо\n",
+ "оценивать в контексте баланса классов. Eсли в выборке $950$\n",
+ "отрицательных и $50$ положительных объектов, то при абсолютно случайной\n",
+ "классификации мы получим долю правильных ответов $0.95$. Это означает,\n",
+ "что доля положительных ответов сама по себе не несет никакой\n",
+ "информации о качестве работы алгоритма $a(x)$, и вместе с ней следует \n",
+ "-анализировать соотношение классов в выборке. \n",
+ "\n",
+ "Гораздо более информативными критериями являются *точность* (precision)\n",
+ "и *полнота* (recall).\n",
+ "\n",
+ "Точность показывает, какая доля объектов, выделенных классификатором\n",
+ "как положительные, действительно является положительными:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\text{precision} = \\frac{\\mathrm{TP}}{\\mathrm{TP} + \\mathrm{FP}}\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Полнота показывает, какая часть положительных объектов была выделена\n",
+ "классификатором:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\text{precision} = \\frac{\\mathrm{TP}}{\\mathrm{TP} + \\mathrm{FN}}\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Существует несколько способов получить один критерий качества на основе\n",
+ "точности и полноты. Один из них — $F$-мера, гармоническое среднее\n",
+ "точности и полноты:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "F_\\beta = (1+\\beta^2) \\frac{\\text{precision}\\cdot\n",
+ "\\text{recall}}{\\beta^2 \\cdot \\text{precision} + \n",
+ "\\text{recall}}.\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Среднее гармоническое обладает важным свойством — оно близко к нулю,\n",
+ "если хотя бы один из аргументов близок к нулю. Именно поэтому оно\n",
+ "является более предпочтительным, чем среднее арифметическое (если\n",
+ "алгоритм будет относить все объекты к положительному классу, то он\n",
+ "будет иметь $\\text{recall} = 1$ и $\\text{precision} > 0$, а их среднее\n",
+ "арифметическое будет больше $1/2$, что недопустимо).\n",
+ "\n",
+ "Чаще всего берут $\\beta = 1$ хотя иногда встречаются и другие\n",
+ "модификации. $F_2$ острее реагирует на recall (т. е. на долю\n",
+ "ложноположительных ответов), а $F_{0.5}$ чувствительнее к точности\n",
+ "(ослабляет влияние ложноположительных ответов).\n",
+ "\n",
+ "В `sklearn` есть удобная функция\n",
+ "`sklearn.metrics.classification_report`, которая возвращает recall,\n",
+ "precision и $F$-меру для каждого из классов, а также количество\n",
+ "экземпляров каждого класса."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 86,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.metrics import classification_report\n",
+ "y_true = [0, 1, 2, 2, 2]\n",
+ "y_pred = [0, 0, 2, 2, 1]\n",
+ "target_names = ['class 0', 'class 1', 'class 2']\n",
+ "print(classification_report(y_true, y_pred, target_names=target_names))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Линейная классификация\n",
+ "\n",
+ "\n",
+ "Основная идея линейного классификатора заключается в том, что\n",
+ "признаковое пространство может быть разделено гиперплоскостью на две\n",
+ "полуплоскости, в каждой из которых прогнозируется одно из двух\n",
+ "значений целевого класса. Если это можно сделать без ошибок, то\n",
+ "обучающая выборка называется *линейно разделимой*.\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "Указанная разделяющая плоскость называется *линейным дискриминантом*.\n",
+ "\n",
+ "\n",
+ "### Логистическая регрессия\n",
+ "\n",
+ "\n",
+ "\n",
+ "*Логистическая регрессия* является частным случаем линейного\n",
+ "классификатора, но она обладает хорошим «умением» – прогнозировать\n",
+ "вероятность отнесения наблюдения к классу. Таким образом, результат\n",
+ "логистической регрессии всегда находится на отрезке $[0, 1]$. Возьмем\n",
+ "данные по [ирисам](https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 87,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "!wget https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 88,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "iris = pd.read_csv(\"https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 89,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "iris.describe()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 90,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "sns.pairplot(iris, hue=\"species\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 91,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "sns.lmplot(x=\"petal_length\", y=\"petal_width\", data=iris)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 92,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "X = iris.iloc[:, 2:4].values\n",
+ "y = iris['species'].values"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 93,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "y[:5]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 94,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.preprocessing import LabelEncoder\n",
+ "\n",
+ "le = LabelEncoder()\n",
+ "le.fit(y)\n",
+ "y = le.transform(y)\n",
+ "y[:5]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 95,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "iris_pred_names = le.classes_\n",
+ "iris_pred_names"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 96,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.model_selection import train_test_split\n",
+ "\n",
+ "X_train, X_test, y_train, y_test = train_test_split(\n",
+ " X, y, test_size=0.3, random_state=0)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 97,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.preprocessing import StandardScaler\n",
+ "\n",
+ "sc = StandardScaler()\n",
+ "sc.fit(X_train)\n",
+ "X_train_std = sc.transform(X_train)\n",
+ "X_test_std = sc.transform(X_test)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 98,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "X_train[:5], X_train_std[:5]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 99,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.linear_model import LogisticRegression\n",
+ "\n",
+ "lr = LogisticRegression(C=100.0, random_state=1)\n",
+ "lr.fit(X_train_std, y_train)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 100,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "lr.predict_proba(X_test_std[:3, :])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 101,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "lr.predict_proba(X_test_std[:3, :]).sum(axis=1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 102,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "y_test[:3]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 103,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "lr.predict_proba(X_test_std[:3, :]).argmax(axis=1)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Предсказываем класс первого наблюдения"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 104,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "lr.predict(X_test_std[0, :].reshape(1, -1))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "На основе его коэффициентов:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 105,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "X_test_std[0, :]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 106,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "X_test_std[0, :].reshape(1, -1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 107,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "y_pred = lr.predict(X_test_std)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 108,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "len(iris_pred_names)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 109,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "print(classification_report(y_test, y_pred, target_names=iris_pred_names))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "# Задание\n",
+ "\n",
+ "\n",
+ "Задание состоит из двух основных частей. В первой части необходимо сделать\n",
+ "простой препроцессинг и произвести разведывательный анализ данных. \n",
+ "\n",
+ "Во второй части у Вас будет выбор между двумя вариантами: Вы можете\n",
+ "провести регрессионный анализ данных или заняться обработкой\n",
+ "естественного языка и построением классификатора текстов.\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "## Задание по базе wine\n",
+ "\n",
+ "\n",
+ "\n",
+ "**a)**\n",
+ "**Загрузка и разведывательный анализ.**\n",
+ "* Загрузите данные ([скачать](src-ml/wine_reviews.csv.zip)).\n",
+ "\n",
+ "* Посчитайте размерность данных.\n",
+ "\n",
+ "* Посчитайте количество пропущенных значений в каждой переменной.\n",
+ "\n",
+ "* Выведите тип данных каждой переменной. Переконвертируйте при необходимости.\n",
+ "\n",
+ "* Вина какой области (province) получают наилучшие рейтинги?\n",
+ "\n",
+ "* На основе словаря color оздайте переменную, в которой закодирован цвет вина.\n",
+ "\n",
+ "* Удалите наблюдения для которых цвет (color) не указан.\n",
+ "\n",
+ "* Визуализируйте распределения числовых переменных.\n",
+ "\n",
+ "* Для каждой страны рассчитайте долю каждого вида вина. В какой стране доля белого вина наибольшая, а в какой красного? (Нужен ответ вида: в стране А наибольшая доля белого вина, а в стране B — красного.\n",
+ "\n",
+ "* Разделите выборку на обучающую и тестовую\n",
+ "\n",
+ "**b)**\n",
+ "**Регрессионная модель.**\n",
+ "* На обучающей выборке постройте регрессионную модель, показывающую зависимость между баллом (зависимая переменная) и ценой. Визуализируйте эту зависимость. На сколько изменяется оценка при изменении цены на одну условную единицу?\n",
+ "\n",
+ "* Оцените качество модели на основе предсказаний по тестовой выборке по помощи стандартных метрик качества для регрессионных моделей.\n",
+ "\n",
+ "* Добавьте в модель переменную, в которой закодирован цвет вина. Как изменилось качество?\n",
+ "\n",
+ "ИЛИ\n",
+ "\n",
+ "**c)**\n",
+ "**Классификация текстов.**\n",
+ "* Сделайте препроцессинг текстов в поле description.\n",
+ "\n",
+ "* На обучающей выборке постройте модель классификации текста, которая бы классифицировала вина по цвету на основе текстов из описания.\n",
+ "\n",
+ "* Оцените качество работы модели по помощи стандартных метрик качества для алгоритмов классификации. Использование автоматических методов подбора параметров (Grid Search) не обязательно, но в случае наличия — зачтётся.\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "Имя файла: `task_surname.ipynb`.\n",
+ "\n",
+ ""
+ ]
+ }
+ ],
+ "metadata": {},
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/numpy.ipynb b/numpy.ipynb
index 2f97e72..e64c3fb 100644
--- a/numpy.ipynb
+++ b/numpy.ipynb
@@ -142,7 +142,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 1,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -156,7 +156,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 2,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -170,7 +170,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 3,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -184,28 +184,46 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 4,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "CPU times: user 32.3 ms, sys: 16.8 ms, total: 49.1 ms\n",
+ "Wall time: 126 ms\n"
+ ]
+ }
+ ],
"source": [
"%time for _ in range(10): my_arr2 = my_arr*2"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 5,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "CPU times: user 817 ms, sys: 172 ms, total: 989 ms\n",
+ "Wall time: 1.06 s\n"
+ ]
+ }
+ ],
"source": [
"%time for _ in range(10): my_list2 = [x * 2 for x in my_list]"
]
@@ -228,7 +246,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 6,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -242,7 +260,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 7,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -256,42 +274,78 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 8,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[ 0.62955711, 0.22558868, -0.15732107],\n",
+ " [-1.23977365, -0.04357442, 0.82177343]])"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"data"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 9,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[ 6.29557109, 2.25588682, -1.57321072],\n",
+ " [-12.39773646, -0.43574416, 8.21773429]])"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"data * 10"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 10,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[ 1.25911422, 0.45117736, -0.31464214],\n",
+ " [-2.47954729, -0.08714883, 1.64354686]])"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"data + data"
]
@@ -308,28 +362,50 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 11,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(2, 3)"
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"data.shape"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 12,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "dtype('float64')"
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"data.dtype"
]
@@ -349,7 +425,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 13,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -363,7 +439,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 14,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -377,16 +453,27 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 15,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([6. , 7.5, 8. , 0. , 1. ])"
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "In [15]: arr1"
+ "arr1"
]
},
{
@@ -399,7 +486,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 22,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -413,7 +500,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 28,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -422,19 +509,31 @@
},
"outputs": [],
"source": [
- "arr2 = np.array(data2)"
+ "arr2 = np.array(data2, dtype='float64')"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 29,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[1., 2., 3., 4.],\n",
+ " [5., 6., 7., 8.]])"
+ ]
+ },
+ "execution_count": 29,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr2"
]
@@ -451,17 +550,27 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 30,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "dtype('float64')"
+ ]
+ },
+ "execution_count": 30,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "In [19]: arr1.dtype\n",
- "In [20]: arr2.dtype"
+ "In [19]: arr2.dtype"
]
},
{
@@ -474,60 +583,133 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 31,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])"
+ ]
+ },
+ "execution_count": 31,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"np.zeros(10)"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 33,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[0., 0., 0., 0., 0., 0.],\n",
+ " [0., 0., 0., 0., 0., 0.],\n",
+ " [0., 0., 0., 0., 0., 0.]])"
+ ]
+ },
+ "execution_count": 33,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"np.zeros((3, 6))"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 32,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[[4.68232729e-310, 0.00000000e+000],\n",
+ " [0.00000000e+000, 0.00000000e+000],\n",
+ " [0.00000000e+000, 0.00000000e+000]],\n",
+ "\n",
+ " [[0.00000000e+000, 0.00000000e+000],\n",
+ " [0.00000000e+000, 0.00000000e+000],\n",
+ " [0.00000000e+000, 0.00000000e+000]]])"
+ ]
+ },
+ "execution_count": 32,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"np.empty((2, 3, 2))"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 36,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])"
+ ]
+ },
+ "execution_count": 36,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"np.arange(15)"
]
},
+ {
+ "cell_type": "code",
+ "execution_count": 38,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[1., 1., 1., 1.],\n",
+ " [1., 1., 1., 1.]])"
+ ]
+ },
+ "execution_count": 38,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "np.empty_like(arr2)"
+ ]
+ },
{
"cell_type": "markdown",
"metadata": {},
@@ -568,7 +750,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 39,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -582,7 +764,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 40,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -596,42 +778,78 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 41,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[1., 2., 3.],\n",
+ " [4., 5., 6.]])"
+ ]
+ },
+ "execution_count": 41,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"In [3]: arr"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 42,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[ 1., 4., 9.],\n",
+ " [16., 25., 36.]])"
+ ]
+ },
+ "execution_count": 42,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr * arr"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 43,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[0., 0., 0.],\n",
+ " [0., 0., 0.]])"
+ ]
+ },
+ "execution_count": 43,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr - arr"
]
@@ -646,35 +864,59 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 44,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[1. , 0.5 , 0.33333333],\n",
+ " [0.25 , 0.2 , 0.16666667]])"
+ ]
+ },
+ "execution_count": 44,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"1 / arr"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 45,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[1. , 1.41421356, 1.73205081],\n",
+ " [2. , 2.23606798, 2.44948974]])"
+ ]
+ },
+ "execution_count": 45,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr ** 0.5"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 46,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -688,30 +930,54 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 47,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[ 0., 4., 1.],\n",
+ " [ 7., 2., 12.]])"
+ ]
+ },
+ "execution_count": 47,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr2"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 48,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[False, True, False],\n",
+ " [ True, False, True]])"
+ ]
+ },
+ "execution_count": 48,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "arr2 > arrщ"
+ "arr2 > arr"
]
},
{
@@ -728,7 +994,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 49,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -742,49 +1008,82 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 50,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])"
+ ]
+ },
+ "execution_count": 50,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 51,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "5"
+ ]
+ },
+ "execution_count": 51,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr[5]"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 52,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([5, 6, 7])"
+ ]
+ },
+ "execution_count": 52,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr[5:8]"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 53,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -798,14 +1097,25 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 54,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([ 0, 1, 2, 3, 4, 12, 12, 12, 8, 9])"
+ ]
+ },
+ "execution_count": 54,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr"
]
@@ -826,7 +1136,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 55,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -840,14 +1150,25 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 56,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([12, 12, 12])"
+ ]
+ },
+ "execution_count": 56,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr_slice"
]
@@ -862,7 +1183,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 57,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -876,14 +1197,26 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 58,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([ 0, 1, 2, 3, 4, 12, 12345, 12, 8,\n",
+ " 9])"
+ ]
+ },
+ "execution_count": 58,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr"
]
@@ -897,7 +1230,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 59,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -911,14 +1244,25 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 61,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([ 0, 1, 2, 3, 4, 64, 64, 64, 8, 9])"
+ ]
+ },
+ "execution_count": 61,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr"
]
@@ -947,7 +1291,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 62,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -961,14 +1305,25 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 63,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([7, 8, 9])"
+ ]
+ },
+ "execution_count": 63,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr2d[2]"
]
@@ -984,30 +1339,52 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 64,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([7, 8, 9])"
+ ]
+ },
+ "execution_count": 64,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr2d[2]"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 66,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "3"
+ ]
+ },
+ "execution_count": 66,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "arr2d[0][2]"
+ "arr2d[0, 2]"
]
},
{
@@ -1021,7 +1398,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 67,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -1035,14 +1412,29 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 68,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[[ 1, 2, 3],\n",
+ " [ 4, 5, 6]],\n",
+ "\n",
+ " [[ 7, 8, 9],\n",
+ " [10, 11, 12]]])"
+ ]
+ },
+ "execution_count": 68,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr3d"
]
@@ -1056,14 +1448,26 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 69,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[1, 2, 3],\n",
+ " [4, 5, 6]])"
+ ]
+ },
+ "execution_count": 69,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr3d[0]"
]
@@ -1077,7 +1481,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 70,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -1091,7 +1495,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 71,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -1105,21 +1509,36 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 72,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[[42, 42, 42],\n",
+ " [42, 42, 42]],\n",
+ "\n",
+ " [[ 7, 8, 9],\n",
+ " [10, 11, 12]]])"
+ ]
+ },
+ "execution_count": 72,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr3d"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 73,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -1133,14 +1552,29 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 74,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[[ 1, 2, 3],\n",
+ " [ 4, 5, 6]],\n",
+ "\n",
+ " [[ 7, 8, 9],\n",
+ " [10, 11, 12]]])"
+ ]
+ },
+ "execution_count": 74,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr3d"
]
@@ -1155,14 +1589,25 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 75,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([7, 8, 9])"
+ ]
+ },
+ "execution_count": 75,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr3d[1, 0]"
]
@@ -1176,7 +1621,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 76,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -1190,28 +1635,51 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 77,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[ 7, 8, 9],\n",
+ " [10, 11, 12]])"
+ ]
+ },
+ "execution_count": 77,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"x"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 78,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([7, 8, 9])"
+ ]
+ },
+ "execution_count": 78,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"x[0]"
]
@@ -1230,28 +1698,50 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 79,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([ 0, 1, 2, 3, 4, 64, 64, 64, 8, 9])"
+ ]
+ },
+ "execution_count": 79,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 80,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([ 1, 2, 3, 4, 64])"
+ ]
+ },
+ "execution_count": 80,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr[1:6]"
]
@@ -1266,30 +1756,55 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 81,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[1, 2, 3],\n",
+ " [4, 5, 6],\n",
+ " [7, 8, 9]])"
+ ]
+ },
+ "execution_count": 81,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr2d"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 83,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[1, 2, 3],\n",
+ " [4, 5, 6]])"
+ ]
+ },
+ "execution_count": 83,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "arr[:2]"
+ "arr2d[:2]"
]
},
{
@@ -1305,14 +1820,26 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 84,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[2, 3],\n",
+ " [5, 6]])"
+ ]
+ },
+ "execution_count": 84,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr2d[:2, 1:]"
]
@@ -1328,28 +1855,50 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 85,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([4, 5])"
+ ]
+ },
+ "execution_count": 85,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr2d[1, :2]"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 86,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([3, 6])"
+ ]
+ },
+ "execution_count": 86,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr2d[:2, 2]"
]
@@ -1380,7 +1929,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 87,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -1394,7 +1943,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 88,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -1408,28 +1957,56 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 89,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'], dtype='"
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
"source": [
- "plt.imshow(z, cmap=plt.cm.gray); plt.colorbar()"
+ "plt.imshow(z, cmap=plt.cm.gray); plt.colorbar()\n",
+ "plt.title('Визуализация функции $\\sqrt{x^2 + y^2}$ на сетке')"
]
},
{
@@ -2634,7 +3789,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 164,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -2648,7 +3803,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 165,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -2662,7 +3817,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 166,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -2686,7 +3841,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 167,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -2700,14 +3855,25 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 168,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[1.1, 2.2, 1.3, 1.4, 2.5]"
+ ]
+ },
+ "execution_count": 168,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"result"
]
@@ -2725,7 +3891,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 169,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -2739,16 +3905,27 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 171,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([1.1, 2.2, 1.3, 1.4, 2.5])"
+ ]
+ },
+ "execution_count": 171,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "result = np.where(cond, xarr, yarr)"
+ "result"
]
},
{
@@ -2766,7 +3943,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 172,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -2780,42 +3957,84 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 173,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[-0.66464048, -1.11134705, 1.37884191, 1.43021577],\n",
+ " [-1.40300745, -0.75443307, 0.30600186, -0.0735264 ],\n",
+ " [-0.70828539, 1.0644955 , -1.20046209, -0.70420307],\n",
+ " [ 1.12269842, -0.43256645, -0.13543629, -0.02699621]])"
+ ]
+ },
+ "execution_count": 173,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 174,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[False, False, True, True],\n",
+ " [False, False, True, False],\n",
+ " [False, True, False, False],\n",
+ " [ True, False, False, False]])"
+ ]
+ },
+ "execution_count": 174,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr > 0"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 175,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[-2, -2, 2, 2],\n",
+ " [-2, -2, 2, -2],\n",
+ " [-2, 2, -2, -2],\n",
+ " [ 2, -2, -2, -2]])"
+ ]
+ },
+ "execution_count": 175,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"np.where(arr > 0, 2, -2)"
]
@@ -2831,14 +4050,28 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 176,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[-0.66464048, -1.11134705, 2. , 2. ],\n",
+ " [-1.40300745, -0.75443307, 2. , -0.0735264 ],\n",
+ " [-0.70828539, 2. , -1.20046209, -0.70420307],\n",
+ " [ 2. , -0.43256645, -0.13543629, -0.02699621]])"
+ ]
+ },
+ "execution_count": 176,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"np.where(arr > 0, 2, arr)"
]
@@ -2863,7 +4096,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 177,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -2877,56 +4110,104 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 178,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[-1.2167025 , 0.26684004, 0.37933051, 0.92982079],\n",
+ " [-0.02473966, 0.73980057, -0.44155996, -2.06986949],\n",
+ " [ 0.03720622, 0.92436984, -1.58246901, -0.28881663],\n",
+ " [-0.06352456, 0.55178233, -1.43402474, 2.07847906],\n",
+ " [-0.55224505, -0.40871248, 0.78480968, -1.41514863]])"
+ ]
+ },
+ "execution_count": 178,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 179,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "-0.14026868401976725"
+ ]
+ },
+ "execution_count": 179,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr.mean()"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 180,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "-0.14026868401976725"
+ ]
+ },
+ "execution_count": 180,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"np.mean(arr)"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 181,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "-2.805373680395345"
+ ]
+ },
+ "execution_count": 181,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr.sum()"
]
@@ -2942,28 +4223,50 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 185,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([ 0.08982221, -0.44909214, -0.2274274 , 0.28317802, -0.39782412])"
+ ]
+ },
+ "execution_count": 185,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr.mean(axis=1)"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 186,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([-1.82000556, 2.07408029, -2.29391351, -0.7655349 ])"
+ ]
+ },
+ "execution_count": 186,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr.sum(axis=0)"
]
@@ -2981,7 +4284,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 190,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -2990,21 +4293,32 @@
},
"outputs": [],
"source": [
- "arr = np.array([0, 1, 2, 3, 4, 5, 6, 7])"
+ "arr = np.array([1, 2, 3, 4, 5, 6, 7])"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 191,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([ 1, 2, 6, 24, 120, 720, 5040])"
+ ]
+ },
+ "execution_count": 191,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "arr.cumsum()"
+ "arr.cumprod()"
]
},
{
@@ -3019,7 +4333,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 193,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -3033,42 +4347,81 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 194,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[0, 1, 2],\n",
+ " [3, 4, 5],\n",
+ " [6, 7, 8]])"
+ ]
+ },
+ "execution_count": 194,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 195,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[ 0, 1, 2],\n",
+ " [ 3, 5, 7],\n",
+ " [ 9, 12, 15]])"
+ ]
+ },
+ "execution_count": 195,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr.cumsum(axis=0)"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 196,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[ 0, 0, 0],\n",
+ " [ 3, 12, 60],\n",
+ " [ 6, 42, 336]])"
+ ]
+ },
+ "execution_count": 196,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr.cumprod(axis=1)"
]
@@ -3117,28 +4470,70 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 199,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([-1.32390275, -1.0677737 , -0.75591368, -0.4284737 , 1.60423034,\n",
+ " 0.69672924, 1.68048259, 0.43237566, -0.9369892 , -1.11156679,\n",
+ " 0.58929476, 0.08824475, 0.4212576 , 0.39878124, 0.7383381 ,\n",
+ " -0.35939768, 0.16423203, -0.92236598, 0.46042767, -0.98861342,\n",
+ " -0.18848097, -0.79606263, 0.83448883, -1.8489933 , 0.11509521,\n",
+ " -0.52785657, 0.16546174, 1.62477592, 1.04921672, -0.08406352,\n",
+ " 1.33675875, -0.36904779, -0.25620027, 1.06950333, -0.05524866,\n",
+ " 2.31922315, -0.17508064, 0.51216759, -0.31534566, -1.61432312,\n",
+ " -0.61582557, -0.38697939, -0.28057501, -1.32700842, 0.08026122,\n",
+ " 0.38809548, 0.30056911, 0.90816488, -0.14090822, -0.46949723,\n",
+ " -0.26949007, 0.23234959, -1.01386424, 0.37079297, -0.92979541,\n",
+ " -0.36825517, -1.51214788, -0.56054003, -0.84206451, 0.39224787,\n",
+ " -0.77837871, -1.79345594, 1.1404122 , -2.05518387, 1.32978656,\n",
+ " 1.55939981, -1.12400554, 0.31047509, -0.30145171, 0.39520486,\n",
+ " -1.37320207, -1.30786396, -0.17600666, 0.32959543, -0.92741269,\n",
+ " -0.22968272, 0.62521425, -0.70538808, 0.99930085, 0.04282135,\n",
+ " 0.97037357, 1.18057706, -0.47032835, -0.24715178, -0.35812267,\n",
+ " 0.41219654, -1.07288305, -1.45971665, -0.31750339, -1.69654704,\n",
+ " 0.05366386, -0.09160625, 0.38790378, 0.46497527, 0.70792639,\n",
+ " -0.74452609, 0.21340049, -0.17084294, -0.54755447, 1.62859608])"
+ ]
+ },
+ "execution_count": 199,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "arr = np.random.randn(100)"
+ "arr = np.random.randn(100)\n",
+ "arr"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 198,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "47"
+ ]
+ },
+ "execution_count": 198,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"(arr > 0).sum()"
]
@@ -3155,7 +4550,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 200,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -3169,28 +4564,50 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 201,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 201,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr.any()"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 202,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 202,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr.all()"
]
@@ -3216,7 +4633,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 203,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -3230,21 +4647,33 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 204,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([-1.12155186, -0.54081677, 0.22116091, -0.31268949, 1.06918716,\n",
+ " -0.77957656])"
+ ]
+ },
+ "execution_count": 204,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 205,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -3258,14 +4687,26 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 206,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([-1.12155186, -0.77957656, -0.54081677, -0.31268949, 0.22116091,\n",
+ " 1.06918716])"
+ ]
+ },
+ "execution_count": 206,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr"
]
@@ -3280,7 +4721,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 207,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -3294,21 +4735,36 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 208,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[-0.3831215 , 1.44012127, 0.4054832 ],\n",
+ " [ 1.471936 , -0.28302072, -1.52508038],\n",
+ " [ 0.16557173, 0.91101596, 1.20965603],\n",
+ " [ 0.24972433, 0.4125885 , -2.13286408],\n",
+ " [-0.38250019, 1.37333992, 0.26052155]])"
+ ]
+ },
+ "execution_count": 208,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 209,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -3322,14 +4778,29 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 210,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[-0.3831215 , 0.4054832 , 1.44012127],\n",
+ " [-1.52508038, -0.28302072, 1.471936 ],\n",
+ " [ 0.16557173, 0.91101596, 1.20965603],\n",
+ " [-2.13286408, 0.24972433, 0.4125885 ],\n",
+ " [-0.38250019, 0.26052155, 1.37333992]])"
+ ]
+ },
+ "execution_count": 210,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"arr"
]
@@ -3346,7 +4817,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 211,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -3360,7 +4831,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 212,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -3374,14 +4845,25 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 213,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "-1.731823670640617"
+ ]
+ },
+ "execution_count": 213,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"large_arr[int(0.05 * len(large_arr))] # 5% квантиль"
]
@@ -3400,7 +4882,7 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 214,
"metadata": {
"collapsed": false,
"jupyter": {
@@ -3414,21 +4896,32 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 215,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array(['Bob', 'Joe', 'Will'], dtype='