學習機器學習也有段時間了,借《機器學習 實戰》的第一篇中的例子來記錄下自己的學習過程吧,《實戰》中的第一講即是利用k近鄰分類器進行手寫體的識別,原理很簡單,由於手寫體的數字已經被處理成用01表示的文本
,如圖所示
在進行識別的時候,把要識別的文本轉化成一個32*32的矩陣,爲了方便計算,又將該矩陣轉化爲一個1024維的向量,然後將該向量與訓練的樣本相減求模,選擇模最小的幾個樣本,又根據這個樣本所代表數字最多的作爲識別的結果,思路很簡單,但計算量比較大,每識別一次就得利用每個樣本進行大量的運算,這是書中所採用的方法,作爲訓練自己,我當然不會按步就班,於是,我就想,能否利用其他的監督學習方法呢?首先這是一個多分類的問題,一共有十個結果,既然是多分類,那麼第一個我能想到的便是樸素貝葉斯的分類方法,樸素貝葉斯原理也很簡單,它有一個很強的假設,對於這個手寫識別的特定問題而言,就是每個位置上出現的1和0是獨立事件,儘管不大合適,作爲練習實驗,也無不可,好,說幹就幹!
clear; rate=1; sour=dir('*.txt');%Get all *.txt sourc=size(sour); sourconut=sourc(1); samto=cell(1,sourconut); for k=1:sourconut title=int8(sour(k).name(1))-int8('0');%獲取txt文件的第一個字符,作爲值 sample.title=title; f = fopen(sour(k).name,'rt'); x = fread(f,'char'); fclose(f); t=size(x); buff=[]; for i=1:t(1) if( int8(x(i))~=10 && int8(x(i))~= 32) t1=size(buff); t2=t1(1)+1; buff(t2,1)=int8(int8(x(i))-int8('0')); end end sample.content=buff; samto{k}=sample;%此處samto爲所有樣本的元胞,格式爲{title content} end %samto={{title content},..},content=圖片按行取列 Qy=zeros(1,10); %Qy爲樣本中出現每個類型的概率,即樣本爲0的概率,1的概率... Q=zeros(1024,10); ty=zeros(1,10); for i=0:9 t=0; for k=1:sourconut t1=samto(k); if(t1{1}.title==i) t=t+1; end end ty(i+1)=t; Qy(i+1)=t/sourconut*rate; end %Qy計算完 disp('begin to calculate Q'); for y=0:9 disp(strcat('y=',int2str(y))); for k=1:1024 t2=0; for i=1:sourconut t1=samto{i}.title; if(samto{i}.content(k)==1 &&t1==y) t2=t2+1; end end Q(k,y+1)=(t2+1)/(ty(y+1)+10)*rate; %disp(strcat('Q=',int2str(t2))); end end disp('done!');
靠,代碼居然沒有Matlab,那就將就用Python的吧,應該也行吧,呵呵,Matlab剛學不久,表示代碼寫得有點不倫不類.....代碼中的*.txt是用的《實戰》中的訓練樣本,每個訓練樣本被都爲一個txt文件,如數字1的7號書寫體文件名爲1_7.txt,數字2的28號書寫體文件名2_28.txt,樣本中一共有近2000個樣本,上面的代碼,即可獲得Q及Qy兩個值,Qy表示樣本中出現數字n的概率,Q爲數字n中每個位置爲1的概率,還是截個圖吧。。。
Qy:
Q(太長了就部分截圖吧):
稍微解釋一下數據的含義,比如Qy中的0.0977就表示樣本中數字0所佔得比例,即0出現的概率,可以發現Qy中每種樣本的概率接近1,這是因爲各種樣本數量相當,而Q是一個1024*10的矩陣,就那1行1列的數來說吧,表示數字0的手寫體中的1行1列爲1的概率爲0.0050,噢,對了,由於進行了拉格朗日平滑,所以沒有爲0的概率,其實這個0.0050算是最小的了, 這些相信只要懂得樸素貝葉斯的原理,應該很好理解吧...呵呵....
最後,測試下識別率!
clear; Qroot=load('Q'); Qroot=Qroot.Q; Qyroot=load('Qy'); Qyroot=Qyroot.Qy; sour=dir('*.txt'); sourc=size(sour); sourcount=sourc(1); samto=cell(1,sourcount); for k=1:sourcount title=int8(sour(k).name(1))-int8('0'); sample.title=title; sample.name=sour(k).name; f = fopen(sour(k).name,'rt'); x = fread(f,'char'); fclose(f); t=size(x); buff=[]; for i=1:t(1) if( int8(x(i))~=10 && int8(x(i))~= 32) t1=size(buff); t2=t1(1)+1; buff(t2,1)=int8(int8(x(i))-int8('0')); end end sample.content=buff; samto{k}=sample; end r=0; for j=1:sourcount test=samto{j}.content; testTitle=samto{j}.title; name=samto{j}.name; p=ones(1,10); for i=0:9 for k=1:1024 if(test(k)==1) p(i+1)=p(i+1)*Qroot(k,i+1); else p(i+1)=p(i+1)*(1-Qroot(k,i+1)); end end p(i+1)=p(i+1)*Qyroot(i+1); end guess=find(p==max(p))-1; if guess==testTitle r=r+1; else disp(strcat('guess:',int2str(guess))); disp(strcat('title:',int2str(testTitle))); disp(strcat('name:',name)); disp(p); end end disp(r/sourcount);
正確率爲0.9302,還算行吧,呵呵,噢,對了,代碼不但輸出了正確率,也輸出了識別錯誤的那些樣本,幫助自己分析錯誤原因,如果大家要實驗的話,建議大家先把《實戰》的樣本包下載下來,再實驗,至於網址吧,百度一下就行了,哈哈!