矩陣分解推薦系統 — Python實戰:如何找出商品搭配的個體消費者策略?

Eric Huang 黃海潮
Marketingdatascience
7 min readNov 23, 2020

本篇文章要繼續和大家分享如何針對個體的消費者作有效的商品推薦,在前一篇文章《矩陣分解推薦系統 — Python實戰:商務資料結構整理》中,已經與各位講解如何將初始資料轉換為我們能夠分析的格式,如下圖所示:

圖 1、分析所需的資料集

有了這個整理好的資料後,我們希望將原本的dataframe轉為陣列(arrays),透過以下第一行的程式碼,即可將之前所整理的data_core轉為一個三維陣列。再者,我們再將這個陣列各自分成三個一維陣列。接著,將這三個陣列轉為Spotlight Interaction的形式,而這種資料形式即會將上列資訊包含在內,轉換成此種形式後,則可以更方便地使用Spotlight套件進行分析。如下程式碼1。

程式碼1:

# 資料集的重新處理
data = np.genfromtxt('data_core.csv', delimiter=',', names=True, dtype=(float, int, int))
usuarios = data['user_id']
items = data['item_id']
ratings = data['rating'].astype(np.float32)
dataset = Interactions(*(usuarios, items, ratings))

準備進入模型分析囉~

接下來就要進入最重要的模型分析部分,我們透過設定損失函數的選擇、演算的迭代次數等參數,來建立一個矩陣分解模型。接著,再將先前生成的dataset的Interaction透過Spotlight中的套件分解成訓練集與測試集。

接著將訓練集帶入先前設定的模型之中,除此之外,由於模型運算量較為龐大,我們在此使用pickle套件將模型的使用存成’finalized_model.sav’,在未來就能更方便地使用這個模型。如下程式碼2。

程式碼2:

model = ExplicitFactorizationModel(loss='regression',#logistic
embedding_dim=500,
#120 # latent dimensionality
n_iter=100,
# 500 number of epochs of training
batch_size=1024,
# minibatch size
l2=1e-7,
# strength of L2 regularization
learning_rate=1e-3,
use_cuda=torch.cuda.is_available())
from spotlight.cross_validation import random_train_test_split
train, test = random_train_test_split(dataset, random_state=np.random.RandomState(42))
print('Split into \n {} and \n {}.'.format(train, test))
# 此行產出分割的結果
model.fit(train, verbose=True) #fit# save model
pickle.dump(model, open('finalized_model.sav', 'wb'))

產出如圖2:

圖 2、 訓練集與測試集

在成功產出模型後,我們使用均方根誤差(RMSE)來衡量模型適配的程度,當RMSE越小時,則表示模型的適配程度越好。在Spotlight中,它也替我們寫好了計算RMSE的套件,可說是相當方便。如下程式碼3。

程式碼3:

train_rmse = rmse_score(model, train)
test_rmse = rmse_score(model, test)

透過這套模型,我們可以找出各個消費者最適合推薦的產品為何,在此以先前重新編號過的user_id = 0的這位消費者來作為範例。透過我們的模型,可以算出對此位消費者推薦對各產品的預測利潤,藉此作為日後行銷的基石。在計算出預測利潤後,我們將其對應到的商品與先前所建立起的pd_index.csv資料集來做串連,並將其命名為alld。如下程式碼4。

程式碼4:

i = 0
bought_prob = pd.DataFrame(model.predict(i), columns = ['預測利潤'])
item_index = pd.read_csv('pd_index.csv')
alld = pd.concat([item_index, bought_prob], axis= 1)
alld['user_id'] = i

產出如圖3:

圖 3、初始的產品推薦清單

但這樣的結束了嗎!?

但若只有這樣的資料,還不足以讓行銷人員能更方便地去做推薦,故我們在此將先前所做出的利潤評分表重新讀入成df2並與alld做合併,命名為user_single_data,此即user_id = 0的這位消費者的推薦清單。

在合併後,我們將NA值填入「沒買過」,藉此能提供行銷人員更多資訊,讓行銷人可以掌握更多推薦清單的資料,以利作行銷策略及行銷方案的有效規劃。

接著,我們將user_single_data中重複的一欄item_id刪除,並重新抓取該使用者原先真正的會員編號,也重新將欄位命名成較易讀的形式,最終的顧客推薦清單如下。如下程式碼5。

程式碼5:

df2 = pd.read_csv('data_core.csv')
# merge all data set together
user_single_data = pd.merge(df2, alld, on = ['user_id','item_id'],how='right')
user_single_data['rating'] = user_single_data['rating'].fillna('沒買過')
del user_single_data['item_id']
user_single_data['user_id'] = user_index['user'][i]
user_single_data.columns = ['利潤','會員編號','產品項目','預測利潤']
# 新增推薦順序
recomd = user_single_data[['產品項目','預測利潤']]
recomd = recomd.sort_values('預測利潤',ascending = False).reset_index(drop = True)
user_single_data['優先推薦產品'] = recomd['產品項目']
print(user_single_data)
user_single_data.to_csv('user_'+ str(i) +'_recommended.csv',encoding = 'utf-8-sig')

產出如圖4:

圖4、最終的產品推薦清單

前述的程式碼,即為單一用戶的推薦清單,若我們要對全體會員推薦最適合他的商品,可以使用for迴圈的方式執行,如此就可以從現存的資料庫中建構出一個更龐大且完整的推薦系統。

您也可以試著跟我的步驟進行分析看看哦~喜歡我的文章請給我多一些掌聲!!

作者:黃海潮 (臺灣行銷研究特邀作者)、鍾皓軒(臺灣行銷研究有限公司創辦人)

--

--

Eric Huang 黃海潮
Marketingdatascience

“All models are wrong, but some are useful” — George Box