Многие Data Scientist’ы используют библиотеку Pandas, но даже не подозревают о существовании наследования классов. В этой статье мы расскажем вам, как наследование от DataFrame делает ваш код более читаемый и воспроизводимым.
В чем заключается проблема DataFrame из Pandas
Аналитики и инженеры данных обычно представляют данные в виде объекта DataFrame, который используется во всем коде. Поэтому многие операции связаны с этим объектом: его передают в функции, возвращают, преобразовывают, удаляют и т.д. Например, ниже функция на Python, которая принимает на вход DataFrame и возвращает столбец со средними значениями.
def calculate_mean(students_df): # ... остальной код return df['scores'].mean()
Как можно заметить, название столбца мы определяли в виде строки (string). Иными словами, используются строковые значения средства взаимодействия. Иными словами, требуется знать и помнить о деталях реализации. А если датафреймов больше одного, то нужно помнить у кого какие столбцы. При повторном обращении к коду придется снова вспоминать где что. Поэтому если мы думаем о сопровождении кода в будущем, то лучше так не делать.
С другой стороны, мы можем завести класс, который будет иметь поля с названиями столбцов. Пример такого класс на Python продемонстрирован ниже.
class StudentsData: SCORES = 'scores' STUDENT_NAME = 'student_name'
Так, теперь функцию для подсчета среднего значения переписывается следующим образом:
from student_data_def import StudentsData def calculate_mean(students_df): # ... return df[StudentsData.SCORES].mean()
Такой код выглядит немного лучше. Но появилась новая проблема: класс StudentsData
и датафрейм students_df
не связаны. Мы можем по имени класса догадаться, что он относится к конкретному датафрейму и ничему больше. Но догадки, связанные с кодом, лучше оставить в стороне. Другая проблема заключается в том, что нужно постоянно импортировать его там, где используется датафрейм. Такой модуль придется перезагружать при внесении изменений, если вы используете Jupyter Notebook.
Если вы используете Python 3.5 и выше, то возможно вам пригодятся подсказки типов (type hints), которые в связке с различными линтерами (о которых мы говорили тут) помогают выявлять несоответствия типов. Аннотируем подсказками нашу функцию:
def calculate_mean(students_df: pd.DataFrame) -> np.float: # ... return df[StudentsData.SCORES].mean()
Аннотация pd.DataFramе
не дает больше информации, чем имя переменной. Как понять, какие столбцы доступны? И опять придется помнить именно об этом объекте во всем коде.
Код курса
DPREP
Ближайшая дата курса
по запросу
Продолжительность
ак.часов
Стоимость обучения
0 руб.
Итак, проблемы были обозначены, хотелось бы всё-таки создать единый класс, который бы объединял и класс с полями, и датафрейм. Такой класс должен удовлетворять следующим условиям:
- не должно быть ни какого строкового обращения к столбцам,
- класс и поля должны быть связаны,
- должна быть возможность использовать его c подсказками типов.
Решение — наследование классов Pandas
Наследование от pd.DataFrame
решает перечисленные проблемы. Для этого вам нужно определить метод _constructor
и вернуть нужный класс. Пример того, как можно переписать код выше:
import pandas as pd class StudentsDF(pd.DataFrame): SCORES = 'scores' STUDENT_NAME = 'name' @property def _constructor(self): return StudentsDF x = StudentsDF(data=dict(name=['Alice', 'Bob'], scores=[60, 50])) type(x) # __main__.StudentData
Этот же класс можно использовать в качестве аннотации типов:
def calculate_mean(df: StudentsDF): # ... return df[df.SCORES].mean()
Обратите внимание, что с помощью этой конструкции также можно создать экземпляр типа StudentDF
из файла (точнее по указанию пути до него):
df = pd.read_csv('/tmp/t.csv') students_df = StudentsDF(df) print(student_df.columns)
Вот таким нехитрым способом можно сделать свой код более приятным для сопровождения при использовании библиотеки Pandas.
А о том, как проводить анализ данных с помощью библиотеки Pandas на реальных примерах Data Science вы узнаете на специализированных курсах в лицензированном учебном центре обучения и повышения квалификации разработчиков, менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data в Москве.
- FUNP: Основы языка Python для анализа данных и решения задач машинного обучения
- DPREP: Подготовка данных для Data Mining на Python
- PYML: Машинное обучение на Python