knn分類算法
1.特點
- 精度高
- 對異常值不敏感、計算時間空間復雜度高
2.基本思想、算法偽代碼
計算待預測樣本與數據集中點的距離
選取前k個與待預測樣本距離最小的點
返回這前k個點出現頻率最高的類別作為待預測樣本的類別
3.構思定義好存儲數據結構
- dataSet (m*n階矩陣):m代表m個數據,n代表每個數據的特征向量維度
- labels (m*1 list):m與數據數對應
- classCount (p個key-value對的字典):p代表類別數,key代表類比名稱,value代表與待預測樣本距離最近的前k個點中相應類別出現的次數
該結構適用於投票表決情況,例如DT中子節點的類別歸屬問題,同樣適用
4.算法python代碼細節
- 注意利用np.tile將待預測樣本維度擴展,餐能進一步整體計算距離
例如(testMat = np.tile(x, (m, 1)))
- 注意利用np.argsort()對距離排序,並返回由小到大的索引值
例如(sortedDistIndex = np.argsort(dist))
- 注意sorted函數與operator.itemgetter(1)的配合使用,對字典的value進行排序,也要注意對字典進行.iems()轉換為可迭代列表操作
例如(sortedClassCount = sorted(classCount.itmes(), key = operator.itemgetter(1), reverse = True))
- 注意使用字典的.get()方法直接為不存在key設置初始值,簡化代碼
例如(classCount[label] = classCount.get(label, 0) + 1)
- 注意數據特征的歸一化處理(消除量綱)
- 注意錯誤率的計算思路
例如(預測標簽和測試集標簽不同的數量/總預測數量)
5.實戰
- 約會網站配對、手寫數字識別
LR分類算法
1.特點
- 計算代價不高,易於理解實現,大部分時間用於訓練,訓練完成后分類快。
- 容易欠擬合,分類精度不高。
2.基本思想
- LR的目的:尋找一個非線性函數sigmoid的最佳擬合參數,求解過程由最優化算法完成。
- sigmoid函數:輸入為實數域,輸出為0~1之前的數值,大於0.5歸入1類,小於0.5歸入0類。(可看成是一種概率估計)。
- 最優化算法:BGD(批量梯度下降)、SGD(隨機梯度下降)、mini-batch SGD。
SGD算法是在線學習算法(與之對應的是批處理算法),他的優勢:在新數據到來時就完成參數的更新,無需重新讀取整個數據集進行計算
- 整體分類處理流程:將測試集上每個特征向量乘以之前最優化算法訓練好的回歸系數,再將乘積結果求和,最后出入到sigmoid函數中即可輸出類別。
3.構思定義好存儲數據結構
- dataSet(m*n 階矩陣):m代表m個數據點,n代表每個數據點向量維度(最后一維表示該點的標簽),沒有x0。
- weights(n*1 階矩陣):n代表回歸系數的維度與數據點維度相同。
4.算法偽代碼
def BGD:
初始化回歸系數為1
循環k次:
計算整個數據集梯度(gradient)
利用alphs*gradient更新回歸系數向量
返回回歸系數
def SGD:
初始化回歸系數為1
循環k次:
隨機選取之前未選去過的某個數據點:
計算該數據點的梯度
更新回歸系數
返回回歸系數
5.算法python代碼細節
- 注意numpy矩陣(mat)的transpose()使用,避免矩陣相乘出錯
(例如:weights += alpha * dataMatrix.transpose() * error)
- 注意numpy矩陣(mat)和numpy數組(array)的乘法使用不同
- 注意SGD中隨機選取某個數據點應與之前選去過的去重
(例如:del(dataIndex[randIndex]))
6.實戰
- 從疝氣病症預測病馬的死亡率
- 數據預處理中數據缺失問題:
LR特征缺失采用0填充
原因: 1。更新時不會影響系數的值 weights += alpha * dataMatrix * error ,以0填充,該特征系數將不做更新
2。對結果預測不產生任何傾斜性,因為sigmoid(dataMatrix * weight)中sigmoid(0)=0.5
- 注意算法錯誤率的計算,並測試多次取平均值思想
決策樹(DT)分類算法
1.特點
- 計算復雜度不高、輸出結果易於理解(訓練好的模型可以序列化存儲)、對中間值的缺失不敏感
- 會產生過度匹配問題(ID3算法),可采用CART算法解決
2.基本思想
- 首先測量初始集合中數據的不一致性,即熵。熵越高,數據越混亂。
- 然后根據信息增益尋找最優方案划分數據集,直至數據集中所有數據屬於同一類
- 信息增益,即熵的減少或者數據無序度的減少。信息增益最高的特征就是最好的划分選擇。
3.構思定義好存儲數據結構
- dataSet (m*n階矩陣):m個數據、每個數據n-1個特征,最后一維代表標簽
- myTree ({feature: { }}字典):構造的決策樹
- labels (k大小的列表):類別列表
4.算法偽代碼(五個主要函數)
def 遞歸創建決策樹(dataSet, labels):
遞歸出口(兩種情況):
1. 划分后的集合類別完全相同
2. 遍歷完所有特征(采用投票多數選舉策略)
確定最佳划分特征
對於該特征的每個特征值划分后的數據:
遞歸調用創建決策樹
返回決策樹
def 確定最佳划分特征(dataSet):
計算初始熵
對於每個特征:
對於該特征的每個特征值:
計算該特征值划分后的熵
每個特征值划分后的熵相加得到該特征划分后的熵
返回信息增益(前后熵變化)最大的特征
def 按照給定特征划分數據集(dataSet, axis, value):
返回指定特征的去除特征值的數據
def 計算給定數據集的香農熵(dataSet):
統計每個類別數據量
計算每個類別概率:每個類別數據量/總數據量
計算香濃熵:- prob * log(prob, 2)
def 使用決策樹進行分類(tree, labels, testVec):
對於字典中每個value:
如果該value是字典型,則遞歸調用函數
如果不為,則直接返回該類別
5.python代碼細節
- 注意使用列表推導創建新列表,並使用python原生的集合(set)數據類型去重,簡化代碼
(例如:featValue = set([example[i] for example in dataSet]))
- 注意列表extend和append的恰當使用
- 注意字典類型判斷使用isinstance或type().__name__
(例如:if type(secondDict[key].__name__ == 'dict') if isinstance(secondDict[key], dict))
- 注意使用pickle序列化存儲
(例如pickle.dump(tree, file) pickle.load(file))
6.實戰
- 預測隱形眼鏡類型
Bayes分類
1.特點
- 數據較少的情況下仍然有效,可處理多類別問題
- 對輸入數據要求較為敏感
2.基本思想
- 朴素貝葉斯前提:特征之間相互獨立,即一個詞的出現概率不依賴於其他的詞
- 貝葉斯准則:p(c|w) = p(w|c) * p(c) / p(w)
其中c代表類別,w代表文本向量。p(c|w)最大即將其划分為對應c類。
- 主要計算p(w|c)和p(c)
- 兩種主要細節解決實際問題
1.p(w|c)為0問題。在求p(w|c)時,有一個為0就會導致整個條件概率為0。
采用拉普拉斯平滑方法,初始化時將每個詞條出現次數設為1,將總詞條出現數設為k,k為類別數
2.下溢出問題。由於p(w|c)往往都很小,python嘗試想成很多很小的數時,會四舍五入為0。
采用取對數方法,ln(a * b) = ln(a) + ln(b)
3.構思定義好存儲數據結構
- dataSet (二維列表):存儲文檔集;一維存儲文檔,二維存儲每個文檔的內容(詞)
- vocList(1*n列表):存儲每個詞;m代表文檔集中的n個不同的詞
- trainMat(m*n階矩陣):存儲訓練文檔集向量;m代表m個訓練文檔,n代表每個文檔中所有詞出現的次數(與vocList中的n對應)
4.算法偽代碼(共五大函數)
def 創建總詞集合(dataSet):
對於每個文檔:
去重詞條
將所有詞條合並
返回總詞集合列表
def 將文檔轉化為向量(vocList, doc): one-hot表示法
初始化詞計數列表各項為0
對於該文檔每個詞:
如果詞在vocList(總詞集合)中:
詞計數列表相應位置計數+1
若果不在:
報錯:總詞集合中不存在該詞
返回詞計數列表,即文檔向量
def 訓練參數(trainMat, trainClass):
計算pc1=屬於類別c1的文檔數/總文檔數
對於每個文檔:
對於每個類別:
統計各詞條出現次數
統計總詞條出現次數
對於每個類別:
對於每個詞條:
計算p(w|c) = 該詞條出現次數/總詞條出現次數
返回各個p(w|c)和p(c)
def 分類函數(testVec, pwc0, pwc1, pc1):
計算p0和p1
將測試文檔划分為p值(概率)大的那一類
def 垃圾郵件分類封裝函數():
對於每篇文檔:
文檔預處理(去除特殊符號、和長度小於2的詞、轉化為小寫)
讀入詞列表、類別標簽
形成文檔集合
創建總詞集合
留存交叉驗證划分訓練集和測試集
訓練出p(w|c)和p(c)
對於每篇測試文檔:
根據訓練好的參數分類
計算誤差(錯誤率)
5.python代碼細節
- 注重集合set類型的去重使用和並集操作
(例如:vocList = vocList | set(doc))
- 注重列表快速初始化
(例如:docVec = [0] * len(vocList) trainingSet = range(50))
- 注重留存交叉驗證技巧,設置隨機索引,並注意del的使用
(例如:trainingSet = range(50) for i in range(10):randIndex = random.randint(0, len(trainingSet)) testSet.append(tS[rI]) del(tS[rI]))
6.實戰
- 過濾網站惡意留言、過濾垃圾郵件
SVM支持向量機
1.特點
- 泛化能力強、計算開銷不大、結果易解釋
- 對參數調節和核函數的選擇敏感,原始不加修改的分類器僅適用於二分類
2.基本思想
- 最大化支持向量到分隔超平面的距離;支持向量:離分隔超平面最近的那些點;公式化:argmax{miny(wx+b)*1/||w||}
||w||為w的L2范數
- 最優分離超平面由支持向量完全決定
- 函數間隔、幾何間隔:幾何間隔在函數間隔的基礎上對超平面的法向量w加某些約束(當w和b成倍增加時,超平面不變,而函數間隔卻也成倍增加,所以引入幾何間隔,即*1/||w||)
- 凸二次規划問題,求解方法:朗格朗日乘子法;通過求解對偶問題學習線性支持向量機,即首先求解對偶問題的最優質α,然后求最優質w和b,得出分離超平面和分類決策函數
- 對偶問題:實質相同但從不同角度提出不同提法的一對問題。
二次規划問題:優化的目標函數為二次函數、約束函數為線性函數。
凸二次規划:目標函數是凸函數。
- 核函數:通過非線性變換將低維非線性問題映射為高維線性問題。常用核函數:高斯徑向基函數。
- SMO(序列最小優化)算法:是支持向量機學習的一種快速算法。
基本思想:不斷將原二次規划問題分解為只有兩個變量的二次規划子問題,並對子問題進行求解,直到所有變量滿足KKT條件為止。
AdaBoost(Boosting)元算法
1.特點
- 分類器組合,與bagging都屬於集成算法或元算法。與bagging區別:bagging通過隨機抽樣的替換方式,得到與元數據集規模一樣的數據集(RF隨機森林算法),而boosting在bagging的思路上更進一步,它在數據集上順序應用多個分類器,共同決定分類結果。
2.基本思想
- AdaBoost以弱分類器作為基分類器,輸入數據,使其通過權重向量D進行加權。在第一次迭代中,所有數據樣本的權重相等為1/N,在后續迭代過程中,前次迭代分錯的數據的權重會增大。最后基於每個弱分類器的錯誤率計算每個弱分類器的權重alpha,所有這些弱分類器的結果加權求和就得到了最終結果。
3.構思定義好存儲數據結構
- numIt(整數):AdaBoost訓練迭代次數,即弱分類器個數
- classEst(列表中元素對應1或-1):弱分類器評估的類別
- bestStump(字典):存儲給定數據權重向量D時所得到的弱分類器,即最佳DS(單層決策樹),的相關信息(划分特征、閾值、該分類器權重alpha等)
- weakClassList(列表):存儲每個bestStump的列表集合,用於封裝各個弱分類器的相關信息,即該列表每行對應一個弱分類器的bestStump。
- aggClassEst(列表中元素為float):存儲每次alpha權重加權求和后的類別估計值,后續引入符號函數sign(aggClassEst)形成強分類器。
4.算法偽代碼(三大函數)
根據向量D構建最佳DS
def buildStamp(dataList, classLabels, D):
初始化最小錯誤率為正無窮
對於數據集中的每個特征:
對於每個步長:
對於每個不等號:
建立一顆單層決策樹並利用加權數據集對其進行測試
如果錯誤率低於最小錯誤率,則將當前單層決策樹作為最佳單層決策樹
返回最佳單層決策樹
基於DS的adaboost訓練函數
def adaBoostTrainDS(dataList, classLabels, numIt=40):
初始化數據權重D為1/N
對於每次迭代:
找到該D下的最佳單層決策樹,返回該最佳決策樹信息,在D下的誤差和類別數組
將該DS加入DS累積數組
利用該弱分類器在D下的誤差計算出分類器權重alpha
計算更新D
更新累計類別估計值,即計算alpha和相應弱分類器的類別數組加權求和
通過符號函數sign得到強分類器,計算錯誤率。如果錯誤率等於0,退出循環
返回DS累積數組
adaboost分類函數
def adaClassify(testData, classifyArr):
對於訓練好的每個弱分類器:
計算測試數據的類別
進行相應alpha加權求和
利用符號函數返回類別
5.實戰
- 提升從疝氣病症預測病馬的死亡率的准確度
- 非均衡分類問題(正反樣例數目不相等)解決辦法:1. 通過過抽樣(復制樣例)和欠抽樣(刪除樣例)調節 2. 訓練分類器時,將錯誤代價考慮在內
K-means聚類算法
1.特點
- 容易實現,無監督(無需訓練操作)
- 容易受到初始簇質心的影響,可能收斂到局部最小、在大規模數據集上收斂較慢。
2.基本思想
- 隨機確定k個初始點作為質心。
- 將數據集中每個點分配到一個簇中(為每個點找出距離其最近的質心,並將其分配給該質心所對應的簇)。
- 更新每個簇的質心為所有點的平均值(直至每個點的簇分配結果不再改變)
3.構思定義好存儲數據結構
- 數據集dataSet(m*n 階 numpy 數據 (矩陣) ):m代表有m個數據點,n代表每個數據點向量維度為n。
- 質心集centroids(k*n 階):k代表有k個質心,n對應向量維度。
- 簇分配集clustAss(m*2)[minIndex, minDis]:m對應m個數據點,索引[0](即minIndex)代表相應數據點分配的質心索引,索引[1](即minDis)代表數據點和其分配質心的距離平方。
4.算法偽代碼
初始化k個質心
當任意一個數據點的簇分配結果改變時:
對數據集中的每個點:
對每個質心:
計算該點與該質心的距離
將該點分配到距離最近的質心所在簇
對每個質心所在簇:
更新其質心為簇中所有點的均值
5.算法python代碼細節
- 善於使用數組過濾器
(例如:更新質心時簡短代碼:centroids[i, :] = np.mean(dataSet[np.nonzero(clustAss[i, :] == cent) [0] ]))
- 善於使用標志變量
(例如:利用clustchanged來標記數據點簇分配結果是否改變)
- 善於打包函數,防止主程序過於臃腫
(例如:將加載文件、計算距離和隨即初始化質心集另打包為三個函數,在kmeans主函數中直接使用上述函數)
6.算法改進
- 二分k-means聚類算法
- 基本思想:將所有點作為一個簇,然后使用傳統Kmeans聚類算法(k=2)對其進行划分。下一次迭代時,選擇有最大誤差的簇進行划分,直至k個簇創建成功。
- 偽代碼:
將所有點看作一個簇
當簇數目小於k時:
計算總誤差
對於每個簇:
對該簇進行傳統k-means聚類(k=2)
計算將該簇一分為二后的總誤差
選擇使得總誤差最小的簇進行實際划分操作
7.實戰
- 地圖點聚類
- 具體步驟:
0. 目的:將多個地方聚類,選擇最佳地點
1. 利用Yahoo PlaceFinder API 將地名轉化為數據,並提取出經緯度
2. 應用biKmeans算法聚類