Skip to content

Commit 82000c5

Browse files
committed
kk Nov2018 Post
1 parent f2cc05e commit 82000c5

File tree

7 files changed

+190
-0
lines changed

7 files changed

+190
-0
lines changed

_posts/2018-11-12-CMU_marathon.md

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
---
2+
author: bachkukkik
3+
layout: post
4+
title: "แนะนำนักวิ่ง CMU Marathon 2019 แบบแแมวๆ"
5+
description: "webscraping, clean, plot แบบแมวๆ"
6+
tags: [CMU Marathon, Marathon]
7+
image:
8+
feature: post/cmu_marathon/cmu_marathon.png
9+
comments: true
10+
share: true
11+
date: 2018-11-12 23:30:00
12+
---
13+
14+
## เกริ่นนำ
15+
16+
ช่วงต้นเดือนกุมภาพันธ์ที่จะถึงนี้ ทางม.เชียงใหม่เค้าจัดให้ลงทะเบียน CMU Marathon เพื่อไปวิ่งที่เชียงใหม่กันครับ ซึ่งทางทีม Tupleblog ส่งตัวแทนเข้าชิง 2 นายด้วยกัน ได้แก่จารย์มาย (Titipata) และผมเอง (Bachkukkik)
17+
18+
นอกจากนี้ยังมีเพื่อนสนิทจากเมืองกรุงไปร่วมแจมงานวิ่งอีกหลายท่านด้วย อาทิเช่น เหลียงธนบุรี แพนด้าหัวลำโพง จ๋อดาวคะนอง เป็นต้น จัดว่าเป็น Mini Party ของ Tuple Team เลยครับ
19+
20+
ตอนวันที่ 11/11 เวลา 11.11 น. (วันคนโสด เวลาคนเหงา) เป็นฤกษ์งามยามดีครับที่ทาง มช. เค้าเปิดให้ลงทะเบียนทางเว็บไซต์ พอทุกคนลงเสร็จก็นึกอยากรู้อยากเห็นขึ้นมาว่า เอ เพื่อนๆพี่ๆน้องๆที่ร่วมสมัครวิ่งงานเดียวกันนี่เค้าเป็นใครกัน จะวิ่งเท่าไรกันบ้าง จะได้เตรียมตัวได้ถูกต้องเหมาะสมครับ
21+
22+
สำหรับใครที่จะเช็คชื่อคนไปวิ่ง สามารถดูได้ทางลิ้งนี้นะครับ https://go.cmu-marathon.com/retro-2019/runner เว็บเค้าทำไว้ดีมากทีเดียวครับ
23+
24+
## ด้วยความอยากรู้อยากเห็น
25+
26+
ส่วนผมที่อยากรู้จักทุกคนเลย ก็จะใช้ python การใน Scrape เว็บออกมาครับ โดยเริ่มจาก Code block ด้านล่างนี้เลยจ้า
27+
```py
28+
import pandas as pd
29+
import requests
30+
import seaborn as sns
31+
import matplotlib.pyplot as plt
32+
33+
URL = 'https://go.cmu-marathon.com/retro-2019/runner/tableRunner?init=1&order=asc&offset=0&limit=10000'
34+
data = requests.get(URL).json()
35+
marathon_df = pd.DataFrame(data['rows'])
36+
```
37+
<figure><center>
38+
<img width="800" src="images/post/cmu_marathon/marathon_df.png" data-action="zoom"/>
39+
40+
<figcaption>
41+
<a title="Inline Code 1">
42+
marathon_df.head()
43+
</a>
44+
</figcaption>
45+
</center></figure>
46+
47+
ได้มาเป็นตารางแบบที่ในเว็บเขาใช้ แต่ว่าได้มาทุกรายชื่อครับ และเราก็จะทำการ clean ข้อมูลจากภาษาไทยเป็นภาษาอังกฤษ เวลาพลอตกราฟจะได้อ่านง่ายครับ
48+
```py
49+
d = {'ชาย': 'M', 'หญิง': 'F'}
50+
marathon_df['gender'] = marathon_df.gender.map(lambda x: d[x])
51+
52+
def clean_string(s):
53+
s = s.replace('ฟันรัน', 'Fun Run').replace('ชาย', '')
54+
s = s.replace('หญิง', '').replace('ชาวต่างชาติ', 'foreigner')
55+
s = s.replace('ขึ้นไป', '>')
56+
s = s.replace('ปี', 'yo').replace('ฮาล์ฟมาราธอน', 'Half Marathon')
57+
s = s.replace('มินิมาราธอน', 'Mini Marathon')
58+
s = s.replace('มาราธอน', 'Marathon')
59+
return s
60+
61+
marathon_df['courseList'] = marathon_df.courseList.map(lambda x: clean_string(x))
62+
```
63+
<figure><center>
64+
<img width="800" src="images/post/cmu_marathon/cleand1_marathon_df.png" data-action="zoom"/>
65+
66+
<figcaption>
67+
<a title="Inline Code 1">
68+
marathon_df.head()
69+
</a>
70+
</figcaption>
71+
</center></figure>
72+
73+
## Plot แบบแมวๆ
74+
75+
อย่างแรกเลยที่ผมอยากรู้ก็คือทั้งนักวิ่งชาย นักวิ่งหญิงเนี่ย เค้าลงรายการไหนกันบ้าง ว่าแล้วก็ไปพลอตกราฟกันเลย ส่วนของโค้ดที่พลอตกราฟทั้งหมดต้องยกให้เครดิตจารย์มายครับ งานดี งานไวจริมๆ
76+
```py
77+
# เตรียมข้อมูลเพื่อตีกราฟ
78+
sum_df = marathon_df.groupby(['courseList', 'gender']).size().reset_index().rename(columns={0: 'Number of runners'})
79+
80+
order = [
81+
'Fun Run', 'Mini Marathon (16-19 yo)', 'Mini Marathon (20-29 yo)',
82+
'Mini Marathon (30-39 yo)', 'Mini Marathon (40-49 yo)',
83+
'Mini Marathon (50-59 yo)', 'Mini Marathon (60 yo>)',
84+
'Half Marathon (20-29 yo)',
85+
'Half Marathon (30-39 yo)', 'Half Marathon (40-49 yo)',
86+
'Half Marathon (50-59 yo)', 'Half Marathon (60 yo>)',
87+
'Marathon (20-29 yo)', 'Marathon (30-39 yo)',
88+
'Marathon (40-49 yo)', 'Marathon (50-59 yo)',
89+
'Marathon (60 yo>)', 'Marathon foreigner ']
90+
91+
# plot จริง
92+
g = sns.catplot(x='courseList',
93+
y='Number of runners',
94+
hue='gender',
95+
kind='bar',
96+
data=sum_df,
97+
order=order,
98+
palette="muted",
99+
size=7)
100+
g.set_xticklabels(rotation=90, fontsize=15)
101+
g.set_yticklabels(fontsize=15)
102+
g.set_ylabels(fontsize=15)
103+
g.set_xlabels(label='', fontsize=15)
104+
g.despine(left=True)
105+
```
106+
<figure><center>
107+
<img width="800" src="images/post/cmu_marathon/program_by_gender.png" data-action="zoom"/>
108+
109+
<figcaption>
110+
<a title="Inline Code 1">
111+
โปรแกรมวิ่งแบ่งตามเพศและวัย
112+
</a>
113+
</figcaption>
114+
</center></figure>
115+
116+
จากกราฟมีความน่าสนใจอยู่ว่า รายการวิ่งที่เบาๆ เน้นเป็นงานอดิเรก สาวๆจะชอบมากเป็นพิเศษครับ ให้ได้ชัดมากๆว่างาน Fun run / Mini Marathon นี่สาวๆทุกช่วงอายุให้ความสนใจเป็นอย่างมาก
117+
118+
แต่ก็ไม่ได้หมายความว่าหนุ่มๆจะไม่รักสุขภาพนะครับ แต่เหมือนจะชอบความ Challenge (หรือซาดิสต์ดีนะ) อธิบายได้จากกราฟครับ ชัดเจนว่างาน Half / Full Marathon นี่ ชายไทยจะชื่นชอบมากครับ
119+
120+
ที่น่าสนใจอีกข้อคือกลุ่มคนที่ชอบวิ่งงาน CMU Marathon ส่วนใหญ่จะอายุช่วง 30-39 ปีครับ
121+
122+
ส่วนผมกับจารย์มายน่ะหรอ สายบันเทิงครับ 10K พอ อิอิ
123+
124+
พลอตด้านล่างเทียบอัตราส่วนชายหญิงที่มาวิ่งของแต่ละโปรแกรมจ้า
125+
```py
126+
ratios = []
127+
for c, df in marathon_df.groupby('courseList'):
128+
try:
129+
ratio = len(df[df.gender == 'F']) / len(df[df.gender == 'M'])
130+
total = len(df)
131+
except:
132+
ratio = 0
133+
ratios.append({'courseList': c, 'y': ratio, 'x': total})
134+
ratio_df = pd.DataFrame(ratios)
135+
ax = ratio_df.plot(x='x',
136+
y='y',
137+
kind='scatter',
138+
figsize=(6, 6), fontsize=15)
139+
ax.set_xlabel('Number of Runners', fontsize=15)
140+
ax.set_ylabel('Female/Male Ratio', fontsize=15)
141+
142+
ratio_df[['x', 'y', 'courseList']].apply(lambda x: ax.text(*x),axis=1);
143+
plt.axhline(y=1, linewidth=1, color='grey')
144+
```
145+
<figure><center>
146+
<img width="800" src="images/post/cmu_marathon/ratio_program.png" data-action="zoom"/>
147+
148+
<figcaption>
149+
<a title="Inline Code 1">
150+
อัตราส่วนหญิงชายของแต่ละรายการวิ่ง
151+
</a>
152+
</figcaption>
153+
</center></figure>
154+
155+
อีกส่วนที่น่าสนใจมากๆคือ Size เสื้อของนักวิ่งครับ ตัวแทนเข้าชิงฝ่ายชายส่วนใหญ่จะมีขนาดประมาณ M-L ครับ ซึ่งถ้าสังเกตุจากความเกือบจะเป็น Bell-curve Distribution แล้ว ชายไทยก็ถือว่ามีไซส์มาตรฐานครับ (ผู้เขียนจำไม่ได้ว่าเสื้อขนาดเท่าไรยาวกี่นิ้ว อกกว้างกี่นิ้ว ครับ)
156+
157+
สำหรับนักวิ่งเข้าชิงฝ่ายหญิงนี่จะมีขนาดเสื้อทีมีความตัวผอม ตัวเล็กครับ ขนาดเสื้อส่วนใหญ่จะมีขนาด SS-M ซึ่งบางท่านที่มีส่วนสูง หรือ มีความเจ้าเนื้อมากเป็นพิเศษจึงต้องเพิ่มขนาดเสื้อให้เกินขนาด M ทำให้ Distribution ของขนาดเสื้อฝั่งนักวิ่งหญิงของงานนี้ไม่ได้เป็น Bell-curve แบบฝ่ายชายครับ
158+
```py
159+
size_df = marathon_df.groupby(['Shirt Size', 'gender'])\
160+
.size().reset_index().rename(columns={0: 'Number of runners'})
161+
162+
g = sns.catplot(x='Shirt Size',
163+
y='Number of runners',
164+
hue='gender',
165+
kind='bar',
166+
data=size_df,
167+
order=['3S', 'SS', 'S', 'M', 'L', 'XL', '2XL', '3XL', '4XL'],
168+
palette="muted",
169+
height=7)
170+
g.set_xticklabels(rotation=90, fontsize=15)
171+
g.set_yticklabels(fontsize=15)
172+
g.set_ylabels(fontsize=15)
173+
g.set_xlabels(label='', fontsize=15)
174+
g.despine(left=True)
175+
```
176+
<figure><center>
177+
<img width="800" src="images/post/cmu_marathon/shirt_size.png" data-action="zoom"/>
178+
179+
<figcaption>
180+
<a title="Inline Code 1">
181+
plot เรื่องขนาดเสื้อระหว่างชายหญิง
182+
</a>
183+
</figcaption>
184+
</center></figure>
185+
186+
และนี้ก็เป็นการทำความรู้จักนักวิ่งงาน CMU Marathon แบบคร่าวๆนะครับ สำหรับท่านไหนอยากรู้จักให้อยากรู้จักนักวิ่งให้มากกว่านี้ ต้องไปโดนเองที่เชียงใหม่แล้วครับ ^^
187+
188+
Stay Hungry. Stay Foolish.
189+
190+
> ขอบคุณจารย์มาย [@titipata](https://github.com/titipata) ที่ช่วยทำ plotting ให้นะครับ นอกจากนี้ใน Tupleteam ของเรายังมี จารย์ตุลย์ [@bluenex](https://github.com/bluenex) และ จารย์พี่ตั๋น [@kittinan](https://github.com/kittinan) เป็นผู้เขียน tupleblog ด้วย
83.8 KB
Loading
465 KB
Loading
85.8 KB
Loading
26.1 KB
Loading
11.7 KB
Loading
35 KB
Loading

0 commit comments

Comments
 (0)