Физтех.Статистика
Скачать ipynb
Python для анализа данных¶
Перед изучением убедитесь, что вы достаточно хорошо ознакомились с первой частью нашего материала про pandas.
Операции в pandas¶
import numpy as np
import pandas as pd
import scipy.stats as sps
1. Простые операции¶
Сгенерируем случайные числа и представим их в виде DataFrame.
df = pd.DataFrame(sps.norm.rvs(size=(10, 4)),
columns=['A', 'B', 'C', 'D'])
df
Выведем описательные статистики по столбцам — количество значений, среднее, стандартное отклонение (корень из дисперсии), минимум, квантили, максимум.
df.describe()
Среднее по столбцам
df.mean()
Оценка матрицы корреляций значений в столбцах
df.corr()
Применение функции к данным. Для примера посчитаем разброс значений — разница максимума и минимума.
df.apply(lambda x: x.max() - x.min())
2. Объединение таблиц¶
2.1 Функция df.append¶
Добавление строк в виде таблицы other в таблицу df. При наличии у новых строк колонок, которых нет в таблице, они добавляются в таблицу.
df.append(other, ignore_index=False, verify_integrity=False, sort=None)
df— таблица;other— добавляемые строки в виде таблицы;ignore_index— сохранить индексы или определить и как $0, ..., n-1$;verify_integrity— еслиTrue, то создает исключение в случае повторения индексов;sort— сортировать ли колонки, если они (или их порядок) различаются.
Создадим новую таблицу из первых четырех строк таблицы df. В новую таблицу добавим колонку flag, в которую запишем условие, что число в столбце D положительно. Затем добавим строки из новой таблицы к старой. Полученная таблица содержит пропуски, которые отмечены как NaN.
other = df[:4].copy() # Полное копирование
other['flag'] = other['D'] > 0
other['D'] = other['D'] ** 2
df.append(other, ignore_index=True, sort=False)
2.2 Функция pd.concat¶
Соединение таблиц вдоль выбранной оси
pd.concat(objs, axis=0, join='outer', ignore_index=False, copy=True, ...)
objs— объединяемые таблицы;axis: {0или'index',1или'columns'} — ось индексов или ось колонок, иными словами соединение по вертикали или по горизонтали;join: {'inner','outer'} — тип объединения — пересечение или объединение индексов/колонок;ignore_index— сохранить индексы или определить и как $0, ..., n-1$;copy— копировать данные или нет.
Простой пример соединения таблиц:
pd.concat([df[:5], df[5:]])
2.3 Функции pd.merge и df.join¶
Слияние таблиц по вертикали путем выполнения операций слияния баз данных в стиле SQL.
pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False, suffixes=('_x', '_y'), ...)
leftиright— объединяемые таблицы.how— тип объединения:left— только по ключам из левой таблицы == SQL left outer join;right— только по ключам из правой таблицы == SQL right outer join;outer— по объединению ключей == SQL full outer join;inner— по пересечению ключей == SQL inner join.
on— имя (или имена) колонок, по которым будет производиться объединение (т.е. ключи). Если их несколько, то нужно передать список имен. Имена колонок в таблице должны совпадать.left_onиright_on— аналогичноonдля случая, когда в таблицах различаются имена колонок, соответствующие ключам.left_indexиright_index— использовать ли индексы в качестве ключей.suffixes— суффиксы, которые будут добавлены к тем колонкам, имена которых повторяются.
Пример. Опция how=left, left_on='A', right_on='B' соответствует взятию всех строк из таблицы left, а из таблицы right берутся те строки, в которых значения в колонке A таблицы left совпадает со значением колонки B таблицы right. Если в одной из таблиц таких значений несколько, то строки другой таблицы дублируются. Если в таблице right каких-то значений нет, то в результирующей таблице будут пропуски.
df.join(other, on=None, how='left', lsuffix='', rsuffix='', sort=False)
df— основная таблица. В качестве ключей используется индекс.other— другая таблица.on— колонка(-и) вother, соответствующая ключам, по ним происходит объедиенение. ЕслиNone, то используется индекс.how— тип объединения (см.pd.merge).lsuffixиrsuffix— суффиксы, которые будут добавлены к тем колонкам, имена которых повторяются.
left = pd.DataFrame({'key': ['A', 'A'],
'lval': [1, 2]})
right = pd.DataFrame({'key': ['A', 'A'],
'rval': [4, 5]})
left
right
В результате объединения получаем 4 строки — для каждой строки из левой таблице есть две строки из правой таблицы с таким же ключом.
pd.merge(left, right, on='key')
Пример 2.¶
В таблицах ключи не повторяются
left = pd.DataFrame({'key': ['A', 'B'],
'lval': [1, 2]})
right = pd.DataFrame({'key': ['A', 'B'],
'rval': [4, 5]})
left
right
В результате объединения получаем 2 строки — для каждой строки из левой таблице есть только одна строка из правой таблицы с таким же ключом.
pd.merge(left, right, on='key')
Пример 3.¶
Посмотрим на различные типы объединения. Сооздадим и напечатаем две таблицы.
left = pd.DataFrame({'lkey': ['A', 'B', 'C', 'A'],
'value': range(4)})
right = pd.DataFrame({'rkey': ['A', 'B', 'D', 'B'],
'value': range(4, 8)})
left
right
Внешнее слияние — используются ключи из объединения списков ключей. Иначе говоря, используются ключи, которые есть хотя бы в одной из таблиц. Если в другой таблице таких ключей нет, то ставятся пропуски.
pd.merge(left, right,
left_on='lkey', right_on='rkey', how='outer')
Внутреннее слияние — используются ключи из пересечения списков ключей. Иначе говоря, используются ключи, которые присутствуют в обеих таблицах.
pd.merge(left, right,
left_on='lkey', right_on='rkey', how='inner')
Объединение по ключам левой таблицы. Не используются ключи, которые есть в правой таблицы, но которых нет в левой. Если в правой таблице каких-то ключей нет, то ставятся пропуски.
pd.merge(left, right,
left_on='lkey', right_on='rkey', how='left')
Объединение по ключам правой таблицы. Не используются ключи, которые есть в левой таблицы, но которых нет в правой. Если в левой таблице каких-то ключей нет, то ставятся пропуски.
pd.merge(left, right,
left_on='lkey', right_on='rkey', how='right')
Выполним внтуреннее объединение и установим ключ качестве индекса
pd.merge(left, right,
left_on='lkey', right_on='rkey', how='inner') \
.set_index('lkey')[['value_x', 'value_y']]
Ту же операцию можно выполнить с помощью join
left.set_index('lkey') \
.join(right.set_index('rkey'), rsuffix='_r', how='inner')
3. Группировка¶
Часто на практике необходимо вычислять среднее по каким-либо категориям или группам в данных. Группа может определяться, например, столбцом в таблице, у которого не так много значений. Мы хотели бы для каждого такого значения посчитать среднее значение другой колонки данных в этой группе.
Этапы группировки данных:
- разбиение данных на группы по некоторым критериям;
- применение функции отдельно к каждой группе;
- комбинирование результата в структуру данных.
Группировка выполняется функцией
df.groupby(by=None, axis=0, level=None, sort=True, ...)
df— таблица, данные которой должны быть сгруппированы;by— задает принцип группировки. Чаще всего это имя столбца, по которому нужно сгруппировать. Может так же быть функцией;axis— ось (0 = группировать строки, 1 = группировать столбцы);level— если ось представлена мультииндексом, то указывает на уровень мультииндекса;sort— сортировка результата по индексу.
Результатом группировки является объект, состоящий из пар (имя группы, подтаблица). Имя группы соответствует значению, по которому произведена группировка. К объекту-результату группировки применимы, например, следующие операции:
for name, group in groupped: ...— цикл по группам;get_group(name)— получить таблицу, соответствующую группе с именемname;groups— получить все группы в виде словаря имя-подтаблица;count()— количество значений в группах, исключая пропуски;size()— размер групп;sum(),max(),min();mean(),median(),var(),std(),corr(),quantile(q);describe()— вывод описательных статистик;aggregate(func)— применение функции (или списка функций)funcк группам.
Создадим таблицу для примера
df = pd.DataFrame({
'Животное' : ['Котик', 'Песик', 'Котик', 'Песик',
'Котик', 'Песик', 'Котик', 'Песик'],
'Цвет шерсти' : ['белый', 'белый', 'коричневый', 'черный',
'коричневый', 'коричневый', 'белый', 'черный'],
'Рост' : sps.gamma(a=12, scale=3).rvs(size=8),
'Длина хвостика' : sps.gamma(a=10).rvs(size=8)
})
df
Пример 1.¶
Если все котики встанут друг на друга, то какой их суммарный рост? А у песиков? А какова суммарная длинна хвостиков у котиков и у песиков?
Группировка по одной колонке и последующее применение операции суммирования:
df.groupby('Животное').sum()
Посчитаем описательные статистики для каждого животного
df.groupby('Животное').describe()
Пример 2.¶
Теперь предположим, что котики и песики встают только на представителей своего вида и своего цвета шерсти. Что тогда будет?
Группировка по двум колонкам и последующее применение операции суммирования
df.groupby(['Животное', 'Цвет шерсти']).sum()
Полученная таблица имеет мультииндекс
df.groupby(['Животное', 'Цвет шерсти']).sum().index
4. Таблицы сопряженности (Crosstab) и сводные таблицы (Pivot table)¶
Задача. В медицинской клинике информацию о приемах записывают в таблицу со следующими полями:
- время приема,
- врач,
- пациент,
- поставленный диагноз,
- назначение,
- другие поля.
Требуется посчитать, сколько раз за предыдущий месяц каждый врач ставил какой-либо диагноз. Результаты представить в виде таблицы, в которой посчитать также суммы по строкам и столбцам, т.е. сколько врач сделал приемов за месяц и сколько раз конкретный диагноз поставлен всеми врачами.
Как решать?
Способ 1
- Группировка по врачам.
- Для каждого врача группировка по диагнозам.
- В каждой группе вычисление суммы.
- Соединение в одну таблицу.
- Вычисление суммы по столбцам и по строкам.
Можете прикинуть количество строк кода и время работы 😁
Способ 2
- Создать пустую таблицу.
- Циклом 🤣 по всем записям исходной таблицы считать суммы.
- Вычисление суммы по столбцам и по строкам.
И снова можете прикинуть количество строк кода и время работы 😁
Способ 3
Применить умную функцию из pandas, которая сделает все сама!
4.1 Функция pd.crosstab¶
Эксель-подобные таблицы сопряженности
pd.crosstab(index, columns, values=None, rownames=None, colnames=None, aggfunc=None, margins=False, margins_name='All', dropna=True, normalize=False)
index— значения для группировки по строкам;columns— значения для группировки по столбцам;values— аггригируемый столбец (или столбцы), его значения непосредственно определяют значения таблицы сопряженности;aggfunc— функция, которая будет применена к каждой группе значенийvalues, сгруппированным по значениямindexиcolumns. Значения этой функции и есть значения сводной таблицы;rownamesиcolnames— имена строк и столбцов таблицы сопряженности;margins— добавляет результирующий столбец/строку;margins_name— имя результирующего столбец/строку;dropna— не включать столбцы, которые состоят только изNaN;normalize:boolean, {'all','index','columns'} — нормировка всей таблицы (или только по строкам/столбцам).
В примере выше:
pd.crosstab(df['Врач'], df['Диагноз'], margins=True)
4.2 Функция pd.pivot_table¶
Эксель-подобные сводные таблицы
pd.pivot_table(data, values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All')
data— исходная таблица;values— аггригируемый столбец, его значения непосредственно определяют значения сводной таблицы;index— ключи для группировки, относятся к индексам сводной таблицы;columns— ключи для группировки, относятся к столбцам сводной таблицы;aggfunc— функция, которая будет применена к каждой группе значенийvalues, сгруппированным по значениямindexиcolumns. Значения этой функции и есть значения сводной таблицы. Если передается список функций, то сводная таблица имеет иерархические имена колонок, верхние значения которых — имена функций;fill_value— значения для замены пропусков;dropna— не включать столбцы, которые состоят только изNaN;margins— добавляет результирующий столбец/строку;margins_name— имя результирующего столбец/строку.
В примере выше:
pd.pivot_table(df, index='врач', columns='диагноз', margins=True)
df = pd.DataFrame({
'Специальность' : ['Ветеринар', 'Ветеринар',
'Психолог', 'Психолог'] * 6,
'Врач' : ['Андрей', 'Сергей', 'Ирина'] * 8,
'Диагноз' : ['Простуда', 'Простуда', 'Простуда',
'Волнения', 'Волнения', 'Простуда'] * 4,
'Доза' : sps.randint(low=1, high=6).rvs(size=24),
'Продолжительность' : sps.randint(low=1, high=6).rvs(size=24)
})
df
Посчитаем, сколько раз какой врач ставил каждый из диагнозов, а также суммы по строкам и столбцам
pd.crosstab(df['Врач'], df['Диагноз'], margins=True)
Посчитаем, какую среднюю дозу какой врач назначал по каждому из диагнозов
pd.crosstab(df['Врач'], df['Диагноз'],
values=df['Доза'], aggfunc=np.mean)
Простейший вариант сводной таблицы — среднее в группах, определяемых столбцом. Посчитаем средние по каждому врачу
pd.pivot_table(df, index=['Врач'])
Посчитаем, сколько раз врач и в какой специальности ставил тот или иной диагноз
pd.pivot_table(df,
values='Доза',
index=['Специальность', 'Врач'],
columns=['Диагноз'],
aggfunc=np.sum)
Добавим строчку, являющейся суммой столбцов, и столбец, являющийся суммой строк
pd.pivot_table(df,
values='Доза',
index=['Специальность', 'Врач'],
columns=['Диагноз'],
aggfunc=np.sum,
margins=True)
Применим несколько функций и несколько столбцов со значениями
pd.pivot_table(df,
values=['Доза', 'Продолжительность'],
index=['Специальность', 'Врач'],
columns=['Диагноз'],
aggfunc=[np.min, np.mean, np.max],
margins=True)
