ใครไปวิ่งงาน CMU Marathon 2019 บ้างจ๊ะ

bachkukkik bio photo

By bachkukkik

a lonely man stand alone is known as bachkukkik

Email Twitter Google+ Github

Reading time ~28 minutes

bachkukkik bio photo

By bachkukkik

a lonely man stand alone is known as bachkukkik

Email Twitter Google+ Github

เกริ่นนำ

ช่วงต้นเดือนกุมภาพันธ์ที่จะถึงนี้ ทางม.เชียงใหม่เค้าจัดให้ลงทะเบียน CMU Marathon เพื่อไปวิ่งที่เชียงใหม่กันครับ ซึ่งทางทีม tupleblog ส่งตัวแทนเข้าชิง 2 นายด้วยกัน ได้แก่จารย์มาย @titipata และผมเอง @bachkukkik

นอกจากนี้ยังมีเพื่อนสนิทจากเมืองกรุงไปร่วมแจมงานวิ่งอีกหลายท่านด้วย อาทิเช่น เหลียงธนบุรี แพนด้าหัวลำโพง จ๋อดาวคะนอง เป็นต้น จัดว่าเป็น Mini Party ของ tuple team เลยครับ

ตอนวันที่ 11/11 เวลา 11.11 น. (วันคนโสด เวลาคนเหงา) เป็นฤกษ์งามยามดีครับที่ทาง มช. เค้าเปิดให้ลงทะเบียนทางเว็บไซต์ พอทุกคนลงเสร็จก็นึกอยากรู้อยากเห็นขึ้นมาว่า เอ เพื่อนๆพี่ๆน้องๆที่ร่วมสมัครวิ่งงานเดียวกันนี่เค้าเป็นใครกัน จะวิ่งเท่าไรกันบ้าง จะได้เตรียมตัวได้ถูกต้องเหมาะสมครับ

สำหรับใครที่จะเช็คชื่อคนไปวิ่ง สามารถดูได้ทางลิ้งนี้นะครับ https://go.cmu-marathon.com/retro-2019/runner เว็บเค้าทำไว้ดีมากทีเดียวครับ

ด้วยความอยากรู้อยากเห็น

ผมอยากรู้จักทุกคนเลยครับ เลยจะใช้โปรแกรมภาษา Python การใน scrape เว็บออกมาดูครับว่า นักวิ่งของเราหน่วยก้านเป็นอย่างไรกันบ้าง โดยเริ่มจาก Code block ด้านล่างนี้เลยจ้า

import pandas as pd
import requests
import seaborn as sns
import matplotlib.pyplot as plt

URL = 'https://go.cmu-marathon.com/retro-2019/runner/tableRunner?init=1&order=asc&offset=0&limit=10000'
data = requests.get(URL).json()
marathon_df = pd.DataFrame(data['rows'])
marathon_df.head()

ได้มาเป็นตารางแบบที่ในเว็บเขาใช้ แต่ว่าได้มาทุกรายชื่อครับ และเราก็จะทำการ clean ข้อมูลจากภาษาไทยเป็นภาษาอังกฤษ เวลาพลอตกราฟจะได้อ่านง่ายครับ

d = {'ชาย': 'M', 'หญิง': 'F'}
marathon_df['gender'] = marathon_df.gender.map(lambda x: d[x])

def clean_string(s):
    s = s.replace('ฟันรัน', 'Fun Run').replace('ชาย', '')
    s = s.replace('หญิง', '').replace('ชาวต่างชาติ', 'foreigner')
    s = s.replace('ขึ้นไป', '>')
    s = s.replace('ปี', 'yo').replace('ฮาล์ฟมาราธอน', 'Half Marathon')
    s = s.replace('มินิมาราธอน', 'Mini Marathon')
    s = s.replace('มาราธอน', 'Marathon')
    return s

marathon_df['courseList'] = marathon_df.courseList.map(lambda x: clean_string(x))
sum_df.groupby('gender').sum()

สรุปจำนวนนักวิ่งชายหญิงได้เป็นดังนี้ครับ: นั่งวิ่งชายทั้งหมด 3,606 คนและนักวิ่งหญิง 3,225 คน

marathon_df.head()

Plot แบบแมวๆ

อย่างแรกเลยที่ผมอยากรู้ก็คือทั้งนักวิ่งชาย นักวิ่งหญิงเนี่ย เค้าลงรายการไหนกันบ้าง ว่าแล้วก็ไปพลอตกราฟกันเลย ส่วนของโค้ดที่พลอตกราฟทั้งหมดต้องยกให้เครดิตจารย์มายครับ งานดี งานไวจริมๆ

# เตรียมข้อมูลเพื่อตีกราฟ
sum_df = marathon_df.groupby(['courseList', 'gender']).size().reset_index().rename(columns={0: 'Number of runners'})

order = [
    'Fun Run', 'Mini Marathon  (16-19 yo)', 'Mini Marathon  (20-29 yo)',
    'Mini Marathon  (30-39 yo)', 'Mini Marathon  (40-49 yo)',
    'Mini Marathon  (50-59 yo)', 'Mini Marathon  (60 yo>)', 
    'Half Marathon  (20-29 yo)',
    'Half Marathon  (30-39 yo)', 'Half Marathon  (40-49 yo)',
    'Half Marathon  (50-59 yo)', 'Half Marathon  (60 yo>)',
    'Marathon  (20-29 yo)', 'Marathon  (30-39 yo)',
    'Marathon  (40-49 yo)', 'Marathon  (50-59 yo)',
    'Marathon  (60 yo>)', 'Marathon foreigner ']

# plot จริง
g = sns.catplot(x='courseList', 
                y='Number of runners', 
                hue='gender', 
                kind='bar', 
                data=sum_df, 
                order=order,
                palette="muted",
                size=7)
g.set_xticklabels(rotation=90, fontsize=15)
g.set_yticklabels(fontsize=15)
g.set_ylabels(fontsize=15)
g.set_xlabels(label='', fontsize=15)
g.despine(left=True)
โปรแกรมวิ่งแบ่งตามเพศและวัย

จากกราฟมีความน่าสนใจอยู่ว่า รายการวิ่งที่เบาๆ เน้นเป็นงานอดิเรก สาวๆจะชอบมากเป็นพิเศษครับ ให้ได้ชัดมากๆว่างาน Fun run / Mini Marathon นี่สาวๆทุกช่วงอายุให้ความสนใจเป็นอย่างมาก

แต่ก็ไม่ได้หมายความว่าหนุ่มๆจะไม่รักสุขภาพนะครับ แต่เหมือนจะชอบความ Challenge (หรือซาดิสต์ดีนะ) อธิบายได้จากกราฟครับ ชัดเจนว่างาน Half / Full Marathon นี่ ชายไทยจะชื่นชอบมากครับ

ที่น่าสนใจอีกข้อคือกลุ่มคนที่ชอบวิ่งงาน CMU Marathon ส่วนใหญ่จะอายุช่วง 30-39 ปีครับ

ส่วนผมกับจารย์มายน่ะหรอ สายบันเทิงครับ 10K พอ อิอิ

พลอตด้านล่างเทียบอัตราส่วนชายหญิงที่มาวิ่งของแต่ละโปรแกรมจ้า

ratios = []
for c, df in marathon_df.groupby('courseList'):
    try:
        ratio = len(df[df.gender == 'F']) / len(df[df.gender == 'M'])
        total = len(df)
    except:
        ratio = 0
    ratios.append({'courseList': c, 'y': ratio, 'x': total})
ratio_df = pd.DataFrame(ratios)
ax = ratio_df.plot(x='x', 
                  y='y', 
                  kind='scatter', 
                  figsize=(6, 6), fontsize=15)
ax.set_xlabel('Number of Runners', fontsize=15)
ax.set_ylabel('Female/Male Ratio', fontsize=15)

ratio_df[['x', 'y', 'courseList']].apply(lambda x: ax.text(*x),axis=1);
plt.axhline(y=1, linewidth=1, color='grey')
อัตราส่วนหญิงชายของแต่ละรายการวิ่ง (มี Fun run และ Mini Marathon เกือบทุกอายุที่อัตราส่วนของผู้หญิงมีมากกว่าผู้ชาย ที่เหลือผู้ชายมีมากกว่าฮะ)

อีกส่วนที่น่าสนใจมากๆคือ Size เสื้อของนักวิ่งครับ ตัวแทนเข้าชิงฝ่ายชายส่วนใหญ่จะมีขนาดประมาณ M-L ครับ ซึ่งถ้าสังเกตุจากความเกือบจะเป็น Bell-curve Distribution แล้ว ชายไทยก็ถือว่ามีไซส์มาตรฐานครับ (ผู้เขียนจำไม่ได้ว่าเสื้อขนาดเท่าไรยาวกี่นิ้ว อกกว้างกี่นิ้ว ครับ)

สำหรับนักวิ่งเข้าชิงฝ่ายหญิงนี่จะมีขนาดเสื้อทีมีความตัวผอม ตัวเล็กครับ ขนาดเสื้อส่วนใหญ่จะมีขนาด SS-M ซึ่งบางท่านที่มีส่วนสูง หรือ มีความเจ้าเนื้อมากเป็นพิเศษจึงต้องเพิ่มขนาดเสื้อให้เกินขนาด M ทำให้ Distribution ของขนาดเสื้อฝั่งนักวิ่งหญิงของงานนี้ไม่ได้เป็น Bell-curve แบบฝ่ายชายครับ

size_df = marathon_df.groupby(['Shirt Size', 'gender'])\
    .size().reset_index().rename(columns={0: 'Number of runners'})

g = sns.catplot(x='Shirt Size', 
                y='Number of runners', 
                hue='gender', 
                kind='bar', 
                data=size_df, 
                order=['3S', 'SS', 'S', 'M', 'L', 'XL', '2XL', '3XL', '4XL'],
                palette="muted",
                height=7)
g.set_xticklabels(rotation=90, fontsize=15)
g.set_yticklabels(fontsize=15)
g.set_ylabels(fontsize=15)
g.set_xlabels(label='', fontsize=15)
g.despine(left=True)
plot เรื่องขนาดเสื้อระหว่างชายหญิง

และนี้ก็เป็นการทำความรู้จักนักวิ่งงาน CMU Marathon แบบคร่าวๆนะครับ สำหรับท่านไหนอยากรู้จักนักวิ่งให้มากกว่านี้ ต้องไปโดนกันเองที่เชียงใหม่แล้วครับ ^^

Stay Hungry. Stay Foolish.

ขอบคุณจารย์มาย @titipata ที่ช่วยทำ plotting ให้นะครับ นอกจากนี้ใน tupleteam ของเรายังมี จารย์ตุลย์ @bluenex และ จารย์พี่ตั๋น @kittinan เป็นผู้เขียน tupleblog ด้วย

Pytorch กับ Gradient Descent

ทำความเข้าใจกับพื้นฐานของ Gradient Descent ผ่านไลบรารี่ Pytorch (สำหรับผู้ที่เริ่มศึกษา Deep Learning)