Библиотека Pandas

Загрузка данных вручную

Здравствуйте и вновь добро пожаловать на занятия по теме «Инструментарий Numpy на языке Python».

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

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

Бывает, что данные являются частично структурированными. К примеру, если мы подключимся к веб-серверу и посмотрим на логи сервера Apache, то увидим, что каждый запрос идёт отдельной строкой, но данные в этой строке весьма неоднородны.

В других случаях данные полностью структурированы. Такое встречается, если обратиться к размеченным наборам данных. Например, Kaggle.com – сайт, на котором проводятся состязания в сфере обработки данных, предоставляет структурированные данные. Известнейшая база данных MNIST, представляющая собой набор рукописных цифр, является набором структурированных данных.

Чащевсего структурированные данные представляются в форме CSV-файлов.CSV расшифровывается как commaseparated values– значения, разделённые запятыми. Это значит, что каждая строка представляетзапись, а каждая ячейка в записи отделяется запятыми. CSV-файлыможно открыть в программах вроде Excel, посколькуформат CSV по сути является таблицей. Впрочем, для нас,специалистов по обработке данных, таблица на самом деле является матрицей, а мылюбим матрицы, так как они позволяют проводить математические операции.

Ввидуэтого нас интересует, как получить матрицу, состоящую из чисел, из файла вформате CSV. В этой, первой лекции данной части, мы используемобычные программные средства языка Python, чтобыпреобразовать CSV в матрицу. Это включает в себя построчное считываниеданных из файла, разделение каждой строки запятой и помещение каждого иззначений в список. Файл, с которым мы будем работать, называется data_2d.csv; он находится в том же репозитарии Github, но в папке linear_regression_class,так что если вы изучали мой курс по линейной регрессии, то в действительностивы уже работали с этим файлом.

Сделаемкраткий обзор файла. Как вы можете видеть, файл содержит 100 строк, а в каждойстроке по три значения. Следовательно, в итоге мы будем работать с матрицейразмерности 100×3. Конечно же,не хотелось бы задавать жёсткий размер 100×3,так что считывать файл будем таким образом, будто мы не знаем значенийразмерности.

Итак,заходим в папку linear_regression_classи запускаем Python. Но прежде, чем что-то делать, мы должныозаботиться о списке, в котором будут храниться полученные значения. Поэтомусоздадим пустой список, а также импортируем библиотеку Numpy:

X = []

import numpyas np

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

for linein open(‘’data_2d.csv’’):

    row = line.split(‘,’)

    sample =map(float, row)

    X.append.sample

Теперьу нас есть список списков. Как вы уже знаете, мы можем преобразовать его вмассив Numpy:

X = np.array(X)

Проверимразмерность X:

X.shape

Размерностьправильная – 100×3.

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

Датафреймы

Библиотека Pandas во многом схожа на язык R, так что если вы знакомы с R, то легко освоите и Pandas. Если же вы с R не знакомы, то некоторые вещи, производимые с помощью Pandas, могут показаться работающими задом наперёд или вообще противоречащими тому, как работает остальной инструментарий Numpy. Целью этого раздела является не продемонстрировать всё, на что способна библиотека Pandas, а, скорее, показать функции, используемые в машинном обучении и обработке данных чаще всего. Во множестве случаев нам необходимо загрузить данные и сразу же преобразовать их в матрицу Numpy, поэтому нет действительной нужды в знакомстве с полным списке функций библиотеки, и к тому же при нечастом использовании их легко можно забыть.

Давайте продолжим и загрузим тот же набор данных, который загружали в предыдущий раз. Не забывайте, что мы до сих пор находимся в папке linear_regression_class. Итак, импортируем Pandas:

import pandas as pd

Используемметод библиотеки Pandas, которыйназывается read_csv:

X = pd.read_csv(‘’data_2d.csv’’, header=None)

Приэтом параметру header необходимоприсвоить значение None, потому что Pandas может считывать и те CSV-файлы,в которых есть строка заголовков. В ней, как правило, содержатся названиястолбцов. Мы рассмотрим наборы данных со столбцами позже. Если вы захотитеузнать больше об аргументах функции read_csv, то можете обратиться к документации по библиотеке Pandas. Как вы можете увидеть, их очень много, но в 99%случаев вам не понадобится ни один из них. Поэтому не стоит всё перечитывать отначала до конца, просто просматривайте, если вам нужно что-то конкретное.

Можетвозникнуть вопрос: какой тип данных возвращает эта функция? Давайте проверим.

type(X)

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

X.info()

Мывидим, как и следовало ожидать, 100 строк, а также тот факт, что индекс каждойстроки представлен в виде int64. Этолюбопытный факт, поскольку он свидетельствует о том, что могут быть и другиетипы индексов строк, например текстовые строки. Не забывайте, что в Numpy мы работаем с матрицами, поэтому наши индексывсегда являются целыми числами. Видно также, что всего у нас три столбца,помеченные как 0, 1 и 2. Кроме того, показано, что тип данных, хранящихся вдатафрейме, – float64. Вообще, Pandasстарается использовать наиболее конкретный тип данных. К примеру, если у насвсе целые числа, то тип данных будет указан не вещественные числа, а целые, аесли в одной из ячеек будет текстовая строка, то тип будет указан как текстоваястрока для всего датафрейма.

Другая вызываемая функция называется head; она даёт предварительный просмотр содержимого датафрейма, а точнее, выводит на экран первые несколько строк:

X.head()

Еслинужно увидеть конкретное число строк, нужно просто вставить это число в функцию:

X.head(10)

Ещё о датафреймах. Выбор строк и столбцов

Возникает вопрос: правильно ли полагать, что датафреймы работают как двухмерные массивы Numpy? В этой лекции вы увидите, что это определённо не так.

Предположим,мы хотим получить доступ к элементу датафрейма с координатами 0, 0. Обычно мыделаем так:

X[0,0]

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

M = X.as_matrix()

Проверимтип данных, чтобы узнать, что у нас получилось:

type(M)

Интересноедело: хотя функция называется as_matrix, на самом деле она возвращает массив Numpy. Ранее мы видели, что в Numpyесть матричный тип данных, хотя и нечасто им пользовались. Так что хорошо, что Pandas поддерживает массивы Numpy.

Новернёмся к работе с датафреймами. Попробуем по-другому и подставим лишь одиннуль в X:

X[0]

Интереснаявещь: мы получили нечто, содержащее 100 значений. Фактически мы получили целыйстолбец X-ов с индексом столбца 0. Давайте посмотрим напервые пять значений и запомним их, а потом воспользуемся функцией head:

X.head()

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

Сугубоиз любопытства проверим, тип данных X[0]:

type(X[0])

Каквидим, у нас совершенно другой тип объектов – ряд (series).Дело в том, что датафреймы Pandas предназначеныдля работы с двухмерными объектами, а ряды – с одномерными.

Теперь,когда мы знаем, как получить столбец из датафрейма Pandas,который даёт нам ряд, возникает вопрос: как на самом деле получить строку? Япокажу вам два способа – iloc и ix. Оба они делают одно и то же. Допустим, мы хотим получитьнулевую строку. Первый способ:

X.iloc[0]

Можнои так:

X.ix[0]

Обратитевнимание, что тип – также ряд:

type(X.ix[0])

Такимобразом, выбор чего-то одного в Pandas даёт ряд.

ВPandas есть и несколько других интересных механизмовотбора. К примеру, мы можем одновременно выбрать более чем один столбец. Пустьнам нужен нулевой и второй столбцы. Тогда

X[[0,2]]

Этодаёт нужные нам два столбца.

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

X[ X[0] < 5 ]

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

Внимательноприсмотревшись к тому, что на самом деле указывается, мы можем выбрать лишьсреднюю часть команды:

X[0] < 5

Каквидим, получится одномерный объект логического типа, причём количество значенийравно количеству строк в X. Проверим типданных:

type(X[0] < 5)

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

И ещё о датафреймах. Названия столбцов

Давайте рассмотрим другой набор данных с помощью библиотеки Pandas. Для этого упражнения необходимо зайти в папку airline.

Итак, вначале познакомимся с данными. Они находятся в файле international-airline-passengers.csv. Как видим, у нас есть ряд названий столбцов довольно безобразного вида. Внизу также есть три строки, явно здесь неуместные, так что их придётся удалить.

Начнёмработу с Ipython. Импортируем Pandasи загружаем данные:

import pandas as pd

df = pd.read_csv(“international-airline-passengers.csv”, engine=”python”, skipfooter=3)

Итак, тут есть кое-что новое. Прежде всего мы не вставляем аргумент header, связанный с заголовком, поскольку Pandas по умолчанию читает заголовки. Мы также знаем, что нужно пропустить три последних строки, поэтому указали skipfooter=3. В действительности вы можете узнать обо всём этом, прочитав документацию по Pandas, показанную мною ранее. В ней отмечается, что что пропуск нижних колонтитулов не работает по умолчанию, как в C, поэтому в Python это приходится указывать явно.

Первое,что мы отметили, – что названия столбцов безобразны. Проверить их можно спомощью команды

df.columns

Мыможем переименовать названия столбцов и вставить их в список. Так и сделаем:

df.columns = [“month”, “passengers”]

Теперьназвания столбцов выглядят куда лучше.

Мыуже видели, как выбрать столбец, вставив его название в квадратные скобки,например

df[‘passengers’]

Ноесли названия столбцов являются строками, то есть и другой способ. Можносделать так:

df.passengers

Иполучаем то же самое. Разумеется, это не сработает, если название столбцасодержит пробелы, как было вначале.

Ипоследнее, что мы рассмотрим в этой лекции, – добавление нового столбца. Приизучении машинного обучения обнаруживается, что можно добавлять свободный членк набору данных путём добавления к матрице данных столбца из единиц. Этоделается так:

df[‘ones’] = 1

Этодобавляет новый столбец с названием ones, каждая строкакоторого будет иметь значение, равное 1. Проверим:

df.head()

Таки есть.

Может возникнуть вопрос: а что, если не нужно, чтобы каждой строке присваивалось одно и то же значение? Мы рассмотрим этот вопрос позже, когда будем обсуждать функцию apply.

Функция apply

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

Пусть, например, мы хотим смоделировать эффект взаимодействия между столбцами X1 и X2 таким образом, чтобы новый столбец состоял из результатов произведения X1 на X2. Сделать это можно с помощью функции apply. В данном случае это делается с помощью команды

df[‘x1x2’] = df.apply(lambda row: row[‘x1’]*row[‘x2’],axis=1)

Обратитевнимание, что необходимо добавлять axis=1, чтобыфункция работала применительно к каждой строке, а не к каждому столбцу.

Есливы не знакомы с lambda, то это то жесамое, что и подстановка функции в метод apply.Другими словами, альтернативной записью было бы определение функции get_interaction, берущей вкачестве аргумента строку и возвращающей произведение x1на x2:

def get_interaction(row):

    returnrow[‘x1’]*row[‘x2’]

Послечего данная функция подставляется в apply, а всёостальное остаётся прежним:

df[‘x1x2’] = df.apply(get_interaction, axis=1)

Заметьте,что подставляемая функция имеет один аргумент – row.

Такимобразом, всё это эквивалентно написанию цикла for,в котором поочередно просматриваются строки, подставляются вычисленные значенияв список и присваиваются df[‘x1x2’]:

interaction = []

for idx, row in df.iterrows():

    x1x2 =row[‘x1’] * row[‘x2’]

   interactions.append(x1x2)

df[‘x1x2’] = interactions

Разумеется,делать так никогда не надо, поскольку цикл forработаеточень медленно.

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

Итак, сначала импортируем функцию datetime:

from datetime import datetime

Теперь проверим функцию strptime, чтобы удостовериться, что она делает именно то, что нужно, подставив дату в формате «год-месяц»:

datetime.strptime(“1949-05”,“%Y-%m”)

Получаем именно то, что нужно. Теперь подставим это в функцию apply:

df[‘dt’] = df.apply(lambda row:datetime.strptime(row[‘month’], “%Y-%m”), axis=1)

Проверим:

df.info()

И убеждаемся, что столбец dt содержит объекты даты/времени.

Объединения

Если вы когда-либо изучали SQL, то должны быть знакомы с объединениями, поскольку это часто используемая операция в случаях, когда у нас есть данные из разных таблиц. Такие таблицы есть в папке numpy_class, их названия table1.csv и table2.csv. Первая таблица содержит заголовки user_id, email и age, а вторая таблица – заголовки user_id, ad_id, click.

Итак,вернёмся в среду Ipython. Импортируембиблиотеку Pandas и загрузим эти две таблицы:

import pandas as pd

t1 = pd.read_csv(‘table1.csv’)

t2 = pd.read_csv(‘table2.csv’)

Мы можем даже вывести на экран эти таблицы, поскольку они весьма небольшие. Естественно, мы объединим их, используя идентификатор user_id. Соответствующая функция в Pandas называется merge:

m = pd.merge(t1, t2, on=’user_id’)

Аргументon позволяет указать, по какому столбцу идётобъединение. Если его не указать, то объединение будет происходить по индексамстрок. Обратите внимание, что подставить можно и не один аргумент, то есть впринципе при желании объединять можно по двум, трём и более разным  столбцам.

Итак,проверим, что у нас получилось. Всё как и ожидалось.

Аналогично функции dot библиотеки Numpy, Pandas также позволяет вызывать функцию merge для самого датафрейма, поэтому другим способом объединения может служить команда

t1.merge(t2, on=’user_id’)

Результатбудет тем же.

Понравилась статья? Поделить с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: