Thuật toán Apriori

Một phần của tài liệu (LUẬN VĂN THẠC SĨ) Một số phương pháp khai phá dữ liệu sinh luật kết hợp Luận văn ThS Công nghệ thông tin 1.01.10 (Trang 34)

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.

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)

(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ớ trong và xử lý trực tiếp trên bộ nhớ trong do đó để tìm các tập mục phổ biến địa phương thì ta chỉ cần duyệt CSDL D (bộ nhớ ngoài) duy nhất 1 lần. Các tập mục phổ biến địa phương có thể hoặc không là tập mục phổ biến của toàn bộ CSDL D nhưng bất kỳ tập mục nào là phổ biến tổng thể phải là phổ biến của ít nhất 1 vùng, do đó tập hợp các tập mục phổ biến địa phương từ tất cả các vùng sẽ được tập các tập mục ứng cử tổng thể.

+ Giai đoạn 2, duyệt CSDL D lần thứ 2 để tính độ hỗ trợ cho mỗi ứng cử nhằm xác định tập mục phổ biến tổng thể.

3.1.3.4. Lấy mẫu (Sampling)

Ý tưởng cơ bản của cách tiếp cận lấy mẫu này là dựa trên xác suất thống kê, lấy ngẫu nhiên S trên trên CSDL đã cho D và sau đó tìm các tập mục phổ biến trong S thay cho D. Kích thước của mẫu S phải đảm bảo đủ nhỏ để khai phá trực tiếp trong bộ nhớ trong nhờ đó tốc độ được cải thiện đáng kể nhưng điều quan trọng nhất là độ lớn của không gian hay độ phức tạp được cải thiện rất nhiều. Tuy nhiên, do S chỉ là bộ phận của D nên rất có thể một số tập mục phổ biến sẽ bị mất khi khai phá. Do đó cách lấy mẫu phải đảm bảo tính ngẫu nhiên và S cũng phải đủ lớn hơn một ngưỡng tối thiểu nào đó. Đồng thời chúng ta hạ thấp ngưỡng độ hỗ trợ cực tiểu minsup để tìm được nhiều hơn các tập mục phổ biến địa

Các giao dịch trong D Chia D thành n vùng Tìm các tập mục phổ biến địa phương cho mỗi vùng. Quét D lần 1 Tổ hợp các tập mục phổ biến địa phương để được tập mục ứng cử Tìm các tập mục phổ biến đích trong số các ứng cử. Quét D lần 2 Các tập mục phổ biến trong D

phương trong S (ký hiệu LS), tránh việc mất mát các tập mục phổ biến tổng thể. Lúc này ta chỉ cần duyệt toàn bộ D duy nhất 1 lần để tìm các tập mục phổ biến tổng thể. Cách tiếp cận lấy mẫu này rất hiệu quả khi D là cực lớn và phân bố tương đối ngẫu nhiên.

3.1.4. Sinh luật kết hợp từ tập mục phổ biến

Sau khi các tập mục phổ biến từ các giao dịch trong CSDL được tìm thấy, chúng ta đi tìm các luật kết hợp mạnh (Strong association rule) – là luật thoả mãn cả độ hỗ trợ cực tiểu và độ tin cậy cực tiểu: sup(X=>Y) minsupconf(X=>Y) minconf.

Trong đó: sup(X=>Y) = sup(XY)conf(X=>Y) = P(Y|X) = sup(XY) / sup(X). Các luật kết hợp có thể sinh ra như sau:

+ Với mỗi tập mục phổ biến l (sup(l) minsup), thực hiện sinh ra tất cả tập con a khác rỗng và khác l của l.

+ Với mỗi tập con a này, ta có luật a=>(l\a) nếu sup(l)/sup(a) minconf.

Xét CSDL D trong Bảng 3.2 và độ hỗ trợ được tính trong Hình 3.1, giả sử dữ liệu chứa tập mục phổ biến l={1,2,5}. Khi đó ta có các tập con khác rỗng của l (theo lực lượng giảm dần) là: {1,2}, {1,5}, {2,5}, {1}, {2}, {5} với độ tin cậy lần lượt là:

(r1) 1^2 => 5, conf = 2/4 = 50%. (r2) 1^5 => 2, conf = 2/2 = 100%. (r3) 2^5 => 1, conf = 2/2 = 100%. (r4) 1 => 2^5, conf = 2/6 = 33%. (r5) 2 => 1^5, conf = 2/7 = 29%. (r6) 5 => 1^2, conf = 2/2 = 100%.

Nếu ngưỡng độ tin cậy cực tiểu minconf=50% thì các luật r1, r2, r3, r6 là các luật kết hợp mạnh cần tìm.

3.1.4.1. Thuật toán đơn giản sinh luật kết hợp từ tập mục phổ biến

Chúng ta cải tiến thủ tục xử lý bằng cách sinh ra các tập con của tập mục lớn theo kiểu đệ quy ưu tiên độ sâu và theo lực lượng của tập con nhỏ dần. Ví dụ: với tập mục ABCD, đầu tiên ta xét ABC, sau đó mới là AB, .... Ưu điểm ở đây là nếu tập con a của tập mục lớn l không sinh ra được luật thì ta không cần xét đến các tập con của nó nữa. Chẳng hạn, nếu luật ABC=>D không đủ độ tin cậy thì ta không cần xét đến luật AB=>CD nữa.

Điều này có thể chứng minh như sau: Nếu luật a=>(l\a) không thoả mãn độ tin cậy:

conf(a=>(l\a)) < minconf, thì ba ta đều có sup(b)sup(a) và do vậy:

Bảng 3.7: Thuật toán đơn giản sinh luật kết hợp từ tập mục phổ biến.

Input: Tập các k-mục phổ biến L, ngưỡng tin cậy cực tiểu minconf.

Output: Tập luật.

Thực hiện: GenAllRules(L, minconf)

(1) Foreach (lk in L & k>1)

(2) GenRules(lk, lk, minconf); // Sinh luật cho từng tập mục phổ biến. (3) Return;

Bảng 3.8: Thủ tục GenRules.

Input: Tập k-mục phổ biến lk dùng để sinh luật, tập m-mụcam dùng để sinh ra các tập con làm vế trái của luật, ngưỡng tin cậy cực tiểu minconf.

Output: Tập luật ứng với lk.

Thực hiện: GenRules(lk, am, minconf)

(1) A = {am-1 | am-1  am}; (2) Foreach (am-1 in A) {

(3) conf = sup(lk) / sup(am-1); (4) If (conf  minconf) {

(5) OutputRule(am-1 => (lk\am-1), sup(lk), conf); (6) If (m > 2)

(7) GenRules(lk, am-1, minconf); (8) }

(9) }

(10) Return;

3.1.4.2. Thuật toán nhanh hơn sinh luật kết hợp từ tập mục phổ biến

Ở trên ta đã chỉ ra rằng nếu một luật không thoả mãn độ tin cậy với tập cha a (ở vế trái) thì cũng không thoả mãn với tập con của nó. Ví dụ: nếu ABC=>D không đủ độ tin cậy thì luật AB=>CD cũng không đủ độ tin cậy, tương tự nếu ABD=>C không đủ độ tin cậy thì luật AB=>CD cũng không đủ độ tin cậy. Điều đó gợi ý cho ta áp dụng tính chất Apriori đối với vế phải của luật.

Bảng 3.9: Thuật toán nhanh hơn sinh luật kết hợp từ tập mục phổ biến.

Input: Tập các k-mục phổ biến L, ngưỡng tin cậy cực tiểu minconf.

Output: Tập luật.

Thực hiện: GenAllRulesNew(L, minconf)

(1) Foreach (lk in L & k>1) {

(2) H1 = {h1 | h1lk}; // h1 là 1 mục đơn trong lk và sẽ nằm ở vế phải của luật (lk\h1)=>h1. (3) Ap_GenRules(lk, H1, minconf);

(4) } (5) Return;

Bảng 3.10: Thủ tục Ap_GenRules.

Input: Tập k-mục phổ biến lk dùng để sinh luật, tập các m-mụcHm dùng làm vế phải của luật, ngưỡng tin cậy cực tiểu minconf.

Output: Tập luật ứng với lk.

Thực hiện: Ap_GenRules(lk, Hm, minconf)

(1) Foreach (hm in Hm) {

(2) conf = sup(lk) / sup(lk\hm); (3) If (conf  minconf)

(4) OutputRule((lk\hm) => hm, sup(lk), conf); (5) Else (6) Hm = Hm \ {hm}; (7) } (8) If (Hm != null & k > m+1) { (9) Hm+1 = Apriori_Gen(Hm); // Sinh tập ứng cử từ Hm. (10) Ap_GenRules(lk, Hm+1, minconf); (11) } (12) Return;

Thuật toán nhanh hơn này sử dụng thủ tục Apriori_Gen mô tả ở Bảng 3.4. Ta có thể thấy thuật toán vừa đưa ra nhanh hơn thuật toán đơn giản ban đầu vì thủ tục Apriori_Gen đã sử dụng tính chất Apriori để loại các ứng cử (của Hm+1) có tập con không nằm trong tập những mục đang xét (Hm).

Cụ thể: xét tập mục ABCDE và giả sử rằng chỉ có các luật ACDE=>BABCE=>D

là các luật có 1-mục ở phần kết luận thoả mãn độ hỗ trợ cực tiểu minconf.

Trong thuật toán đơn giản, thủ tục GenRules(ABCDE, ACDE, minconf) sẽ kiểm tra tất cả 4 luật với 2-mục ở phần kết luận (vế phải) là: ACD=>BE, ACE=>BD, ADE=>BC

CDE=>BA.

Còn trong thuật toán sau, nhờ thủ tục Apriori_Gen với Hm={B,D} ta có Hm+1={BD} và do vậy chỉ cần xét duy nhất luật ACE=>BD là đủ.

Độ phức tạp của các thuật toán sinh luật trong trường hợp xấu là O(n*2lmax) trong đó n

3.2. Thuật toán FP-Growth

3.2.1. Giới thiệu

Thuật toán kinh điển Apriori tìm tập mục phổ biến như trình bày ở trên thực hiện khá tốt bởi việc thu gọn không gian tập ứng cử nhờ kỹ thuật tỉa. Tuy nhiên trong tình huống mà số các mẫu nhiều, mẫu dài hoặc độ hỗ trợ cực tiểu thấp thì thuật toán này gặp phải 2 chi phí lớn là:

+ Chi phí cho số lượng khổng lồ các tập ứng cử. Ví dụ: nếu có 104 tập 1-mục phổ biến thì thuật toán Apriori sẽ cần sinh ra hơn 107 các ứng cử 2-mục và thực hiện kiểm tra sự xuất hiện của chúng. Hơn nữa, để 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. Ví dụ nếu l = 100 thì nó phải sinh ra tổng số 2100 tức là khoảng 1030 ứng cử (khổng lồ).

+ Đòi hỏi lặp quá nhiều lần duyệt CSDL (bộ nhớ ngoài) để tìm độ hỗ trợ của các ứng cử. Số lần duyệt CSDL của thuật toán Apriori bằng độ dài của mẫu phổ biến dài nhất tìm được. Trong trường hợp mẫu phổ biến dài và CSDL lớn thì điều này là không thể thực hiện được. Và vì vậy thuật toán Apriori chỉ thích hợp với các CSDL thưa (sparse), với các CSDL dày (dense) thuật toán này tỏ ra rất kém hiệu quả.

Năm 2000, Jian Pei, Jiawei Han và Yin đã đề xuất thuật toán FP-Growth giúp giải quyết cơ bản các vấn đề trên [106]. Đây là một thuật toán không sinh ứng cử và hiệu quả hơn thuật toán Apriori với 3 kỹ thuật chính sau:

+ Thực hiện mở rộng cấu trúc cây prefix, được gọi là cây mẫu phổ biến (Frequent pattern tree hay gọi tắt là FP-tree) dùng để nén CSDL. Các nút của cây được sắp đặt để các nút xuất hiện thường xuyên hơn có thể dễ dàng chia sẻ với các nút xuất hiện ít hơn. CSDL lớn được nén trong cấu trúc dữ liệu nhỏ hơn này giúp tránh việc duyệt CSDL trên bộ nhớ ngoài, không những vậy quá trình duyệt cũng ít hơn.

+ Phương pháp thực hiện khai phá phát triển (growth) từng đoạn dựa trên FP-tree. Bắt đầu từ mỗi mẫu phổ biến độ dài 1, FP-Growth chỉ xem xét CSDL phụ thuộc mẫu (conditional pattern base) tương ứng mà thôi. Thực hiện xây dựng conditional FP-tree từ CSDL con này và thực hiện khai phá đệ quy cây cho đến khi cây suy biến. Mẫu phát triển nhận được qua việc nối một đoạn mới (prefix pattern) được sinh ra từ conditional FP-tree với mẫu đang xét (suffix pattern). Khai phá dựa trên FP-tree thực hiện theo cách phát triển các đoạn mẫu để tránh chi phí trong việc sinh ra số lớn các ứng cử.

+ Kỹ thuật tìm kiếm được dùng ở đây là dựa trên chiến lược chia để chế ngự (divide and conquer), phân rã nhiệm vụ khai phá thành tập các nhiệm vụ nhỏ hơn với giới hạn các mẫu trong các CSDL nhằm thu gọn không gian tìm kiếm.

Một phần của tài liệu (LUẬN VĂN THẠC SĨ) Một số phương pháp khai phá dữ liệu sinh luật kết hợp Luận văn ThS Công nghệ thông tin 1.01.10 (Trang 34)