机器学习头歌(第二部分)

发布于:2025-02-10 ⋅ 阅读:(49) ⋅ 点赞:(0)

一、朴素贝叶斯简述

任务描述
本关任务:了解朴素贝叶斯的基本概念,完成右侧窗口内的单项选择题。

相关知识
概率的解释
现在我们站在两个统计学派的角度来深入理解什么是概率。

经典统计学认为概率表述的是一件事发生的频率,概率定义为频率的极限,或者说这叫作客观概率。如抛硬币试验时通过大量试验,发现结果基本是一半正面一半反面,因此认为正反面的概率都是 0.5,这体现了经典统计学的思想,概率是基于大量实验而得到。

但现实中有些事情我们没办法进行试验,例如今天下雨的概率 50%,某城市下个月发生地震的概率 30%,这些我们无法通过试验来验证。

贝叶斯框架下的概率理论虽然认可经典统计学的概率定义,但它同时把概率理解为人对随机事件发生可能性的一种信念,他认为概率是个人的主观概念,即主观概率,表明我们对某个事物发生的相信程度。两种对于概率的认识区分了经典统计学派(也称频率学派)和贝叶斯学派。

贝叶斯学派与经典统计学派的争论
仅仅基于总体信息和样本信息进行统计推断的统计学理论与方法称为经典统计学。经典统计学认为只要进行足够多次的试验,就能推断出隐藏在数据背后的规律,人们完全可以通过直接研究这些样本来推断总体的分布规律 。 

贝叶斯学派认为任意未知量 θ 都可以看作一个随机变量, 可以用一个概率分布去描述 θ 的未知状况,并且这个概率最初可以通过主观经验设置。频率学派对此无法接受,他们认为参数应该是一个确定的值而不应该具有随机性。

在人们认识事物不全面的情况下,贝叶斯方法是一种很好的利用经验帮助做出更合理判断的方法,至少把概率与统计的研究与应用范围扩大到无法进行大量重复实验的问题中。当然主观概率的确定不是随意的,而是要求当事人对所考察的事件有透彻的了解和丰富的经验,甚至是这一行的专家。

贝叶斯学派和经典统计学派没有好坏之分,关键在于统计方法是否适合该问题的应用场景。数据科学不是偏袒某一方, 而是为了找出工作的最佳工具,能否解决实际问题是衡量统计方法优劣的标准,以往的实践证明两个统计学派在各自的应用领域的表现都不错,各有其适用的范围。

贝叶斯方法
贝叶斯方法是以贝叶斯原理为基础,使用概率统计的知识对样本数据集进行分类。由于其有着坚实的数学基础,贝叶斯分类算法的误判率是很低的。贝叶斯方法的特点是结合先验概率和后验概率,即避免了只使用先验概率的主观偏见,也避免了单独使用样本信息的过拟合现象。贝叶斯分类算法在数据集较大的情况下表现出较高的准确率,同时算法本身也比较简单。

朴素贝叶斯算法
朴素贝叶斯算法是应用最为广泛的分类算法之一。朴素贝叶斯方法是在贝叶斯算法的基础上进行了相应的简化,即假定给定目标值时属性之间相互条件独立。也就是说没有哪个属性变量对于决策结果来说占有着较大的比重,也没有哪个属性变量对于决策结果占有着较小的比重。虽然这个简化方式在一定程度上降低了贝叶斯分类算法的分类效果,但是在实际的应用场景中,极大地简化了贝叶斯方法的复杂性。 

优点:朴素贝叶斯算法假设了数据集属性之间是相互独立的,因此算法的逻辑性十分简单,并且算法较为稳定,当数据呈现不同的特点时,朴素贝叶斯的分类性能不会有太大的差异。当数据集属性之间的关系相对比较独立时,朴素贝叶斯分类算法会有较好的效果。

缺点:属性独立性的条件同时也是朴素贝叶斯分类器的不足之处。数据集属性的独立性在很多情况下是很难满足的,因为数据集的属性之间往往都存在着相互关联,如果在分类过程中出现这种问题,会导致分类的效果大大降低。

二、朴素贝叶斯算法

 

import numpy as np
class NaiveBayesClassifier(object):
    def __init__(self):
        '''
        self.label_prob表示每种类别在数据中出现的概率
        例如,{0:0.333, 1:0.667}表示数据中类别0出现的概率为0.333,类别1的概率为0.667
        '''
        self.label_prob = {}
        '''
        self.condition_prob表示每种类别确定的条件下各个特征出现的概率
        例如训练数据集中的特征为 [[2, 1, 1],
                              [1, 2, 2],
                              [2, 2, 2],
                              [2, 1, 2],
                              [1, 2, 3]]
        标签为[1, 0, 1, 0, 1]
        那么当标签为0时第0列的值为1的概率为0.5,值为2的概率为0.5;
        当标签为0时第1列的值为1的概率为0.5,值为2的概率为0.5;
        当标签为0时第2列的值为1的概率为0,值为2的概率为1,值为3的概率为0;
        当标签为1时第0列的值为1的概率为0.333,值为2的概率为0.666;
        当标签为1时第1列的值为1的概率为0.333,值为2的概率为0.666;
        当标签为1时第2列的值为1的概率为0.333,值为2的概率为0.333,值为3的概率为0.333;
        因此self.label_prob的值如下:     
        {
            0:{
                0:{
                    1:0.5
                    2:0.5
                }
                1:{
                    1:0.5
                    2:0.5
                }
                2:{
                    1:0
                    2:1
                    3:0
                }
            }
            1:
            {
                0:{
                    1:0.333
                    2:0.666
                }
                1:{
                    1:0.333
                    2:0.666
                }
                2:{
                    1:0.333
                    2:0.333
                    3:0.333
                }
            }
        }
        '''
        self.condition_prob = {}
    def fit(self, feature, label):
        '''
        对模型进行训练,需要将各种概率分别保存在self.label_prob和self.condition_prob中
        :param feature: 训练数据集所有特征组成的ndarray
        :param label:训练数据集中所有标签组成的ndarray
        :return: 无返回
        '''
 
 
        #********* Begin *********#
        row_num = len(feature)
        col_num = len(feature[0])
        for c in label:
            if c in self.label_prob:
                self.label_prob[c] += 1
            else:
                self.label_prob[c] = 1
        for key in self.label_prob.keys():
            self.label_prob[key] /= row_num
            self.condition_prob[key] = {}
            for i in range(col_num):
                self.condition_prob[key][i] = {}
                for k in np.unique(feature[:,i], axis=0):
                    self.condition_prob[key][i][k] = 0
        for i in range(len(feature)):
            for j in range(len(feature[i])):
                if feature[i][j] in self.condition_prob[label[i]]:
                    self.condition_prob[label[i]][j][feature[i][j]] += 1
                else:
                    self.condition_prob[label[i]][j][feature[i][j]] = 1
        for label_key in self.condition_prob.keys():
            for k in self.condition_prob[label_key].keys():
                total = 0
                for v in self.condition_prob[label_key][k].values():
                    total += v
                for kk in self.condition_prob[label_key][k].keys():
                    self.condition_prob[label_key][k][kk] /= total
        #********* End *********#
 
 
    def predict(self, feature):
        '''
        对数据进行预测,返回预测结果
        :param feature:测试数据集所有特征组成的ndarray
        :return:
        '''
        # ********* Begin *********#
        result = []
        for i,f in enumerate(feature):
            prob=np.zeros(len(self.label_prob.keys()))
            i1 = 0
            for label,label_prob in self.label_prob.items():
                prob[i1] = label_prob
                for  j  in range(len(feature[0])):
                    prob[i1] *= self.condition_prob[label][j][f[j]]
                i1 += 1
            result.append(list(self.label_prob.keys())[np.argmax(prob)])
        return np.array(result)
 
        #********* End *********#

三、朴素贝叶斯模型

利用sklearn构建朴素贝叶斯模型

import numpy as np
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.model_selection import train_test_split
import numpy as np
import pandas as pd
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import roc_auc_score
from sklearn.metrics import classification_report
 
data_path ='/data/bigfiles/5297379b-7cd5-4239-bcac-e2d361753393'
df = pd.read_csv(data_path, delimiter='\t',header=None)
######Begin ######
 
# 将label编码
df[0] = df[0].replace(to_replace=['spam', 'ham'], value=[0, 1])
 
# 完成数据划分及词向量的转化
X = df[1].values
y = df[0].values
X_train_raw,X_test_raw,y_train,y_test=train_test_split(X,y,random_state = 0)
vectorizer = TfidfVectorizer()
x_train = vectorizer.fit_transform(X_train_raw)
x_test = vectorizer.transform(X_test_raw) 
 
# 构建模型及训练
model = MultinomialNB()
model.fit(x_train,y_train)
 
#对于测试集x_test进行预测
x_pre_test=model.predict(x_test)
x_pro_test = model.predict_proba(x_test)
#计算验证集的auc值,参数为预测值和概率估计
auc=roc_auc_score(y_test, x_pro_test[:, 1])
###### End ######
print("auc的值:{}".format(auc))

四、机器学习-DBSCAN

1.DBSCAN算法的基本概念

2.DBSCAN算法流程

# encoding=utf8
import numpy as np
import random
from copy import copy
from collections import deque


# 寻找eps邻域内的点
def findNeighbor(j, X, eps):
    return {p for p in range(X.shape[0]) if np.linalg.norm(X[j] - X[p]) <= eps}


# dbscan算法
def dbscan(X, eps, min_Pts):
    """
    input:X(ndarray):样本数据
          eps(float):eps邻域半径
          min_Pts(int):eps邻域内最少点个数
    output:cluster(list):聚类结果
    """
    # ********* Begin *********#

    # 初始化核心对象集合
    core_objects = {i for i in range(len(X)) if len(findNeighbor(i, X, eps)) >= min_Pts}

    # 初始化聚类簇数
    k = 0

    # 初始化未访问的样本集合
    not_visited = set(range(len(X)))

    # 初始化聚类结果
    cluster = np.zeros(len(X))

    while len(core_objects) != 0:
        old_not_visited = copy(not_visited)
        # 初始化聚类簇队列
        o = random.choice(list(core_objects))
        queue = deque()
        queue.append(o)
        not_visited.remove(o)

        while len(queue) != 0:
            q = queue.popleft()
            neighbor_list = findNeighbor(q, X, eps)
            if len(neighbor_list) >= min_Pts:
                # 寻找在邻域中并没被访问过的点
                delta = neighbor_list & not_visited
                for element in delta:
                    queue.append(element)
                    not_visited.remove(element)

        k += 1
        this_class = old_not_visited - not_visited
        cluster[list(this_class)] = k
        core_objects = core_objects - this_class

    # ********* End *********#
    return cluster

3.sklearn中的DBSCAN

# encoding=utf8
from sklearn.cluster import DBSCAN


def data_cluster(data):
    """
    input: data(ndarray) :数据
    output: result(ndarray):聚类结果
    """
    # ********* Begin *********#
    dbscan = DBSCAN(eps=0.5, min_samples=10)
    result = dbscan.fit_predict(data)
    return result
    # ********* End *********#

五、机器学习-AGNES

1.距离的计算

import numpy as np
def calc_min_dist(cluster1, cluster2):
    '''
    计算簇间最小距离
    :param cluster1:簇1中的样本数据,类型为ndarray
    :param cluster2:簇2中的样本数据,类型为ndarray
    :return:簇1与簇2之间的最小距离
    '''
    #********* Begin *********#
    min_dist = np.inf
    for i in range(len(cluster1)):
        for j in range(len(cluster2)):
            dist = np.sqrt(np.sum(np.square(cluster1[i] - cluster2[j])))
            if dist < min_dist:
                min_dist = dist
    return min_dist
    #********* End *********#
def calc_max_dist(cluster1, cluster2):
    '''
    计算簇间最大距离
    :param cluster1:簇1中的样本数据,类型为ndarray
    :param cluster2:簇2中的样本数据,类型为ndarray
    :return:簇1与簇2之间的最大距离
    '''
    #********* Begin *********#
    max_dist = 0
    for i in range(len(cluster1)):
        for j in range(len(cluster2)):
            dist = np.sqrt(np.sum(np.square(cluster1[i] - cluster2[j])))
            if dist > max_dist:
                max_dist = dist
    return max_dist
    #********* End *********#
def calc_avg_dist(cluster1, cluster2):
    '''
    计算簇间平均距离
    :param cluster1:簇1中的样本数据,类型为ndarray
    :param cluster2:簇2中的样本数据,类型为ndarray
    :return:簇1与簇2之间的平均距离
    '''
    #********* Begin *********#
    total_sample = len(cluster1)*len(cluster2)
    total_dist = 0
    for i in range(len(cluster1)):
        for j in range(len(cluster2)):
            total_dist += np.sqrt(np.sum(np.square(cluster1[i] - cluster2[j])))
    return total_dist/total_sample
    #********* End *********#

2.AGNES算法流程



import numpy as np
def AGNES(feature, k):
    '''
    AGNES聚类并返回聚类结果
    假设数据集为`[1, 2], [10, 11], [1, 3]],那么聚类结果可能为`[[1, 2], [1, 3]], [[10, 11]]]
    :param feature:训练数据集所有特征组成的ndarray
    :param k:表示想要将数据聚成`k`类,类型为`int`
    :return:聚类结果
    '''
    #********* Begin *********#
    # 找到距离最小的下标
    def find_Min(M):
        min = np.inf
        x = 0;
        y = 0
        for i in range(len(M)):
            for j in range(len(M[i])):
                if i != j and M[i][j] < min:
                    min = M[i][j];
                    x = i;
                    y = j
        return (x, y, min)
    #计算簇间最大距离
    def calc_max_dist(cluster1, cluster2):
        max_dist = 0
        for i in range(len(cluster1)):
            for j in range(len(cluster2)):
                dist = np.sqrt(np.sum(np.square(cluster1[i] - cluster2[j])))
                if dist > max_dist:
                    max_dist = dist
        return max_dist
    #初始化C和M
    C = []
    M = []
    for i in feature:
        Ci = []
        Ci.append(i)
        C.append(Ci)
    for i in C:
        Mi = []
        for j in C:
            Mi.append(calc_max_dist(i, j))
        M.append(Mi)
    q = len(feature)
    #合并更新
    while q > k:
        x, y, min = find_Min(M)
        C[x].extend(C[y])
        C.pop(y)
        M = []
        for i in C:
            Mi = []
            for j in C:
                Mi.append(calc_max_dist(i, j))
            M.append(Mi)
        q -= 1
    return C
    #********* End *********#

3.红酒聚类

#encoding=utf8
from sklearn.cluster import AgglomerativeClustering
 
def Agglomerative_cluster(data):
    '''
    对红酒数据进行聚类
    :param data: 数据集,类型为ndarray
    :return: 聚类结果,类型为ndarray
    '''
 
    #********* Begin *********#
    from sklearn.preprocessing import StandardScaler
    scaler = StandardScaler()
    data = scaler.fit_transform(data)
    agnes = AgglomerativeClustering(n_clusters=3)
    result = agnes.fit_predict(data)
    return result
 
    #********* End *********#

六、机器学习-高斯混合聚类

1.高斯混合聚类的核心思想

2.实现高斯混合聚类

import numpy as np
from scipy.stats import multivariate_normal

def multiGaussian(x, mu, sigma):
    return 1 / ((2 * np.pi) * pow(np.linalg.det(sigma), 0.5)) * np.exp(-0.5 * (x - mu).dot(np.linalg.pinv(sigma)).dot((x - mu).T))

def computeGamma(X, mu, sigma, alpha, multiGaussian):
    n_samples = X.shape[0]
    n_clusters = len(alpha)
    gamma = np.zeros((n_samples, n_clusters))
    p = np.zeros(n_clusters)
    g = np.zeros(n_clusters)
    for i in range(n_samples):
        for j in range(n_clusters):
            p[j] = multiGaussian(X[i], mu[j], sigma[j])
            g[j] = alpha[j] * p[j]
        for k in range(n_clusters):
            gamma[i, k] = g[k] / np.sum(g)
    return gamma

class GMM(object):
    def __init__(self, n_components, max_iter=100):
        '''
        构造函数
        :param n_components: 想要划分成几个簇,类型为int
        :param max_iter: EM的最大迭代次数
        '''
        self.n_components = n_components
        self.ITER = max_iter

    def fit(self, train_data):
        '''
        训练,将模型参数分别保存至self.alpha,self.mu,self.sigma中
        :param train_data: 训练数据集,类型为ndarray
        :return: 无返回
        '''
        n_samples, n_features = train_data.shape
        
        mu = train_data[np.random.choice(range(n_samples), self.n_components)]
        alpha = np.ones(self.n_components) / self.n_components
        sigma = np.full((self.n_components, n_features, n_features), np.diag(np.full(n_features, 0.1)))

        for i in range(self.ITER):
            gamma = computeGamma(train_data, mu, sigma, alpha, multiGaussian)
            alpha = np.sum(gamma, axis=0) / n_samples

            for i in range(self.n_components):
                mu[i] = np.sum(train_data * gamma[:, i].reshape((n_samples, 1)), axis=0) / np.sum(gamma, axis=0)[i]
                sigma[i] = 0
                for j in range(n_samples):
                    sigma[i] += (train_data[j].reshape((1, n_features)) - mu[i]).T.dot(
                        (train_data[j] - mu[i]).reshape((1, n_features))) * gamma[j, i]
                sigma[i] = sigma[i] / np.sum(gamma, axis=0)[i]

        self.mu = mu
        self.sigma = sigma
        self.alpha = alpha

    def predict(self, test_data):
        '''
        预测,根据训练好的模型参数将test_data进行划分。
        注意:划分的标签的取值范围为[0,self.n_components-1],即若self.n_components为3,则划分的标签的可能取值为0,1,2。
        :param test_data: 测试集数据,类型为ndarray
        :return: 划分结果,类型为你ndarray
        '''

        pred = computeGamma(test_data, self.mu, self.sigma, self.alpha, multiGaussian)
        results = np.argmax(pred, axis=1)
        return results

3.图像分割

from PIL import Image
import numpy as np
from sklearn.mixture import GaussianMixture
 
#******** Begin *********#
im = Image.open('./step3/image/test.jpg')
img = np.array(im)
img_reshape = img.reshape(-1,3)
gmm = GaussianMixture(n_components=3,covariance_type='full')
pred = gmm.fit_predict(img_reshape)
img_reshape[pred == 0, :] = [255,255,0]
img_reshape[pred==1,:] = [0,0,255]
img_reshape[pred==2,:] = [0,255,0]
im = Image.fromarray(img.astype('uint8'))
im.save('./step3/dump/result.jpg')
#********* End *********#

七、机器学习-多维缩放

1.多维缩放

# -*- coding: utf-8 -*-
import numpy as np
def mds(data,d):
    '''
    input:data(ndarray):待降维数据
          d(int):降维后数据维数
    output:Z(ndarray):降维后的数据
    '''
    #********* Begin *********#
    #计算dist2,dist2i,dist2j,dist2ij
    m,n = data.shape
    dist =np.zeros((m,m))
    disti = np.zeros(m)
    distj = np.zeros(m)
    B = np.zeros((m,m))
    for i in range(m):
        dist[i] = np.sum(np.square(data[i]-data),axis=1).reshape(1,m)
    for i in range(m):
        disti[i] = np.mean(dist[i,:])
        distj[i] = np.mean(dist[:,i])
    distij = np.mean(dist)
    #计算B
    for i in range(m):
        for j in range(m):            
            B[i,j] = -0.5*(dist[i,j] - disti[i] - distj[j] + distij)
    #矩阵分解得到特征值与特征向量
    lamda,V=np.linalg.eigh(B)
    #计算Z
    index=np.argsort(-lamda)[:d]
    diag_lamda=np.sqrt(np.diag(-np.sort(-lamda)[:d]))
    V_selected=V[:,index]
    Z=V_selected.dot(diag_lamda)
    #********* End *********#
    return Z 

2.sklearn中的多维缩放

# -*- coding: utf-8 -*-
from sklearn.manifold import MDS
def mds(data,d):
    '''
    input:data(ndarray):待降维数据
          d(int):降维后数据维度
    output:Z(ndarray):降维后数据
    '''
    #********* Begin *********#
    mds = MDS(d)
    Z = mds.fit_transform(data)
    #********* End *********#
    return Z

八、机器学习-等度量映射

1.等度量映射

# -*- coding: utf-8 -*-
import numpy as np
 
def isomap(data, d, k, Max=10000):
    '''
    input:
        data(ndarray): 待降维数据
        d(int): 降维后数据维数
        k(int): 最近的k个样本
        Max(int): 表示无穷大
    output:
        Z(ndarray): 降维后的数据
    '''
    # 计算dist2, dist2i, dist2j, dist2ij
    m, n = data.shape
    dist = np.ones((m, m)) * Max
    disti = np.zeros(m)
    distj = np.zeros(m)
    B = np.zeros((m, m))
    
    for i in range(m):
        distance = np.power(np.tile(data[i], (m, 1)) - data, 2).sum(axis=1)
        index = np.argsort(distance)
        q = index[:k]
        for l in q:
            dist[i][l] = np.power(data[i] - data[l], 2).sum()
 
    for i in range(m):
        disti[i] = np.mean(dist[i, :])
        distj[i] = np.mean(dist[:, i])
        
    distij = np.mean(dist)
    
    # 计算B
    for i in range(m):
        for j in range(m):
            B[i, j] = -0.5 * (dist[i, j] - disti[i] - distj[j] + distij)
    
    # 矩阵分解得到特征值与特征向量
    lamda, V = np.linalg.eigh(B)
    
    # 计算Z
    index = np.argsort(-lamda)[:d]
    diag_lamda = np.sqrt(np.diag(-np.sort(-lamda)[:d]))
    V_selected = V[:, index]
    Z = V_selected.dot(diag_lamda)
    
    return Z
 

2.sklearn中的等度量映射

# -*- coding: utf-8 -*-
from sklearn.manifold import Isomap
 
def isomap(data,d,k):
    '''
    input:data(ndarray):待降维数据
          d(int):降维后数据维度
          k(int):最近的k个样本
    output:Z(ndarray):降维后数据
    '''
    #********* Begin *********#
    isomap = Isomap(n_components=d, n_neighbors=k)
    Z = isomap.fit_transform(data)
    #********* End *********#
    return Z

九、机器学习-局部线性嵌入

1.局部线性嵌入

#encoding=utf8 
import numpy as np

def lle(data,d,k):
    from scipy.spatial.distance import pdist, squareform
    '''
    input:data(ndarray):待降维数据,行数为样本个数,列数为特征数
          d(int):降维后数据维数
          k(int):最近的k个样本
    output:Z(ndarray):降维后的数据
    '''
    #********* Begin *********#
    def get_k_maxtria(D, k):
        dist = pdist(D, 'euclidean')    
        dist = squareform(dist)         
        m = dist.shape[0]
        k_idx = np.zeros([m, k])
        for i in range(m):
            topk = np.argsort(dist[i])[1:k + 1]  
            k_idx[i] = k_idx[i] + topk
        return k_idx.astype(np.int32)
    def get_w(D, knear_idx, k):
        m = D.shape[0]
        w = np.zeros([m, k])
        I = np.ones((k, 1))
        for i in range(m):
            Q_x = D[knear_idx[i]]       
            xi = D[i]              
            xi = np.tile(xi, (k,1))   
            C = np.dot((xi - Q_x), (xi-Q_x).T)    
            C = C +np.eye(k)*(1e-3)*np.trace(C)
            C_inv = np.linalg.pinv(C)
            w[i,:] = np.sum(C_inv, axis=0)/np.sum(C_inv)    
        return w
    m = data.shape[0]
    knear_idx = get_k_maxtria(data, k)
    w = get_w(data, knear_idx, k)            
    W = np.zeros([m,m])
    for i in range(m):
        for j in range(k):
            idx = knear_idx[i, j]
            W[i, idx] = w[i, j]
    I = np.eye(m)               
    M = np.dot((I-W).T, (I-W))   
    A, U = np.linalg.eig(M)             
    top_A_idx = np.argsort(A)[1:d+1]    
    Z = U[:,top_A_idx]   
    return Z    

2.sklearn中的局部线性嵌入

# -*- coding: utf-8 -*-
from sklearn.manifold import LocallyLinearEmbedding
def lle(data,d,k):
    '''
    input:data(ndarray):待降维数据
          d(int):降维后数据维度
          k(int):邻域内样本数
    output:Z(ndarray):降维后数据
    '''
    #********* Begin *********#
    lle = LocallyLinearEmbedding(n_components=d, n_neighbors=k, random_state=0)
    Z = lle.fit_transform(data)
    #********* End *********#
    return Z