一:訓練模型、實現預測函數
import numpy as np import re import random def loadDataSet(): DataSetList=[] #全部數據集 classVec = [] #標簽值 #獲取數據 SpamPath = "email/spam/{}.txt" #獲取文件路徑 HamPath = "email/ham/{}.txt" for i in range(1,26): #兩個路徑各有25個文件 documentData = open(SpamPath.format(i),'r', encoding='ISO-8859-1').read() #使用正則進行分割,除了空格、還有標點都可以用於分割 WordVec = re.split(r"\W+",documentData) #\W*表示匹配多個非字母、數字、下划線的字符 DataSetList.append([item for item in WordVec if len(item)>0]) classVec.append(1) documentData = open(HamPath.format(i), 'r', encoding='ISO-8859-1').read() # 使用正則進行分割,除了空格、還有標點都可以用於分割 WordVec = re.split(r"\W+", documentData) # \W*表示匹配多個非字母、數字、下划線的字符 DataSetList.append([item for item in WordVec if len(item)>0]) classVec.append(0) return DataSetList,classVec def createVocabList(dataSet): #創建詞匯列表 將多個文檔單詞歸為一個 VocabSet = set([]) #使用集合,方便去重 for document in dataSet: VocabSet = VocabSet | set(document) #保持同類型 VocabList = list(VocabSet) VocabList.sort() return VocabList def WordSet2Vec(VocaList,inputSet): #根據我們上面得到的全部詞匯列表,將我們輸入得inputSet文檔向量化 returnVec = [0]*len(VocaList) for word in inputSet: if word in VocaList: returnVec[VocaList.index(word)] = 1 else: print("the word: %s is not in my Vocabulary!"%word) return returnVec def trainNB0(trainMatrix,trainCategory): #訓練朴素貝葉斯模型 傳入numpy數組類型 trainMatrix所有文檔詞匯向量矩陣(m*n矩陣 m個文檔,每個文檔都是n列,代表詞匯向量大小),trainCategory每篇文檔得標簽 numTrainDoc = len(trainMatrix) #文檔數量 pC1 = np.sum(trainCategory)/numTrainDoc #p(c1)得概率 p(c0)=1-p(c1) wordVecNum = len(trainMatrix[0]) #因為每個文檔轉換為詞匯向量后都是一樣得長度 #初始化p1,p0概率向量---改進為拉普拉斯平滑 p1VecNum,p0VecNum = np.ones(wordVecNum),np.ones(wordVecNum) p1Sum,p0Sum = 2.0,2.0 #N*1 N表示分類數 #循環每一個文檔 for i in range(numTrainDoc): if trainCategory[i] == 1: #侮辱性文檔 p1VecNum += trainMatrix[i] #統計侮辱性文檔中,每個單詞出現頻率 p1Sum += np.sum(trainMatrix[i]) #統計侮辱性文檔中出現得全部單詞數 每個單詞出現概率就是單詞出現頻率/全部單詞 else: #正常文檔 p0VecNum += trainMatrix[i] p0Sum += np.sum(trainMatrix[i]) p1Vect = np.log(p1VecNum / p1Sum) #統計各類文檔中的單詞出現頻率 p0Vect = np.log(p0VecNum / p0Sum) #使用對數避免下溢 return p1Vect,p0Vect,pC1 def classifyNB(testVec,p0Vec,p1Vec,pC1): p1 = sum(testVec*p1Vec)+np.log(pC1) #使用對數之后變為求和 p0 = sum(testVec*p0Vec)+np.log(1-pC1) if p1 > p0: return 1 else: return 0
二:實現K折交叉驗證法---k=5
def OneCrossValidate(trainSet,trainCls,testSet,testCls): #訓練模型 p1Vect,p0Vect,pC1 = trainNB0(np.array(trainSet),np.array(trainCls)) err_count = 0 #驗證集進行測試 for i in range(10): c = classifyNB(np.array(testSet[i]),p0Vect,p1Vect,pC1) if c != testCls[i]: err_count += 1 return err_count/10 def KCrossValidate(trainMat,trainClassVec): #K折交叉驗證 5 randIdx = list(range(50)) random.shuffle(randIdx) error_radio = 0.0 for i in range(5): #5次 rdInd = randIdx #隨機索引 #選取訓練集、驗證集索引 trainSet = [] trainCls = [] testSet = [] testCls = [] testSetIdx = set(randIdx[10*i:10*i+10]) # 訓練集 trainSetIdx = set(rdInd)-testSetIdx # 驗證集 #選取訓練集、驗證集數據 for idx in trainSetIdx: trainSet.append(trainMat[idx]) trainCls.append(trainClassVec[idx]) for idx in testSetIdx: testSet.append(trainMat[idx]) testCls.append(trainClassVec[idx]) print(OneCrossValidate(trainSet,trainCls,testSet,testCls)) error_radio += OneCrossValidate(trainSet,trainCls,testSet,testCls) return error_radio/5 DocData,classVec = loadDataSet() voclist = createVocabList(DocData) #獲取全部文檔詞匯向量矩陣 trainMulList = [] for doc in DocData: trainMulList.append(WordSet2Vec(voclist,doc)) print(KCrossValidate(trainMulList,classVec))


