Эта статья является частью серии «Наука о данных с нуля — могу ли я, чтобы я могла».
Нажмите здесь, чтобы перейти к предыдущей статье/лекции «A7: NumPy (практические упражнения).»
✅ Предложение:Откройте новый блокнот Jupyter и введите код, читая эту статью. Делать — это учиться, и да, «ПОЖАЛУЙСТА, прочитайте комментарий, он очень полезен…. .!»
Панды: главное
Добро пожаловать в основы панд!
Pandas — это современный инструмент/библиотека в экосистеме Python для Data Science. Эта высокопроизводительная и простая в использовании библиотека с открытым исходным кодом является обязательным навыком для любого специалиста по данным. Благодаря концепции открытого исходного кода, которая удобно объединила единомышленников, чтобы посвятить свое драгоценное время и энергию, они сделали панд доступными для всех сегодня!
В этом разделе мы начнем с основ, перейдем к дополнительным темам и научимся использовать pandas для анализа данных. В этом разделе мы рассмотрим следующие концепции.
- Структуры данных Pandas: (Серии, DataFrame и как получить из них необходимые данные — индексирование и выбор)
- Иерархическая индексация
- Очистка данных, подготовка и обработка недостающих данных
- Обработка данных: слияние/объединение, объединение/объединение
- Агрегация данных и GroupBy
Если вы никогда не использовали эту библиотеку, подумайте о пандах как о чрезвычайно мощной версии Excel с гораздо большим количеством функций и возможностей для работы.
Начнем со структур данных pandas.
Структуры данных панд:
Series и DataFrame — это две рабочие лошадки в пандах.
Давайте сначала поговорим о сериях:
Ряд:
Серия — это одномерный объект, похожий на массив, который содержит значения и массив меток, связанных со значениями. Серии могут содержать данные любого типа (например, целые числа, строки, числа с плавающей запятой, объекты Python…) и могут быть проиндексированы с помощью меток (меток осей).
(Серия похожа на массив NumPy — на самом деле она построена поверх объекта массива NumPy) Серия может содержать любой произвольный объект Python.
Давайте приступим к практике и изучим концепции Series на примерах:
Мы можем создать серию, используя список, массив numpy или словарь
Давайте создадим эти объекты и преобразуем их в серию панды!
Серии с использованием списков
Давайте создадим списки Python, один из которых будет содержать метки, а другой — данные.
Итак, у нас есть два объекта списка Python:
my_labels
- список строк, иmy_data
- список чисел
Мы можем использовать pd.Series
(базовый метод в пандах, начинающийся с заглавной S), чтобы преобразовать объект списка Python в серию панд.
✅:Если вы нажмете
<Shift+tab>
, из документации вы заметите, что Series может принимать самые разные параметры, в данный момент мы сосредоточимся на данных и индексе.
Давайте рассмотрим только параметр data
и посмотрим, как он работает!
Обратите внимание, что «0 1 2
» — это автоматически сгенерированный индекс для элементов в ряду с данными «100 200 300
».
Мы можем указать значения индекса и получить соответствующие данные/значения, используя эти индексы.
Давайте передадим my_labels
в серию как индекс.
Серии с использованием массивов NumPy
Давайте создадим массив NumPy из my_data, а затем из этого массива
Обратите внимание, мы снова получили столбец индекса «0 1 2
», давайте передадим наши собственные значения индекса!
Серия с использованием словаря:
Обратите внимание на разницу: если мы передаем
dictionary
вpd.Series
, панды будут принимать ключи какindex/labels
иvalues
в качестве данных.
Двигаясь вперед, давайте создадим несколько серий для практики и посмотрим, как это работает, когда мы хотим поместить разные типы данных в одну серию.
Создание серии типа int
с использованием arange()
.
Ну, по умолчанию это int64
типов, однако мы можем создать серию, если тип int32
. Позвольте мне сделать это двумя способами.
ser2
— тип с плавающей запятой, мы можем создать новую серию типов int
, например. ser3
из ser2
. Давай сделаем это. Помните, что по умолчанию int
равно int64
.
В случае, если вы просто хотите проверить тип данных вашей серии, используйте dtype
.
Что, если мы создадим объект Series
с integers
от 1 до 5 и float
6.0.
- Каким будет тип данных
Series
? - Что если вместо
float
вставитьstring '6'
? - Можете ли вы преобразовать серию в тип
int
?
Давайте попробуем это с кодом.
Обратите внимание на разницу в dtype!
Что, если у нас есть какая-то строка вместо 6. Например, «s»
Что нужно сделать: создайте серию с данными [1, 2, 3, 6., 'foo']
. Какой тип данных у серии?
Серии могут содержать самые разные типы объектов, давайте рассмотрим несколько примеров:
Получение данных из серии:
Индексы — ключевая вещь, которую нужно понять в Series. Панды используют эти индексы (числа или имена) для быстрого поиска информации. (Индекс работает так же, как хеш-таблица или словарь).
Чтобы понять концепции, давайте создадим три серии, ser1
, ser2
, ser3
из словарей с некоторыми случайными данными:
Теперь у нас есть три серии ser1, ser2 & ser3
. Вы можете распечатать их все, чтобы посмотреть, как они выглядят, я проверю один из них, ser1
.
Чтобы получить информацию для серии, мы можем просто передать индекс, и он вернет значение, связанное с этим индексом. (похоже на словарь, верно?)
Во всех наших сериях ser1
, ser2
и ser3
индексами являются названия городов, которые представляют собой строки. Возьмем значения некоторых городов из этих рядов. Помните, что названия городов (индексы) чувствительны к регистру, calgary
не совпадает с Calgary
.
Вместо строк, если у нас есть число в качестве индекса, мы просто передаем число в квадратных скобках, чтобы получить соответствующее значение. Это просто!
Основные операции над сериями обычно основаны на индексе.
Например, если мы хотим добавить ser1 + ser2
, он пытается сопоставить операцию на основе индекса. Для Calgary
, Montreal
и Vancouver
он добавляет значения, тогда как для Toronto
он не может найти совпадение и помещает туда NaN
. (Торонто – это 700 – это ser1
, где ser2
его нет, поэтому присвоение значения Торонто в дополнение к операции сложения ser1
и ser2
вводит в заблуждение)
Теперь давайте добавим ser4
и ser3
сейчас.
Если вы сравните ser4
и ser3
, вы ожидаете еще NaN
после их добавления.
Итак, из приведенных выше операций мы узнали, что значения, найденные в ряду, будут складываться для их соответствующего индекса, с другой стороны, если нет совпадения, значение отображается как NaN (не число), что считается в pandas, чтобы отмечать отсутствующие значения или значения NA.
Теперь давайте продолжим и рассмотрим некоторые полезные встроенные функции methods
и attributes
в сериях.
isnull()
: обнаруживает отсутствующие данные и возвращает True
для отсутствующих точек данных.
notnull()
: обнаруживает существующие (ненулевые) значения и возвращает True
, если значение не равно нулю.
Что ж, гораздо лучше знать, сколько точек данных отсутствует и/или сколько точек данных ненулевые. Очень просто использовать sum()
вместе с isnull()
и/или notnull()
.
Давайте еще раз попробуем ser5
.
head()
, tail()
: чтобы просмотреть небольшую выборку объекта Series
или DataFrame
(мы скоро узнаем DataFrame
), мы используем head()
и tail()
методов.
Количество отображаемых элементов/точек данных по умолчанию равно 5, но мы можем указать другое число. ‹shift+tab›, чтобы просмотреть документацию.
axes
: возвращает список меток оси строки (индекс).
values
: возвращает список значений/данных.
size
: возвращает количество элементов (размер) в серии.
empty
: True, если серия пуста.
Итак, на данный момент это все о Series
, давайте продолжим и поговорим о DataFrame
, второй рабочей лошадке панд.
Датафрейм:
- Очень простой способ представить себе
DataFrame
— это "группа рядов вместе, например, если они имеют один и тот же индекс". DataFrame
– это прямоугольная таблица (двумерная структура данных с метками), которая содержит упорядоченный набор столбцов, каждый из которых может относиться к разным типам данных (числовым, строковым, логическим , и т.д).DataFrame
имеет индексы строк и столбцов, подумайте об электронной таблице! Без сомнения, это наиболее часто используемая структура данных от pandas.
Давайте двигаться дальше и изучать DataFrame
на примерах:
Что ж, следуйте инструкциям ниже и создайте фрейм данных для целей обучения. Это было бы хорошим пересмотром некоторых концепций, которые мы изучили в предыдущих разделах/статьях.
- Создайте две метки или индексы:
row_label
иcol_label
- Создайте двумерную матрицу
10x10
, используя встроенные методы numpy,arange()
иreshape()
- Создайте DataFrame, используя индексы и матрицу
✅ СОВЕТ. Используйте <TAB>
для автозаполнения и <shift + TAB>
для документации.
df
— это наш первыйdataframe
, верно!c1
доc10
— столбцы, аr1
доr10
— строки вdf
.- Каждый столбец на самом деле является pandas
Series
, имеющим общий индекс, метки строк.
Давайте продолжим и изучим некоторые важные концепции, используя наш фрейм данных df
.
Захват столбцов из фрейма данных:
Чтобы получить столбец, мы просто передаем имя нужного столбца в квадратных скобках!
- Вы заметили, что вывод выше выглядит как
Series
, верно? - Еще одна вещь, на которую следует обратить внимание: возвращенные
Series
имеют те жеindex
, что иDataFrame
.
Давайте проверим type
одного столбца (Series
) из df
.
Мы можем получить более одного столбца, просто передав список нужных нам столбцов!
✅ СОВЕТ: нажмите
<TAB>
послеdf.
, вы увидите ряд доступных методов для фрейма данных. Тем не менее, это хорошо для этого один раз!
Полезно знать:df.<name_of_the_column>
(например, df.c1
, df.c2
в приведенном выше кадре данных) также можно использовать для захвата одного столбца, однако на данном этапе это не рекомендуется. Может быть столбец с именем, содержащим более одного слова и разделенным пробелом, например. <product name>
, мы не можем получить такие столбцы с помощью этого метода и должны передать имя столбца в виде строки в квадратных скобках.
Давайте попробуем получить столбец из нашего фрейма данных df
с помощью оператора dot .
.
Добавление нового столбца в фрейм данных:
pandas
кадры данных очень удобны. Мы можем удобно добавить новый столбец в наш фрейм данных. Давайте добавим столбец с именем c1+c2
, добавив два существующих столбца с помощью простого оператора +
!
Удаление столбца из фрейма данных:
Мы можем удалить любой столбец из фрейма данных, используя метод drop()
.
Несколько важных параметров, которые нам нужно учитывать в drop()
:
label
: имя столбца, которое нам нужно передать, если нам нужно удалить более одного столбца, это должен быть список имен столбцов.axis
: значение по умолчанию —0
, которое относится к строкам, чтобы удалить столбец, нам нужно передатьaxis = 1
.inplace
: по умолчаниюFalse
, что предотвращает постоянное изменение. Нам нужно пройтиTrue
для постоянного изменения.Inplace
очень полезен, он гарантирует, что мы не удаляем/удаляем какой-либо столбец по ошибке. Если мы не передадим этот параметр, столбец не будет удален из фрейма данных.
Хотите узнать больше, используйте <Shift+tab>
для изучения документации.
Просто быстро проверьте, сколько столбцов и строк у нас есть в нашем фрейме данных, df
. Здесь мы можем использовать атрибут shape
!
Итак, у нас есть 10 строк и 11 столбцов в нашем фрейме данных df
, «c1+c2
» — это 11-й столбец, который мы добавили выше. Давайте удалим этот столбец.
Помните: если мы не передадим inplace = True
, изменение не будет постоянным. Попробуйте сами, не проходя inplace
и увидите разницу.
Напоминание. Чтобы удалить столбец, вы должны сообщить пандам, установив inplace = True
(по умолчанию inplace = False
). pandas щедр и не хочет, чтобы мы потеряли информацию по какой-либо ошибке.
Захват строк из фрейма данных:
Захват строки отличается от захвата столбцов из фрейма данных. Если вы думаете, что можете использовать df['r1']
для захвата строки 'r1'
, это неверно и возвращает KeyError: 'r1'
.
Чтобы получить или получить строку, нам нужно использовать loc
и iloc
.
loc
: доступ к строкам поlabel(s)/name(s)
.iloc
: использование строкиindex location
.
Давайте используем loc
для получения двух строк r2
и r3
. Для этого нам нужно передать список [r2, r3]
внутри квадратных скобок.
Итак, r1
и r2
— это метки, их соответствующие местоположения индекса — 1
и 2
(помните, что индекс начинается с 0), давайте теперь используем местоположения индекса с iloc. Это легко, даже если наш индекс помечен.
Захват одного элемента из кадра данных:
Вспомните свой класс линейной алгебры, работающий с матрицами. Чтобы получить один элемент, вам нужно его местоположение, [row, col]
, правильно!
Захват подмножества фрейма данных:
Мы можем получить подмножество, передав [[list of required rows],[list of required columns]]
в наборе квадратных скобок.
Условный выбор или маскирование:
панды получили возможности! Мы можем сделать условный выбор. Например, все значения, которые больше некоторого значения.
Давайте попробуем захватить все значения в df
, которые больше 5.
Обратите внимание, что мы получаем True
во всех местах, где выполняется условие (df>5
)! Подобно логической маскировке numpy, нам нужно создать маску, и они используют эту маску для соответствующего захвата значений. Мы получим NaN
, где условие False
.
Попробуем создать другую маску "mask_df_div_3==0"
для значений, которые делятся на 3 (df % 3 == 0
). Нам нужны значения, в которых условие выполнено (True
), и NaN
, где оно равно False
.
Полезно знать:
Использование такой операции (см. выше) для всего фрейма данных не является распространенным явлением, поскольку они могут добавить многоNaN
или отсутствующих данных. Обычно мы используем их в столбцах или строках вместо фильтрации.
Что, если мы хотим получить все строки, для которых значения больше 11 в столбце c1
. Все строки на основе условия для любого столбца. Начнем с проверки, где требуемое условие не выполняется и возвращает False
в столбце c1
. Затем мы работаем со всем фреймом данных df
, хорошо!
Итак, нам не нужны строки r1
и r2
в нашем выборе, так как условие False
.
Давайте отфильтруем строки на основе условия для значений столбца (c1>11
).
Что ж, если мы хотим сохранить результаты в новом фрейме данных, мы действительно можем создать новый фрейм данных на основе нашего условного выбора result = df[df['c1']>11]
.
Давайте создадим фрейм данных result
и будем работать с ним, это просто!
Обратите внимание, что после операции выбора/фильтрации положение индекса для строк изменяется. В приведенном выше примере r3
теперь получил 0
index. Именно здесь loc
и iloc
имеют значение, и мы предпочитаем захватывать строки (если требуется), используя их метки в loc
.
Например, мы все еще можем получить r3
и r5
с их метками, не зная их местоположения индекса из кадра данных result
.
В случае, если мы все еще заинтересованы в захвате, скажем, r3
и r5
, используя iloc
, нам нужно знать их индексные позиции.
Мы видим, что r3
получил индекс 0
, а r5
получил индекс 2
. Мы можем использовать [0,2]
в iloc
для захвата соответствующих строк.
Хорошо, чтобы немного попрактиковаться, давайте возьмем все строки из нашего исходного фрейма данных df
, которые имеют значение 70
в столбце c1
.
Двигаясь вперед, вспомните свое понимание условных операторов из раздела Python. Мы можем легко комбинировать несколько условий, используя операторы &, |
.
Давайте попробуем!
- фильтровать кадр данных
df
для значений меньше30
вc1
&
меньше50
вc2
. - фильтровать кадр данных
df
для значений меньше30
вc1
|
меньше50
вc2
.
Примечание: and
и or
не будут работать, нам нужно использовать &
и |
, см. объяснение ниже после нескольких ячеек.
Важное примечание.
Операторы «and
,or
» не будут работать в вышеуказанных условиях, они вернут
*ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
Это «неоднозначное» означает, что
True
работает только для одного логического значения одновременно «True
иFalse
». Вместо этого нам нужно использовать «&
». ('|
' вместоor
)
Попробуйте использовать приведенный выше код, используя вместо этого 'and
,or
, чтобы увидеть!'
Операторы 'and
,or
' путаются с сериямиTrue/False
и вызывают ошибку!
Надеюсь, вы хорошо разобрались с DataFrames на данном этапе. Давайте двигаться дальше и изучим пару полезных встроенных методов для DataFrames. Мы рассмотрим больше позже в следующих статьях!
reset_index()
: это сбросит индекс нашего фрейма данных на числовой индекс (который является индексом по умолчанию), существующий индекс (с r1
на r10
для нашего фрейма данных df
) будет новым столбец.
set_index()
: учтите, мы считаем, что существующий столбец в нашем фрейме данных может быть полезным индексом, и мы хотим установить этот столбец в качестве индекса. Этот метод полезен для этой цели!
Пожалуйста, посмотрите код ниже и внимательно прочитайте комментарии.
Что ж, мы можем думать о new_index
как о хорошем индексе и использовать set_index()
для создания нового индекса. (inplace
должен мне True
для постоянного изменения)
head()
, tail()
: пока наш фрейм данных 'df'
содержит только 10 строк. Что, если строк будет много? head()
и tail()
— это полезные методы (похожие на Series
выше), чтобы увидеть первые и последние 5 строк (по умолчанию) в качестве образца нашего фрейма данных.
info()
: очень полезный метод, предоставляющий краткую сводку (количество точек данных, столбцов, тип каждого столбца, объем используемой памяти...) кадр данных.
describe()
: очень удобный и один из предпочтительных методов создания описательной или сводной статистики, которая обобщает центральную тенденцию, дисперсию и форму распределения набора данных, за исключением NaN
значений.
Обратите внимание, что в описании учитываются только числовые столбцы.
Отличная работа, ребята! На данный момент это было все о Series
и DataFrame
. Мы рассмотрим другие важные концепции в следующих статьях.
Похлопайте и поделитесь этой статьей в своих контактах, возможно, кто-то изо всех сил пытается изучить эти понятия.
Удачи!
Увидимся на следующей лекции на тему A9: Иерархическое индексирование (многоиндексирование) и обработка отсутствующих данных”.
Примечание. Полный курс, включая видеолекции и блокноты Jupyter, доступен по следующим ссылкам:
Доктор. Джунаид Кази— предметный специалист, консультант по науке о данных и машинному обучению. Он является тренером по профессиональному развитию, наставником, автором и приглашенным спикером. С ним можно связаться для консультационных проектов и/или обучения профессионального развития через LinkedIn или через ScienceAcademy.ca.