<jupyter_start><jupyter_text>Обработка итоговых результатов<jupyter_code>import re
import requests
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator, NullLocator
from matplotlib.colors import Normalize
import seaborn as sns
%matplotlib inline<jupyter_output><empty_output><jupyter_text>Идентификатор паркрана.<jupyter_code>parkrun = 'kuzminki'<jupyter_output><empty_output><jupyter_text>Список идентификаторов всех российских паркранов находится в файле `russian_parkruns.csv`.<jupyter_code>page_all_results = requests.get(f'https://www.parkrun.ru/{parkrun}/results/eventhistory/', 
                                headers={'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:86.0) Gecko/20100101 Firefox/86.0'})
data = pd.read_html(page_all_results.text)[0]
data = data.drop(columns=data.columns[8:])
data = data.rename(columns={data.columns[0]: 'n', data.columns[1]: 'date',
                           data.columns[2]: 'finishers', data.columns[3]:'volunteers',
                           data.columns[4]: 'men_name', data.columns[5]: 'men_time',
                           data.columns[6]: 'women_name', data.columns[7]: 'women_time'})
pd.set_option('display.max_colwidth', None)
data[data.columns[1]] = data[data.columns[1]].transform(lambda s: re.search(r'\d\d/\d\d/\d{4}', s)[0])
data[data.columns[2]] = data[data.columns[2]].transform(lambda s: s.replace('finishers', ''))
data[data.columns[3]] = data[data.columns[3]].transform(lambda s: s.replace('volunteers', ''))
data[data.columns[4]] = data[data.columns[4]].transform(lambda s: re.sub(r'(\d\d:?){2,3}', '', s))
data[data.columns[6]] = data[data.columns[6]].transform(lambda s: re.sub(r'(\d\d:?){2,3}', '', s))
data
data['men_time_m'] = data['men_time'].transform(lambda time: sum(x * int(t) for x, t in zip([1/60, 1, 60], time.split(':')[::-1])))
data['women_time_m'] = data['women_time'].transform(lambda time: sum(x * int(t) for x, t in zip([1/60, 1, 60], time.split(':')[::-1])))
# data[data.columns[5]] = ('00:' + data[data.columns[5]]).apply(pd.to_timedelta)
# data[data.columns[7]] = ('00:' + data[data.columns[7]]).apply(pd.to_timedelta)
def min_to_mmss(m: float) -> str:
    mins = int(m)
    return f'{mins}:{int((m - mins) * 60)}'
number_parkruns = len(data)
plt.figure(figsize=(16, 7))
ax = data['men_time_m'].hist(bins=30)
ax.yaxis.set_major_locator(MultipleLocator(4))
ptchs = ax.patches
med = data['men_time_m'].median()
norm = Normalize(min(2*med-ptchs[-1].get_x(), ptchs[0].get_x()), med)

for ptch in ptchs:
    ptch_x = ptch.get_x()
    color = plt.cm.plasma(norm(med-abs(ptch_x-med)))
    ptch.set_facecolor(color)
    if ptch_x <= med:
        m_height = ptch.get_height() + 0.3
    

ax.set_xlabel("Время победителей (минуты)", size=14)
ax.set_ylabel("Количество побед")

ax.annotate(f'Медиана {min_to_mmss(med)}', (med, m_height+0.2))
plt.plot([med,med],[0,m_height], 'r')

ldr_time = ptchs[0].get_x()
ldr_y_mark = ptchs[0].get_height() + 0.4
ax.annotate(f'Рекорд {min_to_mmss(ldr_time)}', (ldr_time, ldr_y_mark+0.5), rotation=60)
plt.plot([ldr_time,ldr_time],[0,ldr_y_mark], 'r')

lst_time = ptchs[-1].get_x() + ptchs[-1].get_width()
lst_y_mark = ptchs[-1].get_height() + 0.4
ax.annotate(f'Проведено паркранов {number_parkruns}', (lst_time, lst_y_mark+0.5), rotation=90)
plt.plot([lst_time,lst_time],[0,lst_y_mark], 'r')
plt.title('Распределение времени победы (мужчины)', size=16, fontweight='bold')

plt.tight_layout()
# plt.savefig('results.png')<jupyter_output><empty_output><jupyter_text>Статистика по мужчинам  Топ10 мужчин по числу побед<jupyter_code>data['men_name'].value_counts().head(10)<jupyter_output><empty_output><jupyter_text>Среднее время мужчины-победителя Рассчитывается среднее время на всех паркранах, на которых была одержана победа.Можно видеть чего примерно ждать от того или иного участника.<jupyter_code>leaders_men_avr_time = data.groupby('men_name')['men_time_m'].mean().sort_values(ascending=False)
mm = data['men_time_m'].mean() * 1.02
plt.figure(figsize=(7,7))
plt.xlim([int(leaders_men_avr_time[-1]), 1.01 * mm])
ax = leaders_men_avr_time[leaders_men_avr_time < mm].plot(kind = 'barh', grid=True)
for ptch, tick in zip(ax.patches, ax.yaxis.get_major_ticks()):
    c = '#2ca02c' if ptch.get_width() < mm / 1.02 else '#1f77b4'
    ptch.set_facecolor(c)
    ax.annotate(
        str(data['men_name'].value_counts()[tick.label.get_text()]), 
        (ptch.get_width()+0.03, ptch.get_y()+ptch.get_height()/5), size=8, color='r'
        )
ax.minorticks_on()
ax.grid(b=False, which='major', axis='y')
ax.grid(which='minor', axis='x', lw=0.5, ls=':')
ax.xaxis.set_major_locator(MultipleLocator(1))
ax.xaxis.set_minor_locator(MultipleLocator(1/6))
ax.xaxis.tick_top()
ax.yaxis.set_minor_locator(NullLocator())
ax.set_ylabel(f'Участники со средним временем победы до {min_to_mmss(mm)}')
plt.title('Среднее время и суммарное число побед', size=16, fontweight='bold')
plt.tight_layout()<jupyter_output><empty_output><jupyter_text>Среднее время победителя (мужчины)<jupyter_code>mean_men_time = data['men_time_m'].mean()
print(min_to_mmss(mean_men_time))<jupyter_output>17:49<jupyter_text>Топ10 мужских результатов<jupyter_code>data.sort_values(by=['men_time_m']).drop(data.iloc[:,[2,3,6,7,8,9]], axis=1).reset_index(drop=True).head(10)<jupyter_output><empty_output><jupyter_text>Статистика по женщинам  Топ10 женщин по числу побед<jupyter_code>data['women_name'].value_counts().head(10)<jupyter_output><empty_output><jupyter_text>Среднее время победителя (женщины)<jupyter_code>print(min_to_mmss(data['women_time_m'].mean()))
plt.figure(figsize=(16, 7))
ax = data['women_time_m'].hist(bins=30)
ax.yaxis.set_major_locator(MultipleLocator(4))
ptchs = ax.patches
med = data['women_time_m'].median()
norm = Normalize(min(2*med-ptchs[-1].get_x(), ptchs[0].get_x()), med)

for ptch in ptchs:
    ptch_x = ptch.get_x()
    color = plt.cm.plasma(norm(med-abs(ptch_x-med)))
    ptch.set_facecolor(color)
    if ptch_x <= med:
        m_height = ptch.get_height() + 0.3
    

ax.set_xlabel("Время победителей (минуты)", size=14)
ax.set_ylabel("Количество побед")

ax.annotate(f'Медиана {min_to_mmss(med)}', (med, m_height+0.2))
plt.plot([med,med],[0,m_height], 'r')

ldr_time = ptchs[0].get_x()
ldr_y_mark = ptchs[0].get_height() + 0.4
ax.annotate(f'Рекорд {min_to_mmss(ldr_time)}', (ldr_time, ldr_y_mark+0.5), rotation=60)
plt.plot([ldr_time, ldr_time], [0, ldr_y_mark], 'r')

lst_time = ptchs[-1].get_x() + ptchs[-1].get_width()
lst_y_mark = ptchs[-1].get_height() + 0.4
ax.annotate(f'Проведено паркранов {number_parkruns}', (lst_time, lst_y_mark+0.5), rotation=90)
plt.plot([lst_time, lst_time], [0, lst_y_mark], 'r')
plt.title('Распределение времени победы (женщины)', size=16, fontweight='bold')

plt.tight_layout()
# plt.savefig('results.png')<jupyter_output><empty_output><jupyter_text>Топ10 женских результатов<jupyter_code>data.sort_values(by=['women_time_m']).drop(data.iloc[:,[2,3,4,5,8,9]], axis=1).reset_index(drop=True).head(10)<jupyter_output><empty_output><jupyter_text>Среди женщин нет явных постоянных лидеров (участниц, которые регулярно выигрывают).А сильный разброс времени победительницы говорит также об очень слабой конкуренции и соревновательности.<jupyter_code>leaders_avr_time = data.groupby('women_name')['women_time_m'].mean().sort_values(ascending=False)
mm = data['women_time_m'].mean() * 1.02
plt.figure(figsize=(7,7))
plt.xlim([int(leaders_avr_time[-1]), 1.01 * mm])
ax = leaders_avr_time[leaders_avr_time < mm][:30].plot(kind = 'barh', grid=True)
for ptch, tick in zip(ax.patches, ax.yaxis.get_major_ticks()):
    c = '#2ca02c' if ptch.get_width() < mm / 1.02 else '#1f77b4'
    ptch.set_facecolor(c)
    ax.annotate(
        str(data['women_name'].value_counts()[tick.label.get_text()]), 
        (ptch.get_width()+0.03, ptch.get_y()+ptch.get_height()/5), size=8, color='r'
        )
ax.minorticks_on()
ax.grid(b=False, which='major', axis='y')
ax.grid(which='minor', axis='x', lw=0.5, ls=':')
ax.xaxis.set_major_locator(MultipleLocator(1))
ax.xaxis.set_minor_locator(MultipleLocator(1/6))
ax.xaxis.tick_top()
ax.yaxis.set_minor_locator(NullLocator())
ax.set_ylabel(f'Участницы со средним временем победы до {min_to_mmss(mm)}')
plt.title('Среднее время и суммарное число побед', size=16, fontweight='bold')
plt.tight_layout()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.18321342925659473, 'fraction_numerical': 0.029256594724220625, 'mean_word_length': 6.453976764968722, 'pattern_counts': {'":': 0, '<': 50, '<?xml version=': 0, '>': 45, 'https://': 1, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '335857', 'license': 'MIT', 'n_tokens_mistral': 3657, 'n_tokens_neox': 3670, 'n_words': 488, 'path': 'eventhistory.ipynb', 'repo_name': 'vol1ura/parkrun_analysis', 'size': '8340'}