小白好難得會用python做第分類,實踐一下用于kaggle入門賽之泰坦尼克生還預測
問題介紹:泰坦尼克電影大家都看過,大災難過后有些人生還了,有些人卻遭遇了不信,官方提供了1309名乘客的具體信息以及提供了其中891名乘客的最后的存活情況,讓我們去預測另外418乘客的存活情況。是很基本的二分類問題。
官方所給的數據長這樣:

Survived:是否存活(0代表否,1代表是)Pclass:社會階級(1代表上層階級,2代表中層階級,3代表底層階級)Name:船上乘客的名字Sex:船上乘客的性別Age: 船上乘客的年齡(可能存在 NaN)SibSp:乘客在船上的兄弟姐妹和配偶的數量Parch:乘客在船上的父母以及小孩的數量Ticket:乘客船票的編號Fare:乘客為船票支付的費用Cabin:乘客所在船艙的編號(可能存在 NaN)Embarked:乘客上船的港口( S 代表從 Southampton 登船, C 代表從 Cherbourg 登船,Q 代表從 Queenstown 登船,)
我們面臨的主要問題有兩個,一個是age和cabin存在很多缺失值(Age(年齡)屬性只有714名乘客有記錄,Cabin(客艙)只有204名乘客是已知的),很可能會影響模型性能;另一個是訓練樣本就891個,訓練集過小,很容易造成過擬合。
由于影響因素太多,我們先對特征向量進行篩選。根據信息增益比進行排序畫圖(詳細知識點見《機器學習》周志華)

故我們就保留前三個影響因子。推測性別女士優先,年齡小孩優先,票價可能影響到其所在船艙而影響其存活率。
def file2matrix(filename): fr = open(filename) numberOfLines = len(fr.readlines()) #get the number of lines in the file returnMat = zeros((numberOfLines,3)) #PRepare matrix to return classLabelVector = [] #prepare labels return fr = open(filename) index = 0#確保指針在最前面 for line in fr.readlines(): line = line.strip() listFromLine = line.split(',') if listFromLine[5]=='male': listFromLine[5]='0' else: listFromLine[5]='1' if listFromLine[6]=='': listFromLine[6]=29.7 if listFromLine[7]=='': listFromLine[7]=35.6 #年齡的缺省用平均年齡29.7代替 returnMat[index,:] = listFromLine[5:8] #對應著性別,年齡和船票價 classLabelVector.append(int(listFromLine[1])) index += 1 return returnMat,classLabelVector#return的位置一定要找對二、分析數據
import matplotlib import matplotlib.pyplot as plt from os import listdirimport numpy as npdataset,classlabel=file2matrix('train1.csv')classlabel=array(classlabel)id0=np.where(classlabel==0)id1=np.where(classlabel==1)fig=plt.figure() ax=fig.add_subplot(111) p1=ax.scatter(dataset[id1,1],dataset[id1,2],color = 'r',label='1',s=20)p0=ax.scatter(dataset[id0,1],dataset[id0,2],color ='b',label='0',s=10)plt.legend(loc = 'upper right')plt.show這是以年齡和船票價分的
這是以年齡和性別分的
這是以性別和船票價分的
其實這里應該繼續探討特征間的相互聯系,做集成算法。不過初步先直接選定年齡和船票價為分類標準吧(誰叫小白還不會處理定性特征值呢
)
三、準備數據
歸一化數值
def autoNorm(dataSet): minVals = dataSet.min(0) maxVals = dataSet.max(0) ranges = maxVals - minVals normDataSet = zeros(shape(dataSet))#建立框架 m = dataSet.shape[0]#行數 normDataSet = dataSet - tile(minVals, (m,1))#每個數減該列最小 normDataSet = normDataSet/tile(ranges, (m,1)) #差再除以max-min return normDataSet, ranges, minVals四、測試算法
導入核心算法
def classify0(inX, dataSet, labels, k): dataSetSize = dataSet.shape[0]#4l diffMat = tile(inX, (dataSetSize,1)) - dataSet#inx按4*1重復排列再與sataset做差 sqDiffMat = diffMat**2#每個元素平方 sqDistances = sqDiffMat.sum(axis=1)#一個框里的都加起來 distances = sqDistances**0.5#加起來之后每個開根號 sortedDistIndicies = distances.argsort() #返回的是數組值從小到大的索引值,最小為0 classCount={} for i in range(k):#即0到k-1.最后得到的classCount是距離最近的k個點的類分布,即什么類出現幾次如{'A': 1, 'B': 2} voteIlabel = labels[sortedDistIndicies[i]]#返回從近到遠第i個點所對應的類 classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1#字典模式,記錄類對應出現次數.這里.get(a,b)就是尋找字典classcount的a對應的值,如果沒找到a,就顯示b sortedClassCount = sorted(classCount.iteritems(),key=Operator.itemgetter(1), reverse=True) return sortedClassCount[0][0]測試算法def surviorclasstest(): hoRatio = 0.10 #hold out 10% dataset,classlabel=file2matrix('train1.csv') #load data setfrom file normMat, ranges, minVals = autoNorm(dataset) m = normMat.shape[0] numTestVecs = int(m*hoRatio) errorCount = 0.0 for i in range(numTestVecs): classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],classlabel[numTestVecs:m],3) print "the classifier came back with: %d, the real answer is: %d" % (classifierResult, classlabel[i]) if (classifierResult != classlabel[i]): errorCount += 1.0 print "the total error rate is: %f" % (errorCount/float(numTestVecs)) print errorCount得到
the total error rate is: 0.269這里要提到一點,此時我們可以調節K值來使錯誤率變小,實際上K值越大錯誤率越小(驗證了一下k=10時0.235,k=15時0.224,k=100時0.191)如果選擇較小的k值,就相當于用較小的領域中的訓練實例學習,其近似誤差會小,但估計誤差會大,其泛化性能會比較差,因為預測結果會對近鄰的實例點非常敏感,即k值越小就意味著整體模型越復雜,容易發生過擬合;相對地,用較大的k值,可以減小學習的估計誤差,但是近似誤差會增大,這時與輸入實例較遠的不相似的訓練實例也會起預測作用,使預測發生錯誤,夸張一點k=N時無論輸入什么實例都返回整個訓練集占多數的類,k值越大意味著整體模型變得簡單,有可能欠擬合。在應用中,通常采用交叉驗證法來選取較優的k值。
(from《機器學習》周志華)
這里我比較懶加上之前提過這里樣本少很容易過擬合,再加上能上75%的準確率我已經很滿意啦。這里就選擇k=10吧。
五、使用算法
def classifyperson(): dataset,classlabel=file2matrix('train1.csv') normMat, ranges, minVals = autoNorm(dataset) testset,whatever=file2matrix('test.csv') normMattest, rangestset, minValstest = autoNorm(testset) h=testset.shape[0] for i in range(h): classifierResult = classify0(normMattest[i,:],normMat[:,:],classlabel[:],10) print classifierResult得到一串01的序列就可以提交啦。果然還是太粗糙,換成k=3
排名立馬上升150,這臉打得好疼。
六、優化方向
1、其實性別影響很大的,后期要加入2、關于K值的選擇和過擬合問題,可以引入正則化和交叉驗證3、數據挖掘分類算法辣么多,都試試
感覺靠譜的還有邏輯回歸,決策樹和支持向量機(SVM)另外可以嘗試集成學習
另外可以Bagging :有放回的自助采樣,生成多棵決策樹訓練以及在此基礎上再引入隨機屬性,進一步增加“多樣性”(隨機森林)(據說這一串下來可以到81%)
新聞熱點
疑難解答