Условие
Дана выборка по заболеваниям (id заболевания, даты начала/выздоровления, id пациента, дата рождения, пол, тяжесть, медицинская организация). На отдельных вкладках Excel выполнить:
- Общее число пациентов и общее число заболеваний.
- Ежедневная динамика прироста инфекции.
- Распределение заболеваний по полу × возрастным категориям (0–17, 18–64, 65+) × тяжести; уязвимая группа.
- Рейтинг медорганизаций по
заболевших / прикреплённое население. - Аномальное поле и признак аномалии.
- Средняя продолжительность заболевания и от каких признаков она зависит.
Также — Python-блок (уникальные элементы, аббревиатура, разница в %, разделение на файлы).
Решение
Pandas-решение основной задачи
import pandas as pd
df = pd.read_excel('data.xlsx')
# 1) Общее число
total_patients = df['IDпациента'].nunique()
total_diseases = df['IDзаболевания'].nunique()
# 2) Ежедневная динамика
daily = df.groupby('Датаначалазаболевания').size().rename('cnt').reset_index()
daily['delta_pct'] = daily.cnt.pct_change() * 100
# 3) Распределение по полу/возрасту/тяжести
df['Возраст'] = (pd.to_datetime('2022-11-30') - pd.to_datetime(df.ДР)).dt.days // 365
df['ВозрКат'] = pd.cut(df.Возраст, bins=[0,17,64,200], labels=['0-17','18-64','65+'])
pivot = df.pivot_table(index=['Пол','ВозрКат'], columns='Тяжесть',
values='IDзаболевания', aggfunc='count', fill_value=0)
# Уязвимая группа = группа с макс долей "Средней"+"Тяжелой"
# 5) Аномалия — если есть пациент с ДР в будущем (5/13/17 → 2017, ребёнок 5 лет)
# или пол в нестандартном формате; проверяем пропуски и редкие значения
df.isna().sum()
df.Пол.value_counts()
# 6) Средняя продолжительность
df['Продолж'] = (pd.to_datetime(df.Датавыздоровления)
- pd.to_datetime(df.Датаначалазаболевания)).dt.days
df.groupby(['ВозрКат','Тяжесть']).Продолж.mean()Python-задачи
# 1) Уникальные элементы списка
arr = [1,4,2,1,4,3,2,12,8,7,12]
unique = list(set(arr))
n = len(unique)
# 2) Аббревиатура
s = "Полис обязательного медицинского страхования"
abbr = "".join(w[0].upper() for w in s.split())
# 3) Разница в процентах между годами для возрастной группы
def find_mothers_age_diff(year1, year2, age_group):
df = pd.read_csv('births-by-mothers-age.csv')
df['share'] = df.value / df.groupby('year').value.transform('sum') * 100
s1 = df.loc[(df.year==year1) & (df.age_group==age_group), 'share'].iloc[0]
s2 = df.loc[(df.year==year2) & (df.age_group==age_group), 'share'].iloc[0]
diff = s2 - s1
print(f'Разница в группе {age_group} составляет {diff:+.2f}%. '
f'В {year1} было {s1:.2f}%, в {year2} стало {s2:.2f}%')
# 4) Разделение на файлы
for clinic, sub in df.groupby('Медицинскаяорганизация'):
sub.to_excel(f'{clinic}.xlsx', index=False)Подводные камни
- Возраст по дате рождения: в датасете есть
5/13/17— может быть либо13.05.2017, либо13.05.1917— формат хранения американский (M/D/Y). Без явного формата → ошибки. - «Прикреплённое население» — в отдельной справочной таблице; нужно
JOIN(LEFT, иначе потеряем поликлиники без записей). - Аномалия: чаще всего это пол с пустыми значениями или ID с лидирующими нулями (string vs int).
- Длительность заболевания: если
Датавыздоровленияпуста — пациент ещё болен; нельзя считать.
Эталонный ответ
1) nunique; 2) groupby даты + pct_change; 3) pivot_table с возр.группами; 4) JOIN с прикреплением, cases / population; 5) аномальное поле — пол / ДР; 6) средняя длительность по (возраст × тяжесть). Python: set, list comprehension с [0], разница долей, цикл groupby+to_excel.