【机器学习】LDA(多类别降维)—— python3 实现方案

 参考博文:https://www.cnblogs.com/pinard/p/6244265.html

http://www.cnblogs.com/jerrylead/archive/2011/04/21/2024384.html

首先感谢两位博主。研究了一天,其他都好说,在类内散列矩阵卡了不少时间。 先看的第一篇博文,把Sw理解成了协方差矩阵,结果在写算法的时候,用np.cov()计算,测试数据,总是不对。后来看到第二篇博文,才恍然大悟,这个Sw是协方差矩阵的分子部分,叫做散列矩阵。至于推导,建议看第一篇博文,即把目标函数转换成广义瑞利商函数,利用瑞利商函数的性质,直接得出目标基向量就是目标矩阵((Sw的逆矩阵).dot(Sb))的特征向量。第二篇文章不明说瑞利商矩阵,而是对同样的表达式用拉格朗日乘子法求极值的方法,得到了相同的结果。推导过程稍显复杂。   把这个过程包装瑞利商函数去理解LDA,要简单许多!

import numpy as np
import pandas as pd

class LDA():
    '''
    LDA(线性判别分析)降维算法
    '''
    def lda(self, dataSet, k):
        '''
        对于包含类别标签的多类别数据集(n+1)*m, 使降维至(k+1)*m数据集
        :param dataSet: 包含类别标签的多类别数据集,(n+1)*m
        :param k: k<n
        :return: 降维后的数据集 (k+1)*m
        '''
        dataMat = np.mat(dataSet)  # 转换成矩阵
        data_X = dataMat[: -1, :]  # 获取不含标签的数据集
        n = dataSet.shape[0] - 1  # 获取原维度
        labels = set(list(dataSet[-1, :]))  # 所有类别标签的集合
        sw = np.mat(np.zeros((n, n)))  # 定义类内散列矩阵(注意不是协方差矩阵!区别在于没有分母)
        sb = np.mat(np.zeros((n, n)))  # 定义类间散列矩阵
        mean = np.mean(data_X, axis=1)  # 计算原始各维度的均值
        
        for label in labels:
            x = data_X[:, np.nonzero(dataSet[-1, :] == label)[0]]  # 取出类别标签等于目标类别的数据集(不含标签)
            sw += (x - np.mean(x, axis=1)).dot((x - np.mean(x, axis=1)).T)  # 根据公式计算sw
            sb += x.shape[1] * (np.mean(x, axis=1) - mean).dot((np.mean(x, axis=1) - mean).T)  # 根据公式计算sb
            
        u, s, vt = np.linalg.svd(np.linalg.inv(sw).dot(sb))  # 对目标矩阵 (sw的逆矩阵).dot(sb) 做奇异值分解
        lowDDataMat = u[:k, :].dot(data_X)  # u的前k行,是前k个最大的特征值 对应的 特征向量,利用左乘基向量的方法,降维
        lowDDataMat = np.array(lowDDataMat)  # 转换成数据形式
        lowDDataMat = np.vstack((lowDDataMat, dataSet[-1, :]))  # 添加最初的类别行
        
        return lowDDataMat  # 返回降维后的数据集



# 以下是测试数据
dataSet = pd.read_csv('data/iris.txt', names=['x1', 'x2', 'x3', 'x4', 'label'])
def labels(x):
    '''
    源数据的标签列是字符串,利用apply把字符串转换成数字
    '''
    if x == 'Iris-setosa':
        return 1
    elif x == 'Iris-versicolor':
        return 2
    else:
        return 3
dataSet['label'] = dataSet['label'].apply(lambda x: labels(x))
dataSet = np.array(dataSet).T  # 把数据集变成 (n+1)*m

lda = LDA()
lowD = lda.lda(dataSet, 2)
print(lowD)

猜你喜欢

转载自blog.csdn.net/zhenghaitian/article/details/81291462