本文记录了在人工智能自动组方实习中所进行的机器学习分类算法的实现和个人总结,如果有哪位小伙伴在做相关内容,可以发邮件([email protected])我们一起交流学习
以下为该项目的系列文章
工作记录
萤火虫算法
FCM模糊C聚类
爬虫及python代码
数据预处理
中医分类及python代码
数据预处理python代码
基于字典的最大正向匹配
基于欧式距离的方剂推荐
基于方剂相似性的方剂推荐
GitHub地址
#PCA 主成分分析
在进行分类算法时,我们将病症转化为onehot向量之后因为维度太大(2000维病症)计算效果很差,所以采用了PCA进行降低维度,但降低维度之后效果也不是很好,然后才使用了下面的数据预处理环节,建立了病症同义词词典和降低了病症集维度。关于PCA的内容详情请见我的另一篇博文PCA主成分分析
#机器学习分类算法
在分类算法模块我们将对方剂数据集中的主治字段的病症作为特征输入,将我们人工标注的该方剂的治疗证型作为标签。
我们将病症转化为onehot向量,通过分类算法得到该病症集合的所对应的证型,在通过该证型找到治疗该证型的药方,从而实现根据病症得到药方的功能。
在这里我们使用的分类方法是经典的机器学习分类方法,对于每一个机器学习算法,具体详情请看对应的每一篇具体博文:
##SKlearn调包实现分类算法
import pandas as pd
import re
from sklearn.naive_bayes import GaussianNB
from sklearn import metrics
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.multiclass import OneVsRestClassifier
from sklearn import svm
from sklearn import tree
from sklearn.decomposition import PCA
import numpy as np
def getdict(f_dict):
a = f_dict.readlines()
dict = []
for i in range(len(a)):
b = a[i].strip().split('\t')
dict.append(b)
# print(dict)
return dict
def get_onehotandlabels(dict,f_excel):
onehot = []
labels = []
for i in range(f_excel.shape[0]):
a = [0] * len(dict)
for j in range(len(dict)):
for t in range(len(dict[j])):
try:
if dict[j][t] in f_excel['主治'].loc[i]:
a[j] = 1
except TypeError:
pass
onehot.append(a)
labels.append(str(f_excel['证型'].loc[i]))
# print(onehot)
# print(labels)
return onehot,labels
"""高斯朴素贝叶斯"""
def NB(X_train, X_test, y_train, y_test):
gnb = GaussianNB()
gnb.fit(X_train, y_train)
y_pred = gnb.predict(X_test)
print("Gaussian Naive Bayes model accuracy(in %):", metrics.accuracy_score(y_test, y_pred) * 100)
"""KNN"""
def KNN(X_train, X_test, y_train, y_test):
knn = KNeighborsClassifier() # 定义一个knn分类器对象
knn.fit(X_train, y_train) # 调用该对象的训练方法,主要接收两个参数:训练数据集及其样本标签
y_predict = knn.predict(X_test) # 调用该对象的测试方法,主要接收一个参数:测试数据集
probility = knn.predict_proba(X_test) # 计算各测试样本基于概率的预测
score = knn.score(X_test, y_test)
# 调用该对象的打分方法,计算出准确率
# 输出测试的结果
# 输出原始测试数据集的正确标签,以方便对比
print('KNN_Accuracy:', score)
# 输出准确率计算结果
"""逻辑回归"""
def LR(X_train, X_test, y_train, y_test):
cls = LogisticRegression() # 把数据交给模型训练
cls.fit(X_train, y_train) # 选择模型
cls = LogisticRegression(multi_class='multinomial', solver='lbfgs')
# 把数据交给模型训练
cls.fit(X_train, y_train)
# print("Coefficients:%s, intercept %s" % (cls.coef_, cls.intercept_))
y_predict = cls.predict(X_test)
# print("Residual sum of squares: %.2f" % np.mean((y_predict - y_test) ** 2))
print('logistic回归_Score: %.2f' % cls.score(X_test, y_test))
"""SVM"""
def SVM(X_train, X_test, y_train, y_test):
model = OneVsRestClassifier(svm.SVC(kernel='linear'))
clf = model.fit(X_train, y_train)
y_result = clf.predict(X_test)
print("SVM_score:", clf.score(X_test, y_test))
"""CART"""
def CART(X_train, X_test, y_train, y_test):
clf = tree.DecisionTreeClassifier()
clf = clf.fit(X_train, y_train)
y_predict = clf.predict(X_test)
matchCount = 0
for i in range(len(y_predict)):
if y_predict[i] == y_test[i]:
matchCount += 1
accuracy = float(matchCount / len(y_predict))
print('Testing_CART :Testing completed.Accuracy: %.3f%%' % (accuracy * 100))
"""PCA"""
def pca(onehot_matrix):
x = np.array(onehot_matrix)
print(x.shape)
pca = PCA(n_components=0.9)
pca.fit(x)
#print(pca.explained_variance_ratio_)
#print(pca.explained_variance_)
#print(pca.n_components_)
x_pca = pca.transform(x)
#print(x_pca.shape)
return x
if __name__ =="__main__":
f_dict = open(r'病症同义词.txt', 'r',encoding='utf-8')
#病症同义词字典是我们在数据预处理阶段建立的同义词集
#其形式为:关于同一个症状的不同描述我们将其放在同一行上,默认第一个词作为标准词(标准词可以根据所需要进行调整)
#中医方剂数据集是我们进行分类算法的数据,其中“主治”字段的“症状”属性转化为onehot向量作为输入,人工标注的证型作为输出标签
f_excel = pd.read_excel(r'中医方剂数据_主治字段的病症作为特征_证型做为标签.xlsx')
dict = getdict(f_dict)
onehot, labels = get_onehotandlabels(dict, f_excel)
X_train, X_test, y_train, y_test = train_test_split(onehot, labels, test_size=0.9, random_state=0)
CART(X_train, X_test, y_train, y_test)
#算法总结
因为中病症数据集维度太大,分类算是将数据的病症转为onehot向量作为输入,所以首先需要降低病症集维度。在前期我们采用了建立同义词字典的方式将所有的病症归类在了352个语义中,将病症数据集维度从1043降低到了352。在进行分类之后准确率仍然很低,我们采用了先通过病症集分类到妇科病类型标签,在从该类型标签下分类到具体证型标签。这样做之后准确率稍有提高但仍不能满足我们的要求,最终我们放弃了分类算法转到了聚类算法。
分类算法的缺点如下:
1、相对于标签而言,,数据量太少,特征数目太多。例如:带下病药方有279条,而带下病标注的证型有12个,病症集中有261个同义词。
2、真实的中医病症集应该是一个病症集对应多个证型标签,在我们处理中只保留了一个标签,这样可能会造成分类的误差。
3、在标注中,很多药方无法确定其证型,就保留为空标签,损失了一部分数据。
4、在标签标注时,我们参考的主要是《中医妇科学》上关于证型的症状描述,因为不是中医专业人员,有部分标签可能标注错误。
聚类算法的优点如下:
1、要在人工标注证型,节省大量时间
2、有监督的人工标注需要先验的中医知识,且每个病症集只能得到一个证型不符合中医相关知识
3、通过无监督聚类得到对应的证型正确率要比人工标注准确性高。
4、通过聚类得到病症集对应证型,更加容易得到其对应药方及加减方