好奇心和直覺是資料科學家最強大的兩個工具。第三個可能就是 Pandas 了。
我在 上一篇文章 中,展示瞭如何瞭解一個資料集的完整性,並繪製一些變數,以及檢視隨時間變化的趨勢和傾向。
為此,我在 Jupyter Notebook 上使用了 Python 的 Pandas 框架 進行資料分析和處理,並使用Seaborn 框架進行視覺化。
和本文一樣,前一篇文章中我們使用了 Kaggle 上 120 年奧運會資料集,研究了女性運動員隨時間推進的參與情況、運動員的體重和身高分佈以及其它一些變數的分析,但沒有使用到每一位運動員參與運動專案的資料。
這一次,我們將關注資料集的體育運動欄資料,並獲取一些關於它的資訊。
我能想到的幾個問題是:
- 哪項運動更有利於身材魁梧的人?個子高的人呢?
- 哪些運動專案較新,哪些較舊?有沒有什麼運動專案是由於失去了奧運會的青睞而停止了比賽呢?
- 有沒有在某些運動專案中,總是同樣的隊伍獲勝嗎?那最多樣化的運動呢,獲勝者是不是來自於不同的地區?
與前面一樣,我們分析中使用的專案放在 這個 Github 專案 中,你可以對其進行 fork(複製),並新增自己的分析和理解。
讓我們開始吧!
體重與身材分析
在我們的第一個分析中,我們想要分析看看哪些運動專案擁有最重和最高的運動員,哪些運動專案擁有最輕或最矮的運動員。
正如我們在前一篇文章中看到的,身高和體重都很大程度上取決於性別,資料集中男性運動員的資料比女性運動員的資料要多。所以我們會對男性做分析,但同樣的程式碼對任何一種性別都是適用的,只需要切換性別過濾器即可。
male_df = df[df.Sex==`M`]
sport_weight_height_metrics = male_df.groupby([`Sport`])[`Weight`,`Height`].agg(
[`min`,`max`,`mean`])
sport_weight_height_metrics.Weight.dropna().sort_values(`mean`, ascending=False)[:5]
複製程式碼
正如你所看見的那樣,如果我按運動進行分組,就可以計算每個運動運動員體重和身高的最小、最大和平均值。
然後我檢視了排名前五的擁有體重最重運動員的運動,發現(以公斤為單位):
Sport min max average
Tug-Of-War 75.0 118.0 95.61
Basketball 59.0 156.0 91.68
Rugby Sevens 65.0 113.0 91.00
Bobsleigh 55.0 145.0 90.38
Beach Volleyball 62.0 110.0 89.51
複製程式碼
不是很意外對吧?拔河運動員、籃球運動員和橄欖球運動員體重都很重。有趣的是,籃球和橄欖球運動員的體重變化很大,從 59 公斤到 156 公斤,而大多數拔河運動員的體重都超過了 80 公斤。
然後我畫出了每種運動的平均體重圖,發現它服從一個很好的正態分佈:
sns.distplot(sport_weight_height_metrics.Weight.dropna()[`mean`])
複製程式碼
運動員的平均體重是服從正態分佈的。
運動員的身高具有相似的正態分佈,但其方差很小,高度集中在均值附近:
運動員的身高是呈正態分佈的。
接下來,我開始繪製所有的個體平均值,在有序的散點圖中,看看是否有異常值出現。
means = list(sport_weight_height_metrics.Weight.dropna()[`mean`])
sports = list(sport_weight_height_metrics.Weight.dropna().index)
plot_data = sorted(zip(sports, means), key = lambda x:x[1])
plot_data_dict = {
`x` : [i for i, _ in enumerate(plot_data)],
`y` : [v[1] for i, v in enumerate(plot_data)],
`group` : [v[0] for i, v in enumerate(plot_data)]
}
sns.scatterplot(data = plot_data_dict, x = `x` , y = `y`)
複製程式碼
每個奧林匹克運動員的平均身高分佈。
實際上,擁有最重運動員的運動相對於圖表的其餘部分來說是非常離群的,而擁有最輕運動員的運動也是如此。如果我們在觀察一下身高,儘管方差明顯更小,但圖中顯示的“離群值”和接近均值的人之間的差異更大,更明顯的是大多數人並沒有偏離均值太多。
每項運動的運動員平均體重。
對於運動員體重最輕的運動,可以使用之前生成的變數 plot_data 來獲取結果。
print(`lightest:`)
for sport,weight in plot_data[:5]:
print(sport + `: ` + str(weight))
print(`
heaviest:`)
for sport,weight in plot_data[-5:]:
print(sport + `: ` + str(weight))
複製程式碼
結果(省略了最重的,因為我們已經在上面看過了)如下:
lightest:
Gymnastics: 63.3436047592
Ski Jumping: 65.2458805355
Boxing: 65.2962797951
Trampolining: 65.8378378378
Nordic Combined: 66.9095595127
複製程式碼
體操運動員中甚至是男性運動員,都是迄今為止體重最輕的運動員!緊隨其後的是跳臺滑雪、拳擊(這個讓我有點吃驚)和蹦床,這其實很合理。
如果我們尋找身高最高和最矮的運動員,結果就不會那麼令人驚訝了。我猜我們都期望與想象中同樣的運動能夠在榜首,不出所料,確實如此。至少我們現在可以說這不是刻板印象。
shortest (cm):
Gymnastics: 167.644438396
Weightlifting: 169.153061224
Trampolining: 171.368421053
Diving: 171.555352242
Wrestling: 172.870686236
複製程式碼
tallest (cm):
Rowing: 186.882697947
Handball: 188.778373113
Volleyball: 193.265659955
Beach Volleyball: 193.290909091
Basketball: 194.872623574
複製程式碼
我們可以看到體操運動員一般是很輕、很矮的。但是,身高排名中的一些運動專案並沒有出現在體重排名中。我想知道每種運動都有著什麼樣的“體型”(即重量 / 高度)?
mean_heights = sport_weight_height_metrics.Height.dropna()[`mean`]
mean_weights = sport_weight_height_metrics.Weight.dropna()[`mean`]
avg_build = mean_weights/mean_heights
avg_build.sort_values(ascending = True)
builds = list(avg_build.sort_values(ascending = True))
plot_dict = {`x`:[i for i,_ in enumerate(builds)],`y`:builds}
sns.lineplot(data=plot_dict, x=`x`, y=`y`)
複製程式碼
這幅圖看上去是線性的,直到我們到達大多數離群點落下來的頂端:
奧林匹克運動員的體型(重量/高度)分佈
以下是具有體型最小值和最大值的運動專案:
Smallest Build (Kg/centimeters)
Alpine Skiing 0.441989
Archery 0.431801
Art Competitions 0.430488
Athletics 0.410746
Badminton 0.413997
Heaviest Build
Tug-Of-War 0.523977
Rugby Sevens 0.497754
Bobsleigh 0.496656
Weightlifting 0.474433
Handball 0.473507
複製程式碼
橄欖球和拔河比賽是具有最大值體型的運動專案。這次高山滑雪的運動員則是擁有最小值體型中的一個,緊隨其後的是射箭和藝術比賽(這個是我剛知道的一項奧林匹克運動,需要進一步研究)。
隨時間推移的體育運動變化
現在我們已經做了所有能想到的關於這三列的有趣的事情,我想開始觀察一下時間變數。特別是今年。我想看看奧運會是否引進了新的運動專案,什麼時候引進。同樣也要觀察一下被廢棄的體育專案。
我們想要看一下一個東西第一次是什麼時候出現的,下面這段程式碼一般會很有用,特別是當我們想看一下某個變數的異常增長時。
from collections import Counter
sport_min_year = male_df.groupby(`Sport`).Year.agg([`min`,`max`])[`min`].sort_values(`index`)
year_count = Counter(sport_min_year)
year = list(year_count.keys())
new_sports = list(year_count.values())
data = {`x`:year, `y`:new_sports}
sns.scatterplot(data=data, x = `x`, y=`y`)
複製程式碼
結果
這張圖表向我們展示了每年有多少體育專案首次在奧運會上進行。或者,換句話說,每年有多少運動被引進:
Quantity of Sports introduced each year.
所以儘管在 1910 年之前就已經有很多運動專案,並且大多數的運動專案是在 1920 年之前引進的,但還是有很多新引進的。看著這些資料,我們就會發現 1936 年引進了很多新的運動專案,之後的每年引進的新專案就很少了(少於 5 個運動專案)
從 1936 年到 1960 年的這段時間裡沒有什麼新的運動專案引進,直到冬季兩項運動專案的出現,之後就定期地增加新專案:
Sport introduced
Biathlon 1960
Luge 1964
Volleyball 1964
Judo 1964
Table Tennis 1988
Baseball 1992
Short Track Speed Skating 1992
Badminton 1992
Freestyle Skiing 1992
Beach Volleyball 1996
Snowboarding 1998
Taekwondo 2000
Trampolining 2000
Triathlon 2000
Rugby Sevens 2016
複製程式碼
對廢棄運動(最大的年份並不在最近)進行的類比分析,結果顯示這張運動列表中,其中大部分我從未聽說過(儘管這絕不是衡量一項運動是否是流行的好指標!)
Basque Pelota 1900
Croquet 1900
Cricket 1900
Roque 1904
Jeu De Paume 1908
Racquets 1908
Motorboating 1908
Lacrosse 1908
Tug-Of-War 1920
Rugby 1924
Military Ski Patrol 1924
Polo 1936
Aeronautics 1936
Alpinism 1936
Art Competitions 1948
複製程式碼
我們看到藝術比賽在 1948 年被取消,馬球自 1936 年以來就沒有在奧運會上出現過,飛行比賽也是如此。如果有人知道飛行比賽到底是什麼,請告知我。我可以想到是在飛機上進行,但不知道比賽會是什麼樣子。也許是飛機飛行比賽?讓它們再回到賽場上吧!
今天就到這裡,夥計們!我希望你能喜歡這個教程,或許你已經得到了一個新的有趣的想法,可以在你的下次家庭晚餐中聊一聊。
和以往一樣,你可以隨意從該分析中 fork(複製)程式碼並新增自己的觀點。後續工作我正在考慮使用基於運動、體重和身高列的資料來 訓練一個小型的機器學習模型來預測運動員的性別,告訴我你會用什麼模型呢?
如果你覺得本文有什麼地方表述不正確,或者有一些簡單錯誤,請讓我知道,讓我們共同學習!
繼續訪問網站以獲取更多資料分析文章、Python 技術教程和其它資料相關內容。如果你喜歡這篇文章,請在 twitter 上與你的朋友分享。
可以在 Twitter 或者 Medium 上關注我獲取更多新內容。
如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。
掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。