|
| 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 ด้วย |
0 commit comments