Введение в pandas: анализ данных на Python
4 Март 2017 , Python, 741047 просмотров, Introduction to pandas: data analytics in Python
pandas это высокоуровневая Python библиотека для анализа данных. Почему я её называю высокоуровневой, потому что построена она поверх более низкоуровневой библиотеки NumPy (написана на Си), что является большим плюсом в производительности. В экосистеме Python, pandas является наиболее продвинутой и быстроразвивающейся библиотекой для обработки и анализа данных. В своей работе мне приходится пользоваться ею практически каждый день, поэтому я пишу эту краткую заметку для того, чтобы в будущем ссылаться к ней, если вдруг что-то забуду. Также надеюсь, что читателям блога заметка поможет в решении их собственных задач с помощью pandas, и послужит небольшим введением в возможности этой библиотеки.
DataFrame и Series
Чтобы эффективно работать с pandas, необходимо освоить самые главные структуры данных библиотеки: DataFrame и Series. Без понимания что они из себя представляют, невозможно в дальнейшем проводить качественный анализ.
Series
Структура/объект Series представляет из себя объект, похожий на одномерный массив (питоновский список, например), но отличительной его чертой является наличие ассоциированных меток, т.н. индексов, вдоль каждого элемента из списка. Такая особенность превращает его в ассоциативный массив или словарь в Python.
>>> import pandas as pd >>> my_series = pd.Series([5, 6, 7, 8, 9, 10]) >>> my_series 0 5 1 6 2 7 3 8 4 9 5 10 dtype: int64 >>>
В строковом представлении объекта Series, индекс находится слева, а сам элемент справа. Если индекс явно не задан, то pandas автоматически создаёт RangeIndex от 0 до N-1, где N общее количество элементов. Также стоит обратить, что у Series есть тип хранимых элементов, в нашем случае это int64, т.к. мы передали целочисленные значения.
У объекта Series есть атрибуты через которые можно получить список элементов и индексы, это values и index соответственно.
>>> my_series.index RangeIndex(start=0, stop=6, step=1) >>> my_series.values array([ 5, 6, 7, 8, 9, 10], dtype=int64)
Доступ к элементам объекта Series возможны по их индексу (вспоминается аналогия со словарем и доступом по ключу).
>>> my_series[4] 9
Индексы можно задавать явно:
>>> my_series2 = pd.Series([5, 6, 7, 8, 9, 10], index=['a', 'b', 'c', 'd', 'e', 'f']) >>> my_series2['f'] 10
Делать выборку по нескольким индексам и осуществлять групповое присваивание:
>>> my_series2[['a', 'b', 'f']] a 5 b 6 f 10 dtype: int64 >>> my_series2[['a', 'b', 'f']] = 0 >>> my_series2 a 0 b 0 c 7 d 8 e 9 f 0 dtype: int64
Фильтровать Series как душе заблагорассудится, а также применять математические операции и многое другое:
>>> my_series2[my_series2 > 0] c 7 d 8 e 9 dtype: int64 >>> my_series2[my_series2 > 0] * 2 c 14 d 16 e 18 dtype: int64
Если Series напоминает нам словарь, где ключом является индекс, а значением сам элемент, то можно сделать так:
>>> my_series3 = pd.Series() >>> my_series3 a 5 b 6 c 7 d 8 dtype: int64 >>> 'd' in my_series3 True
У объекта Series и его индекса есть атрибут name, задающий имя объекту и индексу соответственно.
>>> my_series3.name = 'numbers' >>> my_series3.index.name = 'letters' >>> my_series3 letters a 5 b 6 c 7 d 8 Name: numbers, dtype: int64
Индекс можно поменять «на лету», присвоив список атрибуту index объекта Series
>>> my_series3.index = ['A', 'B', 'C', 'D'] >>> my_series3 A 5 B 6 C 7 D 8 Name: numbers, dtype: int64
Имейте в виду, что список с индексами по длине должен совпадать с количеством элементов в Series.
DataFrame
Объект DataFrame лучше всего представлять себе в виде обычной таблицы и это правильно, ведь DataFrame является табличной структурой данных. В любой таблице всегда присутствуют строки и столбцы. Столбцами в объекте DataFrame выступают объекты Series, строки которых являются их непосредственными элементами.
DataFrame проще всего сконструировать на примере питоновского словаря:
>>> df = pd.DataFrame(< . 'country': ['Kazakhstan', 'Russia', 'Belarus', 'Ukraine'], . 'population': [17.04, 143.5, 9.5, 45.5], . 'square': [2724902, 17125191, 207600, 603628] . >) >>> df country population square 0 Kazakhstan 17.04 2724902 1 Russia 143.50 17125191 2 Belarus 9.50 207600 3 Ukraine 45.50 603628
Чтобы убедиться, что столбец в DataFrame это Series, извлекаем любой:
>>> df['country'] 0 Kazakhstan 1 Russia 2 Belarus 3 Ukraine Name: country, dtype: object >>> type(df['country'])
Объект DataFrame имеет 2 индекса: по строкам и по столбцам. Если индекс по строкам явно не задан (например, колонка по которой нужно их строить), то pandas задаёт целочисленный индекс RangeIndex от 0 до N-1, где N это количество строк в таблице.
>>> df.columns Index([u'country', u'population', u'square'], dtype='object') >>> df.index RangeIndex(start=0, stop=4, step=1)
В таблице у нас 4 элемента от 0 до 3.
Доступ по индексу в DataFrame
Индекс по строкам можно задать разными способами, например, при формировании самого объекта DataFrame или «на лету»:
>>> df = pd.DataFrame(< . 'country': ['Kazakhstan', 'Russia', 'Belarus', 'Ukraine'], . 'population': [17.04, 143.5, 9.5, 45.5], . 'square': [2724902, 17125191, 207600, 603628] . >, index=['KZ', 'RU', 'BY', 'UA']) >>> df country population square KZ Kazakhstan 17.04 2724902 RU Russia 143.50 17125191 BY Belarus 9.50 207600 UA Ukraine 45.50 603628 >>> df.index = ['KZ', 'RU', 'BY', 'UA'] >>> df.index.name = 'Country Code' >>> df country population square Country Code KZ Kazakhstan 17.04 2724902 RU Russia 143.50 17125191 BY Belarus 9.50 207600 UA Ukraine 45.50 603628
Как видно, индексу было задано имя — Country Code. Отмечу, что объекты Series из DataFrame будут иметь те же индексы, что и объект DataFrame:
>>> df['country'] Country Code KZ Kazakhstan RU Russia BY Belarus UA Ukraine Name: country, dtype: object
Доступ к строкам по индексу возможен несколькими способами:
- .loc — используется для доступа по строковой метке
- .iloc — используется для доступа по числовому значению (начиная от 0)
>>> df.loc['KZ'] country Kazakhstan population 17.04 square 2724902 Name: KZ, dtype: object >>> df.iloc[0] country Kazakhstan population 17.04 square 2724902 Name: KZ, dtype: object
Можно делать выборку по индексу и интересующим колонкам:
>>> df.loc[['KZ', 'RU'], 'population'] Country Code KZ 17.04 RU 143.50 Name: population, dtype: float64
Как можно заметить, .loc в квадратных скобках принимает 2 аргумента: интересующий индекс, в том числе поддерживается слайсинг и колонки.
>>> df.loc['KZ':'BY', :] country population square Country Code KZ Kazakhstan 17.04 2724902 RU Russia 143.50 17125191 BY Belarus 9.50 207600
Фильтровать DataFrame с помощью т.н. булевых массивов:
>>> df[df.population > 10][['country', 'square']] country square Country Code KZ Kazakhstan 2724902 RU Russia 17125191 UA Ukraine 603628
Кстати, к столбцам можно обращаться, используя атрибут или нотацию словарей Python, т.е. df.population и df[‘population’] это одно и то же.
Сбросить индексы можно вот так:
>>> df.reset_index() Country Code country population square 0 KZ Kazakhstan 17.04 2724902 1 RU Russia 143.50 17125191 2 BY Belarus 9.50 207600 3 UA Ukraine 45.50 603628
pandas при операциях над DataFrame, возвращает новый объект DataFrame.
Добавим новый столбец, в котором население (в миллионах) поделим на площадь страны, получив тем самым плотность:
>>> df['density'] = df['population'] / df['square'] * 1000000 >>> df country population square density Country Code KZ Kazakhstan 17.04 2724902 6.253436 RU Russia 143.50 17125191 8.379469 BY Belarus 9.50 207600 45.761079 UA Ukraine 45.50 603628 75.377550
Не нравится новый столбец? Не проблема, удалим его:
>>> df.drop(['density'], axis='columns') country population square Country Code KZ Kazakhstan 17.04 2724902 RU Russia 143.50 17125191 BY Belarus 9.50 207600 UA Ukraine 45.50 603628
Особо ленивые могут просто написать del df[‘density’].
Переименовывать столбцы нужно через метод rename:
>>> df = df.rename(columns=) >>> df country_code country population square 0 KZ Kazakhstan 17.04 2724902 1 RU Russia 143.50 17125191 2 BY Belarus 9.50 207600 3 UA Ukraine 45.50 603628
В этом примере перед тем как переименовать столбец Country Code, убедитесь, что с него сброшен индекс, иначе не будет никакого эффекта.
Чтение и запись данных
pandas поддерживает все самые популярные форматы хранения данных: csv, excel, sql, буфер обмена, html и многое другое:

Чаще всего приходится работать с csv-файлами. Например, чтобы сохранить наш DataFrame со странами, достаточно написать:
>>> df.to_csv('filename.csv')
Функции to_csv ещё передаются различные аргументы (например, символ разделителя между колонками) о которых подробнее можно узнать в официальной документации.
Считать данные из csv-файла и превратить в DataFrame можно функцией read_csv.
>>> df = pd.read_csv('filename.csv', sep=',')
Аргумент sep указывает разделитесь столбцов. Существует ещё масса способов сформировать DataFrame из различных источников, но наиболее часто используют CSV, Excel и SQL. Например, с помощью функции read_sql, pandas может выполнить SQL запрос и на основе ответа от базы данных сформировать необходимый DataFrame. За более подробной информацией стоит обратиться к официальной документации.
Группировка и агрегирование в pandas
Группировка данных один из самых часто используемых методов при анализе данных. В pandas за группировку отвечает метод .groupby. Я долго думал какой пример будет наиболее наглядным, чтобы продемонстрировать группировку, решил взять стандартный набор данных (dataset), использующийся во всех курсах про анализ данных — данные о пассажирах Титаника. Скачать CSV файл можно тут.
>>> titanic_df = pd.read_csv('titanic.csv') >>> print(titanic_df.head()) PassengerID Name PClass Age \ 0 1 Allen, Miss Elisabeth Walton 1st 29.00 1 2 Allison, Miss Helen Loraine 1st 2.00 2 3 Allison, Mr Hudson Joshua Creighton 1st 30.00 3 4 Allison, Mrs Hudson JC (Bessie Waldo Daniels) 1st 25.00 4 5 Allison, Master Hudson Trevor 1st 0.92 Sex Survived SexCode 0 female 1 1 1 female 0 1 2 male 0 0 3 female 0 1 4 male 1 0
Необходимо подсчитать, сколько женщин и мужчин выжило, а сколько нет. В этом нам поможет метод .groupby.
>>> print(titanic_df.groupby(['Sex', 'Survived'])['PassengerID'].count()) Sex Survived female 0 154 1 308 male 0 709 1 142 Name: PassengerID, dtype: int64
А теперь проанализируем в разрезе класса кабины:
>>> print(titanic_df.groupby(['PClass', 'Survived'])['PassengerID'].count()) PClass Survived * 0 1 1st 0 129 1 193 2nd 0 160 1 119 3rd 0 573 1 138 Name: PassengerID, dtype: int64
Сводные таблицы в pandas
Термин «сводная таблица» хорошо известен тем, кто не по наслышке знаком с инструментом Microsoft Excel или любым иным, предназначенным для обработки и анализа данных. В pandas сводные таблицы строятся через метод .pivot_table. За основу возьмём всё тот же пример с Титаником. Например, перед нами стоит задача посчитать сколько всего женщин и мужчин было в конкретном классе корабля:
>>> titanic_df = pd.read_csv('titanic.csv') >>> pvt = titanic_df.pivot_table(index=['Sex'], columns=['PClass'], values='Name', aggfunc='count')
В качестве индекса теперь у нас будет пол человека, колонками станут значения из PClass, функцией агрегирования будет count (подсчёт количества записей) по колонке Name.
>>> print(pvt.loc['female', ['1st', '2nd', '3rd']]) PClass 1st 143.0 2nd 107.0 3rd 212.0 Name: female, dtype: float64
Всё очень просто.
Анализ временных рядов
В pandas очень удобно анализировать временные ряды. В качестве показательного примера я буду использовать цену на акции корпорации Apple за 5 лет по дням. Файл с данными можно скачать тут.
>>> import pandas as pd >>> df = pd.read_csv('apple.csv', index_col='Date', parse_dates=True) >>> df = df.sort_index() >>> print(df.info()) DatetimeIndex: 1258 entries, 2017-02-22 to 2012-02-23 Data columns (total 6 columns): Open 1258 non-null float64 High 1258 non-null float64 Low 1258 non-null float64 Close 1258 non-null float64 Volume 1258 non-null int64 Adj Close 1258 non-null float64 dtypes: float64(5), int64(1) memory usage: 68.8 KB
Здесь мы формируем DataFrame с DatetimeIndex по колонке Date и сортируем новый индекс в правильном порядке для работы с выборками. Если колонка имеет формат даты и времени отличный от ISO8601, то для правильного перевода строки в нужный тип, можно использовать метод pandas.to_datetime.
Давайте теперь узнаем среднюю цену акции (mean) на закрытии (Close):
>>> df.loc['2012-Feb', 'Close'].mean() 528.4820021999999
А если взять промежуток с февраля 2012 по февраль 2015 и посчитать среднее:
>>> df.loc['2012-Feb':'2015-Feb', 'Close'].mean() 430.43968317018414
А что если нам нужно узнать среднюю цену закрытия по неделям?!
>>> df.resample('W')['Close'].mean() Date 2012-02-26 519.399979 2012-03-04 538.652008 2012-03-11 536.254004 2012-03-18 576.161993 2012-03-25 600.990001 2012-04-01 609.698003 2012-04-08 626.484993 2012-04-15 623.773999 2012-04-22 591.718002 2012-04-29 590.536005 2012-05-06 579.831995 2012-05-13 568.814001 2012-05-20 543.593996 2012-05-27 563.283995 2012-06-03 572.539994 2012-06-10 570.124002 2012-06-17 573.029991 2012-06-24 583.739993 2012-07-01 574.070004 2012-07-08 601.937489 2012-07-15 606.080008 2012-07-22 607.746011 2012-07-29 587.951999 2012-08-05 607.217999 2012-08-12 621.150003 2012-08-19 635.394003 2012-08-26 663.185999 2012-09-02 670.611995 2012-09-09 675.477503 2012-09-16 673.476007 . 2016-08-07 105.934003 2016-08-14 108.258000 2016-08-21 109.304001 2016-08-28 107.980000 2016-09-04 106.676001 2016-09-11 106.177498 2016-09-18 111.129999 2016-09-25 113.606001 2016-10-02 113.029999 2016-10-09 113.303999 2016-10-16 116.860000 2016-10-23 117.160001 2016-10-30 115.938000 2016-11-06 111.057999 2016-11-13 109.714000 2016-11-20 108.563999 2016-11-27 111.637503 2016-12-04 110.587999 2016-12-11 111.231999 2016-12-18 115.094002 2016-12-25 116.691998 2017-01-01 116.642502 2017-01-08 116.672501 2017-01-15 119.228000 2017-01-22 119.942499 2017-01-29 121.164000 2017-02-05 125.867999 2017-02-12 131.679996 2017-02-19 134.978000 2017-02-26 136.904999 Freq: W-SUN, Name: Close, dtype: float64
Resampling мощный инструмент при работе с временными рядами (time series), помогающий переформировать выборку так, как удобно вам. Метод resample первым аргументом принимает строку rule. Все доступные значения можно найти в документации.
Визуализация данных в pandas
Для визуального анализа данных, pandas использует библиотеку matplotlib. Продемонстрирую простейший способ визуализации в pandas на примере с акциями Apple.
Берём цену закрытия в промежутке между 2012 и 2017.
>>> import matplotlib.pyplot as plt >>> new_sample_df = df.loc['2012-Feb':'2017-Feb', ['Close']] >>> new_sample_df.plot() >>> plt.show()
И видим вот такую картину:

По оси X, если не задано явно, всегда будет индекс. По оси Y в нашем случае цена закрытия. Если внимательно посмотреть, то в 2014 году цена на акцию резко упала, это событие было связано с тем, что Apple проводила сплит 7 к 1. Так мало кода и уже более-менее наглядный анализ 😉
Эта заметка демонстрирует лишь малую часть возможностей pandas. Со своей стороны я постараюсь по мере своих сил обновлять и дополнять её.
Полезные ссылки
- pandas cheatsheet
- Официальная документация pandas
- Почему Python
- Python Data Science Handbook
Интересные записи:
- Что нового появилось в Django Channels?
- Почему Python?
- Руководство по работе с HTTP в Python. Библиотека requests
- Django Channels: работа с WebSocket и не только
- Celery: начинаем правильно
- FastAPI, asyncio и multiprocessing
- Обзор Python 3.9
- Работа с MySQL в Python
- Pyenv: удобный менеджер версий python
- Введение в logging на Python
- Python-RQ: очередь задач на базе Redis
- Работа с PostgreSQL в Python
- Как написать Telegram бота: практическое руководство
- Авторизация через Telegram в Django и Python
- Разворачиваем Django приложение в production на примере Telegram бота
- Django, RQ и FakeRedis
- Итоги первой встречи Python программистов в Алматы
- Обзор Python 3.8
- Интеграция Trix editor в Django
- Участие в подкасте TalkPython
- Строим Data Pipeline на Python и Luigi
- Видео презентации ETL на Python
- Авторизация через Telegram в Django приложении
Структуры данных в pandas / pd 2
Ядром pandas являются две структуры данных, в которых происходят все операции:
Series — это структура, используемая для работы с последовательностью одномерных данных, а Dataframe — более сложная и подходит для нескольких измерений.
Пусть они и не являются универсальными для решения всех проблем, предоставляют отличный инструмент для большинства приложений. При этом их легко использовать, а множество более сложных структур можно упросить до одной из этих двух.
Однако особенности этих структур основаны на одной черте — интеграции в их структуру объектов index и labels (метки). С их помощью структурами становится очень легко манипулировать.
Series (серии)
Series — это объект библиотеки pandas, спроектированный для представления одномерных структур данных, похожих на массивы, но с дополнительными возможностями. Его структура проста, ведь он состоит из двух связанных между собой массивов. Основной содержит данные (данные любого типа NumPy), а в дополнительном, index , хранятся метки.

Создание объекта Series
Для создания объекта Series с предыдущего изображения необходимо вызвать конструктор Series() и передать в качестве аргумента массив, содержащий значения, которые необходимо включить.
>>> s = pd.Series([12,-4,7,9]) >>> s 0 12 1 -4 2 7 3 9 dtype: int64
Как можно увидеть по выводу, слева отображаются значения индексов, а справа — сами значения (данные).
Если не определить индекс при объявлении объекта, метки будут соответствовать индексам (положению в массиве) элементов объекта Series .
Однако лучше создавать Series , используя метки с неким смыслом, чтобы в будущем отделять и идентифицировать данные вне зависимости от того, в каком порядке они хранятся.
В таком случае необходимо будет при вызове конструктора включить параметр index и присвоить ему массив строк с метками.
>>> s = pd.Series([12,-4,7,9], index=['a','b','c','d']) >>> s a 12 b -4 c 7 d 9 dtype: int64
Если необходимо увидеть оба массива, из которых состоит структура, можно вызвать два атрибута: index и values .
>>> s.values array([12, -4, 7, 9], dtype=int64) >>> s.index Index(['a', 'b', 'c', 'd'], dtype='object')
Выбор элементов по индексу или метке
Выбирать отдельные элементы можно по принципу обычных массивов numpy, используя для этого индекс.
>>> s[2] 7
Или же можно выбрать метку, соответствующую положению индекса.
>>> s['b'] -4
Таким же образом можно выбрать несколько элементов массива numpy с помощью следующей команды:
>>> s[0:2] a 12 b -4 dtype: int64
В этом случае можно использовать соответствующие метки, но указать их список в массиве.
>>> s[['b','c']] b -4 c 7 dtype: int64
Присваивание значений элементам
Понимая как выбирать отдельные элементы, важно знать и то, как присваивать им новые значения. Можно делать это по индексу или по метке.
>>> s[1] = 0 >>> s a 12 b 0 c 7 d 9 dtype: int64
>>> s['b'] = 1 >>> s a 12 b 1 c 7 d 9 dtype: int64
Создание Series из массивов NumPy
Новый объект Series можно создать из массивов NumPy и уже существующих Series .
>>> arr = np.array([1,2,3,4]) >>> s3 = pd.Series(arr) >>> s3 0 1 1 2 2 3 3 4 dtype: int32
>>> s4 = pd.Series(s) >>> s4 a 12 b 1 c 7 d 9 dtype: int64
Важно запомнить, что значения в массиве NumPy или оригинальном объекте Series не копируются, а передаются по ссылке. Это значит, что элементы объекта вставляются динамически в новый Series . Если меняется оригинальный объект, то меняются и его значения в новом.
>>> s3 0 1 1 2 2 3 3 4 dtype: int32
>>> arr[2] = -2 >>> s3 0 1 1 2 2 -2 3 4 dtype: int32
На этом примере можно увидеть, что при изменении третьего элемента массива arr , меняется соответствующий элемент и в s3 .
Фильтрация значений
Благодаря тому что основной библиотекой в pandas является NumPy, многие операции, применяемые к массивам NumPy, могут быть использованы и в случае с Series . Одна из таких — фильтрация значений в структуре данных с помощью условий.
Например, если нужно узнать, какие элементы в Series больше 8, то можно написать следующее:
>>> s[s > 8] a 12 d 9 dtype: int64
Операции и математические функции
Другие операции, такие как операторы ( +, -, * и / ), а также математические функции, работающие с массивами NumPy, могут использоваться и для Series .
Для операторов можно написать простое арифметическое уравнение.
>>> s / 2 a 6.0 b 0.5 c 3.5 d 4.5 dtype: float64
Но в случае с математическими функциями NumPy необходимо указать функцию через np , а Series передать в качестве аргумента.
>>> np.log(s) a 2.484907 b 0.000000 c 1.945910 d 2.197225 dtype: float64
Количество значений
В Series часто встречаются повторения значений. Поэтому важно иметь информацию, которая бы указывала на то, есть ли дубликаты или конкретное значение в объекте.
Так, можно объявить Series , в котором будут повторяющиеся значения.
>>> serd = pd.Series([1,0,2,1,2,3], index=['white','white','blue','green',' green','yellow']) >>> serd white 1 white 0 blue 2 green 1 green 2 yellow 3 dtype: int64
Чтобы узнать обо всех значениях в Series , не включая дубли, можно использовать функцию unique() . Возвращаемое значение — массив с уникальными значениями, необязательно в том же порядке.
>>> serd.unique() array([1, 0, 2, 3], dtype=int64)
На unique() похожа функция value_counts() , которая возвращает не только уникальное значение, но и показывает, как часто элементы встречаются в Series .
>>> serd.value_counts() 2 2 1 2 3 1 0 1 dtype: int64
Наконец, isin() показывает, есть ли элементы на основе списка значений. Она возвращает булевые значения, которые очень полезны при фильтрации данных в Series или в колонке Dataframe .
>>> serd.isin([0,3]) white False white True blue False green False green False yellow True dtype: bool
>>> serd[serd.isin([0,3])] white 0 yellow 3 dtype: int64
Значения NaN
В предыдущем примере мы попробовали получить логарифм отрицательного числа и результатом стало значение NaN . Это значение (Not a Number) используется в структурах данных pandas для обозначения наличия пустого поля или чего-то, что невозможно обозначить в числовой форме.
Как правило, NaN — это проблема, для которой нужно найти определенное решение, особенно при работе с анализом данных. Эти данные часто появляются при извлечении информации из непроверенных источников или когда в самом источнике недостает данных. Также значения NaN могут генерироваться в специальных случаях, например, при вычислении логарифмов для отрицательных значений, в случае исключений при вычислениях или при использовании функций. Есть разные стратегии работы со значениями NaN .
Несмотря на свою «проблемность» pandas позволяет явно определять NaN и добавлять это значение в структуры, например, в Series . Для этого внутри массива достаточно ввести np.NaN в том месте, где требуется определить недостающее значение.
>>> s2 = pd.Series([5,-3,np.NaN,14]) >>> s2 0 5.0 1 -3.0 2 NaN 3 14.0 dtype: float64
Функции isnull() и notnull() очень полезны для определения индексов без значения.
>>> s2.isnull() 0 False 1 False 2 True 3 False dtype: bool
>>> s2.notnull() 0 True 1 True 2 False 3 True dtype: bool
Они возвращают два объекта Series с булевыми значениями, где True указывает на наличие значение, а NaN — на его отсутствие. Функция isnull() возвращает True для значений NaN в Series , а notnull() — True в тех местах, где значение не равно NaN . Эти функции часто используются в фильтрах для создания условий.
>>> s2[s2.notnull()] 0 5.0 1 -3.0 3 14.0 dtype: float64
s2[s2.isnull()] 2 NaN dtype: float64
Series из словарей
Series можно воспринимать как объект dict (словарь). Эта схожесть может быть использована на этапе объявления объекта. Даже создавать Series можно на основе существующего dict .
>>> mydict = 'red': 2000, 'blue': 1000, 'yellow': 500, 'orange': 1000> >>> myseries = pd.Series(mydict) >>> myseries blue 1000 orange 1000 red 2000 yellow 500 dtype: int64
На этом примере можно увидеть, что массив индексов заполнен ключами, а данные — соответствующими значениями. В таком случае соотношение будет установлено между ключами dict и метками массива индексов. Если есть несоответствие, pandas заменит его на NaN .
>>> colors = ['red','yellow','orange','blue','green'] >>> myseries = pd.Series(mydict, index=colors) >>> myseries red 2000.0 yellow 500.0 orange 1000.0 blue 1000.0 green NaN dtype: float64
Операции с сериями
Вы уже видели, как выполнить арифметические операции на объектах Series и скалярных величинах. То же возможно и для двух объектов Series , но в таком случае в дело вступают и метки.
Одно из главных достоинств этого типа структур данных в том, что он может выравнивать данные, определяя соответствующие метки.
В следующем примере добавляются два объекта Series , у которых только некоторые метки совпадают.
>>> mydict2 = 'red':400,'yellow':1000,'black':700> >>> myseries2 = pd.Series(mydict2) >>> myseries + myseries2 black NaN blue NaN green NaN orange NaN red 2400.0 yellow 1500.0 dtype: float64
Новый объект получает только те элементы, где метки совпали. Все остальные тоже присутствуют, но со значением NaN.
DataFrame (датафрейм)
Dataframe — это табличная структура данных, напоминающая таблицы из Microsoft Excel. Ее главная задача — позволить использовать многомерные Series . Dataframe состоит из упорядоченной коллекции колонок, каждая из которых содержит значение разных типов (числовое, строковое, булевое и так далее).

В отличие от Series у которого есть массив индексов с метками, ассоциированных с каждым из элементов, Dataframe имеет сразу два таких. Первый ассоциирован со строками (рядами) и напоминает таковой из Series . Каждая метка ассоциирована со всеми значениями в ряду. Второй содержит метки для каждой из колонок.
Dataframe можно воспринимать как dict , состоящий из Series , где ключи — названия колонок, а значения — объекты Series , которые формируют колонки самого объекта Dataframe . Наконец, все элементы в каждом объекте Series связаны в соответствии с массивом меток, называемым index .
Создание Dataframe
Простейший способ создания Dataframe — передать объект dict в конструктор DataFrame() . Объект dict содержит ключ для каждой колонки, которую требуется определить, а также массив значений для них.
Если объект dict содержит больше данных, чем требуется, можно сделать выборку. Для этого в конструкторе Dataframe нужно определить последовательность колонок с помощью параметра column . Колонки будут созданы в заданном порядке вне зависимости от того, как они расположены в объекте dict .
>> data = 'color' : ['blue', 'green', 'yellow', 'red', 'white'], 'object' : ['ball', 'pen', 'pencil', 'paper', 'mug'], 'price' : [1.2, 1.0, 0.6, 0.9, 1.7]> >>> frame = pd.DataFrame(data) >>> frame
| color | object | price | |
|---|---|---|---|
| 0 | blue | ball | 1.2 |
| 1 | green | pen | 1.0 |
| 2 | yellow | pencil | 0.6 |
| 3 | red | paper | 0.9 |
| 4 | white | mug | 1.7 |
Даже для объектов Dataframe если метки явно не заданы в массиве index , pandas автоматически присваивает числовую последовательность, начиная с нуля. Если же индексам Dataframe нужно присвоить метки, необходимо использовать параметр index и присвоить ему массив с метками.
>>> frame2 = pd.DataFrame(data, columns=['object', 'price']) >>> frame2
| object | price | |
|---|---|---|
| 0 | ball | 1.2 |
| 1 | pen | 1.0 |
| 2 | pencil | 0.6 |
| 3 | paper | 0.9 |
| 4 | mug | 1.7 |
Теперь, зная о параметрах index и columns , проще использовать другой способ определения Dataframe . Вместо использования объекта dict можно определить три аргумента в конструкторе в следующем порядке: матрицу данных, массив значений для параметра index и массив с названиями колонок для параметра columns .
В большинстве случаев простейший способ создать матрицу значений — использовать np.arrange(16).reshape((4,4)) . Это формирует матрицу размером 4х4 из чисел от 0 до 15.
>>> frame3 = pd.DataFrame(np.arange(16).reshape((4,4)), ... index=['red', 'blue', 'yellow', 'white'], ... columns=['ball', 'pen', 'pencil', 'paper']) >>> frame3
Выбор элементов
Если нужно узнать названия всех колонок Dataframe , можно вызвать атрибут columns для экземпляра объекта.
>>> frame.columns Index(['color', 'object', 'price'], dtype='object')
То же можно проделать и для получения списка индексов.
>>> frame.index RangeIndex(start=0, stop=5, step=1)
Весь же набор данных можно получить с помощью атрибута values .
>>> frame.values array([['blue', 'ball', 1.2], ['green', 'pen', 1.0], ['yellow', 'pencil', 0.6], ['red', 'paper', 0.9], ['white', 'mug', 1.7]], dtype=object)
Указав в квадратных скобках название колонки, можно получить значений в ней.
>>> frame['price'] 0 1.2 1 1.0 2 0.6 3 0.9 4 1.7 Name: price, dtype: float64
Возвращаемое значение — объект Series . Название колонки можно использовать и в качестве атрибута.
>>> frame.price 0 1.2 1 1.0 2 0.6 3 0.9 4 1.7 Name: price, dtype: float64
Для строк внутри Dataframe используется атрибут loc со значением индекса нужной строки.
>>> frame.loc[2] color yellow object pencil price 0.6 Name: 2, dtype: object
Возвращаемый объект — это снова Series , где названия колонок — это уже метки массива индексов, а значения — данные Series .
Для выбора нескольких строк можно указать массив с их последовательностью.
>>> frame.loc[[2,4]]
| color | object | price | |
|---|---|---|---|
| 2 | yellow | pencil | 0.6 |
| 4 | white | mug | 1.7 |
Если необходимо извлечь часть Dataframe с конкретными строками, для этого можно использовать номера индексов. Она выведет данные из соответствующей строки и названия колонок.
>>> frame[0:1]
| color | object | price | |
|---|---|---|---|
| 2 | yellow | pencil | 0.6 |
| 4 | white | mug | 1.7 |
Возвращаемое значение — объект Dataframe с одной строкой. Если нужно больше одной строки, необходимо просто указать диапазон.
>>> frame[1:3]
| color | object | price | |
|---|---|---|---|
| 0 | blue | ball | 1.2 |
Наконец, если необходимо получить одно значение из объекта, сперва нужно указать название колонки, а потом — индекс или метку строки.
>>> frame['object'][3] 'paper'
Присваивание и замена значений
Разобравшись с логикой получения доступа к разным элементам Dataframe , можно следовать ей же для добавления новых или изменения уже существующих значений.
Например, в структуре Dataframe массив индексов определен атрибутом index , а строка с названиями колонок — columns . Можно присвоить метку с помощью атрибута name для этих двух подструктур, чтобы идентифицировать их.
>>> frame.index.name = 'id' >>> frame.columns.name = 'item' >>> frame
| item | color | object | price |
|---|---|---|---|
| id | |||
| 0 | blue | ball | 1.2 |
| 1 | green | pen | 1.0 |
| 2 | yellow | pencil | 0.6 |
| 3 | red | paper | 0.9 |
| 4 | white | mug | 1.7 |
Одна из главных особенностей структур данных pandas — их гибкость. Можно вмешаться на любом уровне для изменения внутренней структуры данных. Например, добавление новой колонки — крайне распространенная операция.
Ее можно выполнить, присвоив значение экземпляру Dataframe и определив новое имя колонки.
>>> frame['new'] = 12 >>> frame
| item | color | object | price | new |
|---|---|---|---|---|
| id | ||||
| 0 | blue | ball | 1.2 | 12 |
| 1 | green | pen | 1.0 | 12 |
| 2 | yellow | pencil | 0.6 | 12 |
| 3 | red | paper | 0.9 | 12 |
| 4 | white | mug | 1.7 | 12 |
Здесь видно, что появилась новая колонка new со значениями 12 для каждого элемента.
Для обновления значений можно использовать массив.
frame['new'] = [3.0, 1.3, 2.2, 0.8, 1.1] frame
| item | color | object | price | new |
|---|---|---|---|---|
| id | ||||
| 0 | blue | ball | 1.2 | 3.0 |
| 1 | green | pen | 1.0 | 1.3 |
| 2 | yellow | pencil | 0.6 | 2.2 |
| 3 | red | paper | 0.9 | 0.8 |
| 4 | white | mug | 1.7 | 1.1 |
Тот же подход используется для обновления целой колонки. Например, можно применить функцию np.arrange() для обновления значений колонки с помощью заранее заданной последовательности.
Колонки Dataframe также могут быть созданы с помощью присваивания объекта Series одной из них, например, определив объект Series , содержащий набор увеличивающихся значений с помощью np.arrange() .
>>> ser = pd.Series(np.arange(5)) >>> ser 0 0 1 1 2 2 3 3 4 4 dtype: int32
frame['new'] = ser frame
| item | color | object | price | new |
|---|---|---|---|---|
| id | ||||
| 0 | blue | ball | 1.2 | 0 |
| 1 | green | pen | 1.0 | 1 |
| 2 | yellow | pencil | 0.6 | 2 |
| 3 | red | paper | 0.9 | 3 |
| 4 | white | mug | 1.7 | 4 |
Наконец, для изменения одного значения нужно лишь выбрать элемент и присвоить ему новое значение.
>>> frame['price'][2] = 3.3
Вхождение значений
Функция isin() используется с объектами Series для определения вхождения значений в колонку. Она же подходит и для объектов Dataframe .
>>> frame.isin([1.0,'pen'])
| item | color | object | price | new |
|---|---|---|---|---|
| id | ||||
| 0 | False | False | False | False |
| 1 | False | True | True | True |
| 2 | False | False | False | False |
| 3 | False | False | False | False |
| 4 | False | False | False | False |
Возвращается Dataframe с булевыми значениями, где True указывает на те значения, где членство подтверждено. Если передать это значение в виде условия, тогда вернется Dataframe , где будут только значения, удовлетворяющие условию.
>>> frame[frame.isin([1.0,'pen'])]
| item | color | object | price | new |
|---|---|---|---|---|
| id | ||||
| 0 | NaN | NaN | NaN | NaN |
| 1 | NaN | pen | 1.0 | 1.0 |
| 2 | NaN | NaN | NaN | NaN |
| 3 | NaN | NaN | NaN | NaN |
| 4 | NaN | NaN | NaN | NaN |
Удаление колонки
Для удаления целой колонки и всего ее содержимого используется команда del .
>>> del frame['new'] >>> frame
| item | color | object | price |
|---|---|---|---|
| id | |||
| 0 | blue | ball | 1.2 |
| 1 | green | pen | 1.0 |
| 2 | yellow | pencil | 3.3 |
| 3 | red | paper | 0.9 |
| 4 | white | mug | 1.7 |
Фильтрация
Даже для Dataframe можно применять фильтры, используя определенные условия. Например, вам нужно получить все значения меньше определенного числа (допустим, 1,2).
>>> frame[frame 1.2]
| item | color | object | price |
|---|---|---|---|
| id | |||
| 0 | blue | ball | NaN |
| 1 | green | pen | 1.0 |
| 2 | yellow | pencil | NaN |
| 3 | red | paper | 0.9 |
| 4 | white | mug | NaN |
Результатом будет Dataframe со значениями меньше 1,2 на своих местах. На месте остальных будет NaN .
Dataframe из вложенного словаря
В Python часто используется вложенный dict :
>>> nestdict = 'red': 2012: 22, 2013: 33>, ... 'white': 2011: 13, 2012: 22, 2013: 16>, ... 'blue': 2011: 17, 2012: 27, 2013: 18>>
Эта структура данных, будучи переданной в качестве аргумента в DataFrame() , интерпретируется pandas так, что внешние ключи становятся названиями колонок, а внутренние — метками индексов.
При интерпретации вложенный структуры возможно такое, что не все поля будут совпадать. pandas компенсирует это несоответствие, добавляя NaN на место недостающих значений.
>>> nestdict = 'red': 2012: 22, 2013: 33>, ... 'white': 2011: 13, 2012: 22, 2013: 16>, ... 'blue': 2011: 17, 2012: 27, 2013: 18>> >>> frame2 = pd.DataFrame(nestdict) >>> frame2
| blue | red | white | |
|---|---|---|---|
| 2011 | 17 | NaN | 13 |
| 2012 | 27 | 22.0 | 22 |
| 2013 | 18 | 33.0 | 16 |
Транспонирование Dataframe
При работе с табличным структурами данных иногда появляется необходимость выполнить операцию перестановки (сделать так, чтобы колонки стали рядами и наоборот). pandas позволяет добиться этого очень просто. Достаточно добавить атрибут T .
>>> frame2.T
| 2011 | 2012 | 2013 | |
|---|---|---|---|
| blue | 17.0 | 27.0 | 18.0 |
| red | NaN | 22.0 | 33.0 |
| white | 13.0 | 22.0 | 16.0 |
Объекты Index
Зная, что такое Series и Dataframes , и понимая как они устроены, проще разобраться со всеми их достоинствами. Главная особенность этих структур — наличие объекта Index , который в них интегрирован.
Объекты Index являются метками осей и содержат другие метаданные. Вы уже знаете, как массив с метками превращается в объект Index , и что для него нужно определить параметр index в конструкторе.
>>> ser = pd.Series([5,0,3,8,4], index=['red','blue','yellow','white','green']) >>> ser.index Index(['red', 'blue', 'yellow', 'white', 'green'], dtype='object')
В отличие от других элементов в структурах данных pandas ( Series и Dataframe ) объекты index — неизменяемые. Это обеспечивает безопасность, когда нужно передавать данные между разными структурами.
У каждого объекта Index есть методы и свойства, которые нужны, чтобы узнавать значения.
Методы Index
Есть методы для получения информации об индексах из структуры данных. Например, idmin() и idmax() — структуры, возвращающие индексы с самым маленьким и большим значениями.
>>> ser.idxmin() 'blue' >>> ser.idxmax() 'white'
Индекс с повторяющимися метками
Пока что были только те случаи, когда у индексов одной структуры лишь одна, уникальная метка. Для большинства функций это обязательное условие, но не для структур данных pandas.
Определим, например, Series с повторяющимися метками.
>>> serd = pd.Series(range(6), index=['white','white','blue','green', 'green','yellow']) >>> serd white 0 white 1 blue 2 green 3 green 4 yellow 5 dtype: int64
Если метке соответствует несколько значений, то она вернет не один элемент, а объект Series .
>>> serd['white'] white 0 white 1 dtype: int64
То же применимо и к Dataframe . При повторяющихся индексах он возвращает Dataframe .
В случае с маленькими структурами легко определять любые повторяющиеся индексы, но если структура большая, то растет и сложность этой операции. Для этого в pandas у объектов Index есть атрибут is_unique . Он сообщает, есть ли индексы с повторяющимися метками в структуре ( Series или Dataframe ).
>>> serd.index.is_unique False >>> frame.index.is_unique True
Операции между структурами данных
Теперь когда вы знакомы со структурами данных, Series и Dataframe , а также базовыми операциями для работы с ними, стоит рассмотреть операции, включающие две или более структур.
Гибкие арифметические методы
Уже рассмотренные операции можно выполнять с помощью гибких арифметических методов:
Для их вызова нужно использовать другую спецификацию. Например, вместо того чтобы выполнять операцию для двух объектов Dataframe по примеру frame1 + frame2 , потребуется следующий формат:
>>> frame1.add(frame2)
| ball | mug | paper | pen | pencil | |
|---|---|---|---|---|---|
| blue | 6.0 | NaN | NaN | 6.0 | NaN |
| green | NaN | NaN | NaN | NaN | NaN |
| red | NaN | NaN | NaN | NaN | NaN |
| white | 20.0 | NaN | NaN | 20.0 | NaN |
| yellow | 19.0 | NaN | NaN | 19.0 | NaN |
Результат такой же, как при использовании оператора сложения + . Также стоит обратить внимание, что если названия индексов и колонок сильно отличаются, то результатом станет новый объект Dataframe , состоящий только из значений NaN .
Операции между Dataframe и Series
Pandas позволяет выполнять переносы между разными структурами, например, между Dataframe и Series . Определить две структуры можно следующим образом.
>>> frame = pd.DataFrame(np.arange(16).reshape((4,4)), ... index=['red', 'blue', 'yellow', 'white'], ... columns=['ball','pen','pencil','paper']) >>> frame
| ball | pen | pencil | paper | |
|---|---|---|---|---|
| red | 0 | 1 | 2 | 3 |
| blue | 4 | 5 | 6 | 7 |
| yellow | 8 | 9 | 10 | 11 |
| white | 12 | 13 | 14 | 15 |
>>> ser = pd.Series(np.arange(4), index=['ball','pen','pencil','paper']) >>> ser ball 0 pen 1 pencil 2 paper 3 dtype: int32
Они были специально созданы так, чтобы индексы в Series совпадали с названиями колонок в Dataframe . В таком случае можно выполнить прямую операцию.
>>> frame - ser
| ball | pen | pencil | paper | |
|---|---|---|---|---|
| red | 0 | 0 | 0 | 0 |
| blue | 4 | 4 | 4 | 4 |
| yellow | 8 | 8 | 8 | 8 |
| white | 12 | 12 | 12 | 12 |
По результату видно, что элементы Series были вычтены из соответствующих тому же индексу в колонках значений Dataframe .
Если индекс не представлен ни в одной из структур, то появится новая колонка с этим индексом и значениями NaN .
>>> ser['mug'] = 9 >>> ser ball 0 pen 1 pencil 2 paper 3 mug 9 dtype: int64
>>> frame - ser
| ball | mug | paper | pen | pencil | |
|---|---|---|---|---|---|
| red | 0 | NaN | 0 | 0 | 0 |
| blue | 4 | NaN | 4 | 4 | 4 |
| yellow | 8 | NaN | 8 | 8 | 8 |
| white | 12 | NaN | 12 | 12 | 12 |
Python 3 Pandas: Объекты Series и DataFrame. Построение Index

Pandas — более новый пакет, надстройка над библиотекой NumPy, обеспечивающий эффективную реализацию класса DataFrame.
Объекты DataFrame — многомерные массивы с метками для строк и столбцов, а также зачастую с неоднородным типом данных и/или пропущенными данными.
Помимо удобного интерфейса для хранения маркированных данных, библиотека Pandas реализует множество операций для работы с данными хорошо знакомых пользователям фреймворков баз данных и электронных таблиц.
Импорт библиотек NumPy и Pandas
На самом примитивном уровне объекты библиотеки Pandas можно считать расширенной версией структурированных массивов библиотеки NumPy, в которых строки и столбцы идентифицируются метками, а не простыми числовыми индексами. Библиотека Pandas предоставляет множество полезных утилит, методов и функциональности в дополнение к базовым структурам данных, но все последующее изложение потребует понимания этих базовых структур. Позвольте познакомить вас с тремя фундаментальными структурами данных библиотеки Pandas: классами Series, DataFrame и Index.
Начнем наш сеанс программирования с обычных импортов библиотек NumPy и Pandas:
import numpy as np import pandas as pd
Объект Series библиотеки Pandas
Объект Series библиотеки Pandas — одномерный массив индексированных данных. Его можно создать из списка или массива следующим образом:
import numpy as np import pandas as pd data = pd.Series([0.25, 0.5, 0.75, 1.0]) print(data)
Результат:

Как мы видели из предыдущего результата, объект Series служит адаптером как для последовательности значений, так и последовательности индексов, к которым можно получить доступ посредством атрибутов values и index. Атрибут values представляет собой массив NumPy:
import numpy as np import pandas as pd data = pd.Series([0.25, 0.5, 0.75, 1.0]) print(data.values)
Результат:
[0.25 0.5 0.75 1. ]
Index — массивоподобный объект типа pd.Index:
import numpy as np import pandas as pd data = pd.Series([0.25, 0.5, 0.75, 1.0]) print(data.index)
Результат:
RangeIndex(start=0, stop=4, step=1)
Аналогично массивам библиотеки NumPy, к данным можно обращаться по соответствующему им индексу посредством нотации с использованием квадратных скобок языка Python:
import numpy as np import pandas as pd data = pd.Series([0.25, 0.5, 0.75, 1.0]) print('data[1]:') print(data[1]) print('data[1:3]:') print(data[1:3])
Результат:
data[1]: 0.5 data[1:3]: 1 0.50 2 0.75 dtype: float64
Однако объект Series библиотеки Pandas намного универсальнее и гибче, чем эмулируемый им одномерный массив библиотеки NumPy.
Объект Series как обобщенный массив NumPy
Может показаться, что объект Series и одномерный массив библиотеки NumPy взаимозаменяемы. Основное различие между ними — индекс. В то время как индекс массива NumPy, используемый для доступа к значениям, — целочисленный и описывается неявно, индекс объекта Series библиотеки Pandas описывается явно и связывается со значениями.
Явное описание индекса расширяет возможности объекта Series. Такой индекс не должен быть целым числом, а может состоять из значений любого нужного типа. Например, при желании мы можем использовать в качестве индекса строковые значения:
import numpy as np import pandas as pd data = pd.Series([0.25, 0.5, 0.75, 1.0], index=['a', 'b', 'c', 'd']) print(data)
Результат:
a 0.25 b 0.50 c 0.75 d 1.00 dtype: float64
При этом доступ к элементам работает обычным образом:
import numpy as np import pandas as pd data = pd.Series([0.25, 0.5, 0.75, 1.0], index=['a', 'b', 'c', 'd']) print(data['b'])
Результат:
Объект Series как специализированный словарь
Объект Series библиотеки Pandas можно рассматривать как специализированную разновидность словаря языка Python. Словарь — структура, задающая соответствие произвольных ключей набору произвольных значений, а объект Series — структура, задающая соответствие типизированных ключей набору типизированных значений.
Типизация важна: точно так же, как соответствующий типу специализированный код для массива библиотеки NumPy при выполнении определенных операций делает его эффективнее, чем стандартный список Python, информация о типе в объекте Series библиотеки Pandas делает его намного более эффективным для определенных операций, чем словари Python.
Можно сделать аналогию «объект Series — словарь» еще более наглядной, сконструировав объект Series непосредственно из словаря Python.
По умолчанию при этом будет создан объект Series с полученным из отсортированных ключей индексом. Следовательно, для него возможен обычный доступ к элементам, такой же, как для словаря. Объект Series поддерживает операции «срезы».
import numpy as np import pandas as pd # Словарь population_dict = population = pd.Series(population_dict) print('population:') print(population) # Доступ к элементам print("population['California']:") print(population['California']) # Срез print("population['California':'New York']:") print(population['California':'New York'])
Результат:
population: California 38332521 Texas 26448193 New York 19651127 Florida 19552860 Illinois 12882135 dtype: int64 population['California']: 38332521 population['California':'New York']: California 38332521 Texas 26448193 New York 19651127 dtype: int64
Создание объектов Series
Мы уже изучили несколько способов создания объектов Series библиотеки Pandas с нуля.
Все они представляют собой различные варианты следующего синтаксиса Pandas Series (общий вид синтаксиса):
pd.Series(data, index=index)
где index — необязательный аргумент, а data может быть одной из множества сущностей.
Например, аргумент data может быть списком или массивом NumPy. В этом случае index по умолчанию будет целочисленной последовательностью:
import pandas as pd data = pd.Series([2, 4, 6]) print(data)
Результат:
0 2 1 4 2 6 dtype: int64
Аргумент data может быть скалярным значением, которое будет повторено нужное количество раз для заполнения заданного индекса:
import pandas as pd data = pd.Series(5, index=[100, 200, 300]) print(data)
Результат:
100 5 200 5 300 5 dtype: int64
Аргумент data может быть словарем, в котором index по умолчанию является отсортированными ключами этого словаря:
import pandas as pd data = pd.Series() print(data)
Результат:
2 a 1 b 3 c dtype: object
В каждом случае индекс можно указать вручную, если необходимо получить другой результат:
import pandas as pd data = pd.Series(, index=[3, 2]) print(data)
Результат:
3 c 2 a dtype: object
Обратите внимание, что объект Series заполняется только заданными явным образом ключами.
Объект DataFrame библиотеки Pandas
Следующая базовая структура библиотеки Pandas — объект DataFrame. Как и объект Series, объект DataFrame можно рассматривать или как обобщение массива NumPy, или как специализированную версию словаря Python. Изучим оба варианта.
DataFrame как обобщенный массив NumPy
Если объект Series — аналог одномерного массива с гибкими индексами, объект DataFrame — аналог двумерного массива с гибкими индексами строк и гибкими именами столбцов. Аналогично тому, что двумерный массив можно рассматривать как упорядоченную последовательность выровненных столбцов, объект DataFrame можно рассматривать как упорядоченную последовательность выровненных объектов Series. Под «выровненными» имеется в виду то, что они используют один и тот же индекс.
Чтобы продемонстрировать это, сначала создадим новый объект Series, содержащий площадь каждого из пяти упомянутых в предыдущем разделе штатов:
import pandas as pd area_dict = area = pd.Series(area_dict) print(area)
Результат:
California 423967 Texas 695662 New York 141297 Florida 170312 Illinois 149995 dtype: int64
Воспользовавшись объектом population класса Series, сконструируем на основе словаря единый двумерный объект, содержащий всю эту информацию:
import pandas as pd # Словарь площадь штатов area_dict = area = pd.Series(area_dict) # Словарь население population_dict = population = pd.Series(population_dict) # Создаем DataFrame states = pd.DataFrame() print(states)
Результат:
population area California 38332521 423967 Texas 26448193 695662 New York 19651127 141297 Florida 19552860 170312 Illinois 12882135 149995
Аналогично объекту Series у объекта DataFrame имеется атрибут index, обеспечивающий доступ к меткам индекса. Еще у объекта DataFrame есть атрибут columns, представляющий собой содержащий метки столбцов объект Index.
import pandas as pd # Словарь площадь штатов area_dict = area = pd.Series(area_dict) # Словарь население population_dict = population = pd.Series(population_dict) # Создаем DataFrame states = pd.DataFrame() print('Индексы - states.index:') print(states.index) print('') print('Колонки - states.columns:') print(states.columns)
Результат:
Индексы - states.index: Index(['California', 'Texas', 'New York', 'Florida', 'Illinois'], dtype='object') Колонки - states.columns: Index(['population', 'area'], dtype='object')
Таким образом, объект DataFrame можно рассматривать как обобщение двумерного массива NumPy, где как у строк, так и у столбцов есть обобщенные индексы для доступа к данным.
Объект DataFrame как специализированный словарь
DataFrame можно рассматривать как специализированный словарь. Если словарь задает соответствие ключей значениям, то DataFrame задает соответствие имени столбца объекту Series с данными этого столбца. Например, запрос данных по атрибуту ‘area’ приведет к тому, что будет возвращен объект Series, содержащий площади штатов:
import pandas as pd # Словарь площадь штатов area_dict = area = pd.Series(area_dict) # Словарь население population_dict = population = pd.Series(population_dict) # Создаем DataFrame states = pd.DataFrame() print(states['area'])
Результат:
California 423967 Texas 695662 New York 141297 Florida 170312 Illinois 149995 Name: area, dtype: int64
Создание объектов DataFrame
Существует множество способов создания объектов DataFrame библиотеки Pandas. Вот несколько примеров.
Из одного объекта Series
Объект DataFrame — набор объектов Series.
DataFrame, состоящий из одного столбца, можно создать на основе одного объекта Series:
import pandas as pd # Словарь население population_dict = population = pd.Series(population_dict) df = pd.DataFrame(population, columns=['population']) print(df)
Результат:
population California 38332521 Texas 26448193 New York 19651127 Florida 19552860 Illinois 12882135
Из списка словарей
Любой список словарей можно преобразовать в объект DataFrame. Мы воспользуемся простым списковым включением для создания данных:
import pandas as pd data = [ for i in range(3)] print('data:') print(data) print('') df = pd.DataFrame(data) print('df:') print(df)
Результат:
data: [, , ] df: a b 0 0 0 1 1 2 2 2 4
Даже если некоторые ключи в словаре отсутствуют, библиотека Pandas просто заполнит их значениями NaN (то есть Not a number — «не является числом»):
import pandas as pd df = pd.DataFrame([, ]) print('df:') print(df)
Результат:
df: a b c 0 1.0 2 NaN 1 NaN 3 4.0
Из словаря объектов Series
Объект DataFrame также можно создать на основе словаря объектов Series (этот пример был приведен ранее):
import pandas as pd # Словарь площадь штатов area_dict = area = pd.Series(area_dict) # Словарь население population_dict = population = pd.Series(population_dict) # Создаем DataFrame df = pd.DataFrame() print(df)
Результат:
population area California 38332521 423967 Texas 26448193 695662 New York 19651127 141297 Florida 19552860 170312 Illinois 12882135 149995
Из двумерного массива NumPy
Если у нас есть двумерный массив данных, мы можем создать объект DataFrame с любыми заданными именами столбцов и индексов. Для каждого из пропущенных значений будет использоваться целочисленный индекс:
import numpy as np import pandas as pd df = pd.DataFrame(np.random.rand(3, 2), columns=['foo', 'bar'], index=['a', 'b', 'c']) print(df)
Результат:
foo bar a 0.290872 0.647270 b 0.690850 0.950563 c 0.468706 0.344193
Из структурированного массива NumPy
Объект DataFrame библиотеки Pandas ведет себя во многом аналогично структурированному массиву библиотеки NumPy и может быть создан непосредственно из него:
import numpy as np import pandas as pd A = np.zeros(3, dtype=[('A', 'i8'), ('B', 'f8')]) print('A:') print(A) print('') df = pd.DataFrame(A) print('df:') print(df)
Результат:
A: [(0, 0.) (0, 0.) (0, 0.)] df: A B 0 0 0.0 1 0 0.0 2 0 0.0
Объект Index библиотеки Pandas
Как объект Series, так и объект DataFrame содержат явный индекс, обеспечивающий возможность ссылаться на данные и модифицировать их.
Объект Index можно рассматривать или как неизменяемый массив (immutable array), или как упорядоченное множество (ordered set) (формально мультимножество, так как объекты Index могут содержать повторяющиеся значения). Из этих способов его представления следуют некоторые интересные возможности операций над объектами Index. В качестве простого примера создадим Index из списка целых чисел:
import pandas as pd ind = pd.Index([2, 3, 5, 7, 11]) print(ind)
Результат:
Int64Index([2, 3, 5, 7, 11], dtype='int64')
Объект Index как неизменяемый массив
Объект Index во многом ведет себя аналогично массиву. Например, для извлечения из него значений или срезов можно использовать стандартную нотацию индексации языка Python. У объектов Index есть много атрибутов.
Результат:
ind[1] 3 ind[::2] Int64Index([2, 5, 11], dtype='int64') ind.size, ind.shape, ind.ndim, ind.dtype 5 (5,) 1 int64
Одно из различий между объектами Index и массивами NumPy — неизменяемость индексов, то есть их нельзя модифицировать стандартными средствами:
import pandas as pd ind = pd.Index([2, 3, 5, 7, 11]) ind[1] = 0
Результат:
Traceback (most recent call last): File "C:/Users/User/Desktop/test.py", line 4, in ind[1] = 0 File "C:\Users\User\AppData\Local\Programs\Python\Python37-32\lib\site-packages\pandas\core\indexes\base.py", line 3938, in __setitem__ raise TypeError("Index does not support mutable operations") TypeError: Index does not support mutable operations
Неизменяемость делает безопаснее совместное использование индексов несколькими объектами DataFrame и массивами, исключая возможность побочных эффектов в виде случайной модификации индекса по неосторожности.
Выбор подмножеств данных в Pandas
Анатомия Python Pandas DataFrame — Column, Index, Data
Рассмотрим изображение контейнера данных DataFrame (библиотеки Pandas):

Три компонента DataFrame:
DataFrame состоит из трех различных компонентов: индекса , столбцов и данных. Данные также известны как значения.
Индекс — это последовательность значений в левой части DataFrame. Каждое отдельное значение индекса называется index label, Иногда индекс упоминается как заголовки строк. В приведенном выше примере метки строк не очень интересны и представляют собой целые числа, начиная с 0 до n-1, где n — количество строк в таблице.
Столбцы представляют собой последовательность значений в самой верхней части DataFrame.
Все остальное является данными или значениями. Иногда вы будете слышать, как датафреймы называют табличными данными. Это просто еще одно имя для данных прямоугольной таблицы со строками и столбцами.
Каждая строка имеет метку, каждая колонка имеет метку
Основной вывод из анатомии DataFrame заключается в том, что каждая строка имеет метку, каждый столбец имеет метку. Эти метки используются для ссылки на конкретные строки или столбцы в DataFrame.
Что такое выбор подмножества?
Прежде чем мы начнем делать выбор подмножества, было бы хорошо определить, что это такое. Выбор подмножества — это просто выбор определенных строк и столбцов данных из DataFrame (или Series). Это может означать выбор всех строк и некоторых столбцов, некоторых строк и всех столбцов или некоторых строк и столбцов.
Выбор при помощи []
Загружаем данные из CSV в Pandas DataFrame (Python 3)
В совокупности [], .loc и .iloc называются индексаторами. Это самые распространенные способы выбора данных.
Скачать файл для использования в примерах:
Код загрузки данных из csv в Pandas DataFrame:
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';', index_col=0) print(df)
Результат:

Вариант 2 загрузки данных из CSV (Index генерируется самостоятельно)
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') print(df)
Результат:

Извлечение отдельных компонентов DataFrame
Ранее мы упоминали три компоненты DataFrame. Индекс, столбцы и данные (значения). Мы можем извлечь каждый из этих компонентов в свои переменные. Давайте сделаем это, а затем осмотрим их:
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') index = df.index columns = df.columns values = df.values index_list = df.index.tolist() columns_list = df.columns.tolist() values_list = df.values.tolist() print('+++++ БЕЗ TOLIST() +++++') print(index) print('==========================') print(columns) print('==========================') print(values) print('==========================') print('+++++ С TOLIST() +++++') print(index_list) print('==========================') print(columns_list) print('==========================') print(values_list)
Результат:

Типы данных компонентов
Давайте выведем тип каждого компонента, чтобы точно понять, что это за объект.
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') index = df.index columns = df.columns values = df.values index_list = df.index.tolist() columns_list = df.columns.tolist() values_list = df.values.tolist() print('+++++ БЕЗ TOLIST() +++++') print(type(index)) print('==========================') print(type(columns)) print('==========================') print(type(values)) print('==========================') print('+++++ С TOLIST() +++++') print(type(index_list)) print('==========================') print(type(columns_list)) print('==========================') print(type(values_list))
Результат:
+++++ БЕЗ TOLIST() +++++ ========================== ========================== ========================== +++++ С TOLIST() +++++ ========================== ==========================
Понимание этих типов
Интересно, что и индекс, и столбцы имеют одинаковый тип. Они оба Index- объект Pandas. Этот объект сам по себе довольно мощный, но сейчас вы можете думать о нем как о последовательности меток для строк или столбцов.
Значения (ячейки таблицы) — это numpy.ndarray , который обозначает n-мерный массив и является основным контейнером данных в библиотеке NumPy.
Pandas построен непосредственно поверх NumPy, и именно этот массив отвечает за большую часть рабочей нагрузки.
Выбор одного столбца как серии
Чтобы выбрать один столбец данных, просто поместите имя столбца в скобках. Давайте выберем столбец Подразделение:
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') print(df['Подразделение'])
Результат:
0 Отдел продаж 1 Отдел продвижения 2 Отдел продвижения 3 Отдел продвижения . 2662 Отдел продаж 2663 Отдел продаж 2664 Отдел продаж 2665 Отдел продвижения 2666 Отдел продвижения 2667 Отдел продвижения 2668 Отдел продвижения Name: Подразделение, Length: 2669, dtype: object
Анатомия Series, возвращаемой при выборе 1 столбца
Выбор одного столбца данных возвращает другой контейнер данных Pandas Series.
Series — это одномерная последовательность помеченных данных. Существует два основных компонента Серии: указатель и данные (или значения . В серии нет колонок.
Визуальное отображение Series — это просто текст, в отличие от красиво оформленной таблицы для DataFrames.
Вы также заметите две дополнительные части данных в нижней части Series.
Name из Series становится старое имя колонки. Вы также увидите тип данных или dtype серии. Вы можете игнорировать оба этих элемента на данный момент. А также количество элементов Length.
Выбор нескольких столбцов с помощью оператора индексации
Можно выбрать несколько столбцов только с помощью оператора индексации, передав ему список имен столбцов. Давайте выберем ‘Подразделение’, ‘Менеджер’, ‘Номенклатура’, ‘Продажи’
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') print(df[['Подразделение','Менеджер','Номенклатура','Продажи']])
Результат:
Подразделение Менеджер Номенклатура Продажи 0 Отдел продаж Петров Лыжи 956898,3051 1 Отдел продвижения Сидоров Велосипеды 1841949,153 2 Отдел продвижения Сидоров Доски 1052542,373 3 Отдел продвижения Сидоров Палатки 74478,81356 4 Отдел продаж Илинская Велосипеды 1649745,763 5 Отдел продаж Илинская Доски 1263241,525 . . . . . 2661 Отдел продаж Петров Прочее 423,7288136 2662 Отдел продаж Илинская Лыжи -15254,23729 2663 Отдел продаж Петров Лыжи 8176271,186 2664 Отдел продаж Петров Прочее 171186,4407 2665 Отдел продвижения Охлобыстин Прочее 16949,15254 2666 Отдел продвижения Розницов Лыжи 15254,23729 2667 Отдел продвижения Розницов Одежда 1444915,254 2668 Отдел продвижения Розницов Прочее 3389,830508 [2669 rows x 4 columns]
Выбор нескольких столбцов возвращает DataFrame
Выбор нескольких столбцов возвращает DataFrame. На самом деле вы можете выбрать один столбец как DataFrame со списком из одного элемента:
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') print(df[['Подразделение']])
Результат:
Подразделение 0 Отдел продаж 1 Отдел продвижения 2 Отдел продвижения . . 2666 Отдел продвижения 2667 Отдел продвижения 2668 Отдел продвижения [2669 rows x 1 columns]
Хотя это напоминает Series, технически это DataFrame, другой объект.
Порядок столбцов не имеет значения
При выборе нескольких столбцов вы можете выбрать их в любом порядке по вашему выбору. Это не должен быть тот же самый порядок как оригинальный DataFrame.
Например, давайте выберем Номенклатура, Подразделение:
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') print(df[['Номенклатура','Подразделение']])
Результат:
Номенклатура Подразделение 0 Лыжи Отдел продаж 1 Велосипеды Отдел продвижения 2 Доски Отдел продвижения 3 Палатки Отдел продвижения 4 Велосипеды Отдел продаж . . . 2666 Лыжи Отдел продвижения 2667 Одежда Отдел продвижения 2668 Прочее Отдел продвижения [2669 rows x 2 columns]
Исключения, при выполнении скрипта
Есть несколько общих исключений, которые возникают при выполнении выборок только с помощью оператора индексации.
- Если вы ошиблись словом, вы получите KeyError
- Если вы забыли использовать список, содержащий несколько столбцов, вы также получите KeyError
print(df['ПодразделениЯ']) Результат: KeyError: 'ПодразделениЯ' print(df['Номенклатура','Подразделение']) Результат: KeyError: ('Номенклатура', 'Подразделение')
В первом случае должно стоять print(df[‘Подразделение’]) . А во-втором случае: print(df[[‘Номенклатура’,’Подразделение’]]) .
Выборка данных из Pandas DataFrame с помощью .loc
В .loc индексатор выбирает данные по-другому, чем просто оператор индексации. Он может выбирать подмножества строк и/или столбцов. Самое главное, он выбирает данные только по метке (label) строк и столбцов.
Выберем одну строку как Series с .loc
.loc — Индексатор возвращает одну строку в серии, когда указали одну метку строки (один индекс).
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') print(df.loc[0])
Результат:
Дата 01.01.2016 Подразделение Отдел продаж Контрагент Абакус ООО Менеджер Петров Номенклатура Лыжи Продажи 956898,3051 Себестоимость 621983,8983 Валовая прибыль 334914,4068 Name: 0, dtype: object
Теперь у нас есть Series, где старые имена столбцов теперь являются индексными метками.
Выбираем несколько строк из DataFrame с помощью .loc
Чтобы выбрать несколько строк, поместите все метки строк, которые вы хотите выбрать, в список и передайте их .loc . Давайте выберем 3 и 20 .
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') print(df.loc[[3,20]])
Результат:
Дата Подразделение . Себестоимость Валовая прибыль 3 01.01.2016 Отдел продвижения . 55859,11017 18619,70339 20 01.01.2016 Отдел продаж . 80585,27542 26861,75847 [2 rows x 8 columns]
Обозначение среза для выборки диапазона строк с .loc
Можно «нарезать» строки DataFrame с .loc помощью нотации среза . Для обозначения среза используется двоеточие для разделения значений начала , остановки и шага . Например, мы можем выбрать все строки из с 134 по 139 :
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') print(df.loc[134:139])
Результат:
Дата Подразделение . Себестоимость Валовая прибыль 134 01.01.2016 Отдел продвижения . 560,5932203 62,28813559 135 01.01.2016 Отдел продаж . 625773,3051 268188,5593 136 01.01.2016 Отдел продвижения . 508671,6102 218002,1186 137 01.01.2016 Отдел продвижения . 1034427,966 443326,2712 138 01.01.2016 Отдел продвижения . 55792,37288 18597,45763 139 01.01.2016 Отдел продвижения . 8477,542373 941,9491525 [6 rows x 8 columns]
.loc включает в себя последнее значение из обозначения среза
Обратите внимание, что строка с пометкой 139 в примере без шага была выведена. В других контейнерах данных, таких как списки Python, последнее значение исключается.
Вывод среза с использованием .loc и шага из DataFrame
Выведем тот же самый результат, только будем выводить каждый второй элемент из среза:
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') print(df.loc[134:139:2])
Результат:
Дата Подразделение . Себестоимость Валовая прибыль 134 01.01.2016 Отдел продвижения . 560,5932203 62,28813559 136 01.01.2016 Отдел продвижения . 508671,6102 218002,1186 138 01.01.2016 Отдел продвижения . 55792,37288 18597,45763 [3 rows x 8 columns]
Выбор до указанной позиции .loc
Пример скрипта Python 3 для вывода 139 первых строк из Pandas DataFrame:
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') print(df.loc[:139])
Результат:
Дата Подразделение . Себестоимость Валовая прибыль 0 01.01.2016 Отдел продаж . 621983,8983 334914,4068 1 01.01.2016 Отдел продвижения . 1289364,407 552584,7458 2 01.01.2016 Отдел продвижения . 736779,661 315762,7119 3 01.01.2016 Отдел продвижения . 55859,11017 18619,70339 .. . . . . . 136 01.01.2016 Отдел продвижения . 508671,6102 218002,1186 137 01.01.2016 Отдел продвижения . 1034427,966 443326,2712 138 01.01.2016 Отдел продвижения . 55792,37288 18597,45763 139 01.01.2016 Отдел продвижения . 8477,542373 941,9491525 [140 rows x 8 columns]
Тот же самый пример, но выведем с шагом 25:
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') print(df.loc[:139:25])
Результат выполнения выборки данных из Pandas DataFrame:
Дата Подразделение . Себестоимость Валовая прибыль 0 01.01.2016 Отдел продаж . 621983,8983 334914,4068 25 01.01.2016 Отдел продаж . 12813,55932 5491,525424 50 01.01.2016 Отдел продаж . 42978,81356 14326,27119 75 01.01.2016 Отдел продвижения . 6246,610169 694,0677966 100 01.01.2016 Отдел продвижения . 89694,91525 38440,67797 125 01.01.2016 Отдел продвижения . 879864,4068 377084,7458 [6 rows x 8 columns]
Выбор с указанной позиции до конца DataFrame через .loc
Полный код вывода данных из Pandas DataFrame:
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') print(df.loc[2660:])
Результат запроса к DataFrame:
Дата Подразделение . Себестоимость Валовая прибыль 2660 01.12.2017 Отдел продаж . 762,7118644 84,74576271 2661 01.12.2017 Отдел продаж . 381,3559322 42,37288136 2662 01.12.2017 Отдел продаж . -9915,254237 -5338,983051 2663 01.12.2017 Отдел продаж . 5314576,271 2861694,915 2664 01.12.2017 Отдел продаж . 154067,7966 17118,64407 2665 01.12.2017 Отдел продвижения . 15254,23729 1694,915254 2666 01.12.2017 Отдел продвижения . 9915,254237 5338,983051 2667 01.12.2017 Отдел продвижения . 1083686,441 361228,8136 2668 01.12.2017 Отдел продвижения . 3050,847458 338,9830508 [9 rows x 8 columns]
Тот же пример, но с шагом 3 (вывод каждого третьего элемента из Pandas DataFrame с использованием .iloc[]):
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') print(df.loc[2660::3])
Дата Подразделение . Себестоимость Валовая прибыль 2660 01.12.2017 Отдел продаж . 762,7118644 84,74576271 2663 01.12.2017 Отдел продаж . 5314576,271 2861694,915 2666 01.12.2017 Отдел продвижения . 9915,254237 5338,983051 [3 rows x 8 columns]
Выбор строк и столбцов одновременно с .loc
В отличие от просто оператора индексирования, можно выбирать строки и столбцы одновременно с .loc . Вы делаете это, разделяя выбранные строки и столбцы запятой . Это будет выглядеть примерно так:
df.loc [row_selection, column_selection]
Пример запроса на Python 3:
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') print(df.loc[[150,163],['Подразделение','Менеджер','Продажи']])
Результат:
Подразделение Менеджер Продажи 150 Отдел продаж Петров 1067796,61 163 Отдел продвижения Сидоров 13665,25424
Используйте любую комбинацию выбора для строки или столбца с .loc
Выбор строки или столбца может быть совершен любым из следующих способов:
- Один ярлык
- Список ярлыков
- slice с метками
Мы можем использовать любой из этих трех вариантов для выбора строки или столбца с помощью .loc . Давайте посмотрим несколько примеров.
Пример 1 «Выборка данных из Pandas DataFrame»:
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') print(df.loc[150:163:3,['Подразделение','Менеджер','Продажи']])
Результат:
Подразделение Менеджер Продажи 150 Отдел продаж Петров 1067796,61 153 Отдел продвижения Добряков 82944,91525 156 Отдел продвижения Добряков 85023,30508 159 Отдел продаж Петров 499385,5932 162 Отдел продвижения Сидоров 130805,0847
Выбор строк и столбцов через переменные
Гораздо проще назначить список строк и столбцов переменным перед использованием в .loc . Это полезно, если вы выбираете много строк или столбцов:
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') rows = [59, 134, 1045] columns = ['Контрагент', 'Номенклатура', 'Продажи'] print(df.loc[rows, columns])
Результат:
Контрагент Номенклатура Продажи 59 ИП Лусон Велосипеды 1139110,169 134 Союз АО Прочее 622,8813559 1045 Эсвольтр ООО Прочее 2915,254237
Пример параметризации с slice:
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') iStart = 59 iEnd = 134 iStep = 7 columns = ['Контрагент', 'Номенклатура', 'Продажи'] print(df.loc[iStart:iEnd:iStep, columns])
Результат:
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') iStart = 59 iEnd = 134 iStep = 7 columns = ['Контрагент', 'Номенклатура', 'Продажи'] print(df.loc[iStart:iEnd:iStep, columns])
Выборка данных из Pandas DataFrame с помощью индексатора .iloc[]
.iloc индексатор очень похож на .loc, но использует только целое число позиций, по которым необходимо сделать выборку.
Выбор одной строки при помощи .iloc
Передав одно целое число в .iloc , он выберет одну строку в качестве ряда:
Код запроса:
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') print(df.iloc[5])
Результат:
Дата 01.01.2016 Подразделение Отдел продаж Контрагент Билли Боб ООО Менеджер Илинская Номенклатура Доски Продажи 1263241,525 Себестоимость 884269,0678 Валовая прибыль 378972,4576 Name: 5, dtype: object
Выбор нескольких строк с .iloc
Используйте список целых чисел, чтобы выбрать несколько строк:
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') print(df.iloc[[5,45,876]])
Дата Подразделение . Себестоимость Валовая прибыль 5 01.01.2016 Отдел продаж . 884269,0678 378972,4576 45 01.01.2016 Отдел продаж . 162972,4576 69845,33898 876 01.08.2016 Отдел продвижения . 444322,0339 190423,7288 [3 rows x 8 columns]
Выборка диапазона строк через указание среза в .iloc
В случае с .iloc нотация слайса работает так же, как и список, и исключает последний элемент.
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') print(df.iloc[5:9])
Результат:
Дата Подразделение . Себестоимость Валовая прибыль 5 01.01.2016 Отдел продаж . 884269,0678 378972,4576 6 01.01.2016 Отдел продаж . 16517,47881 5505,826271 7 01.01.2016 Отдел продаж . 1098,305085 122,0338983 8 01.01.2016 Отдел продвижения . 22957,62712 9838,983051 [4 rows x 8 columns]
Выбор строк и столбцов одновременно в .iloc
Рассмотрим несколько примеров, чтобы понять, чем отличается .iloc от .loc.
Выберем две строки и два столбца:
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') print(df.iloc[[2,3], [0,3]])
Дата Менеджер 2 01.01.2016 Сидоров 3 01.01.2016 Сидоров
Осуществим выборку строк и столбцов с помощью среза:
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') print(df.iloc[2:9, 0:3])
Дата Подразделение Контрагент 2 01.01.2016 Отдел продвижения Абакус ООО 3 01.01.2016 Отдел продвижения Абакус ООО 4 01.01.2016 Отдел продаж Билли Боб ООО 5 01.01.2016 Отдел продаж Билли Боб ООО 6 01.01.2016 Отдел продаж Билли Боб ООО 7 01.01.2016 Отдел продаж Билли Боб ООО 8 01.01.2016 Отдел продвижения Билли Боб ООО
Выберем 1 значение из столбца и указанной колонки:
import pandas as pd import numpy as np df = pd.read_csv('D:\#python#\example\SampleData_Pandas.csv', sep=';') print(df.loc[3, 4])
Результат:
Палатки
Резюме по .loc и .iloc
Доступ к строкам и колонкам по индексу возможен несколькими способами:
- .loc — используется для доступа по строковой метке — т.е. фактически по значению индекса и по названию столбца
- .iloc — используется для доступа по числовому значению (начиная от 0) — т.е. по номеру строки и номеру столбца



Как выбрать строки из Pandas DataFrame по условию
Собираем тестовый набор данных для иллюстрации работы выборки по условию
| Color | Shape | Price |
| Green | Rectangle | 10 |
| Green | Rectangle | 15 |
| Green | Square | 5 |
| Blue | Rectangle | 5 |
| Blue | Square | 10 |
| Red | Square | 15 |
| Red | Square | 15 |
| Red | Rectangle | 5 |
Пишем скрипт:
import pandas as pd Boxes = df = pd.DataFrame(Boxes, columns= ['Color','Shape','Price']) print (df)
Color Shape Price 0 Green Rectangle 10 1 Green Rectangle 15 2 Green Square 5 3 Blue Rectangle 5 4 Blue Square 10 5 Red Square 15 6 Red Square 15 7 Red Rectangle 5
Синтаксис выборки строк из Pandas DataFrame по условию
Вы можете использовать следующую логику для выбора строк в Pandas DataFrame по условию:
df.loc[df.column name condition]
Например, если вы хотите получить строки с зеленым цветом , вам нужно применить:
df.loc[df.Color == 'Green']
- Color — это название столбца
- Green — это условие (значение колонки)
А вот полный код Python для нашего примера:
import pandas as pd Boxes = df = pd.DataFrame(Boxes, columns= ['Color','Shape','Price']) print (df.loc[df.Color == 'Green'])
Результат:
Color Shape Price 0 Green Rectangle 10 1 Green Rectangle 15 2 Green Square 5
Выберем строки, где цена равна или больше 10
Чтобы получить все строки, где цена равна или больше 10, Вам нужно применить следующее условие:
df.loc[df.Price >= 10]
Полный код Python:
import pandas as pd Boxes = df = pd.DataFrame(Boxes, columns= ['Color','Shape','Price']) print (df.loc[df.Price >= 10])
Результат:
Color Shape Price 0 Green Rectangle 10 1 Green Rectangle 15 4 Blue Square 10 5 Red Square 15 6 Red Square 15
Выберем строки, в которых цвет зеленый, а форма — прямоугольник
Теперь цель состоит в том, чтобы выбрать строки на основе двух условий:
- Color зеленый; а также
- Shape = прямоугольник
Мы будем использовать символ & для применения нескольких условий. В нашем примере код будет выглядеть так:
df.loc[(df.Color == 'Green') & (df.Shape == 'Rectangle')]
Полный код примера Python для выборки Pandas DataFrame:
import pandas as pd Boxes = df = pd.DataFrame(Boxes, columns= ['Color','Shape','Price']) print (df.loc[(df.Color == 'Green') & (df.Shape == 'Rectangle')])
Результат:
Color Shape Price 0 Green Rectangle 10 1 Green Rectangle 15
Выберем строки, где цвет зеленый ИЛИ форма прямоугольная
Для достижения этой цели будем использовать символ | следующим образом:
df.loc[(df.Color == 'Green') | (df.Shape == 'Rectangle')]
Полный код Python 3:
import pandas as pd Boxes = df = pd.DataFrame(Boxes, columns= ['Color','Shape','Price']) print (df.loc[(df.Color == 'Green') | (df.Shape == 'Rectangle')])
Color Shape Price
0 Green Rectangle 10
1 Green Rectangle 15
2 Green Square 5
3 Blue Rectangle 5
7 Red Rectangle 5
Выберем строки, где цена не равна 15
Мы будем использовать комбинацию символов !=, чтобы выбрать строки, цена которых не равна 15:
df.loc[df.Price != 15]
Полный код Pandas DF на питоне:
import pandas as pd Boxes = df = pd.DataFrame(Boxes, columns= ['Color','Shape','Price']) print (df.loc[df.Price != 15])
Результат работы скрипта Python:
Color Shape Price 0 Green Rectangle 10 2 Green Square 5 3 Blue Rectangle 5 4 Blue Square 10 7 Red Rectangle 5
Data Wrangling with Pandas
- Data Wrangling Pandas Cheat Sheet.pdf
- Data Wrangling With Pandas

Обработка данных с помощью Pandas ( Data Wrangling )
Обработка данных является одной из важнейших задач в data science и анализе данных, которая включает такие операции, как:
- Dealing with missing values (Работа с пропущенными значениями) — количественная оценка пропущенных значений для каждого столбца, заполнение и удаление пропущенных значений.
- Reshaping data (Изменение формы данных) — единая кодировка данных, сводные таблицы, объединения, группировка и агрегирование.
- Data Sorting (Сортировка данных): упорядочивание значений в порядке возрастания или убывания.
- Data Filtration (Фильтрация данных): создание подмножества данных согласно тем или иным условиям.
- Data deduplication (Дедупликация данных) — это технология поиска и устранения дубликатов в хранилищах данных. Применяется для снижения накладные расходов на хранение информации.
- Data Reduction (Понижение размерности/Сокращение данных): Уменьшение объема данных, сокращение количества используемых признаков и разнообразия их значений. Применяется в случае, когда данные избыточны. Избыточность возникает тогда, когда задачу анализа можно решить с тем же уровнем эффективности и точности, но используя меньшую размерность данных. Это позволяет сократить время и вычислительные затраты на решение задачи, сделать данные и результаты их анализа более интерпретируемыми и понятными для пользователя.
- Data Access (Доступ к данным): для чтения или записи файлов данных.
- Data Handling/Data Processing (Обработка данных) или Data Transformation (преобразование данных): выполнение агрегации, статистических и подобных операций над конкретными значениями.
- Другое: Создание описательных столбцов, поэлементные условные операции.
Concatenation DataFrame
Joining DataFrame
Merging DataFrame
Pivot & Melt (Unpivot) DataFrame
GroupBy Операции
Применение Lambda функции в DataFrame
10 трюков Python Pandas, которые сделают вашу работу более эффективной
Pandas — это широко используемый пакет Python для структурированных данных.
read_csv
Все знают эту команду. Но данные, которые вы пытаетесь прочитать, велики, попробуйте добавить этот аргумент: nrows = 5, чтобы загружать только часть данных. Тогда вы можете избежать ошибки, выбрав неправильный разделитель (он не всегда может быть разделен запятой).
(Или вы можете использовать команду ‘head’ в linux, чтобы проверить первые 5 строк (скажем) в любом текстовом файле: head -n 5 data.txt )
Затем вы можете извлечь список столбцов, используя df.columns.tolist() для извлечения всех столбцов, а затем добавить аргумент usecols = [‘c1’, ‘c2’,…], чтобы загрузить нужные вам столбцы.
Кроме того, если вы знаете типы данных нескольких определенных столбцов, вы можете добавить аргумент dtype = , чтобы он загружался быстрее.
Еще одно преимущество этого аргумента в том, что если у вас есть столбец, который содержит как строки, так и числа, рекомендуется объявить его тип строковым, чтобы не возникало ошибок при попытке объединить таблицы, используя этот столбец в качестве ключа.
select_dtypes
Если предварительная обработка данных должна выполняться в Python, эта команда сэкономит вам время. После чтения в таблице типами данных по-умолчанию для каждого столбца могут быть bool, int64, float64, object, category, timedelta64 или datetime64. Вы можете сначала проверить распределение по
df.dtypes.value_counts()
чтобы узнать все возможные типы данных вашего DataFrame
df.select_dtypes(include=['float64', 'int64'])
выбрать sub-dataframe только с числовыми характеристиками.
copy()
Это важная команда, если вы еще не слышали о ней. Если вы выполните следующие команды:
import pandas as pd
df1 = pd.DataFrame(< 'a':[0,0,0], 'b': [1,1,1]>)
df2 = df1
df2['a'] = df2['a'] + 1
df1.head()
Вы обнаружите, что df1 изменен. Это потому, что df2 = df1 не делает копию df1 и присваивает ее df2, но устанавливает указатель, указывающий на df1. Таким образом, любые изменения в df2 приведут к изменениям в df1. Чтобы это исправить, вы можете сделать либо
df2 = df1.copy()
from copy import deepcopy
df2 = deepcopy(df1)
map()
Это классная команда для простого преобразования данных. Сначала вы определяете словарь, в котором «ключами» являются старые значения, а «значениями» являются новые значения.
level_map =
df['c_level'] = df['c'].map(level_map)
Некоторые примеры:
True, False до 1, 0 (для моделирования); определение уровней; определяемые пользователем лексические кодировки.
apply or not apply?
Если мы хотим создать новый столбец с несколькими другими столбцами в качестве входных данных, функция apply иногда будет весьма полезна.
def rule(x, y):
if x == 'high' and y > 10:
return 1
else:
return 0
df = pd.DataFrame(< 'c1':[ 'high' ,'high', 'low', 'low'], 'c2': [0, 23, 17, 4]>)
df['new'] = df.apply(lambda x: rule(x['c1'], x['c2']), axis = 1)
df.head()
В приведенных выше кодах мы определяем функцию с двумя входными переменными и используем функцию apply, чтобы применить ее к столбцам ‘c1’ и ‘c2’.
Но проблема «apply» в том , что иногда он слишком медленный . Скажем, если вы хотите вычислить максимум из двух столбцов «c1» и «c2», конечно, вы можете сделать
df['maximum'] = df.apply(lambda x: max(x['c1'], x['c2']), axis = 1)
но вы найдете это намного медленнее, чем эта команда:
df['maximum'] = df[['c1','c2']].max(axis =1)
Вывод : не используйте apply, если вы можете выполнить ту же работу с другими встроенными функциями (они часто быстрее). Например, если вы хотите округлить колонку «с» целыми числами, делать
round(df[‘c’], 0)
df[‘c’].round(0)
Вместо использования функции применяются:
df.apply(lambda x: round(x['c'], 0), axis = 1)
value counts
Это команда для проверки распределения значений. Например, если вы хотите проверить возможные значения и частоту для каждого отдельного значения в столбце «c», вы можете сделать
df['c'].value_counts()
Есть несколько полезных трюков / аргументов:
- normalize = True : если вы хотите проверить частоту вместо количества.
- dropna = False : если вы также хотите включить пропущенные значения в статистику.
- df[‘c’].value_counts().reset_index() .: если вы хотите преобразовать таблицу статистики в кадр данных pandas и манипулировать ею
- df[‘c’].value_counts().sort_index() : показать статистику, отсортированную по разным значениям, в столбце «c» вместо счетчиков.
number of missing values — количество пустых значений
При построении моделей может потребоваться исключить строку со слишком большим количеством пропущенных значений / строки со всеми пропущенными значениями. Вы можете использовать .isnull() и .sum() для подсчета количества пропущенных значений в указанных столбцах.
import pandas as pd
import numpy as np
df = pd.DataFrame(< 'id': [1,2,3], 'c1':[0,0,np.nan], 'c2': [np.nan,1,1]>)
df = df[['id', 'c1', 'c2']]
df['num_nulls'] = df[['c1', 'c2']].isnull().sum(axis=1)
df.head()
выбрать строки с конкретными идентификаторами (select rows with specific IDs)
В SQL мы можем сделать это, используя SELECT * FROM … WHERE ID in (‘A001’, ‘C022’, …), чтобы получить записи с конкретными идентификаторами. Если вы хотите сделать то же самое с Pandas, вы можете сделать
df_filter = df['ID'].isin(['A001','C022'. ])
df[df_filter]
Процентильные группы (Percentile groups)
У вас есть числовой столбец, и вы хотите классифицировать значения в этом столбце по группам, скажем, верхние 5% в группе 1, 5–20% в группе 2, 20–50% в группе 3, нижние 50% в группе 4 Конечно, вы можете сделать это с помощью pandas.cut, но я бы хотел предоставить здесь другую опцию:
import numpy as np
cut_points = [np.percentile(df['c'], i) for i in [50, 80, 95]]
df['group'] = 1
for i in range(3):
df['group'] = df['group'] + (df['c'] < cut_points[i])
# orкоторый быстро запускается (не применяется функция apply).
to_csv
Опять же, это команда, которую все будут использовать. Я хотел бы указать на две уловки здесь. Первый
print(df[:5].to_csv())Вы можете использовать эту команду, чтобы распечатать первые пять строк того, что будет записано в файл точно.
Еще один трюк — это смешанные целые числа и пропущенные значения. Если столбец содержит как пропущенные значения, так и целые числа, тип данных по-прежнему будет плавающим, а не целым. Когда вы экспортируете таблицу, вы можете добавить float_format=‘%.0f’ , чтобы округлить все числа с плавающей точкой до целых чисел. Используйте этот трюк, если вам нужны только целочисленные выходные данные для всех столбцов — вы избавитесь от всех назойливых ‘.0’s.
Что такое объект series в Python? Узнайте преимущества и особенности
Объект Series в Python представляет собой одномерный набор данных с метками (индексами) для каждого элемента. Этот объект может содержать данные любого типа, таких как числа, строки или даже другие объекты.
import pandas as pd data = [10, 20, 30, 40, 50] index = ['a', 'b', 'c', 'd', 'e'] series = pd.Series(data, index) print(series)Приведенный код демонстрирует создание объекта Series с данными [10, 20, 30, 40, 50] и метками 'a', 'b', 'c', 'd', 'e'. Функция print выводит объект Series, который содержит значения и соответствующие метки индекса.
Детальный ответ
Что из себя представляет объект series в Python
- Каждое значение в объекте Series имеет свой уникальный маркер, называемый индексом. Индекс позволяет быстро идентифицировать и извлекать значения из Series.
- Series может содержать данные различных типов, включая числа, строки, булевы значения и т.д.
- Series поддерживает операции между объектами, включая математические операции, фильтрацию по условию и многое другое.
- Имеется возможность применять функции и методы для агрегации данных, извлечения статистических показателей или манипуляции с значениями внутри объекта Series.
Давайте рассмотрим примеры создания и манипуляции объектов Series.
# Создание Series из списка import pandas as pd data = [1, 3, 5, 7, 9] s = pd.Series(data) print(s) # Создание Series из словаря data = s = pd.Series(data) print(s) # Создание Series из массива NumPy import numpy as np data = np.array([1, 3, 5, 7, 9]) s = pd.Series(data) print(s) # Создание Series с указанием пользовательских индексов data = [1, 3, 5, 7, 9] index = ['a', 'b', 'c', 'd', 'e'] s = pd.Series(data, index=index) print(s)
В вышеприведенном примере мы создаем объекты Series из списка, словаря и массива NumPy. Мы также указываем пользовательские индексы для каждого элемента в объекте Series.
Манипуляции с объектом Series также являются важной частью его функциональности. Ниже приведены несколько примеров:
# Получение значения по индексу print(s['a']) # Фильтрация по условию print(s[s > 5]) # Математические операции print(s * 2) # Применение функции к значениям print(s.apply(lambda x: x ** 2))
В приведенных примерах мы получаем значения по индексу, фильтруем данные по определенному условию, выполняем математические операции и применяем функцию к каждому значению в объекте Series.
Объект Series обладает множеством других функций и методов для работы с данными. Вы можете изучить документацию по объекту Series в Pandas, чтобы получить более полное представление о его возможностях.
