前言
最近剛讀完《利用 Python 進行數據分析》,知識點還不是很牢固,于是想找些數據練手,剛好自己是個籃球迷,于是找了些 NBA 數據統計網站作為數據的來源,并借此來走一遍數據分析的流程。
背景
三雙
通常情況,是指在一場比賽中,得分,籃板,助攻,搶斷,蓋帽中,有三項技術統計達到兩位數,就被稱為「三雙」(不考慮失誤上雙的情況)。
豪華型三雙 & 經濟型三雙
并沒有明確標準來定義「豪華型」或「經濟型」,下文會以平均得分作為指標,平均得分越高就越「豪華」,反之則越「經濟」(實際上可以根據三雙數據的標準差來判斷選擇以得分作為標準的合理性)。
數據來源
來自 Basketball Refference,篩選了 1983-84 賽季至本賽季(2016-2017)的常規賽這段時間所有球員的三雙數據,查詢到結果共有 1449 人次獲得過三雙或以上(也會有四雙)。
數據抓取
雖然網站提供了 CSV 文本格式,但似乎并不支持下載(需要自己手動復制),此外,數據太詳細了,對于這次的分析來說,無效值太多了,與其在數據處理的過程中被繁多的數據項「轟炸」,還不如在抓取的過程中將符合分析需求的數據項篩選出來。
先來看看 Basketball Refference 都提供了哪些數據:
對于此次的分析來說,我們只需要抓取最基礎的數據項,如名字(Player)、得分(PTS)、籃板(TRB)、助攻(AST)、搶斷(STL)、蓋帽(BLK),當然,還可以根據自己的分析需求加上其他數據項。
確定了需要抓取的數據項后,再確定一下用于抓取的工具,這里我選擇了 Python + PySpider 框架。
PySpider
PySpider 是國內大神 binux 開發的一套簡單易用并且功能強大的爬蟲框架,支持多線程爬取、JS 動態解析,提供 WebUI、出錯重試、定時爬取等功能,非常人性化。
PySpider 官網:http://docs.pyspider.org/
代碼展示
閱讀 PySpider 文檔和 Sample Code,并作出修改:
1. 一頁獲取多個結果:PySpider 是有提供 url 去重功能的(避免重復抓取 url),而這個例子中的數據是以表格形式展示的(每條數據的 url 是相同的),所以需要人為地修改每條數據的 url,方法是在 url 的結尾加上一個數字標記「#i」。PySpider API 里提供了 self.send_message() 的方法,最后也別忘記設置 on_message()。
2. 設置逐頁爬取:response.doc 支持 css selector,所以在找到「下一頁」的標簽 url 后,將讓它重新執行 index_page(),實現逐頁爬取功能。
代碼在 PySpider 內置的編輯器上執行,點擊藍色 save 保存代碼,再點擊綠色的 run,就可以調試代碼能否正確爬取代碼。若確認數據就是自己想要的,可以回到 PySpider 的 Dashboard 上,將項目設置為 Debug 或 Running 狀態,再執行 Run,數據就會進行爬取了。
數據爬取完成后,點擊 Dashboard 該項目的 Results,右上方便有 CSV 文件下載的選項了,這個就是我想要的歷年 NBA 三雙球員場次的數據了。
數據清洗
網站爬蟲難免會爬取到一些無效值,在進行分析之前,先要對數據進行一番清理,避免影響數據分析的結果。由于我有其他的分析項目,所以我在數據爬蟲的時候,也爬取了其他的數據項,但對于本例子的分析項目來說,這些數據項就是無效值,需要清除。另外,表格出現若干帶有空值的行,這也是無效值,需要清理。另外,PySpider 也附加了一些無意義的列,也需要清理一下。如下圖,紅框框住的行/列,都是需要清洗掉的:
代碼展示
除了對無效值的清洗,數據清洗還包括對數據類型的轉換,通過 df.dtypes 指令可得知,例子中獲取到的 age 和 date 都是字符串數據類型,這樣就不方便進行數值化統計(比如平均年齡)等操作了。所以在進行分析前,還需要對這兩列的數據類型進行轉換。
(P.S. 這兩數據項在本例子里本應也是無效值,但作為展示數據清洗中的數據類型轉換,還是保留下來)
最后得出來的數據結果是:
至此,本例子的數據清洗,先到這一步,實際上在其他項目中,可能還需要進行的數據清洗的操作有,填充空值、去除數據中多余的空格、大小寫轉換、異常值替換等等。由于篇幅限制,就不展開討論了。
數據分析
數據分析最重要的是分析目標,只有明確了分析目標,才能明確下一步操作的思路。回到本例子中,是希望通過抓取的球員數據,分析出誰拿的三雙最「豪華」,誰的最「經濟」。
根據這一目標,只要匯總統計每個球員的三雙數據取平均值就可以了,不過在此之前,還需要對數據進行一番篩選,我們都知道,只有樣本數量較大的時候,數據平均值才不至于太夸張,這里我將篩選拿到超過 10 次三雙的球員進行比較:
player_tribles 就是我們想要的每位球員三雙場次的平均數據,輸入 player_tribles.head(10) 可得到以下的表格:
根據平均得分數值大小排名,抽取一部分進行比較:
1. 詹姆斯·哈登的三雙場次平均數據在得分、籃板、助攻上居然稍壓邁克爾·哪里都有我·喬丹,可以通過 df3[df3['player']=='James Harden'].sort_values(by='pts',ascending=False) 查看哈登所有的三雙場次數據,本賽常規賽居然打出了兩次驚世駭俗的 50 分三雙,還有 5 次 40 分三雙,所以三雙場次平均得分被拉上也不奇怪了;
2. 威少和詹姆斯兩位「全能戰士」的比較,威少在得分、籃板、助攻上穩壓詹姆斯,但籃球從來不是一個數據游戲,熟悉 NBA 的朋友應該知道,有些球員對比賽的影響并不會體現在數據上;
3. 一生宿敵,海軍上將與大夢,兩人的場均數據都沒有達到三雙,是什么原因呢,通過 df3[df3['player']=='...'] 查詢,原來他們都曾得過不同類型的三雙,包括「得分+籃板+助攻」類型和「得分+籃板+蓋帽」類型,所以數據平均下來沒有達到三雙,但也側面說面他們的全面身手。(P.S. 巧合的是,兩人都得到四雙)
4. 大家都熟悉的科比,共拿到 21 次三雙,24.48 的平均得分似乎并不符合歷史級得分高手的「人設」,要進一步探究的話,可以補充一下出手次數和命中率的數據,分析是他拿三雙的場次,到底是出手意愿不強,還是命中率被限制了。
同樣通過 player_tribles.tail(10) 也可以得出:
再來看看三雙場次平均得分較低的十位球員的數據:
1. 之前因為看球晚,印象中的經濟型三雙常客基德,實際上他在拿到三雙的比賽中平均得分不算低,可能是被生涯后期的數據拖累。而三雙拿得最「經濟」的當屬被我 Darrell Walker,曾是 93 公牛的一員,職業生涯最佳的賽季數據為 9.5+8.8+8(1989-90賽季 華盛頓子彈隊)。
2. 現役球員中,三雙平均數據最經濟的是追夢格林,平均得分居然沒有「真拒投」隆多高…通過 df3[df3['player']=='Draymond Green'] 查了一下,他居然在這賽季拿過一次「籃板+助攻+搶斷」的詭異三雙。
結語
至此,文章標題提到的問題相信已經有答案了,由于現有的數據已經能得出結論了,就不加入可視化的操作了(也考慮到篇幅問題)。帶著分析目的,從數據抓取到數據清洗,再到數據分析(甚至可視化),可以算是一個比較完整的分析過程了。每一個步驟產出不同的結果,一步一步逼近「真相」。
當然,本例子的數據量不大,數據清洗,數據分析以及可視化,都是可以通過其他工具(比如 Excel,BI)完成的,但如果數據量較大時,采用 Pandas 的優勢便會顯示出來。
文章里的代碼都是現學現賣的,未必是最優的解決方案,遇到問題,查查官方文檔就對了 :-)