Анализ данных — PYTHON https://chel-center.ru/python-yfc курс молодого бойца Fri, 26 Feb 2021 06:16:25 +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 Python — идеальный инструмент для любой проблемы https://chel-center.ru/python-yfc/2019/09/29/python-idealnyj-instrument-dlya-ljuboj-problemy/ https://chel-center.ru/python-yfc/2019/09/29/python-idealnyj-instrument-dlya-ljuboj-problemy/#respond Sun, 29 Sep 2019 05:30:13 +0000 http://chel-center.ru/python-yfc/?p=102 Читать далее «Python — идеальный инструмент для любой проблемы»

]]>
Размышления о моей первой программе на Python.

Размышления это всегда помогающее (а иногда и развлекающее) занятие. Из ностальгических соображений, конечно, если можно испытывать ностальгию по чему-то, что было два года назад — я хочу поделиться моей программой на Python. Изначально я начал работать с Python, когда был ещё студентом и изучал аэрокосмическую технику. Используя Python, я хотел избежать работ с электронными таблицами. Тогда я ещё не подозревал, насколько хорошее решение я принял.

Моё изучение Python началось с книги «Автоматизация рутинных задач с помощью Python»  (в оригинале «Automate the Boring Stuff with Python») Эла Свейгарта. Великолепная приложение-ориентированная книга с простыми программами, которые делают полезные вещи. Когда я изучаю что-то новое, я ищу любую возможность использовать свои новые знания, поэтому я хотел найти проблему, которую я мог бы решить с помощью Python. Такой проблемой стал учебник для класса, который стоил 200 долларов. Мой персональный лимит для учебника около 20 долларов («Автоматизация рутинных задач с помощью Python» бесплатна в онлайне), поэтому я отказался даже арендовать эту книгу. Отчаявшись получить книгу к своему первому занятию, я заметил, что её можно получить в свободное пользование на неделю через Amazon, сделав новый аккаунт. Я получил книгу на одну неделю и смог выполнить своё первое учебное занятие. И пока я продолжал создавать новые аккаунты каждую неделю, я понимал, что мне нужно решение получше. Именно так я и решил создать своё первое приложение на Python.

Одной из многих полезных библиотек, описанных в «Автоматизация рутинных задач с помощью Python», являлась PyAutoGUI, которая позволяет контролировать мышь и клавиатуру через Python. Как говорится, «когда у тебя есть молоток, то каждая проблема выглядит как гвоздь», и это было идеальное описание моей ситуации. Python и PyAutoGUI позволили мне нажимать стрелки на клавиатуре и делать скриншоты, и я использовал обе эти возможности чтобы решить свою книжную проблему. Я написал свою первую программу, чтобы автоматически пролистать каждую страницу книги и сделать скриншот. В программе всего 10 строк кода, но я горжусь ими настолько же, насколько горжусь всем, что я сделал в аэрокосмической технике. Далее пример всего кода, что я написал:

import pyautogui
import time

# Sleep for 5 seconds to allow me to open book
time.sleep(5)

# Range can be changed depending on the number of pages
for i in range(1000):
# Turn page
     pyautogui.keyDown('right')
     pyautogui.keyUp('right')

# Take and save a screenshot
     pyautogui.screenshot('images/page_%d.pdf' % i)
     time.sleep(0.05)

Запустить программу очень просто (и я настаиваю каждому попробовать). Я сохранил скрипт как book_screenshot.py, затем переместился в командой строке в ту же директорию, где лежит этот файл, и ввёл:

python book_screenshot.py

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

Программа же сделает всё остальное, пролистав каждую страницу и сделав скриншот, который сохранится в pdf

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

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

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

С тех пор я сделал ещё пару сложных программ, но до сих пор с любовью вспоминаю свой первый скрипт!

Перевод статьи William Koehrsen: Python is the Perfect Tool for any Problem

]]>
https://chel-center.ru/python-yfc/2019/09/29/python-idealnyj-instrument-dlya-ljuboj-problemy/feed/ 0
Практикум №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
Как оформлять код https://chel-center.ru/python-yfc/2019/10/01/kak-oformlyat-kod/ https://chel-center.ru/python-yfc/2019/10/01/kak-oformlyat-kod/#respond Tue, 01 Oct 2019 01:35:18 +0000 http://chel-center.ru/python-yfc/?p=502 Читать далее «Как оформлять код»

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

PEP 8 (Python Enhancement Proposals, англ. или предложения по улучшению Python, рус.) создан на основе рекомендаций Гуидо ван Россума с добавлениями от Барри. Если где-то возникал конфликт, мы выбирали стиль Гуидо. И, конечно, этот PEP может быть неполным (фактически, он, наверное, никогда не будет закончен).

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

Это руководство о согласованности и единстве. Согласованность с этим руководством очень важна. Согласованность внутри одного проекта еще важнее. А согласованность внутри модуля или функции — самое важное. Но важно помнить, что иногда это руководство неприменимо, и понимать, когда можно отойти от рекомендаций. Когда вы сомневаетесь, просто посмотрите на другие примеры и решите, какой выглядит лучше.

Две причины для того, чтобы нарушить данные правила:

  1. Когда применение правила сделает код менее читаемым даже для того, кто привык читать код, который следует правилам.
  2. Чтобы писать в едином стиле с кодом, который уже есть в проекте и который нарушает правила (возможно, в силу исторических причин) — впрочем, это возможность переписать чужой код.

Внешний вид кода

Отступы

Используйте 4 пробела на каждый уровень отступа.

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

Правильно:

# Выровнено по открывающему разделителю
foo = long_function_name(var_one, var_two,
                         var_three, var_four)

# Больше отступов включено для отличения его от остальных
def long_function_name(
        var_one, var_two, var_three,
        var_four):
    print(var_one)

Неправильно:

# Аргументы на первой линии запрещены, если не используется вертикальное выравнивание
foo = long_function_name(var_one, var_two,
    var_three, var_four)

# Больше отступов требуется, для отличения его от остальных
def long_function_name(
    var_one, var_two, var_three,
    var_four):
    print(var_one)

Опционально:

# Нет необходимости в большем количестве отступов.
foo = long_function_name(
  var_one, var_two,
  var_three, var_four)

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

my_list = [
    1, 2, 3,
    4, 5, 6,
    ]
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
    )

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

my_list = [
    1, 2, 3,
    4, 5, 6,
]
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
)

Табуляция или пробелы?

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

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

Python 3 запрещает смешивание табуляции и пробелов в отступах.

Python 2 пытается преобразовать табуляцию в пробелы.

Когда вы вызываете интерпретатор Python 2 в командной строке с параметром -t, он выдает предупреждения (warnings) при использовании смешанного стиля в отступах, а запустив интерпретатор с параметром -tt, вы получите в этих местах ошибки (errors). Эти параметры очень рекомендуются!

Максимальная длина строки

Ограничьте длину строки максимум 79 символами.

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

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

Некоторые команды предпочитают большую длину строки. Для кода, поддерживающегося исключительно или преимущественно этой группой, в которой могут прийти к согласию по этому вопросу, нормально увеличение длины строки с 80 до 100 символов (фактически увеличивая максимальную длину до 99 символов), при условии, что комментарии и строки документации все еще будут 72 символа.

Стандартная библиотека Python консервативна и требует ограничения длины строки в 79 символов (а строк документации/комментариев в 72).

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

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

with open('/path/to/some/file/you/want/to/read') as file_1, \
        open('/path/to/some/file/being/written', 'w') as file_2:
    file_2.write(file_1.read())

Ещё один случай — assert.

Сделайте правильные отступы для перенесённой строки. Предпочтительнее вставить перенос строки после логического оператора, но не перед ним. Например:

class Rectangle(Blob):

    def __init__(self, width, height,
                 color='black', emphasis=None, highlight=0):
        if (width == 0 and height == 0 and
                color == 'red' and emphasis == 'strong' or
                highlight > 100):
            raise ValueError("sorry, you lose")
        if width == 0 and height == 0 and (color == 'red' or
                                           emphasis is None):
            raise ValueError("I don't think so -- values are %s, %s" %
                             (width, height))
        Blob.__init__(self, width, height,
                      color, emphasis, highlight)

Пустые строки

Отделяйте функции верхнего уровня и определения классов двумя пустыми строками.

Определения методов внутри класса разделяются одной пустой строкой.

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

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

Python расценивает символ control+L как незначащий (whitespace), и вы можете использовать его, потому что многие редакторы обрабатывают его как разрыв страницы — таким образом логические части в файле будут на разных страницах. Однако, не все редакторы распознают control+L и могут на его месте отображать другой символ.

Кодировка исходного файла

Кодировка Python должна быть UTF-8 (ASCII в Python 2).

Файлы в ASCII (Python 2) или UTF-8 (Python 3) не должны иметь объявления кодировки.

В стандартной библиотеке, нестандартные кодировки должны использоваться только для целей тестирования, либо когда комментарий или строка документации требует упомянуть имя автора, содержащего не ASCII символы; в остальных случаях использование \x, \u, \U или \N — наиболее предпочтительный способ включить не ASCII символы в строковых литералах.

Начиная с версии python 3.0 в стандартной библиотеке действует следующее соглашение: все идентификаторы обязаны содержать только ASCII символы, и означать английские слова везде, где это возможно (во многих случаях используются сокращения или неанглийские технические термины). Кроме того, строки и комментарии тоже должны содержать лишь ASCII символы. Исключения составляют: (а) test case, тестирующий не-ASCII особенности программы, и (б) имена авторов. Авторы, чьи имена основаны не на латинском алфавите, должны транслитерировать свои имена в латиницу.

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

Импорты

  • Каждый импорт, как правило, должен быть на отдельной строке.

    Правильно:

    import os
    import sys

    Неправильно:

    import sys, os

    В то же время, можно писать так:

    from subprocess import Popen, PIPE
  • Импорты всегда помещаются в начале файла, сразу после комментариев к модулю и строк документации, и перед объявлением констант.

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

    1. импорты из стандартной библиотеки
    2. импорты сторонних библиотек
    3. импорты модулей текущего проекта

    Вставляйте пустую строку между каждой группой импортов.

    Указывайте спецификации __all__ после импортов.

  • Рекомендуется абсолютное импортирование, так как оно обычно более читаемо и ведет себя лучше (или, по крайней мере, даёт понятные сообщения об ошибках) если импортируемая система настроена неправильно (например, когда каталог внутри пакета заканчивается на sys.path):

    import mypkg.sibling
    from mypkg import sibling
    from mypkg.sibling import example

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

    from . import sibling
    from .sibling import example

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

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

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

    from myclass import MyClass
    from foo.bar.yourclass import YourClass

    Если такое написание вызывает конфликт имен, тогда пишите:

    import myclass
    import foo.bar.yourclass

    И используйте «myclass.MyClass» и «foo.bar.yourclass.YourClass».

  • Шаблоны импортов (from import *) следует избегать, так как они делают неясным то, какие имена присутствуют в глобальном пространстве имён, что вводит в заблуждение как читателей, так и многие автоматизированные средства. Существует один оправданный пример использования шаблона импорта, который заключается в опубликовании внутреннего интерфейса как часть общественного API (например, переписав реализацию на чистом Python в модуле акселератора (и не будет заранее известно, какие именно функции будут перезаписаны).

Пробелы в выражениях и инструкциях

Избегайте использования пробелов в следующих ситуациях:

  • Непосредственно внутри круглых, квадратных или фигурных скобок.

    Правильно:

    spam(ham[1], {eggs: 2})

    Неправильно:

    spam( ham[ 1 ], { eggs: 2 } )
  • Непосредственно перед запятой, точкой с запятой или двоеточием:

    Правильно:

    if x == 4: print(x, y); x, y = y, x

    Неправильно:

    if x == 4 : print(x , y) ; x , y = y , x
  • Сразу перед открывающей скобкой, после которой начинается список аргументов при вызове функции:

    Правильно:

    spam(1)

    Неправильно:

    spam (1)
  • Сразу перед открывающей скобкой, после которой следует индекс или срез:

    Правильно:

    dict['key'] = list[index]

    Неправильно:

    dict ['key'] = list [index]
  • Использование более одного пробела вокруг оператора присваивания (или любого другого) для того, чтобы выровнять его с другим:

    Правильно:

    x = 1
    y = 2
    long_variable = 3

    Неправильно:

    x             = 1
    y             = 2
    long_variable = 3

Другие рекомендации

  • Всегда окружайте эти бинарные операторы одним пробелом с каждой стороны: присваивания (=, +=, -= и другие), сравнения (==, <, >, !=, <>, <=, >=, in, not in, is, is not), логические (and, or, not).
  • Если используются операторы с разными приоритетами, попробуйте добавить пробелы вокруг операторов с самым низким приоритетом. Используйте свои собственные суждения, однако, никогда не используйте более одного пробела, и всегда используйте одинаковое количество пробелов по обе стороны бинарного оператора.

    Правильно:

    i = i + 1
    submitted += 1
    x = x*2 - 1
    hypot2 = x*x + y*y
    c = (a+b) * (a-b)

    Неправильно:

    i=i+1
    submitted +=1
    x = x * 2 - 1
    hypot2 = x * x + y * y
    c = (a + b) * (a - b)
  • Не используйте пробелы вокруг знака =, если он используется для обозначения именованного аргумента или значения параметров по умолчанию.

    Правильно:

    def complex(real, imag=0.0):
        return magic(r=real, i=imag)

    Неправильно:

    def complex(real, imag = 0.0):
        return magic(r = real, i = imag)
  • Не используйте составные инструкции (несколько команд в одной строке).

    Правильно:

    if foo == 'blah':
        do_blah_thing()
    do_one()
    do_two()
    do_three()

    Неправильно:

    if foo == 'blah': do_blah_thing()
    do_one(); do_two(); do_three()
  • Иногда можно писать тело циклов while, for или ветку if в той же строке, если команда короткая, но если команд несколько, никогда так не пишите. А также избегайте длинных строк!

    Точно неправильно:

    if foo == 'blah': do_blah_thing()
    for x in lst: total += x
    while t < 10: t = delay()

    Вероятно, неправильно:

    if foo == 'blah': do_blah_thing()
    else: do_non_blah_thing()
    
    try: something()
    finally: cleanup()
    
    do_one(); do_two(); do_three(long, argument,
                                 list, like, this)
    
    if foo == 'blah': one(); two(); three()

Комментарии

Комментарии, противоречащие коду, хуже, чем отсутствие комментариев. Всегда исправляйте комментарии, если меняете код!

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

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

Ставьте два пробела после точки в конце предложения.

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

Блоки комментариев

Блок комментариев обычно объясняет код (весь, или только некоторую часть), идущий после блока, и должен иметь тот же отступ, что и сам код. Каждая строчка такого блока должна начинаться с символа # и одного пробела после него (если только сам текст комментария не имеет отступа).

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

«Встрочные» комментарии

Старайтесь реже использовать подобные комментарии.

Такой комментарий находится в той же строке, что и инструкция. «Встрочные» комментарии должны отделяться по крайней мере двумя пробелами от инструкции. Они должны начинаться с символа # и одного пробела.

Комментарии в строке с кодом не нужны и только отвлекают от чтения, если они объясняют очевидное. Не пишите вот так:

x = x + 1                 # Increment x

Впрочем, такие комментарии иногда полезны:

x = x + 1                 # Компенсация границы

Строки документации

  • Пишите документацию для всех публичных модулей, функций, классов, методов. Строки документации необязательны для приватных методов, но лучше написать, что делает метод. Комментарий нужно писать после строки с def.
  • PEP 257 объясняет, как правильно и хорошо документировать. Заметьте, очень важно, чтобы закрывающие кавычки стояли на отдельной строке. А еще лучше, если перед ними будет ещё и пустая строка, например:

    """Return a foobang
    
    Optional plotz says to frobnicate the bizbaz first.
    
    """
  • Для однострочной документации можно оставить закрывающие кавычки на той же строке.

Контроль версий

Если вам нужно использовать Subversion, CVS или RCS в ваших исходных кодах, делайте вот так:

__version__ = "$Revision: 1a40d4eaa00b $"
# $Source$

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

Соглашения по именованию

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

Главный принцип

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

Описание: Стили имен

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

Обычно различают следующие стили:

  • b (одиночная маленькая буква)
  • B (одиночная заглавная буква)
  • lowercase (слово в нижнем регистре)
  • lower_case_with_underscores (слова из маленьких букв с подчеркиваниями)
  • UPPERCASE (заглавные буквы)
  • UPPERCASE_WITH_UNDERSCORES (слова из заглавных букв с подчеркиваниями)
  • CapitalizedWords (слова с заглавными буквами, или CapWords, или CamelCase). Замечание: когда вы используете аббревиатуры в таком стиле, пишите все буквы аббревиатуры заглавными — HTTPServerError лучше, чем HttpServerError.
  • mixedCase (отличается от CapitalizedWords тем, что первое слово начинается с маленькой буквы)
  • Capitalized_Words_With_Underscores (слова с заглавными буквами и подчеркиваниями — уродливо!)

Ещё существует стиль, в котором имена, принадлежащие одной логической группе, имеют один короткий префикс. Этот стиль редко используется в python, но мы упоминаем его для полноты. Например, функция os.stat() возвращает кортеж, имена в котором традиционно имеют вид st_mode, st_size, st_mtime и так далее. (Так сделано, чтобы подчеркнуть соответствие этих полей структуре системных вызовов POSIX, что помогает знакомым с ней программистам).

В библиотеке X11 используется префикс Х для всех public-функций. В python этот стиль считается излишним, потому что перед полями и именами методов стоит имя объекта, а перед именами функций стоит имя модуля.

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

  • _single_leading_underscore: слабый индикатор того, что имя используется для внутренних нужд. Например, from M import * не будет импортировать объекты, чьи имена начинаются с символа подчеркивания.
  • single_trailing_underscore_: используется по соглашению для избежания конфликтов с ключевыми словами языка python, например:

    Tkinter.Toplevel(master, class_='ClassName')
  • __double_leading_underscore: изменяет имя атрибута класса, то есть в классе FooBar поле __boo становится _FooBar__boo.
  • __double_leading_and_trailing_underscore__ (двойное подчеркивание в начале и в конце имени): магические методы или атрибуты, которые находятся в пространствах имен, управляемых пользователем. Например, __init__, __import__ или __file__. Не изобретайте такие имена, используйте их только так, как написано в документации.

Предписания: соглашения по именованию

Имена, которых следует избегать

Никогда не используйте символы l (маленькая латинская буква «эль»), O (заглавная латинская буква «о») или I (заглавная латинская буква «ай») как однобуквенные идентификаторы.

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

Имена модулей и пакетов

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

Так как имена модулей отображаются в имена файлов, а некоторые файловые системы являются нечувствительными к регистру символов и обрезают длинные имена, очень важно использовать достаточно короткие имена модулей — это не проблема в Unix, но, возможно, код окажется непереносимым в старые версии Windows, Mac, или DOS.

Когда модуль расширения, написанный на С или C++, имеет сопутствующий python-модуль (содержащий интерфейс высокого уровня), С/С++ модуль начинается с символа подчеркивания, например, _socket.

Имена классов

Имена классов должны обычно следовать соглашению CapWords.

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

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

Имена исключений

Так как исключения являются классами, к исключениями применяется стиль именования классов. Однако вы можете добавить Error в конце имени (если, конечно, исключение действительно является ошибкой).

Имена глобальных переменных

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

Добавляйте в модули, которые написаны так, чтобы их использовали с помощью from M import *, механизм __all__, чтобы предотвратить экспортирование глобальных переменных. Или же, используйте старое соглашение, добавляя перед именами таких глобальных переменных один символ подчеркивания (которым вы можете обозначить те глобальные переменные, которые используются только внутри модуля).

Имена функций

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

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

Аргументы функций и методов

Всегда используйте self в качестве первого аргумента метода экземпляра объекта.

Всегда используйте cls в качестве первого аргумента метода класса.

Если имя аргумента конфликтует с зарезервированным ключевым словом python, обычно лучше добавить в конец имени символ подчеркивания, чем исказить написание слова или использовать аббревиатуру. Таким образом, class_ лучше, чем clss. (Возможно, хорошим вариантом будет подобрать синоним).

Имена методов и переменных экземпляров классов

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

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

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

Python искажает эти имена: если класс Foo имеет атрибут с именем __a, он не может быть доступен как Foo.__a. (Настойчивый пользователь все еще может получить доступ, вызвав Foo._Foo__a.) Вообще, два ведущих подчеркивания должны использоваться только для того, чтобы избежать конфликтов имен с атрибутами классов, предназначенных для наследования.

Примечание: есть некоторые разногласия по поводу использования __ имена (см. ниже).

Константы

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

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

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

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

Мы не используем термин «приватный атрибут», потому что на самом деле в python таких не бывает.

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

Теперь сформулируем рекомендации:

  • Открытые атрибуты не должны иметь в начале имени символа подчеркивания.
  • Если имя открытого атрибута конфликтует с ключевым словом языка, добавьте в конец имени один символ подчеркивания. Это более предпочтительно, чем аббревиатура или искажение написания (однако, у этого правила есть исключение — аргумента, который означает класс, и особенно первый аргумент метода класса (class method) должен иметь имя cls).
  • Назовите простые публичные атрибуты понятными именами и не пишите сложные методы доступа и изменения (accessor/mutator, get/set, — прим. перев.) Помните, что в python очень легко добавить их потом, если потребуется. В этом случае используйте свойства (properties), чтобы скрыть функциональную реализацию за синтаксисом доступа к атрибутам.

    Примечание 1: Свойства (properties) работают только в классах нового стиля (в Python 3 все классы являются таковыми).

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

    Примечание 3: Избегайте использования вычислительно затратных операций, потому что из-за записи с помощью атрибутов создается впечатление, что доступ происходит (относительно) быстро.

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

    Примечание 1: Будьте внимательны: если подкласс будет иметь то же имя класса и имя атрибута, то вновь возникнет конфликт имен.

    Примечание 2: Механизм изменения имен может затруднить отладку или работу с __getattr__(), однако он хорошо документирован и легко реализуется вручную.

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

Общие рекомендации

  • Код должен быть написан так, чтобы не зависеть от разных реализаций языка (PyPy, Jython, IronPython, Pyrex, Psyco и пр.).

    Например, не полагайтесь на эффективную реализацию в CPython конкатенации строк в выражениях типа a+=b или a=a+b. Такие инструкции выполняются значительно медленнее в Jython. В критичных к времени выполнения частях программы используйте ».join() — таким образом склеивание строк будет выполнено за линейное время независимо от реализации python.

  • Сравнения с None должны обязательно выполняться с использованием операторов is или is not, а не с помощью операторов сравнения. Кроме того, не пишите if x, если имеете в виду if x is not None — если, к примеру, при тестировании такая переменная может принять значение другого типа, отличного от None, но при приведении типов может получиться False!
  • При реализации методов сравнения, лучше всего реализовать все 6 операций сравнения (__eq__, __ne__, __lt__, __le__, __gt__, __ge__), чем полагаться на то, что другие программисты будут использовать только конкретный вид сравнения.

    Для минимизации усилий можно воспользоваться декоратором functools.total_ordering() для реализации недостающих методов.

    PEP 207 указывает, что интерпретатор может поменять y > х на х < y, y >= х на х <= y, и может поменять местами аргументы х == y и х != y. Гарантируется, что операции sort() и min() используют оператор <, а max() использует оператор >. Однако, лучше всего осуществить все шесть операций, чтобы не возникало путаницы в других местах.

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

    Правильно:

    def f(x): return 2*x

    Неправильно:

    f = lambda x: 2*x
  • Наследуйте свой класс исключения от Exception, а не от BaseException. Прямое наследование от BaseException зарезервировано для исключений, которые не следует перехватывать.
  • Используйте цепочки исключений соответствующим образом. В Python 3, «raise X from Y» следует использовать для указания явной замены без потери отладочной информации.

    Когда намеренно заменяется исключение (использование «raise X» в Python 2 или «raise X from None» в Python 3.3+), проследите, чтобы соответствующая информация передалась в новое исключение (такие, как сохранение имени атрибута при преобразовании KeyError в AttributeError или вложение текста исходного исключения в новом).

  • Когда вы генерируете исключение, пишите raise ValueError(‘message’) вместо старого синтаксиса raise ValueError, message.

    Старая форма записи запрещена в python 3.

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

  • Когда код перехватывает исключения, перехватывайте конкретные ошибки вместо простого выражения except:.

    К примеру, пишите вот так:

    try:
        import platform_specific_module
    except ImportError:
        platform_specific_module = None

    Простое написание «except:» также перехватит и SystemExit, и KeyboardInterrupt, что породит проблемы, например, сложнее будет завершить программу нажатием control+C. Если вы действительно собираетесь перехватить все исключения, пишите «except Exception:».

    Хорошим правилом является ограничение использования «except:», кроме двух случаев:

    1. Если обработчик выводит пользователю всё о случившейся ошибке; по крайней мере, пользователь будет знать, что произошла ошибка.
    2. Если нужно выполнить некоторый код после перехвата исключения, а потом вновь «бросить» его для обработки где-то в другом месте. Обычно же лучше пользоваться конструкцией «try…finally».
  • При связывании перехваченных исключений с именем, предпочитайте явный синтаксис привязки, добавленный в Python 2.6:

    try:
        process_data()
    except Exception as exc:
        raise DataProcessingFailedError(str(exc))

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

  • При перехвате ошибок операционной системы, предпочитайте использовать явную иерархию исключений, введенную в Python 3.3, вместо анализа значений errno.
  • Постарайтесь заключать в каждую конструкцию try…except минимум кода, чтобы легче отлавливать ошибки. Опять же, это позволяет избежать замаскированных ошибок.

    Правильно:

    try:
        value = collection[key]
    except KeyError:
        return key_not_found(key)
    else:
        return handle_value(value)

    Неправильно:

    try:
        # Здесь много действий!
        return handle_value(collection[key])
    except KeyError:
        # Здесь также перехватится KeyError, который может быть сгенерирован handle_value()
        return key_not_found(key)
  • Когда ресурс является локальным на участке кода, используйте выражение with для того, чтобы после выполнения он был очищен оперативно и надёжно.
  • Менеджеры контекста следует вызывать с помощью отдельной функции или метода, всякий раз, когда они делают что-то другое, чем получение и освобождение ресурсов. Например:

    Правильно:

    with conn.begin_transaction():
        do_stuff_in_transaction(conn)

    Неправильно:

    with conn:
        do_stuff_in_transaction(conn)

    Последний пример не дает никакой информации, указывающей на то, что __enter__ и __exit__ делают что-то кроме закрытия соединения после транзакции. Быть явным важно в данном случае.

  • Используйте строковые методы вместо модуля string — они всегда быстрее и имеют тот же API для unicode-строк. Можно отказаться от этого правила, если необходима совместимость с версиями python младше 2.0.

    В Python 3 остались только строковые методы.

  • Пользуйтесь ».startswith() и ».endswith() вместо обработки срезов строк для проверки суффиксов или префиксов.

    startswith() и endswith() выглядят чище и порождают меньше ошибок. Например:

    Правильно:

    if foo.startswith('bar'):

    Неправильно:

    if foo[:3] == 'bar':
  • Сравнение типов объектов нужно делать с помощью isinstance(), а не прямым сравнением типов:

    Правильно:

    if isinstance(obj, int):

    Неправильно:

    if type(obj) is type(1):

    Когда вы проверяете, является ли объект строкой, обратите внимание на то, что строка может быть unicode-строкой. В python 2 у str и unicode есть общий базовый класс, поэтому вы можете написать:

    if isinstance(obj, basestring):

    Отметим, что в Python 3, unicode и basestring больше не существуют (есть только str) и bytes больше не является своего рода строкой (это последовательность целых чисел).

  • Для последовательностей (строк, списков, кортежей) используйте тот факт, что пустая последовательность есть false:

    Правильно:

    if not seq:
    if seq:

    Неправильно:

    if len(seq)
    if not len(seq)
  • Не пользуйтесь строковыми константами, которые имеют важные пробелы в конце — они невидимы, а многие редакторы (а теперь и reindent.py) обрезают их.
  • Не сравнивайте логические типы с True и False с помощью ==:

    Правильно:

    if greeting:

    Неправильно:

    if greeting == True:

    Совсем неправильно:

    if greeting is True:
  • Оригинал

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

    В самом начале скрипта с кодом Python необходимо указывать следующие атрибуты:

    #имя проекта: numpy-example
    #номер версии: 1.0
    #имя файла: example_2.py
    #автор и его учебная группа: Е. Волков, ЭУ-142
    #дата создания: 20.03.2019
    #дата последней модификации: 25.03.2019
    #связанные файлы: пакеты numpy, matplotlib
    #описание: простейшие статистические вычисления
    #версия Python: 3.6
    ]]> https://chel-center.ru/python-yfc/2019/10/01/kak-oformlyat-kod/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
    10 полезных библиотек Python https://chel-center.ru/python-yfc/2019/10/01/10-poleznyh-bibliotek-python/ https://chel-center.ru/python-yfc/2019/10/01/10-poleznyh-bibliotek-python/#respond Tue, 01 Oct 2019 01:55:49 +0000 http://chel-center.ru/python-yfc/?p=37 Читать далее «10 полезных библиотек Python»

    ]]>
    Пакетов для Python создано уже очень много, поэтому ни один человек физически не может изучить их все. Только PyPi насчитывает 47 000 пакетов. В то время как pandas, scikit-learn или numpy у многих на слуху, про перечисленные здесь — уже достаточно старые, но всё ещё полезные — библиотеки часто забывают.

    Delorean

    Это – отличная библиотека для работы с датами и временем. Работа с временем с помощью неё в Python мне кажется наиболее естественной. Delorean чем-то похожа на Moment.js. Так же стоит отметить отличную документацию и бесчисленное количество отсылок к «Назад в будущее».

    from delorean import Delorean
    EST = "US/Eastern"
    d = Delorean(timezone=EST)
    
    Назад в будущее
    Назад в будущее

    Prettytable

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

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

    from prettytable import PrettyTable
    table = PrettyTable(["животное", "свирепость"])
    table.add_row(["Оборотень", 100])
    table.add_row(["Гризли", 87])
    table.add_row(["Кролик из Кэрбенног", 110])
    table.add_row(["Кот", -1])
    table.add_row(["Утконос", 23])
    table.add_row(["Дельфин", 63])
    table.add_row(["Альбатрос", 44])
    table.sort_key("свирепость")
    table.reversesort = True
    +----------------------+------------+
    |       животное       | свирепость |
    +----------------------+------------+
    | Кролик из Кэрбенног |   110      |
    |      Оборотень       |   100      |
    |        Гризли        |    87      |
    |       Дельфин        |    63      |
    |       Альбатрос      |    44      |
    |        Утконос       |    23      |
    |         Кот          |    -1      |
    +----------------------+------------+
    

    Snowballstemmer

    Ладно, признаюсь, первый раз я установил snowballstemmer из-за крутого названия. Но оказалось, что это действительно очень удобная маленькая библиотечка. Она содержит алгоритмы стемминга для 15 языков (включая русский).

    from snowballstemmer import EnglishStemmer, SpanishStemmer
    EnglishStemmer().stemWord("Gregory")
    # Gregori
    SpanishStemmer().stemWord("amarillo")
    # amarill
    

    Wget

    Наверняка вам ни раз приходилось писать методы для какой-то специфической работы с вебом. Но я вас огорчу – вы делали это зря. Ведь уже есть wget. Рекурсивно скачать сайт? Забрать со страницы все изображения? Для wget это не проблема.

    import wget
    wget.download("http://www.cnn.com/")
    # 100% [............................................................................] 280385 / 280385
    

    PyMC

    А эта библиотека предназначена для Байесовского анализа. По непонятным причинам эта библиотека используется гораздо реже, чем scikit-learn, а ведь очень зря.

    from pymc.examples import disaster_model
    from pymc import MCMC
    M = MCMC(disaster_model)
    M.sample(iter=10000, burn=1000, thin=10)
    [-----------------100%-----------------] 10000 of 10000 complete in 1.4 sec
    
    

    Sh

    Я не могу себе позволить, чтобы вы ушли с этой страницы, не зная о sh. Как можно догадаться, sh импортирует в Python команды shell в виде функций. Это – суперудобная возможность, когда вы помните, как сделать что-то с помощью bash, но не помните, как это реализуется на Python (например, рекурсивный поиск по файлам).

    from sh import find
    find("/tmp")
    /tmp/foo
    /tmp/foo/file1.json
    /tmp/foo/file2.json
    /tmp/foo/file3.json
    /tmp/foo/bar/file3.json
    

    Fuzzywuzzy

    Эта библиотека добавляет классных фич для сравнения данных. Может быть использована для связи записей в различных базах данных.

    from fuzzywuzzy import fuzz
    fuzz.ratio("Hit me with your best shot", "Hit me with your pet shark")
    # 85
    

    Progressbar

    Да, да, эта библиотека делает именно то, о чём вы подумали – выводит прогрессбар.

    from progressbar import ProgressBar
    import time
    pbar = ProgressBar(maxval=10)
    for i in range(1, 11):
        pbar.update(i)
        time.sleep(1)
    pbar.finish()
    # 60% |########################################################                                      |
    

    Colorama

    Если уж вы занимаетесь добавление прогрессбаров в свои программы, то, может, стоит добавить ещё немного цвета? Справиться с этим вам поможет Colorama.

    Сolorama
    Сolorama

    Uuid

    Наверняка вам приходилось генерировать для пользователей ID, или рассылать покупателям промокоды, или делать ещё что-то, где нужно создать уникальные последовательности. UUID вам в этом поможет:

    import uuid
    print uuid.uuid4()
    # e7bafa3d-274e-4b0a-b9cc-d898957b4b61
    

    И если вы переживаете, что ID кончатся, то не стоит: их количество сравнимо с количеством атомов во вселенной.

    Источник: blog.yhat.com

    ]]>
    https://chel-center.ru/python-yfc/2019/10/01/10-poleznyh-bibliotek-python/feed/ 0
    5 ключевых библиотек и пакетов для анализа данных на Python https://chel-center.ru/python-yfc/2019/10/01/5-klyuchevyih-bibliotek-i-paketov-dlya-analiza-dannyih-na-python/ https://chel-center.ru/python-yfc/2019/10/01/5-klyuchevyih-bibliotek-i-paketov-dlya-analiza-dannyih-na-python/#respond Tue, 01 Oct 2019 02:28:02 +0000 http://waksoft.susu.ru/?p=26432 Читать далее «5 ключевых библиотек и пакетов для анализа данных на Python»

    ]]>
    Не все знают, что Python не задумывался создателями как язык для анализа данных. Однако сегодня это один из самых лучших языков для статистики, машинного обучения, прогнозной аналитики, а также стандартных задач по обработке данных. Python — язык с открытым кодом, и специалисты по data science стали создавать инструменты, чтобы более эффективно выполнять свои задачи. Сайт DEV.BY со ссылкой на ресурс Data36 опубликовал пять сторонних библиотек и пакетов, не встроенных в Python 3, которые должен знать каждый аналитик.

    NumPy

    NumPy позволяет очень эффективно обрабатывать многомерные массивы. Многие другие библиотеки построены на NumPy, и без неё было бы невозможно использовать pandas, Matplotlib, SciPy или scikit‑learn — именно поэтому она занимает первое место в списке.

    >
    Трёхмерный массив в NumPy. Источник: Data36

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

    >
    Прогнозирование с использованием функции polyfit. Источник: Data36

    pandas

    Аналитики данных обычно используют плоские таблицы, такие, как в SQL и Excel. Изначально в Python такой возможности не было. Библиотека pandas позволяет работать с двухмерными таблицами на Python.

    Таблица в pandas. Источник: Data36

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

    Matplotlib

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

    Пример визуализации данных в Matplotlib. Источник: Data36

    scikit‑learn

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

    Простая классификация с использованием модели «случайный лес» в scikit‑learn. Источник: Data36

    Машинное обучение в scikit‑learn заключается в том, чтобы импортировать правильные модули и запустить метод подбора модели. Сложнее вычистить, отформатировать и подготовить данные, а также подобрать оптимальные входные значения и модели. Поэтому прежде чем взяться за scikit‑learn, нужно, во-первых, отработать навыки работы с Python и pandas, чтобы научиться качественно подготавливать данные, а во-вторых, освоить теорию и математическую основу различных моделей прогнозирования и классификации, чтобы понимать, что происходит с данными при их применении.

    SciPy

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

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

    Другие библиотеки и пакеты для обработки и анализа данных

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

    Как начать пользоваться библиотеками pandas, NumPy, Matplotlib, scikit‑learn и SciPy

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

    1. Подключиться к серверу
    2. Установить NumPy, используя команду
      >sudo -H pip3 install numpy
    3. Установить pandas, используя команду
      sudo apt-get install python3-pandas
    4. Обновить дополнительные инструменты pandas с помощью двух команд:
      sudo -H pip3 install —upgrade beautifulsoup4 и
      sudo -H pip3 install —upgrade html5lib
    5. Установить scikit‑learn, используя команду
      sudo -H pip3 install scikit‑learn

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

    import numpy as np
    import pandas as pd
    import matplotlib
    matplotlib.use(‘Agg’)
    import matplotlib.pyplot as plt
    %matplotlib inline
    from sklearn.linear_model import LinearRegression

    После этого можно протестировать pandas и Matplotlib вместе, запустив вот эти строки:

    df = pd.DataFrame({‘a’:[1,2,3,4,5,6,7],
    ‘b’:[1,4,9,16,25,36,49]})
    df.plot()
    Источник: Data36

    Использованы материалы: dev.by

    ]]>
    https://chel-center.ru/python-yfc/2019/10/01/5-klyuchevyih-bibliotek-i-paketov-dlya-analiza-dannyih-na-python/feed/ 0
    Нескучный NumPy https://chel-center.ru/python-yfc/2019/10/01/neskuchnyj-numpy/ https://chel-center.ru/python-yfc/2019/10/01/neskuchnyj-numpy/#respond Tue, 01 Oct 2019 02:29:31 +0000 http://chel-center.ru/python-yfc/?p=29028 Читать далее «Нескучный NumPy»

    ]]>

    Содержание

    Что такое NumPy?

    Это библиотека с открытым исходным кодом, некогда отделившаяся от проекта SciPy. NumPy является наследником Numeric и NumArray. Основан NumPy на библиотеке LAPAC, которая написана на Fortran. Не-python альтернативой для NumPy является Matlab.

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

    Кроме базового варианта (многомерные массивы в базовом варианте) NumPy включает в себя набор пакетов для решения специализированных задач, например:

    • numpy.linalg — реализует операции линейной алгебры (простое умножение векторов и матриц есть в базовом варианте);
    • numpy.random — реализует функции для работы со случайными величинами;
    • numpy.fft — реализует прямое и обратное преобразование Фурье.

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

    Но, прежде чем продолжить чтение этой статьи загрузите IDLE Python, где в режиме интерактивного интерпретатора повторяйте приведённые здесь скрипы и «в живую» смотрите на результат их выполнения. Но, не забудьте в начале сеанса записать:

    import numpy
    

    Создание массива

    Создать массив можно несколькими способами:

    1. преобразовать список в массив:
      A = np.array([ [1, 2, 3], [4, 5, 6] ])
      A
      Out:
      array([ [1, 2, 3],
             [4, 5, 6] ])
      
    2. скопировать массив (копия и глубокая копия обязательна!!!):
      B = A.copy()
      B
      Out:
      array([ [1, 2, 3],
             [4, 5, 6] ])
      
    3. создать нулевой или единичный массив заданного размера:
      A = np.zeros((2, 3))
      A
      Out:
      array([ [0., 0., 0.],
             [0., 0., 0.] ])
      B = np.ones((3, 2))
      B
      Out:
      array([ [1., 1.],
             [1., 1.],
             [1., 1.] ])
      
      B = np.ones((3, 2))
      B
      Out:
      array([ [1., 1.],
             [1., 1.],
             [1., 1.] ])
      

      Либо взять размеры уже существующего массива:

      A = np.array([ [1, 2, 3], [4, 5, 6] ])
      B = np.zeros_like(A)
      B
      Out:
      array([ [0, 0, 0],
             [0, 0, 0] ])
      
      A = np.array([ [1, 2, 3], [4, 5, 6] ])
      B = np.ones_like(A)
      B
      Out:
      array([ [1, 1, 1],
             [1, 1, 1] ])
      
    4. при создании двумерного квадратного массива можете сделать его единичной диагональной матрицей:
      A = np.eye(3)
      A
      Out:
      array([ [1., 0., 0.],
             [0., 1., 0.],
             [0., 0., 1.] ])
      
    5. построить массив чисел от From (включая) до To (не включая) с шагом Step:
      From = 2.5
      To = 7
      Step = 0.5
      A = np.arange(From, To, Step)
      A
      Out:
      array([2.5, 3. , 3.5, 4. , 4.5, 5. , 5.5, 6. , 6.5])
      

      По умолчанию from = 0, step = 1, поэтому возможен вариант с одним параметром, интерпретируемым как To:

      A = np.arange(5)
      A
      Out:
      array([0, 1, 2, 3, 4])
      

      Либо с двумя — как From и To:

      A = np.arange(10, 15)
      A
      Out:
      array([10, 11, 12, 13, 14])
      

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

    A = np.zeros((2, 3), 'int')
    A
    Out:
    array([ [0, 0, 0],
           [0, 0, 0] ])
    
    B = np.ones((3, 2), 'complex')
    B
    Out:
    array([ [1.+0.j, 1.+0.j],
           [1.+0.j, 1.+0.j],
           [1.+0.j, 1.+0.j] ])
    

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

    A = np.ones((3, 2))
    B = A.astype('str')
    B
    Out:
    array([ ['1.0', '1.0'],
           ['1.0', '1.0'],
           ['1.0', '1.0'] ], dtype='<U32')
    

    Все доступные типы можно найти в словаре sctypes:

    np.sctypes
    Out:
    {'int': [numpy.int8, numpy.int16, numpy.int32, numpy.int64],
     'uint': [numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64],
     'float': [numpy.float16, numpy.float32, numpy.float64, numpy.float128],
     'complex': [numpy.complex64, numpy.complex128, numpy.complex256],
     'others': [bool, object, bytes, str, numpy.void]}
    

     <наверх>

    Доступ к элементам, срезы

    Доступ к элементам массива осуществляется по целочисленным индексами, начинается отсчет с 0:

    A = np.array([ [1, 2, 3], [4, 5, 6] ])
    A[1, 1]
    Out:
    5
    

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

    A = np.array([ [1, 2, 3], [4, 5, 6] ])
    A[1]
    Out:
    array([4, 5, 6])
    

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

    A = np.array([ [1, 2, 3], [4, 5, 6] ])
    A[1][1]
    Out:
    5
    

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

    A = np.array([ [1, 2, 3], [4, 5, 6] ])
    A[1, :]
    Out:
    array([4, 5, 6])
    

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

    A = np.array([ [1, 2, 3], [4, 5, 6] ])
    A[:, 1]
    Out:
    array([2, 5])
    

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

    A = np.arange(5)
    print(A)
    A[-1]
    Out:
    [0 1 2 3 4]
    4
    

    Можно использовать не одиночные индексы, а списки индексов вдоль каждой оси:

    A = np.arange(5)
    print(A)
    A[ [0, 1, -1] ]
    Out:
    [0 1 2 3 4]
    array([0, 1, 4])
    

    Либо диапазоны индексов в виде «From:To:Step». Такая конструкция называется срезом. Выбираются все элементы по списку индексов начиная с индекса From включительно, до индекса To не включая с шагом Step:

    A = np.arange(5)
    print(A)
    A[0:4:2]
    Out:
    [0 1 2 3 4]
    array([0, 2])
    

    Шаг индекса имеет значение по умолчанию 1 и может быть пропущен:

    A = np.arange(5)
    print(A)
    A[0:4]
    Out:
    [0 1 2 3 4]
    array([0, 1, 2, 3])
    

    Значения From и To тоже имеют дефолтные значения: 0 и размер массива по оси индексации соответственно:

    A = np.arange(5)
    print(A)
    A[:4]
    Out:
    [0 1 2 3 4]
    array([0, 1, 2, 3])
    
    A = np.arange(5)
    print(A)
    A[-3:]
    Out:
    [0 1 2 3 4]
    array([2, 3, 4])
    

    Если вы хотите использовать From и To по умолчанию (все индексы по данной оси) а шаг отличный от 1, то вам необходимо использовать две пары двоеточий, чтобы интерпретатор смог идентифицировать единственный параметр как Step. Следующий код «разворачивает» массив вдоль второй оси, а вдоль первой не меняет:

    A = np.array([ [1, 2, 3], [4, 5, 6] ])
    B = A[:, ::-1]
    print("A", A)
    print("B", B)
    Out:
    A [ [1 2 3]
     [4 5 6] ]
    B [ [3 2 1]
     [6 5 4] ]
    

    А теперь выполним

    print(A)
    B[0, 0] = 0
    print(A)
    Out:
    [ [1 2 3]
     [4 5 6] ]
    [ [1 2 0]
     [4 5 6] ]
    

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

    A = np.array([ [1, 2, 3], [4, 5, 6] ])
    B = A.copy()[:, ::-1]
    print("A", A)
    print("B", B)
    Out:
    A [ [1 2 3]
     [4 5 6] ]
    B [ [3 2 1]
     [6 5 4] ]
    

    В NumPy также реализована возможность доступа ко множеству элементов массива через булев индексный массив. Индексный массив должен совпадать по форме с индексируемым.

    A = np.array([ [1, 2, 3], [4, 5, 6] ])
    I = np.array([ [False, False, True], [ True, False, True] ])
    A[I]
    Out:
    array([3, 4, 6])
    

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

    A = np.array([ [1, 2, 3], [4, 5, 6] ])
    I = np.array([ [False, False, True], [ True, False, True] ])
    A[I] = 0
    print(A)
    Out:
    [ [1 2 0]
     [0 5 0] ]
    

    Над индексирующими булевыми массивами определены логические операции logical_and, logical_or и logical_not выполняющие логические операции И, ИЛИ и НЕ поэлементно:

    A = np.array([ [1, 2, 3], [4, 5, 6] ])
    I1 = np.array([ [False, False, True], [True, False, True] ])
    I2 = np.array([ [False, True, False], [False, False, True] ])
    B = A.copy()
    C = A.copy()
    D = A.copy()
    B[np.logical_and(I1, I2)] = 0
    C[np.logical_or(I1, I2)] = 0
    D[np.logical_not(I1)] = 0
    print('B\n', B)
    print('\nC\n', C)
    print('\nD\n', D)
    Out:
    B
     [ [1 2 3]
     [4 5 0] ]
    C
     [ [1 0 0]
     [0 5 0] ]
    D
     [ [0 0 3]
     [4 0 6] ]
    

    logical_and и logical_or принимают 2 операнда, logical_not — один. Можно использовать операторы &, | и ~ для выполнения И, ИЛИ и НЕ соответственно с любым количеством операндов:

    A = np.array([ [1, 2, 3], [4, 5, 6] ])
    I1 = np.array([ [False, False, True], [True, False, True] ])
    I2 = np.array([ [False, True, False], [False, False, True] ])
    A[I1 & (I1 | ~ I2)] = 0
    print(A)
    Out:
    [ [1 2 0]
     [0 5 0] ]
    

    Что эквивалентно применению только I1.

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

    Найдем индексирующий массив I элементов, которые больше, чем 3, а элементы со значениями меньше чем 2 и больше 4 — обнулим:

    A = np.array([ [1, 2, 3], [4, 5, 6] ])
    print('A before\n', A)
    I = A > 3
    print('I\n', I)
    A[np.logical_or(A < 2, A > 4)] = 0
    print('A after\n', A)
    Out:
    A before
     [ [1 2 3]
     [4 5 6] ]
    I
     [ [False False False]
     [ True  True  True] ]
    A after
     [ [0 2 3]
     [4 0 0] ]
    

     <наверх>

    Форма массива и ее изменение

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

    Для наглядности рассмотрим пример:

    A = np.arange(24)
    B = A.reshape(4, 6)
    C = A.reshape(4, 3, 2)
    print('B\n', B)
    print('\nC\n', C)
    Out:
    B
     [ [ 0  1  2  3  4  5]
     [ 6  7  8  9 10 11]
     [12 13 14 15 16 17]
     [18 19 20 21 22 23] ]
    C
     [ [ [ 0  1]
      [ 2  3]
      [ 4  5] ]
     [ [ 6  7]
      [ 8  9]
      [10 11] ]
     [ [12 13]
      [14 15]
      [16 17] ]
     [ [18 19]
      [20 21]
      [22 23] ] ]
    

    В этом примере мы из одномерного массива длиной 24 элемента сформировали 2 новых массива. Массив B, размером 4 на 6. Если посмотреть на порядок значений, то видно, что вдоль второго измерения идут цепочки последовательных значений.

    В массиве C, размером 4 на 3 на 2, непрерывные значения идут вдоль последней оси. Вдоль второй оси идут последовательно блоки, объединение которых дало бы в результате строки вдоль второй оси массива B.

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

    Чтобы узнать размерность массива (количество осей), можно использовать поле ndim (число), а чтобы узнать размер вдоль каждой оси — shape (кортеж). Размерность можно также узнать и по длине shape. Чтобы узнать полное количество элементов в массиве можно воспользоваться значением size:

    A = np.arange(24)
    C = A.reshape(4, 3, 2)
    print(C.ndim, C.shape, len(C.shape), A.size)
    Out:
    3 (4, 3, 2) 3 24
    

    Обратите внимание, что ndim и shape — это атрибуты, а не методы!
    Чтобы увидеть массив одномерным, можно воспользоваться функцией ravel:

    A = np.array([ [1, 2, 3], [4, 5, 6] ])
    A.ravel()
    Out:
    array([1, 2, 3, 4, 5, 6])
    

    Чтобы поменять размеры вдоль осей или размерность используется метод reshape:

    A = np.array([ [1, 2, 3], [4, 5, 6] ])
    A.reshape(3, 2)
    Out:
    array([ [1, 2],
           [3, 4],
           [5, 6] ])
    

    Важно, чтобы количество элементов сохранилось. Иначе возникнет ошибка:

    A = np.array([ [1, 2, 3], [4, 5, 6] ])
    A.reshape(3, 3)
    Out:
    ValueError                                Traceback (most recent call last)
    <ipython-input-73-d204e18427d9> in <module>
          1 A = np.array([ [1, 2, 3], [4, 5, 6] ])
    ----> 2 A.reshape(3, 3)
    ValueError: cannot reshape array of size 6 into shape (3,3)
    

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

    A = np.arange(24)
    B = A.reshape(4, -1)
    C = A.reshape(4, -1, 2)
    print(B.shape, C.shape)
    Out:
    (4, 6) (4, 3, 2)
    

    Можно reshape использовать вместо ravel:

    A = np.array([ [1, 2, 3], [4, 5, 6] ])
    B = A.reshape(-1)
    print(B.shape)
    Out:
    (6,)
    

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

    Исходная фотография для упражнений
    Исходная фотография для упражнений

    Попробуем ее загрузить и визуализировать средствами Python. Для этого нам понадобятся OpenCV и Matplotlib (ext-1.py):

    import cv2
    from matplotlib import pyplot as plt
    
    I = cv2.imread('susu-new-year.jpg')[:, :, ::-1]
    flg = plt.figure(num=None, figsize=(15, 15), dpi=80, facecolor='w', edgecolor='k')
    plt.imshow(I)
    plt.show()
    
    flg.savefig('./output-images/ext-1.jpg')
    

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

    Результат загрузки фото
    Результат загрузки фото

    Обратите внимание на строку загрузки:

    I = cv2.imread('susu-new-year.jpg')[:, :, ::-1]
    print(I.shape)
    Out:
    (1280, 1920, 3)
    

    OpenCV работает с изображениями в формате BGR, а нам привычен RGB. Мы меняем порядок байтов вдоль оси цвета без обращения к функциям OpenCV, используя конструкцию [:, :, ::-1].

    Уменьшим изображение в 2 раза по каждой оси. Наше изображение имеет четные размеры по осям, соответственно, может быть уменьшено без интерполяции (ext-2.py):

    I_ = I.reshape(I.shape[0] // 2, 2, I.shape[1] // 2, 2, -1)
    print(I_.shape)
    plt.figure(num=None, figsize=(10, 10), dpi=80, facecolor='w', edgecolor='k')
    plt.imshow(I_[:, 0, :, 0])
    plt.show()
    
    Уменьшим изображение в 2 раза по каждой оси
    Уменьшим изображение в 2 раза по каждой оси

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

     <наверх>

    Перестановка осей и транспонирование

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

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

    A = np.array([ [1, 2, 3], [4, 5, 6] ])
    print('A\n', A)
    print('\nA data\n', A.ravel())
    B = A.T
    print('\nB\n', B)
    print('\nB data\n', B.ravel())
    Out:
    A
     [ [1 2 3]
     [4 5 6] ]
    A data
     [1 2 3 4 5 6]
    B
     [ [1 4]
     [2 5]
     [3 6] ]
    B data
     [1 4 2 5 3 6]
    

    В этом примере для транспонирования матрицы A использовалась конструкция A.T. Оператор транспонирования инвертирует порядок осей. Рассмотрим еще один пример с тремя осями:

    C = np.arange(24).reshape(4, -1, 2)
    print(C.shape, np.transpose(C).shape)
    print()
    print(C[0])
    print()
    print(C.T[:, :, 0])
    Out:
    [ [0 1]
     [2 3]
     [4 5] ]
    [ [0 2 4]
     [1 3 5] ]
    

    У этой короткой записи есть более длинный аналог: np.transpose(A). Это более универсальный инструмент для замены порядка осей. Вторым параметром можно задать кортеж номеров осей исходного массива, определяющий порядок их положения в результирующем массиве.

    Для примера переставим первые две оси изображения. Картинка должна перевернуться, но цветовую ось оставим без изменения (ext-3.py):

    I_ = np.transpose(I, (1, 0, 2))
    plt.figure(num=None, figsize=(15, 15), dpi=80, facecolor='w', edgecolor='k')
    plt.imshow(I_)
    plt.show()
    
    Переставим первые две оси изображения
    Переставим первые две оси изображения

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

    I_ = np.swapaxes(I, 0, 1)
    

     <наверх>

    Объединение массивов

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

    Для объединения с образованием новой оси исходные массивы должны иметь одинаковые размеры вдоль всех осей:

    A = np.array([ [1, 2, 3, 4], [5, 6, 7, 8] ])
    B = A[::-1]
    C = A[:, ::-1]
    D = np.stack((A, B, C))
    print(D.shape)
    D
    Out:
    (3, 2, 4)
    array([ [ [1, 2, 3, 4],
            [5, 6, 7, 8] ],
           [ [5, 6, 7, 8],
            [1, 2, 3, 4] ],
           [ [4, 3, 2, 1],
            [8, 7, 6, 5] ] ])
    

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

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

    A = np.ones((2, 1, 2))
    B = np.zeros((2, 3, 2))
    C = np.concatenate((A, B), 1)
    print(C.shape)
    C
    Out:
    (2, 4, 2)
    array([ [ [1., 1.],
            [0., 0.],
            [0., 0.],
            [0., 0.] ],
           [ [1., 1.],
            [0., 0.],
            [0., 0.],
            [0., 0.] ] ])
    

    Для объединения по первой или второй оси можно использовать методы vstack и hstack соответственно. Покажем это на примере изображений. vstack объединяет изображения одинаковой ширины по высоте, а hsstack объединяет одинаковые по высоте картинки в одно широкое (ext-4.py):

    import numpy as np
    import cv2
    from matplotlib import pyplot as plt
    
    I = cv2.imread('susu-new-year.jpg')[:, :, ::-1]
    I_ = I.reshape(I.shape[0] // 2, 2, I.shape[1] // 2, 2, -1)
    Ih = np.hstack((I_[:, 0, :, 0], I_[:, 0, :, 1]))
    Iv = np.vstack((I_[:, 0, :, 0], I_[:, 1, :, 0]))
    flg = plt.figure(num=None, figsize=(10, 10), dpi=80, facecolor='w', edgecolor='k')
    plt.imshow(Ih)
    plt.show()
    flg.savefig('./output-images/ext-41.jpg')
    
    flg = plt.figure(num=None, figsize=(10, 10), dpi=80, facecolor='w', edgecolor='k')
    plt.imshow(Iv)
    plt.show()
    flg.savefig('./output-images/ext-42.jpg')
    
    Объединение изображений по горизонтали
    Объединение изображений по горизонтали
    Объединение изображений по вертикали
    Объединение изображений по вертикали

    Обратите внимание на то, что во всех примерах этого раздела объединяемые массивы передаются одним параметром (кортежем). Количество операндов может быть любым, а не обязательно только 2.

    Также обратите внимание на то, что происходит с памятью, при объединении массивов:

    A = np.array([ [1, 2, 3, 4], [5, 6, 7, 8] ])
    B = A[::-1]
    C = A[:, ::-1]
    D = np.stack((A, B, C))
    D[0, 0, 0] = 0
    print(A)
    Out:
    [ [1 2 3 4]
     [5 6 7 8] ]
    

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

     <наверх>

    Клонирование данных

    Оператор np.repeat(A, n) вернет одномерный массив с элементами массива A, каждый из которых будет повторен n раз.

    A = np.array([ [1, 2, 3, 4], [5, 6, 7, 8] ])
    print(np.repeat(A, 2))
    Out:
    [1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8]
    

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

    A = np.array([ [1, 2, 3, 4], [5, 6, 7, 8] ])
    B = np.repeat(A, 2).reshape(A.shape[0], A.shape[1], -1)
    print(B)
    Out:
    [ [ [1 1]
      [2 2]
      [3 3]
      [4 4] ]
     [ [5 5]
      [6 6]
      [7 7]
      [8 8] ] ]
    

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

    A = np.array([ [1, 2, 3, 4], [5, 6, 7, 8] ])
    B = np.stack((A, A))
    print(B)
    Out:
    [ [ [1 2 3 4]
      [5 6 7 8] ]
     [ [1 2 3 4]
      [5 6 7 8] ] ]
    

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

    A = np.array([ [1, 2, 3, 4], [5, 6, 7, 8] ])
    B = np.transpose(np.stack((A, A)), (1, 0, 2))
    C = np.transpose(np.repeat(A, 2).reshape(A.shape[0], A.shape[1], -1), (0, 2, 1))
    print('B\n', B)
    print('\nC\n', C)
    Out:
    B
     [ [ [1 2 3 4]
      [1 2 3 4] ]
     [ [5 6 7 8]
      [5 6 7 8] ]]
    C
     [ [[1 2 3 4]
      [1 2 3 4] ]
     [ [5 6 7 8]
      [5 6 7 8] ] ]
    

    Если же мы хотим «растянуть» какую либо ось, используя повторение элементов, то ось с одинаковыми значениями надо поставить после растягиваемой (используя transpose), а затем объединить эти две оси (используя reshape). Рассмотрим пример с растяжением изображения вдоль вертикальной оси за счет дублирования строк (ext-5.py):

    import numpy as np
    import cv2
    from matplotlib import pyplot as plt
    
    I0 = cv2.imread('susu-new-year.jpg')[:, :, ::-1]     # загрузили большое изображение
    I1 = I0.reshape(I0.shape[0] // 2, 2, I0.shape[1] // 2, 2, -1)[:, 0, :, 0]  # уменьшили вдвое по каждому измерению
    I2 = np.repeat(I1, 2)  # склонировали данные
    I3 = I2.reshape(I1.shape[0], I1.shape[1], I1.shape[2], -1)
    I4 = np.transpose(I3, (0, 3, 1, 2)) # поменяли порядок осей
    I5 = I4.reshape(-1, I1.shape[1], I1.shape[2]) # объединили оси
    
    print('I0', I0.shape)
    print('I1', I1.shape)
    print('I2', I2.shape)
    print('I3', I3.shape)
    print('I4', I4.shape)
    print('I5', I5.shape)
    
    flg = plt.figure(num=None, figsize=(10, 10), dpi=80, facecolor='w', edgecolor='k')
    plt.imshow(I5)
    plt.show()
    flg.savefig('./output-images/ext-5.jpg')
    
    Пример с растяжением изображения вдоль вертикальной оси за счет дублирования строк
    Пример с растяжением изображения вдоль вертикальной оси за счет дублирования строк

     <наверх>

    Математические операции над элементами массива

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

    A = np.array([ [-1., 2., 3.], [4., 5., 6.], [7., 8., 9.] ])
    B = np.array([ [1., -2., -3.], [7., 8., 9.], [4., 5., 6.], ])
    C = A + B
    D = A - B
    E = A * B
    F = A / B
    G = A ** B
    print('+\n', C, '\n')
    print('-\n', D, '\n')
    print('*\n', E, '\n')
    print('/\n', F, '\n')
    print('**\n', G, '\n')
    Out:
    +
     [ [ 0.  0.  0.]
     [11. 13. 15.]
     [11. 13. 15.] ] 
    -
     [ [-2.  4.  6.]
     [-3. -3. -3.]
     [ 3.  3.  3.] ] 
    *
     [ [-1. -4. -9.]
     [28. 40. 54.]
     [28. 40. 54.] ] 
    /
     [ [-1.         -1.         -1.        ]
     [ 0.57142857  0.625       0.66666667]
     [ 1.75        1.6         1.5       ] ] 
    **
     [ [-1.0000000e+00  2.5000000e-01  3.7037037e-02]
     [ 1.6384000e+04  3.9062500e+05  1.0077696e+07]
     [ 2.4010000e+03  3.2768000e+04  5.3144100e+05] ]
    

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

    A = np.array([ [-1., 2., 3.], [4., 5., 6.], [7., 8., 9.] ])
    B = -2.
    
    C = A + B
    D = A - B
    E = A * B
    F = A / B
    G = A ** B
    print('+\n', C, '\n')
    print('-\n', D, '\n')
    print('*\n', E, '\n')
    print('/\n', F, '\n')
    print('**\n', G, '\n')
    Out:
    +
     [ [-3.  0.  1.]
     [ 2.  3.  4.]
     [ 5.  6.  7.] ] 
    -
     [ [ 1.  4.  5.]
     [ 6.  7.  8.]
     [ 9. 10. 11.] ] 
    *
     [ [  2.  -4.  -6.]
     [ -8. -10. -12.]
     [-14. -16. -18.] ] 
    /
     [ [ 0.5 -1.  -1.5]
     [-2.  -2.5 -3. ]
     [-3.5 -4.  -4.5] ] 
    **
     [ [1.         0.25       0.11111111]
     [0.0625     0.04       0.02777778]
     [0.02040816 0.015625   0.01234568] ] 
    

    Учитывая, что многомерный массив можно рассматривать как плоский массив (первая ось), элементы которого — массивы (остальные оси), возможно выполнение рассматриваемых операций над массивами A и B в случае, когда геометрия B совпадает с геометрией подмассивов A при фиксированном значении по первой оси. Иными словами, при совпадающем количестве осей и размерах A[i] и B. Этом случае каждый из массивов A[i] и B будут операндами для операций, определенных над массивами.

    A = np.array([ [1., 2., 3.], [4., 5., 6.], [7., 8., 9.] ])
    B = np.array([-1.1, -1.2, -1.3])
    C = A.T + B
    D = A.T - B
    E = A.T * B
    F = A.T / B
    G = A.T ** B
    print('+\n', C, '\n')
    print('-\n', D, '\n')
    print('*\n', E, '\n')
    print('/\n', F, '\n')
    print('**\n', G, '\n')
    Out:
    +
     [ [-0.1  2.8  5.7]
     [ 0.9  3.8  6.7]
     [ 1.9  4.8  7.7] ] 
    -
     [ [ 2.1  5.2  8.3]
     [ 3.1  6.2  9.3]
     [ 4.1  7.2 10.3] ] 
    *
     [ [ -1.1  -4.8  -9.1]
     [ -2.2  -6.  -10.4]
     [ -3.3  -7.2 -11.7] ] 
    /
     [ [-0.90909091 -3.33333333 -5.38461538]
     [-1.81818182 -4.16666667 -6.15384615]
     [-2.72727273 -5.         -6.92307692] ] 
    **
     [ [1.         0.18946457 0.07968426]
     [0.4665165  0.14495593 0.06698584]
     [0.29865282 0.11647119 0.05747576] ] 
    

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

    A = np.array([ [1., 2., 3.], [4., 5., 6.], [7., 8., 9.] ])
    B = np.array([-1.1, -1.2, -1.3])
    C = (A.T + B).T
    D = (A.T - B).T
    E = (A.T * B).T
    F = (A.T / B).T
    G = (A.T ** B).T
    print('+\n', C, '\n')
    print('-\n', D, '\n')
    print('*\n', E, '\n')
    print('/\n', F, '\n')
    print('**\n', G, '\n')
    Out:
    +
     [ [-0.1  0.9  1.9]
     [ 2.8  3.8  4.8]
     [ 5.7  6.7  7.7] ] 
    -
     [ [ 2.1  3.1  4.1]
     [ 5.2  6.2  7.2]
     [ 8.3  9.3 10.3] ] 
    *
     [ [ -1.1  -2.2  -3.3]
     [ -4.8  -6.   -7.2]
     [ -9.1 -10.4 -11.7] ] 
    /
     [ [-0.90909091 -1.81818182 -2.72727273]
     [-3.33333333 -4.16666667 -5.        ]
     [-5.38461538 -6.15384615 -6.92307692] ] 
    **
     [ [1.         0.4665165  0.29865282]
     [0.18946457 0.14495593 0.11647119]
     [0.07968426 0.06698584 0.05747576] ] 
    

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

    A = np.array([ [1., 2., 3.], [4., 5., 6.], [7., 8., 9.] ])
    B = np.exp(A)
    C = np.log(B)
    print('A', A, '\n')
    print('B', B, '\n')
    print('C', C, '\n')
    Out:
    A [ [1. 2. 3.]
     [4. 5. 6.]
     [7. 8. 9.] ] 
    B [ [2.71828183e+00 7.38905610e+00 2.00855369e+01]
     [5.45981500e+01 1.48413159e+02 4.03428793e+02]
     [1.09663316e+03 2.98095799e+03 8.10308393e+03] ] 
    C [ [1. 2. 3.]
     [4. 5. 6.]
     [7. 8. 9.] ] 
    

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

     <наверх>

    Матричное умножение

    Описанная выше операция произведения массивов выполняется поэлементно. А при необходимости выполнения операций по правилам линейной алгебры над массивами как над тензорами можно воспользоваться методом dot(A, B). В зависимости от вида операндов, функция выполнит:

    • если аргументы скаляры (числа), то выполнится умножение;
    • если аргументы вектор (одномерный массив) и скаляр, то выполнится умножение массива на число;
    • если аргументы вектора, то выполнится скалярное умножение (сумма поэлементных произведений);
    • если аргументы тензор (многомерный массив) и скаляр, то выполнится умножение вектора на число;
    • если аргументы тензора, то выполнится произведение тензоров по последней оси первого аргумента и предпоследней — второго;
    • если аргументы матрицы, то выполнится произведение матриц (это частный случай произведения тензоров);
    • если аргументы матрица и вектор, то выполнится произведение матрицы и вектора (это тоже частный случай произведения тензоров).

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

    Рассмотрим примеры со скалярами и векторами:

    # скаляры
    A = 2
    B = 3
    print(np.dot(A, B), '\n')
    # вектор и скаляр
    A = np.array([2., 3., 4.])
    B = 3
    print(np.dot(A, B), '\n')
    # вектора
    A = np.array([2., 3., 4.])
    B = np.array([-2., 1., -1.])
    print(np.dot(A, B), '\n')
    # тензор и скаляр
    A = np.array([ [2., 3., 4.], [5., 6., 7.] ])
    B = 2
    print(np.dot(A, B), '\n')
    Out:
    6 
    [ 6.  9. 12.] 
    -5.0 
    [ [ 4.  6.  8.]
     [10. 12. 14.] ] 
    

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

    # матрица (тензор 2) и вектор (тензор 1)
    A = np.ones((5, 6))
    B = np.ones(6)
    print('A:', A.shape, '\nB:', B.shape, '\nresult:', np.dot(A, B).shape, '\n\n')
    # матрицы (тензора 2)
    A = np.ones((5, 6))
    B = np.ones((6, 7))
    print('A:', A.shape, '\nB:', B.shape, '\nresult:', np.dot(A, B).shape, '\n\n')
    # многомерные тензора
    A = np.ones((5, 6, 7, 8))
    B = np.ones((1, 2, 3, 8, 4))
    print('A:', A.shape, '\nB:', B.shape, '\nresult:', np.dot(A, B).shape, '\n\n')
    Out:
    A: (5, 6) 
    B: (6,) 
    result: (5,) 
    A: (5, 6) 
    B: (6, 7) 
    result: (5, 7) 
    A: (5, 6, 7, 8) 
    B: (1, 2, 3, 8, 4) 
    result: (5, 6, 7, 1, 2, 3, 4) 
    

    Для выполнения произведения тензоров с использованием других осей, вместо определенных для dot можно воспользоваться tensordot с явным указанием осей:

    A = np.ones((1, 3, 7, 4))
    B = np.ones((5, 7, 6, 7, 8))
    print('A:', A.shape, '\nB:', B.shape, '\nresult:', np.tensordot(A, B, [2, 1]).shape, '\n\n')
    Out:
    A: (1, 3, 7, 4) 
    B: (5, 7, 6, 7, 8) 
    result: (1, 3, 4, 5, 6, 7, 8)  
    

    Мы явно указали, используем третью ось первого массива и вторую — второго (размеры по этим осям должны совпадать).

     <наверх>

    Агрегаторы

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

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

    A = np.random.rand(4, 5)
    print('A\n', A, '\n')
    print('min\n', np.min(A, 0), '\n')
    print('max\n', np.max(A, 0), '\n')
    print('mean\n', np.mean(A, 0), '\n')
    print('average\n', np.average(A, 0), '\n')
    Out:
    A
     [ [0.58481838 0.32381665 0.53849901 0.32401355 0.05442121]
     [0.34301843 0.38620863 0.52689694 0.93233065 0.73474868]
     [0.09888225 0.03710514 0.17910721 0.05245685 0.00962319]
     [0.74758173 0.73529492 0.58517879 0.11785686 0.81204847] ] 
    min
     [0.09888225 0.03710514 0.17910721 0.05245685 0.00962319] 
    max
     [0.74758173 0.73529492 0.58517879 0.93233065 0.81204847] 
    mean
     [0.4435752  0.37060634 0.45742049 0.35666448 0.40271039] 
    average
     [0.4435752  0.37060634 0.45742049 0.35666448 0.40271039]
    

    При таком использовании mean и average выглядят синонимами. Но эти функции обладают разным набором дополнительных параметров. У нах разные возможности по маскированию и взвешиванию усредняемых данных.

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

    A = np.ones((10, 4, 5))
    print('sum\n', np.sum(A, (0, 2)), '\n')
    print('min\n', np.min(A, (0, 2)), '\n')
    print('max\n', np.max(A, (0, 2)), '\n')
    print('mean\n', np.mean(A, (0, 2)), '\n')
    Out:
    sum
     [50. 50. 50. 50.] 
    min
     [1. 1. 1. 1.] 
    max
     [1. 1. 1. 1.] 
    mean
     [1. 1. 1. 1.] 
    

    В этом примере рассмотрена еще одна интегральная характеристика sum — сумма.

    Список агрегаторов выглядит примерно так:

    • сумма: sum и nansum — вариант корректно обходящийся с nan;
    • произведение: prod и nanprod;
    • среднее и матожидание: average и mean (nanmean), nanaverage нету;
    • медиана: median и nanmedian;
    • перцентиль: percentile и nanpercentile;
    • вариация: var и nanvar;
    • стандартное отклонение (квадратный корень из вариации): std и nanstd;
    • минимальное значение: min и nanmin;
    • максимальное значение: max и nanmax;
    • индекс элемента, имеющего минимальное значение: argmin и nanargmin;
    • индекс элемента, имеющего максимальное значение: argmax и nanargmax.

    В случае использования argmin и argmax (соответственно, и nanargmin, и nanargmax) необходимо указывать одну ось, вдоль которой будет считаться характеристика.

    Если не указать оси, то по умолчанию все рассматриваемые характеристики считаются по всему массиву. В этом случае argmin и argmax тоже корректно отработают и найдут индекс максимального или минимального элемента так, как буд-то все данные в массиве вытянуты вдоль одной оси командой ravel().

    Еще следует отметить, агрегирующие методы определены не только как методы модуля NumPy, но и для самих массивов: запись np.aggregator(A, axes) эквивалентна записи A.aggregator(axes), где под aggregator подразумевается одна из рассмотренных выше функций, а под axes — индексы осей.

    A = np.ones((10, 4, 5))
    print('sum\n', A.sum((0, 2)), '\n')
    print('min\n', A.min((0, 2)), '\n')
    print('max\n', A.max((0, 2)), '\n')
    print('mean\n', A.mean((0, 2)), '\n')
    Out:
    sum
     [50. 50. 50. 50.] 
    min
     [1. 1. 1. 1.] 
    max
     [1. 1. 1. 1.] 
    mean
     [1. 1. 1. 1.] 
    

     <наверх>

    Вместо заключения — пример

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

    Для начала загрузим зашумленное изображение.

    Рассмотрите это изображения, открыв в соседнем окне
    Рассмотрите это изображения, открыв в соседнем окне

    Фильтровать изображение будем с использованием гауссова фильтра. Но вместо выполнения свертки непосредственно (с итерированием), применим взвешенное усреднение срезов изображения, сдвинутых относительно друг друга(ext-6.py):

    def smooth(I):
        J = I.copy()
    
        J[1:-1] = (J[1:-1] // 2 + J[:-2] // 4 + J[2:] // 4)
        J[:, 1:-1] = (J[:, 1:-1] // 2 + J[:, :-2] // 4 + J[:, 2:] // 4)
    
        return J
    

    Применим эту функцию к нашему изображению единожды, дважды и трижды:

    I_noise = cv2.imread('susu-new-year-noise.jpg')
    
    I_denoise_1 = smooth(I_noise)
    I_denoise_2 = smooth(I_denoise_1)
    I_denoise_3 = smooth(I_denoise_2)
    
    cv2.imwrite('./output-images/susu-new-year-noise_1.jpg', I_denoise_1)
    cv2.imwrite('./output-images/susu-new-year-noise_2.jpg', I_denoise_2)
    cv2.imwrite('./output-images/susu-new-year-noise_3.jpg', I_denoise_3)
    

    Получаем следующие результаты:

    Делай раз
    Делай раз

    при однократном применении фильтра;

    Делай два
    Делай два

    при двукратном;

    Делай три
    Делай три

    при трехкратном.

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

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

    M = np.zeros((11, 11))
    
    M[5, 5] = 255
    M1 = smooth(M)
    M2 = smooth(M1)
    M3 = smooth(M2)
    
    flg = plt.figure(num=None, figsize=(10, 10), dpi=80, facecolor='w', edgecolor='k')
    plt.subplot(1, 3, 1)
    plt.imshow(M1)
    
    plt.subplot(1, 3, 2)
    plt.imshow(M2)
    
    plt.subplot(1, 3, 3)
    plt.imshow(M3)
    
    plt.show()
    flg.savefig('./output-images/ext-7.jpg')
    

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

    Скрипты этой статьи, посвященные работе с картинками расположены на Gihub

    Основано на материалах Habr

    ]]>
    https://chel-center.ru/python-yfc/2019/10/01/neskuchnyj-numpy/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
    Программирование на языке Python для сбора и анализа данных https://chel-center.ru/python-yfc/2019/10/10/programmirovanie-na-yazyke-python-dlya-sbora-i-analiza-dannyh/ https://chel-center.ru/python-yfc/2019/10/10/programmirovanie-na-yazyke-python-dlya-sbora-i-analiza-dannyh/#respond Thu, 10 Oct 2019 02:32:46 +0000 http://chel-center.ru/python-yfc/?p=39 Специально для визуалов в дополнение к очным занятиям. Есть что повторить и очень, очень, очень много нового и интересного.

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

    ]]>
    https://chel-center.ru/python-yfc/2019/10/10/programmirovanie-na-yazyke-python-dlya-sbora-i-analiza-dannyh/feed/ 0
    С чего начиналось «шаманство» в анализе данных https://chel-center.ru/python-yfc/2019/11/03/s-chego-nachinalos-shamanstvo-v-analize-dannyih/ https://chel-center.ru/python-yfc/2019/11/03/s-chego-nachinalos-shamanstvo-v-analize-dannyih/#respond Sun, 03 Nov 2019 02:31:15 +0000 http://waksoft.susu.ru/?p=24505 Читать далее «С чего начиналось «шаманство» в анализе данных»

    ]]>
    Так что мы больше не будем винить себя в недостатке
    ясность, так как мы cделаем это профессией

    Блез Паскаль

    В 60-х годах прошлого века, как тогда говорили, «партия и правительство» (а точнее Председатель Совета Министров СССР Косыгин Алексей Николаевич) поручили геологам найти на территории СССР месторождение золота африканского типа. Всего таких месторождений в мире было семь, они представляют собой «золотые блины» толщиной 10–15 сантиметров на глубине 2–3 километра (т.е. найти их «случайно» почти невозможно). Имелась полная статистика по ним: пробы грунта, снимки местности и т.д. Имелась также статистика по местам, в которых специалисты предполагали наличие золота, но тщательный анализ установил его отсутствие. Такую статистику в анализе данных часто собирают в таблицы «объект-признак», пример показан на рис. 1: по строкам записаны описания месторождений (объектов), а столбцы соответствуют некоторым признакам (мнение одного эксперта, особенность рельефа и т.д.).

    Рис.1. Таблица объект-признак. 

    Для консультации два молодых геолога (А.Н. Дмитриев и Ф.П. Кренделев) обратились в Институт математики новосибирского Академгородка. Проблемой заинтересовался математик Журавлёв Юрий Иванович. На вид это была как раз математическая задача: интерполяция функции от многих переменных (функция равна единице на описаниях месторождений золота и нулю – на описаниях остальных мест, надо определить, где она ещё будет равна единице, кроме известных семи точек). Проблема была только в том, что переменных больше сотни, а точек, в которых известны значения функции, всего несколько. Задача казалась неразрешимой, по крайней мере, методами «классической математики», но помог случай. За год до этого Академгородок посетил американский профессор Э. Фейгенбаум, который в своих лекциях утверждал, в частности, что ни одна по-настоящему сложная задача не может быть решена чисто математическим путём, необходимо использовать человеческий опыт, «подсматривать», как решают задачу специалисты и разрабатывать эвристические алгоритмы. Ю.И. Журавлёв ухватился за эту идею, долго беседовал с геологами, выяснял, как вообще принято искать полезные ископаемые, и переводил эти «геологические» идеи в математическую форму.

    В результате был изобретён алгоритм для поиска золота. С точки зрения «чистой математики» он был некорректен (сама постановка задачи была не совсем корректна), но он сработал! Описывать алгоритм в этой лекции мы не будем, но объясним один из основных принципов его работы. Рассмотрим рис. 1. Если подописание (1,1) (выделено в таблице) встречается только в первых двух признаках объектов первого класса и не встречается в объектах второго класса, то наличие такого подописания характерно для объектов первого класса. Это называют элементарным тестовым классификатором, их строят много, причём строят так, чтобы они были «неупрощаемы», т.е., например, если сократить это подописание, то значение 1 в первом признаке (или во втором) уже не будет характерно ни для одного из классов. Для нового объекта (потенциального месторождения), который надо классифицировать, смотрят, какие классификаторы «голосуют» за его вхождение в первый класс, а какие – за вхождение во второй. В простейшем случае «прислушиваются к большинству».

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

    Впервые эта история была рассказана в научно-популярной лекции «ШАМАНСТВО» В АНАЛИЗЕ ДАННЫХ доцента ВМК МГУ имени М.В. Ломоносова, д.ф.-м.н. А.Г. Дьяконова

    ]]>
    https://chel-center.ru/python-yfc/2019/11/03/s-chego-nachinalos-shamanstvo-v-analize-dannyih/feed/ 0