直播系統,利用關聯規則實現推薦演算法

云豹科技-苏凌霄發表於2024-07-27

直播系統,利用關聯規則實現推薦演算法

關聯規則是以規則的方式呈現直播系統之間的相關性:關聯規則(Association Rules)是反映一個事物與其他事物之間的相互依存性和關聯性,是資料探勘的一個重要技術,用於從大量資料中挖掘出有價值的資料項之間的相關關係。

關聯規則的經典例子是透過發現顧客放入其購物籃中的不同商品之間的聯絡,可分析顧客在直播系統中的購買習慣。透過了解哪些商品頻繁地被顧客同時購買,可以幫助零售商制定營銷策略。

Apriori Algorithm(先驗)

它是一種購物車的分析方法,用於揭示產品之間的關聯關係。

他有三個簡單的公式:

Support(X, Y) = Freq(X, Y) / N :它表示 X 和 Y 一起出現的機率。它是 X 和 Y 一起出現的頻率除以 N。

Confidence(X, Y) = Freq(X, Y) / Freq(X) :表示購買產品X時購買產品Y的機率。X 和 Y 一起出現的頻率除以 X 出現的頻率。

Lift = Support(X, Y) / (Support(x) * Support (Y)) :當購買X時,購買Y的機率增加了lift的倍數。X 和 Y 一起出現的機率是 X 和 Y 分別出現的機率的乘積。它陳述了一個表示式,例如當我們購買一種產品時,購買另一種產品的機率會增加多少倍。

下面我們將使用Apriori Algorithm向使用者推薦相應的產品

資料預處理

這裡我們使用的資料集是online retail II dataset

!pip install mlxtend
import pandas as pd
pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)
pd.set_option('display.width', 500)
# It ensures that the output is on one line.
pd.set_option('display.expand_frame_repr', False)
from mlxtend.frequent_patterns import apriori, association_rules
df_ = pd.read_excel("datasets/online_retail_II.xlsx", sheet_name = "Year 2010-2011")
df = df_.copy()
df.info()
# Column       Non-Null Count   Dtype
# ---  ------       --------------   -----
#  0   Invoice      541910 non-null  object
#  1   StockCode    541910 non-null  object
#  2   Description  540456 non-null  object
#  3   Quantity     541910 non-null  int64
#  4   InvoiceDate  541910 non-null  datetime64[ns]
#  5   Price        541910 non-null  float64
#  6   Customer ID  406830 non-null  float64
#  7   Country      541910 non-null  objectdf.head()
#  Invoice StockCode                          Description  Quantity         InvoiceDate  Price  Customer ID         Country
# 0  536365    85123A   WHITE HANGING HEART T-LIGHT HOLDER         6 2010-12-01 08:26:00   2.55      17850.0  United Kingdom
# 1  536365     71053                  WHITE METAL LANTERN         6 2010-12-01 08:26:00   3.39      17850.0  United Kingdom
# 2  536365    84406B       CREAM CUPID HEARTS COAT HANGER         8 2010-12-01 08:26:00   2.75      17850.0  United Kingdom
# 3  536365    84029G  KNITTED UNION FLAG HOT WATER BOTTLE         6 2010-12-01 08:26:00   3.39      17850.0  United Kingdom
# 4  536365    84029E       RED WOOLLY HOTTIE WHITE HEART.         6 2010-12-01 08:26:00   3.39      17850.0  United Kingdom

我們使用這個函式來確定資料的閾值。

def outlier_thresholds(dataframe, variable):
    quartile1 = dataframe[variable].quantile(0.01)
    quartile3 = dataframe[variable].quantile(0.99)
    interquantile_range = quartile3 - quartile1
    up_limit = quartile3 + 1.5 * interquantile_range
    low_limit = quartile1 - 1.5 * interquantile_range
    return low_limit, up_limit

下面這個函用閾值替換了異常值。

def replace_with_thresholds(dataframe, variable):
    low_limit, up_limit = outlier_thresholds(dataframe, variable)
    dataframe.loc[(dataframe[variable] < low_limit), variable] = low_limit
    dataframe.loc[(dataframe[variable] > up_limit), variable] = up_limit

第三個函式中我們從資料中提取包含“C”的值。“C”表示退回的物品。要計算總價,變數數量和價格必須大於零。在這個函式中還呼叫了 Outlier 和 Threshold 函式。

def retail_data_prep(dataframe):
    dataframe.dropna(inplace=True)
    dataframe = dataframe[~dataframe["Invoice"].str.contains("C", na=False)]
    dataframe = dataframe[dataframe["Quantity"] > 0]
    dataframe = dataframe[dataframe["Price"] > 0]
    replace_with_thresholds(dataframe, "Quantity")
    replace_with_thresholds(dataframe, "Price")
    return dataframedf = retail_data_prep(df)

準備購買-物品的矩陣

資料集中的收據(Invoice)包含了產品的購買,所以我們先處理這個

df_gr = df[df['Country'] == 'Germany']
df_gr.head()
Invoice StockCode                          Description  Quantity         InvoiceDate  Price  Customer ID  Country
1109  536527     22809              SET OF 6 T-LIGHTS SANTA       6.0 2010-12-01 13:04:00   2.95      12662.0  Germany
1110  536527     84347  ROTATING SILVER ANGELS T-LIGHT HLDR       6.0 2010-12-01 13:04:00   2.55      12662.0  Germany
1111  536527     84945   MULTI COLOUR SILVER T-LIGHT HOLDER      12.0 2010-12-01 13:04:00   0.85      12662.0  Germany
1112  536527     22242        5 HOOK HANGER MAGIC TOADSTOOL      12.0 2010-12-01 13:04:00   1.65      12662.0  Germany
1113  536527     22244           3 HOOK HANGER MAGIC GARDEN      12.0 2010-12-01 13:04:00   1.95      12662.0  Germany

根據 Invoice 和 Description,我們透過 groupby 計算 Quantities,可以計算產品的數量。

df_gr.groupby(['Invoice', 'Description']).agg({"Quantity": "sum"}).head(20)
# Invoice Description
# 536527  3 HOOK HANGER MAGIC GARDEN               12.0
#         5 HOOK HANGER MAGIC TOADSTOOL            12.0
#         5 HOOK HANGER RED MAGIC TOADSTOOL        12.0
#         ASSORTED COLOUR LIZARD SUCTION HOOK      24.0
#         CHILDREN'S CIRCUS PARADE MUG             12.0
#         HOMEMADE JAM SCENTED CANDLES             12.0
#         HOT WATER BOTTLE BABUSHKA                 4.0
#         JUMBO BAG OWLS                           10.0
#         JUMBO BAG WOODLAND ANIMALS               10.0
#         MULTI COLOUR SILVER T-LIGHT HOLDER       12.0
#         PACK 3 FIRE ENGINE/CAR PATCHES           12.0
#         PICTURE DOMINOES                         12.0
#         POSTAGE                                   1.0
#         ROTATING SILVER ANGELS T-LIGHT HLDR       6.0
#         SET OF 6 T-LIGHTS SANTA                   6.0
# 536840  6 RIBBONS RUSTIC CHARM                   12.0
#         60 CAKE CASES VINTAGE CHRISTMAS          24.0
#         60 TEATIME FAIRY CAKE CASES              24.0
#         CAKE STAND WHITE TWO TIER LACE            2.0
#         JAM JAR WITH GREEN LID                   12.0

我們使用 unstack 來避免重複的索引,使用 iloc 來顯示前 5 個觀察結果。如果產品不在收據中,則 使用NA 表示。

df_gr.groupby(['Invoice', 'Description']).agg({"Quantity": "sum"}).unstack().iloc[0:5, 0:5]
# Description  50'S CHRISTMAS GIFT BAG LARGE  DOLLY GIRL BEAKER  I LOVE LONDON MINI BACKPACK  RED SPOT GIFT BAG LARGE  SET 2 TEA TOWELS I LOVE LONDON
# Invoice
# 536527                                 NaN                NaN                          NaN                      NaN                              NaN
# 536840                                 NaN                NaN                          NaN                      NaN                              NaN
# 536861                                 NaN                NaN                          NaN                      NaN                              NaN
# 536967                                 NaN                NaN                          NaN                      NaN                              NaN
# 536983                                 NaN                NaN                          NaN                      NaN                              NaN

進行獨熱編碼。把 NA 的地方寫 0。

df_gr.groupby(['Invoice', 'Description']).agg({"Quantity": "sum"}).unstack().fillna(0).iloc[0:5, 0:5]
# Description  50'S CHRISTMAS GIFT BAG LARGE  DOLLY GIRL BEAKER  I LOVE LONDON MINI BACKPACK  RED SPOT GIFT BAG LARGE  SET 2 TEA TOWELS I LOVE LONDON
# Invoice
# 536527                                 0.0                0.0                          0.0                      0.0                              0.0
# 536840                                 0.0                0.0                          0.0                      0.0                              0.0
# 536861                                 0.0                0.0                          0.0                      0.0                              0.0
# 536967                                 0.0                0.0                          0.0                      0.0                              0.0
# 536983                                 0.0                0.0                          0.0                      0.0                              0.0

如果發票中的產品數量大於0,我們就寫1,如果小於0或0,我們就寫0。用apply對行或列進行操作。這裡將透過應用 applymap 並執行操作來遍歷所有單元格。

df_gr.groupby(['Invoice', 'Description']).agg({"Quantity": "sum"}).unstack().fillna(0).applymap(lambda x: 1 if x > 0 else 0).iloc[0:5, 0:5]
# Description  50'S CHRISTMAS GIFT BAG LARGE  DOLLY GIRL BEAKER  I LOVE LONDON MINI BACKPACK  RED SPOT GIFT BAG LARGE  SET 2 TEA TOWELS I LOVE LONDON
# Invoice
# 536527                                   0                  0                            0                        0                                0
# 536840                                   0                  0                            0                        0                                0
# 536861                                   0                  0                            0                        0                                0
# 536967                                   0                  0                            0                        0                                0
# 536983                                   0                  0                            0                        0                                0

我們建立了一個名為 create_invoice_df 的函式。如果想根據id變數搜尋並得到結果,它會根據stockcode進行與上述相同的操作。如果我們輸入的id為False,它會根據Description執行上面的操作。

def create_invoice_product_df(dataframe, id=False):
    if id:
        return dataframe.groupby(['Invoice', "StockCode"])['Quantity'].sum().unstack().fillna(0). \
            applymap(lambda x: 1 if x > 0 else 0)
    else:
        return dataframe.groupby(['Invoice', 'Description'])['Quantity'].sum().unstack().fillna(0). \
            applymap(lambda x: 1 if x > 0 else 0)
gr_inv_pro_df = create_invoice_product_df(df_gr)
gr_inv_pro_df.head(20)
gr_inv_pro_df = create_invoice_product_df(df_gr, id=True)
gr_inv_pro_df.head()
def check_id(dataframe, stock_code):
    product_name = dataframe[dataframe["StockCode"] == stock_code][["Description"]].values[0].tolist()
    print(product_name)
    
check_id(df_gr, 16016)
# ['LARGE CHINESE STYLE SCISSOR']

所有可能的產品組合

frequent_itemsets = apriori(gr_inv_pro_df, min_support=0.01, use_colnames=True)
frequent_itemsets.sort_values("support", ascending=False).head()
#  support       itemsets
# 538   0.818381         (POST)
# 189   0.245077        (22326)
# 1864  0.225383  (POST, 22326)
# 191   0.157549        (22328)
# 1931  0.150985  (22328, POST)
check_id(df_gr, 22328)
#['ROUND SNACK BOXES SET OF 4 FRUITS ']

透過將我們用 Apriori 找到的Support插入到 association_rules 函式中,找到一些其他的統計資料,例如置信度和提升度。

rules = association_rules(frequent_itemsets, metric="support", min_threshold=0.01)
rules.sort_values("support", ascending=False).head()

POST產品和編號為22326的產品同時出現的機率為0.225383。被一起買的機率是0.275401。同時購買這兩種產品的機率增加為1.123735。

# antecedents consequents  antecedent support  consequent support   support  confidence      lift  leverage  conviction
# 2650      (POST)     (22326)            0.818381            0.245077  0.225383    0.275401  1.123735  0.024817    1.041850
# 2651     (22326)      (POST)            0.245077            0.818381  0.225383    0.919643  1.123735  0.024817    2.260151
# 2784     (22328)      (POST)            0.157549            0.818381  0.150985    0.958333  1.171012  0.022049    4.358862
# 2785      (POST)     (22328)            0.818381            0.157549  0.150985    0.184492  1.171012  0.022049    1.033038
# 2414     (22328)     (22326)            0.157549            0.245077  0.131291    0.833333  3.400298  0.092679    4.529540

以上就是直播系統,利用關聯規則實現推薦演算法, 更多內容歡迎關注之後的文章

相關文章