Một số thuật toán cơ bản

Một phần của tài liệu luật kết hợp mờ và ứng dụng đối với một số bài toán dự báo (Trang 25 - 34)

1.4.2.1. Thuật toán Apriori

Thuật toán Apriori được Agrawal và Srikant phát biểu năm 1994[3]. Apriori là thuật toán phổ biến nhất để tìm luật kết hợp, được coi là một sự cải tiến lớn trong lịch sử khai phá luật kết hợp vì đã vượt xa tầm của các thuật toán quen thuộc trong lĩnh vực này. Thuật toán dựa trên một nhận xét đơn giản là bất kỳ tập con nào của tập thường xuyên cũng là tập thường xuyên. Do đó, trong quá trình đi tìm tập ứng viênk Itemset, chỉ cần dùng đến các tập thường xuyên k-1 Itemset đã tìm thấy ở bước trước đó. Nhờ vậy, bộ nhớ được giải phóng đáng kể.

Thuật toán Apriori có hai bước để tìm ra tất cả các tập mục dữ liệu thường xuyên:

- Bƣớc 1: Duyệt qua CSDL để tìm ra tất cả các mục dữ liệu thường xuyên bằng

cách đếm số lần xuất hiện của từng mục trong tất cả các giao tác (Bảng 1.2.a), sau đó loại bỏ những mục dữ liệu có độ hỗ trợ nhỏ hơn Minsup, được tập L1. Tập L1 gọi là tập các mục dữ liệu thường xuyên một mục dữ liệu (Bảng 1.2.b). Trong bước 2, mỗi lần duyệt CSDL tiếp theo ta chỉ cần xét các mục dữ liệu trong bảng này.

- Bƣớc 2: Gọi Ck là tập các tập ứng viênkItemset, Lk là tập các tập thường xuyên

a) C'k là tập các tập k Itemset có được bằng cách hợp từng hai tập k-1 Itemset thường xuyên trong Lk-1 có k-2 mục dữ liệu đầu tiên giống nhau, mục thứ k-1 khác nhau (Bảng 1.2.c, Bảng 1.2.f).

b) Tìm tập ứng viên Ck bằng cách loại bỏ những tập trong C'k có chứa một tập con k-1 Itemset nhưng không là tập k-1 Itemset thường xuyên (Bảng 1.2.d, Bảng 1.2.g).

c) Ứng với mỗi tập ứng viên trong Ck, duyệt qua CSDL, đếm số giao tác chứa tập ứng viên này để xem tập này có phải là tập thường xuyên hay không, ta được tập Lk (Bảng 1.2.e, Bảng 1.2.h).

Lặp lại bước 2 cho đến khi tập Lk là rỗng.

Chạy thuật toán Apriori với dữ liệu cho ởBảng 1.1 với Minsup S0=2.

Bƣớc 1:

Bảng 1.2: Kết quả thuật toán Apriori

a) C1 b) L1 Mục dữ liệu Độ hỗ trợ A 6 B 7 C 6 D 2 E 2 G 1 Bƣớc 2:

- Lần lặp thứ nhất: Mọi tập trong C'2 đều có tập con một mục dữ liệu là phần tử của L1 nên C2 = C'2. Như vậy, tại bước này chưa sử dụng lợi ích của thuật toán Apriori.

c) C'2 d) C2 e) L2 1-Itemset A B C D E 2 Itemset A, B A, C A, D A, E Itemset Support A, B 4 A, C 4 A, D 1 A, E 2 2 Itemset A,B A,C A,E B,C

B,D B,E

- Lần lặp thứ hai: Tập C'3 được tính toán bằng cách hợp từng 2 tập của L2. Tập C3

được tính bằng cách loại bỏ trong C'3 các tập {A, C, E}, {B, C, D}, {B, C, E}, {B, D, E} do lần lượt chứa các tập con {C, E}, {C, D}, {C, E}, {D, E} không thuộc L2 (không là tập thường xuyên).

g) C'3 h) C3 i) L3

3 Itemset

A,B, C A,B,E

- Lần lặp thứ 3: C'4= {{A,B,C,E}}, chứa {A, C, E} không là tập thường xuyên C4 = L4 = . Ngừng lặp.

Thuật toán Apriori phát sinh số lượng lớn tập ứng viên. Có quá nhiều lần duyệt toàn bộ CSDL để tính độ hỗ trợ của các mục dữ liệu. Thuật toán không thể giải được khi số mục dữ liệu lớn. Dựa vào thuật toán Apriori, nhiều thuật toán mới được thiết kế với những sửa đổi hoặc cải tiến. Nói chung có hai cách tiếp cận: một là sẽ giảm bớt số lần duyệt qua toàn bộ CSDL, hai là thay thế toàn bộ CSDL với chỉ một bộ phận của nó dựa vào tập mục dữ liệu thường xuyên hiện thời. Cách tiếp cận khác là dùng kỹ thuật xén bớt để làm cho số tập ứng viên nhỏ đi.

1.4.2.2. Thuật toán Partition

Năm 1995, Ashok Savasere và đồng nghiệp ở Viện tính toán trường Đại học kỹ thuật Georgia, Atlanta, Hoa Kỳ đề xuất thuật toán Partition để phân dữ liệu thành nhiều phần nhỏ, mỗi phần có thể đưa vào bộ nhớ trong để xử lý [6].

B, C B,D B,E C,D C,E D,E B, C 4 B,D 2 B,E 2 C,D 0 C,E 1 D,E 0 3 Itemset A, B, C A, B, E A, C, E B, C, D B, C, E B, D, E 3 Itemset Support A, B, C 2 A, B, E 2

Một phân hoạch P = {P1, P2, …, Ph} của CSDL giao tác T là một sự phân chia tập T thành h tập con rời nhau: T = {P1, P2, …, Ph} với Pi Pj =

i, j {1, 2, …, h} và i j. Mỗi tập Pi gọi là một lớp tương đương. Trong thuật toán này, với X I, định nghĩa:

Độ hỗ trợ toàn cục của X: Supp(X) = ||t T | X t|| / ||T||. Độ hỗ trợ cục bộ của X trên Pi: Suppi(X) = ||t Pi | X t|| / ||Pi||.

Một tập mục dữ liệu thường xuyên cục bộ có thể không thường xuyên toàn cục. Mục tiêu tìm tất cả các tập mục dữ liệu thường xuyên toàn cục với ngưỡng S0. (adsbygoogle = window.adsbygoogle || []).push({});

Thuật toán Partition gồm ba bước:

Bước một:Duyệt CSDL T lần thứ nhất, phân hoạch T thành h lớp tương đương:

T = {P1, P2, …, Ph}.

Bước hai: Trong mỗi lớp tương đương Pi, tìm tất cả các tập mục dữ liệu thường xuyên cục bộ và ghép thành Li , Li ,..., Li , với

Li là tập các tập thường xuyên có j- mục

1 2 k j

dữ liệu của Pi. Việc tính độ hỗ trợ cục bộ cho từng tập ứng viên được thực hiện như sau: Ứng với mỗi mục dữ liệu xj I, Tij = {t | t là định danh giao tác trong Pi chứa xj}. Với X I, số đếm cục bộ của X trong Pi là i ||  Tij || , độ hỗ trợ cục bộ của X

x j X

i i

trong Pi là Suppi(X) = SX / ||Pi||. Nếu ||X|| = j và Suppi(X) S0thì X L j.

h i

Bước ba: Xác định các tập ứng viên k- mục dữ liệu toàn cục:Ck = Lk

i 1

Với X Ck, nếu Supp(X) = h i / ||T|| S0 thì X là tập thường xuyên toàn cục.

i 1

1.4.2.3. Thuật toán FP-Growth (Frequent-Pattern)

Thuật toán FP-Growth chuyển toàn bộ dữ liệu vào bộ nhớ trong thành cấu trúc cây, quá trình tìm tập thường xuyên là quá trình duyệt cây.

FP-Growth do nhóm nghiên cứu của Jiawei Han trường đại học Illinois Hoa Kỳ đề xuất năm 2000[9]. FP-Growth đánh một dấu mới trong sự phát triển KPDL, giải quyết được hai điểm nút của thuật toán Apriori và Partition. Những tập mục dữ liệu thường xuyên được phát hiện với hai lần duyệt CSDL và không có quá trình phát sinh

S

S

X

Quá trình phát hiện các tập mục dữ liệu thường xuyên bao gồm 2 bước:

- Bƣớc 1: Xây dựng FP-tree

- Bƣớc 2: Phát hiện các tập mục dữ liệu thường xuyên từ FP-tree Bƣớc 1: Xây dựng FP-tree

Mục tiêu của việc xây dựng FP-tree là đưa toàn bộ dữ liệu vào bộ nhớ trong. FP- tree là một cây đa cấp không đầy đủ. Mỗi nút của cây gồm hai phần: Item_name chứa tên mục dữ liệu, Item_count chứa số lần duyệt qua nút này trong quá trình xây dựng cây. Số nhánh tại các nút không bằng nhau. Nút gốc R của cây là nút đặc biệt: R.Item_name = và R.Item-count = 0.

Xây dựng FP-tree thực hiện theo hai bước sau:

Bước 1: Duyệt CSDL lần thứ nhất để tính độ hỗ trợ cho từng mục dữ liệu, chọn và lập danh sách các mục dữ liệu thường xuyên và sắp xếp chúng theo thứ tự giảm dần của độ hỗ trợ (hình 1.1.b)

Bước 2: Tạo cây:

- Tạo ra nút gốc R của FP-tree, gắn nhãn Root. - Duyệt CSDL lần thứ 2, ứng với mỗi giao tác: (adsbygoogle = window.adsbygoogle || []).push({});

+ Lọc ra những mục dữ liệu thường xuyên thành danh sách L và sắp xếp L theo thứ tự giảm dần của độ hỗ trợ (đã tính ở bước 1).

+ Nếu L , phân L thành [x | L1] với x là mục dữ liệu đầu tiên trong L, gọi hàm Insert([x | L1], R).

Hàm Insert([x | L], R) làm việc như sau: Nếu nút R có một nút con Q sao cho Q.Item_name = x thì Q.Item_count = Q.Item_count + 1, ngược lại thì tạo nút Q mới là con của nút R và gán Q.Item_name = x và Q.Item_count =1. Nếu L ≠ ,gọi đệ quy Insert([y | L1], Q) với y là thuộc tính đầu của L và L1 là phần còn lại.

b) Tìm tập thường xuyên

Thủ tục FP-Growth duyệt qua cây để sinh ra tập những tập mục dữ liệu thường xuyên. Xem chi tiết thủ tục này trong [9].

Chạy thuật toán FP-Growth với dữ liệu cho ở Bảng 1.3 với S0=2:

Bảng 1.3: Những biến đổi dữ liệu của FP-Growth

tid Mục dữ liệu t1 A, B, E t2 B, D t3 B, C t4 A, B, D t5 A, C t6 B, C t7 A, C t8 A, B, C, E t9 A, B, C, G a) Tạo cây Đầu bảng Root 0 Mục DL B A C D E Đầu của các nút kết nối B 7 A 2 A 4 C 2 D 1 C 2

Hình 1.2: FP-tree của dữ liệu Bảng 1.1

1-Itemset Độ hỗ trợ B 7 A 6 C 6 D 2 E 2 tid Tập mục dữ liệucó thứ tự t1 B, A, E t2 B, D t3 B, C t4 B, A, D t5 A, C t6 B, C t7 A, C t8 B, A, C, E t9 B, A, C E 1 C 2 D 1 E 1

xj1:Cj1 xj2:Cj2 Thân xjk:Cjk :Csj xij1:Cij1 xs 1 1 xij :Cij xsj :Csj Nhánh 2 2 2 2 Hình 1.3: Thành phần của FP-tree Bƣớc 2:Chạy thủ tục FP-Growth

FP_Growth(Root, ): Root có hai nhánh: Pt1:(B:7)… và Pt2:(A:2)…

Gọi đệ quy FP_Growth(Pt1, ): Có thân: (B:7) và ba nhánh con Pt11: (A:4)…, Pt12:(C:2) và Pt13:(D:1). Thân (B:7) chỉ có một nút nên được tập mục dữ liệu FP_Set(Pt1)={(B:7)}.

Gọi đệ quy FP_Growth(Pt11, ): Có thân: (A:4) và ba nhánh con Pt111:(E:1)… Pt112:(C:2) và Pt113:(D:1). Thân (A:4) chỉ có một nút nên được tập mục dữ liệu FP_Set(Pt11)={(A:4)}.

Gọi đệ quy FP_Growth(Pt111, ): Có thân: (E:1) và không có nhánh con. Thân (E:1) chỉ có một nút nên được tập mục dữ liệu trả về: FP_Set(Pt111)={(E:1)}.

Gọi đệ quy FP_Growth(Pt112, ): Có thân: {(C:2), (E,1)} và không có nhánh con. Thân {(C:2), (E,1)} có hai nút nên được tập mục dữ liệu trả về: FP_Set(Pt112)={(C:2), (E:1), (CE:1)}.

Gọi đệ quy FP_Growth(Pt113, ): Có thân: (D:1) và không có nhánh con. Thân (D:1) chỉ có một nút nên được tập mục dữ liệu trả về: FP_Set(Pt111)={(D:1)}.

Có ba nhánh con: Pt111, Pt112 và Pt113:

1= FP_Set(Pt111) FP_Set(Pt112) FP_Set(Pt113)= {(C:2), (E:2),(D:1), (CE:1)}.

2= FP_Set(Pt11) 1 {FP_Set(Pt11) x 1}= {(A:4), (C:2), (E:2), (D:1), (CE:1), (AC:2), (AE:2), (AD:1), (ACE:1)}.

Gọi đệ quy FP_Growth(Pt12, ): Có thân: (C:2) và không có nhánh con. Thân (C:2) chỉ có một nút nên trả về tập mục dữ liệu FP_Set(Pt12)={(C:2)}.

Gọi đệ quy FP_Growth(Pt13, ): Có thân: (D:1) và không có nhánh con. Thân (D:2) chỉ có một nút nên trả về tập mục dữ liệu FP_Set(Pt13)={(D:1)}.

Hợp ba nhánh con Pt11, Pt12và Pt13:

3 = 2 FP_Set(Pt12) FP_Set(Pt13)

= {(A:4), (C:4), (E:2, (D:2), (CE:1), (AC:2), (AE:2), (AD:1), (ACE:1)}. Trả về: 4 =FP_Set(Pt1) 3 {FP_Set(Pt1) x 3}

= {(B:7), (A:4), (C:4), (E:2), (D:2), (CE:1), (AC:2), (AE:2), (AD:1) (ACE:1), (BA:4), (BC:4), (BE:2), (BD:2), (BCE:1), (BAC:2), (BAE:2), (BAD:1) (BACE:1)}.

Gọi đệ quy FP_Growth(Pt2, ): Có thân: {(A:2),(C:2)} và không có nhánh con. nên trả về tập mục dữ liệu FP_Set(Pt2)={(AC:2), (A:2), (C:2)}.

FP_Growth(Root, ) trả về:

FP_Set = 4 FP_Set(Pt2) = {(B:7), (A:6), (C:6), (E:2), (D:2), (CE:1), (AC:2), (AE:2), (AD:1) (ACE:1), (BA:4), (BC:4), (BE:2), (BD:2), (BCE:1), (BAC:2), (BAE:2), (BAD:1) (BACE:1)}.

Từ tập FP_Set ta lọc ra các tập mục dữ liệu thường xuyên với S0=2 là: FP = {A, B, C, D, E, AC, AE, BA, BC, BE, BD, BAC, BAE}. (adsbygoogle = window.adsbygoogle || []).push({});

Dựa vào bảng dữ liệu đầu của các mục dữ liệu và cây FP_Tree, có thể tìm ra dễ dàng tập các mục dữ liệu thường xuyên và cũng dễ dàng tìm ra tập tất cả các tập mục dữ liệu thường xuyên chứa một mục dữ liệu cho trước. Ví dụ, với E, ta có các nhánh chứa nó: {B A E} và {B A C E}.

Thuật toán FP_Tree có hiệu quả trong tính toán vì ba lý do. Thứ nhất, quá trình giải bài toán chỉ xét trên những mục dữ liệu thường xuyên, các mục dữ liệu không thường xuyên bị cắt bỏ, do đó dữ liệu xét sẽ nhỏ hơn nhiều. Thứ hai, thuật toán này chỉ duyệt CSDL hai lần. Thứ ba, FP_Tree sử dụng phương pháp “chia để trị” để làm giảm đáng kể kích thước của cây, một nhánh dài được sinh ra bằng nối thêm mục dữ liệu vào một nhánh ngắn, không phải làm lại từ đầu.

Mỗi thuật toán đều có những hạn chế riêng. Trong quá trình KPDL, người dùng có thể thay đổi ngưỡng độ hỗ trợ, tuy nhiên với FP_Tree, khi thay đổi ngưỡng độ hỗ trợ thì công việc phải làm lại từ đầu. Hạn chế khác của FP_Tree là không thích hợp cho trường hợp dữ liệu gia tăng. Một khi CSDL thay đổi, công việc khai phá dữ liệu cũng phải làm lại từ đầu.

Một phần của tài liệu luật kết hợp mờ và ứng dụng đối với một số bài toán dự báo (Trang 25 - 34)