[МУЗЫКА]
[МУЗЫКА] Ознакомимся
подробнее с библиотеками машинного обучения.
Начнем с NumPy.
NumPy — это библиотека,
которая используется в качестве некоторого движка для вычислений
более продвинутыми библиотеками уже конкретно для анализа данных.
Скажем, stats module или Scikit-learn активно используют NumPy.
Зачем нужна отдельно NumPy?
Почему, если у нас уже есть стандартные элементы Python?
Это хороший вопрос, и в действительности стандартные элементы Python из-за
своей универсальности крайне медленные, а NumPy реализована с использованием
библиотеки BLAS, с исходниками на C Fortran, и это проиходит намного быстрее.
Однако пришлось пожертвовать некоторой универсальностью.
Но в своём контексте, в контексте вычислений алгебраических,
NumPy достаточно хороша.
Начнём с того, что импортируем модуль NumPy (как вы уже знаете,
мы можем импортировать модули) и создадим одномерный массив из обычного списка.
Можем создать матрицу.
Любой массив и любая матрица — это питоновский объект.
И как у любого объекта, у него есть различные поля, методы и свойства.
И одно из важнейших свойств NumPy — это свойство shape.
С помощью свойства shape можно посмотреть на размерность.
То есть вот мы взяли нашу матрицу, сказали shape и увидели кортеж.
Кортеж из двойки и двойки.
Ну и, соответственно, понятно: мы создали матрицу два на два.
Кроме прямых способов задания массивов,
в NumPy можно также использовать встроенные функции.
И это также бывает зачастую удобно.
Например, функция zeros создаёт матрицу из нулей или вектор из нулей,
в зависимости от того, какую размерность мы передадим этой функции.
По аналогии есть также некоторый набор других функций, например,
функция ones, которая создаёт аналогичную матрицу из единиц.
Функция ones — матрица из единиц.
Всё логично.
Или функция arange.
Функция arange позволяет создать вектор чисел из некоторого диапазона.
Причём первым параметром мы указываем начало диапазона, вторым параметром —
конец диапазона, а если мы укажем также третий парметр — step (или шаг),
то это будет шаг, с которым будет шагать функция arange.
Похожим образом работает функция linspace; но она делит отрезок
на указанное число частей равной длины.
Эту функцию крайне часто используют при построении математических графиков.
Также мы можем создать диагональную матрицу с помощью встроенной функции
— это бывает полезно при реализации какой-либо алгебры линейной —
или единичную матрицу для тех же целей.
Массивы NumPy типизированы, и тип массива выводится во время создания.
Но при этом зачастую бывает удобно задать его явно; а иногда сам NumPy не совсем
правильно выводит тип массива.
Давайте создадим массив явно.
То есть мы возьмём некоторый список и явно укажем тип,
добавив дополнительный параметр dtype.
Как вы видите по наличию точки, а также при вызовах свойства
dtype — это у нас float, float64 — это такой особый NumPy float.
Кстати, в NumPy числа всё-таки ограничены, и может возникнуть переполнение.
Также можно легко менять размерность массива.
То есть создав массив из десяти элементов, мы очень легко можем сделать его матрицей
из 16 элементов, мы можем легко его сделать матрицей два на восемь.
Однако стоит помнить некоторую особенность: reshape не создаёт нового
элемента, она возвращает view, некоторый образ старого массива.
И, соответственно, если мы возьмём нашу новую матрицу и изменим, например,
нулевой элемент — «ноль-ноль» или «ноль» в терминах одномерного массива,
то он изменится и в исходном.
Помимо такой простой работы с массивами, NumPy также поддерживает индексацию.
Это доступ к отдельным элементам.
И, в принципе, он осуществляется таким же способом,
как осуществляется доступ в уже знакомых вам списках.
Кроме того, массив NumPy также позволяет срезать свои элементы,
то есть фактически использовать слайсы.
Опять же возьмём нашу матрицу и срежем нашу матрицу следующим образом.
И получим некоторую подматрицу.
В принципе, достаточно очевидно, каким образом её можно получить.
Кроме того, можно указывать так называемые wildcard'ы, то есть если нам нужна вторая
строка матрицы и неважно, какие индексы — то есть все доступные индексы из столбцов,
мы просто пишем двоеточие.
Также можно использовать различные хитрости, связанные с индексами.
Вот здесь мы, например, взяли столбцы в обратном порядке.
Можно также использовать срезы для изменения матриц.
То есть, скажем, элемент wise присвоения, то есть присвоение поэлементно.
Мы берём срез, говорим «равно единице» и, соответственно,
получаем в нашей матрице второй столбец, заполненный единицами.
Или впишем в левый угол нашей матрицы матрицу два на два, состоящую из единиц.
Срезы, конечно, удобны, но иногда нужно уметь выбирать элементы,
удовлетворяющие более сложным условиям.
А если в качестве индексатора использовать массивы одинакового размера,
то создастся подмассив из соответствующих элементов.
Посмотрим на практике.
Создадим некоторую матрицу.
Создадим некоторые массивы rows and columns.
И также сделаем массив.
Да, действительно, мы смогли проиндексировать таким образом.
Ну и некоторые более сложные примеры индексации.
Здесь, когда мы выделяем подмассив; здесь, когда мы смешиваем
разные способы индексации; и некоторые более интересные примеры,
когда мы попробуем сделать маску из логической операции.
То есть здесь, казалось бы, мы применили классическое больше,
однако мы получили некоторую подмаску, состоящую из битовых значений.
И эту подмаску можно применять для того, чтобы индексировать наши матрицы.
То есть вот тут мы получаем массив, точнее, даже подмассив,
для которого у соответствующих элементов выставлено значение маски True.
Вот такая вот индексация логическими масками.
В NumPy также встроены классические методы оперирования с массивами:
массивы можно суммировать, можно складывать не только отдельные элементы,
а, например, подматрицы по отдельным осям, вдоль оси x или y.
Здесь за это отвечает параметр axis — достаточно частый
параметр в библиотеках на Python.
Достаточно частый подход.
И здесь, например, axis = 0 — это суммирование вдоль строк.
Ну а если мы скажем axis = 1,
то соответственно будет суммирование вдоль столбцов.
Кроме того, можно опять же использовать данные функции в масках и срезах.
То есть здесь мы формируем подматрицы из строк,
сумма элементов которых больше восьми.
Кроме того, между массивами в NumPy также можно совершать
различные математические операции.
При этом операции осуществляются поэлементно.
То есть, скажем, здесь мы суммировали две
матрицы единичные, матрицу arange.
И также матрицы можно перемножить.
Хочу сказать,
что здесь происходит не матричное умножение, а именно поэлементное.
Можно даже совершать операции между массивом и скаляром; тут,
в принципе, вполне себе понятная семантика.
При некоторых условиях можно
осуществлять даже операции между массивами разной длины.
В данном случае происходит бродкастинг, то есть один из массивов бьётся на
подмассивы меньших размерностей, и операции будут совершаться
поэлементно над каждым из подмассивов младшей размерности.
Вот такие вот различные примеры использования данной функции.
Ну и, кроме того, можно совершать более сложные операции.
Например, классический знакомый синус, встроенный в NumPy.
И, в конце концов, давайте сравним скорость,
то есть в начале видео я говорил, что скорость на NumPy сильно больше скорости
классических питоновских коллекций классических питоновский элементов.
Давайте замерим это с помощью встроенной в Jupyter команды timeit.
Посчитаем синусы.
Да, NumPy работает раз в пять быстрее примерно.
Конкретные числа, естественно, зависят от вашего ноутбука,
если вы будете повторять данный эксперимент.
Ну и зачастую бывает необходимо соединить несколько массивов с
помощью функции concatenate.
Можно соединять массивы с различными условиями, например,
вдоль первой оси или же использовать также встроенные функции vstack и hstack.
Также в NumPy реализовано некоторое количество классических
линейно-алгебраических операций — операций линейной алгебры: собственные числа,
вектора, SVD разложение, матричное умножение,
нахождение обратной и псевдообратной матрицы.
Ну и, кроме того,
так как Python — динамический язык,
то мы можем передавать массивы NumPy в обычные функции.
И зачастую из-за некоторых особенностей поэлементного умножения мы даже
получим простой интерпретируемый результат.
В NumPy имеются функции для сохранения состояния на диск и
даже различные генераторы случайных чисел; причём не просто случайных чисел,
но и случайных чисел, которые удовлетворяют определённым статистическим
распределениям, как, например, нормальному или распределению Дирихле.
Кроме того, уделим внимание библиотеке Matplotlib,
котрая крайне широко используется для рисования графиков.
Matplotlib обладает определёнными преимуществами.
У Matplotlib достаточно удобный объектно-ориентированный интерфейс,
огромные возможности для кастомизации и стилизации графиков.
Matplotlib фактически из коробки работает с массивами, например,
NumPy представленными.
И кроме того, Matplotlib интегрирована в Jupyter Notebook.
Однако стоит заметить, что Matplotlib — это настолько общая и обширная библиотека,
что зачастую пользоваться ей не очень удобно.
И в каких-то простых случаях зачастую проще использовать библиотеки
[НЕРАЗБОРЧИВО], которые мы также рассмотрим позже.
Импортируем Matplotlib и с помощью особой magic-функции matplotlib inline укажем,
что вывод Matplotlib необходимо встраивать в Jupyter Notebook.
Мы также будем использовать библиотеку seaborn,
ту самую надстройку на Matplotlib, одну из возможных.
Давайте попробуем нарисовать следующую функцию.
Создадим сетку и построим достаточно простой график.
Как вы видите, это некоторая синусоида с особенностями.
Можем также построить более интересные графики.
Например, диаграмму рассеяния.
Зададим случайную матрицу и нарисуем по оси x первую строку,
а по оси y — вторую строку.
И отобразим её с помощью функции scatter.
И с помощью Matplotlib можно рисовать различные гистограммы.
Это классический вид графиков,
который пришёл к нам ещё от математической статистики.
Например, классическую гистограмму или столбиковую гистограмму.
С помощью Matplotlib, как я уже говорил, можно кастомизировать свой график.
И здесь небольшой пример графиков различной формы,
цветов и конфигурации.