Tải bản đầy đủ (.doc) (27 trang)

TÌM HIỂU THUẬT TOÁN KNEAREST NEIGHBORS (KNN) TRONG BỘ NHỚ THEO KHÔNG GIAN

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (784.84 KB, 27 trang )






 !
"#$$%$%&"#'
()$"
*+,-.*/,%0%0123
45.*/, 627,8,-
9:; <==<==>
?@A 8BC45D"CE8F
CG,-=<,7HI=<J

TÌM HIỂU THUẬT TOÁN
K-NEAREST NEIGHBORS (K-NN)
TRONG BỘ NHỚ THEO KHÔNG GIAN

GIỚI THIỆU


Hiện nay công nghệ thông tin là ngành không thể thiếu cho tất cả những ngành nghề
khác tồn tại trên thế giới hiện đại. Tuy nhiên nếu không có có các khoa học cơ bản nhất là
toán học thì tin học không thể ra đời. Toán học đóng vai trò hầu như trong mọi phạm vi
của tin học từ lúc sản xuất ra phần cứng, biểu diễn thông tin, tính toán …cho đến giao
diện giao tiếp với người sử dụng. Và cho đến ngày nay và cả trong tương lai, vai trò về
mặt ứng dụng của toán học cho tin học ngày càng cao đến một mức độ thông minh tuyệt
đỉnh. Chúng ta sẽ đi sơ qua một khía cạnh nhỏ của toán học trong phạm vi ứng dụng để
tạo ra các phần mềm, sự tích hợp và dịch vụ trong tin học.
Thuật toán là thành phần cơ bản không thể thiếu của chúng nhất là đối với các hệ
thống thông minh hơn đơn thuần là giao tiếp và lưu trữ dữ liệu.


Trong bài thu hoạch này chúng ta sẽ “TÌM HIỂU THUẬT TOÁN K-NEAREST
NEIGHBORS (K-NN) TRONG BỘ NHỚ THEO KHÔNG GIAN”. k-NN là
một trong những thuật toán rất đơn giản để hiểu, nhưng làm việc rất tốt trong thực tế, nó
nằm trong nhóm các thuật toán về NNS (tìm các lân cận gần nhất) là thuật toán có ứng
dụng rất đa dạng và linh hoạt. Nếu đi sâu vào các lĩnh vực như xử lý ảnh, nhận dạng và
phân tích dữ liệu, chúng là một thuật toán mà thiếu nó thì mọi thứ sẽ trở nên cực kì khó
khăn. Hầu hết mọi người chỉ tìm hiểu các thuật toán chứ không sử dụng nó nhiều, đó
là một điều rất đáng tiếc. k-NN là một trong 10 những thuật toán khai thác dữ liệu (data
mining) hàng đầu và là thuật toán thuật toán đơn giản nhất trong các thuật toán về máy
học (machine learning).
Em rất chân thành cám ơn thầy Đỗ Văn Nhơn, dạy môn học này đã cho em biết thêm
các kiến thức về khái niệm, ý nghĩa, các tài liệu và ứng dụng của toán trong tin học và cụ
thể là giúp em có kiến thức để thực hiện bài viết này.
Trong phạm vi môn học phương pháp toán trong tin học, em chỉ trình bày bài viết có
tính chất tìm hiểu thuật toán k-NN trong phạm vi sử dụng bộ nhớ (memory algorithms )
và các giải thuật tập trung vào cấu trúc không gian (Spatial Structure) chứ không trình
bày tất cả các phương pháp của chúng.
TP. HCM, Ngày 04 tháng 01 năm 2015
Đỗ Văn Cang

Mục Lục

 !
"#$%&' (##)

#&*
+,-.
/0-12
Nội Dung


I. Định nghĩa
Theo từ định nghĩa tiếng anh thì k-NN có nghĩa là “k-nearest neighbors” và thuật
toán đó là “the k-nearest neighbors algorithm (k-NN)”
Bài toán này là bài toán tìm người láng giềng gần nhất , ví dụ bạn đang ngồi học bài
trong một lớp học, hãy tìm người gần bạn nhất ? hoặc tìm người có mái tóc giống mái tóc
của bạn nhất ?
Xét tập N điểm trong không gian 2 chiều, cho một điểm q trong không gian đó, hãy tìm
điểm p trong tập N điểm gần với q nhất (euclide).
Một cách tổng quát cho một tập S chứa n các đối tượng có d thuộc tính trong không gian
. Cho một đối tượng q trong không gian đó, hãy tìm k đối tượng gần với q nhất.
Thông tin cơ bản nhất để thực hiện việc tìm kiếm này là khoảng cách (xét khoảng cách
euclide), để tìm được điểm gần nhất tức là ta phải tìm được điểm p sao cho
(1)
Trong đó khoảng cách euclide từ p bất kì đến q sẽ là
(2)
Mở rộng k đối tượng cần tìm , ta sẽ lần lượt tìm các đối tượng thõa mãn điều kiện (1)
nhưng phải có khoảng cách lớn hơn đối tượng tìm được trước trước đó.
.
q
p
Hình 1. Lân cận gần nhất của q là p
II. Thuật toán k-NN Vét cạn
2.1. Ý tưởng
Duyệt qua tất cả các điểm trong tập S, tìm khoảng cách đến đối tượng đang xét q
và nếu khoảng cách này nhỏ hơn khoảng cách lớn nhất trong tập K thì chèn nó vào tập K
theo đúng thứ tự tăng dần theo khoảng cách. Sau khi chạy hết n đối tượng trong S thì K là
tập kết quả chỉ chứa k đối tượng.
2.2. Thuật toán
//S : tập điểm vào
//q : điểm cần tìm

//k : số điểm gần nhất
//K : tập hợp có thứ tự theo dis
Find_kNN_Linear ( Input : S(n) , q,k; Output : K(k) )
{
B1/ K = {}
B2/
for( pi S)
{
if ( dis(pi,q) <= Max(K) )
{
InsertOrder(K, dis(pi,q),pi);
}
}
}
//K : tập cần insert chứa dis và p, dis : khoảng cách, p : điểm insert – có
thể sử dụng thuật thoán QuickSearch để chèn ngay vào vị trí cần chèn.
InsertOrder(K(k), dis, p)
{
for i = k-1 downto 0 step -1
{
if K[i] <= dis then
{
K[i+1] (dis,p)//insert to position i+1
return;
}
}
K[0] (dis,p)
2
}
2.3. Phân tích độ phức tạp và nhận xét

- Find_kNN_Linear có độ phưc tạp O(n) do vòng lặp n lần, hàm Max(K) lấy đối tượng
cuối nên không tính.
- InsertOrder : có độ phức tạp O(k) = c hằng số
Độ phức tạp của thuật toán tìm k-NN = c*O(n)= O(n)
Nếu tìm cho n điểm bên trong tập S thì độ phức tạp sẽ là O( )
Thuật toán linear này chỉ để nhìn thấy tính chất rõ rang nhất của cách tìm k-NN,
và chỉ ứng dụng cho tập số lượng đối tượng tương đối nhỏ.
III. Thuật toán k-NN cải tiến sau vét cạn
3.1. Ý tưởng
Bắt đầu nghĩ đến không gian (spatial partitioning strategy) ?!? phải có một cách
nào đó để việc tìm kiến chỉ dựa vào một vùng không gian nhỏ hơn tập S và gần với q.
Cách đơn giản nhất là chúng ta sẽ chia lưới chúng , mỗi một ô gọi là điểm rời rạc. Vì khi
theo các điểm rời thì ta biết chắc chắn những điểm gần nó phải là 8 ô gần nhất của nó
theo 8 hướng trong không gian rời rạc.
Nếu xét trên không gian rời rạc (Raster hóa), ta có thể dựa vào phương pháp quét theo
vòng tròn quanh điểm cần tìm để mở rộng ra cho đến khi tìm được. Như thế đảm bảo cho
việc các đối tượng đầu tiên tìm được luôn thõa điều kiện. Và sẽ không phải duyệt qua các
điểm không cần thiết.
Ở đây không trình bày thuật toán phần này vì nó liên quan đến raster và một số việc xét
duyệt các điểm lân cận theo vòng tròn.
3.2. Phân tích độ phức tạp và nhận xét
Nếu kết quả tìm được là khoảng cách k-NN trung bình (theo đơn vị raster) của tất
cả các điểm trong tập S là e. thì lúc đó ta sẽ có độ phức tạp thuật toán sẽ xấp xỉ e*O(n)
- Nếu ta raster tập S càng nhỏ thì lúc đó e ~ n và độ phức tạp là O( )
- Nếu raster tập S lớn lúc đó một đơn vị raster gần như ~ n thì việc tìm k-NN sẽ tương
đương với linear O( ), vì chỉ có 1 ô raster.
3
- Như vậy thuật toán này sử dụng raster vừa phải sẽ cho kết quả tương đối theo O(n).
Nhưng nếu S phân số theo kiểu chứa n1 đối tượng rời rạc và n2 đối tượng tập trung dày
đặt và đường đi từ n1 đến n2  n thì độ phức tạp ~ O( ) nên thuật toán này cũng không

khả thi cho mọi trường hợp.
IV. Thuật toán k-NN kd-Tree
4.1. Ý tưởng
Theo cách raster ở trên, với phân vùng là các ô vuông và từ ô hiện hành (chứa q)
mở rộng ra 8 hướng theo xoắn ốc cho đến khi tìm ra đối tượng gần nhất.
Tuy nhiên cách tìm mở rộng theo 8 hướng sẽ dẫn tới trường hợp duyệt hết toàn bộ các
đối tượng nếu khoảng cách giữa 2 ô chứa rất nhiều ô rỗng dẫn tới duyệt gần như hết toàn
bộ data.
Thêm vào đó việc phân vùng càng nhỏ thì việc tìm càng nhanh, tuy nhiên các ô trống sẽ
phát sinh rất nhiều và làm cho tốc độ tìm đến ô có đối tượng rất chậm trong không gian
ma trận raster cực kì lớn.
Từ đó ngoài việc phân vùng, nhất thiết cần phải có cách để nhận biết trong các vùng
sau khi phân hoạch thì vùng nào gần q nhất và phân vùng đó càng nhỏ càng tốt. Nếu
có được 2 điều này và một phân vùng chỉ chứa 1 đối tượng thì đó là cách hoàn hảo nhất
nếu không gian lưu trữ không quá nhiều.
Vấn đề là điều đó gần như rất khó thực hiện, tuy nhiên nếu không tìm được vùng nào gần
nhất thì hãy thử tìm vùng nào gần nhất theo 1 thuộc tính (dimension) nào đó. Bởi vì 2 đối
tượng có gần nhau thì thường chúng cũng gần theo các thuộc tính khác. Điều này thì có
thể thực hiên được. Nhưng cần phải có một cách phân vùng khác.
4.2. Phân tích thuật toán QuadTree
Ý tưởng nhờ vào cấu trúc cây đã phần nào giải quyết các vấn đề trên, điển hình là
thuật toán QuadTree. Thuật toán này chia vùng không gian hiện tại thành 4 thành phần
con gọi là Node, và tiếp tục như thế cho các Nodes con cho đến khi nào mỗi Node chỉ
chứa giới hạn tối thiểu các đối tượng gọi là Leaf Node.
4
Việc tìm kiếm trên tree này dựa vào sự giao nhau của vùng đang xét và một bán
kính R tối đa nhờ vào thông tin từ bên ngoài hoặc trước đó để giới hạn không gian tìm
kiếm, nếu đi qua được Leaf Node thì cập nhật lại R theo khoảng cách ngắn nhất. Quá
trình này tiếp tục cho đến khi quá trình kết thúc do không gian tìm kiếm bị co lại tối
thiểu.

Như vậy QuadTree cũng đã giải quyết được phần nào về vấn đề phân vùng tìm kiếm, tuy
nhiên với dữ liệu rời rạc trong không gian rộng lớn, việc build tree này làm chứa
nodes con và tiêu tốn rất nhiều không gian trống, và tất nhiên tìm kiếm trên số lượng
nodes như thế là không tốt lắm.
5
6#789:;<=>"=>?@?;
6ABCD-;
Có một cải thiện của QuadTree là trong quá trình build tree, node nào không chứa đối
tượng nào thì xem như không có node đó. Nhưng dù sao nó cũng không phải là thuật toán
làm hài lòng nhất.
4.3. Phân tích thuật toán kd-Tree
Sự xuất hiện của kd-Tree đã làm cho mọi thứ trở nên cực kì tốt đẹp, các phân vùng
nhỏ tùy ý và việc giới hạn phân vùng tìm kiếm dựa trên một số nền tảng cơ bản về kd-
Tree.
KL#MNNOP-QR
kd-Tree (k- dimension tree) thực chất là một BTree (Binary tree - cây nhị phân), sự khác
biệt duy nhất và đơn giản nhất của kd-Tree với BTree là :
+ Btree phân cấp theo một thuộc tính duy nhất cho mọi Nodes(*) trong tree.
+ kd-Tree phân cấp theo nhiều thuộc tính, mỗi node trung gian sẽ chọn một thuộc tính để
phân cấp. Thuộc tính đó chính mà số chiều (dimension) của đối tượng.
STUMV5KL#MNN
Có 2 loại node trong kd-Tree:
+ SplitNode: node trung gian chứa các thông tin cơ bản sau
 Thuộc tính cắt lát ( dimension)
 Giá trị cắt lát (Split Value)
 Thông tin phân vùng không gian chứa các đối tượng bên
trong.
+ Leaf Node: node lá chứa thông tin của các đối tượng.
T*OLKL#MNN
Bắt đầu từ node root ban đầu là vùng chứa vùng không gian bao đóng(*) của tất cả

các đối tượng trong S. Root node là SplitNode.
Quá trình hình thành các nodes con từ một node hiện hành từ việc chọn ra tiêu chuẩn cắt
lát (Split ) dựa trên một thuộc tính nào đó (cần tìm) và tính chất thứ tự từ trái sang phải từ
trên xuống của bTree.
Phương pháp cắt lát tại mỗi node
+ Chọn thuộc tính cắt lát.
E
+ Cắt lát theo giá trị Median(*) của thuộc tính đã chọn.
Khảo sát ví dụ gồm các đối tượng A,B,C,D,E như (hình 4.1), là các đối tượng trong
không gian 2 chiều ( 2 thuộc tính) là Ox, Oy.

Nguyên tắc: Cắt theo median của Ox,Oy,Ox,Oy… tổng quát: level mod 2 với level là cấp
của node. Đối tượng tại lát cắt phải thuột node con bên phải, cắt cho tới khi nào Node chỉ
chứa số đối tượng <= bucketsize(*), bucketsize ở đây = 1 là số đối tượng tối đa trong
LeafNode(node lá), các Node trung gian gọi là SplitNode.
- Trước tiên từ node root N0, chọn Ox làm chiều cắt lát, cắt theo median thành 2 nodes con
N1, N2 (hình 4.2).
- Tiếp tục cắt theo Oy 2 Node con còn lại
F
 N1 thành 2 node N3, N4
 N2 thành 2 node N5, N6 (hình 4.3)
- Xét Node N6 còn lại cắt theo Ox được 2 Nodes con N7,N8  tất cả các nodes được
build. (hình 4.4).
QHW;*UXY,--Z,,CSU5[8W;*UXY,-5CBUMX@5
Nguyên tắc chung của việc tìm ra đối tượng trong tập S, lân cận gần nhất đối
tượng cho trước q là cách duyệt cây theo chiều sâu ( sử dụng đệ quy). Tại một Node cho
trước Ni, có thể đi theo 2 hướng trái hoặc phải. Việc quyết định đi theo hướng nào là tùy
thuột vào việc so sánh giá trị của thuộc tính cắt lát (split dimention) của đối tượng q với
giá trị cắt lát (Split Value) tại node đó.


+ Nếu Ni là node lá LeafNode: tìm được đối tượng nghi vấn, cập nhật đối tượng này và
khoảng cách từ q đến nó sẽ được cập nhật gọi là mindis(p).
+ Nếu Ni là node trung gian SplitNode, xét giá trị cắt lát của q với giá trị cắt lát tại Ni:
thì gọi đệ quy cho node con bên trái.
- Nếu khoảng cách nhỏ nhất của đối tượng q đến phân vùng của node còn
lại bên phải dis_right(Ni) : dis_right(Ni) < mindis(p) , tiếp tục thực hiện cho node bên
phải này. Ngược lại duyệt bên phải và kiểm tra bên trái.
Quá trình này được thực hiện theo chiều sâu, lúc đầu cây sẽ được duyệt từ root đến lá khả
nghi nhất, sau đó nó được so sánh khoảng cách với các khoảng cách các vủng lân cận,
nếu thuận buồm xuôi gió thõa mãn điều kiện nhỏ hơn khoảng cách nhỏ nhất của tất cả
các vị trí nodes ở trên thì nó sẽ trả ngược về kết quả tại node root giá trị cần tìm. Nếu
không , nó sẽ phải đào sâu vào các nhánh node cấp cha ông của nó. Việc này tùy thuộc
vào phân bố các đối tượng và nhất là cơ chế build tree ban đầu.
Trong ví dụ trên, xét đối tượng X nằm tại vị trí như hình 4.5.
Bây giờ ta hãy xem qua cách tìm kiếm đối tượng gần đối tượng X nhất.
 Duyệt node gốc: giá trị duyệt node trái (N1)
 Duyệt N1: giá trị duyệt node phải (N4)

 Duyệt N4 chứa B tính khoảng cách mindis(X) với B.
 Quay lại N1: so sánh mindis(X) với Dis(N1) : phân vùng N3 ta thấy rõ mindis(X) <
Dis(N1) : vùng chữ nhật chứa A và C
Quay lại N0 : tương tự mindis(X) < Dis(N0) vùng chứa CDE.
Kết thúc tại Root. Với giá trị cần tím là B 
Các quá trình build kd-Tree và Search theo các nguyên tắc này gọi là tìm k-NN theo kd-
Tree chuẩn bằng cách sử dụng cắt lát theo Median.
QHW;*UXY,--Z,,CSU5[8W;*UXY,-5CBUMX@5UCNBW\XT]/,
Phương pháp này tương tự như phương pháp chuẩn ở trên, tuy nhiên có một sự
khác biệt là:
Trong quá trình duyệt node tìm ra được khoảng cách, với phương pháp chuẩn thì sẽ quay
ngược lên node cha để so sánh khoảng cách tìm được với khoảng cách nhỏ nhất của q

với node còn lại của cha nó… cho đến root, nhưng phương pháp này sẽ so sánh sánh
khoảng cách tìm được với khoảng cách nhỏ nhất của q từ các node còn lại của cha
đến node root bằng cách sử dụng một Sorted Queue theo khoảng cách để xác định sẽ tìm
đến node nào ngon nhất 
Như vậy trong quá trình duyệt và kiểm tra xét đến node lân cận, thay vì xét node lân cận
tại node cha, thì chỉ xét node lân cận gần nhất trong các node lân cận ở tất cả các cấp
trước đó và như thế có thể tìm được nhanh chóng hơn.
Tuy nhiên, thực tế thì các node có mối quan hệ gần nhất lại là các node khả nghi nhất và
chúng cũng chiếm phân vùng nhỏ nhất, do đó việc thực hiện theo phương pháp này, lúc
đầu thì thấy rất là hay, nhưng khi cài đặt thực tế thì quá trình thay đổi Queue tốn chi phí
khá lớn và số cấp duyệt lại lớn hơn. Lý do chính là các phân vùng các node ở cấp càng
sát với root có độ rộng càng lớn.
Dựa vào ý tưởng thuật toán này và kết hợp với việc đo khoảng cách để loại dần các node
trong queue, thuật toán tìm k-NN xấp xỉ ANN hay còn gọi là Best Bin First ra đời để tìm
giá trị k-NN gần đúng nhất với giá trị epsilon cho sẳn. Tuy nhiên do giới hạn thời gian
trong phạm vi bài biết này không đề cập đến thuật toán Best Bin First.
4.4. Thuật toán kd-Tree sử dụng Median
Phương pháp tìm hoàn toàn tương tự nguyên tắc chuẩn kd-Tree
Chỉ có thay đổi 1 chút ít về cách build tree như sau

+ Chọn thuộc tính cắt lát: tại một node cần cắt lát, chọn thuộc tính có mà có độ dài của
phân vùng (các đối tượng) lớn nhất. Thường giá trị này cũng chính là độ dài bao đóng
của các đối tượng bên trong theo thuộc tính đó do tính chất median.
+ Cắt lát theo giá trị Median(*) của thuộc tính đã chọn : phần từ đứng giữa trong tập các
đối tượng được sắp xếp tăng dần theo thuộc tính cắt lát.
Lưu ý: Các thuật toán dưới đây chỉ mô tả các bước quang trọng nhất hình thành thuật
toán.
//Si : tập các điểm cần build
//Ni : Node trả về sau khi build
//RECi : vùng bao chứa tập điểm Si.

//Bucketsize : số lượng tối đa đối tượng trong LeaftNode
Tree::BuildTree( Input : Si ,RECi, Output : Ni )
{
If Count(Si) <= BucketSize) then
Ni = new LeafNode(Si);
//khai báo
RECl, RECr, Sl, Sr,splitdimension
//Lấy các giá tri sau khi Split
SlitNode(Si,RECi,out splitdimension,out RECl,out RECr,out Sl, out Sr;
Childleft = BuildTree(Sl, RECl, Nl );
ChildRight = BuildTree(Sr, RECr,Nr);
Ni = new SplitNode( Si, RECi, splitdimension, Nl, Nr);
}
//Si : tập các điểm cần build
//RECi : vùng bao chứa tập điểm Si.
//SplitDimension : thuộc tính cắt lát
//REC(l) : vùng bao chứa tập bên trái
//S(l) : tập đối tượng bên trái
//REC(r), S(r) : bên phải
Tree::SplitNode( Input : Si ,input RECi, Output : splitdimension, output
RECl, output RECr, output Sl, output Sr)
{
//duyệt qua vùng REC (chỉ chứa 2 tập min và max theo thuộc tính )
FindSplitDimension(RECi , out splitdimension )
//Sort theo thuộc tính splitdimension
QuickSort( Si,splitdimension );
Medianindex = Count(Si) / 2;
// SplitValue là giá trị cắt vùng bao thành 2
Splitvalue = Si(Medianindex);
//Cập nhật RECl, RECr, Sl, Sr theo SplitValue

Sl = Si[0,Medianindex);
Sr = Si[Medianindex,Count(Si)];
RECl = RECi;
RECl.Max = SplitValue;
RECr = RECi;
.
RECr.Min = SplitValue;
}
//q : cần tìm đối tượng gần q nhất
//result : đối tượng kết quả ( bao gồm khoảng cách)
Tree::SearchNearestNeighbours(q,result)
{
Reset(result)
RootNode.FindNearestItem(q,result);
}
//q : cần tìm đối tượng gần q nhất
//result : đối tượng kết quả ( bao gồm khoảng cách)
SplitNode::FindNearestItem(q, result)
{
if REC(splitdimension) < SplitVal then //go Left First
{

//go Left
Left.FindNearestItem(q, result);
//go Right when max distance found is not good
if MaxDistance(result) > MinDistance(Right,q) then
Right.FindNearestItem(q, result);

}
else//go Right First

{
Right.FindNearestItem(q, result);
//go Left when max distance found is not good
if MaxDistance(result) > MinDistance(Left,q) then
Left.FindNearestItem(q, result);
}
}
4.5. Thuật toán kd-Tree sử dụng Sliding MidPoint
Thuật toán Split theo median đảm bảo cho cấu trúc cây gần như là cân bằng với
mọi lát cắt split đều phải nằm ngay đối tượng giữa của tập đối tượng đã được sort trong
node. Điều này làm cho việc duyệt theo cây sẽ rất đơn giản và dễ tính ra được độ phức
tạp cho một lần duyệt từ trên xuống dưới node lá.
Nếu sự phân bố các đối tượng đồng đều (random) trong không gian thì các phân vùng
bao sẽ khá cân bằng giữa các thuộc tính (hình vuông trong 2 dimension), điều này làm
cho việc tìm node gần nhất hầu như rất ít khả năng quay ngược lên duyệt lại con cháu
của cha ông họ hàng của node đó. Và khả năng tìm ra là nhanh nhất.
2
Tuy nhiên, sự thật là các đối tượng luôn không đồng đều mà phân bố mật độ khá khác
biệt nhau, từ đó dẫn tới nếu theo median thì các phân vùng sẽ trở nên lệch hẳn giữa các
thuộc tính, ví dụ trong 2 dimension 0x, 0y thì nó sẽ trở thành hình chữ nhật cực kì dài
và mỏng. Sự lệch này làm cho quá trình tìm đến node lá không còn nhiều ý nghĩa nữa
dẫn tới quá trình duyệt tìm sẽ quay ngược lên bà con họ hàng cho đến khi tỉ lệ giữa các
thuộc tính ngang nhau thì mới được kết quả tốt nhất.
Từ nhận xét này, dẫn tới sự xuất hiện của phép cắt theo không gian. Vì bản chất các
thuột toán kd-Tree là phân vùng theo không gian. Phép cắt này không cắt theo median mà
nó sẽ cắt theo điểm chính giữa của phân vùng không gian dựa trên thuộc tính cắt tại node
đang xét. Hay còn gọi là MidPoint Split. Cụ thể nếu vùng bao của nó là một hình chữ
nhật trong không gian 2d và tại node đó thuộc tính theo 0x là thuộc tính cắt thì giá trị cắt
chính là tâm điểm của khoảng bao trên 0x tức là (minx+maxx)/2.
Gần giống như QuadTree, phép cắt theo MidPoint không đảm bảo cho tree cân bằng và

có thể xảy ra trường hợp cây rất là sâu (> n ).
Để hạn chế việc đi quá sâu và cắt lát vô ích, thay vì cắt một cách mù quáng theo phương
pháp điểm giữa, sau khi cắt nếu như 1 trong 2 phân vùng mới hoàn hoàn không chứa đối
tượng nào, thì dịch chuyển vị trí cắt về phía bên phân vùng còn lại cho tới khi đụng đối
tượng đầu tiên, lúc đó phân vùng mới gồm phân vùng chứa n-1 điểm và phân vùng bị
trống sẽ chứa 1 điểm. Phương pháp này gọi là Sliding Midpoint Split.
Hình 5. Sliding MidPoint
Thuật toán theo Sliding MidPoint cũng chỉ thay đổi cơ chế build tree
//Si : tập các điểm cần build
//RECi : vùng bao chứa tập điểm Si.
//SplitDimension : thuộc tính cắt lát
//REC(l) : vùng bao chứa tập bên trái
//S(l) : tập đối tượng bên trái
3
//REC(r), S(r) : bên phải
Tree::SplitNode( Input : Si ,input RECi, Output : splitdimension, output
RECl, output RECr, output Sl, output Sr)
{
//duyệt qua vùng REC (chỉ chứa 2 tập min và max theo thuộc tính )
FindSplitDimension( RECi , out splitdimension )
//Tính điểm giữa midpoint theo splitdimension
SplitValue = (RECi.min + RECi.max)/2;
//Tìm khoảng min max nhỏ nhất trong Si theo splitdimension
FindMinMaxOfPoints(Si,slitdimension, out min,out max);
//kiểm tra để sliding
If splitValue < min then splitvalue = min
Else if splitvalue > max then splitvalue = max
//Dựa vào splitvalue phân 2 vùng không gian mới
RECl = RECi;
RECl.Max = SplitValue;

RECr = RECi;
RECr.Min = SplitValue;
GetDataInRec(Si,RECl,out Sl);
GetDataInRec(Si,RECr,out Sr);
}
4.6. Phân tích độ phức tạp
\AC^5U_A5[8KL#MNNNL*8,
Xét số cấp tối đa của cây:
Giả sử trường hợp cây cân bằng, tức là một node cha luôn có 2 node con.
Lúc đó số node tại cấp j sẽ là (1)
Nếu node lá chỉ chứa một đối tượng thì tổng số node ở cấp cuối cùng phải là n ( bằng số
đối tượng trong S)
Như vậy số node tại cấp m cuối cùng sẽ là
 m = là số cấp tối đa của cây (2).
Xét tại mỗi cấp: lúc đó số đối tượng trong mỗi node tại cấp j sẽ là
nj = ví dụ:tại cấp root 1 node có n đối tượng, cấp 2 có 2 node có n/2 (3)
4
Chi phí build cây:
Tại mỗi node, chi phí để split sử dụng median bao gổm:
+ Chi phí tìm thuộc tính cắt = 2d (dimension): không đáng kể
+ Chi phí tìm median: quicksort tức là (4)
+ Chi phí tách đối tượng thành 2 vùng: quản lý mảng bằng index và dựa vào index của
median nên chi phí này xem như không đáng kể.
Từ (1),(3),(4) Chi phí split tại cấp j =
= = (5)
 Tổng chi phí = (2)*(5)
T(n) =
=
= n* - ~ n*


Nếu bước tìm median sử dụng phương pháp median finding (tham khảo
h ttp://ranger.uta.edu/~gdas/Courses/Fall2004/advAlgos/student_slides/W6Presentation.ppt) thì chi phí cho
bước này là O(n) , phân tích tượng tự ta có được
Chi phí tìm kiếm k đối tượng gần nhất:
Chi phí tìm k đối tượng gần nhất bao gồm:
+ Chi phí duyệt cây cho đến nút cần tìm
+ Chi phí số thuộc tính dimension d.
5
T(n) = O( n*
T(n) = O(n*
+ Chi phí bổ sung đối tượng cần tìm vào mảng kết quả có thứ tự k bằng chi phí chèn vào
mảng với chi phí là k.
Nếu các phân vùng có tỉ lệ thuộc tính gần nhau cho trong mọi node, thì khả năng duyệt
tìm được đối tượng gần nhất sẽ là .
Như vậy tổng chi phí tìm k đối tượng sẽ là
Trong trường hợp xấu nhất:
Nếu có sự cải tiến thì cải tiến nằm ở chỗ median, nếu node hiện tại sử dụng cùng thuộc
tính như node trước đó thì không cần chi phí QuickSort do đó chi phí build tree giảm bớt,
tuy nhiên so với chi phí tìm thì vẫn không có sự khác biệt.
\AC^5U_A5[8KL#MNN%AO*L*,-*LB*,U
Chi phí build cây:
Nếu mật độ phân bố đồng đều, thì số cấp của kd-Tree bằng với phương pháp
median . Thực tế thường mật độ phân bố các đới tượng bị sai lệch vùng thì dày
đặt vùng thì rất thưa thớt. Lúc đó Tổng số cấp của kd-Tree Splitding MidPoint luôn luôn
cao hơn kd-Tre Median, bởi vì phương pháp build này, cây có thể không được cân bằng.
Tuy nhiên kỹ thuật sliding giúp cho tại 1 node bất kì nếu sự phân vùng vô ích ( có 1 node
con rỗng), thì chúng cũng được dịch chuyển sao cho bất cứ node nào cũng có ít nhất 1
đối tượng. Điều đó đảm bảo số cấp của cây sẽ không tiến về n mà trường hợp xấu nhất
vẫn chỉ ở một mực độ nào đó.
Nếu xét cây cân bằng thì tương tự như thuật toán median chỉ khác ở chi phí split

+ Chi phí tìm midpoint sử dụng đối tượng tâm để phân thành 2 vùng đối tượng phân biệt
bởi giá trị tại lát cắt:
tức là (4) =
E
T (n) =O ( * d +k) với d là dimension
T (n) = O (d. )
Từ (1),(3),(4) Chi phí split tại cấp j =
= = (6)
 Tổng chi phí = (2)*(6)
T(n) =
Chi phí tìm kiếm k đối tượng gần nhất:
Chi phí tìm kiếm k đối tượng gần nhất hoàn toàn giống Median, tuy nhiên do
phương pháp Sliding MidPoint đảm bảo các thuộc tính của phân vùng không bị lệch nhau
quá nhiều nên đảm bảo độ phức tập thuật toán tiến gần về trường hợp tốt nhất.
4.7. Nhận xét:
Do chi phí tìm kiếm cho n điểm quyết định chi phí của cả quá trình, nên bõ qua
phần chi phí build cây, có thể kết luận: trong mọi trường hợp thì phương pháp Spliding
MidPoint vẫn là lựa chọn tốt nhất.
F
V. Cài đặt
Source code được đặt tại địa chỉ
/>5.1. Tính đúng đắn của các thuật toán
Tất cả các thuật toán tìm k-NN dựa trên kd-Tree chỉ đơn thuần là phân vùng các
đối tượng là tìm trên phân vùng gần hơn theo không gian.
Giả sử tập S phân thành 2 phân vùng con: S = S1 U S2
Trong đó dis(q) = qmin(S2) là khoảng cách nhỏ nhất từ điểm query q đến S2 và dmin =
boundmin(S1) là khoảng cách nhỏ nhất từ điểm query q đến vùng bao của S1. Thì
+ Nếu dis(q) <= dmin : thì dis(q) là nghiệm, bởi vì giá trị nhỏ nhất tìm ra nhỏ hơn giá trị
nhỏ nhất của vùng bao nên không cần tìm
+ Ngược lại thực hiện cho S1.

Nghĩa là thuật toán luôn luôn đúng (nếu cài đặt không bị sai).
5.2. Các chú ý trong cài đặt cơ bản thuật toán
+ Thuật toán được cài đặt trên ngôn ngữ C# nền .NET 3.5 (có thể chuyển sang 1.1 dễ
dàng).
+ Thuật toán cài đặt mức độ tổng quát cho không gian d chiều, do đó tốc độ sẽ không
được tốt nhất bởi vì phải sử dụng vòng lặp cho d chiều. Nếu áp dụng vào không gian cụ
thể thì nên bỏ vòng lặp để tối ưu tốc độ.
+ Thuật toán sử dụng index hóa các array nhằm mục đích tiết kiệm không gian nhớ và
tăng tốc độ.
+ Thuật toán cài đặt tách riêng phần build tree và search, do đó nếu có nhu cầu build cây
theo 1 cách khác thì có thể tái sử dụng toàn bộ source code với thay đổi tối thiểu code.
+ Thuật toán thực hiện dựa trên sự so sánh về logic tốc độ với thuật toán ANN chuẩn C+
+ trên trang web />+ Thuật toán có áp dụng xử lý parallel (song song) theo số lượng CPU.
5.3. Kiểm tra và so sánh tốc độ
Kiểm tra tốc độ dựa trên dữ liệu test khoảng 300000 đối tượng, k = 10.
So sánh logic và tốc độ giữa thuật toán ANN C++ và thuật toán kd-Tree Median

o Bucket Size = 1
• Dữ liệu random
• Dữ liệu tập trung
Kết luận:
Với dữ liệu random median chạy tốc độ gần bằng ANN C++, chỉ cần tối ưu code sử dụng
pointer unsafe thay cho array và loại bớt array không cần thiết là tốc độ ngang với ANN
C++, tuy nhiên với dữ liệu tập trung median chạy rất chậm, chậm gần 4 lần so với ANN
C++ (tùy thuột vào mức độ tập trung).
So sánh logic và tốc độ giữa thuật toán ANN C++ và thuật toán kd-Tree Sliding
MidPoint
o Bucket Size = 1
• Dữ liệu random
• Dữ liệu tập trung


o Bucket Size = 7
• Dữ liệu random
• Dữ liệu tập trung
• Dữ liệu tập trung + xử lý Parallel ( 2 CPU )
Kết luận:
Sử dụng cắt lớp theo Sliding MidPoint cho ra kết quả gần như giống với ANN C+
+. Nếu sử dụng tham số Bucket Size trong Leaf Node hợp lý có thể có kết quả tốt thậm
chí ngay cả chưa tối ưu hóa code.
5.4. Ứng dụng lọc nhiễu ( noise )

Một ứng dụng đơn giản sử dụng lọc nhiễu dựa trên kNN ( min max hoặc knn% ),
việc lọc nhiễu rất quang trọng cho việc xử lý và nhận dạng trên tập dữ liệu có quá nhiều
thông tin nhiễu mà các thông tin này có thể làm cho quá trình nhận dạng bị sai lệch.
VI. Điểm qua một số ứng dụng của thuật toán k-NN
.
 Pattern recognition - in particular for optical character recognition Nhận dạng mẫu - đặc
biệt đối với nhận dạng ký tự quang học
 Statistical classification- see k-nearest neighbor algorithm - Thống kê phân loại
 Computer vision- Cơ sở dữ liệu - ví dụ: nội dung dựa trên hình ảnh thu hồi
 Databases - e.g. content-based image retrieval
 Coding theory - see maximum likelihood decoding - Lý thuyết mã hóa - tối đa khả năng
giải mã
 Data compression - see MPEG-2 standard - Nén dữ liệu - xem MPEG-2 tiêu chuẩn
 Recommendation systems - Khuyến cáo của hệ thống
 Internet marketing - see contextual advertising and behavioral targeting - Internet tiếp
thị - quảng cáo theo ngữ cảnh nhìn thấy hành vi và mục tiêu
 DNA sequencing- Trình tự ADN
 Spell checking - suggesting correct spelling
 Plagiarism detection

 Similarity scores for predicting career paths of professional athletes.
 Lọc nhiễu ( noise )
 Cluster analysis - assignment of a set of observations into subsets (called clusters) so that
observations in the same cluster are similar in some sense, usually based on Euclidean
distance
• Cluster phân tích - phân công của một tập hợp các quan sát vào các tập con (gọi
làcụm) để quan sát trong cùng một nhóm tương tự như ở một nghĩa nào đó, thường
dựa trên khoảng cách Euclide
 Tính density
 Nếu xem một thành phần là một đơn thể và các đơn thể này có các tính chất được xác
định bởi một giá trị cụ thể thì k-NN có thể sử dụng cho việc tìm và nhóm các thành phần
cùng chung một số tiêu chuẩn (features, attributes, properties) nào đó.
 data mining, statistical pattern recognition
Kết luận

Bài nghiên cứu này nhằm mục đích tìm hiểu về thuật toán tìm các đối tượng lân
cận gần nhất (k-NN) trong bộ nhớ sử dụng kd-Tree. Từ việc tìm hiểu cài đặt thuật toán có
thể kết luận: thuật toán dựa trên kd-Tree là thuật toán có thể nói là tốt nhất trong các thuật
2

×