【机器学习】西瓜书习题3.5Python编程实现线性判别分析,并给出西瓜数据集 3.0α上的结果

3.5 编程实现线性判别分析,并给出西瓜数据集 3.0α上的结果

参考代码
结合自己的理解,添加注释。

代码

  1. 导入相关的库
import numpy as np
import pandas as pd
import matplotlib
from matplotlib import pyplot as plt
  1. 导入数据,进行数据处理和特征工程
    得到数据集 D = { ( x i , y i ) } i = 1 m , y i ∈ { 0 , 1 } D=\{ (x_i,y_i) \}_{i=1}^m, y_i \in \{0,1\} D={(xi,yi)}i=1m,yi{0,1}
# 1.数据处理,特征工程
data_path = 'watermelon3_0_Ch.csv'
data = pd.read_csv(data_path).values
# 按照数据集3.0α,强制转换数据类型
X = data[:,7:9].astype(float)
y = data[:,9]
y[y=='是'] = 1
y[y=='否'] = 0
y = y.astype(int)
  1. 计算西瓜书60页中的 X i 、 μ i 、 Σ i X_{i}、\mu_i、\Sigma_i XiμiΣi
# 将X的数据根据label值分成X0和X1
pos = y == 1
neg = y == 0
X0 = X[neg]
X1 = X[pos]

# 计算u0,u1 keepdims保持原数据维数
u0 = X0.mean(0, keepdims=True)
u1 = X1.mean(0, keepdims=True)

# 计算sigma0,sigma1
sigma0 = np.dot((X0-u0).T,X0-u0)
sigma1 = np.dot((X1-u1).T,X1-u1)
  1. 根据式3.33计算类内散度矩阵
    S w = Σ 0 + Σ 1 = ∑ x ∈ X 0 ( x − μ 0 ) ( x − μ 0 ) T + ∑ x ∈ X 1 ( x − μ 1 ) ( x − μ 1 ) T S_w=\Sigma_0+\Sigma_1=\sum_{x\in X_{0}}(x-\mu_0)(x-\mu_0)^T+\sum_{x\in X_{1}}(x-\mu_1)(x-\mu_1)^T Sw=Σ0+Σ1=xX0(xμ0)(xμ0)T+xX1(xμ1)(xμ1)T
    根据式3.39计算 w w w
    w = S w − 1 ( μ 0 − μ 1 ) w=S_w^{-1}(\mu_0-\mu_1) w=Sw1(μ0μ1)
# 计算类内散度矩阵 with-class scatter matrix
sw = sigma0 + sigma1

# numpy.linalg.inv() 函数来计算矩阵的逆
w = np.dot(np.linalg.inv(sw),(u0-u1).T).reshape(1,-1)
  1. 画出样本点和得到的直线
fig, ax = plt.subplots()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.spines['left'].set_position(('data', 0))
ax.spines['bottom'].set_position(('data', 0))

plt.scatter(X1[:, 0], X1[:, 1], c='k', marker='o', label='good')
plt.scatter(X0[:, 0], X0[:, 1], c='r', marker='x', label='bad')

plt.xlabel('密度', labelpad=1)
plt.ylabel('含糖量')
plt.legend(loc='upper right')

x_tmp = np.linspace(-0.05, 0.15)
y_tmp = x_tmp * w[0, 1] / w[0, 0]
plt.plot(x_tmp, y_tmp, '#808080', linewidth=1)

得到下图
在这里插入图片描述

  1. 计算每个样本点在直线上的投影
    计算的理解参考这篇文章
# 求w这个向量的 单位向量 wu
# np.linalg.norm()默认求2 范数,表示向量中各个元素平方和 的 1/2 次方,L2 范数又称 Euclidean 范数或者 Frobenius 范数。
wu = w / np.linalg.norm(w)

# 正负样本点
# 求负样本的投影点,并连线
X0_project = np.dot(X0, np.dot(wu.T, wu))
plt.scatter(X0_project[:, 0], X0_project[:, 1], c='r', s=15)
for i in range(X0.shape[0]):
    plt.plot([X0[i, 0], X0_project[i, 0]], [X0[i, 1], X0_project[i, 1]], '--r', linewidth=1)

# 求正样本的投影点,并连线
X1_project = np.dot(X1, np.dot(wu.T, wu))
plt.scatter(X1_project[:, 0], X1_project[:, 1], c='k', s=15)
for i in range(X1.shape[0]):
    plt.plot([X1[i, 0], X1_project[i, 0]], [X1[i, 1], X1_project[i, 1]], '--k', linewidth=1)

得到下图
在这里插入图片描述

将上述代码封装成类,如下:

class LDA(object):

    def fit(self, X_, y_, plot_=False):
        pos = y_ == 1
        neg = y_ == 0
        X0 = X_[neg]
        X1 = X_[pos]

        u0 = X0.mean(0, keepdims=True)  # (1, n)
        u1 = X1.mean(0, keepdims=True)

        sw = np.dot((X0 - u0).T, X0 - u0) + np.dot((X1 - u1).T, X1 - u1)
        w = np.dot(np.linalg.inv(sw), (u0 - u1).T).reshape(1, -1)  # (1, n)

        if plot_:
            # 设置字体为楷体
            plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
            plt.rcParams['font.sans-serif'] = ['KaiTi']
            fig, ax = plt.subplots()
            ax.spines['right'].set_color('none')
            ax.spines['top'].set_color('none')
            ax.spines['left'].set_position(('data', 0))
            ax.spines['bottom'].set_position(('data', 0))

            plt.scatter(X1[:, 0], X1[:, 1], c='k', marker='o', label='good')
            plt.scatter(X0[:, 0], X0[:, 1], c='r', marker='x', label='bad')

            plt.xlabel('密度', labelpad=1)
            plt.ylabel('含糖量')
            plt.legend(loc='upper right')

            x_tmp = np.linspace(-0.05, 0.15)
            y_tmp = x_tmp * w[0, 1] / w[0, 0]
            plt.plot(x_tmp, y_tmp, '#808080', linewidth=1)

            wu = w / np.linalg.norm(w)

            # 正负样板店
            X0_project = np.dot(X0, np.dot(wu.T, wu))
            plt.scatter(X0_project[:, 0], X0_project[:, 1], c='r', s=15)
            for i in range(X0.shape[0]):
                plt.plot([X0[i, 0], X0_project[i, 0]], [X0[i, 1], X0_project[i, 1]], '--r', linewidth=1)

            X1_project = np.dot(X1, np.dot(wu.T, wu))
            plt.scatter(X1_project[:, 0], X1_project[:, 1], c='k', s=15)
            for i in range(X1.shape[0]):
                plt.plot([X1[i, 0], X1_project[i, 0]], [X1[i, 1], X1_project[i, 1]], '--k', linewidth=1)

            # 中心点的投影
            u0_project = np.dot(u0, np.dot(wu.T, wu))
            plt.scatter(u0_project[:, 0], u0_project[:, 1], c='#FF4500', s=60)
            u1_project = np.dot(u1, np.dot(wu.T, wu))
            plt.scatter(u1_project[:, 0], u1_project[:, 1], c='#696969', s=60)

            ax.annotate(r'u0 投影点',
                        xy=(u0_project[:, 0], u0_project[:, 1]),
                        xytext=(u0_project[:, 0] - 0.2, u0_project[:, 1] - 0.1),
                        size=13,
                        va="center", ha="left",
                        arrowprops=dict(arrowstyle="->",
                                        color="k",
                                        )
                        )

            ax.annotate(r'u1 投影点',
                        xy=(u1_project[:, 0], u1_project[:, 1]),
                        xytext=(u1_project[:, 0] - 0.1, u1_project[:, 1] + 0.1),
                        size=13,
                        va="center", ha="left",
                        arrowprops=dict(arrowstyle="->",
                                        color="k",
                                        )
                        )
            plt.axis("equal")  # 两坐标轴的单位刻度长度保存一致
            plt.show()

        self.w = w
        self.u0 = u0
        self.u1 = u1
        return self

    def predict(self, X):
        project = np.dot(X, self.w.T)

        wu0 = np.dot(self.w, self.u0.T)
        wu1 = np.dot(self.w, self.u1.T)

        return (np.abs(project - wu1) < np.abs(project - wu0)).astype(int)
  • 5
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 线性判别分析(Linear Discriminant Analysis,简称LDA)是一种常用的模式识别和机器学习算法,它通过将样本投影到一个低维度线性空间中,以实现最大化类间距离并最小化类内距离的目标,从而实现分类任务。 要实现线性判别分析,可以按照以下步骤进行: 步骤1:导入所需的库和模块,如numpy、pandas等。 步骤2:读取西瓜数据集3.0,并将其分为特征和标签两部分。 步骤3:对每一类样本计算其均值向量。 步骤4:计算类内散度矩阵Sw和类间散度矩阵Sb。 步骤5:计算Sw的逆矩阵与Sb的乘积。 步骤6:对Sb*Sw的特征值和特征向量进行排序。 步骤7:选择最大的k个特征值对应的特征向量作为投影向量。 步骤8:将样本投影到投影向量所张成的低维空间中。 步骤9:利用投影后的样本进行新的分类任务。 以下是使用Python实现线性判别分析的代码示例: ```python import numpy as np import pandas as pd # 步骤2:读取西瓜数据集3.0 watermelon_data = pd.read_csv('watermelon_data.csv') # 假设数据集保存为watermelon_data.csv features = watermelon_data.iloc[:, :-1].values # 特征 labels = watermelon_data.iloc[:, -1].values # 标签 # 步骤3:计算均值向量 mean_vectors = [] # 存储每个类别的均值向量 for label in np.unique(labels): mean_vectors.append(np.mean(features[labels == label], axis=0)) # 步骤4:计算类内散度矩阵Sw和类间散度矩阵Sb Sb = np.zeros((features.shape[1], features.shape[1])) # 类间散度矩阵 Sw = np.zeros((features.shape[1], features.shape[1])) # 类内散度矩阵 overall_mean = np.mean(features, axis=0) # 全局均值向量 for label, mean_vector in zip(np.unique(labels), mean_vectors): n = features[labels == label].shape[0] # 类别样本数量 class_scatter_matrix = np.cov(features[labels == label].T, bias=True) # 类内散度矩阵 Sw += class_scatter_matrix mean_diff = (mean_vector - overall_mean).reshape(features.shape[1], 1) Sb += n * mean_diff.dot(mean_diff.T) # 步骤5:计算Sw的逆矩阵与Sb的乘积 eigen_values, eigen_vectors = np.linalg.eig(np.linalg.inv(Sw).dot(Sb)) # 步骤6:对特征值和特征向量进行排序 idx = np.argsort(np.abs(eigen_values))[::-1] eigen_values = eigen_values[idx] eigen_vectors = eigen_vectors[:, idx] # 步骤7:选择投影向量 k = 2 # 假设选择两个投影向量 projection_matrix = eigen_vectors[:, :k] # 步骤8:样本投影 projected_data = features.dot(projection_matrix) # 步骤9:进行新的分类任务 # 这一步根据具体需求选择分类算法进行分类 # 例如,使用K近邻算法进行分类 from sklearn.neighbors import KNeighborsClassifier X_train, X_test, y_train, y_test = train_test_split(projected_data, labels, test_size=0.3, random_state=42) knn = KNeighborsClassifier() knn.fit(X_train, y_train) predictions = knn.predict(X_test) ``` 以上代码示例实现线性判别分析,并通过投影将样本从原始高维空间投影到仅有两个特征的低维空间中,最后使用K近邻算法进行分类任务。根据具体需求,可以选择其他分类算法进行分类任务。 ### 回答2: 线性判别分析(Linear Discriminant Analysis,LDA)是一种经典的机器学习算法,用于降维和分类任务。它基于统计学原理,通过最大化类之间的可分离性和最小化类内的可分离性,找到一个最佳的投影方向,将数据映射到一维或更低维的空间。 下面是使用Python实现线性判别分析,并应用于西瓜数据集3.0的步骤: 1. 载入所需的Python库,例如`numpy`用于数组操作,`pandas`用于数据处理,`matplotlib`用于数据可视化。 ``` import numpy as np import pandas as pd import matplotlib.pyplot as plt ``` 2. 载入西瓜数据集3.0,可以使用`pandas`的`read_csv`函数读取csv文件,并将特征和标签分别存储到矩阵`X`和向量`y`中。 ``` data = pd.read_csv('watermelon_dataset.csv') X = data.iloc[:, 1:-1].values y = data.iloc[:, -1].values ``` 3. 计算各类别的均值向量和类内散度矩阵。 ``` def calculate_mean_vectors(X, y): class_labels = np.unique(y) mean_vectors = [] for label in class_labels: mean_vectors.append(np.mean(X[y==label], axis=0)) return mean_vectors def calculate_within_class_scatter_matrix(X, y): class_labels = np.unique(y) num_features = X.shape[1] S_W = np.zeros((num_features, num_features)) mean_vectors = calculate_mean_vectors(X, y) for label, mean_vector in zip(class_labels, mean_vectors): class_scatter_matrix = np.zeros((num_features, num_features)) for sample in X[y==label]: sample, mean_vector = sample.reshape(num_features, 1), mean_vector.reshape(num_features, 1) class_scatter_matrix += (sample - mean_vector).dot((sample - mean_vector).T) S_W += class_scatter_matrix return S_W ``` 4. 计算类间散度矩阵。 ``` def calculate_between_class_scatter_matrix(X, y): class_labels = np.unique(y) num_features = X.shape[1] overall_mean = np.mean(X, axis=0).reshape(num_features, 1) S_B = np.zeros((num_features, num_features)) mean_vectors = calculate_mean_vectors(X, y) for i, mean_vector in enumerate(mean_vectors): n = X[y==class_labels[i]].shape[0] mean_vector = mean_vector.reshape(num_features, 1) S_B += n * (mean_vector - overall_mean).dot((mean_vector - overall_mean).T) return S_B ``` 5. 计算特征向量和特征值,并选择投影方向。 ``` def select_projection_direction(X, y, num_dimensions): S_W = calculate_within_class_scatter_matrix(X, y) S_B = calculate_between_class_scatter_matrix(X, y) eigen_values, eigen_vectors = np.linalg.eig(np.linalg.inv(S_W).dot(S_B)) eigen_pairs = [(np.abs(eigen_values[i]), eigen_vectors[:,i]) for i in range(len(eigen_values))] eigen_pairs.sort(key=lambda x: x[0], reverse=True) projection_matrix = np.hstack([eigen_pairs[i][1].reshape(num_dimensions, 1) for i in range(num_dimensions)]) return projection_matrix ``` 6. 将数据映射到选择的投影方向,观察分类结果。 ``` def project_data(X, projection_matrix): return X.dot(projection_matrix) projection_matrix = select_projection_direction(X, y, 1) X_prime = project_data(X, projection_matrix) plt.scatter(X_prime[y=='是'], np.zeros(len(X_prime[y=='是'])), color='r', label='是') plt.scatter(X_prime[y=='否'], np.zeros(len(X_prime[y=='否'])), color='b', label='否') plt.xlabel('投影向量') plt.legend() plt.show() ``` 通过以上步骤,我们就可以实现线性判别分析,并且使用选择的投影方向将西瓜数据集3.0映射到一维空间。可视化结果显示了在投影空间中的分类结果,红色点表示‘是’类别,蓝色点表示‘否’类别。 ### 回答3: 编程实现线性判别分析是一种常用的降维和分类算法,可以有效地提取高维数据的主要特征,并进行分类预测。下面给出一个简单的 Python 实现示例,使用西瓜数据集3.0进行线性判别分析。 首先,我们需要导入必要的库和模块: ``` import numpy as np import pandas as pd from sklearn.discriminant_analysis import LinearDiscriminantAnalysis ``` 接下来,读取西瓜数据集3.0,并对其进行预处理: ``` data = pd.read_csv("watermelon_3.csv") X = data.iloc[:, 1:3].values # 特征矩阵 y = data.iloc[:, -1].values # 标签向量 ``` 然后,我们使用 LinearDiscriminantAnalysis 类进行线性判别分析: ``` lda = LinearDiscriminantAnalysis(n_components=1) # 指定降维后的维度为1 X_lda = lda.fit_transform(X, y) # 进行降维 ``` 最后,我们可以输出降维后的特征矩阵,并查看分类结果: ``` print("降维后的特征矩阵:") print(X_lda) print("预测分类结果:") pred = lda.predict(X) for i in range(len(X)): print(f"样本 {i+1}: 预测为 {pred[i]}") ``` 这样,我们就完成了使用线性判别分析西瓜数据集3.0进行降维和分类的编程实现。当然,具体的实现还会涉及到一些数据预处理、模型评估等其他步骤,但以上示例可以作为一个简单的起点。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个甜甜的大橙子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值