最近在看knn算法,順便敲敲代碼。
knn屬於數據挖掘的分類算法。基本思想是在距離空間裡,如果一個樣本的最接近的k個鄰居裡,絕大多數屬於某個類別,則該樣本也屬於這個類別。俗話叫,“隨大流”。
簡單來說,KNN可以看成:有那麼一堆你已經知道分類的數據,然後當一個新的數據進入的時候,就開始跟訓練裡的每個點求距離,然後挑出離這個數據最近的K個點,看看這K個點屬於什麼類型,然後用少數服從多數的原則,給新數據歸類。
該算法的示意圖,簡單明了:
下面的算法步驟取自於百度文庫(文庫是一個好東西),代碼是參照這個思路實現的:
code:
1 #include<stdio.h> 2 #include<math.h> 3 #include<stdlib.h> 4 5 #define K 3 //近鄰數k 6 typedef float type; 7 8 //動態創建二維數組 9 type **createarray(int n,int m) 10 { 11 int i; 12 type **array; 13 array=(type **)malloc(n*sizeof(type *)); 14 array[0]=(type *)malloc(n*m*sizeof(type)); 15 for(i=1;i<n;i++) array[i]=array[i-1]+m; 16 return array; 17 } 18 //讀取數據,要求首行格式為 N=數據量,D=維數 19 void loaddata(int *n,int *d,type ***array,type ***karray) 20 { 21 int i,j; 22 FILE *fp; 23 if((fp=fopen("data.txt","r"))==NULL) fprintf(stderr,"can not open data.txt!\n"); 24 if(fscanf(fp,"N=%d,D=%d",n,d)!=2) fprintf(stderr,"reading error!\n"); 25 *array=createarray(*n,*d); 26 *karray=createarray(2,K); 27 28 for(i=0;i<*n;i++) 29 for(j=0;j<*d;j++) 30 fscanf(fp,"%f",&(*array)[i][j]); //讀取數據 31 32 for(i=0;i<2;i++) 33 for(j=0;j<K;j++) 34 (*karray)[i][j]=9999.0; //默認的最大值 35 if(fclose(fp)) fprintf(stderr,"can not close data.txt"); 36 } 37 //計算歐氏距離 38 type computedistance(int n,type *avector,type *bvector) 39 { 40 int i; 41 type dist=0.0; 42 for(i=0;i<n;i++) 43 dist+=pow(avector[i]-bvector[i],2); 44 return sqrt(dist); 45 } 46 //冒泡排序 47 void bublesort(int n,type **a,int choice) 48 { 49 int i,j; 50 type k; 51 for(j=0;j<n;j++) 52 for(i=0;i<n-j-1;i++){ 53 if(0==choice){ 54 if(a[0][i]>a[0][i+1]){ 55 k=a[0][i]; 56 a[0][i]=a[0][i+1]; 57 a[0][i+1]=k; 58 k=a[1][i]; 59 a[1][i]=a[1][i+1]; 60 a[1][i+1]=k; 61 } 62 } 63 else if(1==choice){ 64 if(a[1][i]>a[1][i+1]){ 65 k=a[0][i]; 66 a[0][i]=a[0][i+1]; 67 a[0][i+1]=k; 68 k=a[1][i]; 69 a[1][i]=a[1][i+1]; 70 a[1][i+1]=k; 71 } 72 } 73 } 74 } 75 //統計有序表中的元素個數 76 type orderedlist(int n,type *list) 77 { 78 int i,count=1,maxcount=1; 79 type value; 80 for(i=0;i<(n-1);i++) { 81 if(list[i]!=list[i+1]) { 82 //printf("count of %d is value %d\n",list[i],count); 83 if(count>maxcount){ 84 maxcount=count; 85 value=list[i]; 86 count=1; 87 } 88 } 89 else 90 count++; 91 } 92 if(count>maxcount){ 93 maxcount=count; 94 value=list[n-1]; 95 } 96 //printf("value %f has a Maxcount:%d\n",value,maxcount); 97 return value; 98 } 99 100 int main() 101 { 102 int i,j,k; 103 int D,N; //維度,數據量,標簽 104 type **array=NULL; //數據數組 105 type **karray=NULL; // K近鄰點的距離及其標簽 106 type *testdata; //測試數據 107 type dist,maxdist; 108 109 loaddata(&N,&D,&array,&karray); 110 testdata=(type *)malloc((D-1)*sizeof(type)); 111 printf("input test data containing %d numbers:\n",D-1); 112 for(i=0;i<(D-1);i++) scanf("%f",&testdata[i]); 113 114 while(1){ 115 for(i=0;i<K;i++){ 116 if(K>N) exit(-1); 117 karray[0][i]=computedistance(D-1,testdata,array[i]); 118 karray[1][i]=array[i][D-1]; 119 //printf("first karray:%6.2f %6.0f\n",karray[0][i],karray[1][i]); 120 } 121 122 bublesort(K,karray,0); 123 //for(i=0;i<K;i++) printf("after bublesort in first karray:%6.2f %6.0f\n",karray[0][i],karray[1][i]); 124 maxdist=karray[0][K-1]; //初始化k近鄰數組的距離最大值 125 126 for(i=K;i<N;i++){ 127 dist=computedistance(D-1,testdata,array[i]); 128 if(dist<maxdist) 129 for(j=0;j<K;j++){ 130 if(dist<karray[0][j]){ 131 for(k=K-1;k>j;k--){ //j後元素復制到後一位,為插入做准備 132 karray[0][k]=karray[0][k-1]; 133 karray[1][k]=karray[1][k-1]; 134 } 135 karray[0][j]=dist; //插入到j位置 136 karray[1][j]=array[i][D-1]; 137 //printf("i:%d karray:%6.2f %6.0f\n",i,karray[0][j],karray[1][j]); 138 break; //不比較karray後續元素 139 } 140 } 141 maxdist=karray[0][K-1]; 142 //printf("i:%d maxdist:%6.2f\n",i,maxdist); 143 } 144 //for(i=0;i<K;i++) printf("karray:%6.2f %6.0f\n",karray[0][i],karray[1][i]); 145 bublesort(K,karray,1); 146 //for(i=0;i<K;i++) printf("after bublesort in karray:%6.2f %6.0f\n",karray[0][i],karray[1][i]); 147 printf("\nThe data has a tag: %.0f\n\n",orderedlist(K,karray[1])); 148 149 printf("input test data containing %d numbers:\n",D-1); 150 for(i=0;i<(D-1);i++) scanf("%f",&testdata[i]); 151 } 152 return 0; 153 }
實驗:
訓練數據data.txt:
N=6,D=9
1.0 1.1 1.2 2.1 0.3 2.3 1.4 0.5 1
1.7 1.2 1.4 2.0 0.2 2.5 1.2 0.8 1
1.2 1.8 1.6 2.5 0.1 2.2 1.8 0.2 1
1.9 2.1 6.2 1.1 0.9 3.3 2.4 5.5 0
1.0 0.8 1.6 2.1 0.2 2.3 1.6 0.5 1
1.6 2.1 5.2 1.1 0.8 3.6 2.4 4.5 0
預測數據:
1.0 1.1 1.2 2.1 0.3 2.3 1.4 0.5
1.7 1.2 1.4 2.0 0.2 2.5 1.2 0.8
1.2 1.8 1.6 2.5 0.1 2.2 1.8 0.2
1.9 2.1 6.2 1.1 0.9 3.3 2.4 5.5
1.0 0.8 1.6 2.1 0.2 2.3 1.6 0.5
1.6 2.1 5.2 1.1 0.8 3.6 2.4 4.5
程序測試的結果:
1.0 1.1 1.2 2.1 0.3 2.3 1.4 0.5 類別為: 1
1.7 1.2 1.4 2.0 0.2 2.5 1.2 0.8 類別為: 1
1.2 1.8 1.6 2.5 0.1 2.2 1.8 0.2 類別為: 1
1.9 2.1 6.2 1.1 0.9 3.3 2.4 5.5 類別為: 0
1.0 0.8 1.6 2.1 0.2 2.3 1.6 0.5 類別為: 1
1.6 2.1 5.2 1.1 0.8 3.6 2.4 4.5 類別為: 0
實驗截圖: