[新手Python 應用搭建指南] 3. IMDB老電影選取器
本系列文章我將手把手的帶你們完成應用程式專案。從選題,找資料,探索資料,最後進而搭建出應用並且部署在網頁上讓你可以秀給你的媽媽,老闆或是阿娜答。
關聯文章目錄
4篇轉職工具箱 Four weeks to reach even better
4篇新手Python 應用搭建指南
- python 基礎資料結構
- python if/ for /while
- (本篇)python套件 pandas/ 專案老電影選擇器
- python專案 食譜選擇器
前兩周我們花了一些篇幅研究程式的基本功,基本的組合元件,接下來你會發現,複雜的業務邏輯往往不是只有你有這個需求,你喜歡吃蛋餅大家都喜歡,做蛋餅的食譜大家早就寫好了,你不用再去測試甚麼比例才能做出好的粉漿。說到粉漿,你聽過全聯就有賣的生蛋餅皮嗎? 你直接買一張別人做好的蛋餅皮,就可以從冷凍庫拿出來煎,應該很少人從調粉漿開始的吧。
那這個蛋餅皮,就是因應需求被封裝好的一種介面。 (冷凍再包裝一包一個,要吃的時候拿出來煎就好) 。程式裡面常見的需求也不需要一直重複開發,就像我們開發車子不需要一直重新發明輪子。 約定俗成的需求,就開發一個套件來處理。
我們今天就來講套件吧
資料科學的三板斧, numpy, pandas, matplottlib(by the way, 這個字大概全台灣90%工程師念錯).
我們今天主要會介紹pandas
由於我們前面已經有紮實的基本功了,我們終於可以不用像之前一樣,手指指著遙控器上面每一個按鈕,從第一個按鈕講解到最後一個,相信脾氣比較不好沒耐性的同學應該已經想吃遙控器來洩憤了吧。 今天我們就來以需求為導向開發。
我身為需求方我來講講我們的情境吧。
是這樣的,在一個風和日麗的夜晚,我想要選一部老電影,最好是有點劇情片的動動腦,讓我配上一杯深沉的威士忌時能夠深思
明確一點的需求是我想做一個IMDB老電影選取器,可以幫我選出評價很高的特定主題老電影
首先我們來拆解需求,有三個需求,最後我希望拿到
- 特定時間的電影(時間區間)
- 可指定主題
- 顯示IMDB前十名
資料分析第一步,找資料,既然提到了電影就來去IMDB挖挖寶物吧
首先我們到這裡下載需要的資料
這裡有個簡單的資料使用教學(同學們可能會覺得打開火星文,沒關係,容我娓娓道來)
直接下載上面的csv 然後放到data子層級資料夾後就可以run
目前專案資料夾架構如下,我有一個imdb_data.py是參考上方啟動專案下載資料使用,如果直接使用我載好的資料集可以忽略這個檔案
目前專案run在imdb.ipynb上面,如果你採用跟我一樣的資料夾結果你應該可以在前五行跑完後出現以下的結果
那我們來開始分析吧
下面的程式碼可以看到全部的column name
第一個column是color 就看不懂在幹嘛
沒關係,可以搜尋一下資料集的定義,看完定義就知道是不是黑白電影的意思,恩 看起來資料集涵蓋非常老的電影
我們需要關注的有4點
- movie_title , 片名
- title_year 發行年份
- imdb_score, imdb分數
- genres, 類型
我們可以看到有91個獨立的年份,分別如下表示
也可以看到分數
也可以看到片名第一部是阿凡達
如果有人覺得那個\xa0很煩,我們後面可以把它去掉
大致上我們需要用的工具就是replace
下一個我們來看一個小魔王
你會發現它的類別安排了多標籤並且用”|”隔開,我們會因此選到非常多的獨立類別(順便介紹一下unique是獨立類別的意思,與此同時nunique則是獨立類別的數量)
我們想要的特性可能會接近當我選一個類別,只要多標籤裡面有包含我要的類別,就幫我回傳
那我們先看看,總過有幾種類別
先來看一下 我們要怎麼把這個 | 隔開的資料取出來
我發現當只有一個或是多個的時候,它都可以正常工作
那接下來我們就創造一個set(),並且把這每一個獨立的list update進去我們的set,就可以取得單一獨立的影片類別了
程式碼如下
執行成果 可以看到有26種類別
(26,
{‘Action’, ‘Adventure’, ‘Animation’, ‘Biography’, ‘Comedy’, ‘Crime’, ‘Documentary’, ‘Drama’, ‘Family’, ‘Fantasy’, ‘Film-Noir’, ‘Game-Show’, ‘History’, ‘Horror’, ‘Music’, ‘Musical’, ‘Mystery’, ‘News’, ‘Reality-TV’, ‘Romance’, ‘Sci-Fi’, ‘Short’, ‘Sport’, ‘Thriller’, ‘War’, ‘Western’})
下方我們開始設定選取器
首先我想要限制年份在1990~2000之間的電影
電影的數量從全部的5043 馬上降到了786
接下來因為我只對劇情片有興趣
我就濾掉了不包含劇情片的電影,剩下442個
最後我們按照imdb分數進行排序,在選取我們要的四個column並取前十名
目前先教到模組只用的部分,之後會補上如何進行應用化,大家可以先多摸摸看pandas,探索自己想要選取資料的方式
接下來的部分,會涉及到環境安裝,該來的還是要來,大家就一起挽起袖子開始吧
首先我們大致上分成三個步驟(以windows為例),如果有卡住的同學可以參考我的安裝教學
- 安裝python(3.8.9) — python執行
- 安裝vscode — 程式碼編輯器
- 安裝anaconda — 套件管理
首先我們需要安裝基本的python來當我們系統default的python,這時推薦將python加入我們的PATH,可以免除掉後續使用的很多麻煩,默認忘記勾選到想要事後加的朋友可以參考這篇
接下來我們使用vscode來擔任我們的編輯器,因為可以同時展示專案樹狀結構與程式碼區塊,同時還可以開始命令提示字元的執行介面,可以讓我們寫程式與測試效率大大提升,很推薦
最後則是使用anaconda來進行環境獨立套件管理,一般人可能比較難理解為什麼需要管理,是這樣的,因為python一個應用程式在執行的時候往往底層會需要跟很多套件協作,而套件在不同的版本時(version: x.y.z) 通常是中版號以上也就是y跟x,在進行變化時會涉及到呼叫的方式改變 ,也就是說,你call 函式時要放進去的參數可能順序不同,或是需要多放少放一些東西,如果你用舊版的呼叫方式可能就會出錯。因此我們需要對版本進行鎖定,通常專案的相依套件會放在requirements.txt檔案裏面並且用==來進行版本鎖定
舉一個我自己做的專案來當例子,我在這個專案中使用了opencv,為了避免將來opencv在版本更新時我現在的程式碼會出問題,因此我把我現在測試沒問題的版本鎖定好。 通常你會為你的專案給出一個range的版本,比如你用的功能比較新可能就會寫 opencv>4.5 之類的。
試想一個情境,如果你不同的專案一個需要4.5以上,一個需要剛好4.3。那麼你同一台電腦要怎麼處理這兩個不同的專案。答對了,就是刪刪裝裝。老闆今天請你開發A專案,你就打開A專案的相依套件檔案,一個一個手動解除安裝,在安裝成裡面要求的。這時候老闆跟你說B專案出問題了請你救個火,你就把剛剛安裝好A專案的需求解除安裝重新安裝B專案的。如果你有使用過AI套件的同學可能會知道這很痛,因為套件可能都幾個GB同時又有一堆大套件相依的小套件也要一併安裝,這樣裝裝刪刪太痛苦了
這時就有大神發現,其實可以把環境獨立出來,按照你現在的專案需求來切換套件就好了,使用conda activate {env_name}
來切換專案的相依套件,一鍵搞定。
首先我們開啟新的專案資料夾
並且conda create — name streamlit python==3.7.9
系統會問你是不是要這樣執行,輸入y 按enter
環境安裝好了, activate(啟動) 環境以及安裝streamlit(今日主角套件)
接著來看看手冊吧,工程師最重要的就是站在巨人的肩膀上,站著只能看遠而已,我們其實可以遙控巨人(怎麼變成進擊的巨人XD),遙控巨人的方式就是看官方出的說明文件,免不了的落落長英文,但通常是寫得最清晰有用的,相比於看中文文件,可能無法切入核心的使用方式,慢慢看原廠文件其實最有效率。
我們在專案資料夾下面改好檔案之後,在terminal使用streamlit run {filename}
來執行,vscode 要使用terminal可以使用快捷鍵 ctrl + ` (鍵盤最左上角的那個小鈕) +
{filename}的部分要改成自己檔案的命名,舉例來說下面的例子就是執行
streamlit run imdb_selector.py
以上就是將後端資料庫呈現在網頁前端的有史以來最簡便的方式。(恭喜你,你真的走了好大一步)
接下來回到我們的重點,我們想要搭建的imdb電影選取器,我們希望從使用者那邊拿到一些邊界條件,來讓我們調整應用變得更彈性
翻譯給電腦聽上面這句話: 我們要取得一些 input 並且儲存在 variable 裡面,留待後面使用
我們關心下列四種屬性
- movie_title , 片名 → 這個我們一開始無法限制,這是最後我們要取得的 data
- title_year 發行年份 → 這個我們需要兩個,分別是上界(2000)與下界(1990)
- imdb_score, imdb分數 → 這個也是我們後續要取得的,但可能可以限制至少需要幾分以上(加分題)
- genres, 類型 → 這個 是我們的重中之重,我們就是要選取特定的類別,我想規劃下拉式選單
接下來我們來定義需要的三個變數
- max_year: int, 電影最新發行年份
- min_year: int, 電影最新發行年份
- genres: str, 電影的類別
接下來我們到streamlit 看一下,變數跟使用者輸入要怎麼定義
點開下方的教學後,你可以看到裡面有幾種範例
首先我們要使用者輸入年份的text input (看了一看我覺得slider好像更好,我們可以晚點來玩 加分題2)
還有我們讓使用者選取的selectbox
下面我們就來拉些輸入,並且賦值到變數max_year, min_year中
存檔後我們重新整理一下網頁就會發現服務自動更新了
調整input窗裡面的數字,下面的回傳也是輕鬆調整
你可能馬上意識到用文字輸入框的問題,使用者可以隨興的輸入他要輸入的數字,但這數字可能很有問題(不存在的年份)
那我們換一個可以限制大小的
查了一下上面pandas分析時的日期表,發現年份最小是1916,最大是2016
在這個min max被定義好的情況如果你想要輸入不在區域的值,就會噴提示,不讓使用者輸入該值
處理好年份,我們要來處理類別的問題
首先,處理這個獨立類別是一個棘手的問題,我們寫一個丟進資料表自動幫我處理的小程式出來
首先我們先下載資料集,並丟到我們{app}.py所在的同一個資料夾
很好有把我們全部的類別印出來
現在就增加簡單一行
st.selectbox(‘select the genre you like’, unique_genres)
就產生一個下拉式選單,streamlit像魔法一樣,變出的結果完全是我們要
既然我們已經把這個類別做成資料集動態生成的,那我們就順便把年份也這樣處理
table_min_year = int(movie_table.title_year.min())
table_max_year = int(movie_table.title_year.max())
到現在為止,我們全部的依據資料集動態產生使用者輸入需求的程式碼就已經完成
調整一下我們的呈現方式,把原件換成slider,結果順眼多了,注意下面選了Drama也有被正確的印出來
此時你的code應該會像下面這樣
- 你可能會看到一個醜醜的cache,想說這是甚麼鬼東東
- 其實是這樣的,基本上streamlit 是一個隨著使用者做了任何改動都會重新載入的一種服務,如果你的資料集一直重新載入會很花時間,那我們能夠怎麼避免這個狀況呢,streamlit邦你想到了,就是利用cache, cache會去偵測內部的內容有沒有真的變更,如果沒有的話,就會拿記憶體裡面的來用就好,是不是很方便。
- cache可以協助我們更新網頁的時候pd讀取我們的表格不要讀取太久 因為可以放記憶體裡面,任何需要IO操作的東東都很適合放在cache
後面我們就馬不停蹄地把我們jupyter notebook 的code遷移過來吧
依照上一個教學貼上下列這些code
Demo影片
- 增加對缺失值的處理,讓年份可以用int的方式顯示。
- 由於是教學性的code,補上更多的註解來解釋每一段在幹嘛
最終專案APP部屬於streamlit
有些人可能會看不順眼年份是浮點數的問題,我也有發現,當我試著解決的時候我發現滿多坑的,如果有興趣的可以往這邊看
最終成果部屬於webapp
https://share.streamlit.io/yz830620/imdb_movie_streamlit/main/app.py
跟著我走到,你離在手機上看到自己的應用只剩一步之遙,下周就讓我們介紹怎麼將應用佈建在網際網路上,以及了解工程師最重要的程式碼管理工具Github
登泰山而小天下,跬步千里,大家一起加油