# Spotify 讀書歌單推薦系統
**[Github](https://github.com/little-air-1019/Spotify-Songs-Recommendation-System-for-Studying)**
## 一、發想與目的
  許多人在學習或閱讀時都喜歡聆聽音樂,然而,要找到合適的歌單,或是自行建立歌單:邊聽邊篩選歌曲再一首一首加入播放清單中,相當費時。
Spotify 是全球擁有最多使用者的音樂串流平台,擁有龐大的音樂資料庫以及強大的API與活躍的開發者社群,因此選定Spotify為分析使用的音樂串流平台。
Spotify 本身已有多元的歌單,其中包含官方及社群分享的 Study Playlist,但官方歌單更新速度極慢,而社群分享的 Study Playlist 品質不一(部分收錄歌曲的曲調、音量、節奏...等,明顯不適合邊讀書邊聽),因此想設計一個==能為使用者生成推薦的讀書歌單的系統。==
## 二、實作架構
### 系統設計

1. 對曲目的曲調、音量、節奏、舞蹈性......等 12 種變項資料分析。
2. 建立機器學習模型,為使用者生成推薦的讀書歌單。
3. 透過前後端整合,以網頁的方式呈現系統。
### 資料蒐集
1. 以 “Study” 作為搜尋關鍵字,手動整理出Spotify官方推薦的讀書歌單以及社群追蹤數超過10000的讀書歌單(考量官方資料完整性及時下追蹤趨勢,蒐集到的歌曲以英語、韓語歌曲為主)。
2. 經過小組討論後,人工整理出可能不適合邊讀書時邊聽的歌曲類型:吵雜、節奏變化頻率高、舞蹈性太高,並以 “Heavy Metal”, “Rock”, “Party”, “Work out” 作為搜尋關鍵字,手動整理出Spotify官方推薦以及社群追蹤數超過10000的歌單。
3. 實作爬蟲的過程中,利用Spotify 所提供的 Audio Features API 來取得每首歌的變項,如:音高、節奏、音量、能量等等共計 12 種變項。初步蒐集完成後,得到兩個歌單資料集: “Study Playlist”(適合在學習時聆聽的歌曲)以及 “Non - Study Playlist”(非適合讀書歌曲)。
4. 採取「容許偽陽性、減少偽陰性」的原則整併資料:比對兩個資料集,若Non - Study Playlist資料集初步蒐集到的歌曲有被收錄在Study Playlist中,則將其視為適合讀書的歌曲,從Non - Study Playlist中刪除。
### 資料清理
1. 型別不相容及空值:由於資料集是根據Spotify上提供的特定格式資料爬取,因此,我們預想在多數情況下並不會有資料缺失的問題,但在我們實作過程進行分析或訓練時,仍有遇到少數型別上的不相容或是空值。利用 Pandas 將不相容的數值型態的欄位整理出來,將含有空欄位的資料列移除;若出現格式不符的資料,檢視是否僅是由部份的資料誤植所導致,若是則手動修正,而無法處理則逕行刪除。
2. 變數型態:查閱 Spotify 官方所提供的 Web API Refernece Documentation,發現音高 (key)、調性 (mode) 以及音符值 (time_signature) 屬於==類別變數==,因此使用 get_dummies 以 one-hot encoding 的方式取得虛擬變數。最後,使用 Normalize 將資料中的各變項進行正規化。
### 資料分析
#### 特徵相關圖
  使用相關性矩陣查看資料集中各個特徵的相關程度,其中與 good_for_study 相關性絕對值大於 0.5 的特徵為:energy, loudness, instrumentalness。

#### 特徵分佈圖
  雖然由上圖得知特徵的關聯性,卻不知在訓練集中的適合讀書的歌曲與非適合讀書的歌曲的資料特徵分布,因此,在下圖中依照將特徵兩兩分組,用不同顏色標示資料特徵分布。

### 模型建立
#### 資料集整併
  沒有被收錄在Study Playlist中的歌曲不一定不適合邊讀書邊聽,而是官方或建立熱門歌單者沒有將其選入Study Playlist中,但若有被收錄在Study Playlist中,則代表有人會認為這樣的歌曲適合邊讀書邊聽;另外,在這個推薦歌單的系統中,若將「適合讀書」定為陽性、「不適合讀書」為陰性,則應減少偽陰性,因為使用者在歌單中聽到認為不合適的歌曲時,可直接刪除,故希望生成的歌單中能有愈多可能適合邊讀書邊聽的歌曲愈佳。
  因上述原因,採取==容許偽陽性、減少偽陰性==的原則整併資料:比對 Study Playlist 資料集以及 Non - Study Playlist 資料集,若 Non - Study Playlist 資料集初步蒐集到的歌曲有被收錄在 Study Playlist 中,則將其視為適合讀書的歌曲,從 Non - Study Playlist 中刪除。最後,==利用 Shuffle 將資料隨機排序==,以避免分割訓練集與驗證集時,所分割的資料 good_for_study值不平均。
#### 選擇適當的模型
  在本階段預測目標為「是否適合讀書的音樂」,是二元分類問題,因此使用==分類模型==: DecisionTreeClassifier、RandomForestClassifier、XGBClassifier、LogisticRegression、KneighborsClassifier 以及 SVC 共計六種機器學習分類方式進行==模型表現評估==,並繪製根據學習資料比例,所呈現的學習分數。

由附圖結果觀察出前四者(DecisionTree、RandomForest、XGBoost,LogisticRegression)有較好的表現,經過資料蒐集調查,XGBoost 的 booster 參數可以使用gbtree(梯度提升樹),效果較隨機森林與決策樹具有更高的預測效果以及魯棒性。
因此,==選定 XGBoost(將 booster 參數設置為 gbtree) 和 LogisticRegression== 來進行下階段的模型評估與選擇。
#### 模型建立與調整參數
* XGBoost Model
* XGBoost 有原生介面以及 Sklearn 介面的分類器方式,儘管在參數相同情況下,執行效能應當相同,但根據不同的介面在算法上會造成些許差異,模型成果段落將會實作兩者,並表示其在準確性上的落差及特徵重要性排序的不同。
* 嘗試進行 Grid 交叉驗證,但參數過多影響執行效率,因此也有嘗試隨機方式抽取,但效果不如手動調參的成效佳,故最後參數經由手動調參完成。
* 參數決定考量:booster 採用 gbtree 分類方式會達到最好的效果、二元分類問題,因此將 num_class 設為 2;gamma 為避免參數過擬和,在 { 0.1, 0.2, 0.3 } 分別測試得出 0.1 最佳;max_depth 也同為避免過擬和,在 { 3, 4, 5, 6 } 得出 6 最佳;sub_sample 設置 0.7 表示每棵樹使用的訓練數據為原始數據集的 70%,提高模型泛化能力、eta(學習率)分別測試 { 0.01, 0.1, 1 } 得到 0.1 最佳。
* Logistic Regression
* 先以 C 值為 1、陽性門檻值為 0.05 建立一個模型作為比較基準,再使用迭代法尋找最佳C值陽性門檻值組合
* 透過自訂函式建立模型,並在函式內進行 **Cross validation prediction**,然後以格式化輸出呈現混淆矩陣,計算出 **Accuracy、Precision、Recall、F1 score** 四個評估分數,如圖:

* 雖然在整併資料集的原則是容許容許偽陽性、減少偽陰性,但在調整參數的過程中若以 Recall 值愈高愈好作為調整的原則,會導致最佳模型將所有資料都預測為陽性,因此模型評估方式採用以下兩種標準:**原始資料比對、F1 score**。
#### 模型效果
* Logistic Regression
* 進行交叉驗證 (10 folds),計算10次驗證所得之 F1-score 及 Accuracy,取其最大值、最小值、平均值以觀察模型表現:

* 使用 ROC 曲線繪製模型在不同閾值下分類性能,評估模型的整體預測能力:

* 計算ROC曲線下面積,得AUC值約為 0.881
* XGBoost
* Sklearn 介面分類器表現及其重要性特徵

* 原生介面分類器表現及其重要性特徵

由以上三組模型評估成績,觀察出==XGBoost的原生介面表現最佳==,因此選作為我們主要的機器學習模型使用
## 三、結果呈現
{%youtube iOmQXI_T7k0%}
## 四、協作方式
* 系統設計、資料蒐集、資料清理、模型建立與效能評估:職治四 楊淨雯
* 資料分析:資管一 林晏亘
* 模型建立與效能評估:資管一 林承佑
* 前後端整合:資管一 詹竣翔