Pandas - это библиотека Python, предоставляющая широкие возможности для анализа данных. С ее помощью очень удобно загружать, обрабатывать и анализировать табличные данные с помощью SQL-подобных запросов. В связке с библиотеками Matplotlib и Seaborn появляется возможность удобного визуального анализа табличных данных.
# Python 2 and 3 compatibility
# pip install future
from __future__ import absolute_import, division, print_function, unicode_literals
# отключим предупреждения Anaconda
import warnings
warnings.simplefilter("ignore")
import numpy as np
import pandas as pd
%matplotlib inline
import matplotlib.pyplot as plt
Основными структурами данных в Pandas являются классы Series и DataFrame. Первый из них представляет собой одномерный индексированный массив данных некоторого фиксированного типа. Второй - это двухмерная структура данных, представляющая собой таблицу, каждый столбец которой содержит данные одного типа. Можно представлять её как словарь объектов типа Series. Структура DataFrame отлично подходит для представления реальных данных: строки соответствуют признаковым описаниям отдельных объектов, а столбцы соответствуют признакам.
Для начала рассмотрим простые примеры создания таких объектов и возможных операций над ними.
** Создание объекта Series из 5 элементов, индексированных буквами:**
salaries = pd.Series([400, 300, 200, 250], index=["Andrew", "Bob", "Charles", "Ann"])
print(salaries)
salaries[salaries > 250]
Индексирование возможно в виде s.Name или s['Name'].
print(salaries.Andrew == salaries["Andrew"])
salaries["Carl"] = np.nan
salaries.fillna(salaries.median(), inplace=True)
salaries
Series поддерживает пропуски в данных.
salaries.c = np.nan # Series can contain missing values
print(salaries)
Объекты Series похожи на ndarray и могут быть переданы в качестве аргументов большинству функций из Numpy.
print("Second element of salaries is", salaries[1], "\n")
# Smart indexing
print(salaries[:3], "\n")
print("There are", len(salaries[salaries > 0]), "positive elements in salaries\n")
# Series obects can be the arguments for Numpy functions
print(np.exp(salaries))
Перейдём к рассмотрению объектов типа DataFrame. Такой объект можно создать из массива numpy, указав названия строк и столбцов.
df1 = pd.DataFrame(
np.random.randn(5, 3),
index=["o1", "o2", "o3", "o4", "o5"],
columns=["f1", "f2", "f3"],
)
df1
Альтернативным способом является создание DataFrame из словаря numpy массивов или списков.
df2 = pd.DataFrame(
{"A": np.random.random(5), "B": ["a", "b", "c", "d", "e"], "C": np.arange(5) > 2}
)
df2
Обращение к элементам (или целым кускам фрейма):
print("The element in position 3, B is", df2.at[3, "B"], "\n")
print(df2.loc[[1, 4], ["A", "B"]])
Изменение элементов и добавление новых:
df2.at[2, "B"] = "f"
df2
df2.loc[5] = [3.1415, "c", False]
df2
df1.columns = ["A", "B", "C"]
df3 = df1.append(df2)
df3
df1.at["o2", "A"] = np.nan
df1.at["o4", "C"] = np.nan
df1
Булева маска для пропущенных значений (True - там, где был пропуск, иначе - False):
pd.isnull(df1)
Можно удалить все строки, где есть хотя бы один пропуск.
df1.dropna(how="any")
Пропуски можно заменить каким-то значением.
df1.fillna(0)
Однако на практике DataFrame, с которым нам предстоит работать, необходимо считать из некоторого файла. Рассмотрим работу с DataFrame на примере следующего набора данных. Для каждрого опрошенного имеется следующая информация: заработная плата за час работы, опыт работы, образование, внешняя привлекательность (в баллах от 1 до 5), бинарные признаки: пол, семейное положение, состояние здоровья (хорошее/плохое), членство в профсоюзе, цвет кожи (белый/чёрный), занятость в сфере обслуживания (да/нет).
df = pd.read_csv("../../data/beauty.csv", sep=";")
Посмотрим на размер данных и названия признаков.
print(df.shape)
print(df.columns.values)
df.head(10)
При работе с большими объёмами данных бывает удобно посмотреть только на небольшие части фрейма (например, начало).
df.head(4)
Метод describe показывает основные статистические характеристики данных по каждому признаку: число непропущенных значений, среднее, стандартное отклонение, диапазон, медиану, 0.25 и 0.75 квартили.
df.describe()
DataFrame можно отсортировать по значению какого-нибудь из признаков. В нашем случае, например, по размеру заработной платы.
df.sort_values(by="wage", ascending=False).head()
df.sort_values(by=["female", "wage"], ascending=[True, False]).head()
DataFrame можно индексировать по-разному. В связи с этим рассмотрим различные способы индексации и извлечения нужных нам данных из DataFrame на примере простых вопросов.
Для извлечения отдельного столбца можно использовать конструкцию вида DataFrame['Name']. Воспользуемся этим для ответа на вопрос: какова доля людей с хорошим здоровьем среди опрошенных?
df["goodhlth"].mean()
Очень удобной является логическая индексация DataFrame по одному столбцу. Выглядит она следующим образом: df[P(df['Name'])], где P - это некоторое логическое условие, проверяемое для каждого элемента столбца Name. Итогом такой индексации является DataFrame, состоящий только из строк, удовлетворяющих условию P по столбцу Name. Воспользуемся этим для ответа на вопрос: На сколько средняя заработная плата мужчин выше средней заработной платы среди женщин?
df[df["female"] == 1].head()
df[(df["goodhlth"] == 1) & (df["female"] == 1)].head()
df[(df["female"] == 0)]["wage"].mean() - df[(df["female"] == 1)]["wage"].mean()
Какова максимальная заработная плата среди мужчин, имеющих членство в профсоюзе, и с опытом работы до 10 лет?
df[(df["female"] == 0) & (df["union"] == 1) & (df["exper"] < 10)]["wage"].max()
Применение функции к каждому столбцу:
df.apply(np.mean)
Группирование данных в зависимости от значения признака looks и подсчет среднего значения по каждому столбцу в каждой группе.
df["looks"].describe()
g = df.groupby("looks")
for (i, sub_df) in g:
print(sub_df["wage"].mean(), sub_df["looks"].mean())
Обращение к конкретной группе:
d1 = g.get_group(1)
d1
Метод scatter_matrix позволяет визуализировать попарные зависимости между признаками (а также распределение каждого признака на диагонали). Проделаем это для небинарных признаков.
pd.plotting.scatter_matrix(
df[["wage", "exper", "educ", "looks"]], figsize=(15, 15), diagonal="kde"
)
plt.show()
Для каждого признака можно построить отдельную гистограмму:
df["looks"].hist()
Или сразу для всех:
df.hist(color="k", bins=30, figsize=(15, 10))
plt.show()
Полезным также является график типа box plot ("ящик с усами"). Он позволяет компактно визуализировать основные характеристики (медиану, нижний и верхний квартили, минимальное и максимальное значение, выбросы) распределения признаков.
df.boxplot(column="exper", by="looks")
plt.show()
Можно сделать это, сгруппировав данные по какому-либо другому признаку:
df.boxplot(column="exper", by=["female", "black"], figsize=(10, 10))
plt.show()