Thuật toán Apriori

Một phần của tài liệu Một số phương pháp khai phá dữ liệu sinh luật kết hợp (Trang 29)

3. Chương 3: Một số phương pháp KPDL sinh luật kết hợp

3.1.Thuật toán Apriori

3.1.1. Giới thiệu

Các thuật toán khai phá luật kết hợp được đưa ra đều thực hiện hai pha:

+ Pha 1: tìm tất cả các tập mục phổ biến (độ hỗ trợ lớn hơn minsup), đây là pha tốn khá nhiều thời gian

+ Pha 2: tìm các luật kết hợp từ các tập mục phổ biến (độ tin cậy lớn hơn minconf), pha này đơn giản và tốn ít thời gian hơn nhiều so với Pha 1.

Các thuật toán khai phá luật kết hợp được đưa ra chủ yếu quan tâm đến Pha 1. Từ khi vấn đề khai phá tập mục phổ biến được đề cập, một số lượng lớn các thuật toán được đề xuất. Các thuật toán khai phá tập mục phổ biến đi theo hai hướng tiếp cận chính sau [105]: + Các thuật toán dựa trên hướng tiếp cận sinh ứng cử và kiểm tra (Generate candidate – and – test), điển hình là thuật toán Apriori.

+ Các thuật toán dựa trên hướng tiếp cận không sinh ứng cử, điển hình là thuật toán FP – Growth.

Thuật toán Apriori được Rakesh Agrawal, Tomaz Imielinski, Arun Swanmi đề xuất năm 1993, cho đến nay thuật toán này đã được nhiều nhà nghiên cứu phát triển để làm tăng tính hiệu quả của nó. Tên thuật toán APRIORI được bắt nguồn từ “Algorithm PRIOR knowledgement of frequent Itemset properties” [109]. Thuật toán sử dụng chiến lược đi từ dưới lên (bottom-up) và tìm kiếm theo chiều rộng (breath-first search).

Trong thuật toán này chúng ta sẽ duyệt nhiều lần CSDL. Trong lần duyệt thứ nhất, chúng ta tính độ hỗ trợ của các mục riêng biệt và xác định các mục phổ biến trong chúng (độ hỗ trợ lớn hơn minsup) – ký hiệu L1. Trong các lần duyệt thứ k, chúng ta thực hiện như sau:

(1) Bắt đầu với tập hạt giống (ký hiệu Lk-1) là tập các tập mục phổ biến đã tìm thấy trong lần duyệt trước (thứ k-1) để sinh ra (generate) các tập mục phổ biến tiềm năng hay các tập mục ứng cử (ký hiệu Ck).

(2) Duyệt CSDL để xác định độ hỗ trợ cho từng tập mục ứng cử. Lọc ra các tập mục có độ hỗ trợ lớn hơn minsup ta thu được Lk để làm tập hạt giống cho lần duyệt tiếp theo.

(3) Giải thuật dừng khi không có tập mục phổ biến nào tìm thấy (Lk = ).

Ta thấy trong thuật toán Apriori, tập ứng cử Ck được sinh ra hoàn toàn dựa trên tập hạt giống Lk-1, chứ không phải dựa trên việc quét CSDL. Cơ sở của điều này là tính chất: bất kỳ tập con nào của tập mục phổ biến cũng phải là phổ biến. Vì vậy, tập các ứng cử Ck có thể được sinh ra bằng cách kết nối các thành viên của tập các mục phổ biến hạt giống Lk-1

chung dẫn đến một số nhỏ hơn nhiều các tập ứng cử viên thông qua chiến lược tỉa không gian tìm kiếm như trên.

Không mất tính tổng quát, chúng ta giả định các mục trong mỗi giao dịch được lưu giữ theo trật tự từ điển. Gọi số lượng các mục trong một tập mục là kích thước của tập mục, và gọi tập mục có kích thước k là tập k-mục. Các mục trong mỗi tập mục cũng được lưu giữ theo trật tự từ điển. Chúng ta có bảng ký hiệu sau:

Ký hiệu Ý nghĩa

k-itemset Tập mục có k mục hay tập k-mục.

Lk Tập các k-itemset phổ biến (vượt ngưỡng minsup nào đó). Mỗi phần tử của tập này có hai trường hợp:

- Tập mục

- Độ hỗ trợ tương ứng của nó

Ck Tập các k-itemset ứng cử (tập các tập phổ biến tiềm năng). Mỗi phần tử của tập này có hai trường:

- Tập mục

- Độ hỗ trợ tương ứng của nó

Bảng 3.1: Ký hiệu mô tả trong thuật toán Apriori.

Chúng ta nhắc lại tính chất quan trọng đã nêu ở trên (còn gọi là tính chất Apriori) được sử dụng để rút gọn không gian tìm kiếm: Tất cả các tập con khác rỗng của tập mục phổ biến phải là tập mục phổ biến hay nói ngược lại: Nếu một tập mục không là phổ biến thì mọi tập mục chứa nó cũng không phải là phổ biến. Cụ thể: cho các tập mục I, A trong đó

sup(I) < minsup thì sup(I A) < minsup.

Quay lại thuật toán Apriori, ta xem xét cụ thể bước kết nốibước tỉa tại bước k: + Bước kết nối:

Để tìm Ck ta kết nối Lk-1 với chính nó. Ký hiệu li [j] là mục thứ j trong tập mục li. Như trên chúng ta đã quy ước các mục trong mọi giao dịch và trong mọi tập mục có trật tự từ điển. Phép nối Lk-1 với chính Lk-1 được thực hiện như sau: cho l1 , l2  Lk-1, l1 và l2 được kết nối nếu (l1 [1]=l2 [1]) ^ (l1 [2]=l2 [2]) ^ ... ^ (l1 [k-2]=l2 [k-2]) ^ (l1 [k-1]<l2 [k-2]).

Điều kiện (l1 [k-1]<l2 [k-2]) để đảm bảo không sinh lặp ứng cử. Kết quả của kết nối trên là tập mục sau: l = l1 [1]l1 [2]...l1 [k-2]l1 [k-1]l2 [k-1].

+ Bước tỉa:

Ta cần tìm Lk là tập tất cả các tập k-mục phổ biến. Ta khẳng định LkCk và do vậy chỉ cần quét CSDL để xác định độ hỗ trợ cho các tập mục trong Ck và so sánh với minsup

nhận được Lk. Tuy nhiên, Ck có thể rất lớn, và do đó khối lượng tính rất lớn. Để rút gọn kích thước của Ck, tính chất Apriori được áp dụng như sau: Bất kỳ tập con (k-1)-mục nào của ứng cử k-mục mà không có mặt trong Lk-1 thì ứng cử đó không phổ biến và ta loại nó khỏi Ck. Việc kiểm tra tập con (k-1)-mục này có thể làm nhanh bằng cách duy trì một cây băm của tất cả các tập mục phổ biến đã tìm thấy. (adsbygoogle = window.adsbygoogle || []).push({});

TID Items T100 1, 2, 5 T200 2, 4 T300 2, 3 T400 1, 2, 4 T500 1, 3 T600 2, 3 T700 1, 3 T800 1, 2, 3, 5 T900 1, 2, 3

Bảng 3.2: Cơ sở dữ liệu minh hoạ thuật toán Apriori.

Hình 3.1: Minh hoạ thuật toán Apriori. Itemset sup 1 6 2 7 3 6 4 2 5 2 C1 Itemset sup 1 6 2 7 3 6 4 2 5 2 L1 Itemset sup 1, 2 ? 1, 3 ? 1, 4 ? 1, 5 ? 2, 3 ? 2, 4 ? 2, 5 ? 3, 4 ? 3, 5 ? 4, 5 ? C2 Bắt đầu Quét D để tính sup Lọc lấy Itemset supminsup Sinh các ứng cử C2 từ L1 Quét D để tính sup Itemset sup 1, 2 4 1, 3 4 1, 4 1 1, 5 2 2, 3 4 2, 4 2 2, 5 2 3, 4 0 3, 5 1 4, 5 0 C2 Itemset sup 1, 2 4 1, 3 4 1, 5 2 2, 3 4 2, 4 2 2, 5 2 L2 Itemset sup 1, 2, 3 ? 1, 2, 5 ? C3 Sinh các ứng cử C3 từ L2 Itemset sup 1, 2, 3 2 1, 2, 5 2 C3 Lọc lấy Itemset supminsup Itemset sup 1, 2, 3 2 1, 2, 5 2 L3 Lọc lấy Itemset supminsup Quét D để tính sup Itemset sup null ? C4 Kết thúc Sinh các ứng cử C4 từ L3

Cụ thể:

(1) Trong lần lặp đầu tiên của thuật toán, mỗi mục là phần tử của tập ứng cử 1-mục: C1. Thuật toán đơn giản quét tất cả các giao dịch theo thứ tự để tính số lần xuất hiện của mỗi mục.

(2) Lọc lấy các phần tử thoả minsup ta được L1.

(3) Sinh ra tập ứng cử 2-mục: C2 bằng thực hiện phép kết nối L1 với L1. Chú ý là trong bước này ta có áp dụng tính chất Apriori, nhưng trong lần kết nối này nó không có tác dụng vì mọi tập con khác rỗng của các ứng cử đều phổ biến. Do đó số ứng cử được sinh ra chính là số tổ hợp C(2, |L1|) = C(2, 5) = 5!/(2!*3!) = 10.

(4) Quét CSDL D để tính độ hỗ trợ cho các phần tử trong C2.

(5) Lọc lấy các phần tử thoả minsup ta được L2={{1,2}, {1,3}, {1,5}, {2,3}, {2,4}, {2,5}}. (6) Sinh ra tập ứng cử 3-mục: C3. Thực hiện phép kết nối L2 với L2 ta thu được các ứng cử

{{1,2,3}, {1,2,5}, {1,3,5}, {2,3,4}, {2,3,5}, {2,4,5}}. Áp dụng tính chất Apriori rằng tất cả các tập con của tập mục phổ biến phải là phổ biến, ta loại đi 4 ứng cử cuối (ví dụ loại {2,4,5}{4,5}L2). Ý nghĩa của việc này là giảm tối đa sự cố gắng không cần thiết tính độ hỗ trợ cho các ứng cử khi quét CDSL và cũng chú ý là với ứng cử k-mục, ta chỉ cần xét sự tồn tại của các tập con (k-1)-mục trong L2 là đủ vì các tập con nhỏ hơn đã được kiểm tra trong các bước trước rồi. Kết quả C3 = {{1,2,3}, {1,2,5}}.

(7) Quét CSDL D để tính độ hỗ trợ cho các phần tử trong C3. (8) Lọc lấy các phần tử thoả minsup ta được L3={{1,2,3}, {1,2,5}}.

(9) Sinh ra tập ứng cử 4-mục: C4. Thực hiện phép kết nối L3 với L3 ta thu được duy nhất ứng cử {1,2,3,5}. Áp dụng tính chất Apriori rằng tất cả các tập con của tập mục phổ biến phải là phổ biến, ta loại đi ứng cử cuối (vì {2,3,5}L3). Do vậy C4 =  và kết thúc quá trình lặp. (10) Kết quả L = L1 L2 L3 = { {1}, {2}, {3}, {4}, {5}, {1,2}, {1,3}, {1,5}, {2,3}, {2,4}, {2,5}, {1,2,3}, {1,2,5} } 3.1.2. Thuật toán

Tại dòng (1) ta tìm các tập 1-mục phổ biến L1. Dòng (2)-(10), Lk-1 được sử dụng để sinh ra các ứng cử Ck, từ đó tìm ra Lk. Thủ tục Apriori_Gen (dòng (3)) sinh ra các ứng cử, trong đó sử dụng tính chất Apriori để loại trừ những ứng cử có tập con không phổ biến và xác định điều kiện lặp kết thúc khi Lk=. Quét CSDL D (dòng (4)), với mỗi giao dịch

tD, tìm tất cả các tập con (Subset) c của tcCk (dòng (5)). Tính tích luỹ độ hỗ trợ cho các tập con c này (dòng (6), (7)). Lọc lấy các tập con cCk thoả mãn minsup ta thu được Lk (dòng (9)). Tập hợp các Lk ta thu được tập các tập mục phổ biến L (dòng (11)).

Thủ tục Apriori_Gen thực hiện 2 công việc là kết nốitỉa. Trong bước nối, Lk-1 được nối với Lk-1 để sinh ra các ứng cử tiềm năng (dòng (1)-(4)). Bước tỉa (dòng (5)-(7)) sử dụng tính chất Apriori để loại các ứng cử có tập con không phải tập mục phổ biến, thủ tục được sử dụng là Has_Infrequent_Subset.

Có thể thấy thuật toán là đúng đắn tuy nhiên để khai phá được một mẫu phổ biến kích thước là l thì thuật toán phải sinh và kiểm tra (2l-1) mẫu phổ biến tiềm năng (số lượng tập con có thể có ngoại trừ rỗng). Và nếu coi mọi phép tính toán, kiểm tra và so sánh là 1 đơn vị thì trong trường hợp xấu độ phức tạp của thuật toán là O(n*2lmax) trong đó lmax là độ dài của tập mục phổ biến lớn nhất và n là số lượng tập mục.

Bảng 3.3: Thuật toán Apriori.

Input: CSDL D, ngưỡng độ hỗ trợ cực tiểu minsup.

Output: Tập L chứa mọi k-mục phổ biến trong D.

Thực hiện: Apriori(D, minsup)

(1) L1 = {x | x is a frequent item in D}; // L1: tập các tập 1-mục phổ biến. (2) For (k=2; Lk-1!=null; k++) {

(3) Ck = Apriori_Gen(Lk-1); // Sinh tập ứng cử từ Lk-1.

(4) Foreach (t in D) { // Quét D tính độ hỗ trợ cho các ứng cử.

(5) Ct=GetAllSubSets(Ck, t); // Tìm mọi c là subset của tcCk. (6) Foreach (c in Ct) (7) c.Count++; // Tích luỹ độ hỗ trợ. (8) } (9) Lk={cCk | c.Count  minsup} // Lọc. (10) } (11) Return L = Lk; Bảng 3.4: Thủ tục Apriori_Gen. Input: Tập các tập mục phổ biến Lk-1. Output: Tập ứng cử Ck. Thực hiện: Apriori_Gen(Lk-1) (1) Ck = null; (2) Foreach (l1 in Lk-1) { (3) Foreach (l2 in Lk-1) {

(4) If (l1[1]=l2[1]&l1[2]=l2[2]&...&l1[k-2]=l2[k-2]&l1[k-1]<l2[k-1]) { (5) c=Join(l1, l2);

(6) If (!Has_Infrequent_Subset(c, Lk-1)) // Tỉa. (7) Ck = Ck{c}; // Bổ sung c vào Ck. (8) }

(10) }

(11) Return Ck;

Bảng 3.5: Thủ tục Has_Infrequent_Subset.

Input:c - ứng cử k-mục. Tập các tập mục phổ biến Lk-1. (adsbygoogle = window.adsbygoogle || []).push({});

Output:true nếu trong c tồn tại ít nhất 1 subset không phổ biến, false nếu ngược lại.

Thực hiện: Has_Infrequent_Subset(c, Lk-1)

(1) S = {s | s is subset of c & length(s) = k-1}; // S: tập các tập (k-1)-mục là con của c. (2) Foreach (s in S) {

(3) If (s not in Lk-1) (4) Return true; (5) }

(6) Return false;

3.1.3. Nâng cao hiệu quả của thuật toán Apriori

Phần này nêu một số phương pháp cải tiến, biến đổi thuật toán Apriori nhằm nâng cao hiệu quả của thuật toán.

3.1.3.1. Sử dụng kỹ thuật băm

Bước tỉa (dòng (6) của thủ tục Apriori_Gen) đòi hỏi kiểm tra tất cả các tập con (k-1)- mục của tập k-mục ứng cử có phải là tập phổ biến không, tức là có mặt trong Lk-1 không. Để có thể kiểm tra nhanh chóng, ta lưu Lk-1 vào bảng băm (Hash table).

Bước tìm các ứng cử (dòng (5) của thuật toán Apriori) yêu cầu tìm tất cả các ứng cử c

được chứa trong giao dịch t khi biết tập các ứng cử Ck. Một giải pháp hiệu quả được đề xuất đó là sử dụng một cấu trúc dữ liệu đặc biệt là cây băm (Hash tree) để lưu tập các ứng cử Ck.

Cây băm là cây có thứ tự có cấu trúc như sau[101]: + Gốc của cây có độ sâu là 1.

+ Nút trong: Chứa một bảng băm với B cụm (bucket), mỗi cụm có giá trị định danh thuộc đoạn [0, B-1]. Mỗi cụm lại trỏ tới một nút khác. Nút trong ở độ sâu d trỏ tới các nút con ở độ sâu d+1. Trên các cung đi từ nút cha tới nút con được gán nhãn tương ứng với định danh của cụm.

+ Nút lá: là một danh sách chứa các tập k-mục được thuộc Ck. Xây dựng cây băm[101]:

+ Khi thêm một tập mục c, chúng ta bắt đầu đi từ gốc cây cho đến khi gặp nút lá. Tại một nút trong ở độ sâu d, chúng ta quyết định đi theo nhánh nào bằng cách áp dụng hàm băm cho mục thứ d của tập mục c. Ban đầu tất cả các nút được tạo ra là lá. Khi số lượng tập mục trong mỗi lá vượt quá ngưỡng nào đó thì ta chuyển lá thành nút trong.

+ v là một lá của cây băm ở độ sâu d.

+ b0, b1, ..., bd-1 là các nhãn bắt gặp trên cung của đường đi từ gốc T đến v. + Cv Ck là tập con của tập ứng cử lưu trong lá v.

Khi đó Cv = {XCk: h(X[i]) = bi, 0i<d} với X[i] là mục thứ i của tập mục X. Ví dụ: Ta xây dựng cây băm sau với các mục là các số nguyên. Trong đó:

+ Số bucket tại 1 nút trong: B = 3. + Hàm băm: h(w) = w mod 3.

+ Số phần tử tối đa tại nút lá Max = 3.

+ Tập mục ứng cử Ck = C3 = {{1,2,3}, {1,2,4}, {1,2,5}, {1,3,4}, {1,3,5}, {1,4,5}, {2,3,4}, {3,4,5}}.

Hình 3.2: Minh hoạ cây băm (Hash tree).

Tính độ hỗ trợ của các tập mục ứng cử với giao dịch t:

+ Bắt đầu từ nút gốc, chọn mục đầu tiên của t, và thực hiện băm với mục này. Giá trị của hàm băm cho biết nút đến ở bước tiếp theo.

+ Nếu ta đang ở nút lá ta tìm tập mục trong lá đó chứa trong t và thực hiện tăng số đếm độ hỗ trợ của tập đó lên 1 đơn vị.

+ Nếu ta đang ở nút trong của cây và ta đi tới nó bằng việc băm mục thứ i trong t thì nếu i<|t| thì thực hiện băm trên mục thứ i+1 trong t và thực hiện gọi đệ quy với kết quả băm mục thứ i+1. 0 1 2 0 1 2 Root 1 {3,4,5} {2,3,4} {1,3,4} {1,3,5} {1,2,3} {1,2,4} {1,2,5} {1,4,5} 0 2 C0 C1 C2 1 0 2 C10 C11 C12

Bảng 3.6: Thủ tục tính tích luỹ độ hỗ trợ của các ứng cử là tập con của giao dịch t.

Input: Giao dịch t, Nút hiện thời trên cây băm v, Chỉ mục i (giả sử i đánh số từ 0) hiện thời đang xét trong t và các mục trong t được sắp theo chiều tăng dần.

Output: Tích luỹ độ hỗ trợ cho các ứng cử X trên cây băm T.

Thực hiện: Accumulate(t, v, i) (adsbygoogle = window.adsbygoogle || []).push({});

(1) If (v is LeafNode) // Nếu v là nút lá.

(2) Foreach (X in Cv) // Duyệt mọi ứng cử lưu trong lá v. (3) If (Xt)

(4) Count(X)++;

(5) Else If (i<|t|) // Nếu v là nút trong và vẫn còn mục trong t. (6) For (j=i; j<|t|; j++)

(7) If (u is Child(v, h[t[j]])) // Nếu u là con của v theo cạnh có nhãn h[t[j]]. (8) Accumulate(t, u, j);

(9) Return;

Ví dụ: Xét t = {1,2,4,5}, sau thủ tục Accumulate(t, Root, 0) thì các ứng cử X sau lần lượt được tích luỹ biến đếm:

+ {1,2,4}, {1,2,5} qua các nút Root, C1, C12. + {1,4,5} qua các nút Root, C1, C11.

3.1.3.2. Rút gọn số giao dịch sau mỗi lần quét CSDL

Một giao dịch không chứa bất kỳ tập k-mục phổ biến nào thì cũng không thể chứa bất kỳ tập (k+1)-mục phổ biến. Do đó, ta có thể đánh dấu giao dịch này để loại bỏ không duyệt nó trong lần duyệt tiếp sau.

3.1.3.3. Phân hoạch (Partitioning)

Chúng ta biết rằng truy cập bộ nhớ ngoài tốc độ khá chậm, nên với kỹ thuật này chúng ta chỉ cần quét CSDL 2 lần trên bộ nhớ ngoài để khai phá các tập mục phổ biến.

Hình 3.3: Sơ đồ khai phá bằng phân hoạch dữ liệu.

Khai phá bằng phân hoạch dữ liệu gồm 2 giai đoạn:

+ Giai đoạn 1, thuật toán chia các giao dịch trong CSDL D thành n vùng. Nếu ngưỡng hỗ trợ cực tiểu của Dminsup thì ngưỡng hỗ trợ cực tiểu của vùng Di

minsup*(|Di|/|D|). Ta đi tìm các tập mục phổ biến cho các Di và gọi là tập các tập mục phổ biến địa phương (local frequent itemsets) trong đó Di được tải hoàn toàn vào bộ nhớ

Một phần của tài liệu Một số phương pháp khai phá dữ liệu sinh luật kết hợp (Trang 29)