天天看點

機器學習十大算法案例

機器學習十大算法與案例實作

  • 監督學習
  • 1. 線性回歸
  • 2. 邏輯回歸
  • 3. 神經網絡
  • 4. SVM支援向量機
  • 5. K鄰近
  • 6. 貝葉斯
  • 7. 決策樹
  • 8. 內建學習(Adaboost)
  • 非監督學習
  • 9. 降維—主成分分析
  • 10. 聚類分析

監督學習

1. 線性回歸

梯度下降一進制線性回歸

import numpy as np
import matplotlib.pyplot as plt

# 載入資料
data = np.genfromtxt("data.csv", delimiter=",")
x_data = data[:,0]
y_data = data[:,1]

# 學習率learning rate
lr = 0.0001
# 截距
b = 0 
# 斜率
k = 0 
# 最大疊代次數
epochs = 50

# 最小二乘法
def compute_error(b, k, x_data, y_data):
    totalError = 0
    for i in range(0, len(x_data)):
        totalError += (y_data[i] - (k * x_data[i] + b)) ** 2
    return totalError / float(len(x_data)) / 2.0

def gradient_descent_runner(x_data, y_data, b, k, lr, epochs):
    # 計算總資料量
    m = float(len(x_data))
    # 循環epochs次
    for i in range(epochs):
        b_grad = 0
        k_grad = 0
        # 計算梯度的總和再求平均
        for j in range(0, len(x_data)):
            b_grad += (1/m) * (((k * x_data[j]) + b) - y_data[j])
            k_grad += (1/m) * x_data[j] * (((k * x_data[j]) + b) - y_data[j])
        # 更新b和k
        b = b - (lr * b_grad)
        k = k - (lr * k_grad)
    return b, k

print("Starting b = {0}, k = {1}, error = {2}".format(b, k, compute_error(b, k, x_data, y_data)))
print("Running...")
b, k = gradient_descent_runner(x_data, y_data, b, k, lr, epochs)
print("After {0} iterations b = {1}, k = {2}, error = {3}".format(epochs, b, k, compute_error(b, k, x_data, y_data)))

#畫圖
plt.plot(x_data, y_data, 'b.')
plt.plot(x_data, k*x_data + b, 'r')
plt.show()
           
機器學習十大算法案例

梯度下降法-多元線性回歸

import numpy as np
from numpy import genfromtxt
import matplotlib.pyplot as plt  
from mpl_toolkits.mplot3d import Axes3D  

# 讀入資料 
data = genfromtxt(r"Delivery.csv",delimiter=',')

# 切分資料
x_data = data[:,:-1]
y_data = data[:,-1]

# 學習率learning rate
lr = 0.0001
# 參數
theta0 = 0
theta1 = 0
theta2 = 0
# 最大疊代次數
epochs = 1000

# 最小二乘法
def compute_error(theta0, theta1, theta2, x_data, y_data):
    totalError = 0
    for i in range(0, len(x_data)):
        totalError += (y_data[i] - (theta1 * x_data[i,0] + theta2*x_data[i,1] + theta0)) ** 2
    return totalError / float(len(x_data))

def gradient_descent_runner(x_data, y_data, theta0, theta1, theta2, lr, epochs):
    # 計算總資料量
    m = float(len(x_data))
    # 循環epochs次
    for i in range(epochs):
        theta0_grad = 0
        theta1_grad = 0
        theta2_grad = 0
        # 計算梯度的總和再求平均
        for j in range(0, len(x_data)):
            theta0_grad += (1/m) * ((theta1 * x_data[j,0] + theta2*x_data[j,1] + theta0) - y_data[j])
            theta1_grad += (1/m) * x_data[j,0] * ((theta1 * x_data[j,0] + theta2*x_data[j,1] + theta0) - y_data[j])
            theta2_grad += (1/m) * x_data[j,1] * ((theta1 * x_data[j,0] + theta2*x_data[j,1] + theta0) - y_data[j])
        # 更新b和k
        theta0 = theta0 - (lr*theta0_grad)
        theta1 = theta1 - (lr*theta1_grad)
        theta2 = theta2 - (lr*theta2_grad)
    return theta0, theta1, theta2

print("Starting theta0 = {0}, theta1 = {1}, theta2 = {2}, error = {3}".
      format(theta0, theta1, theta2, compute_error(theta0, theta1, theta2, x_data, y_data)))
print("Running...")
theta0, theta1, theta2 = gradient_descent_runner(x_data, y_data, theta0, theta1, theta2, lr, epochs)
print("After {0} iterations theta0 = {1}, theta1 = {2}, theta2 = {3}, error = {4}".
      format(epochs, theta0, theta1, theta2, compute_error(theta0, theta1, theta2, x_data, y_data)))

ax = plt.figure().add_subplot(111, projection = '3d') 
ax.scatter(x_data[:,0], x_data[:,1], y_data, c = 'r', marker = 'o', s = 100) #點為紅色三角形  
x0 = x_data[:,0]
x1 = x_data[:,1]
# 生成網格矩陣
x0, x1 = np.meshgrid(x0, x1)
z = theta0 + x0*theta1 + x1*theta2
# 畫3D圖
ax.plot_surface(x0, x1, z)
#設定坐标軸  
ax.set_xlabel('Miles')  
ax.set_ylabel('Num of Deliveries')  
ax.set_zlabel('Time')  
  
#顯示圖像  
plt.show()             
機器學習十大算法案例

2.邏輯回歸

邏輯回歸原理與推導

梯度下降法-邏輯回歸

import matplotlib.pyplot as plt
import numpy as np
from sklearn.metrics import classification_report
from sklearn import preprocessing
# 資料是否需要标準化
scale = True

# 載入資料
data = np.genfromtxt("LR-testSet.csv", delimiter=",")
x_data = data[:,:-1]
y_data = data[:,-1]
    
def plot():
    x0 = []
    x1 = []
    y0 = []
    y1 = []
    # 切分不同類别的資料
    for i in range(len(x_data)):
        if y_data[i]==0:
            x0.append(x_data[i,0])
            y0.append(x_data[i,1])
        else:
            x1.append(x_data[i,0])
            y1.append(x_data[i,1])

    # 畫圖
    scatter0 = plt.scatter(x0, y0, c='b', marker='o')
    scatter1 = plt.scatter(x1, y1, c='r', marker='x')
    #畫圖例
    plt.legend(handles=[scatter0,scatter1],labels=['label0','label1'],loc='best')
    
plot()
#檢視資料
plt.show()           
機器學習十大算法案例
# 資料處理,添加偏置項
x_data = data[:,:-1]
y_data = data[:,-1,np.newaxis]

print(np.mat(x_data).shape)
print(np.mat(y_data).shape)
# 給樣本添加偏置項
X_data = np.concatenate((np.ones((100,1)),x_data),axis=1)

def sigmoid(x):
    return 1.0/(1+np.exp(-x))

def cost(xMat, yMat, ws):
    left = np.multiply(yMat, np.log(sigmoid(xMat*ws)))
    right = np.multiply(1 - yMat, np.log(1 - sigmoid(xMat*ws)))
    return np.sum(left + right) / -(len(xMat))

def gradAscent(xArr, yArr):
    
    if scale == True:
        xArr = preprocessing.scale(xArr)
    xMat = np.mat(xArr)
    yMat = np.mat(yArr)
    
    lr = 0.001
    epochs = 10000
    costList = []
    # 計算資料行列數
    # 行代表資料個數,列代表權值個數
    m,n = np.shape(xMat)
    # 初始化權值
    ws = np.mat(np.ones((n,1)))
    
    for i in range(epochs+1):             
        # xMat和weights矩陣相乘
        h = sigmoid(xMat*ws)   
        # 計算誤差
        ws_grad = xMat.T*(h - yMat)/m
        ws = ws - lr*ws_grad 
        
        if i % 50 == 0:
            costList.append(cost(xMat,yMat,ws))
    return ws,costList

# 訓練模型,得到權值和cost值的變化
ws,costList = gradAscent(X_data, y_data)
print(ws)

if scale == False:
    # 畫圖決策邊界
    plot()
    x_test = [[-4],[3]]
    y_test = (-ws[0] - x_test*ws[1])/ws[2]
    plt.plot(x_test, y_test, 'k')
    plt.show()

# 畫圖 loss值的變化
x = np.linspace(0,10000,201)
plt.plot(x, costList, c='r')
plt.title('Train')
plt.xlabel('Epochs')
plt.ylabel('Cost')
plt.show()           
機器學習十大算法案例
# 預測
def predict(x_data, ws):
    if scale == True:
        x_data = preprocessing.scale(x_data)
    xMat = np.mat(x_data)
    ws = np.mat(ws)
    return [1 if x >= 0.5 else 0 for x in sigmoid(xMat*ws)]

predictions = predict(X_data, ws)

print(classification_report(y_data, predictions))           
機器學習十大算法案例

梯度下降法-非線性邏輯回歸

import matplotlib.pyplot as plt
import numpy as np
from sklearn.metrics import classification_report
from sklearn import preprocessing
from sklearn.preprocessing import PolynomialFeatures
# 資料是否需要标準化
scale = False

# 載入資料
data = np.genfromtxt("LR-testSet2.txt", delimiter=",")
x_data = data[:,:-1]
y_data = data[:,-1,np.newaxis]
    
def plot():
    x0 = []
    x1 = []
    y0 = []
    y1 = []
    # 切分不同類别的資料
    for i in range(len(x_data)):
        if y_data[i]==0:
            x0.append(x_data[i,0])
            y0.append(x_data[i,1])
        else:
            x1.append(x_data[i,0])
            y1.append(x_data[i,1])

    # 畫圖
    scatter0 = plt.scatter(x0, y0, c='b', marker='o')
    scatter1 = plt.scatter(x1, y1, c='r', marker='x')
    #畫圖例
    plt.legend(handles=[scatter0,scatter1],labels=['label0','label1'],loc='best')
    
plot()
plt.show()           
機器學習十大算法案例
# 定義多項式回歸,degree的值可以調節多項式的特征
poly_reg  = PolynomialFeatures(degree=3) 
# 特征處理
x_poly = poly_reg.fit_transform(x_data)

def sigmoid(x):
    return 1.0/(1+np.exp(-x))

def cost(xMat, yMat, ws):
    left = np.multiply(yMat, np.log(sigmoid(xMat*ws)))
    right = np.multiply(1 - yMat, np.log(1 - sigmoid(xMat*ws)))
    return np.sum(left + right) / -(len(xMat))

def gradAscent(xArr, yArr):
    
    if scale == True:
        xArr = preprocessing.scale(xArr)
    xMat = np.mat(xArr)
    yMat = np.mat(yArr)
    
    lr = 0.03
    epochs = 50000
    costList = []
    # 計算資料列數,有幾列就有幾個權值
    m,n = np.shape(xMat)
    # 初始化權值
    ws = np.mat(np.ones((n,1)))
    
    for i in range(epochs+1):             
        # xMat和weights矩陣相乘
        h = sigmoid(xMat*ws)   
        # 計算誤差
        ws_grad = xMat.T*(h - yMat)/m
        ws = ws - lr*ws_grad 
        
        if i % 50 == 0:
            costList.append(cost(xMat,yMat,ws))
    return ws,costList

# 訓練模型,得到權值和cost值的變化
ws,costList = gradAscent(x_poly, y_data)
print(ws)


# 擷取資料值所在的範圍
x_min, x_max = x_data[:, 0].min() - 1, x_data[:, 0].max() + 1
y_min, y_max = x_data[:, 1].min() - 1, x_data[:, 1].max() + 1

# 生成網格矩陣
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02),
                     np.arange(y_min, y_max, 0.02))

# np.r_按row來組合array, 
# np.c_按colunm來組合array
# >>> a = np.array([1,2,3])
# >>> b = np.array([5,2,5])
# >>> np.r_[a,b]
# array([1, 2, 3, 5, 2, 5])
# >>> np.c_[a,b]
# array([[1, 5],
#        [2, 2],
#        [3, 5]])
# >>> np.c_[a,[0,0,0],b]
# array([[1, 0, 5],
#        [2, 0, 2],
#        [3, 0, 5]])
z = sigmoid(poly_reg.fit_transform(np.c_[xx.ravel(), yy.ravel()]).dot(np.array(ws)))# ravel與flatten類似,多元資料轉一維。flatten不會改變原始資料,ravel會改變原始資料
for i in range(len(z)):
    if z[i] > 0.5:
        z[i] = 1
    else:
        z[i] = 0
z = z.reshape(xx.shape)

# 等高線圖
cs = plt.contourf(xx, yy, z)
plot() 
plt.show()
           
機器學習十大算法案例
# 預測
def predict(x_data, ws):
#     if scale == True:
#         x_data = preprocessing.scale(x_data)
    xMat = np.mat(x_data)
    ws = np.mat(ws)
    return [1 if x >= 0.5 else 0 for x in sigmoid(xMat*ws)]

predictions = predict(x_poly, ws)

print(classification_report(y_data, predictions))           
機器學習十大算法案例

3.神經網絡

神經網絡

4. SVM支援向量機

SVM-非線性

import matplotlib.pyplot as plt
import numpy as np
from sklearn.metrics import classification_report
from sklearn import svm

# 載入資料
data = np.genfromtxt("LR-testSet2.txt", delimiter=",")
x_data = data[:,:-1]
y_data = data[:,-1]
    
def plot():
    x0 = []
    x1 = []
    y0 = []
    y1 = []
    # 切分不同類别的資料
    for i in range(len(x_data)):
        if y_data[i]==0:
            x0.append(x_data[i,0])
            y0.append(x_data[i,1])
        else:
            x1.append(x_data[i,0])
            y1.append(x_data[i,1])

    # 畫圖
    scatter0 = plt.scatter(x0, y0, c='b', marker='o')
    scatter1 = plt.scatter(x1, y1, c='r', marker='x')
    #畫圖例
    plt.legend(handles=[scatter0,scatter1],labels=['label0','label1'],loc='best')
    
plot()
plt.show()

# fit the model
# C和gamma
model = svm.SVC(kernel='rbf')
model.fit(x_data, y_data)

model.score(x_data,y_data)

# 擷取資料值所在的範圍
x_min, x_max = x_data[:, 0].min() - 1, x_data[:, 0].max() + 1
y_min, y_max = x_data[:, 1].min() - 1, x_data[:, 1].max() + 1

# 生成網格矩陣
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02),
                     np.arange(y_min, y_max, 0.02))

z = model.predict(np.c_[xx.ravel(), yy.ravel()])# ravel與flatten類似,多元資料轉一維。flatten不會改變原始資料,ravel會改變原始資料
z = z.reshape(xx.shape)

# 等高線圖
cs = plt.contourf(xx, yy, z)
plot() 
plt.show()           
機器學習十大算法案例

5. K鄰近

主要過程

機器學習十大算法案例
機器學習十大算法案例
# 導入算法包以及資料集
import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
from tqdm.notebook import tqdm
from sklearn.metrics import classification_report,confusion_matrix
import operator
import random

def knn(x_test, x_data, y_data, k):
    # 計算樣本數量
    x_data_size = x_data.shape[0]
    # 複制x_test
    np.tile(x_test, (x_data_size,1))
    # 計算x_test與每一個樣本的內插補點
    diffMat = np.tile(x_test, (x_data_size,1)) - x_data
    # 計算內插補點的平方
    sqDiffMat = diffMat**2
    # 求和
    sqDistances = sqDiffMat.sum(axis=1)
    # 開方
    distances = sqDistances**0.5
    # 從小到大排序
    sortedDistances = distances.argsort()
    classCount = {}
    for i in range(k):
        # 擷取标簽
        votelabel = y_data[sortedDistances[i]]
        # 統計标簽數量
        classCount[votelabel] = classCount.get(votelabel,0) + 1
    # 根據operator.itemgetter(1)-第1個值對classCount排序,然後再取倒序
    sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1), reverse=True)
    # 擷取數量最多的标簽
    return sortedClassCount[0][0]

# 載入資料
iris = datasets.load_iris()

#打亂資料
data_size = iris.data.shape[0]
index = [i for i in range(data_size)] 
random.shuffle(index)  
iris.data = iris.data[index]
iris.target = iris.target[index]

#切分資料集
test_size = 40
x_train = iris.data[test_size:]
x_test =  iris.data[:test_size]
y_train = iris.target[test_size:]
y_test = iris.target[:test_size]

#分類
predictions = []
for i in tqdm(range(x_test.shape[0])):
    predictions.append(knn(x_test[i], x_train, y_train, 5))
    
#評估
target_names = ['class 0', 'class 1', 'class 2']
print(classification_report(y_test, predictions,target_names=target_names))           
機器學習十大算法案例

6. 貝葉斯

設每個資料樣本用一個n維特征向量來描述n個屬性的值,即:X={x1,x2,…,xn},假定有m個類,分别用C1, C2,…,Cm表示。給定一個未知的資料樣本X(即沒有類标号),若樸素貝葉斯分類法将未知的樣本X配置設定給類Ci,則一定是

P(Ci|X)>P(Cj|X) 1≤j≤m,j≠i

from sklearn.naive_bayes import  GaussianNB
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.preprocessing import LabelEncoder
import pandas as pd
from numpy import *
import operator
#計算高斯分布密度函數的值
def calculate_gaussian_probability(mean, var, x):
    coeff = (1.0 / (math.sqrt((2.0 * math.pi) * var)))
    exponent = math.exp(-(math.pow(x - mean, 2) / (2 * var)))
    c= coeff * exponent
    return c
#計算均值
def averagenum(num):
    nsum = 0
    for i in range(len(num)):
        nsum += num[i]
    return nsum / len(num)
#計算方差
def var(list,avg):
     var1=0
     for i in list:
       var1+=float((i-avg)**2)
     var2=(math.sqrt(var1/(len(list)*1.0)))
     return var2
#樸素貝葉斯分類模型
def Naivebeys(splitData, classset, test):
    classify = []
    for s in range(len(test)):
        c = {}
        for i in classset:
            splitdata = splitData[i]
            num = len(splitdata)
            mu = num + 2
            character = len(splitdata[0])-1    #具體資料集,個數有變
            classp = []
            for j in range(character):
                zi = 1
                if isinstance(splitdata[0][j], (int, float)):
                    numlist=[example[j] for example in splitdata]
                    Mean=averagenum(numlist)
                    Var=var(numlist,Mean)
                    a = calculate_gaussian_probability(Mean, Var, test[s][j])
                else:
                    for l in range(num):
                        if test[s][j] == splitdata[l][j]:
                            zi += 1
                    a=zi/mu
                classp.append(a)
            zhi = 1
            for k in range(character):
                zhi *= classp[k]
            c.setdefault(i, zhi)
        sorta = sorted(c.items(), key=operator.itemgetter(1), reverse=True)
        classify.append(sorta[0][0])
    return classify
#評估
def accuracy(y, y_pred):
    yarr=array(y)
    y_predarr=array(y_pred)
    yarr = yarr.reshape(yarr.shape[0], -1)
    y_predarr = y_predarr.reshape(y_predarr.shape[0], -1)
    return sum(yarr == y_predarr) / len(yarr)
#資料處理
def splitDataset(dataSet):   #按照屬性把資料劃分
    classList = [example[-1] for example in dataSet]
    classSet = set(classList)
    splitDir = {}
    for i in classSet:
        for j in range(len(dataSet)):
            if dataSet[j][-1] == i:
                splitDir.setdefault(i, []).append(dataSet[j])
    return splitDir, classSet
    
open('test.txt')
df = pd.read_csv('test.txt')
class_le = LabelEncoder()
dataSet = df.values[:, :]
dataset_train,dataset_test=train_test_split(dataSet, test_size=0.1)
splitDataset_train, classSet_train = splitDataset(dataset_train)
classSet_test=[example[-1] for example in dataset_test]
y_pred= Naivebeys(splitDataset_train, classSet_train, dataset_test)
accu=accuracy(classSet_test,y_pred)
print("Accuracy:", accu)           

Accuracy: 0.65

7. 決策樹

決策樹的分類模型是樹狀結構,簡單直覺,比較符合人類的了解方式。決策樹分類器的構造不需要任何領域知識和參數設定,适合于探索式知識的發現。由于決策樹分類步驟簡單快速,而且一般來說具有較高的準确率,是以得到了較多的使用。

機器學習十大算法案例
機器學習十大算法案例

資料集介紹

本實驗采用西瓜資料集,根據西瓜的幾種屬性判斷西瓜是否是好瓜。資料集包含17條記錄,資料格式如下:

機器學習十大算法案例

實驗

首先我們引入必要的庫:

import pandas as pd
from math import log2
from pylab import *
import matplotlib.pyplot as plt           

導入資料

讀取csv檔案中的資料記錄并轉為清單

def load_dataset():
    # 資料集檔案所在位置
    path = "./西瓜.csv"
    data = pd.read_csv(path, header=0)
    dataset = []
    for a in data.values:
        dataset.append(list(a))
    # 傳回資料清單
    attribute = list(data.keys())
    # 傳回資料集和每個次元的名稱
    return dataset, attribute
dataset,attribute = load_dataset()
attribute,dataset           
(['色澤', '根蒂', '敲聲', '紋理', '臍部', '觸感', '好瓜'],
 [['青綠', '蜷縮', '濁響', '清晰', '凹陷', '硬滑', '是'],
  ['烏黑', '蜷縮', '沉悶', '清晰', '凹陷', '硬滑', '是'],
  ['烏黑', '蜷縮', '濁響', '清晰', '凹陷', '硬滑', '是'],
  ['青綠', '蜷縮', '沉悶', '清晰', '凹陷', '硬滑', '是'],
  ['淺白', '蜷縮', '濁響', '清晰', '凹陷', '硬滑', '是'],
  ['青綠', '稍蜷', '濁響', '清晰', '稍凹', '軟粘', '是'],
  ['烏黑', '稍蜷', '濁響', '稍糊', '稍凹', '軟粘', '是'],
  ['烏黑', '稍蜷', '濁響', '清晰', '稍凹', '硬滑', '是'],
  ['烏黑', '稍蜷', '沉悶', '稍糊', '稍凹', '硬滑', '否'],
  ['青綠', '硬挺', '清脆', '清晰', '平坦', '軟粘', '否'],
  ['淺白', '硬挺', '清脆', '模糊', '平坦', '硬滑', '否'],
  ['淺白', '蜷縮', '濁響', '模糊', '平坦', '軟粘', '否'],
  ['青綠', '稍蜷', '濁響', '稍糊', '凹陷', '硬滑', '否'],
  ['淺白', '稍蜷', '沉悶', '稍糊', '凹陷', '硬滑', '否'],
  ['烏黑', '稍蜷', '濁響', '清晰', '稍凹', '軟粘', '否'],
  ['淺白', '蜷縮', '濁響', '模糊', '平坦', '硬滑', '否'],
  ['青綠', '蜷縮', '沉悶', '稍糊', '稍凹', '硬滑', '否']])           

計算資訊熵

def calculate_info_entropy(dataset):
    # 記錄樣本數量
    n = len(dataset)
    # 記錄分類屬性數量
    attribute_count = {}
    # 周遊所有執行個體,統計類别出現頻次
    for attribute in dataset:
        # 每一個執行個體最後一列為類别屬性,是以取最後一列
        class_attribute = attribute[-1]
        # 如果目前類标号不在label_count中,則加入該類标号
        if class_attribute not in attribute_count.keys():
            attribute_count[class_attribute] = 0
        # 類标号出現次數加1
        attribute_count[class_attribute] += 1
    info_entropy = 0
    for class_attribute in attribute_count:
        # 計算該類在執行個體中出現的機率
        p = float(attribute_count[class_attribute]) / n
        info_entropy -= p * log2(p)
    return info_entropy           

資料集劃分

def split_dataset(dataset,i,value):
    split_set = []
    for attribute in dataset:
        if attribute[i] == value:
            # 删除該維屬性
            reduce_attribute = attribute[:i]
            reduce_attribute.extend(attribute[i+1:])
            split_set.append(reduce_attribute)
    return split_set           

計算屬性劃分資料集的熵

def calculate_attribute_entropy(dataset,i,values):
    attribute_entropy = 0
    for value in values:
        sub_dataset = split_dataset(dataset,i,value)
        p = len(sub_dataset) / float(len(dataset))
        attribute_entropy += p*calculate_info_entropy(sub_dataset)
    return attribute_entropy           

計算資訊增益

def calculate_info_gain(dataset,info_entropy,i):
    # 第i維特征清單
    attribute = [example[i] for example in dataset]
    # 轉為不重複元素的集合
    values = set(attribute)
    attribute_entropy = calculate_attribute_entropy(dataset,i,values)
    info_gain = info_entropy - attribute_entropy
    return info_gain           

根據資訊增益進行劃分

def split_by_info_gain(dataset):
    # 描述屬性數量
    attribute_num = len(dataset[0]) - 1
    # 整個資料集的資訊熵
    info_entropy = calculate_info_entropy(dataset)
    # 最高的資訊增益
    max_info_gain = 0
    # 最佳劃分次元屬性
    best_attribute = -1
    for i in range(attribute_num):
        info_gain = calculate_info_gain(dataset,info_entropy,i)
        if(info_gain > max_info_gain):
            max_info_gain = info_gain
            best_attribute = i
    return best_attribute           

構造決策樹

def create_tree(dataset,attribute):
    # 類别清單
    class_list = [example[-1] for example in dataset]
    # 統計類别class_list[0]的數量
    if class_list.count(class_list[0]) == len(class_list):
        # 當類别相同則停止劃分
        return class_list[0]
    # 最佳劃分次元對應的索引
    best_attribute = split_by_info_gain(dataset)
    # 最佳劃分次元對應的名稱
    best_attribute_name = attribute[best_attribute]
    tree = {best_attribute_name:{}}
    del(attribute[best_attribute])
    # 查找需要分類的特征子集
    attribute_values = [example[best_attribute] for example in dataset]
    values = set(attribute_values)
    for value in values:
        sub_attribute = attribute[:]
        tree[best_attribute_name][value] =create_tree(split_dataset(dataset,best_attribute,value),sub_attribute)
    return tree
tree = create_tree(dataset,attribute)
tree           
{'紋理': {'清晰': {'根蒂': {'蜷縮': '是',
    '硬挺': '否',
    '稍蜷': {'色澤': {'青綠': '是', '烏黑': {'觸感': {'軟粘': '否', '硬滑': '是'}}}}}},
  '模糊': '否',
  '稍糊': {'觸感': {'軟粘': '是', '硬滑': '否'}}}}           
# 定義劃分屬性節點樣式
attribute_node = dict(boxstyle="round", color='#00B0F0')
# 定義分類屬性節點樣式
class_node = dict(boxstyle="circle", color='#00F064')
# 定義箭頭樣式
arrow = dict(arrowstyle="<-", color='#000000')           
# 計算葉結點數
def get_num_leaf(tree):
    numLeafs = 0
    firstStr = list(tree.keys())[0]
    secondDict = tree[firstStr]
    for key in secondDict.keys():
        if type(secondDict[key]).__name__ == 'dict':
            numLeafs += get_num_leaf(secondDict[key])
        else:
            numLeafs += 1
    return numLeafs           
# 計算樹的層數
def get_depth_tree(tree):
    maxDepth = 0
    firstStr = list(tree.keys())[0]
    secondDict = tree[firstStr]
    for key in secondDict.keys():
        if type(secondDict[key]).__name__ == 'dict':
            thisDepth = 1 + get_depth_tree(secondDict[key])
        else:
            thisDepth = 1
        if thisDepth > maxDepth:
            maxDepth = thisDepth
    return maxDepth           
# 繪制文本框
def plot_text(cntrPt, parentPt, txtString):
    xMid = (parentPt[0] - cntrPt[0]) / 2.0 + cntrPt[0]
    yMid = (parentPt[1] - cntrPt[1]) / 2.0 + cntrPt[1]
    createPlot.ax1.text(xMid, yMid, txtString, va="center", ha="center", rotation=30)           

繪制樹結構

def plotTree(tree, parentPt, nodeTxt):
    numLeafs = get_num_leaf(tree)
    depth = get_depth_tree(tree)
    firstStr = list(tree.keys())[0]
    cntrPt = (plotTree.xOff + (1.0 + float(numLeafs)) / 2.0 / plotTree.totalW, plotTree.yOff)
    plot_text(cntrPt, parentPt, nodeTxt)  #在父子結點間繪制文本框并填充文本資訊
    plotNode(firstStr, cntrPt, parentPt, attribute_node)  #繪制帶箭頭的注釋
    secondDict = tree[firstStr]
    plotTree.yOff = plotTree.yOff - 1.0 / plotTree.totalD
    for key in secondDict.keys():
        if type(secondDict[key]).__name__ == 'dict':
            plotTree(secondDict[key], cntrPt, str(key))
        else:
            plotTree.xOff = plotTree.xOff + 1.0 / plotTree.totalW
            plotNode(secondDict[key], (plotTree.xOff, plotTree.yOff), cntrPt, class_node)
            plot_text((plotTree.xOff, plotTree.yOff), cntrPt, str(key))
    plotTree.yOff = plotTree.yOff + 1.0 / plotTree.totalD           
# 繪制箭頭
def plotNode(nodeTxt, centerPt, parentPt, nodeType):
    createPlot.ax1.annotate(nodeTxt, xy=parentPt, xycoords='axes fraction',
                            xytext=centerPt, textcoords='axes fraction',
                            va="center", ha="center", bbox=nodeType, arrowprops=arrow)           
# 繪圖
def createPlot(tree):
    fig = plt.figure(1, facecolor='white')
    fig.clf()
    axprops = dict(xticks=[], yticks=[])
    createPlot.ax1 = plt.subplot(111, frameon=False, **axprops)
    plotTree.totalW = float(get_num_leaf(tree))
    plotTree.totalD = float(get_depth_tree(tree))
    plotTree.xOff = -0.5 / plotTree.totalW;
    plotTree.yOff = 1.0;
    plotTree(tree, (0.5, 1.0), '')
    plt.show()           
#指定預設字型
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False
# 繪制決策樹
createPlot(tree)           
機器學習十大算法案例

8. 內建學習(Adaboost)

內建學習(Ensemble Learning),就是使用一系列學習器進行學習,并使用某種規則将各個學習器的結果進行整合,進而獲得比單個學習器效果更好的學習效果的一種方法。

內建學習的條件

通過內建學習提高分類器的整體泛化能力有以下兩個條件:

  1. 基分類器之間具有差異性。如果使用的是同一個分類器內建,內建分類器的性能是不會有提升的。
  2. 每個基分類器的分類精度必須大于0.5。如下圖所示,當基分類器精度小于0.5時,随着內建規模的增加,分類內建分類器的分類精度會下降;但是如果基分類器的精度大于0.5時,內建分類器的最終分類精度是趨近于1的。
機器學習十大算法案例

內建學習的兩個關鍵點:

  1. 如何建構具有差異性的基分類器
  2. 如何對基分類器的結果進行整合

建構差異性分類器一般有以下三種方法:

  1. 通過處理資料集生成差異性分類器
  2. 通過處理資料特征建構差異性分類器
  3. 對分類器的處理建構差異性分類器

內建學習常見的三種元算法是Bagging, Boosting和Stacking。Bagging用于提升機器學習算法的穩定性和準确性。Boosting主要用于減少bias(偏差)和variance(方差),是将一個弱分類器轉化為強分類器的算法。Stacking是一種組合多個模型的方法。

機器學習十大算法案例
機器學習十大算法案例

Boosting與AdaBoost算法的訓練

Boosting分類方法,其過程如下所示:

1)先通過對N個訓練資料的學習得到第一個弱分類器h1;

2)将h1分錯的資料和其他的新資料一起構成一個新的有N個訓練資料的樣本,通過對這個樣本的學習得到第二個弱分類器h2;

3)将h1和h2都分錯了的資料加上其他的新資料構成另一個新的有N個訓練資料的樣本,通過對這個樣本的學習得到第三個弱分類器h3;

4)最終經過提升的強分類器h_final=Majority Vote(h1,h2,h3)。即某個資料被分為哪一類要通過h1,h2,h3的多數表決。

上述Boosting算法,存在兩個問題:

①如何調整訓練集,使得在訓練集上訓練弱分類器得以進行。

②如何将訓練得到的各個弱分類器聯合起來形成強分類器。

針對以上兩個問題,AdaBoost算法進行了調整:

①使用權重後選取的訓練資料代替随機選取的訓練資料,這樣将訓練的焦點集中在比較難分的訓練資料上。

②将弱分類器聯合起來時,使用權重的投票機制代替平均投票機制。讓分類效果好的弱分類器具有較大的權重,而分類效果差的分類器具有較小的權重。

import numpy as np
import matplotlib.pyplot as plt
from sklearn import tree
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import make_gaussian_quantiles
from sklearn.metrics import classification_report           
# 生成2維正态分布,生成的資料按分位數分為兩類,500個樣本,2個樣本特征
x1, y1 = make_gaussian_quantiles(n_samples=500, n_features=2,n_classes=2)
# 生成2維正态分布,生成的資料按分位數分為兩類,400個樣本,2個樣本特征均值都為3
x2, y2 = make_gaussian_quantiles(mean=(3, 3), n_samples=500, n_features=2, n_classes=2)
# 将兩組資料合成一組資料
x_data = np.concatenate((x1, x2))
y_data = np.concatenate((y1, - y2 + 1))           
plt.scatter(x_data[:, 0], x_data[:, 1], c=y_data)
plt.show()           
機器學習十大算法案例
# 決策樹模型
model = tree.DecisionTreeClassifier(max_depth=3)

# 輸入資料建立模型
model.fit(x_data, y_data)

# 擷取資料值所在的範圍
x_min, x_max = x_data[:, 0].min() - 1, x_data[:, 0].max() + 1
y_min, y_max = x_data[:, 1].min() - 1, x_data[:, 1].max() + 1

# 生成網格矩陣
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02),
                     np.arange(y_min, y_max, 0.02))

z = model.predict(np.c_[xx.ravel(), yy.ravel()])# ravel與flatten類似,多元資料轉一維。flatten不會改變原始資料,ravel會改變原始資料
z = z.reshape(xx.shape)
# 等高線圖
cs = plt.contourf(xx, yy, z)
# 樣本散點圖
plt.scatter(x_data[:, 0], x_data[:, 1], c=y_data)
plt.show()           
機器學習十大算法案例
# 模型準确率
model.score(x_data,y_data)           
0.777           
# AdaBoost模型
model = AdaBoostClassifier(DecisionTreeClassifier(max_depth=3),n_estimators=10)
# 訓練模型
model.fit(x_data, y_data)

# 擷取資料值所在的範圍
x_min, x_max = x_data[:, 0].min() - 1, x_data[:, 0].max() + 1
y_min, y_max = x_data[:, 1].min() - 1, x_data[:, 1].max() + 1

# 生成網格矩陣
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02),
                     np.arange(y_min, y_max, 0.02))

# 擷取預測值
z = model.predict(np.c_[xx.ravel(), yy.ravel()])
z = z.reshape(xx.shape)
# 等高線圖
cs = plt.contourf(xx, yy, z)
# 樣本散點圖
plt.scatter(x_data[:, 0], x_data[:, 1], c=y_data)
plt.show()
           
機器學習十大算法案例
# 模型準确率
model.score(x_data,y_data)           
機器學習十大算法案例
0.976           

總結一下,組合算法(combiner algorithm)使用所有其他算法的預測作為附加輸入(additional inputs)來訓練得到最終的預測結果。理論上可以表示任何一種組合學習方法(ensemble techniques);實際中,單層的邏輯回歸模型(single-layer logistic regression model)通常被用作組合器(combiner)。

非監督學習

9. 降維—主成分分析

機器學習十大算法案例
import numpy as np
import matplotlib.pyplot as plt           
# 載入資料
data = np.genfromtxt("data.csv", delimiter=",")
x_data = data[:,0]
y_data = data[:,1]
plt.scatter(x_data,y_data)
plt.show()
print(x_data.shape)           
機器學習十大算法案例
# 資料中心化
def zeroMean(dataMat):
    # 按列求平均,即各個特征的平均
    meanVal = np.mean(dataMat, axis=0) 
    newData = dataMat - meanVal
    return newData, meanVal           
newData,meanVal=zeroMean(data)  
# np.cov用于求協方差矩陣,參數rowvar=0說明資料一行代表一個樣本
covMat = np.cov(newData, rowvar=0)           
# 協方差矩陣
covMat           
array([[ 94.99190951, 125.62024804],
       [125.62024804, 277.49520751]])           
# np.linalg.eig求矩陣的特征值和特征向量
eigVals, eigVects = np.linalg.eig(np.mat(covMat))           
# 特征值
eigVals           
array([ 30.97826888, 341.50884814])           
# 特征向量
eigVects           
matrix([[-0.89098665, -0.45402951],
        [ 0.45402951, -0.89098665]])           
# 對特征值從小到大排序
eigValIndice = np.argsort(eigVals)
eigValIndice           
array([0, 1], dtype=int64)           
top = 1
# 最大的n個特征值的下标
n_eigValIndice = eigValIndice[-1:-(top+1):-1]           
n_eigValIndice           
array([1], dtype=int64)           
# 最大的n個特征值對應的特征向量
n_eigVect = eigVects[:,n_eigValIndice]
n_eigVect           
matrix([[-0.45402951],
        [-0.89098665]])           
# 低維特征空間的資料
lowDDataMat = newData*n_eigVect
lowDDataMat           
# 利用低緯度資料來重構資料
reconMat = (lowDDataMat*n_eigVect.T) + meanVal
reconMat           
# 載入資料
data = np.genfromtxt("data.csv", delimiter=",")
x_data = data[:,0]
y_data = data[:,1]
plt.scatter(x_data,y_data)

# 重構的資料
x_data = np.array(reconMat)[:,0]
y_data = np.array(reconMat)[:,1]
plt.scatter(x_data,y_data,c='r')
plt.show()           
機器學習十大算法案例

10. 聚類分析

續集等下篇文章!

素材來源于網絡,若有侵權聯系删除!

繼續閱讀