题目:第3题,请根据附件 2 所提供的部分食物寒热属性(分为三类:性平、性温热、性凉寒),对附 件 1 中的食物进行分类,判断这些食物是属于性平、性温热或性凉寒中哪一类,并说明你分类 的合理性;
思路:如果食品寒热属性与其成分之间都是线性关系,那么可以考虑采用多元 Logistic回归
模型来分类,后续查看其模型预测准确率,若准确率高,则进一步进行线性检验,若较低。则采用BP神经网络模型,它适用于非线性映射关系,最后通过对比两个模型训练集的准确性来衡量其优劣性能。
多元逻辑回归模型介绍:
它可以划分 3个二元 logistic regression模型
对于二元 logistic regression,如食物是否寒性模型的数学公式如下:
通过sigmoid函数将线性的值映射到0-1之间,再离散化变为0和1。通过此方法可最后得到回归系数,这里的回归系数要用发生比率来解释。
我们最后计算得出模型的准确率为 60.14%,食物 K-S曲线示意图如下,KS值低于0.4,效果一般。
代码如下:这里注意把附件二的文本放在txt文件上读取。
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn import preprocessing
from sklearn import metrics
import re
from sklearn import model_selection
from sklearn import linear_model
# 自定义绘制ks曲线的函数
def plot_ks(y_test, y_score, positive_flag):
# 对y_test重新设置索引
y_test.index = np.arange(len(y_test))
# 构建目标数据集
target_data = pd.DataFrame({'y_test':y_test, 'y_score':y_score})
# 按y_score降序排列
target_data.sort_values(by = 'y_score', ascending = False, inplace = True)
# 自定义分位点
cuts = np.arange(0.1,1,0.1)
# 计算各分位点对应的Score值
index = len(target_data.y_score)*cuts
scores = np.array(target_data.y_score)[index.astype('int')]
# 根据不同的Score值,计算Sensitivity和Specificity
Sensitivity = []
Specificity = []
for score in scores:
# 正例覆盖样本数量与实际正例样本量
positive_recall = target_data.loc[(target_data.y_test == positive_flag) & (target_data.y_score>score),:].shape[0]
positive = sum(target_data.y_test == positive_flag)
# 负例覆盖样本数量与实际负例样本量
negative_recall = target_data.loc[(target_data.y_test != positive_flag) & (target_data.y_score<=score),:].shape[0]
negative = sum(target_data.y_test != positive_flag)
Sensitivity.append(positive_recall/positive)
Specificity.append(negative_recall/negative)
# 构建绘图数据
plot_data = pd.DataFrame({'cuts':cuts,'y1':1-np.array(Specificity),'y2':np.array(Sensitivity),
'ks':np.array(Sensitivity)-(1-np.array(Specificity))})
# 寻找Sensitivity和1-Specificity之差的最大值索引
max_ks_index = np.argmax(plot_data.ks)
plt.plot([0]+cuts.tolist()+[1], [0]+plot_data.y1.tolist()+[1], label = '1-Specificity')
plt.plot([0]+cuts.tolist()+[1], [0]+plot_data.y2.tolist()+[1], label = 'Sensitivity')
# 添加参考线
plt.vlines(plot_data.cuts[max_ks_index], ymin = plot_data.y1[max_ks_index],
ymax = plot_data.y2[max_ks_index], linestyles = '--')
# 添加文本信息
plt.text(x = plot_data.cuts[max_ks_index]+0.01,
y = plot_data.y1[max_ks_index]+plot_data.ks[max_ks_index]/2,
s = 'KS= %.2f' %plot_data.ks[max_ks_index])
# 显示图例
plt.legend()
# 显示图形
plt.show()
# 读取数据
df1 = pd.read_excel(r'食物成分表.xlsx', index_col=0).reset_index(drop=True)
df3 = df1.drop(['可食部分(%)'], axis=1)
scaler = preprocessing.MinMaxScaler()#标准化
df33 = scaler.fit_transform(df3[df3.columns[1:17]]) #训练和导出结果
df33 = pd.DataFrame(df33, columns=df3.columns[1:17])#转换格式
df3 = pd.concat([df3['名 称'], df33], axis=1)#标准化后数据
df3['catef'] = ''#添加列,分类
print(df3.head()) # 查看前5条数据
#自定义函数,根据附件2分类标注数据
def TagCategory(datastr,f,tap):
for line in f:
a = re.split('。|、|;|(|)|\n| ', line)#分割字符串保存到a
a = [x.strip() for x in a if x.strip() != '']#去除空字符串
for ss in a:
index0 = datastr.str.find(ss)#找到则返回所要找字符串在指定字符串位置,没有则返回-1
ind = index0[index0.values != -1].index#不为-1的即表示有
df3['catef'][ind] = tap#标注
mingcheng = df3['名 称'].astype(str)#提取名称所在列
f0 = open(r'性平.txt', encoding='utf-8')
f1 = open(r'性凉寒.txt', encoding='utf-8')
f2 = open(r'性温热.txt', encoding='utf-8')
TagCategory(mingcheng,f0,0)#性平标为0
TagCategory(mingcheng,f1,1)#性凉寒标为1
TagCategory(mingcheng,f2,2)#性温热标为2
print(df3.head())#查看前5行
#标注后,数据分为已知分类数据集和未知数据集
NonNulldf = df3[(df3['catef'].notnull()) & (df3['catef'] != "")]
IsNulldf = df3[(df3['catef'] == "")]
#已知数据集的处理
predictors = NonNulldf.columns[1:17]# 提取出所有自变量名称
X = NonNulldf.loc[:,predictors]# 构建自变量矩阵
y = pd.to_numeric(NonNulldf['catef'])# 提取因变量
# 将数据集拆分为训练集和测试集
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, random_state = 1234)
# 利用训练集建模
sklearn_logistic = linear_model.LogisticRegression(multi_class='multinomial',solver="newton-cg", max_iter=100000)
sklearn_logistic.fit(X_train, y_train)
# 返回模型的各个参数
print(np.around(sklearn_logistic.intercept_,decimals=2), np.around(sklearn_logistic.coef_,decimals=2))
# 模型预测
sklearn_predict = sklearn_logistic.predict(X_test)
# 预测结果统计
print(pd.Series(sklearn_predict).value_counts())
# 混淆矩阵
cm = metrics.confusion_matrix(y_test, sklearn_predict, labels = [0,1,2])
label=['性平','性凉寒','性温热']
cm = pd.DataFrame(cm,index=label,columns=label)
print(cm)
#评价指标
Accuracy = metrics._scorer.accuracy_score(y_test, sklearn_predict)
Sensitivity = metrics._scorer.recall_score(y_test, sklearn_predict,average=None)
Specificity = metrics._scorer.recall_score(y_test, sklearn_predict, pos_label=0,average=None)
print('模型准确率为%.2f%%:' %(Accuracy*100))
print('正例覆盖率:',Sensitivity*100)
# 中文和负号的正常显示
config = {"font.family": 'serif',"mathtext.fontset": 'stix',"font.serif": ['SimSun']}
plt.rcParams.update(config)
plt.rcParams['axes.unicode_minus'] = False
# 混淆矩阵的可视化
# 绘制热力图
sns.heatmap(cm, annot = True, cmap = 'GnBu')
plt.xlabel('预测值')
plt.ylabel('真实值')
plt.show()# 图形显示
# y得分为模型预测正例的概率
y_score = sklearn_logistic.predict_proba(X_test)[:,1]
# 调用自定义函数,绘制K-S曲线
plot_ks(y_test = y_test, y_score = y_score, positive_flag = 1)



