6.2. Модуль pandas

В этой статье вы познакомитесь с библиотекой pandas — одним из ключевых инструментов для анализа данных в Python. Вы узнаете, как создавать и использовать объекты Series и DataFrame, считывать данные из файлов, фильтровать и сортировать таблицы, выполнять агрегирование и строить простые визуализации. Библиотека pandas построена на базе numpy и предоставляет удобный интерфейс для работы с табличными структурами, которые встречаются почти во всех проектах, связанных с анализом, отчётами и машинным обучением.

Ключевые вопросы статьи

  • Как установить и подключить библиотеку pandas?
  • Что такое объекты Series и DataFrame и как с ними работать?
  • Как фильтровать, сортировать и агрегировать данные?
  • Как создавать и изменять табличные структуры в pandas?
  • Как визуализировать табличные данные с помощью библиотеки matplotlib?

Как установить и подключить библиотеку pandas

Для работы с табличными структурами данных в Python чаще всего используют библиотеку pandas. Она построена на основе numpy и обеспечивает удобные инструменты для анализа и обработки данных.

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

pip install pandas

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

import numpy as np
import pandas as pd

Далее вы познакомитесь с двумя основными структурами данных библиотеки pandas — объектами Series и DataFrame — и научитесь создавать и обрабатывать таблицы.

Что такое объекты Series и DataFrame и как с ними работать

В библиотеке pandas определены два основных класса объектов для работы с данными:

  • Series — одномерный массив, способный хранить значения любого типа. По своей структуре напоминает словарь: каждому значению присваивается метка (индекс), которая может быть как числом, так и строкой.
  • DataFrame — двумерная таблица, в которой строки и столбцы имеют имена. Каждый столбец — это объект класса Series, а сами данные удобно организованы для анализа и преобразований.

Создание и работа с этими объектами лежит в основе большинства операций в pandas.

Создание Series

Создать Series можно с помощью конструктора:

s = pd.Series(data, index=index)
  • data может быть массивом numpy, словарём или скаляром (числом).
  • index — список меток, по умолчанию это целые числа от 0 до n-1.

Примеры:

s = pd.Series(np.arange(5), index=["a", "b", "c", "d", "e"])
print(s)

s = pd.Series(np.linspace(0, 1, 5))
print(s)

# Вывод программы

# a    0

# b    1

# c    2

# d    3

# e    4

# dtype: int32

# 0    0.00

# 1    0.25

# 2    0.50

# 3    0.75

# 4    1.00

# dtype: float64

Если data — словарь, а index не задан, то в качестве меток используются ключи словаря:

d = {"a": 10, "b": 20, "c": 30, "g": 40}
print(pd.Series(d))

# Вывод программы:

# a    10

# b    20

# c    30

# g    40

# dtype: int64

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

print(pd.Series(d, index=["a", "b", "c", "d"]))

# Вывод программы

# a    10.0

# b    20.0

# c    30.0

# d     NaN

# dtype: float64

Если data — число, обязательно передаётся index, определяющий количество элементов:

index = ["a", "b", "c"]

print(pd.Series(5, index=index))

# Вывод программы

# a    5

# b    5

# c    5

# dtype: int64

Индексация, срезы и арифметика

Объекты Series поддерживают индексирование, срезы и математические операции:

s = pd.Series(np.arange(5), index=["a", "b", "c", "d", "e"])
print(s["a"])             # Один элемент
print(s[["a", "d"]])      # Несколько элементов
print(s[1:])              # Срез
print(s + s)              # Поэлементное сложение

# Вывод программы

# Выбор одного элемента

# 0

# Выбор нескольких элементов

# a    0

# d    3

# dtype: int32

# Срез

# b    1

# c    2

# d    3

# e    4

# dtype: int32

# Поэлементное сложение

# a    0

# b    2

# c    4

# d    6

# e    8

# dtype: int32

Фильтрация

Можно использовать булевы условия для отбора значений:

print(s[s > 2])

# Вывод программы

# Фильтрация

# d    3

# e    4

# dtype: int32

Атрибуты Series

У объекта Series есть полезные свойства:

s.name = "Данные"
s.index.name = "Индекс"
print(s)

# Вывод программы

# Индекс

# a    0

# b    1

# c    2

# d    3

# e    4

# Name: Данные, dtype: int32

Создание и работа с DataFrame

DataFrame — это таблица с именованными столбцами и индексами строк. Создать DataFrame можно из словаря списков:

students_marks_dict = {
    "student": ["Студент_1", "Студент_2", "Студент_3"],
    "math": [5, 3, 4],
    "physics": [4, 5, 5]
}
students = pd.DataFrame(students_marks_dict)
print(students)

# Вывод программы

# student  math  physics

# 0  Студент_1     5        4

# 1  Студент_2     3        5

# 2  Студент_3     4        5

Индексы строк и столбцов

У объекта DataFrame есть индексы по строкам и по столбцам. Их можно получить с помощью свойств index и columns:

print(students.index)
print(students.columns)

# Вывод программы

# RangeIndex(start=0, stop=3, step=1)

# Index(['student', 'math', 'physics'], dtype='object')

По умолчанию строки нумеруются от 0. При необходимости индексы можно переопределить вручную:

students.index = ["A", "B", "C"]

Каждый столбец DataFrame на самом деле представляет собой отдельный объект Series. Поэтому, если обратиться к одному столбцу по его имени, мы получим объект этого типа:

print(type(students["student"]))  

# <class 'pandas.core.series.Series'>

Для доступа к строкам по индексам используют .loc[], включая срезы:

print(students.loc["B":])

# Вывод программы

# student  math  physics

# B  Студент_2     3        5

# C  Студент_3     4        5

Как фильтровать, сортировать и агрегировать данные

В pandas объект Series можно создать из массива numpy, словаря или даже одного значения. Параметр index задаёт метки осей (индексы) и передаётся в виде списка. Метками могут быть числа, но чаще — строки.

Если в качестве data используется массив numpy, длина index должна совпадать с числом элементов. Если индекс не задан, он формируется автоматически как последовательность от 0 до len(data) - 1:

s = pd.Series(np.arange(5), index=["a", "b", "c", "d", "e"])
print(s)
print()
s = pd.Series(np.linspace(0, 1, 5))
print(s)

# Вывод

# a    0

# b    1

# c    2

# d    3

# e    4

# dtype: int32

#

# 0    0.00

# 1    0.25

# 2    0.50

# 3    0.75

# 4    1.00

# dtype: float64

Объект Series во многом напоминает словарь: каждому значению соответствует собственная метка.

Если data — это словарь, а index не задан, в качестве индексов будут использованы ключи словаря. Если index задан и содержит значения, которых нет среди ключей словаря, то в соответствующих ячейках будет стоять NaN — стандартное обозначение отсутствующих данных в pandas:

d = {"a": 10, "b": 20, "c": 30, "g": 40}
print(pd.Series(d))
print()
print(pd.Series(d, index=["a", "b", "c", "d"]))

# Вывод

# a    10

# b    20

# c    30

# g    40

# dtype: int64

#

# a    10.0

# b    20.0

# c    30.0

# d     NaN

# dtype: float64

Если data — это одно значение, параметр index обязательно нужен. Серия будет состоять из повторяющихся значений:

index = ["a", "b", "c"]
print(pd.Series(5, index=index))

# Вывод

# a    5

# b    5

# c    5

# dtype: int64

С объектами Series можно работать так же, как с массивами numpy: выполнять срезы, индексацию, поэлементные операции:

s = pd.Series(np.arange(5), index=["a", "b", "c", "d", "e"])
print("Выбор одного элемента")
print(s["a"])
print("Выбор нескольких элементов")
print(s[["a", "d"]])
print("Срез")
print(s[1:])
print("Поэлементное сложение")
print(s + s)

# Вывод

# Выбор одного элемента

# 0

# Выбор нескольких элементов

# a    0

# d    3

# dtype: int32

# Срез

# b    1

# c    2

# d    3

# e    4

# dtype: int32

# Поэлементное сложение

# a    0

# b    2

# c    4

# d    6

# e    8

# dtype: int32

Можно отфильтровать данные по условию:

s = pd.Series(np.arange(5), index=["a", "b", "c", "d", "e"])
print("Фильтрация")
print(s[s > 2])

# Вывод

# Фильтрация

# d    3

# e    4

# dtype: int32

У объектов Series есть два полезных атрибута:

  • name — название набора данных;
  • index.name — имя оси индексов:
s = pd.Series(np.arange(5), index=["a", "b", "c", "d", "e"])
s.name = "Данные"
s.index.name = "Индекс"
print(s)

# Вывод

# Индекс

# a    0

# b    1

# c    2

# d    3

# e    4

# Name: Данные, dtype: int32

Как создавать и изменять табличные структуры в pandas

Обычно табличные данные хранятся в файлах. Такие наборы принято называть датасетами (англ. dataset, набор данных). Файлы с данными могут быть в разных форматах: CSV, Excel, JSON, SQL и другие. Библиотека pandas поддерживает как чтение, так и сохранение таблиц в этих форматах.

Как считывать и сохранять данные в различных форматах (CSV, Excel, JSON)

Рассмотрим несколько примеров:

CSV-файлы

  • Считывание: pd.read_csv("имя_файла.csv")
  • Сохранение: df.to_csv("имя_файла.csv")

Excel-файлы (формат 2007+)

  • Считывание: pd.read_excel("имя_файла.xlsx")
  • Сохранение: df.to_excel("имя_файла.xlsx")

JSON-файлы

  • Считывание: pd.read_json("имя_файла.json")
  • Сохранение: df.to_json("имя_файла.json")

Полный список поддерживаемых форматов и настроек доступен в официальной документации.

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

Пример содержимого CSV-файла:

"gender","race/ethnicity","parental level of education","lunch","test preparation course","math score","reading score","writing score"
"female","group B","bachelor's degree","standard","none","72","72","74"
"female","group C","some college","standard","completed","69","90","88"

Для дальнейшей работы скачайте данный файл с датасетом. Получим датасет из CSV-файла с данными о студентах:

import numpy as np
import pandas as pd

students = pd.read_csv("StudentsPerformance.csv")

Полученный объект students относится к классу DataFrame.

Для получения первых n строк датасета используется метод head(n). По умолчанию возвращается пять первых строк:

print(students.head())

# Вывод программы

# gender race/ethnicity  ... reading score writing score

# 0  female        group B  ...            72            74

# 1  female        group C  ...            90            88

# 2  female        group B  ...            95            93

# 3    male        group A  ...            57            44

# 4    male        group C  ...            78            75

# [5 rows x 8 columns]

Для получения последних n строк используется метод tail(n). По умолчанию возвращается пять последних строк:

print(students.tail(3))

# Вывод программы

# gender race/ethnicity  ... reading score writing score

# 997  female        group C  ...            71            65

# 998  female        group D  ...            78            77

# 999  female        group D  ...            86            86

#

# [3 rows x 8 columns]

Для получения части датасета можно использовать срез:

print(students[10:13])

# Вывод программы

# gender race/ethnicity  ... reading score writing score

# 10    male        group C  ...            54            52

# 11    male        group D  ...            52            43

# 12  female        group B  ...            81            73

#

# [3 rows x 8 columns]

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

print(students[students["test preparation course"] == "completed"]["math score"].head())

# Вывод программы

#

# 1     69

# 6     88

# 8     64

# 13    78

# 18    46

# Name: math score, dtype: int64

Выведем пять лучших результатов тестов по трём дисциплинам для предыдущей выборки с помощью сортировки методом sort_values(). Сортировка по умолчанию производится в порядке возрастания значений. Для сортировки по убыванию в именованный аргумент ascending передаётся значение False.

with_course = students[students["test preparation course"] == "completed"]

print(with_course[["math score", "reading score", "writing score"]]
      .sort_values(["math score", "reading score", "writing score"], ascending=False)
      .head())

# Вывод программы
#     math score  reading score  writing score
# 916         100            100            100
# 149         100            100             93
# 625         100             97             99
# 623         100             96             86
# 114          99            100            100

Сортировка по новой колонке total_score, которую добавим вручную:

students["total score"] = (students["math score"]
                           + students["reading score"]
                           + students["writing score"])

print(students.sort_values("total score", ascending=False).head())

# Вывод программы

#

# gender race/ethnicity  ... writing score total score

# 916    male        group E  ...           100         300

# 458  female        group E  ...           100         300

# 962  female        group E  ...           100         300

# 114  female        group E  ...           100         299

# 179  female        group D  ...           100         297

#

# [5 rows x 9 columns]

Чтобы в таблицу добавить колонку, подойдёт метод assign(). Данный метод даёт возможность создавать колонки при помощи лямбда-функции.

Примечание

Данный метод возвращает новую таблицу, а не меняет исходную.

Перепишем предыдущий пример с использованием assign():

scores = students.assign(total_score=lambda x: x["math score"]
                                          + x["reading score"]
                                          + x["writing score"])

print(scores.sort_values("total_score", ascending=False).head())

# Вывод программы

#

# gender race/ethnicity  ... writing score total_score

# 916    male        group E  ...           100         300

# 458  female        group E  ...           100         300

# 962  female        group E  ...           100         300

# 114  female        group E  ...           100         299

# 179  female        group D  ...           100         297

Группировка и агрегирование данных

Метод groupby() позволяет сгруппировать записи по признаку. Например, узнаем, сколько студентов разного пола прошли подготовку:

print(students.groupby(["gender", "test preparation course"])["writing score"].count())

# Вывод программы

#

# gender  test preparation course

# female  completed                  184

# none                        334

# male    completed                  174

# none                       308

# Name: race/ethnicity, dtype: int64

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

Например:

agg_functions = {"math score": ["mean", "median"]}

print(students.groupby(["gender", "test preparation course"]).agg(agg_functions))

# Вывод программы

#

# math score

# mean median

# gender test preparation course

# female completed                67.195652   67.0

# none                     61.670659   62.0

# male   completed                72.339080   73.0

# none                      66.688312   67.0

Как визуализировать табличные данные с помощью matplotlib

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

  1. Установить библиотеку.
  2. Добавить импорт в начало программы.

Для установки выполним команду:

pip install matplotlib

А затем импортируем:

import matplotlib.pyplot as plt

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

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

plt.hist(students["math score"], label="Тест по математике")
plt.xlabel("Баллы за тест")
plt.ylabel("Количество студентов")
plt.legend()
plt.show()

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

Ещё по теме

Для более детального изучения библиотеки numpy рекомендуем почитать документацию.

Что дальше

В этой статье вы освоили базовые приёмы работы с табличными данными в библиотеке pandas.

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

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

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

В следующей статье мы перейдём к важному практическому навыку — работе с HTTP-запросами и API. Вы узнаете, как загружать данные из внешних сервисов, отправлять запросы и получать ответы, а также взаимодействовать с API-сервисами вроде Static API и Яндекс Диска. Всё это — ключ к тому, чтобы ваши программы могли общаться с внешним миром.

Ключевые выводы статьи

  • В pandas определены два основных типа объектов: Series (одномерные структуры) и DataFrame (таблицы), основанные на numpy.
  • Объекты Series и DataFrame позволяют фильтровать, сортировать и агрегировать данные по условиям, индексам и значениям.
  • С pandas удобно считывать и сохранять данные в популярных форматах — CSV, Excel, JSON — и обрабатывать их с помощью встроенных методов.
  • Для анализа доступны мощные инструменты группировки (groupby), агрегации (agg) и построения новых столбцов (assign).
  • Визуализация данных осуществляется с помощью библиотеки matplotlib, на основе которой можно строить гистограммы и другие графики.