#!/usr/bin/env python # coding: utf-8 #

Data Mining Project 1: Frequent Pattern & Association Rule

# #

# 呂伯駿
# Q56074085
# NetDB
# National Cheng Kung University
# pclu@netdb.csie.ncku.edu.tw #

# # ## 1. Introduction # Frequent Pattern & Association Rule 是 Data mining 中的重要議題。 本次報告實作 Apriori [1] & FP Growth [2] 兩種經典算法,並使用IBM 合成資料集與 Kaggle Random Shop cart 資料集來比較兩者的效率。 # --- # # ## 2. Environment # # 這個部分我將會說明實驗所使用的環境與使用資料集。 # # ### 2.1 System Preferences # # 實驗環境如下: # - Operating System: macOS High Sierra (10.13.6) # - CPU: 1.3 GHz Intel Core i5 # - Memory: 8 GB 1600 MHz DDR3 # - Programming Language : Python 3.6.2 # # 由於所用資料集大小皆不超過 4MB,實驗環境記憶體足以符合實驗需求。 # # ### 2.2 Dataset # # 實驗使用以下資料集,來自 IBM Quest Synthetic Data Generator 以及 Kaggle。 # # #### a. IBM # # 本次實驗使用 IBM Quest Synthetic Data Generator Lit 模式合成了四組資料,參數設置如下表 # # | ntrans | tlength | nitems | # |----------|:-------------:|------:| # | 1 | 5 | 5 | # | 10 | 5 | 5 | # | 10 | 5 | 30 | # | 20 | 5 | 30 | # # - ntrans: number of transactions in _000 # - tlength: avg_items per transaction # - nitems: number of different items in _000 # # #### b. Kaggle: Random Shopping cart # # [Random Shopping cart](https://www.kaggle.com/fanatiks/shopping-cart/home) 包含隨機排序之購物車資料,適合本次尋找 Frequent Pattern 的實驗情境。
# 此資料集有 1499筆資料,總共有 38 種商品,由於每筆資料中物品有可能重複出現,後續仍須再次處理去除同一筆資料中之相同商品。 # # # # 資料範例如下: # # 1. yogurt, pork, sandwich bags, lunch meat, all- purpose, flour, soda, butter, vegetables, beef, aluminum foil, all- purpose, dinner rolls, shampoo, all- purpose, mixes, soap, laundry detergent, ice cream, dinner rolls, # 2. toilet paper, shampoo, hand soap, waffles, vegetables, cheeses, mixes, milk, sandwich bags, laundry detergent, dishwashing liquid/detergent, waffles, individual meals, hand soap, vegetables, individual meals, yogurt, cereals, shampoo, vegetables, aluminum foil, tortillas, mixes, # 3. ... # # --- # # ## 3. Implementation # # ### 3.1 pre-processing # # #### a. IBM # # IBM 所產生之資料格式為 id number(每一列),為方便運算我將相同id之資料轉換至同一行,中間以','分隔。 如 (1: 255,266,267...) # # # #### b. Kaggle # # 由於 Random Shopping cart 中的每一筆資料包含商品可能重複,因此再跑演算法之前需要將其過濾。
# 已過濾之資料路徑為: /data/Kaggle/cart_dataset_v2.txt
# 原始資料路徑則為: /data/Kaggle/cart_dataset_v1.txt # # # ### 3.2 Apriori # # 概念:
# 分為兩步驟,先迭代找出 Candidate Set,再篩選掉不符合 minimum support 的set。 # # 優點:
# 易實作,適合用在少量資料集。 # # 缺點: # 需要產生大量 Candidates 也要重複 Scan 資料集造成效能瓶頸。 # # ### 3.3 FP-growth # # 概念:
# 分為兩步驟,建立 FP-Tree,再從中尋找 Frequent Pattern。 # # 優點:
# 不需產生 Candidates,整體資料集僅需 Scan 兩次,速度較 Apriori 快一個量級。 # # 缺點:
# 需要額外構建 FP-Tree 來儲存各 pattern 出現次數。 # --- # # ## 4. Analysis # 實驗使用2.2 敘述之資料集,比較兩種演算法在改變 minsup 數值以及資料量的情況下其時間的變化。
# 其中 FP-Growth 之結果為十次運算之時間平均,Aprior 由於時間上之考量為兩次運算之時間平均。 # # ### a. IBM # In[67]: get_ipython().run_line_magic('matplotlib', 'inline') import pandas as pd import matplotlib.pyplot as plt ibm = pd.read_csv('./results/ibm.csv') kaggle = pd.read_csv('./results/kaggle.csv') ibm.head() # 上圖欄位分別為:
# data: data parameter
# minsup: minimum support
# fp_num: number of frequent pattern
# alforithm: choosen algorithm
# time: running time
# In[68]: # t1_l5_n5 plt.figure(figsize=(15, 15)) plt.subplot(421) x = [0.5, 0.6, 0.7, 0.8, 0.9] y_1 = ibm['time'][0:5] y_2 = ibm['time'][18:23] plt.plot(x, y_1, 'o-') plt.plot(x, y_2, 'o-') plt.xlabel('minsup (%)') plt.ylabel('time (sec)') plt.legend(["FP Growth", "Apriori"], loc=1); plt.title('Figure 1: t1_l5_n5'); plt.subplot(422) x = [0.5, 0.6, 0.7, 0.8, 0.9] y_1 = ibm['fp_num'][0:5] plt.plot(x, y_1, 'o-') plt.xlabel('minsup (%)') plt.ylabel('number of frequent pattern') plt.legend(["number of frequent pattern"], loc=1); plt.title('Figure 2: t1_l5_n5, fp number'); # t10_l5_n5 plt.subplot(423) x = [0.5, 0.6, 0.7, 0.8, 0.9] y_1 = ibm['time'][5:10] y_2 = ibm['time'][23:28] plt.plot(x, y_1, 'o-') plt.plot(x, y_2, 'o-') plt.xlabel('minsup (%)') plt.ylabel('time (sec)') plt.legend(["FP Growth", "Apriori"], loc=1); plt.title('Figure 3: t10_l5_n5'); plt.subplot(424) x = [0.5, 0.6, 0.7, 0.8, 0.9] y_1 = ibm['fp_num'][5:10] plt.plot(x, y_1, 'o-') plt.xlabel('minsup (%)') plt.ylabel('number of frequent pattern') plt.legend(["number of frequent pattern"], loc=1); plt.title('Figure 4: t10_l5_n5, fp number'); # t10_l5_n30 plt.subplot(425) x = [0.2, 0.3, 0.4, 0.5] y_1 = ibm['time'][10:14] y_2 = ibm['time'][28:32] plt.plot(x, y_1, 'o-') plt.plot(x, y_2, 'o-') plt.xlabel('minsup (%)') plt.ylabel('time (sec)') plt.legend(["FP Growth", "Apriori"], loc=1); plt.title('Figure 5: t10_l5_n30'); plt.subplot(426) x = [0.2, 0.3, 0.4, 0.5] y_1 = ibm['fp_num'][10:14] plt.plot(x, y_1, 'o-') plt.xlabel('minsup (%)') plt.ylabel('number of frequent pattern') plt.legend(["number of frequent pattern"], loc=1); plt.title('Figure 6: t10_l5_n30, fp number'); # t20_l5_n30 plt.subplot(427) x = [0.2, 0.3, 0.4, 0.5] y_1 = ibm['time'][14:18] y_2 = ibm['time'][32:36] plt.plot(x, y_1, 'o-') plt.plot(x, y_2, 'o-') plt.xlabel('minsup (%)') plt.ylabel('time (sec)') plt.legend(["FP Growth", "Apriori"], loc=1); plt.title('Figure 7: t20_l5_n30'); plt.subplot(428) x = [0.2, 0.3, 0.4, 0.5] y_1 = ibm['fp_num'][14:18] plt.plot(x, y_1, 'o-') plt.xlabel('minsup (%)') plt.ylabel('number of frequent pattern') plt.legend(["number of frequent pattern"], loc=1); plt.title('Figure 8: t20_l5_n30, fp number'); plt.tight_layout() plt.show() # 在 IBM 合成資料集中,實驗使用四種不同 item 數,與資料量數之資料,結果顯示在 Figure 1 ~ Figure 4 中。 # minsup由於不同資料集所含 frequent patterns 數目不同,因此有 0.5% ~ 0.9%, 0.2% ~ 0.5% 兩種設定。 # 在實驗中可以觀察到 FP growth 的效率遠遠超過 Apriori。 而當 minsup 值升高時兩者的時間差則開始縮小,其原因是因為 minsup 值升高則frequent pattern 的數目減少,而 Apriori 所需要 join 與搜索的 Candicates 數目也隨之減少的緣故。 #
#
# 改變 Item 種類數目
# 而從 Figure 3 跟 Figure 5 可以看到item 種類增加(5000~30000),Apriori 時間似乎會花較久,但事實上是因為後者生成之的FP數目較多,Candidate 數目也較多所導致。 #
# 改變 Datasize
# Figure 5 與 Figure 7 則是改變 Transaction 數目,從約10000筆資料到 20000筆資料。 雖然 Apriori 需要不斷 Scan 整份資料集,但可以看到在目前的資料量下,Apriori 依然是FP 數目影響較大,FP 越多,花的時間越多, 但 FP growth 就不同了,雖然圖片看來差異不大,但在20000筆資料所花的時間是略為大於10000筆資料的。 # # # # In[73]: x = [2, 4, 6, 8] y_1 = [0.014822602272033691,0.024219989776611328,0.04265165328979492,0.037372589111328125] y_2 = [1.559230923652649,3.5876978635787964,3.9564480781555176,5.6181875467300415] plt.plot(x, y_1, 'o-') plt.plot(x, y_2, 'o-') plt.xlabel('data size (10^3)') plt.ylabel('time (sec)') plt.legend(["FP Growth", "Apriori"], loc=2); plt.title('Figure 9: Scalability (minsup = 0.8%'); # 進一步改變 Data size 的結果可參考 Figure 9。 此實驗固定minsup 為0.8%,可觀察到兩者時間皆會隨者資料量增加而提升,但可看到 FP-growth 的時間改變量並不大,在資料量高時具有拓展性。 # ### b. Kaggle # # # In[39]: kaggle.head() # In[74]: plt.figure(figsize=(15, 10)) plt.subplot(121) x = [5, 6, 7, 8, 9, 10] y_1 = kaggle['time'][0:6] y_2 = kaggle['time'][6:12] plt.plot(x, y_1, 'o-') plt.plot(x, y_2, 'o-') plt.xlabel('minsup (%)') plt.ylabel('time (sec)') plt.legend(["FP Growth", "Apriori"], loc=1); plt.title('Figure 10: kaggle running time'); plt.subplot(122) x = [5, 6, 7, 8, 9, 10] y_1 = kaggle['fp_num'][0:6] plt.plot(x, y_1, 'o-') plt.xlabel('minsup (%)') plt.ylabel('number of frequent pattern') plt.legend(["number of frequent pattern"], loc=2); plt.title('Figure 11: kaggle fp number'); plt.show() # 觀察 Figure 10 與 Figure 11,在 Kaggle 資料集 Apriori 依舊比 FP-growth 慢許多,雖然資料僅有 1499 筆,但平均每個 Transaction 有 15 項 Item,算法需要花費極大的Join 與 prune 時間,為此即便FP 數目少 Apriori 所花費時間仍為IBM 1000 筆資料時的 20倍。 # ### c. Association rules # 由於IBM資料集是合成資料,探討其 Association Rules 意義較低,因此以下僅提供 Random Shopping Cart 出現頻率前五高的 Rules。 # In[72]: rules = pd.read_csv('rules.csv') rules.head(10) # ## 5. Conclusion # FP-Growth 算法比起 Apriori 有顯著的效率差異,原因是它透過建立 FP-Tree 來減少探索時間,相對的 Apriori 則需要不斷 Scan 資料集來確認是否滿足 minisup 條件。 雖然這種FP-Tree的結構在資料量大時仍具有優勢,但當 frequent patterns 的數目減少時(minsup增加),兩者的時間差異會越來越少,這時建立 FP-Tree 這種資料結構的時間花費便體現出來。
# ## 6. References # [1] In Proceedings of the 20th International Conference on Very Large Data Bases, VLDB ’94, pages 487–499, San Francisco, CA, USA, 1994. Morgan Kaufmann Publishers Inc.
# [2] J. Han, J. Pei, and Y. Yin: “Mining frequent patterns without candidate generation”. In Proc. ACM-SIGMOD’2000, pp. 1-12, Dallas, TX, May 2000.