Быстрое кодирование, слияние и объединение: познакомьтесь с полезными преобразованиями данных и причудливыми комбинациями данных.

Это третья статья из моей серии Новый уровень. Обязательно ознакомьтесь с первыми двумя: 3 недооцененных навыка, которые сделают вас специалистом по данным следующего уровня и 3 недооцененных навыка, которые сделают вас программистом Python следующего уровня.

Не секрет, что Pandas — сложный для изучения модуль. Это может сбивать с толку и подавлять — особенно для начинающих программистов. Однако это также невероятно важно, если вы собираетесь стать специалистом по данным.

По этой причине даже образовательные программы по науке о данных начинают переходить к модели, в которой больше внимания уделяется изучению Pandas, чем раньше. Когда я впервые изучил науку о данных (около 4 лет назад), на моем курсе в Калифорнийском университете в Беркли использовался внутренний модуль под названием datascience [1], построенный на основе Pandas, но совершенно другой по функциональности.

Но курсы начинают меняться. Недавно в Калифорнийском университете в Сан-Диего вышел модуль, предназначенный для подготовки студентов к переходу на полноценные Pandas — соответственно, они называют его babypandas [2].

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

Если вы читаете это, то, скорее всего, вы один из них. Позвольте мне помочь вам на вашем пути.

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

Горячее кодирование для категориальных переменных

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

  • Дискретный (количественный): это числовое значение, которое можно точно подсчитать. Например, если вашей переменной является население города, это будет дискретная переменная. Почему? Ну, это явно число, над которым можно производить различные арифметические вычисления, но в то же время говорить о населении города в 786,5 человек не имеет смысла. Это должно быть точное число.
  • Непрерывный (количественный): это снова числовое значение, но оно измеряется и поэтому никогда не может быть точно определено. Пример - высота. Хотя мы могли бы измерять его с точностью до сантиметра или миллиметра благодаря доступным инструментам, теоретически мы могли бы пойти настолько глубоко, насколько захотим, с чрезвычайно детальными измерениями (микрометры, нанометры, пикометры и т. д.).
  • Порядковый (категориальный): это качественная переменная, то есть это не число, над которым имеет смысл выполнять арифметические действия. Такая переменная может принимать любое значение в пределах конечного числа упорядоченных категорий. Например, у вас может быть переменная «уровень остроты» с потенциальными значениями «мягкий», «средний» или «острый».
  • Номинальная (категориальная): похожа на порядковую переменную, за исключением того, что категории не имеют четкой иерархии. Типичным примером номинальной переменной является цвет.

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

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

Представьте, что у нас есть набор данных с тремя столбцами: "Age", "State" и "Income". Мы хотим построить модель, которая использует состояние проживания человека и его возраст для прогнозирования его дохода. Подмножество нашего набора данных может выглядеть примерно так:

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

Первая попытка может состоять в том, чтобы просто присвоить число от 1 до 6 шести различным состояниям, которые у нас есть выше. Хотя это хорошая идея для порядковых переменных, она не сработает для нашей номинальной переменной, так как предполагает упорядочение данных, которого не существует.

Наиболее распространенный метод преобразования номинальных переменных известен как горячее кодирование. Горячее кодирование — это процесс преобразования одного столбца с разными категориальными значениями в несколько столбцов (по одному для каждого отдельного категориального значения) и двоичного целого числа для каждой строки, указывающего, соответствует ли оно этому столбцу или нет [3].

Таким образом, вместо того, чтобы иметь один столбец с именем "State", мы бы реорганизовали наши данные, чтобы иметь столбцы "is_state_California", "is_state_Oregon" и т. д. для каждого уникального состояния, присутствующего в данных. Затем строки, которые изначально имели значение "California" для столбца "State", будут иметь значение 1 в столбце "is_state_California" и значение 0 во всех остальных столбцах.

Теперь о важной части: как мы на самом деле реализуем это в Pandas? Проделав всю концептуальную работу, чтобы добраться до этого момента, вы будете рады узнать, что сам код на самом деле довольно прост: в Pandas есть функция с именем get_dummies, которая выполняет всю работу по горячему кодированию за нас [4]. Предполагая, что наш DataFrame выше называется my_df, мы должны сделать следующее:

pd.get_dummies(my_df, columns=["State"], prefix='is_state')

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

Объединение фреймов данных

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

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

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

Как всегда, давайте посмотрим на пример. Давайте начнем с аналогичного DataFrame, как указано выше, за исключением того, что на этот раз он также имеет имена и называется left_df (через мгновение вы поймете, почему):

У нас также есть второй DataFrame с именем right_df, который содержит дополнительную информацию о степенях колледжа для разных людей, некоторые из которых такие же, как в left_df:

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

  • Левый кадр данных
  • Правильный фрейм данных
  • Столбцы, которые мы хотим объединить
  • Какой тип соединения мы хотим: внутреннее, левое, правое или внешнее

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

Внутреннее соединение объединит два кадра данных, чтобы в выходном кадре данных отображались только те строки, которые совпадают в обоих кадрах данных. Например, с нашими двумя вышеприведенными кадрами данных это будет выглядеть следующим образом:

left_df.merge(right_df, on='Name', how='inner')

Только Алиша, Адити и Татьяна появляются в обоих кадрах данных, и поэтому только их строки являются частью выходных данных при слиянии через внутреннее соединение. Мы также можем видеть, что столбец "Degree" теперь присутствует, показывая, почему мы объединились в первую очередь.

Ниже приведен рисунок, визуально изображающий внутреннее соединение. Левый круг можно представить как left_df, а правый как right_df.

Левое соединение включает все строки в левом фрейме данных, даже если они не совпадают в правом фрейме данных. Для тех, которые отсутствуют в правильном DataFrame (и, следовательно, не имеют значения в новом столбце, в данном случае "Degree"), Pandas заполняет нулевое значение. Позже в этой статье мы увидим, как мы можем работать с такими значениями.

Важно отметить, что этот тип слияния не включает значения в правом кадре данных, которые не имеют соответствия в левом. Давайте посмотрим на наш пример:

left_df.merge(right_df, on='Name', how='left')

Мы видим, что все люди из left_df присутствуют, даже если у них не было совпадений в right_df. С другой стороны, Ариэль и Хуан, которые находятся только в right_df, не находятся в выходном DataFrame.

Вот графическое изображение левого соединения:

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

left_df.merge(right_df, on='Name', how='right')

На этот раз в выводе отсутствуют Тед, Аарон, Ли, Абдул и Хадиджа, поскольку их нет в right_df. Вот правильное соединение, показанное графически:

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

left_df.merge(right_df, on='Name', how='outer')

Мы можем видеть, как Pandas заполняет NaN значениями "Degree" Теда, Аарона, Ли, Абдула и Хадиджи, поскольку они отсутствуют в right_df и, следовательно, не имеют соответствующих данных для этого столбца. Точно так же Ариэль и Хуан имеют значения NaN для "State" и "Income", поскольку их нет в left_df.

Вот графическое изображение внешнего соединения:

И с этим вы должны быть готовы слиться с дикой природой.

Давайте перейдем к нашему последнему недооцененному навыку.

Объединение фреймов данных вместе

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

Самый простой пример конкатенации включает в себя два кадра данных, столбцы которых идентичны [5]. Например, предположим, что у нас есть следующие два кадра данных с именами top_df и bottom_df соответственно:

Мы можем объединить их следующим образом:

pd.concat([top_df, bottom_df])

Пара важных замечаний по поводу вышеизложенного:

  • В отличие от merge, который мы часто вызываем непосредственно в объекте DataFrame (например, top_df.merge(bottom_df), мы вызываем concat, используя pd.concat.
  • Объединяемые кадры данных передаются как один аргумент внутри списка, а не как два (или более) отдельных аргумента.

Мы также можем объединить кадры данных, которые не являются точными совпадениями. Например, скажем, мы добавляем еще один столбец к нашему bottom_df:

Затем та же конкатенация дает нам следующий выходной DataFrame:

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

Наконец, конкатенация также работает горизонтально. Чтобы убедиться в этом, мы добавим в наш арсенал еще один DataFrame с именем more_df:

Затем мы получаем следующее:

pd.concat([top_df, more_df], axis=1)

Дополнительный аргумент axis=1 сообщает Pandas, что мы хотим объединить по горизонтали (по столбцу); если мы опускаем этот аргумент, по умолчанию он равен axis=0, который объединяется по вертикали (по строке).

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

Осталось только решить эти надоедливые значения NaN.

Дополнительный навык: заполнить и заменить

Вы, возможно, заметили, что когда мы собираем данные из разных мест в одно место, мы часто получаем раздражающие нулевые значения или ввод данных с ошибками. Давайте посмотрим, как мы можем решить эти проблемы. В качестве примера мы будем использовать один из вышеперечисленных DataFrames, на этот раз назвав его faulty_df:

Нулевые значения представляют данные, которых у нас нет; во многих случаях мы хотим заполнить эти значения, чтобы мы могли выполнять наши анализы, не сталкиваясь с ошибками. Существует много методов заполнения недостающих данных, но мы выберем для этого примера простой: использование среднего значения — в данном случае 17.

Самый простой способ добиться этого в Pandas — через функцию fill_na:

faulty_df = faulty_df.fillna(17)
faulty_df

Затем мы можем преобразовать эти числа с плавающей запятой обратно в желаемый тип — целые числа — с помощью функции astype:

faulty_df['Age'] = faulty_df['Age'].astype('int')
faulty_df

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

Резюме и заключительные мысли

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

Вот шпаргалка для дальнейшего использования:

  1. Категориальные данные не сочетаются с моделями машинного обучения. Изучите горячее кодирование.
  2. Необходимые данные часто разбросаны. Научитесь объединять их вместе.
  3. Подобные наборы данных принадлежат друг другу. Помогите им объединиться с помощью объединения.

Желаем удачи в ваших усилиях по манипулированию данными.

Хотите преуспеть в Python? Получите эксклюзивный бесплатный доступ к моим простым и понятным руководствам здесь. Хотите читать неограниченное количество историй на Medium? Зарегистрируйтесь по моей реферальной ссылке ниже!



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

Рекомендации

[1] http://data8.org/datascience/
[2] https://babypandas.readthedocs.io/en/latest/
[3] https:// www.educative.io/blog/one-hot-encoding
[4] https://stackabuse.com/one-hot-encoding-in-python-with-pandas-and-scikit-learn/
[5] https://www.w3resource.com/pandas/concat.php