Python в настоящее время доминирует как самый популярный язык программирования для специалистов по данным. Его простота использования и популярные библиотеки машинного обучения, такие как scikit-learn и PyTorch, не говоря уже о простоте использования Jupyter Notebook по сравнению с IDE, делают его очевидным выбором, позволяющим быстро запускать и запускать свои проекты.

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

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

Часть 1: Основы Python
Часть 2: Дополнительные основы Python
Часть 3: Структуры данных
Часть 4: Введение в объектно-ориентированное программирование
Часть 5: Подробнее об объектно-ориентированном программировании
Часть 6: Распараллеливание
Часть 7: Стратегии и инструменты для улучшения ваших навыков
Часть 8: Книги для улучшения ваших навыков

Основы Python: интерпретаторы и реализации

Python — интерпретируемый язык высокого уровня. Если вы не знакомы с интерпретаторами и компиляторами, это фактически означает, что Python оценивается программой-интерпретатором во время выполнения для анализа и выполнения команд. Для Python доступно несколько интерпретаторов, реализованных на разных языках. Самая популярная — CPython, эталонная реализация, написанная на C. Если вам никогда прежде не приходилось задумываться о том, какую реализацию Python вы используете, то это CPython.

Другие реализации включают:

Поскольку CPython является оригинальной и наиболее часто используемой реализацией, большинство библиотек написано для CPython, а затем их приходится портировать на другие. Например, еще несколько лет назад Numpy не был доступен для PyPy, а поддержка scikit-learn до сих пор считается экспериментальной.

После этого мы можем погрузиться в язык Python.

Типы данных

Мы должны начать с рассмотрения встроенных типов данных, доступных в Python. Каждый язык программирования имеет базовые типы данных, на основе которых строятся все остальные типы данных и структуры данных. Для некоторых языков, таких как Java, они называются примитивами и имеют фиксированный размер памяти. В Python основными типами данных являются объекты, а не примитивы, что позволяет им иметь различные размеры. Встроенные типы Python включают нулевой тип, числовые типы, логические значения, строки, последовательности, двоичные последовательности и неупорядоченные коллекции, такие как наборы и карты (или «слова»).

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

Никто

Python включает тип данных null None. Когда значение отсутствует или в качестве заполнителя была создана пустая переменная, тип данных — None. Стоит отметить, что NaN («не число») — это не то же самое, что None, хотя некоторые библиотеки, такие как Pandas, рассматривают их как эквивалентные. NaN соответствует неопределенному числу из вычислений с плавающей запятой, таких как деление на 0. Хотя оно не определено, оно все же является значением, тогда как None означает отсутствие какого-либо значения.

Числовые типы: Int, Float, Complex

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

логическое значение (bool)

Логическое значение имеет два значения: True и False. Они получаются в результате оценки выражения для его значения истинности, такого как 1 == 1 (Истина) и 1 == 2 (Ложь). Технически логические значения в Python являются подтипом целых чисел, где ноль соответствует False. Из-за этого 1 и 0 часто используются взаимозаменяемо с True и False, а другие ненулевые целые значения, как положительные, так и отрицательные, оцениваются как True.

Другие встроенные типы также имеют состояние или значение, соответствующее False. Например, для чисел с плавающей запятой это 0,0, для строк — пустая строка ‘’, а для последовательностей и коллекций — когда они пусты. Возьмем, к примеру:

x = []
if x: 
  print(x) 
# nothing is printed

Строка (стр)

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

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

  • Формат: заменяет поле, разделенное фигурными скобками, значением, например. 'ab{}d'}.format('c'); есть множество способов использовать это, как указано в документации.
  • Нижний, верхний: переводит все буквы в один регистр.
  • Заменить: заменяет все (или первые n, если используется аргумент count) экземпляров подстроки новой подстрокой.
  • Присоединение: объединяет список строк в строку с разделителями, например ['a', 'b', 'c'].join(', ') -> ‘a, b, c’.
  • Разделить: преобразует строку с разделителями в список, например 'a, b, c'.split(', ') -> ['a', 'b', 'c'].
  • Zfill: дополняет строку нулями, например '7'.zfill(3) -> '007'.
  • Eval: оценивает и выполняет допустимый код Python в строке, например, eval('1') возвращает целое число 1, а eval('print(x)') печатает сохраненное значение переменной x.

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

Типы последовательностей: Список, Кортеж, Диапазон

Python имеет три основных типа последовательностей:

  • Списки представляют собой изменяемые упорядоченные коллекции объектов, то есть элементы можно изменять, а также добавлять или удалять элементы, и каждый элемент имеет проиндексированную позицию. Объекты не обязательно должны иметь один и тот же тип данных. У вас может быть список целых чисел, переменных, списков и так далее. Доступ к элементам можно получить по индексу или распаковать по порядку (например, a, b = [1, 2] приводит к a=1 и b=2), а списки поддерживают операции изменяемой последовательности.
  • Кортежи — это неизменяемые упорядоченные коллекции. Они имеют фиксированную длину и содержат фиксированный набор элементов. Доступ к элементам можно получить по индексу или распаковать по порядку. Когда функция возвращает несколько значений, результатом является кортеж.
  • Диапазоны — это неизменяемые упорядоченные последовательности целых чисел с фиксированным приращением. Необязательная нижняя граница включается в диапазон, а требуемая верхняя граница исключается. Например, range(6) возвращает числа от 0 до 5, а range(10, 20, 2) возвращает четные числа от 10 до 19.

Типы двоичных последовательностей: Bytes, Bytearrays, Memoryview

Байты форматируются аналогично строкам (с форматом b'text') и поддерживают многие из тех же функций, но представляют собой неизменяемые последовательности одиночных байтов на основе текста ASCII. Bytearrays являются изменяемым эквивалентом байтов и поддерживают операции изменяемой последовательности, такие как нарезка и замена элементов.

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

Наборы и замороженные наборы

Набор в Python — это неупорядоченная коллекция различных хешируемых объектов. Что это значит?

  • Каждый элемент в наборе уникален. Если вы попытаетесь добавить повторяющийся элемент, он не будет добавлен (но и не выдаст ошибку). Из-за этого наборы часто используются для проверки уникальности, идентификации уникальных элементов и сравнения наборов на предмет пересечений и различий.
  • Каждый элемент в наборе должен быть хешируемым. Хеширование позволяет сравнивать объекты друг с другом, а хэш объекта является постоянным. Большинство встроенных неизменяемых типов данных являются хешируемыми, хотя для таких контейнеров, как кортежи, все отдельные элементы в контейнере должны быть хешируемыми. Объекты определяемых пользователем классов можно хэшировать, потому что они имеют уникальный адрес памяти (объект «id»), который можно хэшировать, но только тот же самый объект будет идентифицирован как имеющий такой же хэш.
  • Поскольку они неупорядочены, элементы в наборах не имеют индексов и не могут быть доступны по положению.

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

Словари (дикты)

Словари Python (или dicts) — это тип данных для карт, то есть наборы пар ключ-значение. Они неупорядочены и изменяемы, а ключи должны быть хешируемы. Ключи не обязательно должны иметь один и тот же тип данных.

К значениям в словаре можно получить доступ по ключу так же, как к элементам в списке можно получить доступ по индексу. Словари также имеют объекты просмотра, доступ к которым осуществляется через функции keys(), values() и items(). Эти списки динамически обновляются по мере обновления словаря. Например:

a = {1: 1, 2: 2, 3: 3, 4: 4}
b = a.keys()
del a[1]
print(b)
# prints dict_keys([2, 3, 4])

Типовые подсказки

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

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

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

# Function with return
# if nothing is returned, the return type is None
def function(argument: type = default_value) -> type:
  some code
  return value_of_type
# Examples:
def example(a: int) -> float:
  return a / 1.0
def example2(df: pd.DataFrame) -> np.array:
  return df.values

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

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

Коллекции

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

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

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

from collections import defaultdict
some_list = [1, 2, 2, 3, 4, 5, 6, 9, 10, 10, 11]
# With defaultdict:
d0 = defaultdict(int)
for i in some_list:
  d0[i] += 1
print(d0[7])
# prints 0
# Without defaultdict:
d1 = dict()
for i in some_list:
  if i in d1.keys():
    d1[i] += 1
  else:
    d1[i] = 1
print(d1[7])
# raises KeyError

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

Подведение итогов

Мы рассмотрели много материала в этом посте, но это только начало! Чтобы стать лучшим программистом на Python, нужно изучить гораздо больше.

Следите за новостями из серии «Лучшее программирование на Python для специалистов по данным»!

Основы Python | Больше основ Python| Структуры данных | Объектно-ориентированное программирование 1 | Объектно-ориентированное программирование 2 | Распараллеливание | Стратегии и инструменты | Книги