Практикумы — PYTHON https://chel-center.ru/python-yfc курс молодого бойца Wed, 03 Feb 2021 06:08:48 +0000 ru-RU hourly 1 https://wordpress.org/?v=5.9.3 https://chel-center.ru/python-yfc/wp-content/uploads/sites/15/2020/06/cropped-kmb-icon-2-1-32x32.png Практикумы — PYTHON https://chel-center.ru/python-yfc 32 32 Практикум №1 — набиваем руку https://chel-center.ru/python-yfc/2019/10/01/metodicheskie-ukazaniya-dlya-samostoyatelnoj-raboty-v-i-semestre/ https://chel-center.ru/python-yfc/2019/10/01/metodicheskie-ukazaniya-dlya-samostoyatelnoj-raboty-v-i-semestre/#respond Tue, 01 Oct 2019 01:34:52 +0000 http://chel-center.ru/python-yfc/?p=18 Читать далее «Практикум №1 — набиваем руку»

]]>
Как показывает многолетняя практика, если решить все 1052 задачи из книги Задачи по программированию, то можно приобрести уверенность в таком дел, как программирование, и смело браться за решение практических задач. Но это для особо усердных и тех кому программирование действительно нравится, тех кто хочет сделать программирование своей работой. Завидуйте им.

В курсе «Программирование» на Бизнес-информатике предлагается всего лишь 101 задача, которые приведены ниже, для упражнений на Phyton и каждому необходимо решить самостоятельно.

Решение всех задач хотелось бы видеть в вашем репозитарии на Github

Задачи для самостоятельной работы

Линейные алгоритмы

  1. Нарисуйте блок-схему к следующей задаче: Преобразовать дату в «компьютерном» представлении (системную дату) в «российский» формат, т.е. день/месяц/год (например, 17/05/2009).
    Постановка задачи: Системная дата имеет вид 2009-06-15. Нужно преобразовать это значение в строку, строку разделить на компоненты (символ→разделитель→дефис), потом из этих компонентов сконструировать нужную строку.
  2. Даны действительные числа А, В, С. Найти максимальное и минимальное из этих чисел.
  3. Известны длины трёх сторон треугольника. Вычислить периметр треугольника и площадь по формуле Герона (указание: использовать модуль math и функцию sqrt ()).
  4. Задан вес в граммах. Определить вес в тоннах и килограммах.
  5. Известен объем информации в байтах. Перевести в килобайты, мегабайты.
  6. Определить значение функции Z = \frac{1}{(XY)} при X и Y не равных 0.

Ветвления и оператор выбора

  1. Дано натуральное число. Определить, будет ли это число: чётным, кратным 4.
  2. Дано натуральное число. Определить, будет ли это число: нечётным, кратным 5.
  3. Дано натуральное число. Определить, будет ли это число: нечётным, кратным 7.
  4. Дано натуральное число. Определить, будет ли это число: чётным, кратным 10.
  5. Имеется коробка со сторонами: A \times B \times C. Определить, пройдёт ли она в дверь с размерами M \times K.
  6. Дано вещественное число. Определить, какое это число: положительное, отрицательное, ноль.
  7. Можно ли из бревна, имеющего диаметр поперечного сечения D, выпилить квадратный брус шириной A?
  8. Можно ли в квадратном зале площадью S поместить круглую сцену радиусом R так, чтобы от стены до сцены был проход не менее K?
  9. Дан номер места в плацкартном вагоне. Определить, какое это место: верхнее или нижнее, в купе или боковое.
  10. Известна денежная сумма. Разменять её купюрами 500, 100, 10 и монетой 2 руб., если это возможно.
  11. Имеются две ёмкости: кубическая с ребром A, цилиндрическая с высотой H и радиусом основания R. Определить, поместится ли жидкость объёма M литров в первую ёмкость, во вторую, в обе.
  12. Имеются две ёмкости: кубическая с ребром A, цилиндрическая с высотой H и радиусом основания R. Определить, можно ли заполнить жидкостью объёма M литров первую ёмкость, вторую, обе.
  13. Даны вещественные числа: X, Y, Z. Определить, существует ли треугольник с такими длинами сторон и если существует, будет ли он прямоугольным.
  14. Дано число X. Определить, принадлежит ли это число заданному промежутку [a, b].
  15. Определить значение функции Z = \frac{1}{XY}\text{ при произвольных }X\text{ и }Y.
  16. Даны вещественные числа A, B, C. Определить, выполняются ли неравенства A < B < C\text{ или }A > B > C, и какое именно неравенство выполняется.
  17. Даны два вещественных числа X\text{ и }Y. Вычислить Z = \sqrt{X \times Y} при X > Y, Z = ln{(X + Y)} в противном случае.
  18. Даны вещественные положительные числа a, b, c, d. Выясните, может ли прямоугольник со сторонами a, b уместиться внутри прямоугольника со сторонами c, d так, чтобы каждая сторона внутреннего прямоугольника была параллельна или перпендикулярна стороне внешнего прямоугольника.
  19. Дано вещественное число A. Вычислить f(A), если f(x) = x^2 + 4x +5, при x \leq 2; в противном случае f(x) = \frac{1}{x^2 + 4x + 5}.
  20. Дано вещественное число A. Вычислить f(A), если f(x) = 0, при x \leq 2. f(x) = x, при (x \geq 1), в противном случае f(x) = x^4.
  21. Дано вещественное число A. Вычислить f(A), если f(x) = 0, при x \leq 0. f(x) = x^2 - x, при (x \geq 1), в противном случае f(x) = x^2 - \sin{(\pi x^2)}.
  22. Составить алгоритм и программу для реализации логических операций «И» и «ИЛИ» для двух переменных.
  23. Известен ГОД. Определить, будет ли этот год високосным, и к какому веку этот год относится

Указание.

При вычислении корней и логарифмов используйте функции sqrt() и log() модуля math. В этом же модуле определена константа pi (math.pi).

Циклические алгоритмы. Обработка последовательностей и одномерных массивов

  1. Составьте блок-схему поиска максимального элемента в одномерном массиве.
  2. Нарисуйте полную блок-схему алгоритма сортировки массива «методом пузырька».
  3. Дан одномерный массив числовых значений, насчитывающий N элементов. Поменять местами элементы, стоящие на чётных и нечётных местах: A[1] ↔ A[2]; A[3] ↔ A[4] …
  4. Дан одномерный массив числовых значений, насчитывающий N элементов. Выполнить перемещение элементов массива по кругу вправо, т. е. A[1] → A[2]; A[2] → A[3]; … A[n] → A[1].
  5. Дан одномерный массив числовых значений, насчитывающий N элементов. Поменять местами первую и вторую половины массива.
  6. Дан одномерный массив числовых значений, насчитывающий N элементов. Поменять местами группу из M элементов, начинающихся с позиции K с группой из M элементов, начинающихся с позиции P.
  7. Дан одномерный массив числовых значений, насчитывающий N элементов. Вставить группу из M новых элементов, начиная с позиции K.
  8. Дан одномерный массив числовых значений, насчитывающий N элементов. Сумму элементов массива и количество положительных элементов поставить на первое и второе место.
  9. Дан одномерный массив числовых значений, насчитывающий N элементов.Исключить из него M элементов, начиная с позиции K.
  10. Дан одномерный массив числовых значений, насчитывающий N элементов. Исключить все нулевые элементы.
  11. Дан одномерный массив числовых значений, насчитывающий N элементов. После каждого отрицательного элемента вставить новый элемент, равный квадрату этого отрицательного элемента.
  12. Дан одномерный массив числовых значений, насчитывающий N элементов. Определить, образуют ли элементы массива, расположенные перед первым отрицательным элементом, возрастающую последовательность.
  13. Дан одномерный массив числовых значений, насчитывающий N элементов. Определить, образуют ли элементы массива, расположенные перед первым отрицательным элементом, убывающую последовательность.
  14. Дан одномерный массив числовых значений, насчитывающий N элементов. Из элементов исходного массива построить два новых. В первый должны входить только элементы с положительными значениями, а во второй — только элементы с отрицательными значениями.
  15. Дан одномерный массив числовых значений, насчитывающий N элементов. Добавить столько элементов, чтобы элементов с положительными и отрицательными значениями стало бы поровну.
  16. Дан одномерный массив числовых значений, насчитывающий N элементов. Добавить к элементам массива такой новый элемент, чтобы сумма элементов с положительными значениями стала бы равна модулю суммы элементов с отрицательными значениями.
  17. Дан одномерный массив числовых значений, насчитывающий N элементов. Дано положительное число T. Разделить это число между положительными элементами массива пропорционально значениям этих элементов и добавить полученные доли к соответствующим элементам.
  18. Дан одномерный массив числовых значений, насчитывающий N элементов. Исключить из массива элементы, принадлежащие промежутку [B; C].
  19. Дан одномерный массив числовых значений, насчитывающий N элементов. Вместо каждого элемента с нулевым значением поставить сумму двух предыдущих элементов массива.
  20. Дан одномерный массив числовых значений, насчитывающий N элементов. Определить, имеются ли в массиве два подряд идущих нуля.
  21. Дан одномерный массив числовых значений, насчитывающий N элементов. Подсчитать количество чисел, делящихся на 3 нацело, и среднее арифметическое чисел с чётными значениями. Поставить полученные величины на первое и последнее места в массиве (увеличив массив на 2 элемента).
  22. Заданы M строк символов, которые вводятся с клавиатуры. Найти количество символов в самой длинной строке. Выровнять строки по самой длинной строке, поставив перед каждой строкой соответствующее количество звёздочек.
  23. Заданы M строк символов, которые вводятся с клавиатуры. Из заданных строк, каждая из которых представляет одно слово, составить одну длинную строку, разделяя слова пробелами.
  24. Заданы M строк слов, которые вводятся с клавиатуры. Подсчитать количество гласных букв в каждой из заданных строк.
  25. Заданы M строк слов, которые вводятся с клавиатуры (в каждой строке – одно слово). Вводится слог (последовательность букв). Подсчитать количество таких слогов в каждой строке.
  26. Заданы M строк слов, которые вводятся с клавиатуры (в каждой строке – одно слово). Вводится слог (последовательность букв). Удалить данный слог из каждой строки.
  27. Заданы M строк символов, которые вводятся с клавиатуры. Напечатать все центральные буквы строк нечетной длины.
  28. Заданы M строк символов, которые вводятся с клавиатуры. Каждая строка содержит слово. Записать каждое слово в разрядку (вставить по пробелу между буквами).
  29. Задана строка символов, в которой встречается символ «.». Поставить после каждого такого символа системное время ПК.
  30. Заданы M строк, которые вводятся с клавиатуры. Подсчитать количество пробелов в каждой из строк.
  31. Заданы M строк символов, которые вводятся с клавиатуры. Каждая строка представляет собой последовательность символов, включающих в себя вопросительные знаки. Заменить в каждой строке все имеющиеся вопросительные знаки звёздочками.
  32. Последовательно вводятся числа. Определить сумму чисел с нечётными номерами и произведение чисел с чётными номерами (по порядку ввода). Подсчитать количество слагаемых и количество сомножителей. При вводе числа 55555 закончить работу.
  33. Определить сумму вводимых положительных чисел. Причём числа с нечётными номерами (по порядку ввода) суммировать с обратным знаком, а числа с чётными номерами перед суммированием возводить в квадрат. Подсчитать количество слагаемых. При вводе первого отрицательного числа закончить работу.
  34. Даны число P и число H. Определить сумму чисел меньше P, произведение чисел больше H и количество чисел в диапазоне значений P и H. При вводе числа равного P или H, закончить работу.
  35. Суммировать вводимые числа, среди которых нет нулевых. При вводе нуля обеспечить вывод текущего значения суммы. При вводе числа 99999 закончить работу.
  36. Вводятся положительные числа. Определить сумму чисел, делящихся на положительное число B нацело. При вводе отрицательного числа закончить работу.
  37. Для вводимых чисел определить процент положительных и отрицательных чисел. При вводе числа −65432 закончить работу.

Обработка двумерных массивов (матриц)

  1. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Найти наибольший элемент столбца матрицы A, для которого сумма абсолютных значений элементов максимальна.
  2. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Найти наибольшее значение среди средних значений для каждой строки матрицы.
  3. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Найти наименьший элемент столбца матрицы A, для которого сумма абсолютных значений элементов максимальна.
  4. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Найти наименьшее значение среди средних значений для каждой строки матрицы.
  5. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Определить средние значения по всем строкам и столбцам матрицы. Результат оформить в виде матрицы из N + 1 строк и M + 1 столбцов.
  6. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Найти сумму элементов всей матрицы. Определить, какую долю в этой сумме составляет сумма элементов каждого столбца. Результат оформить в виде матрицы из N + 1 строк и M столбцов.
  7. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Найти сумму элементов всей матрицы. Определить, какую долю в этой сумме составляет сумма элементов каждой строки. Результат оформить в виде матрицы из N строк и M+1 столбцов.
  8. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Определить, сколько отрицательных элементов содержится в каждом столбце и в каждой строке матрицы. Результат оформить в виде матрицы из N + 1 строк и M + 1 столбцов.
  9. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Определить, сколько нулевых элементов содержится в верхних L строках матрицы и в левых К столбцах матрицы.
  10. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Перемножить элементы каждого столбца матрицы с соответствующими элементами K-го столбца.Аим
  11. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Просуммировать элементы каждой строки матрицы с соответствующими элементами L-й строки.
  12. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Разделить элементы каждой строки на элемент этой строки с наибольшим значением.
  13. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Разделить элементы каждого столбца матрицы на элемент этого столбца с наибольшим значением.
  14. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Разделить элементы матрицы на элемент матрицы с наибольшим значением.
  15. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Все элементы имеют целый тип. Дано целое число H. Определить, какие столбцы имеют хотя бы одно такое число, а какие не имеют.
  16. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Исключить из матрицы строку с номером L. Сомкнуть строки матрицы.
  17. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Добавить к матрице строку и вставить ее под номером L.
  18. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Найти сумму элементов, стоящих на главной диагонали, и сумму элементов, стоящих на побочной диагонали (элементы главной диагонали имеют индексы от [0,0] до [N,N], а элементы побочной диагонали – от [N,0] до [0,N]).
  19. Создать квадратную матрицу A, имеющую N строк и N столбцов со случайными элементами. Определить сумму элементов, расположенных параллельно главной диагонали (ближайшие к главной). Элементы главной диагонали имеют индексы от [0,0] до [N,N].
  20. Создать квадратную матрицу A, имеющую N строк и N столбцов со случайными элементами. Определить произведение элементов, расположенных параллельно побочной диагонали (ближайшие к побочной). Элементы побочной диагонали имеют индексы от [N,0] до [0,N].
  21. Создать квадратную матрицу A, имеющую N строк и N столбцов со случайными элементами. Каждой паре элементов, симметричных относительно главной диагонали (ближайшие к главной), присвоить значения, равные полусумме этих симметричных значений (элементы главной диагонали имеют индексы от [0,0] до [N,N]).
  22. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Исходная матрица состоит из нулей и единиц. Добавить к матрице еще один столбец, каждый элемент которого делает количество единиц в каждой строке чётным.
  23. Создать квадратную матрицу A, имеющую N строк и N столбцов со случайными элементами. Найти сумму элементов, расположенных выше главной диагонали, и произведение элементов, расположенных выше побочной диагонали (элементы главной диагонали имеют индексы от [0,0] до [N,N], а элементы побочной диагонали — от [N,0] до [0,N]).
  24. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Дан номер строки L и номер столбца K, при помощи которых исходная матрица разбивается на четыре части. Найти сумму элементов каждой части.
  25. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Определить, сколько нулевых элементов содержится в каждом столбце и в каждой строке матрицы. Результат оформить в виде матрицы из N + 1 строк и M + 1 столбцов.
  26. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Дан номер строки L и номер столбца K, при помощи которых исходная матрица разбивается на четыре части. Найти среднее арифметическое элементов каждой части.
  27. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Все элементы имеют целый тип. Дано целое число H. Определить, какие строки имеют хотя бы одно такое число, а какие не имеют.
  28. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Исключить из матрицы столбец с номером K. Сомкнуть столбцы матрицы.
  29. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Добавить к матрице столбец чисел и вставить его под номером K.
  30. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Добавить к элементам каждого столбца такой новый элемент, чтобы сумма положительных элементов стала бы равна модулю суммы отрицательных элементов. Результат оформить в виде матрицы из N + 1 строк и M столбцов.
  31. Создать прямоугольную матрицу A, имеющую N строк и M столбцов со случайными элементами. Добавить к элементам каждой строки такой новый элемент, чтобы сумма положительных элементов стала бы равна модулю суммы отрицательных элементов. Результат оформить в виде матрицы из N строк и M + 1 столбцов.

Работа с ассоциативными массивами (таблицами данных)

  1. Используя данные таблицы отсортировать блюда по возрастанию цены. Вывести отсортированный вариант списка блюд.
    Блюдо
    Цена

    Борщь
    35

    Котлета
    40

    Каша
    20

    Чай
    3

  2. Имеется список учеников и результаты трёх тестов (баллы от 0 до 100).Определить средний балл каждого ученика по трём тестам, вывести список учеников по убыванию среднего балла.
  3. Известны данные о количестве мальчиков и девочек в нескольких классах. Отсортировать названия классов по возрастанию процента мальчиков, определить количество классов, в которых мальчиков больше, чем девочек, и вывести названия этих классов отдельно.
  4. Решить задачу, связанную с оценкой экономической деятельности группы предприятий на основе известных данных:

    • название предприятий;
    • плановый объем розничного товарооборота;
    • фактический объем розничного товарооборота.

    Требуется определить:

    1. процент выполнения плана каждым предприятием;
    2. количество предприятий, недовыполнивших план на 10% и более;
    3. наименьший плановый товарооборот;
    4. упорядочить предприятия по убыванию планового товара.
]]>
https://chel-center.ru/python-yfc/2019/10/01/metodicheskie-ukazaniya-dlya-samostoyatelnoj-raboty-v-i-semestre/feed/ 0
Практикум №2 — Методы сортировки https://chel-center.ru/python-yfc/2019/10/01/metodicheskie-ukazaniya-prakticheskoj-raboty-metody-sortirovki/ https://chel-center.ru/python-yfc/2019/10/01/metodicheskie-ukazaniya-prakticheskoj-raboty-metody-sortirovki/#respond Tue, 01 Oct 2019 01:49:17 +0000 http://chel-center.ru/python-yfc/?p=29 Читать далее «Практикум №2 — Методы сортировки»

]]>

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

В общем, под сортировкой мы будем понимать процесс перегруппировки заданного множества объектов в некотором определенном порядке. Цель сортировки – облегчить последующий поиск элементов в таком отсортированном множестве. Это почти универсальная, фундаментальная деятельность. Мы встречаемся с отсортированными объектами в телефонных книгах, в списках подоходных налогов, в оглавлениях книг, в библиотеках, в словарях, на складах – почти везде, где нужно искать хранимые объекты. Даже малышей учат держать свои вещи «в порядке», и они уже сталкиваются с некоторыми видами сортировок задолго до того, как познакомятся с азами арифметики».
Н. Вирт — Алгоритмы + данные = программы

Немного теории

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

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

Требованием, предъявляемые к внутренней сортировке является то, что методы не должны требовать дополнительной памяти: все перестановки с целью упорядочения элементов массива должны производиться в пределах того же массива. Мерой эффективности алгоритма внутренней сортировки являются число требуемых сравнений значений ключа (от английского Compare – C) и число перестановок элементов (от английского Move – M).

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

Сортировка включением

Одним из наиболее простых и естественных методов внутренней сортировки является сортировка простыми включениями. Идея алгоритма очень проста. Пусть имеется массив ключей Arr0, Arr1, …, ArrN‑1. Для каждого элемента массива, начиная со второго, производится сравнение с элементами с меньшим индексом. Элемент Arri последовательно сравнивается с элементами Arrj, где jЄ[i‑1;0], т.е. изменяется от i‑1 до 0. До тех пор, пока для очередного элемента Arrj выполняется соотношение Arrj > Arri, Arri и Arrj меняются местами. Если удается встретить такой элемент Arrj, что Arrj ≤ Arri, или если достигнута нижняя граница массива, производится переход к обработке элемента Arri+1. Так продолжается до тех пор, пока не будет достигнута верхняя граница массива.

Легко видеть, что в лучшем случае, когда массив уже упорядочен для выполнения алгоритма с массивом из N элементов потребуется N‑1 сравнение и 0 пересылок. В худшем случае, когда массив упорядочен в обратном порядке потребуется N(N‑1)/2 сравнений и столько же пересылок. Таким образом, можно оценивать сложность метода простых включений как O(N2).

Можно сократить число сравнений, применяемых в методе простых включений, если воспользоваться тем, что при обработке элемента Arri массива элементы Arr0, Arr1, …, Arri‑1 уже упорядочены, и воспользоваться для поиска элемента, с которым должна быть произведена перестановка, методом двоичного деления. В этом случае оценка числа требуемых сравнений становится O(N*Log(N)). Заметим, что поскольку при выполнении перестановки требуется сдвижка на один элемент нескольких элементов, то оценка числа пересылок остается O(N2). Алгоритм сортировки включением, оформленный в виде функции приведен ниже.

Обменная сортировка

Простая обменная сортировка, называемая «методом пузырька», для массива Arr0, Arr2, …, ArrN‑1 работает следующим образом. Начиная с конца массива сравниваются два соседних элемента ArrN‑1 и ArrN‑2. Если выполняется условие ArrN‑2 > ArrN‑1, то они меняются местами. Процесс продолжается для ArrN‑2 и ArrN‑3 и т.д., пока не будет произведено сравнение Arr1 и Arr0. Понятно, что после этого на месте Arr0 окажется элемент с наименьшим значением. На втором шаге процесс повторяется, но последними сравниваются Arr2 и Arr1. И так далее. На последнем шаге будут сравниваться только текущие значения ArrN‑1 и ArrN‑2. Понятна аналогия с пузырьком, поскольку наименьшие элементы, самые «легкие», постепенно «всплывают» к верхней границе массива.

Для метода обменной сортировки требуется число сравнений N(N‑1)/2, минимальное число пересылок 0, а среднее и максимальное число пересылок − O(N2).

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

Сортировка выбором

При сортировке массива Arr0, Arr2, …, ArrN‑1 методом простого выбора среди всех элементов находится элемент с наименьшим значением Arri, и Arr0 и Arri обмениваются значениями. Затем этот процесс повторяется для получаемого подмассива Arr1, Arr2, …, ArrN‑1, … Arrj, Arrj+1, …, ArrN‑1 до тех пор, пока мы не дойдем до подмассива ArrN‑1, содержащего к этому моменту наибольшее значение.
Для метода сортировки простым выбором оценка требуемого числа сравнений – N(N‑1)/2. Порядок требуемого числа пересылок, которые требуются для выбора минимального элемента, в худшем случае составляет O(N2). Однако порядок среднего числа пересылок есть O(N*Lg(N)), что в ряде случаев делает этот метод предпочтительным.

Что бы теория была понятна «визуальщикам»

ПРИМЕЧАНИЕ: Кто сделает подобный мультик на Python для описанных выше алгоритмов может смело подходить с направлением из деканата и зачёткой. Курсовая работа и экзамен — «автоматом».

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

Сравнение методов внутренней сортировки

Для рассмотренных простых методов сортировки существуют точные формулы, вычисление которых дает минимальное, максимальное и среднее число сравнений ключей C и пересылок элементов массива M (см. Таблицу 1 ниже).

Характеристики простых методов сортировки (Таблица 1)

Метод   Min Avr Max
Прямое включение C N–1 (N2 + N – 2)/4 (N2 –N)/2 – 1
M 2(N–1) (N2 – 9N – 10)/4 (N2 –3N-4)/2
Прямой выбор C (N2 – N)/2 (N2 – N)/2 (N2 – N)/2
M 3(N–1) N(Ln(N) + 0,57) N2/4 + 3(N–1)
Прямой обмен C (N2 – N)/2 (N2 – N)/2 (N2 – N)/2
M 0 0,75(N2 – N) 1,5(N2 – N)

Экспериментальное исследование алгоритмов

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

  1. заполнить экспериментальными данными сравнительную таблицу эффективности алгоритмов (см. Таблицу 2 ниже);
  2. рассчитать теоретические значения показателей эффективности для массива вашего размера. Для этого рекомендуется использовать MS Exell;
  3. сравнить экспериментально полученные и расчетные значения;
  4. высказать свое мнение об эффективности алгоритмов.

Сравнительная таблица эффективности алгоритмов (Таблица 2)

Массив Показатель [DIM] элементов
    Insert Select Bubble
Упорядоченный C [Value] [Value] [Value]
M [Value] [Value] [Value]
Обратно упорядоченный C [Value] [Value] [Value]
M [Value] [Value] [Value]
Случайный Avr(C) [Value] [Value] [Value]
 Avr(M) [Value] [Value] [Value]

По структуре таблицы сравнительной эффективности легко видеть, что Вам необходимо проделать как минимум 9 опытов (3 метода х 3 реализации одномерного массива), в каждом из которых должны быть определены два числа C и M. Но в третьем случае, случайного массива, в отличие от двух первых, заранее нельзя предсказать значения показателей эффективности (смотри теорию выше). Естественно, что сравнительный анализ алгоритмов возможен только по средним значениям (в таблице Вы видите функцию Avr(C) – Average, что значит среднее значение С). Для этого необходимо провести серию опытов, желательно, 100–150 для каждого алгоритма (для получения устойчивых значений), т.е. всего 300–450 опытов. Именно это «жуткое» количество экспериментов и определяет структуру построения программы для реализации плана практической работы первой части курсовой работы.

Итак, каждый алгоритм сортировки должен быть оформлен в виде самостоятельной программной единицы – функции, в Python это подключаемый к основной программе модуль. Записать эти модули необходимо в различные файлы, например, insert.py, select.py и bubble.py. Пример одного из них, метод простого включения, файл insert.py,

#метод простого включения Insert
def insert(arr, dim):
    alg_count = [0, 0]              # массив для показателей эффективности
    
    for i in range(1, dim):         # Основной цикл со 2-го элемента право 
        temp = arr[i]               # Запомним элемент для сравнения 
        j = i - 1
        while j >= 0:               # Ищем влево ближайший меньший  
            alg_count[0] += 1       # Считаем операции сравнения 
            if arr[j] > temp:
                alg_count[1] += 1   # Считаем операции перестановки 
                arr[j+1] = arr[j]   # Сдвигаем элемент влево, а на его место ставим наименьший
                arr[j] = temp
            j -= 1        
    return alg_count

А вот оставшиеся две функции Вам надо написать самостоятельно. Обратите внимание на оформление текста программы и комментарии к алгоритму. Комментарии не позволят Вам забыть эти алгоритмы через неделю после сдачи отчета о своей работе. Кроме того, в отдельный файл (например, sort-exp.py) необходимо записать программу, которая реализует весь численный эксперимент. Естественно, результаты вычислений необходимо сохранять в отдельном файле, который можно прочитать и использовать при заполнении таблицы 2.

Отчет по этой практической работе является частью I вашей большой курсовой работы. Время на выполнение — 2 недели с момента выдачи задания, в нашем случае deadline наступает 14 марта 2019. Не опаздывайте, впереди у вас обширное задание по курсовой работе до конца семестра.

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

]]>
https://chel-center.ru/python-yfc/2019/10/01/metodicheskie-ukazaniya-prakticheskoj-raboty-metody-sortirovki/feed/ 0
Практикум №3 — Numpy, Matplotlib и СЛАУ https://chel-center.ru/python-yfc/2019/10/01/metodicheskie-ukazaniya-2-chasti-kursovoj-raboty/ https://chel-center.ru/python-yfc/2019/10/01/metodicheskie-ukazaniya-2-chasti-kursovoj-raboty/#respond Tue, 01 Oct 2019 02:30:50 +0000 http://chel-center.ru/python-yfc/?p=42 Читать далее «Практикум №3 — Numpy, Matplotlib и СЛАУ»

]]>
Если кратко, то:

  1. Установка и настройка numpy и matplotlib под PyCharm;
  2. Несколько задач для демонстрации возможностей;
  3. 30 задач матричной алгебры;
  4. Решение систем линейных алгебраических уравнений;
  5. Демонстрационная программа решения СЛАУ мотодом Гаусса;
  6. Персональное задание с набором из 5 СЛАУ, которые надо решить с использованием numpy.

Курсовая работа. Часть II. Матрицы и СЛАУ

 
Скачать

Краткое руководство по numpy

numpy-ru

Скачать

Полное руководство по numpy (англ.) 

]]>
https://chel-center.ru/python-yfc/2019/10/01/metodicheskie-ukazaniya-2-chasti-kursovoj-raboty/feed/ 0
Отладка в IDLE — найдите и исправьте ошибки Python‑кода https://chel-center.ru/python-yfc/2020/11/14/otladka-v-idle-nbsp-mdash-najdite-i-ispravte-oshibki-python-koda/ https://chel-center.ru/python-yfc/2020/11/14/otladka-v-idle-nbsp-mdash-najdite-i-ispravte-oshibki-python-koda/#respond Sat, 14 Nov 2020 08:17:23 +0000 http://chel-center.ru/python-yfc/?p=31120 Читать далее «Отладка в IDLE — найдите и исправьте ошибки Python‑кода»

]]>
В этом уроке:

Ошибки совершают все — даже опытные профессиональные разработчики! Интерактивный интерпретатор Python, IDLE, довольно хорошо выявляет такие ошибки, как синтаксические ошибки и ошибки времени выполнения, но есть третий тип ошибок, с которыми вы, возможно, уже сталкивались. Логические ошибки возникают, когда действующая в остальном программа не выполняет то, что было задумано. Логические ошибки вызывают непредвиденное поведение, называемое ошибками. Удаление ошибок называется отладкой.

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

В этом уроке вы:

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

Используйте окно управления отладкой

Основным интерфейсом отладчика IDLE является окно Debug Control, или для краткости окно Debug. Вы можете открыть окно «Debug», выбрав «Debug» → «Debugger» в главном меню интерактивного окна. Идите вперед и откройте окно отладки.

Примечание. Если в строке меню отсутствует меню «Debug», убедитесь, что интерактивное окно находится в фокусе, щелкнув его.

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

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

Окно управления отладкой: обзор

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

for i in range(1, 4):
    j = i * 2
    print(f"i is {i} and j is {j}")

Сохраните файл, затем оставьте окно отладки открытым и нажмите F5. Вы заметите, что до исполнения не далеко.

Окно отладки будет выглядеть так:

Обратите внимание, что панель стека в верхней части окна содержит следующее сообщение:

> '__main__'.(), line 1: for i in range(1, 4):

Это говорит о том, что строка 1 (которая содержит код for i in range(1, 4):) вот-вот будет запущена, но еще не началась. Часть сообщения '__main__'.() относится к тому факту, что вы в данный момент находитесь в основном разделе программы, а не находитесь, например, в определении функции до того, как будет достигнут основной блок кода.

Под панелью Stack находится панель Locals, в которой перечислены некоторые странно выглядящие вещи, такие как __annotations__, __builtins__, __doc__ и т.д. Это внутренние системные переменные, которые пока можно игнорировать. Во время выполнения программы вы увидите переменные, объявленные в коде, отображаемом в этом окне, чтобы вы могли отслеживать их значение.

В верхнем левом углу окна отладки расположены пять кнопок: Go, Step, Over, Out и Quit. Эти кнопки управляют тем, как отладчик перемещается по вашему коду.

В следующих разделах вы узнаете, что делает каждая из этих кнопок, начиная с Step.

Кнопка Step

Идите вперед и нажмите Step в верхнем левом углу окна отладки. Окно отладки немного изменится и будет выглядеть так:

Здесь есть два отличия, на которые следует обратить внимание. Сначала сообщение на панели стека меняется на следующее:

> '__main__'.(), line 2: j = i * 2:

На этом этапе выполняется строка 1 вашего кода, а отладчик остановился непосредственно перед выполнением строки 2.

Второе изменение, которое следует отметить, — это новая переменная i, которой на панели Locals присвоено значение 1. Это потому, что цикл for в первой строке кода создал переменную i и присвоил ей значение 1.

Продолжайте нажимать кнопку Step, чтобы пройтись по вашему коду построчно, и посмотрите, что происходит в окне отладчика. Когда вы дойдете до строкового вывода (print(f"i is {i} and j is {j}")), вы сможете увидеть вывод, отображаемый в интерактивном окне, по частям.

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

Точки останова и кнопка перехода

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

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

Чтобы установить точку останова, на строке кода в окне редактора, на которой вы хотите сделать паузу, щелкните правой кнопкой мыши и выберите «Set Breakpoint». IDLE выделяет линию желтым цветом, чтобы указать, что ваша точка останова установлена. Чтобы удалить точку останова, щелкните правой кнопкой мыши строку с точкой останова и выберите «Clear Breakpoint».

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

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

Сохраните и запустите файл. Как и раньше, панель стека в окне отладки указывает, что отладчик запущен и ожидает выполнения строки 1. Щелкните Go и посмотрите, что происходит в окне отладки:

На панели стека теперь отображается следующее сообщение, указывающее, что он ожидает выполнения строки 3:

> '__main__'.(), line 3: print(f"i is {i} and j is {j}")

Если вы посмотрите на панель «Locals», то увидите, что обе переменные i и j имеют значения 1 и 2 соответственно. Нажав Go, вы указали отладчику, что он должен выполнять ваш код непрерывно, пока он не достигнет точки останова или конца программы. Снова нажмите Go. Окно отладки теперь выглядит так:

Вы видите, что изменилось? То же сообщение, что и раньше, отображается на панели стека, указывая, что отладчик ожидает повторного выполнения строки 3. Однако значения переменных i и j теперь равны 2 и 4. Интерактивное окно также отображает результат выполнения строки с помощью print() в первый раз в цикле.

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

Нажмите Go в третий раз. Теперь i и j имеют значения 3 и 6. Как вы думаете, что произойдет, если вы нажмете Go еще раз? Поскольку цикл for повторяется только три раза, когда вы снова нажмете Go, программа завершит работу.

Снова и снова

Кнопка Over работает как комбинация Step и Go — перепрыгиваем через функцию или цикл. Другими словами, если вы не собираетесь по-операторно отслеживать и отлаживать функцию, то можете запустить код без необходимости заходить в неё. Кнопка Over переводит вас прямо к результату выполнения этой функции.

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

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

Устранение некоторых ошибок

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

Следующий код определяет функцию add_underscores(), которая принимает в качестве аргумента одно строковое объектное слово и возвращает новую строку, содержащую копию слова, в которой каждый символ окружен подчеркиванием. Например, add_underscores("python") должен вернуть _p_y_t_h_o_n_.

Вот код с ошибками:

def add_underscores(word):
    new_word = "_"
    for i in range(len(word)):
        new_word = word[i] + "_"
    return new_word

phrase = "hello"
print(add_underscores(phrase))

Введите этот код в окно редактора, затем сохраните файл и нажмите F5, чтобы запустить программу. Ожидаемый результат — _h_e_l_l_o_, но вместо этого все, что вы видите, — это o_ или буква «o», за которой следует одно подчеркивание.

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

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

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

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

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

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

Делай 1. Угадайте, где находится ошибка

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

Обратите внимание, что программа разделена на два отдельных раздела: определение функции (где определено add_underscores()) и основной блок кода, который определяет переменную фразу со значением hello, а затем выводит результат вызова add_underscores(phrase) .

Посмотрите на основной раздел кода:

phrase = "hello"
print(add_underscores(phrase))

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

def add_underscores(word):
    new_word = "_"
    for i in range(len(word)):
        new_word = word[i] + "_"
    return new_word

Первая строка кода внутри функции создает переменную new_word со значением "_". У вас все в порядке, поэтому вы можете сделать вывод, что проблема где-то в теле цикла for.

Делай 2. Установите точку останова и проверьте код

Теперь, когда вы определили, где должна быть ошибка, установите точку останова в начале цикла for, чтобы вы могли точно отслеживать, что происходит внутри кода, с помощью окна отладки:

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

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

На этом этапе выполнение кода приостанавливается непосредственно перед входом в цикл for в функции add_underscores(). Обратите внимание, что на панели Locals отображаются две локальные переменные, word и new_word. В настоящее время word имеет значение "hello", а new_word — значение "_", как и ожидалось.

Щелкните Step один раз, чтобы войти в цикл for. Окно отладки изменится и новая переменная i со значением 0 отображается на панели Locals:

i — это счетчик, используемый в цикле for, и вы можете использовать его, чтобы отслеживать, какую итерацию цикла for вы просматриваете в данный момент.

Еще раз нажмите Step. Если вы посмотрите на панель Locals, то увидите, что переменная new_word приняла значение h_:

Это неправильно. Первоначально new_word имело значение "_", а на второй итерации цикла for теперь оно должно иметь значение "_h_". Если вы нажмете Step еще несколько раз, вы увидите, что для new_word устанавливается значение "e_", затем "l_" и т.д.

Делай 3. Определите ошибку и попытайтесь ее исправить

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

new_word = word[i] + "_"

Посмотрите внимательно на строку. Она сообщает Python, что нужно получить следующий символ слова, прикрепить к нему подчеркивание и присвоить эту новую строку переменной new_word. Это именно то поведение, свидетелем которого вы стали, пройдя цикл for!

Для решения проблемы вам нужно указать Python объединить строковое слово [i] + "_" с существующим значением new_word. Нажмите Quit в окне Debug, но пока не закрывайте окно. Откройте окно редактора и измените строку внутри цикла for на следующую:

new_word = new_word + word[i] + "_"

Делай 4. Повторяйте шаги с 1 по 3, пока ошибка не исчезнет

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

Примечание. Если вы закрыли отладчик на предыдущем шаге, не нажав кнопку Quit, при повторном открытии окна отладки вы можете увидеть следующую ошибку:

You can only toggle the debugger when idle

(Вы можете переключать отладчик только в режиме ожидания)

По завершении сеанса отладки всегда нажимайте кнопку Go или Quit, а не просто закрывайте отладчик, иначе у вас могут возникнуть проблемы с его повторным открытием.Чтобы избавиться от этой ошибки, вам придется закрыть и снова открыть IDLE.

Программа приостанавливается непосредственно перед входом в цикл for в add_underscores(). Несколько раз нажмите Step и посмотрите, что происходит с переменной new_word на каждой итерации. Успех! Все работает как положено!

Ваша первая попытка исправить ошибку сработала, поэтому вам больше не нужно повторять шаги 1–3. Так будет не всегда. Иногда, прежде чем исправлять ошибку, вам придется повторить этот процесс несколько раз.

Альтернативные способы поиска ошибок

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

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

Например, вместо отладки предыдущей программы с помощью окна отладки вы можете добавить следующую строку в конец цикла for в add_underscores():

print(f"i = {i}; new_word = {new_word}")

В этом случае измененный код будет выглядеть так:

def add_underscores(word):
    new_word = "_"
    for i in range(len(word)):
        new_word = word[i] + "_"
        print(f"i = {i}; new_word = {new_word}")
    return new_word

phrase = "hello"
print(add_underscores(phrase))

Когда вы запускаете файл, интерактивное окно отображает следующий вывод:

i = 0; new_word = h_
i = 1; new_word = e_
i = 2; new_word = l_
i = 3; new_word = l_
i = 4; new_word = o_
o_

Здесь показано, какие значение имеет new_word на каждой итерации цикла for. Последняя строка, содержащая только один знак подчеркивания, является результатом выполнения print(add_underscore(phrase)) в конце программы.

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

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

Пример цикла в этом разделе может быть хорошим примером для иллюстрации процесса отладки, но это не лучший пример кода Pythonic. Использование индекса i свидетельствует о том, что может быть лучший способ написать цикл. Один из способов улучшить этот цикл — напрямую перебирать символы в слове. Вот один из способов сделать это:

def add_underscores(word):
    new_word = "_"
    for letter in word:
        new_word = new_word + letter + "_"
    return new_word

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

Заключение: отладка Python с помощью IDLE

Вот так то! Теперь вы знаете все об отладке с помощью окна Debug IDLE. Вы можете использовать базовые принципы, которые вы использовали здесь, с рядом различных инструментов отладки. Теперь у вас есть все необходимое, чтобы начать отладку кода Python.

В этом уроке вы узнали:

  • Как использовать окно управления отладкой IDLE для проверки значений переменных.
  • Как вставить точки останова, чтобы лучше понять, как работает ваш код.
  • Как использовать кнопки Step, Go, Over и Out для построчного отслеживания ошибок.

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

  1. Угадай, где находится ошибка.
  2. Установите точку останова и проверьте код. Определите ошибку и попытайтесь ее исправить.
  3. Повторяйте шаги с 1 по 3, пока ошибка не будет исправлена.
  4. Отладка — это не только наука, но и искусство.

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

Find & Fix Code Bugs in Python: Debug With IDLE

]]>
https://chel-center.ru/python-yfc/2020/11/14/otladka-v-idle-nbsp-mdash-najdite-i-ispravte-oshibki-python-koda/feed/ 0
Как использовать API Github https://chel-center.ru/python-yfc/2020/11/17/kak-ispolzovat-api-github/ https://chel-center.ru/python-yfc/2020/11/17/kak-ispolzovat-api-github/#respond Tue, 17 Nov 2020 05:05:03 +0000 http://chel-center.ru/python-yfc/?p=31185 Читать далее «Как использовать API Github»

]]>
Использование интерфейса программирования приложений Github v3 для поиска репозиториев, пользователей, совершения фиксации, удаления файла и многого другого в Python с помощью запросов и библиотек PyGithub.

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

Как вы, возможно, уже знаете, есть масса данных, которые нужно захватить. В этом руководствевы узнаете, как использовать Github API v3 в Python, используя как запросы, так и библиотеки PyGithub.

Для начала установим зависимости:

pip3 install PyGithub requests

Получение данных пользователя

Поскольку использовать Github API v3 довольно просто, вы можете сделать простой запрос GET на определенный URL-адрес и получить результаты:

import requests
from pprint import pprint

# Имя пользователя github
username = "x4nth055"

# url для запроса
url = f"https://api.github.com/users/{username}"

# делаем запрос и возвращаем json
user_data = requests.get(url).json()

# довольно распечатать данные JSON
pprint(user_data)

Здесь я использовал свою учетную запись, вот часть возвращенного JSON (вы также можете увидеть его в браузере):

{'avatar_url': 'https://avatars3.githubusercontent.com/u/37851086?v=4',
 'bio': None,
 'blog': 'https://www.thepythoncode.com',
 'company': None,
 'created_at': '2018-03-27T21:49:04Z',
 'email': None,
 'events_url': 'https://api.github.com/users/x4nth055/events{/privacy}',
 'followers': 93,
 'followers_url': 'https://api.github.com/users/x4nth055/followers',
 'following': 41,
 'following_url': 'https://api.github.com/users/x4nth055/following{/other_user}',
 'gists_url': 'https://api.github.com/users/x4nth055/gists{/gist_id}',
 'gravatar_id': '',
 'hireable': True,
 'html_url': 'https://github.com/x4nth055',
 'id': 37851086,
 'login': 'x4nth055',
 'name': 'Rockikz',
<..SNIPPED..>

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

Получение публичных репозиториев пользователя

Давайте получим все общедоступные репозитории пользователя с помощью только что установленной библиотеки PyGithub:

import base64
from github import Github
from pprint import pprint

# Github username
username = "x4nth055"
# pygithub object
g = Github()
# get that user by username
user = g.get_user(username)

for repo in user.get_repos():
    print(repo)

Вот мой результат:

Repository(full_name="x4nth055/aind2-rnn")
Repository(full_name="x4nth055/awesome-algeria")
Repository(full_name="x4nth055/emotion-recognition-using-speech")
Repository(full_name="x4nth055/emotion-recognition-using-text")
Repository(full_name="x4nth055/food-reviews-sentiment-analysis")
Repository(full_name="x4nth055/hrk")
Repository(full_name="x4nth055/lp_simplex")
Repository(full_name="x4nth055/price-prediction")
Repository(full_name="x4nth055/product_recommendation")
Repository(full_name="x4nth055/pythoncode-tutorials")
Repository(full_name="x4nth055/sentiment_analysis_naive_bayes")

Хорошо, поэтому я сделал простую функцию для извлечения полезной информации из этого объекта репозитория:

def print_repo(repo):
    # repository full name
    print("Full name:", repo.full_name)
    # repository description
    print("Description:", repo.description)
    # the date of when the repo was created
    print("Date created:", repo.created_at)
    # the date of the last git push
    print("Date of last push:", repo.pushed_at)
    # home website (if available)
    print("Home Page:", repo.homepage)
    # programming language
    print("Language:", repo.language)
    # number of forks
    print("Number of forks:", repo.forks)
    # number of stars
    print("Number of stars:", repo.stargazers_count)
    print("-"*50)
    # repository content (files & directories)
    print("Contents:")
    for content in repo.get_contents(""):
        print(content)
    try:
        # repo license
        print("License:", base64.b64decode(repo.get_license().content.encode()).decode())
    except:
        pass

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

# перебрать все публичные репозитории
for repo in user.get_repos():
    print_repo(repo)
    print("="*100)

Это напечатает некоторую информацию о каждом публичном репозитории этого пользователя:

====================================================================================================
Full name: x4nth055/pythoncode-tutorials
Description: The Python Code Tutorials
Date created: 2019-07-29 12:35:40
Date of last push: 2020-04-02 15:12:38
Home Page: https://www.thepythoncode.com
Language: Python
Number of forks: 154
Number of stars: 150
--------------------------------------------------
Contents:
ContentFile(path="LICENSE")
ContentFile(path="README.md")
ContentFile(path="ethical-hacking")
ContentFile(path="general")
ContentFile(path="images")
ContentFile(path="machine-learning")
ContentFile(path="python-standard-library")
ContentFile(path="scapy")
ContentFile(path="web-scraping")
License: MIT License
<..SNIPPED..>

Я усек весь вывод, так как он вернет все репозитории и их информацию, вы можете видеть, что мы использовали метод repo.get_contents("") для получения всех файлов и папок этого репозитория, PyGithub анализирует его в объект ContentFile, используйте dir(content), чтобы увидеть другие полезные поля.

Кроме того, если у вас есть частные репозитории,вы можете получить к ним доступ, аутентифицировав свою учетную запись (используя правильные учетные данные) с помощью PyGithub следующим образом:

username = "username"
password = "password"

# authenticate to github
g = Github(username, password)

# get the authenticated user
user = g.get_user()
for repo in user.get_repos():
    print_repo(repo)

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

Поиск репозиториев

Github API довольно богат, вы можете искать репозитории по определенному запросу, как и на веб-сайте:

# поиск репозиториев по имени
for repo in g.search_repositories("pythoncode tutorials"):
    # распечатать сведения о репозитории
    print_repo(repo)

Это вернет 9 репозиториев и их информацию.

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

# поиск по языку программирования
for i, repo in enumerate(g.search_repositories("language:python")):
    print_repo(repo)
    print("="*100)
    if i == 9:
        break

Чтобы выполнить поиск по определенной теме, вы просто указываете что-то вроде topic:machine-learning в методе search_repositories().

Управление файлами в воём репозитории

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

# поиск моего репозитория
repo = g.search_repositories("pythoncode tutorials")[0]

# создать файл и зафиксировать n push
repo.create_file("test.txt", "commit message", "content of the file")

# удалить созданный файл
contents = repo.get_contents("test.txt")
repo.delete_file(contents.path, "remove test.txt", contents.sha)

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

И действительно, после выполнения вышеуказанных строк кода,коммиты были созданы и отправлены:

Заключение

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

  • g.get_organization(login): возвращает объект Organization, который представляет организацию Github.
  • g.get_gist(id): возвращает объект Gist, который представляет суть в Github.
  • g.search_code(query): возвращает разбитый на страницы список объектов ContentFile, в которых он представляет совпадающие файлы в нескольких репозиториях.
  • g.search_topics(query): возвращает разбитый на страницы список объектов Topic, в которых он представляет тему Github.
  • g.search_commits(query): возвращает разбитый на страницы список объектов фиксации, в которых он представляет фиксацию в Github.

Их гораздо больше, используйте dir(g), чтобы получить другие методы, проверьте документацию PyGithub или API Github для получения подробной информации.

По мотивам How to Use Github API in Python

]]>
https://chel-center.ru/python-yfc/2020/11/17/kak-ispolzovat-api-github/feed/ 0
Линейная регрессия в Python https://chel-center.ru/python-yfc/2020/12/20/linejnaya-regressiya-v-python/ https://chel-center.ru/python-yfc/2020/12/20/linejnaya-regressiya-v-python/#respond Sun, 20 Dec 2020 12:22:43 +0000 http://chel-center.ru/python-yfc/?p=31194 Читать далее «Линейная регрессия в Python»

]]>

Содержание

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

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

  • Что такое линейная регрессия.
  • Для чего используется линейная регрессия.
  • Как работает линейная регрессия.
  • Как реализовать линейную регрессию в Python, шаг за шагом.

Регрессия

Регрессионный анализ — одна из важнейших областей статистики и машинного обучения. Доступно множество методов регрессии. Линейная регрессия — одна из них.

Что такое регрессия?

Регрессия ищет отношения между переменными.

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

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

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

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

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

Зависимые функции называются зависимыми переменными, выходами или откликами.

Независимые признаки называются независимыми переменными, входными данными или предикторами.

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

Обычно выходы обозначаются y, а входы — x. Если есть две или более независимых переменных, их можно представить в виде вектора X = (x_1, \dots , x_r), где r — количество входов.

Когда вам нужна регрессия?

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

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

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

Линейная регрессия

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

Формулировка проблемы

При реализации линейной регрессии некоторой зависимой переменной y на множестве независимых переменных X = (x_1, \dots , x_r), где r — количество предикторов, вы предполагаете линейную связь между y и x:

y = \beta_0 + \beta_1x_1 + \dots + \beta_rx_r + \epsilon.

Это уравнение является уравнением регрессии. \beta_0, \beta_1, \dots , \beta_r — коэффициенты регрессии, \epsilon — случайная ошибка.

Линейная регрессия вычисляет оценки коэффициентов регрессии или просто прогнозируемых весов, обозначенных \beta_0, \beta_1, \dots , \beta_r. Они определяют оценочную функцию регрессии

f(x) = \beta_0 + \beta_1x_1 + \dots + \beta_rx_r.

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

Предполагаемый или прогнозируемый ответ f(x_i) для каждого наблюдения i = 1, \dots , n должен быть как можно ближе к соответствующему фактическому значению y_i. Разности y_i - f(x_i) для всех наблюдений i = 1, \dots , n называются остатками. Регрессия — это определение наилучшего прогнозируемого веса, то есть веса, соответствующие наименьшим остаткам.

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

i = 1, \dots , n: SSR = \sum_i{(y_i - f(x_i))^2}.

Такой подход называется метод наименьших квадратов.

Эффективность регрессии

Изменение фактических ответов y_i, i = 1, \dots , n, частично происходит из-за зависимости от предикторов x_i. Однако существует также дополнительная внутренняя дисперсия выпуска.

Коэффициент детерминации, обозначенный как R^2, сообщает вам, какое количество вариаций можно объяснить зависимостью от x с использованием конкретной регрессионной модели. Большой R^2 указывает на лучшее соответствие и означает, что модель может лучше объяснить вариации выходных данных с разными входными данными.

Значение R^2 = 1 соответствует SSR = 0, это идеальное совпадение, поскольку значения предсказанных и фактических ответов полностью совпадают друг с другом.

Простая линейная регрессия

Простая или одномерная линейная регрессия — это простейший случай линейной регрессии с одной независимой переменной X = ?.

Ниже, на рисунке, показана простая линейная регрессия:

Пример линейной регрессии
Пример линейной регрессии

При реализации простой линейной регрессии вы обычно начинаете с заданного набора пар ввода-вывода (x-y) (зеленые кружки). Эти пары — ваши наблюдения. Например, крайнее левое наблюдение (зеленый кружок) имеет вход x = 5, а фактический выход (значение) y = 5. В следующем наблюдении x = 15 и y = 20, и так далее.

Расчетная функция регрессии (черная линия) имеет уравнение f(x) = b_0 + b_1x. Ваша цель — вычислить оптимальные значения прогнозируемых весов b_0, которые минимизируют SSR и определяют предполагаемую функцию регрессии. Значение b_0, также называемое перехватом, показывает точку, в которой линия предполагаемой регрессии пересекает ось. Это значение оценочного ответа f(x) для x = 0. Значение b_1 определяет наклон оцененной линии регрессии.

Прогнозируемые ответы (красные квадраты) — это точки на линии регрессии, которые соответствуют входным значениям. Например, для входа x = 5 прогнозируемый ответ равен f(5) = 8,33 (представлен крайним левым красным квадратом).

Невязки (вертикальные пунктирные серые линии) могут быть вычислены как y_i - f(x_i) = y_i - b_0 - b_1x_i для i = 1,\dots, ?. Это расстояния между зелеными кружками и красными квадратами. Когда вы реализуете линейную регрессию, вы фактически пытаетесь минимизировать эти расстояния и сделать красные квадраты как можно ближе к заранее определенным зеленым кругам.

Множественная линейная регрессия

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

f(x_1, x_2) = b_0 + b_1x_1 + b_2x_2.

Он представляет собой плоскость регрессии в трехмерном пространстве. Цель регрессии — определить значения весов b_0, b_1 и b_2 так, чтобы эта плоскость была как можно ближе к реальным значения и дала минимальный SSR. Случай более чем двух независимых переменных аналогичен, но более общий. Предполагаемая функция регрессии —

f(x_1,\dots, x_r) = b_0 + b_1x_1 + \dots + b_rx_r

и необходимо определить r + 1 весовых коэффициентов, когда количество входных данных равно.

Полиномиальная регрессия

Вы можете рассматривать полиномиальную регрессию как обобщенный случай линейной регрессии. Вы предполагаете полиномиальную зависимость между выходом и входами и, следовательно, полиномиальную оценочную функцию регрессии. Другими словами, помимо линейных членов, таких как, ваша функция регрессии f может включать в себя нелинейные члены, такие как b_2x_1^2, b_3x_1^3 или даже b_4x_1x_2, b_5x_1^2x_2 и т. д. Простейший пример полиномиальной регрессии имеет единственную независимую переменную, а предполагаемая функция регрессии — полином степени 2: f(x) = b_0 + b_1x + b_2x^2. Теперь помните, что вы хотите вычислить b_0, b_1 и b_2, которые минимизируют SSR. Это ваши неизвестные! Помня об этом, сравните предыдущую функцию регрессии с функцией f(x_1, x_2) = b_0 + b_1x_1 + b_2x_2, используемой для линейной регрессии. Они выглядят очень похоже и являются линейными функциями от неизвестных b_0, b_1 и b_2. Вот почему вы можете решить задачу полиномиальной регрессии как линейную задачу с членом x^2, рассматриваемым как входная переменная. В случае двух переменных и полинома степени 2 функция регрессии имеет следующий вид:

f(x_1, x_2) = b_0 + b_1x_1 + b_2x_1^2 + b_4x_1x_2 + b_5x_2^2.

Порядок решения проблемы идентичен предыдущему случаю. Вы применяете линейную регрессию для пяти входных данных: x_1, x_2, x_1^2, x_1x_2 и x_2^2. В результате регрессии вы получаете значения шести весов, которые минимизируют SSR: b_0, b_1, b_2, b_3, b_4 и b_5. Конечно, существуют и более общие проблемы, но этого должно быть достаточно, чтобы проиллюстрировать суть дела.

Недостаточное и избыточное соответствие

Один очень важный вопрос, который может возникнуть при реализации полиномиальной регрессии, связан с выбором оптимальной степени функции полиномиальной регрессии. Для этого нет простого рецепта. Это зависит от случая. Тем не менее, вы должны знать о двух проблемах, которые могут возникнуть в результате выбора степени: недостаточное и избыточное соответствие. Неадекватное соответствие возникает, когда модель не может точно уловить зависимости между данными, обычно, из-за ее собственной простоты. Оно часто дает низкий R^2 с известными данными и невозможность обобщения для новых данных. Подгонка происходит, когда модель изучает как зависимости между данными, так и их случайные колебания. Другими словами, модель слишком хорошо изучает существующие данные. Сложные модели, которые имеют множество функций или терминов, часто подвержены переобучению. Применительно к известным данным такие модели обычно дают высокие значения R^2. Однако, они часто плохо обобщаются и имеют значительно меньшее значение R^2 при использовании с новыми данными. Ниже, на рисунке, показаны недостаточно подогнанные, хорошо подогнанные и переобученные (избыточные) модели:

Пример недостаточно подогнанных, хорошо подогнанных и избыточных моделей
Пример недостаточно подогнанных, хорошо подогнанных и избыточных моделей

На верхнем левом графике показана линия линейной регрессии с низким значением R^2. Также может быть важно, что прямая линия не может учитывать тот факт, что фактическая реакция увеличивается по мере того, как x перемещается от 25 к нулю. Вероятно, это пример недостаточного соответствия. Верхний правый график иллюстрирует полиномиальную регрессию со степенью, равной 2. В этом случае это может быть оптимальная степень для моделирования этих данных. Модель имеет значение ², которое во многих случаях является удовлетворительным и хорошо показывает тенденции. Нижний левый график представляет полиномиальную регрессию со степенью, равной 3. Значение R^2 выше, чем в предыдущих случаях. Эта модель лучше работает с известными данными, чем предыдущие. Тем не менее, он показывает некоторые признаки переобучения, особенно для входных значений, близких к 60, где линия начинает уменьшаться, хотя фактические данные этого не показывают. Наконец, на правом нижнем графике вы можете увидеть идеальное соответствие: шесть точек и полиномиальная линия степени 5 (или выше) дает R^2 = 1. Каждое фактическое значение равно соответствующему прогнозу. В некоторых ситуациях это может быть именно то, что вы ищете. Однако, во многих случаях это избыточная модель. Вероятно, она будет плохо себя вести с невидимыми данными, особенно, с входными данными, превышающими 50. Например, она предполагает, без каких-либо доказательств, что существует значительное падение для значений > 50 и что y достигает нуля для x около 60. Такое поведение является следствием чрезмерных усилий по изучению и соответствию существующим данным. Существует множество ресурсов, где вы можете найти дополнительную информацию о регрессии в целом и о линейной регрессии в частности. Статьи Регрессионный анализ и Линейная регрессия в Википедии хорошие отправные точки для глубокого изучения.

Реализация линейной регрессии в Python

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

Пакеты Python для линейной регрессии

Пакет NumPy — это фундаментальный научный пакет Python, который позволяет выполнять множество высокопроизводительных операций с одномерными и многомерными массивами. Он также предлагает множество математических процедур. Конечно, это открытый исходный код. Если вы не знакомы с NumPy, вы можете использовать официальное руководство пользователя NumPy и прочитать Глянь Ма, никаких циклов: работа с массивами, используя NumPy. Кроме того, сравнение производительности в статье Чистый Python против NumPy и TensorFlow. Сравнение производительности может дать вам довольно хорошее представление о приросте производительности, которого вы можете достичь при применении NumPy. Пакет scikit-learn — это широко используемая библиотека Python для машинного обучения, построенная на основе NumPy и некоторые другие пакеты. Они предоставляют инструменты для предварительной обработки данных, уменьшения размерности, реализации регрессии, классификации, кластеризации и многого другого. Как и NumPy, scikit-learn также имеет открытый исходный код. Вы можете проверить страницу Generalized Linear Models на веб-сайте scikit-learn, чтобы узнать больше о линейных моделях и получить более полное представление о том, как работает этот пакет. Если вы хотите реализовать линейную регрессию и вам нужна функциональность, выходящая за рамки scikit-learn, вам следует рассмотреть statsmodels. Это мощный пакет Python для оценки статистических моделей, выполнения тестов и многого другого. Это также открытый исходный код. Вы можете найти дополнительную информацию о статистических моделях на его официальном веб-сайте.

Простая линейная регрессия с помощью scikit-learn

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

  1. Импортировать необходимые пакеты и классы;
  2. Предоставить данные для работы и в конечном итоге выполнить соответствующие преобразования;
  3. Создать модель регрессии и сопоставить его с существующими данными;
  4. Проверить результаты подгонки модели, чтобы узнать, удовлетворительна ли модель.

Примените модель для прогнозов. Эти шаги являются более или менее общими для большинства регрессионных подходов и реализаций.

Шаг 1. Импорт пакетов и классов

Шаг — импортировать пакет numpy и класс LinearRegression из sklearn.linear_model:

import numpy as np
from sklearn.linear_model import LinearRegression

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

Основным типом данных NumPy является тип массива с именем numpy.ndarray. В остальной части этой статьи термин «массив» используется для обозначения экземпляров типа numpy.ndarray.

Класс sklearn.linear_model.LinearRegression будет использоваться для выполнения линейной и полиномиальной регрессии и соответственно делать прогнозы.

Шаг 2. Предоставьте данные

Второй шаг — определение данных для работы. Входные данные (регрессоры, x) и выходные данные (предиктор, y) должны быть массивами (экземплярами класса numpy.ndarray) или подобными объектами.

Это самый простой способ предоставить данные для регрессии:

x = np.array([5, 15, 25, 35, 45, 55]).reshape((-1, 1))
y = np.array([5, 20, 14, 32, 22, 38])

Теперь у вас есть два массива: входной x и выходной y. Вы должны вызвать .reshape() для x, потому что этот массив должен быть двумерным или, если быть более точным, иметь один столбец и столько строк, сколько необходимо. Именно это и определяет аргумент (-1, 1) функции .reshape().

Вот как теперь выглядят x и y:

>>> print(x)
[ [ 5]
 [15]
 [25]
 [35]
 [45]
 [55] ]
>>> print(y)
[ 5 20 14 32 22 38]

Как вы можете видеть, x имеет два измерения, x.shape — это (6, 1), y — одно измерение, а y.shape — (6,).

Шаг 3. Создайте модель и подгоните ее

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

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

model = LinearRegression()

Этот оператор создает переменную модель как экземпляр LinearRegression. Вы можете предоставить LinearRegression несколько дополнительных параметров:

  • fit_intercept — это логическое значение (по умолчанию True), которое определяет, следует ли вычислять точку пересечения b_0 (True) или считать ее равной нулю (False).
  • normalize — это логическое значение (по умолчанию False), которое определяет, следует ли нормализовать входные переменные (True) или нет (False).
  • copy_X — это логическое значение (по умолчанию True), которое решает, копировать (True) или перезаписывать входные переменные (False).
  • n_jobs является целым числом или None (по умолчанию) и представляет количество заданий, используемых в параллельных вычислениях. None обычно означает одно задание, а -1 — использовать все процессоры. В этом примере используются значения по умолчанию для всех параметров.

Пришло время начать пользоваться моделью. Во-первых, вам нужно вызвать .fit() для модели:

model.fit(x, y)

С помощью .fit() вы вычисляете оптимальные значения весов b_0 и b_1, используя существующие входные и выходные данные (x и y) в качестве аргументов. Другими словами, .fit() соответствует модели. Он возвращает self, которое является самой переменной моделью. Вот почему вы можете заменить последние два утверждения на это:

model = LinearRegression().fit(x, y)

Шаг 4. Получите результаты

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

Вы можете получить коэффициент детерминации (?^2) с помощью .score(), вызванного для модели:

>>> r_sq = model.score(x, y)
>>> print('coefficient of determination:', r_sq)
coefficient of determination: 0.715875613747954

Когда вы применяете .score(), аргументы также являются предиктором x и регрессором y, а возвращаемое значение — ?^2.

Атрибуты модели: .intercept_, который представляет коэффициент, и .coef_, который представляет b_1:

>>> print('intercept:', model.intercept_)
intercept: 5.633333333333329
>>> print('slope:', model.coef_)
slope: [0.54]

В приведенном выше коде показано, как получить b_0 и b_1. Вы можете заметить, что .intercept_ — это скаляр, а .coef_ — это массив.

Значение b_0 = 5,63 (приблизительно) показывает, что ваша модель предсказывает реакцию 5,63, когда x равно нулю. Значение b_1 = 0,54 означает, что прогнозируемый ответ увеличивается на 0,54, когда x увеличивается на единицу.

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

>>> new_model = LinearRegression().fit(x, y.reshape((-1, 1)))
>>> print('intercept:', new_model.intercept_)
intercept: [5.63333333]
>>> print('slope:', new_model.coef_)
slope: [ [0.54] ]

Как видите, этот пример очень похож на предыдущий, но в данном случае .intercept_ — это одномерный массив с единственным элементом b_0, а .coef_ — это двумерный массив с единственным элементом b_1.

Шаг 5. Спрогнозируйте ответ

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

Чтобы получить прогнозируемый ответ, используйте .predict():

>>> y_pred = model.predict(x)
>>> print('predicted response:', y_pred, sep='\n')
predicted response:
[ 8.33333333 13.73333333 19.13333333 24.53333333 29.93333333 35.33333333]

При применении .predict() вы передаете регрессор в качестве аргумента и получаете соответствующий прогнозируемый ответ.

Это почти идентичный способ предсказать ответ:

>>> y_pred = model.intercept_ + model.coef_ * x
>>> print('predicted response:', y_pred, sep='\n')
predicted response:
[ [ 8.33333333]
 [13.73333333]
 [19.13333333]
 [24.53333333]
 [29.93333333]
 [35.33333333] ]

В этом случае вы умножаете каждый элемент x на model.coef_ и добавляете model.intercept_ к продукту.

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

Если вы уменьшите количество измерений x до одного, эти два подхода дадут одинаковый результат. Вы можете сделать это, заменив x на x.reshape(-1), x.flatten() или x.ravel() при умножении на model.coef_.

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

>>> x_new = np.arange(5).reshape((-1, 1))
>>> print(x_new)
[ [0]
 [1]
 [2]
 [3]
 [4] ]
>>> y_new = model.predict(x_new)
>>> print(y_new)
[5.63333333 6.17333333 6.71333333 7.25333333 7.79333333]

Здесь .predict() применяется к новому регрессору x_new и дает ответ y_new. В этом примере удобно использовать arange() из numpy для создания массива с элементами от 0 (включительно) до 5 (исключая), то есть 0, 1, 2, 3 и 4.

Вы можете найти дополнительную информацию о LinearRegression на официальной странице документации.

Множественная линейная регрессия с помощью scikit-learn

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

Шаги 1 и 2: Импорт пакетов и классов и предоставление данных

Сначала вы импортируете numpy и sklearn.linear_model.LinearRegression и предоставляете известные входные и выходные данные:

import numpy as np
from sklearn.linear_model import LinearRegression

x = [ [0, 1], [5, 1], [15, 2], [25, 5], [35, 11], [45, 15], [55, 34], [60, 35] ]
y = [4, 5, 20, 14, 32, 22, 38, 43]
x, y = np.array(x), np.array(y)

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

>>> print(x)
[ [ 0  1]
 [ 5  1]
 [15  2]
 [25  5]
 [35 11]
 [45 15]
 [55 34]
 [60 35] ]
>>> print(y)
[ 4  5 20 14 32 22 38 43]

В множественной линейной регрессии x — это двумерный массив, по крайней мере, с двумя столбцами, а y — обычно одномерный массив. Это простой пример множественной линейной регрессии и x имеет ровно два столбца.

Шаг 3: Создайте модель и подгоните ее

Следующим шагом будет создание модели регрессии как экземпляр LinearRegression и подгонка ее с помощью .fit():

model = LinearRegression().fit(x, y)

Результатом этого оператора является переменная модель, ссылающаяся на объект типа LinearRegression. Он представляет собой регрессионную модель, оснащенную существующими данными.

Шаг 4: Получение результатов

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

>>> r_sq = model.score(x, y)
>>> print('coefficient of determination:', r_sq)
coefficient of determination: 0.8615939258756776
>>> print('intercept:', model.intercept_)
intercept: 5.52257927519819
>>> print('slope:', model.coef_)
slope: [0.44706965 0.25502548]

Вы получаете значение R^2 с помощью .score() и значения оценщиков коэффициентов регрессии с .intercept_ и .coef_. Опять же, .intercept_ содержит смещение b_0, в то время как теперь .coef_ — это массив, содержащий b_1 и b_2 соответственно. В этом примере перехват составляет приблизительно 5,52, и это значение прогнозируемого отклика, когда x_1 = x_2 = 0. Увеличение из x_1 на 1 дает рост прогнозируемой реакции на 0,45. Точно так же, когда x_1 увеличивается на 1, отклик увеличивается на 0,26.

Шаг 5: Прогнозирование отклика

Прогнозы также работают так же, как и в случае простой линейной регрессии:

>>> y_pred = model.predict(x)
>>> print('predicted response:', y_pred, sep='\n')
predicted response:
[ 5.77760476  8.012953   12.73867497 17.9744479  23.97529728 29.4660957
 38.78227633 41.27265006]

Прогнозируемый ответ получается с помощью .predict(), который очень похож на следующий:

>>> y_pred = model.intercept_ + np.sum(model.coef_ * x, axis=1)
>>> print('predicted response:', y_pred, sep='\n')
predicted response:
[ 5.77760476  8.012953   12.73867497 17.9744479  23.97529728 29.4660957
 38.78227633 41.27265006]

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

>>> x_new = np.arange(10).reshape((-1, 2))
>>> print(x_new)
[ [0 1]
 [2 3]
 [4 5]
 [6 7]
 [8 9] ]
>>> y_new = model.predict(x_new)
>>> print(y_new)
[ 5.77760476  7.18179502  8.58598528  9.99017554 11.3943658 ]

Это прогноз с использованием модели линейной регрессии.

Полиномиальная регрессия с помощью scikit-learn

Реализация полиномиальной регрессии с помощью scikit-learn очень похожа на линейную регрессию. Есть только один дополнительный шаг: вам нужно преобразовать массив входных данных, чтобы включить нелинейные термины, такие как x^2.

Шаг 1: Импортировать пакеты и классы

Помимо numpy и sklearn.linear_model.LinearRegression, вы также должны импортировать класс PolynomialFeatures из sklearn.preprocessing:

import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures

Импорт завершен, и у вас есть все необходимое для работы.

Шаг 2а: предоставьте данные

Этот шаг определяет ввод и вывод и такой же, как и в случае линейной регрессии:

x = np.array([5, 15, 25, 35, 45, 55]).reshape((-1, 1))
y = np.array([15, 11, 2, 8, 25, 32])

Это новый шаг, который необходимо реализовать для полиномиальной регрессии!

Как вы видели ранее, вам необходимо включить x^2 (и, возможно, другие термины) в качестве дополнительных функций при реализации полиномиальной регрессии. По этой причине, вы должны преобразовать входной массив x, чтобы он содержал дополнительный столбец (столбцы) со значениями x^2 (и, в конечном итоге, другими функциями).

Можно преобразовать входной массив несколькими способами (например, с помощью insert() из numpy), но класс PolynomialFeatures очень удобен для этой цели. Давайте создадим экземпляр этого класса:

transformer = PolynomialFeatures(degree=2, include_bias=False)

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

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

  • degree — это целое число (по умолчанию 2), представляющее степень функции полиномиальной регрессии.
  • Interaction_only — это логическое значение (по умолчанию False), которое определяет, следует ли включать только функции взаимодействия (True) или все функции (False).
  • include_bias — это логическое значение (по умолчанию True), которое решает, включать ли столбец смещения (перехвата) единиц (True) или нет (False).

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

Перед применением transformer его нужно подогнать с помощью .fit():

transformer.fit(x)

После установки code>transformer он готов к созданию нового измененного входа. Для этого вы применяете .transform():

x_ = transformer.transform(x)

Это преобразование входного массива с помощью .transform(). Он принимает входной массив в качестве аргумента и возвращает измененный массив.

Вы также можете использовать .fit_transform() для замены трех предыдущих операторов только одним:

x_ = PolynomialFeatures(degree=2, include_bias=False).fit_transform(x)

Это подгонка и преобразование входного массива в один оператор с помощью .fit_transform(). Он также принимает входной массив и фактически делает то же самое, что .fit() и .transform(), вызываемые в этом порядке. Он также возвращает измененный массив. Так выглядит новый входной массив:

>>> print(x_)
[ [   5.   25.]
 [  15.  225.]
 [  25.  625.]
 [  35. 1225.]
 [  45. 2025.]
 [  55. 3025.] ]

Модифицированный входной массив содержит два столбца: один с исходными входами, а другой с их квадратами.

Вы можете найти дополнительную информацию о PolynomialFeatures на официальной странице документации.

Шаг 3. Создайте модель и подгоните её

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

model = LinearRegression().fit(x_, y)

Теперь регрессионная модель создана и настроена. Готова к применению.

Вы должны помнить, что первый аргумент .fit() — это модифицированный входной массив x_, а не исходный x.

Шаг 4. Получите результаты

Получить свойства модели можно так же, как и в случае линейной регрессии:

>>> r_sq = model.score(x_, y)
>>> print('coefficient of determination:', r_sq)
coefficient of determination: 0.8908516262498564
>>> print('intercept:', model.intercept_)
intercept: 21.372321428571425
>>> print('coefficients:', model.coef_)
coefficients: [-1.32357143  0.02839286]

Опять же, .score() возвращает R^2. Его первым аргументом также является измененный вход x_, а не x. Значения весов связаны с .intercept_ и .coef_: .intercept_ представляет b_0, а .coef_ ссылается на массив, содержащий b_1 и b_2 соответственно.

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

x_ = PolynomialFeatures(degree=2, include_bias=True).fit_transform(x)

Если вы вызываете PolynomialFeatures с параметром по умолчанию include_bias = True (или просто опускаете его), вы получите новый входной массив x_ с дополнительным крайним левым столбцом, содержащим только единицы. Этот столбец соответствует перехвату. Вот как в этом случае выглядит модифицированный входной массив:

>>> print(x_)
[ [1.000e+00 5.000e+00 2.500e+01]
 [1.000e+00 1.500e+01 2.250e+02]
 [1.000e+00 2.500e+01 6.250e+02]
 [1.000e+00 3.500e+01 1.225e+03]
 [1.000e+00 4.500e+01 2.025e+03]
 [1.000e+00 5.500e+01 3.025e+03] ]

Первый столбец x_ содержит единицы, второй — значения x, а третий — квадраты x.

Перехват уже включен в крайний левый столбец единиц, и вам не нужно включать его снова при создании экземпляра LinearRegression. Таким образом, вы можете указать fit_intercept = False. Вот так выглядит следующее утверждение:

>>> print(x_)
model = LinearRegression(fit_intercept=False).fit(x_, y)

Переменная model снова соответствует новому входному массиву x_. Следовательно, x_ следует передавать в качестве первого аргумента вместо x.

Этот подход дает следующие результаты, аналогичные предыдущему:

>>> print(x_)
>>> r_sq = model.score(x_, y)
>>> print('coefficient of determination:', r_sq)
coefficient of determination: 0.8908516262498565
>>> print('intercept:', model.intercept_)
intercept: 0.0
>>> print('coefficients:', model.coef_)
coefficients: [21.37232143 -1.32357143  0.02839286]

Вы видите, что теперь .intercept_ равен нулю, но .coef_ фактически содержит b_0 в качестве своего первого элемента. В остальном все то же самое.

Шаг 5. Спрогнозируйте ответ

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

>>> y_pred = model.predict(x_)
>>> print('predicted response:', y_pred, sep='\n')
predicted response:
[15.46428571  7.90714286  6.02857143  9.82857143 19.30714286 34.46428571]

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

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

# Step 1: Import packages
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures

# Step 2a: Provide data
x = [ [0, 1], [5, 1], [15, 2], [25, 5], [35, 11], [45, 15], [55, 34], [60, 35] ]
y = [4, 5, 20, 14, 32, 22, 38, 43]
x, y = np.array(x), np.array(y)

# Step 2b: Transform input data
x_ = PolynomialFeatures(degree=2, include_bias=False).fit_transform(x)

# Step 3: Create a model and fit it
model = LinearRegression().fit(x_, y)

# Step 4: Get results
r_sq = model.score(x_, y)
intercept, coefficients = model.intercept_, model.coef_

# Step 5: Predict
y_pred = model.predict(x_)

Этот пример регрессии дает следующие результаты и прогнозы:

>>> print('coefficient of determination:', r_sq)
coefficient of determination: 0.9453701449127822
>>> print('intercept:', intercept)
intercept: 0.8430556452395734
>>> print('coefficients:', coefficients, sep='\n')
coefficients:
[ 2.44828275  0.16160353 -0.15259677  0.47928683 -0.4641851 ]
>>> print('predicted response:', y_pred, sep='\n')
predicted response:
[ 0.54047408 11.36340283 16.07809622 15.79139    29.73858619 23.50834636
 39.05631386 41.92339046]

В этом случае имеется шесть коэффициентов регрессии (включая точку пересечения), как показано в оценочной функции регрессии

f(x_1, x_2) = b_0 + b_1x_1 + b_2x_2 + b_3x_1^2 + b_4x_1x_2 + b_5x_2^2.

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

Сначала можно было подумать, что получение такой большой площади — отличный результат, что может быть.

Однако в реальных ситуациях наличие сложной модели и R^2, очень близкого к 1, также может быть признаком переобучения. Чтобы проверить производительность модели, вы должны протестировать ее с новыми данными, то есть с наблюдениями, которые не используются для соответствия (обучения) модели.

Чтобы узнать, как разделить набор данных на обучающие и тестовые подмножества, ознакомьтесь с Split Your Dataset With scikit-learn’s train_test_split().

Расширенная линейная регрессия с моделями статистики

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

Процедура аналогична scikit-learn.

Шаг 1. Импортируйте пакеты

Сначала вам нужно сделать импорт. В дополнение к numpy вам необходимо импортировать statsmodels.api:

import numpy as np
import statsmodels.api as sm

Теперь у вас есть нужные пакеты.

Шаг 2. Предоставьте данные и преобразуйте входные данные

Вы можете предоставить входные и выходные данные так же, как и при использовании scikit-learn:

x = [ [0, 1], [5, 1], [15, 2], [25, 5], [35, 11], [45, 15], [55, 34], [60, 35] ]
y = [4, 5, 20, 14, 32, 22, 38, 43]
x, y = np.array(x), np.array(y)

Массивы ввода и вывода созданы, но работа еще не сделана.

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

x = sm.add_constant(x)

Вот как вы добавляете столбец единиц к x с помощью add_constant(). Он принимает входной массив x в качестве аргумента и возвращает новый массив со столбцом единиц, вставленных в начало. Вот как теперь выглядят x и y:

>>> print(x)
[ [ 1.  0.  1.]
 [ 1.  5.  1.]
 [ 1. 15.  2.]
 [ 1. 25.  5.]
 [ 1. 35. 11.]
 [ 1. 45. 15.]
 [ 1. 55. 34.]
 [ 1. 60. 35.] ]
>>> print(y)
[ 4  5 20 14 32 22 38 43]

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

Шаг 3. Создайте модель и подгоните ее

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

model = sm.OLS(y, x)

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

Чтобы найти дополнительную информацию об этом классе, посетите официальную страницу документации.

Как только ваша модель создана, вы можете применить к ней .fit():

results = model.fit()

Вызывая .fit(), вы получаете переменную results, которая является экземпляром класса statsmodels.regression.linear_model.RegressionResultsWrapper. Этот объект содержит много информации о регрессионной модели.

Шаг 4. Получите результаты

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

Вы можете вызвать .summary(), чтобы получить таблицу с результатами линейной регрессии:

>>> print(results.summary())
OLS Regression Results                            
==============================================================================
Dep. Variable:                      y   R-squared:                       0.862
Model:                            OLS   Adj. R-squared:                  0.806
Method:                 Least Squares   F-statistic:                     15.56
Date:                Sun, 17 Feb 2019   Prob (F-statistic):            0.00713
Time:                        19:15:07   Log-Likelihood:                -24.316
No. Observations:                   8   AIC:                             54.63
Df Residuals:                       5   BIC:                             54.87
Df Model:                           2                                         
Covariance Type:            nonrobust                                         
==============================================================================
coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
const          5.5226      4.431      1.246      0.268      -5.867      16.912
x1             0.4471      0.285      1.567      0.178      -0.286       1.180
x2             0.2550      0.453      0.563      0.598      -0.910       1.420
==============================================================================
Omnibus:                        0.561   Durbin-Watson:                   3.268
Prob(Omnibus):                  0.755   Jarque-Bera (JB):                0.534
Skew:                           0.380   Prob(JB):                        0.766
Kurtosis:                       1.987   Cond. No.                         80.1
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.

Эта таблица очень обширна. Вы можете найти множество статистических значений, связанных с линейной регрессией, включая R^2, b_0, b_1 и b_2.

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

Вы можете извлечь любое из значений таблицы выше. Например:

>>> print('coefficient of determination:', results.rsquared)
coefficient of determination: 0.8615939258756777
>>> print('adjusted coefficient of determination:', results.rsquared_adj)
adjusted coefficient of determination: 0.8062314962259488
>>> print('regression coefficients:', results.params)
regression coefficients: [5.52257928 0.44706965 0.25502548]

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

  • .rsquared содержит R^2.
  • .rsquared_adj представляет собой скорректированный R^2 (R^2 скорректированный согласно количеству входных функций).
  • .params ссылается на массив с помощью b_0, b_1 и b_2 соответственно.

Вы также можете заметить, что эти результаты идентичны результатам, полученным с помощью scikit-learn решать ту же проблему.

Для получения дополнительной информации о результатах линейной регрессии посетите официальную страницу документации.

Шаг 5. Спрогнозируйте ответ

Вы можете получить прогнозируемый ответ на входные значения, используемые для создания модели, используя .fittedvalues ​​или .predict() с входным массивом в качестве аргумента:

>>> print('predicted response:', results.fittedvalues, sep='\n')
predicted response:
[ 5.77760476  8.012953   12.73867497 17.9744479  23.97529728 29.4660957
 38.78227633 41.27265006]
>>> print('predicted response:', results.predict(x), sep='\n')
predicted response:
[ 5.77760476  8.012953   12.73867497 17.9744479  23.97529728 29.4660957
 38.78227633 41.27265006]

Это прогнозируемый ответ для известных входов. Если вам нужны прогнозы с новыми регрессорами, вы также можете применить .predict() с новыми данными в качестве аргумента:

>>> x_new = sm.add_constant(np.arange(10).reshape((-1, 2)))
>>> print(x_new)
[ [1. 0. 1.]
 [1. 2. 3.]
 [1. 4. 5.]
 [1. 6. 7.]
 [1. 8. 9.] ]
>>> y_new = results.predict(x_new)
>>> print(y_new)
[ 5.77760476  7.18179502  8.58598528  9.99017554 11.3943658 ]

Вы можете заметить, что прогнозируемые результаты такие же, как и полученные с помощью scikit-learn для той же проблемы.

За пределами линейной регрессии

Линейная регрессия иногда не подходит, особенно для нелинейных моделей высокой сложности.

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

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

Пакет scikit-learn предоставляет средства для использования других техник регрессии очень похожим образом на то, что вы видели. Он содержит классы для опорных векторных машин, деревьев решений, случайного леса и т.д. С методами .fit(), .predict(), .score() и т.д.

Заключение

Теперь вы знаете, что такое линейная регрессия и как ее можно реализовать с помощью Python и трех пакетов с открытым исходным кодом: NumPy, scikit-learn и statsmodels.

Вы используете NumPy для обработки массивов.

Линейная регрессия реализуется следующим образом:

  • scikit-learn, не нужны ли вам подробные результаты и вы хотите использовать подход, совместимый с другими методами регрессии
  • statsmodels, если вам нужны расширенные статистические параметры модели

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

  1. Импортируйте нужные вам пакеты и классы.
  2. Предоставлять данные для работы и в конечном итоге выполнять соответствующие преобразования.
  3. Создайте регрессионную модель и сопоставьте ее с существующими данными.
  4. Проверьте результаты подгонки модели, чтобы узнать, удовлетворительна ли модель.
  5. Примените модель для прогнозов.

Если у вас есть вопросы или комментарии, пожалуйста, оставьте их в разделе комментариев ниже.

По мотивам Linear Regression in Python

]]>
https://chel-center.ru/python-yfc/2020/12/20/linejnaya-regressiya-v-python/feed/ 0
Логистическая регрессия в Python https://chel-center.ru/python-yfc/2020/12/20/logisticheskaya-regressiya-v-python/ https://chel-center.ru/python-yfc/2020/12/20/logisticheskaya-regressiya-v-python/#respond Sun, 20 Dec 2020 12:23:51 +0000 http://chel-center.ru/python-yfc/?p=31196 Читать далее «Логистическая регрессия в Python»

]]>
Содержание

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

В этом уроке вы узнаете:

  • Что такое логистическая регрессия.
  • Для чего используется логистическая регрессия.
  • Как работает логистическая регрессия.
  • Как реализовать логистическую регрессию в Python, шаг за шагом.

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

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

Что такое классификация?

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

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

  1. Независимые переменные, также называемые входными данными или предикторами, не зависят от других интересующих характеристик (или, по крайней мере, вы предполагаете это для целей анализа).
  2. Зависимые переменные, также называемые выходами или откликами, зависят от независимых переменных.

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

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

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

Есть два основных типа проблем классификации:

  1. Двоичная или биномиальная классификация: на выбор ровно два класса (обычно 0 и 1, истина и ложь, или положительный и отрицательный)
  2. Мультиклассовая или полиномиальная классификация: три или более классов выходных данных на выбор

Если имеется только одна входная переменная, она обычно обозначается как x. Для более чем одного входа вы обычно будете видеть векторную запись x = (x_1,\dots, x_r), где r — количество предикторов (или независимых признаков). Выходная переменная часто обозначается символом и принимает значения 0 или 1.

Когда вам нужна классификация?

Вы можете применять классификацию во многих областях науки и техники. Например, алгоритмы классификации текста используются для разделения легитимных писем и спама, а также положительных и отрицательных комментариев. Вы можете ознакомиться с Practical Text Classification With Python and Keras, чтобы получить некоторое представление об этой теме. Другие примеры включают медицинские приложения, биологическую классификацию, кредитный рейтинг и многое другое.

Задачи распознавания изображений часто представляют как задачи классификации. Например, вы можете спросить, имеется ли на изображение человеческое лицо или нет, мышь или слон, какую цифру от нуля до девяти оно представляет и т.д. Чтобы узнать больше об этом, ознакомьтесь с материалами Traditional Face Detection With Python и Face Recognition with Python, in Under 25 Lines of Code.

Понятие логистической регрессии

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

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

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

Это изображение показывает сигмоиду (или S-образную кривую) некоторой переменной ?:

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

На этом изображении показан натуральный логарифм \log(x) некоторой переменной x для значений x от 0 до 1:

Когда x приближается к нулю, натуральный логарифм падает до отрицательной бесконечности. Когда x = 1, \log(?) равен 0. Обратное верно для \log(1-x).

Обратите внимание, что вы часто найдете натуральный логарифм, обозначаемый \ln вместо \log. В Python math.log(x) и numpy.log(x)представляют собой натуральный логарифм x, поэтому вы будете следовать этим обозначениям в этом руководстве.

Формулировка проблемы

В этом руководстве вы увидите объяснение распространенного случая логистической регрессии, применяемой к двоичной классификации. Когда вы реализуете логистическую регрессию некоторой зависимой переменной y на множестве независимых переменных x = (x_1,\dots, x_r), где r — количество предикторов (или входных данных), вы начинаете с известных значений предикторов x_i и соответствующего фактического отклика (или результата) y_i для каждого наблюдения i = 1, \dots, n.

Ваша цель — найти функцию логистической регрессии p(?) такую, чтобы прогнозируемые ответы p(x_i) были как можно ближе к фактическому ответу y_i для каждого наблюдения i = 1,\dots, ?. Помните, что фактический ответ может быть только 0 или 1 в задачах двоичной классификации! Это означает, что каждый p(x_i) должен быть близок к 0 или 1. Вот почему удобно использовать сигмоиду.

Если у вас есть функция логистической регрессии p(x), вы можете использовать ее для прогнозирования выходных данных для новых и невидимых входов, при условии, что лежащая в основе математическая зависимость не изменилась.

Методология

Логистическая регрессия — это линейный классификатор, поэтому вы будете использовать линейную функцию f(x) = b_0 + b_1x_1 + \dots + b_rx_r, также называемую logit. Переменные b_0, b_1,\dots, b_r являются оценками коэффициентов регрессии, которые также называются прогнозируемыми весами или просто коэффициентами.

Функция логистической регрессии p(x) является сигмоидой f(x):

p(x) = \dfrac{1}{(1 + \exp(−? (?))}.

Таким образом, она часто близка к 0 или 1. функция p(x) часто интерпретируется как прогнозируемая вероятность того, что выход для данного равен 1. Следовательно, 1 — p(x) — это вероятность того, что выход равен 0.

Логистическая регрессия определяет наилучшие предсказанные веса b_0, b_1,\dots, b_r так, чтобы функция p(x) была как можно ближе ко всем фактическим ответам y_i, i = 1,\dots, ?, где n — количество наблюдений. Процесс вычисления лучших весов с использованием имеющихся наблюдений называется обучением модели или подгонкой.

Чтобы получить лучший вес, вы обычно максимизируете функцию логарифма правдоподобия (LLF) для всех наблюдений i = 1,\dots, ?. Этот метод называется оценкой максимального правдоподобия и представляется уравнением

LLF = \sum_i{(y_i \log(p(x_i)) + (1 — y_i) \log(1 — p(x_i)))}.

Когда y_i = 0, LLF для соответствующего наблюдения равен \log(1 — p(x_i)).

Если p(x_i) близко к y_i = 0, то \log(1 — p(x_i)) близко к 0. Это именно тот результат, который вам нужен. Если p(x_i) далеко от 0, то \log(1 — p(x_i)) значительно падает. Вы не хотите такого результата, потому что ваша цель — получить максимальный LLF. Аналогично, когда y_i = 1, LLF для этого наблюдения равен \log(p(x_i)). Если p(x_i) близко к y_i = 1, тогда \log(p(x_i)) близко к 0. Если p(x_i) далеко от 1, то \log(x_i)) — большое отрицательное число.

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

После определения наилучших весов, которые определяют функцию p(x), вы можете получить прогнозируемые выходные данные p(x_i) для любого заданного входа x_i. Для каждого наблюдения i = 1,\dots, n прогнозируемый результат равен 1, если p(x_i) > 0,5 и 0 в противном случае.

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

Есть еще одно важное соотношение между p(x) и f(x_i):

\log(\dfrac{p(?)}{(1- p(?))}) = f(?).

Это равенство объясняет, почему f(?) является logit. Отсюда следует, что p(x) = 0.5, когда f(x) = 0 и что прогнозируемый выход равен 1, если f(?) > 0 и 0 в противном случае.

Эффективность классификации

Бинарная классификация имеет четыре возможных типа результатов:

  1. Истинно отрицательные: правильно предсказанные негативы (нули);
  2. Истинно положительные: правильно предсказанные положительные (единицы);
  3. Ложно отрицательные: неверно предсказанные отрицания (нули);
  4. Ложно положительные: неверно предсказанные срабатывания (единицы).

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

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

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

    Логистическая регрессия по одной переменной

    Логистическая регрессия по одной переменной — это наиболее простой случай логистической регрессии. Есть только одна независимая переменная (или характеристика), которая равна X = ?. Этот рисунок иллюстрирует одномерную логистическую регрессию:

    Здесь у вас есть заданный набор пар входа-выхода (или x \rightarrow y), представленный зелеными кружками. Это ваши наблюдения. Помните, что y может быть только 0 или 1. Например, крайний левый зеленый кружок имеет вход x = 0, а фактический выход y = 0. Крайнее правое наблюдение имеет x = 9 и y = 1.

    Логистическая регрессия находит веса b_0 и b_1, которые соответствуют максимальному LLF. Эти веса определяют logit f(x) = b_0 + b_1x, которая представляет собой черную пунктирную линию. Они также определяют прогнозируемую вероятность p(x) = \dfrac{1} {(1 + \exp (−f(x)))}, показанную здесь сплошной черной линией. В этом случае порог p(x) = 0.5 и f(x) = 0 соответствует значению x немного выше 3. Это значение является пределом между входами с прогнозируемыми выходными значениями 0 и 1.

    Многовариантная логистическая регрессия

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

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

    Логистическая регрессия определяет веса b_1 и b_2, которые максимизируют LLF. Когда у вас есть b_0, b_1 и b_2 можно получить:

    • Logit f(x_1, x_2) = b_0 + b_1x_1 + b_2x_2
    • Вероятности p(x_1, x_2) = \dfrac{1}{(1 + \exp(−f(x_1, x_2)))}

    Пунктирная черная линия линейно разделяет два класса. Эта линия соответствует p(x_1, x_2) = 0,5 и f(x_1, x_2) = 0.

    Регуляризация

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

    Переобучение обычно происходит со сложными моделями. Регуляризация обычно пытается уменьшить сложность модели или снизить ее. Методы регуляризации, применяемые с логистической регрессией, в основном имеют тенденцию штрафовать за большие коэффициенты b_0, b_1,\dots, b_r:

    • Регуляризация L1 штрафует LLF масштабированной суммой абсолютных значений весов: | ?₀ | + | ?₁ | + \dots + | ?ᵣ |.
    • Регуляризация L2 штрафует LLF масштабированной суммой квадратов весов: b_0^2 + b_1^2 + \dots + b_r^2.
    • Регуляризация упругой сети представляет собой линейную комбинацию регуляризации L1 и L2.

    Регуляризация может значительно улучшить точность модели для невидимых данных.

    Логистическая регрессия в Python

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

    • Обзор пакетов Python для логистической регрессии (NumPy, scikit‑learn, StatsModels и Matplotlib).
    • Два наглядных примера логистической регрессии, решенные с помощью scikit‑learn.
    • Один концептуальный пример, решенный с помощью StatsModels.
    • Один из реальных примеров классификации рукописных цифр.

    Приступим к реализации логистической регрессии в Python!

    Пакеты Python для логистической регрессии

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

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

    Примечание. Чтобы узнать больше о производительности NumPy и других преимуществах, которые он может предложить, ознакомьтесь с Сравнение производительности Pure Python vs NumPy vs TensorFlow и Look Ma, No For-Loops: Array Programming With NumPy.

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

    • Предварительная обработка данных;
    • Уменьшение размерности задач;
    • Проверка моделей;
    • Выбор наиболее подходящей модели;
    • Решение проблем регрессии и классификации;
    • Внедрение кластерного анализа.

    Вы найдете полезную информацию на официальном сайте scikit‑learn, где вы, возможно, захотите прочитать об обобщенных линейных моделях и реализации логистической регрессии. Если вам нужна функциональность, которую scikit‑learn не может предложить, вам может пригодиться StatsModels. Это мощная библиотека Python для статистического анализа. Более подробную информацию вы можете найти на официальном сайте.

    Наконец, вы будете использовать Matplotlib для визуализации результатов вашей классификации. Это всеобъемлющая библиотека Python, которая широко используется для высококачественного построения графиков.

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

    Логистическая регрессия в Python с помощью scikit‑learn: пример 1

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

    1. Импорт пакетов, функций и классов.
    2. Получение данных для работы и, при необходимости, их трансформация.
    3. Создание классификационной модели и её обучение (или приспособление) к существующим данным.
    4. Оценка своей модели, чтобы убедиться, что её точность удовлетворительна.

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

    Шаг 1. Импортируйте пакеты, функции и классы

    Во-первых, вам нужно импортировать Matplotlib для визуализации и NumPy для операций с массивами. Вам также понадобятся LogisticRegression, classification_report() и confusion_matrix() из scikit‑learn:

    import matplotlib.pyplot as plt
    import numpy as np
    from sklearn.linear_model import LogisticRegression
    from sklearn.metrics import classification_report, confusion_matrix
    

    Теперь вы импортировали все необходимое для логистической регрессии в Python с помощью scikit‑learn!

    Шаг 2. Получение данных

    На практике у вас обычно есть какие-то данные для работы. Для целей этого примера давайте просто создадим массивы для входных (x) и выходных (y) значений:

    x = np.arange(10).reshape(-1, 1)
    y = np.array([0, 0, 0, 0, 1, 1, 1, 1, 1, 1])
    

    Входные и выходные данные должны быть массивами NumPy (экземпляры класса numpy.ndarray) или аналогичными объектами. numpy.arange() создает массив последовательных, равномерно распределенных значений в заданном диапазоне. Для получения дополнительной информации об этой функции посмотрите NumPy: Справочное руководтсво.

    Массив x должен быть двумерным. В нем должен быть один столбец для каждого входа, а количество строк должно быть равно количеству наблюдений. Чтобы сделать x двумерным, вы применяете .reshape() с аргументами -1, чтобы получить столько строк, сколько необходимо, и 1, чтобы получить один столбец. Для получения дополнительной информации о .reshape() вы можете ознакомиться с официальной документацией.

    Вот как теперь выглядят x и y:

    >>> x
    array([ [0],
           [1],
           [2],
           [3],
           [4],
           [5],
           [6],
           [7],
           [8],
           [9] ])
    >>> y
    array([0, 0, 0, 0, 1, 1, 1, 1, 1, 1])
    

    x имеет два измерения:

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

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

    Шаг 3. Создание модели и её обучение

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

    model = LogisticRegression(solver='liblinear', random_state=0)
    

    Приведенный выше оператор создает экземпляр LogisticRegression и связывает его ссылки с моделью переменных. LogisticRegression имеет несколько дополнительных параметров, которые определяют поведение модели и подход:

    • penalty — строка (по умолчанию ‘l2‘), которая определяет, есть ли регуляризация и какой подход использовать. Другие варианты: l1, elasticnet и None.
    • dual — логическое значение (по умолчанию False), которое определяет, следует ли использовать первичную (если False) или двойную формулировку (если True).
    • tol — число с плавающей запятой (по умолчанию 0,0001), которое определяет допуск для остановки процедуры.
    • C — положительное число с плавающей запятой (1.0 по умолчанию), которое определяет относительную силу регуляризации. Меньшие значения указывают на более сильную регуляризацию.<.li>
    • fit_intercept — логическое значение (по умолчанию True), которое решает, следует ли вычислять точку пересечения b_0 (когда True) или считать ее равной нулю (когда False).
    • intercept_scaling — число с плавающей запятой (1.0 по умолчанию), который определяет масштаб точки пересечения b_0.
    • class_weight — словарь, balanced или None (по умолчанию), который определяет веса, относящиеся к каждому классу. Когда нет, все классы имеют единицу веса.
    • random_state — целое число, экземпляр numpy.RandomState или None (по умолчанию), который определяет, какой генератор псевдослучайных чисел использовать.
    • solver — строка (по умолчанию liblinear), которая решает, какой решатель использовать для подбора модели. Есть варианты: newton-cg, lbfgs, sag и saga.<.li>
    • max_iter — целое число (по умолчанию 100), определяющее максимальное количество итераций решающей программы во время подгонки модели.<.li>
    • multi_class — строка (по умолчанию ovr), которая определяет подход к использованию нескольких классов. Другие варианты — multinomial и auto.<.li>
    • verbose — неотрицательное целое число (по умолчанию 0), определяющее степень детализации для решателей liblinear и lbfgs.
    • warm_start — логическое значение (по умолчанию False), которое определяет, следует ли повторно использовать ранее полученное решение.
    • n_jobs — целое число или None (по умолчанию), определяющее количество используемых параллельных процессов. None обычно означает использование одного ядра, а -1 означает использование всех доступных ядер.
    • l1_ratio — это либо плавающее число точек от нуля до единицы, либо None (по умолчанию). Оно определяет относительную важность части L1 в регуляризации elastic-net.

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

      • решатель ‘liblinear’ не работает без регуляризации.
      • ‘newton-cg’, ‘sag’, ‘saga’ и ‘lbfgs’ не поддерживает регуляризацию L1.
      • ‘saga’ — единственный решатель, который поддерживает регуляризацию elastic-net.

      После того, как модель создана, ее нужно подогнать (или обучить). Подгонка модели — это процесс определения коэффициентов b_0, b_1,\dots, b_r, которые соответствуют наилучшему значению функции стоимости. Вы подходите к модели с помощью .fit():

      model.fit(x, y)
      

      .fit() принимает значения x, y и, возможно, связанные с наблюдением. Она соответствует модели и сама возвращает экземпляр модели:

      LogisticRegression(
          C=1.0, 
          class_weight=None, 
          dual=False, 
          fit_intercept=True,
          intercept_scaling=1, 
          l1_ratio=None, 
          max_iter=100,
          multi_class='warn', 
          n_jobs=None, 
          penalty='l2',
          random_state=0, 
          solver='liblinear', 
          tol=0.0001, 
          verbose=0,
          warm_start=False
      )
      

      Здесь представлено текстовое описание подобранной модели.

      Вы можете использовать тот факт, что .fit() возвращает экземпляр модели и связывает последние два оператора. Они эквивалентны следующей строке кода:

      model = LogisticRegression(solver='liblinear', random_state=0).fit(x, y)
      

      На этом этапе у вас определена модель классификации.

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

      >>> model.classes_
      array([0, 1])
      

      Это пример двоичной классификации, и y может быть 0 или 1, как указано выше.

      Вы также можете получить значение наклона b_1 и точку пересечения b_0 линейной функции f следующим образом:

      >>> model.intercept_
      array([-1.04608067])
      >>> model.coef_
      array([ [0.51491375] ])
      

      Как видите, b_0 задается внутри одномерного массива, а b_1 — внутри двумерного массива. Вы используете атрибуты .intercept_ и .coef_, чтобы получить эти результаты.

      Шаг 4: Оценка модели

      Как только модель определена, вы можете проверить ее точность с помощью .predict_proba(), который возвращает матрицу вероятностей того, что прогнозируемый результат равен нулю или единице:

      >>> model.predict_proba(x)
      array([ [0.74002157, 0.25997843],
             [0.62975524, 0.37024476],
             [0.5040632 , 0.4959368 ],
             [0.37785549, 0.62214451],
             [0.26628093, 0.73371907],
             [0.17821501, 0.82178499],
             [0.11472079, 0.88527921],
             [0.07186982, 0.92813018],
             [0.04422513, 0.95577487],
             [0.02690569, 0.97309431] ])
      

      В приведенной выше матрице каждая строка соответствует одному наблюдению. Первый столбец — это вероятность того, что прогнозируемый результат будет равен нулю, то есть 1 - p(x). Второй столбец — это вероятность того, что на выходе будет единица или p(x).

      Вы можете получить фактические прогнозы на основе матрицы вероятностей и значений p(x) с помощью .predict():

       
      >>> model.predict(x)
      array([0, 0, 0, 1, 1, 1, 1, 1, 1, 1])
      

      Эта функция возвращает предсказанные выходные значения в виде одномерного массива.

      На рисунке ниже показаны результаты входа, выхода и классификации:

      Зеленые круги представляют фактические ответы, а также правильные прогнозы. Красный \times показывает неверный прогноз. Сплошная черная линия — это предполагаемая линия логистической регрессии p(x). Серые квадраты — это точки на этой линии, которые соответствуют x и значениям во втором столбце матрицы вероятностей. Черная пунктирная линия — logit f(x).

      Значение × немного выше 2 соответствует порогу p(x) = 0,5, что составляет f(x) = 0. Это значение \times является границей между точками, которые классифицируются как нули, и точками, предсказанными как единицы.

      Например, первая точка имеет вход input = 0, фактический выход ouput = 0, вероятность p = 0,26 и прогнозируемое значение 0. Вторая точка имеет x = 1, y = 0, p = 0,37 и прогноз 0. Только четвертая точка имеет фактический результат y = 0 и вероятность выше 0,5 (при p = 0,62), поэтому он ошибочно классифицируется как 1. Все остальные значения предсказываются правильно.

      Если девять из десяти наблюдений классифицированы правильно, точность вашей модели равна 9/10 = 0,9, которую вы можете получить с помощью .score():

      >>> model.score(x, y)
      0.9
      

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

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

      • Истинные минусы в верхнем левом углу.
      • Ложные минусы в нижнем левом углу.
      • Ложные плюсы в правом верхнем углу.
      • Истинные плюсы в правом нижнем углу.

      Чтобы создать матрицу ошибок, вы можете использовать confusion_matrix() и предоставить фактические и прогнозируемые результаты в качестве аргументов:

      >>> confusion_matrix(y, model.predict(x))
      array([ [3, 1],
             [0, 6] ])
      

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

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

      Часто бывает полезно визуализировать матрицу ошибок. Вы можете сделать это с помощью .imshow() из Matplotlib, который принимает матрицу ошибок в качестве аргумента:

      cm = confusion_matrix(y, model.predict(x))
      
      fig, ax = plt.subplots(figsize=(8, 8))
      ax.imshow(cm)
      ax.grid(False)
      ax.xaxis.set(ticks=(0, 1), ticklabels=('Predicted 0s', 'Predicted 1s'))
      ax.yaxis.set(ticks=(0, 1), ticklabels=('Actual 0s', 'Actual 1s'))
      ax.set_ylim(1.5, -0.5)
      for i in range(2):
          for j in range(2):
              ax.text(j, i, cm[i, j], ha='center', va='center', color='red')
      plt.show()
      

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

      На этом рисунке разные цвета представляют разные числа, а похожие цвета представляют похожие числа. Тепловые карты — хороший и удобный способ представить матрицу. Чтобы узнать о них больше, ознакомьтесь с документацией Matplotlib по созданию аннотированных тепловых карт и .imshow().

      Вы можете получить более полный отчет о классификации с помощью метода classification_report():

      >>> print(classification_report(y, model.predict(x)))
                    precision    recall  f1-score   support
      
                 0       1.00      0.75      0.86         4
                 1       0.86      1.00      0.92         6
      
          accuracy                           0.90        10
         macro avg       0.93      0.88      0.89        10
      weighted avg       0.91      0.90      0.90        10
      

      Эта функция также принимает фактические и прогнозируемые выходные данные в качестве аргументов. Она возвращает отчет о классификации в виде словаря, если вы указали output_dict = True или строку в противном случае.

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

      Для получения дополнительной информации о LogisticRegression ознакомьтесь с официальной документацией. Кроме того, scikit‑learn предлагает аналогичный класс LogisticRegressionCV и это есть перекрестная проверка. Вы также можете ознакомиться с официальной документацией, чтобы узнать больше о классификационных отчетах и ​​матрицах ошибок.

      Улучшение модели

      Вы можете улучшить свою модель, задав разные параметры. Например, давайте работать с силой регуляризации C, равной 10,0, вместо значения по умолчанию 1,0:

      model = LogisticRegression(solver='liblinear', C=10.0, random_state=0)
      model.fit(x, y)
      

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

      >>> model.intercept_
      array([-3.51335372])
      >>> model.coef_
      array([ [1.12066084] ])
      >>> model.predict_proba(x)
      array([ [0.97106534, 0.02893466],
             [0.9162684 , 0.0837316 ],
             [0.7810904 , 0.2189096 ],
             [0.53777071, 0.46222929],
             [0.27502212, 0.72497788],
             [0.11007743, 0.88992257],
             [0.03876835, 0.96123165],
             [0.01298011, 0.98701989],
             [0.0042697 , 0.9957303 ],
             [0.00139621, 0.99860379] ])
      >>> model.predict(x)
      array([0, 0, 0, 0, 1, 1, 1, 1, 1, 1])
      

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

      Различные значения b_0 и b_1 предполагают изменение logitа f(x), разные значения вероятностей p(x), другая форма линии регрессии и, возможно, изменения в других прогнозируемых выходных данных и производительности классификации. Граничное значение x, для которого p(x) = 0,5 и f(x) = 0, теперь выше. Оно выше 3. В этом случае вы получаете все истинные прогнозы, о чем свидетельствуют точность, матрица ошибок и отчет о классификации:

      >>> model.score(x, y)
      1.0
      >>> confusion_matrix(y, model.predict(x))
      array([ [4, 0],
             [0, 6] ])
      >>> print(classification_report(y, model.predict(x)))
                    precision    recall  f1-score   support
      
                 0       1.00      1.00      1.00         4
                 1       1.00      1.00      1.00         6
      
          accuracy                           1.00        10
         macro avg       1.00      1.00      1.00        10
      weighted avg       1.00      1.00      1.00        10
      

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

      На этом рисунке показано, что оценочная линия регрессии теперь имеет другую форму и что четвертая точка правильно классифицируется как 0. Красный знак \times отсутствует, поэтому нет неверного прогноза.

      Логистическая регрессия в Python с помощью scikit‑learn: пример 2

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

      # Шаг 1. Импортируйте пакеты, функции и классы
      import numpy as np
      from sklearn.linear_model import LogisticRegression
      from sklearn.metrics import classification_report, confusion_matrix
      
      # Шаг 2. Получите данные
      x = np.arange(10).reshape(-1, 1)
      y = np.array([0, 1, 0, 0, 1, 1, 1, 1, 1, 1])
      
      # Шаг 3. Создайте модель и обучите ее
      model = LogisticRegression(solver='liblinear', C=10.0, random_state=0)
      model.fit(x, y)
      
      # Шаг 4. Оцените модель
      p_pred = model.predict_proba(x)
      y_pred = model.predict(x)
      score_ = model.score(x, y)
      conf_m = confusion_matrix(y, y_pred)
      report = classification_report(y, y_pred)
      

      Этот образец кода классификации дает следующие результаты:

      >>> print('x:', x, sep='\n')
      x:
      [ [0]
       [1]
       [2]
       [3]
       [4]
       [5]
       [6]
       [7]
       [8]
       [9] ]
      >>> print('y:', y, sep='\n', end='\n\n')
      y:
      [0 1 0 0 1 1 1 1 1 1]
      
      >>> print('intercept:', model.intercept_)
      intercept: [-1.51632619]
      >>> print('coef:', model.coef_, end='\n\n')
      coef: [ [0.703457] ]
      
      >>> print('p_pred:', p_pred, sep='\n', end='\n\n')
      p_pred:
      [ [0.81999686 0.18000314]
       [0.69272057 0.30727943]
       [0.52732579 0.47267421]
       [0.35570732 0.64429268]
       [0.21458576 0.78541424]
       [0.11910229 0.88089771]
       [0.06271329 0.93728671]
       [0.03205032 0.96794968]
       [0.0161218  0.9838782 ]
       [0.00804372 0.99195628] ]
      
      >>> print('y_pred:', y_pred, end='\n\n')
      y_pred: [0 0 0 1 1 1 1 1 1 1]
      
      >>> print('score_:', score_, end='\n\n')
      score_: 0.8
      
      >>> print('conf_m:', conf_m, sep='\n', end='\n\n')
      conf_m:
      [ [2 1]
       [1 6] ]
      
      >>> print('report:', report, sep='\n')
      report:
                    precision    recall  f1-score   support
      
                 0       0.67      0.67      0.67         3
                 1       0.86      0.86      0.86         7
      
          accuracy                           0.80        10
         macro avg       0.76      0.76      0.76        10
      weighted avg       0.80      0.80      0.80        10
      

      В этом случае оценка (или точность) составляет 0,8. Есть два наблюдения, классифицированных неправильно. Один из них — ложноотрицательный, другой — ложноположительный.

      На рисунке ниже показан этот пример с восемью правильными и двумя неправильными прогнозами:

      Этот рисунок раскрывает одну важную характеристику этого примера. В отличие от предыдущей, эта задача линейно не разделима. Это означает, что вы не можете найти значение и провести прямую линию, чтобы разделить наблюдения с = 0 и наблюдения с = 1. Такой строчки нет.

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

      Логистическая регрессия в Python с помощью StatsModels: пример

      Вы также можете реализовать логистическую регрессию в Python с помощью пакета StatsModels. Обычно это требуется, когда вам нужно больше статистических данных, относящихся к моделям и результатам. Процедура аналогична scikit‑learn.

      Шаг 1. Импортируйте пакеты

      Все, что вам нужно для импорта, это NumPy и statsmodels.api:

      import numpy as np
      import statsmodels.api as sm
      

      Теперь у вас есть нужные пакеты.

      Шаг 2. Получите данные

      Вы можете получать входные и выходные данные так же, как и в scikit‑learn. Однако, StatsModels не принимает во внимание перехват b_0 и вам необходимо включить дополнительный столбец единиц в x. Вы делаете это с помощью add_constant():

      x = np.arange(10).reshape(-1, 1)
      y = np.array([0, 1, 0, 0, 1, 1, 1, 1, 1, 1])
      x = sm.add_constant(x)
      

      add_constant() принимает массив x в качестве аргумента и возвращает новый массив с дополнительным столбцом единиц. Вот как выглядят x и y:

      >>> x
      array([ [1., 0.],
             [1., 1.],
             [1., 2.],
             [1., 3.],
             [1., 4.],
             [1., 5.],
             [1., 6.],
             [1., 7.],
             [1., 8.],
             [1., 9.] ])
      >>> y
      array([0, 1, 0, 0, 1, 1, 1, 1, 1, 1])
      

      Это ваши данные. Первый столбец x соответствует точке пересечения b_0. Второй столбец содержит исходные значения x.

      Шаг 3. Создайте модель и обучите её

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

      >>> model = sm.Logit(y, x)
      

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

      Теперь вы создали свою модель и должны подогнать ее к существующим данным. Вы делаете это с помощью .fit() или, если хотите применить регуляризацию L1, с помощью .fit_regularized():

      >>> result = model.fit(method='newton')
      Optimization terminated successfully.
               Current function value: 0.350471
               Iterations 7
      

      Теперь модель готова, и переменный результат содержит полезные данные. Например, вы можете получить значения b_0 и b_1 с помощью .params:

      >>> result.params
      array([-1.972805  ,  0.82240094])
      

      Первый элемент полученного массива — это точка пересечения b_0, а второй — наклон b_1. Для получения дополнительной информации вы можете посмотреть официальную документацию по Logit, а также по .fit() и .fit_regularized().

      Шаг 4: Оцените модель

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

      >>> result.predict(x)
      array([0.12208792, 0.24041529, 0.41872657, 0.62114189, 0.78864861,
             0.89465521, 0.95080891, 0.97777369, 0.99011108, 0.99563083])
      

      Эти вероятности рассчитываются с помощью .predict(). Вы можете использовать их значения для получения фактических прогнозируемых результатов:

      >>> (result.predict(x) >= 0.5).astype(int)
      array([0, 0, 0, 1, 1, 1, 1, 1, 1, 1])
      

      Полученный массив содержит прогнозируемые выходные значения. Как видите, b_0, b_1 и вероятности, полученные с помощью scikit‑learn и StatsModels, различны. Это следствие применения различных итерационных и приближенных процедур и параметров. Однако в этом случае вы получите те же прогнозируемые результаты, что и при использовании scikit‑learn.

      Вы можете получить матрицу ошибок с помощью .pred_table():

      >>> result.pred_table()
      array([ [2., 1.],
             [1., 6.] ])
      

      Этот пример такой же, как и при использовании scikit‑learn, потому что прогнозируемые результаты равны. Матрицы ошибок, полученные с помощью StatsModels и scikit‑learn, различаются типами их элементов (числа с плавающей запятой и целые числа).

      .summary() и .summary2() получают выходные данные, которые могут оказаться полезными в некоторых случаях:

      >>> result.summary()
      
      """
                                 Logit Regression Results                           
      ==============================================================================
      Dep. Variable:                      y   No. Observations:                   10
      Model:                          Logit   Df Residuals:                        8
      Method:                           MLE   Df Model:                            1
      Date:                Sun, 23 Jun 2019   Pseudo R-squ.:                  0.4263
      Time:                        21:43:49   Log-Likelihood:                -3.5047
      converged:                       True   LL-Null:                       -6.1086
                                              LLR p-value:                   0.02248
      ==============================================================================
                       coef    std err          z      P>|z|      [0.025      0.975]
      ------------------------------------------------------------------------------
      const         -1.9728      1.737     -1.136      0.256      -5.377       1.431
      x1             0.8224      0.528      1.557      0.119      -0.213       1.858
      ==============================================================================
      """
      >>> result.summary2()
      
      """
                              Results: Logit
      ===============================================================
      Model:              Logit            Pseudo R-squared: 0.426   
      Dependent Variable: y                AIC:              11.0094
      Date:               2019-06-23 21:43 BIC:              11.6146
      No. Observations:   10               Log-Likelihood:   -3.5047
      Df Model:           1                LL-Null:          -6.1086
      Df Residuals:       8                LLR p-value:      0.022485
      Converged:          1.0000           Scale:            1.0000  
      No. Iterations:     7.0000                                     
      -----------------------------------------------------------------
                Coef.    Std.Err.      z      P>|z|     [0.025   0.975]
      -----------------------------------------------------------------
      const    -1.9728     1.7366   -1.1360   0.2560   -5.3765   1.4309
      x1        0.8224     0.5281    1.5572   0.1194   -0.2127   1.8575
      ===============================================================
      
      """
      

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

      Логистическая регрессия в Python: распознавание рукописного ввода

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

      Этот пример касается распознавания изображений. Если быть более точным, вы будете работать над распознаванием рукописных цифр. Вы будете использовать набор данных с 1797 наблюдениями, каждое из которых представляет собой изображение одной рукописной цифры. Каждое изображение имеет размер 64 пикселя, ширину 8 пикселей и высоту 8 пикселей.

      Примечание. Чтобы узнать больше об этом наборе данных, обратитесь к официальной документации.

      inputs(x) — это векторы с 64 измерениями или значениями. Каждый входной вектор описывает одно изображение. Каждое из 64 значений представляет один пиксель изображения. Входные значения — это целые числа от 0 до 16, в зависимости от оттенка серого для соответствующего пикселя. outputs(y) каждого наблюдения является целое число от 0 до 9, соответствует цифре на изображении. Всего существует десять классов, каждый из которых соответствует одному изображению.

      Шаг 1. Импортируйте пакеты

      Вам нужно будет импортировать Matplotlib, NumPy, а также несколько функций и классов из scikit‑learn:

      import matplotlib.pyplot as plt
      import numpy as np
      from sklearn.datasets import load_digits
      from sklearn.linear_model import LogisticRegression
      from sklearn.metrics import classification_report, confusion_matrix
      from sklearn.model_selection import train_test_split
      from sklearn.preprocessing import StandardScaler
      

      Это оно! У вас есть все функции, необходимые для выполнения классификации.

      Шаг 2а: Получите данные

      Вы можете получить набор данных прямо из scikit‑learn с помощью load_digits(). Он возвращает кортеж входных и выходных данных:

      x, y = load_digits(return_X_y=True)
      

      Теперь у вас есть данные. Вот как выглядят x и y:

      >>> x
      array([ [ 0.,  0.,  5., ...,  0.,  0.,  0.],
             [ 0.,  0.,  0., ..., 10.,  0.,  0.],
             [ 0.,  0.,  0., ..., 16.,  9.,  0.],
             ...,
             [ 0.,  0.,  1., ...,  6.,  0.,  0.],
             [ 0.,  0.,  2., ..., 12.,  0.,  0.],
             [ 0.,  0., 10., ..., 12.,  1.,  0.] ])
      >>> y
      array([0, 1, 2, ..., 8, 9, 8])
      

      Это ваши данные, с которыми нужно работать. x — это многомерный массив с 1797 строками и 64 столбцами. Он содержит целые числа от 0 до 16. y — одномерный массив с 1797 целыми числами от 0 до 9.

      Шаг 2b: разделение данных

      Хорошая и широко распространенная практика — разделить набор данных, с которым вы работаете, на два подмножества. Это обучающий набор и тестовый набор. Это разделение обычно выполняется случайным образом. Вы должны использовать обучающий набор в соответствии с вашей моделью. После того, как модель найдена, вы оцениваете ее характеристики с помощью набора для испытаний. Важно не использовать тестовый набор в процессе обучения модели. Такой подход позволяет объективно оценить модель. Один из способов разделить ваш набор данных на обучающий и тестовый — применить train_test_split():

      x_train, x_test, y_train, y_test =\
          train_test_split(x, y, test_size=0.2, random_state=0)
      

      train_test_split() принимает x и y. Он также принимает test_size, который определяет размер набора тестов, и random_state, чтобы определить состояние генератора псевдослучайных чисел, а также другие необязательные аргументы. Эта функция возвращает список с четырьмя массивами:

      1. x_train: часть x, используемая для соответствия модели;
      2. x_test: часть x, используемая для оценки модели;
      3. y_train: часть y, соответствующая x_train;
      4. y_test: часть y, которая соответствует x_test.

      После разделения данных вы можете забыть о x_test и y_test, пока не определите свою модель.

      Шаг 2c: масштабирование данных

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

      1. Рассчитайте среднее значение и стандартное отклонение для каждого столбца.
      2. Вычтите соответствующее среднее значение из каждого элемента.
      3. Разделите полученную разницу на соответствующее стандартное отклонение.

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

      Вы можете стандартизировать свои входные данные, создав экземпляр StandardScaler и вызвав для него .fit_transform():

      scaler = StandardScaler()
      x_train = scaler.fit_transform(x_train)
      

      .fit_transform() помещает экземпляр StandardScaler в массив, переданный в качестве аргумента, преобразует этот массив и возвращает новый стандартизованный массив. Теперь x_train — это стандартизированный входной массив.

      Шаг 3. Создайте модель и обучите её

      Этот шаг очень похож на предыдущие примеры. Единственная разница в том, что вы используете подмножества x_train и y_train для соответствия модели. Опять же, вы должны создать экземпляр LogisticRegression и вызвать для него .fit():

      model = LogisticRegression(solver='liblinear', C=0.05, multi_class='ovr',
                                 random_state=0)
      model.fit(x_train, y_train)
      

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

      • ovr‘ говорит, что двоичный файл подходит для каждого класса.
      • multinomial‘ означает применение полиномиальной подгонки потерь.

      Последний оператор дает следующий результат, поскольку .fit() возвращает саму модель:

      LogisticRegression(
          C=0.05, class_weight=None, dual=False, fit_intercept=True,
                         intercept_scaling=1, l1_ratio=None, max_iter=100,
                         multi_class='ovr', n_jobs=None, penalty='l2', random_state=0,
                         solver='liblinear', tol=0.0001, verbose=0, warm_start=False)
      

      Это параметры вашей модели. Теперь она определена и готов к следующему шагу.

      Шаг 4: Оцените модель

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

      x_test = scaler.transform(x_test)
      

      Вот как вы получаете новый, правильно масштабированный x_test. В этом случае вы используете .transform(), который только преобразует аргумент, без установки масштаба.

      Вы можете получить прогнозируемые результаты с помощью .predict():

      y_pred = model.predict(x_test)
      

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

      Вы можете получить точность с помощью .score():

      >>> model.score(x_train, y_train)
      0.964509394572025
      >>> model.score(x_test, y_test)
      0.9416666666666667
      

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

      Вы можете получить матрицу ошибок с confusion_matrix():

      >>> confusion_matrix(y_test, y_pred)
      array([ [27,  0,  0,  0,  0,  0,  0,  0,  0,  0],
             [ 0, 32,  0,  0,  0,  0,  1,  0,  1,  1],
             [ 1,  1, 33,  1,  0,  0,  0,  0,  0,  0],
             [ 0,  0,  1, 28,  0,  0,  0,  0,  0,  0],
             [ 0,  0,  0,  0, 29,  0,  0,  1,  0,  0],
             [ 0,  0,  0,  0,  0, 39,  0,  0,  0,  1],
             [ 0,  1,  0,  0,  0,  0, 43,  0,  0,  0],
             [ 0,  0,  0,  0,  0,  0,  0, 39,  0,  0],
             [ 0,  2,  1,  2,  0,  0,  0,  1, 33,  0],
             [ 0,  0,  0,  1,  0,  1,  0,  2,  1, 36] ])
      

      Полученная матрица ошибок имеет большие размеры. В данном случае у него 100 номеров. Это ситуация, когда было бы действительно полезно визуализировать её:

      cm = confusion_matrix(y_test, y_pred)
      
      fig, ax = plt.subplots(figsize=(8, 8))
      ax.imshow(cm)
      ax.grid(False)
      ax.set_xlabel('Predicted outputs', fontsize=font_size, color='black')
      ax.set_ylabel('Actual outputs', fontsize=font_size, color='black')
      ax.xaxis.set(ticks=range(10))
      ax.yaxis.set(ticks=range(10))
      ax.set_ylim(9.5, -0.5)
      for i in range(10):
          for j in range(10):
              ax.text(j, i, cm[i, j], ha='center', va='center', color='white')
      plt.show()
      

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

      Это тепловая карта, которая иллюстрирует матрицу ошибок с числами и цветами. Вы можете видеть, что оттенки фиолетового представляют небольшие числа (например, 0, 1 или 2), в то время как зеленый и желтый показывают гораздо большие числа (27 и выше).

      Цифры на главной диагонали (27, 32,…, 36) показывают количество правильных прогнозов из тестового набора. Например, есть 27 изображений с нулем, 32 изображения с одним и так далее, которые правильно классифицированы. Остальные числа соответствуют неверным предсказаниям. Например, цифра 1 в третьей строке и первом столбце показывает, что есть одно изображение с номером 2, ошибочно классифицированным как 0.

      В заключение,вы можете получить отчет о классификации в виде строки или словаря с помощью метода classification_report():

      >>> print(classification_report(y_test, y_pred))
                    precision    recall  f1-score   support
      
                 0       0.96      1.00      0.98        27
                 1       0.89      0.91      0.90        35
                 2       0.94      0.92      0.93        36
                 3       0.88      0.97      0.92        29
                 4       1.00      0.97      0.98        30
                 5       0.97      0.97      0.97        40
                 6       0.98      0.98      0.98        44
                 7       0.91      1.00      0.95        39
                 8       0.94      0.85      0.89        39
                 9       0.95      0.88      0.91        41
      
          accuracy                           0.94       360
         macro avg       0.94      0.94      0.94       360
      weighted avg       0.94      0.94      0.94       360
      

      В этом отчете представлена ​​дополнительная информация, например, поддержка и точность классификации каждой цифры.

      За пределами логистической регрессии в Python

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

      • k-Ближайшие соседи;
      • Наивные байесовские классификаторы;
      • Машины опорных векторов;
      • Деревья решений;
      • Случайные леса;
      • Нейронные сети;

      К счастью, существует несколько всеобъемлющих библиотек Python для машинного обучения, которые реализуют эти методы. Например, пакет scikit‑learn, который вы видели здесь в действии, реализует все вышеупомянутые методы,за исключением нейронных сетей.

      Для всех этих методов scikit‑learn предлагает подходящие классы с такими методами, как model.fit(), model.predict_proba(), model.predict(), model.score() и так далее. Вы можете комбинировать их с train_test_split(), confusion_matrix(), classification_report() и другими.

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

      Заключение

      Теперь вы знаете, что такое логистическая регрессия и как ее можно реализовать для классификации с помощью Python. Вы использовали множество пакетов с открытым исходным кодом, включая NumPy, для работы с массивами и Matplotlib для визуализации результатов. Вы также использовали scikit‑learn и StatsModels для создания, подгонки, оценки и применения моделей.

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

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

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

      По мотивам Logistic Regression in Python

      ]]> https://chel-center.ru/python-yfc/2020/12/20/logisticheskaya-regressiya-v-python/feed/ 0 Чистый Python против NumPy и TensorFlow. Сравнение производительности https://chel-center.ru/python-yfc/2020/12/21/chistyj-python-protiv-numpy-i-tensorflow-sravnenie-proizvoditelnosti/ https://chel-center.ru/python-yfc/2020/12/21/chistyj-python-protiv-numpy-i-tensorflow-sravnenie-proizvoditelnosti/#respond Mon, 21 Dec 2020 09:28:42 +0000 http://chel-center.ru/python-yfc/?p=31241 Читать далее «Чистый Python против NumPy и TensorFlow. Сравнение производительности»

      ]]>

      Содержание

      Философия Python заключается в том, чтобы позволить программистам выражать концепции в удобной форме и в меньшем количестве строк кода. Эта философия делает язык подходящим для разнообразного набора сценариев: простые сценарии для Интернета, большие веб-приложения (например, YouTube), язык сценариев для других платформ (например, Blender и Autodesk Maya) и научные приложения в нескольких областях, таких как астрономия, метеорология, физика и наука о данных.

      Технически возможно реализовать скалярные и матричные вычисления с использованием списков Python. Однако это может быть громоздко, а производительность низка по сравнению с языками, подходящими для численных вычислений, такими как MATLAB или Fortran или даже некоторые языки общего назначения, такие как C или C++.

      Чтобы обойти этот недостаток, появилось несколько библиотек, которые поддерживают простоту использования Python, одновременно предоставляя возможность выполнять численные вычисления эффективным образом. Стоит упомянуть две такие библиотеки: NumPy (одна из первых библиотек для обеспечения эффективных численных вычислений в Python) и TensorFlow (недавно развернутая библиотека, ориентированная больше на алгоритмы глубокого обучения).

      • NumPy обеспечивает поддержку больших многомерных массивов и матриц вместе с набором математических функций для работы с этими элементами. Проект полагается на хорошо известные пакеты, реализованные на других языках (например, Fortran) для выполнения эффективных вычислений,предоставляя пользователю выразительность Python и производительность, аналогичную MATLAB или Fortran.
      • TensorFlow — это библиотека с открытым исходным кодом для численных вычислений, первоначально разработанная исследователями и инженерами, работающими в команде Google Brain. Основная цель библиотеки — предоставить простой в использовании API для реализации практических алгоритмов машинного обучения и развертывания их для работы на процессорах, графических процессорах или в кластере.

      Но как эти схемы сравнивать? Насколько быстрее работает приложение, если оно реализовано с помощью NumPy вместо чистого Python? А как насчет TensorFlow? Цель этой статьи — начать изучение улучшений, которых можно достичь с помощью этих библиотек.

      Чтобы сравнить эффективность трех подходов, вы создадите базовую регрессию с помощью нативных Python, NumPy и TensorFlow.

      Генерирование тестовых данных

      Чтобы проверить производительность библиотек, вы рассмотрим простую задачу линейной регрессии с двумя параметрами. Модель имеет два параметра: точку пересечения w_0 и единственный коэффициент w_1.

      Учитывая N пар входов x и желаемых выходов d, идея состоит в том, чтобы смоделировать взаимосвязь между выходами и входами с использованием линейной модели y = w_0 + w_1 \times x, где выход модели y приблизительно равен желаемому выходу d для каждой пары (x, d).

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

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

      import numpy as np
      
      np.random.seed (444)
      
      N = 10000
      sigma = 0.1
      noise = sigma * np.random.randn (N)
      x = np.linspace (0, 2, N)
      d = 3 + 2 * x + noise
      d.shape = (N, 1)
      
      # Нам нужно добавить вектор-столбец единиц к `x`.
      X = np.column_stack ( (np.ones (N, dtype=x.dtype), x))
      print('Размеры исходных данных: ', X.shape)
      

      Эта программа создает набор из 10 000 входов x, линейно распределенных в интервале от 0 до 2. Затем она создает набор желаемых выходов d = 3 + 2 \times x + noise, где шум берется из гауссовского распределения (нормальное распределение) с нулевым средним и стандартным отклонением \sigma = 0,1.

      Создавая таким образом x и d, вы фактически устанавливаете, что оптимальное решение для w_0 и w_13 и 2 соответственно.

      Xplus = np.linalg.pinv (X)
      w_opt = Xplus @ d
      print('Теоретические значения коэффициентов w0 и w1\n', w_opt, '\n\n')
      

      Существует несколько методов оценки параметров w_0 и w_1 для соответствия линейной модели обучающей выборке. Одним из наиболее часто используемых является метод наименьших квадратов, который является хорошо известным решением для оценки w_0 и w_1, чтобы минимизировать квадрат ошибки e, полученный суммированием y - d для каждой обучающей выборки.

      \begin{bmatrix} d_0 \\ d_1 \\ \vdots \\ d_{9999} \end{bmatrix} = \begin{bmatrix} 1 & x_0 \\ 1 & x_1 \\ \vdots \\ 1 & x_{9999} \end{bmatrix} \begin{bmatrix} w_0 \\ w_1 \end{bmatrix}

      Используя этот подход, мы можем оценить w_m, используя w_{opt} = Xplus @ d, где Xplus задается псевдо-инверсией X, которая может быть вычислена с помощью numpy.linalg.pinv, в результате чего w_0 = 2,9978 и w_1 = 2,0016, что является очень близко к ожидаемым значениям w_0 = 3 и w_1 = 2.

      Примечание. Использование w_opt = np.linalg.inv(X.T @ X) @ X.T @ d даст такое же решение. Для получения дополнительной информации см. Приводим уравнение линейной регрессии в матричный вид.

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

      Один из наиболее часто используемых алгоритмов — градиентный спуск, который на высоком уровне состоит в обновлении коэффициентов параметров до тех пор, пока мы не придем к минимизированным потерям (или стоимости). То есть, у нас есть некоторая функция стоимости (часто среднеквадратическое отклонение — MSE) и мы вычисляем её градиент относительно сетевых коэффициентов (в данном случае параметров w_0 и w_1), учитывая размер шага mu. Выполняя это обновление много раз (во многие эпохи), коэффициенты сходятся к решению, которое минимизирует функцию стоимости.

      В следующих разделах мы создадим и будем использовать алгоритмы градиентного спуска на чистом Python, NumPy и TensorFlow. Сравнение эффективность трех подходов по времени выполнения проводилось на ноутбуке с процессоре Intel Core i5 3510M 2,50 ГГц, который работает под ОС Widows 7 (это не есть система real-time, что надо иметь в виду).

      Градиентный спуск в чистом Python

      Давайте начнем с подхода, основанного на чистом Python, в качестве основы для сравнения с другими подходами. Функция Python ниже оценивает параметры w_0 и ww_1 с помощью градиентного спуска:

      import itertools as it
      
      def py_descent (x, d, mu, N_epochs):
          N = len (x)
          f = 2 / N
      
          # "Пустые" прогнозы, ошибки, веса, градиенты.
          y = [0] * N
          w = [0, 0]
          grad = [0, 0]
      
          for _ in it.repeat (None, N_epochs):
              # Не могу использовать генератор, потому что нам нужно
              # доступ к его элементам дважды.
              err = tuple (i - j for i, j in zip (d, y))
              grad[0] = f * sum (err)
              grad[1] = f * sum (i * j for i, j in zip (err, x))
              w = [i + mu * j for i, j in zip (w, grad)]
              y = (w[0] + w[1] * i for i in x)
          return w
      

      Выше все сделано с помощью списков Python, синтаксиса нарезки и встроенных функций sum() и zip(). Перед прохождением каждой эпохи «пустые» контейнеры нулей инициализируются для y, w и grad.

      Технические детали: py_descent выше использует itertools.repeat(), а не для _in range(N_epochs). Первый быстрее, чем второй, потому что repeat() не нужно создавать отдельное целое число для каждого цикла. Ему просто нужно обновить счетчик ссылок до None. Модуль timeit содержит пример.

      Теперь найдём решение:

      import time
      
      x_list = x.tolist()
      d_list = d.squeeze().tolist()  # Нужны 1d списки
      
      # `mu` - размер шага или коэффициент масштабирования.
      mu = 0.001
      N_epochs = 10000
      
      t0 = time.time()
      py_w = py_descent (x_list, d_list, mu, N_epochs)
      t1 = time.time()
      
      print('Найдены коэффициенты линейной регрессии w0 и w1 (чистый Python):', py_w)
      
      print('Время поиска решения (чистый Python): {:.2f} seconds\n\n'.format(round (t1 - t0, 2)))
      

      При размере шага mu = 0,001 и 10 000 эпох мы можем получить довольно точную оценку w_0 и w_1. Внутри цикла for градиенты по параметрам вычисляются и используются, в свою очередь, для обновления весов, перемещаясь в противоположном направлении, чтобы минимизировать функцию стоимости MSE.

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

      Истекшее время алгоритма измеряется с помощью библиотеки времени. Для оценки w_0 = 2,9598 и w_1 = 2,0329 требуется 18,65 секунды. Хотя библиотека timeit может предоставить более точную оценку времени выполнения, запустив несколько циклов и отключив сборку мусора, в этом случае достаточно простого просмотра одного запуска со временем, как вы вскоре увидите.

      Использование NumPy

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

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

      def np_descent (x, d, mu, N_epochs):
          d = d.squeeze()
          N = len (x)
          f = 2 / N
      
          y = np.zeros (N)
          err = np.zeros (N)
          w = np.zeros (2)
          grad = np.empty (2)
      
          for _ in it.repeat (None, N_epochs):
              np.subtract (d, y, out=err)
              grad[:] = f * np.sum (err), f * (err @ x)
              w = w + mu * grad
              y = w[0] + w[1] * x
          return w
      
      np_w = np_descent (x, d, mu, N_epochs)
      print('Найдены коэффициенты линейной регрессии w0 и w1 (NumPy):', np_w)
      

      В приведенном выше блоке кода используются векторизованные операции с массивами NumPy (ndarrays). Единственный явный цикл for — это внешний цикл, в котором повторяется сама программа обучения. Понимание списков здесь отсутствует, потому что тип ndarray NumPy перегружает арифметические операторы для выполнения вычислений массива оптимальным образом.

      Вы можете заметить, что есть несколько альтернативных способов решения этой проблемы. Например, вы можете использовать просто f * err @ X, где X — это 2d-массив, который включает в себя вектор-столбец из единиц, а не наш 1d x.

      Однако на самом деле это не так уж и эффективно, потому что для этого требуется скалярное произведение всего столбца единиц с другим вектором (err), а мы знаем, что результатом будет просто np.sum(err). Аналогично, w[0] + w[1] * x тратит меньше вычислений, чем w * X, в этом конкретном случае.

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

      import timeit
      
      setup = ("from __main__ import x, d, mu, N_epochs, np_descent;"
               "import numpy as np")
      repeat = 5
      number = 5  # Количество петель в каждом повторе
      
      np_times = timeit.repeat ('np_descent (x, d, mu, N_epochs)', setup=setup,
                               repeat=repeat, number=number)
      

      timeit.repeat() возвращает список. Каждый элемент — общее время, затраченное на выполнение number циклов инструкции. Чтобы получить единую оценку времени выполнения, вы можете взять среднее время для одного вызова из нижней границы списка повторов:

      print('Время поиска решения (NumPy): {:.2f} seconds\n\n'.format(min(np_times) / number))
      

      Использование TensorFlow

      TensorFlow — это библиотека с открытым исходным кодом для численных вычислений, первоначально разработанная исследователями и инженерами, работающими в команде Google Brain.

      Используя свой Python API, процедуры TensorFlow реализованы в виде графа вычислений, которые необходимо выполнить. Узлы на графе представляют математические операции, а ребра графа представляют собой многомерные массивы данных (также называемые тензорами), передаваемые между ними.

      Во время выполнения TensorFlow берет граф вычислений и эффективно запускает его, используя оптимизированный код C++. Анализируя граф вычислений, TensorFlow может идентифицировать операции, которые могут выполняться параллельно.

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

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

      import tensorflow as tf
      
      def tf_descent (X_tf, d_tf, mu, N_epochs):
          N = X_tf.get_shape().as_list()[0]
          f = 2 / N
      
          w = tf.Variable (tf.zeros ( (2, 1)), name="w_tf")
          y = tf.matmul (X_tf, w, name="y_tf")
          e = y - d_tf
          grad = f * tf.matmul (tf.transpose (X_tf), e)
      
          training_op = tf.assign (w, w - mu * grad)
          init = tf.global_variables_initializer()
      
          with tf.Session() as sess:
              init.run()
              for epoch in range (N_epochs):
                  sess.run (training_op)
              opt = w.eval()
          return opt
      
      X_tf = tf.constant (X, dtype=tf.float32, name="X_tf")
      d_tf = tf.constant (d, dtype=tf.float32, name="d_tf")
      
      tf_w = tf_descent (X_tf, d_tf, mu, N_epochs)
      print('Найдены коэффициенты линейной регрессии w0 и w1 (TensorFlow):', tf_w)
      

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

      type (X_tf)
      
      

      После создания тензоров из обучающих данных определяется граф вычислений:

      • Во-первых, переменный тензор w используется для хранения параметров регрессии, которые будут обновляться на каждой итерации.
      • Используя w и X_tf, выход y вычисляется с использованием матричного произведения, реализованного с помощью tf.matmul().
      • Ошибка вычисляется и сохраняется в тензоре e.
      • Градиенты вычисляются с использованием матричного подхода путем умножения транспонирования X_tf на e.
      • Наконец, обновление параметров регрессии реализовано с помощью функции tf.assign(). Она создает узел, который реализует пакетный градиентный спуск, обновление тензора следующего шага w до w - mu * grad.

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

      Есть несколько разных способов инициализировать переменные и создать сеанс для выполнения вычислений. В этой программе строка init = tf.global_variables_initializer() создает узел в графе, который будет инициализировать переменные при запуске. Сеанс создается в блоке with, а init.run() используется для фактической инициализации переменных. Внутри блока with, training_op запускается для желаемого количества эпох, оценивая параметр регрессии,окончательное значение которых хранится в opt.

      Вот та же структура синхронизации кода, которая использовалась с реализацией NumPy:

      setup = ("from __main__ import X_tf, d_tf, mu, N_epochs, tf_descent;"
               "import tensorflow as tf")
      
      tf_times = timeit.repeat ("tf_descent (X_tf, d_tf, mu, N_epochs)", setup=setup,
                               repeat=repeat, number=number)
      
      print('Время поиска решения (TensorFlow):', min(tf_times) / number)
      

      Для оценки w_0 = 2,9598553 и w_1 = 2,032969 потребовалось 2,25 секунды. Стоит отметить, что вычисления выполнялись на CPU, и производительность может быть улучшена при запуске на GPU.

      Наконец, вы также можете определить функцию стоимости MSE и передать ее в функцию TensorFlow gradient(), которая выполняет автоматическое дифференцирование,нахождение вектора градиента MSE с учетом весов:

      mse = tf.reduce_mean (tf.square (e), name="mse")
      grad = tf.gradients (mse, w)[0]
      

      Однако разница во времени в этом случае незначительна.

      Заключение

      Цель этой статьи — показать различие производительности реализации простого итеративного алгоритма оценки коэффициентов линейной регрессии на чистом Python, NumPy и TensorFlow.

      Приведённые выше скрипты запускались на довольно «пожилом» ноутбуке, со следующими характеристиками:

      И вот полученные результаты по времени, затраченному на выполнение алгоритмов этих трёх реализаций:

      Реализация
      Время выполнения
      Чистый Python со списками
      37,21 с
      NumPy
      0,68 с
      TensorFlow на 1 ЦП
      2,25 с

      В то время как решения NumPy и TensorFlow конкурентоспособны (по CPU), реализация на чистом Python занимает далекое третье место. Хотя Python является надежным языком программирования общего назначения, его библиотеки, предназначенные для численных вычислений, всегда выиграют, когда дело доходит до больших пакетных операций с массивами.

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

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

      Ссылки

      По мотивам Pure Python vs NumPy vs TensorFlow Performance Comparison

      ]]>
      https://chel-center.ru/python-yfc/2020/12/21/chistyj-python-protiv-numpy-i-tensorflow-sravnenie-proizvoditelnosti/feed/ 0
      PyTorch против TensorFlow для вашего проекта глубокого обучения Python https://chel-center.ru/python-yfc/2020/12/22/pytorch-protiv-tensorflow-dlya-vashego-proekta-glubokogo-obucheniya-python/ https://chel-center.ru/python-yfc/2020/12/22/pytorch-protiv-tensorflow-dlya-vashego-proekta-glubokogo-obucheniya-python/#respond Tue, 22 Dec 2020 13:47:44 +0000 http://chel-center.ru/python-yfc/?p=31335 Читать далее «PyTorch против TensorFlow для вашего проекта глубокого обучения Python»

      ]]>
      PyTorch vs TensorFlow: в чем разница? Обе библиотеки Python с открытым исходным кодом, которые используют графики для выполнения числовых вычислений над данными. Оба они широко используются в академических исследованиях и коммерческом секторе. Оба они расширены различными API, платформами облачных вычислений и репозиториями моделей.

      Если они такие похожие, тогда какой из них лучше всего подходит для вашего проекта?

      Содержание

      В этом руководстве вы узнаете:

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

        Что такое TensorFlow?

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

        Название «TensorFlow» описывает, как вы организуете и выполняете операции с данными. Базовая структура данных как для TensorFlow, так и для PyTorch — это тензор. Когда вы используете TensorFlow, вы выполняете операции с данными в этих тензорах, строя граф потока данных с отслеживанием состояния, что-то вроде блок-схемы, которая запоминает прошлые события.

        Кто использует TensorFlow?

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

        После выпуска PyTorch в 2016 году популярность TensorFlow упала. Но в конце 2019 года Google выпустил TensorFlow 2.0, крупное обновление, которое упростило библиотеку и сделало ее более удобной для пользователя, что привело к возобновлению интереса в сообществе машинного обучения.

        Стиль и функция кода

        До TensorFlow 2.0 TensorFlow требовал, чтобы вы вручную сшивали абстрактное синтаксическое дерево — график — с помощью вызовов API tf. *. Затем потребовалось, чтобы вы вручную скомпилировали модель, передав набор выходных тензоров и входных тензоров в вызов session.run ().

        Объект Session — это класс для выполнения операций TensorFlow. Он содержит среду, в которой оцениваются объекты Tensor и выполняются объекты Operation, и может владеть такими ресурсами, как объекты tf.Variable. Наиболее распространенный способ использования сеанса — это диспетчер контекста.

        В TensorFlow 2.0 вы по-прежнему можете строить модели таким образом, но легче использовать активное выполнение,как обычно работает Python. Активное выполнение немедленно оценивает операции, поэтому вы можете писать свой код, используя поток управления Python, а не поток управления графом.

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

        >>> import tensorflow as tf
        
        >>> tf.compat.v1.disable_eager_execution()
        
        >>> x = tf.compat.v1.placeholder(tf.float32, name = "x")
        >>> y = tf.compat.v1.placeholder(tf.float32, name = "y")
        
        >>> multiply = tf.multiply(x, y)
        
        >>> with tf.compat.v1.Session() as session:
        ...     m = session.run(
        ...         multiply, feed_dict={x: [ [2., 4., 6.] ], y: [ [1.], [3.], [5.] ]}
        ...     )
        ...     print(m)
        [ [ 2.  4.  6.]
         [ 6. 12. 18.]
         [10. 20. 30.] ]
        

        Этот код использует API tf.compat TensorFlow 2.x для доступа к методам TensorFlow 1.x и отключения активного выполнения.

        Сначала вы объявляете входные тензоры x и y, используя объекты тензора tf.compat.v1.placeholder. Затем вы определяете операцию, которую нужно выполнить с ними. Затем, используя объект tf.Session в качестве диспетчера контекста, вы создаете контейнер для инкапсуляции среды выполнения и выполняете умножение, вводя реальные значения в заполнители с помощью feed_dict. Наконец, все еще внутри сеанса, вы print () результат.

        При активном выполнении в TensorFlow 2.0 все, что вам нужно, это tf.multiply () для достижения того же результата:

        >>> import tensorflow as tf
        
        >>> x = [ [2., 4., 6.] ]
        >>> y = [ [1.], [3.], [5.] ]
        >>> m = tf.multiply(x, y)
        
        >>> m
        
        

        В этом коде вы объявляете свои тензоры, используя нотацию списка Python, а tf.multiply () выполняет поэлементное умножение сразу после его вызова.

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

        Специальные возможности

        TensorFlow имеет обширную и хорошо зарекомендовавшую себя базу пользователей и множество инструментов, которые помогают продвигать машинное обучение. Для мобильной разработки у него есть API-интерфейсы для JavaScript и Swift (язык программирования), а TensorFlow Lite позволяет сжимать и оптимизировать модели для устройств Интернет вещей.

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

        Многие популярные алгоритмы машинного обучения и наборы данных встроены в TensorFlow и готовы к использованию. Помимо встроенных наборов данных, вы можете получить доступ к наборам данных Google Research или использовать поиск Google по набору данных, чтобы найти еще больше. Keras упрощает настройку и запуск моделей, поэтому вы можете опробовать новые методы за меньшее время. Действительно, Keras — наиболее часто используемый фреймворк глубокого обучения среди пяти лучших команд на Kaggle.

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

        PyTorch не имеет такой большой проблемы с обратной совместимостью, что может быть причиной его предпочтения перед TensorFlow.

        Экосистема Tensorflow

        Некоторые особенности API, расширений и полезных инструментов расширенной экосистемы TensorFlow включают:

        • TensorFlow Hub, библиотека для многоразовых модулей машинного обучения.
        • Model Garden, официальная коллекция моделей, использующих высокоуровневые API TensorFlow.
        • Практическое машинное обучение с помощью Scikit-Learn, Keras и TensorFlow, всестороннее введение в машинное обучение с использованием TensorFlow.
        • Что такое PyTorch?

          PyTorch был разработан Facebook и впервые публично выпущен в 2016 году. Он был создан, чтобы предложить производственную оптимизацию, аналогичную TensorFlow, при этом упрощая написание моделей.

          Поскольку программисты Python сочли его настолько естественным в использовании, PyTorch быстро приобрел пользователей, вдохновляя команду TensorFlow перенять многие из самых популярных функций PyTorch в TensorFlow 2.0.

          Кто использует PyTorch?

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

          В списке самых популярных «Другие фреймворки, библиотеки и инструменты» Stack Overflow Developer Survey за 2020 год указано, что 10.4% профессиональных разработчиков выбирают TensorFlow и 4,1% выбирают PyTorch. В 2018 году этот показатель составлял 7,6 процента для TensorFlow и всего 1,6 процента для PyTorch.

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

          Стиль и функция кода

          PyTorch основан на фреймворке Torch для быстрых вычислений, написанном на C. Torch имеет оболочку Lua для построения моделей.

          PyTorch оборачивает ту же внутреннюю часть C в интерфейс Python. Но это больше, чем просто обертка. Разработчики построили его с нуля, чтобы упростить написание моделей для программистов на Python. Основная, низкоуровневый код на C и C ++ оптимизирован для запуска кода Python. Благодаря такой тесной интеграции вы получаете:

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

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

        Активное выполнение PyTorch, которое оценивает тензорные операции немедленно и динамически, вдохновило TensorFlow 2.0, поэтому API для обоих выглядят очень похоже. Преобразование объектов NumPy в тензоры встроено в основные структуры данных PyTorch. Это означает, что вы можете легко переключаться между объектами torch.Tensor и numpy.array.

        Например, вы можете использовать встроенную поддержку PyTorch для преобразования массивов NumPy в тензоры, чтобы создать два объекта numpy.array, превратив каждый в факел. Тензорный объект с помощью torch.from_numpy (), а затем получение их поэлементного произведения:

        >>> import torch
        >>> import numpy as np
        
        >>> x = np.array([ [2., 4., 6.] ])
        >>> y = np.array([ [1.], [3.], [5.] ])
        
        >>> m = torch.mul(torch.from_numpy(x), torch.from_numpy(y))
        
        >>> m.numpy()
        array([ [ 2.,  4.,  6.],
               [ 6., 12., 18.],
               [10., 20., 30.] ])
        

        Использование torch.Tensor.numpy () позволяет распечатать результат умножения матриц — объект torch.Tensor — в виде объекта numpy.array.

        Наиболее важное различие между объектом torch.Tensor и объектом numpy.array заключается в том, что класс torch.Tensor имеет разные методы и атрибуты, такие как backward (), который вычисляет градиент и совместимость с CUDA.

        Специальные функции

        PyTorch добавляет модуль C++ для автоматического дифференцирования в серверную часть Torch. Автоматическое дифференцирование автоматически вычисляет градиент функций, определенных в torch.nn во время обратного распространения ошибки.

        По умолчанию PyTorch использует вычисление в режиме ожидания. Вы можете запускать нейронную сеть по мере ее построения, построчно, что упрощает отладку. Также он позволяет строить нейронные сети с условным исполнением. Это динамическое выполнение более интуитивно понятно для большинства Python.

        Экосистема PyTorch

        Некоторые особенности API, расширений и полезных инструментов расширенной экосистемы PyTorch включают:

        • API fast.ai, который упрощает быстрое создание моделей.
        • TorchServe, сервер модели с открытым исходным кодом, разработанный в сотрудничестве между AWS и Facebook.
        • TorchElastic для масштабного обучения глубоких нейронных сетей с помощью Kubernetes
        • PyTorch Hub, активное сообщество для обмена и распространения передовых моделей.

        Руководство по выбору PyTorch и TensorFlow

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

        Стиль

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

        С другой стороны, в TensorFlow поддерживается больше языков программирования, чем в PyTorch, в котором есть C++ API. Вы можете использовать TensorFlow как в JavaScript, так и в Swift. Если вы не хотите писать много низкоуровневого кода, затем Keras абстрагирует многие детали для типичных случаев использования, чтобы вы могли создавать модели TensorFlow, не вдаваясь в детали.

        Данные и модель

        Какие модели вы используете? Если вы хотите использовать конкретную предварительно обученную модель, например BERT или DeepDream, вам следует изучить, с чем она совместима. Некоторые предварительно обученные модели доступны только в одной или другой библиотеке, а некоторые доступны в обеих. Model Garden и хабы PyTorch и TensorFlow также являются хорошими ресурсами для проверки.

        Какие данные вам нужны? Если вы хотите использовать предварительно обработанные данные, они могут быть уже встроены в одну или другую библиотеку. Посмотрите документацию — это ускорит вашу разработку!

        Цель проекта

        Где будет жить ваша модель? Если вы хотите развернуть модель на мобильных устройствах, то TensorFlow — хороший выбор из-за TensorFlow Lite и его Swift API. Что касается обслуживания моделей, TensorFlow тесно интегрирован с Google Cloud, но PyTorch интегрирован в TorchServe на AWS. Если вы хотите принять участие в соревнованиях Kaggle, тогда Керас позволит вам быстро повторять эксперименты.

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

        Заключение

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

        В этом уроке вы узнали:

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

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

        Дополнительная литература

        Следующие учебные пособия — отличный способ попрактиковаться в PyTorch и TensorFlow:

        По мотивам PyTorch vs TensorFlow for Your Python Deep Learning Project

        ]]> https://chel-center.ru/python-yfc/2020/12/22/pytorch-protiv-tensorflow-dlya-vashego-proekta-glubokogo-obucheniya-python/feed/ 0 Python и базы данных MySQL: практическое введение https://chel-center.ru/python-yfc/2021/01/02/python-i-bazy-dannyh-mysql-prakticheskoe-vvedenie/ https://chel-center.ru/python-yfc/2021/01/02/python-i-bazy-dannyh-mysql-prakticheskoe-vvedenie/#respond Sat, 02 Jan 2021 17:45:14 +0000 http://chel-center.ru/python-yfc/?p=31417 Читать далее «Python и базы данных MySQL: практическое введение»

        ]]>
        Содержание

        MySQL — одна из самых популярных сегодня на рынке систем управления базами данных (СУБД). В этом году в рейтинге DB‑Engines она заняла второе место после СУБД Oracle. Поскольку большинству программных приложений необходимо взаимодействовать с данными в той или иной форме, языки программирования, такие как Python, предоставляют инструменты для хранения этих источников данных и доступа к ним. Используя методы, описанные в этом уроке, вы сможете эффективно интегрировать базу данных MySQL с приложением Python. Вы разработаете небольшую базу данных MySQL для системы рейтинга фильмов и узнаете, как запрашивать ее прямо из кода Python.

        К концу этого урока вы сможете:

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

        Чтобы получить максимальную отдачу от этого руководства, вы должны иметь практические знания о таких концепциях Python, как циклы, функции, обработка исключений и т.д, установка пакетов Python с помощью pip. Вы также должны иметь базовое представление о системах управления реляционными базами данных и SQL-запросах, таких как SELECT, DROP, CREATE и JOIN.

        Сравнение MySQL с другими базами данных SQL

        SQL расшифровывается как язык структурированных запросов и является широко используемым языком программирования для управления реляционными базами данных. Возможно, вы слышали о различных вариантах СУБД на основе SQL. К наиболее популярным из них относятся MySQL, PostgreSQL, SQLite и SQL Server. Все эти базы данных соответствуют стандартам SQL, но с разной степенью соответствия.

        Будучи открытым исходным кодом с момента своего создания в 1995 году, MySQL быстро стал лидером рынка среди решений SQL. MySQL также является частью экосистемы Oracle. Хотя его основная функциональность полностью бесплатна, есть и платные дополнения. В настоящее время,MySQL используется всеми крупными техническими фирмами, включая Google, LinkedIn, Uber, Netflix, Twitter и другие.

        Помимо поддержки большого сообщества разработчиков ПО с открытым исходным кодом, есть много других причин успеха MySQL:

        1. Легкость установки: MySQL был разработан, чтобы быть удобным для пользователя. Установить базу данных MySQL довольно просто, а несколько широко доступных сторонних инструментов, таких как phpMyAdmin, еще больше упрощают процесс установки. MySQL доступен для всех основных операционных систем, включая Windows, macOS, Linux и Solaris.
        2. Скорость: MySQL имеет репутацию чрезвычайно быстрого решения для баз данных. Он имеет относительно меньшую площадь и чрезвычайно масштабируем в долгосрочной перспективе.
        3. Права пользователя и безопасность: MySQL поставляется со сценарием, который позволяет вам устанавливать уровень безопасности паролей, назначать пароли администратора, а также добавлять и удалять привилегии учетной записи пользователя. Подобный подход упрощает процесс администрирования портала управления пользователями веб-хостинга. Другие СУБД, такие как PostgreSQL, используют файлы конфигурации, с которыми гораздо сложнее.

        Хотя MySQL славится своей скоростью и простотой использования, вы можете получить более продвинутые функции с PostgreSQL. Кроме того, MySQL не полностью совместим с SQL и имеет определенные функциональные ограничения, например, отсутствие поддержки предложений FULL JOIN.

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

        Примечание. Для более подробного сравнения MySQL и PostgreSQL в реальном контексте ознакомьтесь с Why Uber Engineering Switched from Postgres to MySQL.

        SQL Server также является очень популярной СУБД, известной своей надежностью, эффективностью и безопасностью. Его предпочитают компании, особенно в банковской сфере, которые регулярно имеют дело с большими объемами трафика. Это коммерческое решение и одна из систем, наиболее совместимых со службами Windows.

        В 2010, когда Oracle приобрела Sun Microsystems и MySQL, многих беспокоило будущее MySQL. В то время Oracle была крупнейшим конкурентом MySQL. Разработчики опасались, что это было враждебное поглощение Oracle с целью уничтожения MySQL.

        Несколько разработчиков во главе с Майклом Видениусом, первоначальным автором MySQL, создал форк базы кода MySQL и заложил основу MariaDB. Целью было обезопасить доступ к MySQL и сделать его бесплатным навсегда.

        На сегодняшний день MariaDB остается полностью под GNU General Public License, сохраняя ее полностью в открытом доступе. С другой стороны, некоторые функции MySQL доступны только с платными лицензиями. Также, MariaDB предоставляет несколько чрезвычайно полезных функций, которые не поддерживаются сервером MySQL, например распределенный SQL и столбчатое хранилище. Вы можете найти больше различий между MySQL и MariaDB, перечисленных на веб-сайте MariaDB.

        MySQL использует синтаксис, очень похожий на стандартный SQL. Однако есть некоторые заметные отличия, упомянутые в официальной документации.

        Установка MySQL Server и MySQL Connector/Python

        Теперь, чтобы начать работу с этим руководством, вам необходимо настроить две вещи: сервер MySQL и коннектор MySQL. Сервер MySQL предоставит все услуги, необходимые для работы с вашей базой данных. После того, как сервер запущен и работает, вы можете подключить к нему свое приложение Python с помощью MySQL Connector/Python.

        Установка сервера MySQL

        В официальной документации подробно описан рекомендуемый способ загрузки и установки сервера MySQL. Вы найдете инструкции для всех популярных операционных систем, включая Windows, macOS, Solaris, Linux и многие другие.

        Для Windows лучше всего загрузить установщик MySQL и позволить ему позаботиться обо всем процессе. Диспетчер установки также помогает настроить параметры безопасности сервера MySQL. На странице Учетные записи и роли вам необходимо ввести пароль для учетной записи root (admin), а также при желании добавить других пользователей с различными привилегиями:

        Настройка учетной записи установщика MySQL
        Настройка учетной записи установщика MySQL

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

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

        Хотя в этом уроке понадобится только сервер MySQL, c помощью этих установщика вы можете настроить другие полезные инструменты, такие как MySQL Workbench. Если вы не хотите устанавливать MySQL непосредственно в свою операционную систему, то удобная альтернатива развертывание MySQL в Linux с помощью Docker.

        Установка MySQL Connector/Python

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

        Эти драйверы обычно поставляются как сторонние модули. API базы данных Python(DB‑API) определяет стандартный интерфейс, которому должны соответствовать все драйверы баз данных Python. Эти сведения задокументированы в PEP 249. Все драйверы баз данных Python, такие как sqlite3 для SQLite, psycopg для PostgreSQL и MySQL Connector/Python для MySQL, следуют этим правилам реализации.

        Примечание. В официальной документации MySQL вместо «драйвер» используется термин «коннектор». Технически соединители связаны только с подключением к базе данных, а не с ней. Однако этот термин часто используется для всего модуля доступа к базе данных, включающего коннектор и драйвер.

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

        Многие популярные языки программирования имеют собственный API баз данных. Например, в Java есть API подключения к базе данных Java (JDBC). Если вам необходимо подключить Java‑приложение к базе данных MySQL, вам необходимо использовать MySQL JDBC‑коннектор, который следует за JDBC API.

        Так же, в Python вам необходимо установить коннектор Python MySQL для взаимодействия с базой данных MySQL. Многие пакеты соответствуют стандартам DB‑API, но наиболее популярным среди них является MySQL Connector/Python. Вы можете получить его с помощью pip:

        $ pip install mysql-connector-python
        

        pip устанавливает коннектор как сторонний модуль в текущую активную виртуальную среду. Рекомендуется настроить изолированную виртуальную среду для проекта вместе со всеми зависимостями.

        Чтобы проверить, была ли установка успешной, введите в терминале Python следующую команду:

        >>> import mysql.connector
        

        Если приведенный выше код выполняется без ошибок, значит mysql.connector установлен и готов к использованию. Если вы столкнулись с какими-либо ошибками, убедитесь, что вы находитесь в правильной виртуальной среде и используете правильный интерпретатор Python.

        Убедитесь, что вы устанавливаете правильный пакет mysql‑connector‑python, который является чистой реализацией Python. Остерегайтесь одноименных, но теперь устаревших коннекторов, таких как mysql‑connector.

        Установление соединения с сервером MySQL

        MySQL — это серверная система управления базами данных. Один сервер может содержать несколько баз данных. Чтобы взаимодействовать с базой данных, вы должны сначала установить соединение с сервером. Общий рабочий процесс программы Python, которая взаимодействует с базой данных на основе MySQL, выглядит следующим образом:

        1. Подключитесь к серверу MySQL.
        2. Создайте новую базу данных.
        3. Подключитесь к вновь созданной или существующей базе данных.
        4. Выполните SQL-запрос и получите результаты.
        5. Сообщите базе данных, если в таблицу были внесены какие-либо изменения.
        6. Закройте соединение с сервером MySQL.

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

        Установление соединения

        Первым шагом во взаимодействии с сервером MySQL является установление соединения. Для этого вам потребуется connect() из модуля mysql.connector. Эта функция принимает такие параметры, как хост, пользователь и пароль, и возвращает объект MySQLConnection. Вы можете получить эти учетные данные в качестве ввода от пользователя и передать их в connect():

        from getpass import getpass
        from mysql.connector import connect, Error
        
        try:
            with connect(
                host="localhost",
                user=input("Enter username: "),
                password=getpass("Enter password: "),
            ) as connection:
                print(connection)
        except Error as e:
            print(e)
        

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

        В приведенном выше коде есть несколько важных моментов:

        • Вы всегда должны иметь дело с исключениями, которые могут возникнуть при установлении соединения с сервером MySQL. Вот почему вы используете блок try… except для перехвата и печати любых исключений, с которыми вы можете столкнуться.
        • Вы всегда должны закрывать соединение после завершения доступа к базе данных. Если оставить неиспользуемые открытые соединения, это может привести к нескольким неожиданным ошибкам и проблемам с производительностью. Приведенный выше код использует диспетчер контекста с помощью with, который абстрагирует процесс очистки соединения.
        • Никогда не следует жестко кодировать свои учетные данные для входа, то есть имя пользователя и пароль, непосредственно в скрипт Python. Это плохая практика для развертывания и представляет серьезную угрозу безопасности. Приведенный выше код запрашивает у пользователя учетные данные для входа. Он использует встроенный модуль getpass, чтобы скрыть пароль. Хотя это лучше, чем жесткое кодирование, есть и другие, более безопасные способы хранения конфиденциальной информации, например, использование переменных среды.
        • Теперь вы установили соединение между вашей программой и сервером MySQL, но вам все равно нужно либо создать новую базу данных, либо подключиться к существующей базе данных внутри сервера.

          Создание новой базы данных

          Вы установили соединение с вашим сервером MySQL. Чтобы создать новую базу данных, вам необходимо выполнить инструкцию SQL:

          CREATE DATABASE books_db;
          

          Приведенный выше оператор создаст новую базу данных с именем books_db.

          Примечание. В MySQL обязательно ставить точку с запятой (;) в конце оператора, что означает завершение запроса. Однако MySQL Connector/Python автоматически добавляет точку с запятой в конце ваших запросов, поэтому нет необходимости использовать ее в вашем коде Python.

          Чтобы выполнить SQL-запрос в Python, вам потребуется использовать курсор, который абстрагирует доступ к записям базы данных. MySQL Connector/Python предоставляет вам класс MySQLCursor, который создает экземпляры объектов для выполнения запросов MySQL в Python. Экземпляр класса MySQLCursor также называется cursor. Объект cursor используется для взаимодействия с вашим сервером MySQL. Чтобы создать курсор, используйте метод .cursor() вашей переменной соединения:

          cursor = connection.cursor()
          

          Приведенный выше код создает экземпляр класса MySQLCursor.

          Запрос, который необходимо выполнить, отправляется в cursor.execute() в строковом формате. В этом конкретном случае вы отправите запрос CREATE DATABASE к cursor.execute():

          from getpass import getpass
          from mysql.connector import connect, Error
          
          try:
              with connect(
                  host="localhost",
                  user=input("Enter username: "),
                  password=getpass("Enter password: "),
              ) as connection:
                  create_db_query = "CREATE DATABASE online_movie_rating"
                  with connection.cursor() as cursor:
                      cursor.execute(create_db_query)
          except Error as e:
              print(e)
          

          После выполнения приведенного выше кода на вашем сервере MySQL появится новая база данных с именем online_movie_rating.

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

          Здесь вы можете получить сообщение об ошибке, если база данных с таким именем уже существует на вашем сервере. Чтобы подтвердить это, вы можете отобразить имена всех баз данных на вашем сервере. Используя тот же объект MySQLConnection, что и ранее, выполните инструкцию SHOW DATABASES:

          >>> show_db_query = "SHOW DATABASES"
          >>> with connection.cursor() as cursor:
          ...     cursor.execute(show_db_query)
          ...     for db in cursor:
          ...         print(db)
          ...
          ('information_schema',)
          ('mysql',)
          ('online_movie_rating',)
          ('performance_schema',)
          ('sys',)
          

          Приведенный выше код печатает имена всех баз данных, находящихся в настоящее время на вашем сервере MySQL. Команда SHOW DATABASES также выводит некоторые базы данных, которые вы не создавали на своем сервере, например, information_schema, performance_schema и т.д. Эти базы данных создаются автоматически сервером MySQL и предоставляют доступ к различным метаданным базы данных и настройкам сервера MySQL.

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

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

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

          Вы можете сделать это, используя ту же функцию connect(), которую вы использовали ранее, отправив дополнительный параметр с именем database:

          from getpass import getpass
          from mysql.connector import connect, Error
          
          try:
              with connect(
                  host="localhost",
                  user=input("Enter username: "),
                  password=getpass("Enter password: "),
                  database="online_movie_rating",
              ) as connection:
                  print(connection)
          except Error as e:
              print(e)
          

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

          Создание, изменение и удаление таблицы

          В этом разделе вы узнаете, как выполнять некоторые базовые запросы DDL, такие как CREATE, DROP и ALTER с помощью Python. Вы быстро ознакомитесь с базой данных MySQL, которую будете использовать в оставшейся части этого руководства. Вы также создадите все таблицы, необходимые для базы данных, и позже узнаете, как вносить изменения в эти таблицы.

          Определение схемы базы данных

          Вы можете начать с создания схемы базы данных для онлайн-рейтинговой системы фильмов. База данных будет состоять из трех таблиц:

          1. movies содержит общую информацию о фильмах и имеет следующие атрибуты:
            • id
            • title
            • release_year
            • genre
            • collection_in_mil
          2. reviewers содержат информацию о людях, которые опубликовали обзоры или рейтинги и имеет следующие атрибуты:
            • id
            • first_name
            • last_name
          3. ratings содержат информацию о размещенных рейтингах и имеют следующие атрибуты:
            • movie_id (внешний ключ)
            • reviewer_id (внешний ключ)
            • rating

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

          На изображении ниже показана схема базы данных:

          Схема онлайн-рейтинговой системы фильмов
          Схема онлайн-рейтинговой системы фильмов

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

          Создание таблиц с помощью оператора CREATE TABLE

          Теперь, чтобы создать новую таблицу в MySQL, вам нужно использовать оператор CREATE TABLE. Следующий запрос MySQL создаст таблицу фильмов для вашей базы данных online_movie_rating:

          CREATE TABLE movies(
              id INT AUTO_INCREMENT PRIMARY KEY,
              title VARCHAR(100),
              release_year YEAR(4),
              genre VARCHAR(100),
              collection_in_mil INT
          );
          

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

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

          Чтобы создать новую таблицу, вам необходимо передать этот запрос в cursor.execute(), который принимает запрос MySQL и выполняет запрос в подключенной базе данных MySQL:

          create_movies_table_query = """
          CREATE TABLE movies(
              id INT AUTO_INCREMENT PRIMARY KEY,
              title VARCHAR(100),
              release_year YEAR(4),
              genre VARCHAR(100),
              collection_in_mil INT
          )
          """
          with connection.cursor() as cursor:
              cursor.execute(create_movies_table_query)
              connection.commit()
          

          Теперь у вас есть таблица фильмов в вашей базе данных. Вы передаете create_movies_table_query функции cursor.execute(), которая выполняет требуемое выполнение.

          Примечание. Переменная connection относится к объекту MySQLConnection, который был возвращен при подключении к базе данных.

          Также обратите внимание на оператор connection.commit() в конце кода. По умолчанию ваш connection MySQL не выполняет автоматическую фиксацию транзакций. В MySQL модификации, упомянутые в транзакции, происходят только тогда, когда вы используете в конце команду COMMIT. Всегда вызывайте этот метод после каждой транзакции, чтобы внести изменения в фактическую таблицу.

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

          create_reviewers_table_query = """
          CREATE TABLE reviewers (
              id INT AUTO_INCREMENT PRIMARY KEY,
              first_name VARCHAR(100),
              last_name VARCHAR(100)
          )
          """
          with connection.cursor() as cursor:
              cursor.execute(create_reviewers_table_query)
              connection.commit()
          

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

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

          create_ratings_table_query = """
          CREATE TABLE ratings (
              movie_id INT,
              reviewer_id INT,
              rating DECIMAL(2,1),
              FOREIGN KEY(movie_id) REFERENCES movies(id),
              FOREIGN KEY(reviewer_id) REFERENCES reviewers(id),
              PRIMARY KEY(movie_id, reviewer_id)
          )
          """
          with connection.cursor() as cursor:
              cursor.execute(create_ratings_table_query)
              connection.commit()
          

          Реализация отношений внешнего ключа в MySQL немного отличается и ограничена по сравнению со стандартным SQL. В MySQL и родитель, и потомок в ограничении внешнего ключа должны использовать один и тот же механизм хранения.

          Механизм хранения — это базовый программный компонент, который система управления базами данных использует для выполнения операций SQL. В MySQL механизмы хранения бывают двух разных видов:

          1. Механизмы хранения транзакций безопасны для транзакций и позволяют откатывать транзакции с помощью простых команд, таких как откат. Многие популярные движки MySQL, включая InnoDB и NDB, принадлежат к этой категории.
          2. Нетранзакционные механизмы хранения зависят от сложного ручного кода для отмены операторов, зафиксированных в базе данных. MyISAM, MEMORY и многие другие механизмы MySQL нетранзакционные.

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

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

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

          with connection.cursor() as cursor:
              cursor.execute(create_movies_table_query)
              cursor.execute(create_reviewers_table_query)
              cursor.execute(create_ratings_table_query)
              connection.commit()
          

          Приведенный выше код сначала выполнит все три оператора CREATE. Затем он отправит команду COMMIT серверу MySQL, который фиксирует вашу транзакцию. Вы также можете использовать .rollback() для отправки команды ROLLBACK серверу MySQL и удаления всех изменений данных из транзакции.

          Отображение схемы таблицы с помощью оператора DESCRIBE

          Теперь, когда вы создали все три таблицы, вы можете просмотреть их схему, используя следующий оператор SQL:

          DESCRIBE ;
          

          Чтобы получить некоторые результаты от объекта курсора, вам нужно использовать cursor.fetchall(). Этот метод извлекает все строки из последнего выполненного оператора. Предполагая, что у вас уже есть объект MySQLConnection в переменной соединения, вы можете распечатать все результаты, полученные с помощью cursor.fetchall():

          >>> show_table_query = "DESCRIBE movies"
          >>> with connection.cursor() as cursor:
          ...     cursor.execute(show_table_query)
          ...     # Fetch rows from last executed query
          ...     result = cursor.fetchall()
          ...     for row in result:
          ...         print(row)
          ...
          ('id', 'int(11)', 'NO', 'PRI', None, 'auto_increment')
          ('title', 'varchar(100)', 'YES', '', None, '')
          ('release_year', 'year(4)', 'YES', '', None, '')
          ('genre', 'varchar(100)', 'YES', '', None, '')
          ('collection_in_mil', 'int(11)', 'YES', '', None, '')
          

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

          Изменение схемы таблицы с помощью оператора ALTER

          В таблице фильмов у вас есть столбец с именем collection_in_mil, который содержит кассовые сборы фильма в миллионах долларов. Вы можете написать следующий оператор MySQL, чтобы изменить тип данных атрибута collection_in_mil с INT на DECIMAL:

          ALTER TABLE movies MODIFY COLUMN collection_in_mil DECIMAL(4,1);
          

          DECIMAL (4,1) означает десятичное число, которое может иметь не более 4 цифр, из которых 1 является десятичной, например 120,1, 3,4, 38,0 и т. Д. После выполнения оператора ALTER TABLE вы можете показать обновленную схему таблицы, используя DESCRIBE:

          >>> alter_table_query = """
          ... ALTER TABLE movies
          ... MODIFY COLUMN collection_in_mil DECIMAL(4,1)
          ... """
          >>> show_table_query = "DESCRIBE movies"
          >>> with connection.cursor() as cursor:
          ...     cursor.execute(alter_table_query)
          ...     cursor.execute(show_table_query)
          ...     # Fetch rows from last executed query
          ...     result = cursor.fetchall()
          ...     print("Movie Table Schema after alteration:")
          ...     for row in result:
          ...         print(row)
          ...
          Movie Table Schema after alteration
          ('id', 'int(11)', 'NO', 'PRI', None, 'auto_increment')
          ('title', 'varchar(100)', 'YES', '', None, '')
          ('release_year', 'year(4)', 'YES', '', None, '')
          ('genre', 'varchar(100)', 'YES', '', None, '')
          ('collection_in_mil', 'decimal(4,1)', 'YES', '', None, '')
          

          Как показано в выходных данных, атрибут collection_in_mil теперь имеет тип DECIMAL (4,1). Также обратите внимание, что в приведенном выше коде вы дважды вызываете cursor.execute(). Но cursor.fetchall() выбирает строки только из последнего выполненного запроса, которым является show_table_query.

          Удаление таблиц с помощью оператора DROP

          Чтобы удалить таблицу, вам необходимо выполнить оператор DROP TABLE в MySQL. Удаление таблицы — необратимый процесс. Если вы выполните приведенный ниже код, вам нужно будет снова вызвать запрос CREATE TABLE для использования таблицы рейтингов в следующих разделах.

          Чтобы удалить таблицу рейтингов, отправьте drop_table_query в cursor.execute():

          drop_table_query = "DROP TABLE ratings"
          with connection.cursor() as cursor:
              cursor.execute(drop_table_query)
          

          Если вы выполните приведенный выше код, вы успешно удалите таблицу рейтингов.

          Вставка записей в таблицы

          В последнем разделе вы создали в своей базе данных три таблицы: фильмы, рецензенты и рейтинги. Теперь вам нужно заполнить эти таблицы данными. В этом разделе будут рассмотрены два разных способа вставки записей в MySQL Connector для Python.

          Первый метод, .execute(), хорошо работает, когда количество записей невелико, а записи могут быть сложно-кодированными. Второй метод, .executemany(), более популярен и лучше подходит для реальных сценариев.

          Использование .execute()

          Первый подход использует тот же метод cursor.execute(), который вы использовали до сих пор. Вы пишете запрос INSERT INTO в строке и передаете его в cursor.execute(). Вы можете использовать этот метод для вставки данных в таблицу фильмов.

          Для справки, таблица фильмов имеет пять атрибутов:

          1. id
          2. title
          3. release_year
          4. genre
          5. collection_in_mil

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

          insert_movies_query = """
          INSERT INTO movies (title, release_year, genre, collection_in_mil)
          VALUES
              ("Forrest Gump", 1994, "Drama", 330.2),
              ("3 Idiots", 2009, "Drama", 2.4),
              ("Eternal Sunshine of the Spotless Mind", 2004, "Drama", 34.5),
              ("Good Will Hunting", 1997, "Drama", 138.1),
              ("Skyfall", 2012, "Action", 304.6),
              ("Gladiator", 2000, "Action", 188.7),
              ("Black", 2005, "Drama", 3.0),
              ("Titanic", 1997, "Romance", 659.2),
              ("The Shawshank Redemption", 1994, "Drama",28.4),
              ("Udaan", 2010, "Drama", 1.5),
              ("Home Alone", 1990, "Comedy", 286.9),
              ("Casablanca", 1942, "Romance", 1.0),
              ("Avengers: Endgame", 2019, "Action", 858.8),
              ("Night of the Living Dead", 1968, "Horror", 2.5),
              ("The Godfather", 1972, "Crime", 135.6),
              ("Haider", 2014, "Action", 4.2),
              ("Inception", 2010, "Adventure", 293.7),
              ("Evil", 2003, "Horror", 1.3),
              ("Toy Story 4", 2019, "Animation", 434.9),
              ("Air Force One", 1997, "Drama", 138.1),
              ("The Dark Knight", 2008, "Action",535.4),
              ("Bhaag Milkha Bhaag", 2013, "Sport", 4.1),
              ("The Lion King", 1994, "Animation", 423.6),
              ("Pulp Fiction", 1994, "Crime", 108.8),
              ("Kai Po Che", 2013, "Sport", 6.0),
              ("Beasts of No Nation", 2015, "War", 1.4),
              ("Andadhun", 2018, "Thriller", 2.9),
              ("The Silence of the Lambs", 1991, "Crime", 68.2),
              ("Deadpool", 2016, "Action", 363.6),
              ("Drishyam", 2015, "Mystery", 3.0)
          """
          with connection.cursor() as cursor:
              cursor.execute(insert_movies_query)
              connection.commit()
          

          Таблица фильмов теперь загружена тридцатью записями. В конце код вызывает connection.commit(). Крайне важно вызывать .commit() после внесения любых изменений в таблицу.

          Использование .executemany()

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

          Вот здесь пригодится .executemany(). Он принимает два параметра:

          1. Запрос, содержащий заполнители для записей, которые необходимо вставить.
          2. Список, содержащий все записи, которые вы хотите вставить.

          В следующем примере вставляются записи в таблицу reviewers:

          insert_reviewers_query = """
          INSERT INTO reviewers
          (first_name, last_name)
          VALUES ( %s, %s )
          """
          reviewers_records = [
              ("Chaitanya", "Baweja"),
              ("Mary", "Cooper"),
              ("John", "Wayne"),
              ("Thomas", "Stoneman"),
              ("Penny", "Hofstadter"),
              ("Mitchell", "Marsh"),
              ("Wyatt", "Skaggs"),
              ("Andre", "Veiga"),
              ("Sheldon", "Cooper"),
              ("Kimbra", "Masters"),
              ("Kat", "Dennings"),
              ("Bruce", "Wayne"),
              ("Domingo", "Cortes"),
              ("Rajesh", "Koothrappali"),
              ("Ben", "Glocker"),
              ("Mahinder", "Dhoni"),
              ("Akbar", "Khan"),
              ("Howard", "Wolowitz"),
              ("Pinkie", "Petit"),
              ("Gurkaran", "Singh"),
              ("Amy", "Farah Fowler"),
              ("Marlon", "Crafford"),
          ]
          with connection.cursor() as cursor:
              cursor.executemany(insert_reviewers_query, reviewers_records)
              connection.commit()
          

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

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

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

          insert_ratings_query = """
          INSERT INTO ratings
          (rating, movie_id, reviewer_id)
          VALUES ( %s, %s, %s)
          """
          ratings_records = [
              (6.4, 17, 5), (5.6, 19, 1), (6.3, 22, 14), (5.1, 21, 17),
              (5.0, 5, 5), (6.5, 21, 5), (8.5, 30, 13), (9.7, 6, 4),
              (8.5, 24, 12), (9.9, 14, 9), (8.7, 26, 14), (9.9, 6, 10),
              (5.1, 30, 6), (5.4, 18, 16), (6.2, 6, 20), (7.3, 21, 19),
              (8.1, 17, 18), (5.0, 7, 2), (9.8, 23, 3), (8.0, 22, 9),
              (8.5, 11, 13), (5.0, 5, 11), (5.7, 8, 2), (7.6, 25, 19),
              (5.2, 18, 15), (9.7, 13, 3), (5.8, 18, 8), (5.8, 30, 15),
              (8.4, 21, 18), (6.2, 23, 16), (7.0, 10, 18), (9.5, 30, 20),
              (8.9, 3, 19), (6.4, 12, 2), (7.8, 12, 22), (9.9, 15, 13),
              (7.5, 20, 17), (9.0, 25, 6), (8.5, 23, 2), (5.3, 30, 17),
              (6.4, 5, 10), (8.1, 5, 21), (5.7, 22, 1), (6.3, 28, 4),
              (9.8, 13, 1)
          ]
          with connection.cursor() as cursor:
              cursor.executemany(insert_ratings_query, ratings_records)
              connection.commit()
          

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

          Чтение записей из базы данных

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

          Чтение записей с помощью оператора SELECT

          Чтобы получить записи, вам необходимо отправить запрос SELECT в cursor.execute(). Затем вы используете cursor.fetchall() для извлечения извлеченной таблицы в виде списка строк или записей.

          Попробуйте написать запрос MySQL, чтобы выбрать все записи из таблицы фильмов и отправить его в .execute():

          >>> select_movies_query = "SELECT * FROM movies LIMIT 5"
          >>> with connection.cursor() as cursor:
          ...     cursor.execute(select_movies_query)
          ...     result = cursor.fetchall()
          ...     for row in result:
          ...         print(row)
          ...
          (1, 'Forrest Gump', 1994, 'Drama', Decimal('330.2'))
          (2, '3 Idiots', 2009, 'Drama', Decimal('2.4'))
          (3, 'Eternal Sunshine of the Spotless Mind', 2004, 'Drama', Decimal('34.5'))
          (4, 'Good Will Hunting', 1997, 'Drama', Decimal('138.1'))
          (5, 'Skyfall', 2012, 'Action', Decimal('304.6'))
          

          Переменная результата содержит записи, возвращенные с помощью .fetchall(). Это список кортежей, представляющих отдельные записи из таблицы.

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

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

          SELECT * FROM movies LIMIT 2,5;
          

          Первый аргумент задает смещение 2, а второй аргумент ограничивает количество возвращаемых строк до 5. Вышеупомянутый запрос вернет строки с 3 по 7.

          Вы также можете запросить выбранные столбцы:

          >>> select_movies_query = "SELECT title, release_year FROM movies LIMIT 5"
          >>> with connection.cursor() as cursor:
          ...     cursor.execute(select_movies_query)
          ...     for row in cursor.fetchall():
          ...         print(row)
          ...
          ('Forrest Gump', 1994)
          ('3 Idiots', 2009)
          ('Eternal Sunshine of the Spotless Mind', 2004)
          ('Good Will Hunting', 1997)
          ('Skyfall', 2012)
          

          Теперь код выводит значения только из двух указанных столбцов: title и release_year.

          Фильтрация результатов с использованием предложения WHERE

          Вы можете фильтровать записи таблицы по определенным критериям, используя предложение WHERE. Например, чтобы получить все фильмы с кассовыми сборами более 300 миллионов долларов, вы можете выполнить следующий запрос:

          SELECT title, collection_in_mil
          FROM movies
          WHERE collection_in_mil > 300;
          

          Вы также можете использовать предложение ORDER BY в последнем запросе для сортировки результатов от самого высокого до самого низкого заработка:

          >>> select_movies_query = """
          ... SELECT title, collection_in_mil
          ... FROM movies
          ... WHERE collection_in_mil > 300
          ... ORDER BY collection_in_mil DESC
          ... """
          >>> with connection.cursor() as cursor:
          ...     cursor.execute(select_movies_query)
          ...     for movie in cursor.fetchall():
          ...         print(movie)
          ...
          ('Avengers: Endgame', Decimal('858.8'))
          ('Titanic', Decimal('659.2'))
          ('The Dark Knight', Decimal('535.4'))
          ('Toy Story 4', Decimal('434.9'))
          ('The Lion King', Decimal('423.6'))
          ('Deadpool', Decimal('363.6'))
          ('Forrest Gump', Decimal('330.2'))
          ('Skyfall', Decimal('304.6'))
          

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

          >>> select_movies_query = """
          ... SELECT CONCAT(title, " (", release_year, ")"),
          ...       collection_in_mil
          ... FROM movies
          ... ORDER BY collection_in_mil DESC
          ... LIMIT 5
          ... """
          >>> with connection.cursor() as cursor:
          ...     cursor.execute(select_movies_query)
          ...     for movie in cursor.fetchall():
          ...         print(movie)
          ...
          ('Avengers: Endgame (2019)', Decimal('858.8'))
          ('Titanic (1997)', Decimal('659.2'))
          ('The Dark Knight (2008)', Decimal('535.4'))
          ('Toy Story 4 (2019)', Decimal('434.9'))
          ('The Lion King (1994)', Decimal('423.6'))
          

          Если вы не хотите использовать предложение LIMIT и вам не нужно получать все записи, тогда объект курсора также имеет методы .fetchone() и .fetchmany():

          • .fetchone() извлекает либо следующую строку результата в виде кортежа, либо None, если доступных строк больше нет.
          • .fetchmany() извлекает следующий набор строк из результата в виде списка кортежей.У него есть аргумент размера, который по умолчанию равен 1, который вы можете использовать для указания количества строк, которые вам нужно получить. Если доступных строк больше нет, метод возвращает пустой список.

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

          >>> select_movies_query = """
          ... SELECT CONCAT(title, " (", release_year, ")"),
          ...       collection_in_mil
          ... FROM movies
          ... ORDER BY collection_in_mil DESC
          ... """
          >>> with connection.cursor() as cursor:
          ...     cursor.execute(select_movies_query)
          ...     for movie in cursor.fetchmany(size=5):
          ...         print(movie)
          ...     cursor.fetchall()
          ...
          ('Avengers: Endgame (2019)', Decimal('858.8'))
          ('Titanic (1997)', Decimal('659.2'))
          ('The Dark Knight (2008)', Decimal('535.4'))
          ('Toy Story 4 (2019)', Decimal('434.9'))
          ('The Lion King (1994)', Decimal('423.6'))
          

          Вывод с .fetchmany() аналогичен тому, который вы получили, когда использовали предложение LIMIT. Вы могли заметить дополнительный вызов cursor.fetchall() в конце. Вы делаете это, чтобы очистить все оставшиеся результаты, которые не были прочитаны .fetchmany(). Перед выполнением любых других операторов в том же соединении необходимо очистить все непрочитанные результаты. В противном случае возникает исключение InternalError: Unread result (обнаружен непрочитанный результат).

          Обработка нескольких таблиц с помощью оператора JOIN

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

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

          >>> select_movies_query = """
          ... SELECT title, AVG(rating) as average_rating
          ... FROM ratings
          ... INNER JOIN movies
          ...     ON movies.id = ratings.movie_id
          ... GROUP BY movie_id
          ... ORDER BY average_rating DESC
          ... LIMIT 5
          ... """
          >>> with connection.cursor() as cursor:
          ...     cursor.execute(select_movies_query)
          ...     for movie in cursor.fetchall():
          ...         print(movie)
          ...
          ('Night of the Living Dead', Decimal('9.90000'))
          ('The Godfather', Decimal('9.90000'))
          ('Avengers: Endgame', Decimal('9.75000'))
          ('Eternal Sunshine of the Spotless Mind', Decimal('8.90000'))
          ('Beasts of No Nation', Decimal('8.70000'))
          

          Как показано выше, «’Night of the Living Dead» и «The Godfather» имеют самый высокий рейтинг в вашей базе данных online_movie_rating.

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

          >>> select_movies_query = """
          ... SELECT CONCAT(first_name, " ", last_name), COUNT(*) as num
          ... FROM reviewers
          ... INNER JOIN ratings
          ...     ON reviewers.id = ratings.reviewer_id
          ... GROUP BY reviewer_id
          ... ORDER BY num DESC
          ... LIMIT 1
          ... """
          >>> with connection.cursor() as cursor:
          ...     cursor.execute(select_movies_query)
          ...     for movie in cursor.fetchall():
          ...         print(movie)
          ...
          ('Mary Cooper', 4)
          

          Mary Cooper — самый частый рецензент в этой базе данных. Как видно выше, не имеет значения, насколько сложен запрос, потому что в конечном итоге он обрабатывается сервером MySQL. Ваш процесс выполнения запроса всегда останется прежним: передайте запрос в cursor.execute() и получите результаты с помощью .fetchall().

          Обновление и удаление записей из базы данных

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

          Команда UPDATE

          Одна из рецензентов в вашей базе данных, Amy Farah Fowler, сейчас замужем за Sheldon Cooper. Ее фамилия изменилась на Cooper, поэтому вам необходимо соответствующим образом обновить свою базу данных. Для обновления записей MySQL использует оператор UPDATE:

          update_query = """
          UPDATE
              reviewers
          SET
              last_name = "Cooper"
          WHERE
              first_name = "Amy"
          """
          with connection.cursor() as cursor:
              cursor.execute(update_query)
              connection.commit()
          

          Код передает запрос на обновление в cursor.execute(), а .commit() вносит необходимые изменения в таблицу reviewers.

          Примечание. В запросе UPDATE предложение WHERE помогает указать записи, которые необходимо обновить. Если вы не используете WHERE, все записи будут обновлены!

          Предположим, вам нужно предоставить возможность рецензентам изменять оценки. Рецензент предоставит три значения: movie_id, reviewer_id и новый rating. Код отобразит запись после выполнения указанной модификации.

          Предполагая, что movie_id = 18, reviewer_id = 15 и новый rating = 5.0, вы можете использовать следующие запросы MySQL для выполнения необходимых изменений:

          UPDATE
              ratings
          SET
              rating = 5.0
          WHERE
              movie_id = 18 AND reviewer_id = 15;
          
          SELECT *
          FROM ratings
          WHERE
              movie_id = 18 AND reviewer_id = 15;
          

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

          from getpass import getpass
          from mysql.connector import connect, Error
          
          movie_id = input("Enter movie id: ")
          reviewer_id = input("Enter reviewer id: ")
          new_rating = input("Enter new rating: ")
          update_query = """
          UPDATE
              ratings
          SET
              rating = "%s"
          WHERE
              movie_id = "%s" AND reviewer_id = "%s";
          
          SELECT *
          FROM ratings
          WHERE
              movie_id = "%s" AND reviewer_id = "%s"
          """ % (
              new_rating,
              movie_id,
              reviewer_id,
              movie_id,
              reviewer_id,
          )
          
          try:
              with connect(
                  host="localhost",
                  user=input("Enter username: "),
                  password=getpass("Enter password: "),
                  database="online_movie_rating",
              ) as connection:
                  with connection.cursor() as cursor:
                      for result in cursor.execute(update_query, multi=True):
                          if result.with_rows:
                              print(result.fetchall())
                      connection.commit()
          except Error as e:
              print(e)
          

          Сохраните этот код в файле с именем modify_ratings.py. В приведенном выше коде используются заполнители %s для вставки полученного ввода в строку update_query. Впервые в этом руководстве у вас есть несколько запросов внутри одной строки. Чтобы передать несколько запросов одному cursor.execute(), вам необходимо установить для множественного аргумента метода значение True.

          Если multi равно True, то cursor.execute() возвращает итератор. Каждый элемент в итераторе соответствует объекту курсора, который выполняет инструкцию, переданную в запросе. Приведенный выше код запускает цикл for на этом итераторе, а затем вызывает .fetchall() для каждого объекта курсора.

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

          Если для операции не был получен набор результатов, то .fetchall() вызывает исключение. Чтобы избежать этой ошибки, в приведенном выше коде вы используете свойство cursor.with_rows, которое указывает, создавала ли последняя выполненная операция строки.

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

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

          Например, если пользователь отправляет movie_id = 18, reviewer_id = 15 и новый рейтинг = 5.0 в качестве входных данных, то результат будет выглядеть следующим образом:

          $ python modify_ratings.py
          Enter movie id: 18
          Enter reviewer id: 15
          Enter new rating: 5.0
          Enter username: 
          Enter password:
          [(18, 15, Decimal('5.0'))]
          

          Рейтинг с movie_id = 18 и reviewer_id = 15 изменен на 5.0. Но если вы были хакером, вы могли бы отправить скрытую команду на входе:

          $ python modify_ratings.py
          Enter movie id: 18
          Enter reviewer id: 15"; UPDATE reviewers SET last_name = "A
          Enter new rating: 5.0
          Enter username: 
          Enter password:
          [(18, 15, Decimal('5.0'))]
          

          И снова выходные данные показывают, что указанный рейтинг был изменен на 5.0. Что изменилось?

          Хакер при вводе украл reviewer_id и сделал запрос на обновление reviewers, где записал "; UPDATE reviewers SET last_name = "A, что изменяет last_name всех записей в таблице reviewers на «A«. Вы можете увидеть это изменение, если распечатаете таблицу reviewers:

          >>> select_query = """
          ... SELECT first_name, last_name
          ... FROM reviewers
          ... """
          >>> with connection.cursor() as cursor:
          ...     cursor.execute(select_query)
          ...     for reviewer in cursor.fetchall():
          ...         print(reviewer)
          ...
          ('Chaitanya', 'A')
          ('Mary', 'A')
          ('John', 'A')
          ('Thomas', 'A')
          ('Penny', 'A')
          ('Mitchell', 'A')
          ('Wyatt', 'A')
          ('Andre', 'A')
          ('Sheldon', 'A')
          ('Kimbra', 'A')
          ('Kat', 'A')
          ('Bruce', 'A')
          ('Domingo', 'A')
          ('Rajesh', 'A')
          ('Ben', 'A')
          ('Mahinder', 'A')
          ('Akbar', 'A')
          ('Howard', 'A')
          ('Pinkie', 'A')
          ('Gurkaran', 'A')
          ('Amy', 'A')
          ('Marlon', 'A')
          

          Приведенный выше код отображает first_name и last_name для всех записей в таблице проверяющих. Атака с использованием SQL-инъекции повредила эту таблицу, изменив last_name всех записей на «A».

          Есть быстрое решение для предотвращения таких атак. Не добавляйте значения запроса, предоставленные пользователем, непосредственно в строку запроса. Вместо этого обновите файл modify_ratings.py скрипт для отправки этих значений запроса в качестве аргументов в .execute():

          from getpass import getpass
          from mysql.connector import connect, Error
          
          movie_id = input("Enter movie id: ")
          reviewer_id = input("Enter reviewer id: ")
          new_rating = input("Enter new rating: ")
          update_query = """
          UPDATE
              ratings
          SET
              rating = %s
          WHERE
              movie_id = %s AND reviewer_id = %s;
          
          SELECT *
          FROM ratings
          WHERE
              movie_id = %s AND reviewer_id = %s
          """
          val_tuple = (
              new_rating,
              movie_id,
              reviewer_id,
              movie_id,
              reviewer_id,
          )
          
          try:
              with connect(
                  host="localhost",
                  user=input("Enter username: "),
                  password=getpass("Enter password: "),
                  database="online_movie_rating",
              ) as connection:
                  with connection.cursor() as cursor:
                      for result in cursor.execute(update_query, val_tuple, multi=True):
                          if result.with_rows:
                              print(result.fetchall())
                      connection.commit()
          except Error as e:
              print(e)
          

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

          cursor.execute() проверяет, что значения в кортеже, полученном в качестве аргумента, имеют требуемый тип данных.

          Если пользователь попытается ввести какие-то проблемные символы, код вызовет исключение:

          $ python modify_ratings.py
          Enter movie id: 18
          Enter reviewer id: 15"; UPDATE reviewers SET last_name = "A
          Enter new rating: 5.0
          Enter username: 
          Enter password:
          1292 (22007): Truncated incorrect DOUBLE value: '15";
          UPDATE reviewers SET last_name = "A'
          

          cursor.execute() вызовет исключение, если обнаружит какие-либо нежелательные символы во вводе пользователем. Вы должны использовать этот подход всякий раз, когда вы включаете пользовательский ввод в запрос. Есть и другие способы предотвращения атак SQL-инъекций.

          Команда DELETE

          Удаление записей очень похоже на обновление записей. Вы используете оператор DELETE для удаления выбранных записей.

          Примечание. Удаление — необратимый процесс. Если вы не используете предложение WHERE, все записи из указанной таблицы будут удалены. Вам нужно будет снова запустить запрос INSERT INTO, чтобы вернуть удаленные записи.

          Рекомендуется сначала выполнить запрос SELECT с тем же фильтром, чтобы убедиться, что вы удаляете нужные записи. Например, чтобы удалить все оценки, полученные с помощью reviewer_id = 2, вы должны сначала запустить соответствующий запрос SELECT:

          >>> select_movies_query = """
          ... SELECT reviewer_id, movie_id FROM ratings
          ... WHERE reviewer_id = 2
          ... """
          >>> with connection.cursor() as cursor:
          ...     cursor.execute(select_movies_query)
          ...     for movie in cursor.fetchall():
          ...         print(movie)
          ...
          (2, 7)
          (2, 8)
          (2, 12)
          (2, 23)
          

          Приведенный выше фрагмент кода выводит reviewer_id и movie_id для записей в таблице рейтингов, где reviewer_id = 2. Убедившись, что это те записи, которые вам нужно удалить, вы можете запустить запрос DELETE с тем же фильтром:

          delete_query = "DELETE FROM ratings WHERE reviewer_id = 2"
          with connection.cursor() as cursor:
              cursor.execute(delete_query)
              connection.commit()
          

          С помощью этого запроса вы удаляете все оценки, данные рецензентом с reviewer_id = 2, из таблицы ratings.

          Другие способы соединения Python и MySQL

          В этом уроке вы познакомились с MySQL Connector/Python, который является официально рекомендуемым средством взаимодействия с базой данных MySQL из приложения Python. Есть еще два популярных способа:

          1. mysqlclient — это библиотека, которая является близким конкурентом официального коннектора и активно обновляется новыми функциями. Поскольку его ядро ​​написано на C, он имеет лучшую производительность, чем официальный коннектор на чистом Python. Большой недостаток в том, что его довольно сложно настроить и установить, особенно в Windows.
          2. MySQLdb — это устаревшее программное обеспечение, которое до сих пор используется в коммерческих приложениях. Он написан на C и работает быстрее, чем MySQL Connector / Python, но доступен только для Python 2.

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

          Object-relational mapping (ORM) — это метод, который позволяет вам запрашивать данные из базы данных и управлять ими напрямую, используя объектно-ориентированный язык. Библиотека ORM инкапсулирует код, необходимый для управления данными, что избавляет от необходимости использовать даже крошечный бит SQL. Вот самые популярные ORM Python для баз данных на основе SQL:

          1. SQLAlchemy — это ORM, который упрощает взаимодействие между Python и другими базами данных SQL. Вы можете создавать разные движки для разных баз данных, таких как MySQL, PostgreSQL, SQLite и т. Д. SQLAlchemy обычно используется вместе с библиотекой pandas для обеспечения полной функциональности обработки данных.
          2. peewee — это легкий и быстрый ORM, который можно быстро настроить. Это очень полезно, когда ваше взаимодействие с базой данных ограничивается извлечением нескольких записей. Например, если вам нужно скопировать выбранные записи из базы данных MySQL в файл CSV, тогда peewee может быть вашим лучшим выбором.
          3. Django ORM — одна из самых мощных функций Django, поставляемая вместе с веб-фреймворком Django. Он может взаимодействовать с различными базами данных, такими как SQLite, PostgreSQL и MySQL. Многие приложения на основе Django используют Django ORM для моделирования данных и базовых запросов, но часто переключаются на SQLAlchemy для более сложных требований.

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

          Заключение

          В этом уроке вы узнали, как использовать MySQL Connector/Python для интеграции базы данных MySQL с вашим приложением Python. Вы также увидели некоторые уникальные особенности базы данных MySQL, которые отличают ее от других баз данных SQL.

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

          Здесь вы узнали, как:

          • Подключить приложение Python к базе данных MySQL.
          • Перенести данные из базы данных MySQL в Python для дальнейшего анализа.
          • Выполнять SQL-запросы из вашего приложения Python.
          • Обрабатывать исключения при доступе к базе данных.
          • Предотвращать атаки SQL-инъекций на ваше приложение.

          Если вы заинтересованы,Python также имеет коннекторы для других СУБД, таких как MongoDB и PostgreSQL. Для получения дополнительной информации ознакомьтесь с учебными пособиями по базам данных Python.

          Источник

          ]]> https://chel-center.ru/python-yfc/2021/01/02/python-i-bazy-dannyh-mysql-prakticheskoe-vvedenie/feed/ 0