中药材的鉴别

中药材的鉴别,第1张

中药材的鉴别 数据预处理 导入数据:

先导入数据处理与可视化

#加载包
import numpy as np
import pandas as pd
from plotnine import*

import matplotlib as mpl
import matplotlib.pyplot as plt
#中文显示问题
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# notebook嵌入图片
%matplotlib inline
# 提高分辨率
%config InlineBackend.figure_format='retina'
# 忽略警告
import warnings
warnings.filterwarnings('ignore')

导入附件一数据

# 导入csv文件
data = pd.read_csv("C:/Users/lenovo/Desktop/data1.csv", encoding="utf-8", header = None)
# 打印数据前5行
data.head(5)

绘制各波段下药材吸光度折线图

# 绘制图形观察
plt.figure(dpi = 600,figsize = (24,8))
for i in range(1,data.shape[0]):
    plt.plot(data.iloc[0,:],data.iloc[i,:])
plt.title("红外光谱曲线图",fontsize=20)  # 图像标题
plt.xlabel("波数",fontsize=20)  # X轴标题
plt.ylabel("吸光度",fontsize=20)  # Y轴标题
plt.tick_params(labelsize=16)
plt.savefig("红外光谱图.png")

观察到有3条红外光谱偏离,假定其为异常样本,将其剔除

data_yc = data.iloc[1:,1]
# 排序
yc_id = data_yc.sort_values(ascending=False)
# 将在652波段吸光度最高的三个样本删除
data.drop(yc_id[:3].index, inplace=True)

再次绘制各波段下药材吸光度折线图

# 绘制图形观察
plt.figure(dpi = 600,figsize = (24,8))
for i in range(1,data.shape[0]):
    plt.plot(data.iloc[0,:],data.iloc[i,:])
plt.title("红外光谱曲线图",fontsize=20)  # 图像标题
plt.xlabel("波数",fontsize=20)  # X轴标题
plt.ylabel("吸光度",fontsize=20)  # Y轴标题
plt.tick_params(labelsize=16)
plt.savefig("红外光谱图(剔除异常).png")

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3hoGy2u1-1651724311938)(D:\Jupyter%20Notebook\红外光谱图(剔除异常)].png)

数据处理到此结束

问题一 问题分析
  • 题目要求根据附件1中红外光谱数据,研究不同种类药材的特性和差异性,并鉴别药材种类。由于题目没给出已知的药材种类,所以这是一个聚类问题。

  • 中红外光谱中波数为特征,但波数太多,特征高达3348个,如不进行特征降维将极大程度影响模型训练所需时间。

  • 根据聚类中心与各类药材中红外光谱数据研究特性和差异性,可以从平均值,各波段平均极差等统计数值进行探究。

特征降维

降维算法大致分为线性降维与非线性降维,比较流行的算法有两种,即:PCA(主成分分析)、KPAC(基于核函数的主成分分析),但由于KPAC调参是在有监督学习情况下使用机器学习算法进行检验的,在这里并不合适,所以选择PCA进行降维。

这里保证新特征保留以往特征95%的信息:

from sklearn.decomposition import PCA   #主成分分析法

#PCA方法降维
#保持90%的信息
pca = PCA(n_components=0.95)
pca_95 = pca.fit_transform(data.iloc[1:,:])
pca_95.shape

降维后特征数为2,共422个样本

查看降维后特征的信息量占原特征信息量的比例:

pca.explained_variance_ratio_
pca.explained_variance_ratio_.sum()

输出0.96086,说明新特征的信息量占原特征信息量的96.086%

新特征可视化:

plt.figure(dpi = 600,figsize = (5,3))
plt.scatter(pca_95[:,0],pca_95[:,1])

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BWuk4wqh-1651724311940)(D:\Jupyter%20Notebook\新特征散点图.png)]

聚类

常用的聚类方法有两种,分别是K-Means与DBSCAN,其中K-Means需要调整集群数迭代次数。DBSCAN需要调整学习率叶子数

K-Means聚类

迭代次数使用默认值100次即可,最关键的参数是集群数,这里采用两种方法结合判断,即:手肘法轮廓分数法

假定集群数在2~7类间,以2为初始值,1为步长进行网格搜索,并绘制手肘图与轮廓分数图

# K-Means聚类
# 惯性值
SSE = []
# 轮廓分数
SIL = []
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
for i in range(2,8):
    kmeans = KMeans(n_clusters = i,n_init = 100)
    y_pred = kmeans.fit_predict(pca_95)
    SSE.append([i,kmeans.inertia_])
    SIL.append([i,silhouette_score(pca_95,kmeans.labels_)])
# 将list转为DataFrame
sse = pd.DataFrame(SSE,columns = ["k","SSE"])
sil = pd.DataFrame(SIL,columns = ["k","SIL"])

手肘法:随着聚类数k的增大,样本划分会更加精细,每个簇的聚合程度会逐渐提高,误差平方与SSE也会逐渐变小。并且当k小于真实聚类数时,在增加k所得到的聚合程度回报会迅速变小,所以SSE的下降幅度会骤减,然后随着k值的继续增大二趋于平缓。值越小越好

# 绘制手肘图
plt.figure(dpi = 600,figsize = (5,3))
plt.plot(sse["k"],sse["SSE"])
plt.scatter(sse["k"],sse["SSE"])
plt.savefig("手肘图.png")

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ttsJo2H7-1651724311943)(D:\Jupyter%20Notebook\手肘图.png)]

可以看到当 k = 3 k = 3 k=3时SSE数值已经有了放缓的趋势,这里是一个转折点,当然凭这一张图理由并不是那么的充分。

轮廓分数法:实例的轮廓系数等于(b-a)/max(a,b),其中a是与同一集群中其他实例的平均距离,b是平均最近集群距离。值越大越好

# 轮廓值判断
plt.figure(dpi = 600,figsize = (5,3))
plt.plot(sil["k"],sil["SIL"])
plt.scatter(sil["k"],sil["SIL"])
plt.savefig("轮廓分数图.png")

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7Jt9PLtS-1651724311945)(D:\Jupyter%20Notebook\轮廓分数图.png)]

可以看到当 k = 2 k = 2 k=2 k = 3 k = 3 k=3时,结果都是可以接受的,若 k k k值继续增大效果将不再理想。

综上所述, k k k值应当选取3,这样得到的K_Means模型效果才是最优的。

使用最优参训练模型,并输出分类各样本分类:

kmeans = KMeans(n_clusters = 3,n_init = 100)
y_pred = kmeans.fit_predict(pca_90)
y_pred

输出质心:

# 输出中心点
kmeans.cluster_centers_
DBSCAN聚类

由于在DBSCAN聚类算法中,学习率与叶子数是相互影响的,所以要将它们一起调整,学习率以0.001为初始值,0.001为步长;叶子数以1为初始值,1为步长进行网格搜索,搜索停止的目标是,标签中没有 − 1 -1 1(算法认为此样本为异常),标签种类为 3 3 3种。

# DBSCAN聚类
from sklearn.cluster import DBSCAN
count = 0
e = 0
for i in np.arange(0.0001,1,0.0001):
    for j in np.arange(1,400,1):
        db = DBSCAN(eps=i, min_samples = j)
        db.fit(pca_90)
        labels = db.labels_
        count = labels[labels == -1].shape[0]
        if count == 0 & np.unique(labels).shape[0] == 3:
            e = i
            break
e

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/799344.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-06
下一篇 2022-05-06

发表评论

登录后才能评论

评论列表(0条)

保存