2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

上个月参加了全国数学建模大赛做了C题,很幸运获得省一并送评国奖,整理了一下程序并重新复盘了一下,在这里简单展示 问题一、二、三的部分小问解题思路与过程以及python程序。

读取、展示数据:

读取数据
data1 = pd.read_excel('附件.xlsx',sheet_name='表单1')
data2 = pd.read_excel('附件.xlsx',sheet_name='表单2')
data3 = pd.read_excel('附件.xlsx',sheet_name='表单3')

data1:

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

data2:

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

data3:

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

预处理:

1)填补表单1颜色缺失值以及表单2化学成分缺失值

对除颜色外的三个特征:类型、纹饰、表面风化进行分组,提取颜色的众数来对特定样本点进行填充缺失颜色。

def get_yanse(x):
    return x.value_counts().index[0]
display(data1.groupby(['类型','表面风化','纹饰'])['颜色'].agg(get_yanse,))
"""
类型  表面风化  纹饰
铅钡  无风化   A     浅蓝
          C      紫
    风化    A     浅蓝
          C     浅蓝
高钾  无风化   A     蓝绿
          C     浅蓝
    风化    B     蓝绿
Name: 颜色, dtype: object
"""

data1[data1['颜色'].isna()]
""""""
文物编号    纹饰    类型    颜色    表面风化
18  19  A   铅钡    NaN 风化
39  40  C   铅钡    NaN 风化
47  48  A   铅钡    NaN 风化
57  58  C   铅钡    NaN 风化
""""""

发现缺失数据的对应众数颜色均为浅蓝,使用浅蓝进行填充
data1.fillna('浅蓝',inplace=True)

依据题意对表单2化学成分缺失值进行0填充

data2.fillna(0,inplace=True)

2)提取出表单2数据文物采样点特征中的文物编号信息,通过文物编号信息联结表单1

提取文物采样点中的文物编号信息
def get_number(x):
    number = re.findall('\d*',x)[0]
    number = int(number[1]) if number[0]=='0' else int(number)
    return number
data2['文物编号'] = data2['文物采样点'].apply(get_number)

通过文物编号关联表单1、表单2
data_merge = pd.merge(data1,data2,on = '文物编号')

3)去除化学成分和在85%~105%外的无效数据

查看无效数据:

data_merge[~((zong_chengfen >= 85) & (zong_chengfen <= 105))]< code></=>

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别
&#x53D6;&#x51FA;&#x6709;&#x6548;&#x6570;&#x636E;
data_merge = data_merge[(zong_chengfen >= 85) & (zong_chengfen <= 105)] # data_merge.to_excel('问题一连接两表并处理后数据.xlsx')< code></=>

4)对联结后的数据依据题目附件信息描述以及文物编号、文物采样点信息,获取采样点的风化类型。

&#x83B7;&#x53D6;&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;&#x4FE1;&#x606F;
&#x7B2C;&#x4E00;&#x6B65;
def get_fh(x):
    list_ = list(filter(lambda x:len(x)>0, re.findall('[^\d*]*',x)))
    return list_[0] if list_ else np.nan
data_merge['&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;'] = data_merge['&#x6587;&#x7269;&#x91C7;&#x6837;&#x70B9;'].apply(get_fh)
data_merge['&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;'].value_counts()
"""
&#x90E8;&#x4F4D;       10
&#x672A;&#x98CE;&#x5316;&#x70B9;     10
&#x4E25;&#x91CD;&#x98CE;&#x5316;&#x70B9;     3
Name: &#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;, dtype: int64
"""

&#x7B2C;&#x4E8C;&#x6B65;
data_merge.replace({'&#x90E8;&#x4F4D;':np.nan},inplace=True)
data_merge['&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;'] = data_merge['&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;'].fillna(data_merge['&#x8868;&#x9762;&#x98CE;&#x5316;'])
data_merge['&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;'].value_counts()
"""
&#x98CE;&#x5316;       29
&#x65E0;&#x98CE;&#x5316;      25
&#x672A;&#x98CE;&#x5316;&#x70B9;     10
&#x4E25;&#x91CD;&#x98CE;&#x5316;&#x70B9;     3
Name: &#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;, dtype: int64
"""

&#x7B2C;&#x4E09;&#x6B65;
data_merge['&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;'] = data_merge['&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;'].replace({'&#x65E0;&#x98CE;&#x5316;':'&#x672A;&#x98CE;&#x5316;&#x70B9;', '&#x98CE;&#x5316;':'&#x98CE;&#x5316;&#x70B9;'})
data_merge['&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;'].value_counts()
"""
&#x672A;&#x98CE;&#x5316;&#x70B9;     35
&#x98CE;&#x5316;&#x70B9;      29
&#x4E25;&#x91CD;&#x98CE;&#x5316;&#x70B9;     3
Name: &#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;, dtype: int64
"""

展示:

with sns.color_palette('rainbow'):
    # &#x4F5C;&#x8005;&#x5C01;&#x88C5;&#x7ED8;&#x56FE;&#x7A0B;&#x5E8F;&#xFF0C;&#x9700;&#x8981;&#x6E90;&#x7A0B;&#x5E8F;&#x53EF;&#x5728;&#x4F5C;&#x8005;&#x535A;&#x5BA2;'seaborn'&#x5C01;&#x88C5;&#x4E2D;&#x5BFB;&#x627E;
    count_pieplot(data_merge,1,2,vars = ['&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;'],hue = '&#x7C7B;&#x578B;',show_value=True)

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

问题一:

1、结合玻璃的类型,分析文物样品表面有无风化化学成分的统计规律

对高钾/铅钡玻璃,统计分析未风化、风化样本的化学成分差异,来探究有无风化化学成分的统计规律,使用折线图、箱线图进行分析,箱线图不仅可以看出样本点化学成分的分布范围,同时能够简明的分析均值、最小最大值。

折线图分析:取出有无风化各化学成分的均值,绘制折线图,观察有无风化化学成分的差异。

&#x63D0;&#x53D6;&#x5316;&#x5B66;&#x540D;&#x79F0;
def get_huaxue(x):
    return re.findall('\((.*)\)',x)[0]

plt.figure(figsize=(10, 8))
plt.subplot(211)
plt.plot(range(14),data_merge.query("&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B; == '&#x98CE;&#x5316;&#x70B9;' & &#x7C7B;&#x578B; == '&#x9AD8;&#x94BE;'").iloc[:,6:-1].mean(),label = '&#x98CE;&#x5316;')
plt.plot(range(14),data_merge.query("&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B; == '&#x672A;&#x98CE;&#x5316;&#x70B9;' & &#x7C7B;&#x578B; == '&#x9AD8;&#x94BE;'").iloc[:,6:-1].mean(),label = '&#x672A;&#x98CE;&#x5316;')
plt.legend()
plt.xticks(range(14),list(map(get_huaxue, data_merge.iloc[:,6:-1].columns)),fontsize = 10)
plt.title('&#x9AD8;&#x94BE;&#x98CE;&#x5316;&#x4E0E;&#x672A;&#x98CE;&#x5316;&#x7684;&#x5404;&#x6210;&#x5206;&#x5747;&#x503C;&#x7EDF;&#x8BA1;&#x5BF9;&#x6BD4;&#x56FE;',fontsize = 15)
plt.savefig('&#x9AD8;&#x94BE;&#x98CE;&#x5316;&#x4E0E;&#x672A;&#x98CE;&#x5316;&#x7684;&#x5404;&#x6210;&#x5206;&#x5747;&#x503C;&#x7EDF;&#x8BA1;&#x5BF9;&#x6BD4;&#x56FE;')

plt.subplot(212)
plt.plot(range(14),data_merge.query("&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B; == '&#x98CE;&#x5316;&#x70B9;' & &#x7C7B;&#x578B; == '&#x94C5;&#x94A1;'").iloc[:,6:-1].mean(),label = '&#x98CE;&#x5316;')
plt.plot(range(14),data_merge.query("&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B; == '&#x4E25;&#x91CD;&#x98CE;&#x5316;&#x70B9;' & &#x7C7B;&#x578B; == '&#x94C5;&#x94A1;'").iloc[:,6:-1].mean(),label = '&#x4E25;&#x91CD;&#x98CE;&#x5316;')
plt.plot(range(14),data_merge.query("&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B; == '&#x672A;&#x98CE;&#x5316;&#x70B9;' & &#x7C7B;&#x578B; == '&#x94C5;&#x94A1;'").iloc[:,6:-1].mean(),label = '&#x672A;&#x98CE;&#x5316;')

plt.legend()
plt.xticks(range(14),list(map(get_huaxue, data_merge.iloc[:,6:-1].columns)),fontsize = 10)
plt.title('&#x94C5;&#x94A1;&#x98CE;&#x5316;&#x4E0E;&#x672A;&#x98CE;&#x5316;&#x7684;&#x5404;&#x6210;&#x5206;&#x5747;&#x503C;&#x7EDF;&#x8BA1;&#x5BF9;&#x6BD4;&#x56FE;',fontsize = 15)
plt.savefig('&#x98CE;&#x5316;&#x4E0E;&#x672A;&#x98CE;&#x5316;&#x7684;&#x5404;&#x6210;&#x5206;&#x5747;&#x503C;&#x7EDF;&#x8BA1;&#x5BF9;&#x6BD4;&#x56FE;')
plt.subplots_adjust(hspace=0.35)
plt.savefig('&#x98CE;&#x5316;&#x4E0E;&#x672A;&#x98CE;&#x5316;&#x7684;&#x5404;&#x6210;&#x5206;&#x5747;&#x503C;&#x7EDF;&#x8BA1;&#x5BF9;&#x6BD4;&#x56FE;')

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

箱线图分析:分别取出

def get_colors(color_style):
    cnames = sns.xkcd_rgb
    if color_style =='light':
        colors = list(filter(lambda x:x[:5]=='light',cnames.keys()))
    elif color_style =='dark':
        colors = list(filter(lambda x:x[:4]=='dark',cnames.keys()))
    elif color_style =='all':
        colors = cnames.keys()
    colors = list(map(lambda x:cnames[x], colors))
    return colors

&#x5C01;&#x88C5;&#x7BB1;&#x7EBF;&#x56FE;
def boxplot(data, rows = 3, cols = 4, figsize = (13, 8), vars  =None, hue = None, width = 0.25,
            order = None, color_style ='light',subplots_adjust = (0.2, 0.2)):

    fig = plt.figure(figsize = figsize)
    hue = data[hue] if isinstance(hue,str) and hue in data.columns else hue
    data = data if not vars else data[vars]

    colors = get_colors(color_style)
    ax_num = 1
    for col in data.columns:
        if isinstance(data[col].values[0],(np.int64,np.int32,np.int16,np.int8,np.float16,np.float32,np.float64)):
            plt.subplot(rows, cols, ax_num)
            sns.boxplot(x = hue,y = data[col].values,color=random.sample(colors,1)[0],width= width,order = order)
            plt.xlabel(col)
            data[col].plot(kind = 'box',color=random.sample(colors,1)[0])
            ax_num+=1

    plt.subplots_adjust(hspace = subplots_adjust[0],wspace=subplots_adjust[1])
data_merge
data = pd.read_excel('&#x95EE;&#x9898;&#x4E00;&#x8FDE;&#x63A5;&#x4E24;&#x8868;&#x5E76;&#x5904;&#x7406;&#x540E;&#x6570;&#x636E;.xlsx').iloc[:,1:]

boxplot(data.query("&#x7C7B;&#x578B; == '&#x9AD8;&#x94BE;'"), 4, 4, hue = '&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;',
        vars = data.columns[1:].tolist(), figsize=(11, 8), subplots_adjust=(0.52,0.25))
plt.savefig('&#x9AD8;&#x94BE;&#x6709;&#x65E0;&#x98CE;&#x5316;&#x5316;&#x5B66;&#x6210;&#x5206;&#x7BB1;&#x7EBF;&#x56FE;&#x5206;&#x6790;.jpg')

高钾:

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别
boxplot(data.query("&#x7C7B;&#x578B; == '&#x94C5;&#x94A1;'"), 4, 4, hue = '&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;', vars = data.columns[1:].tolist(),
        figsize=(13, 8), subplots_adjust=(0.55,0.25), order = ['&#x672A;&#x98CE;&#x5316;&#x70B9;','&#x98CE;&#x5316;&#x70B9;','&#x4E25;&#x91CD;&#x98CE;&#x5316;&#x70B9;'])
plt.savefig('&#x94C5;&#x94A1;&#x6709;&#x65E0;&#x98CE;&#x5316;&#x5316;&#x5B66;&#x6210;&#x5206;&#x7BB1;&#x7EBF;&#x56FE;&#x5206;&#x6790;.jpg')

铅钡:

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

结合化学元素的描述性统计以及箱线图和折线图可以大致观察出有无风化化学成分的统计规律:

  1. 高钾玻璃的二氧化硅含量较高,且风化前后氧化钾以及三氧化二铝成分占比减小,而二氧化硅含量增加,其余化学成分占比变化不大。
  2. 铅钡玻璃的二氧化硅占比随着风化程度变大而逐渐减小且减小程度较大,风化前后氧化铅、氧化钡、五氧化二磷含量占比增大,相比较风化数据,严重风化的二氧化硫占比含量增加而风化与未风化的二氧化硫含量相差不大, 其余化学成分占比均变化不大。

2、根据风化点检测数据,预测其风化前的化学成分含量。

大部分人在这里会卡住,我在第一天晚上就基本上有了第二问思路,并且开始着手第二问的聚类,但却在这一小问的思路上卡到凌晨,队友也没有好的想法,其实一开始我也是明确知道不能使用机器学习方法进行建模,因为很明显 没有风化前后的样本匹配点,都是属于不同文物编号的数据,因此不能使用机器学习,在考虑别的方法上花了一点时间,然后想到最简单的统计未风化样本与风化样本的化学成分统计均值比例来得出一个比例系数,然后当预测的时候使用风化后的化学成分乘以这个比例就得到风化前的化学成分含量,这也是答案上提到的’均值’的方法。

但是这样直接统计均值的方法不太合适,因为同类型同风化程度玻璃的同个化学成分含量仍然有部分较大差异,如高钾风化采样点数据中某化学成分大部分近似且较小,而存在个别样本点含量很大,导致取均值后均值也较大,不太符合其他大部分数据的情况。

对于此现象,我们使用正态分布函数对样本点进行 加权平均的方式来得到风化前后化学成分变化比例。

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别
from scipy import stats
def zhengtai(x):
    return stats.norm.pdf(x)

&#x5C01;&#x88C5;&#x51FD;&#x6570;&#xFF0C;&#x4F20;&#x5165;&#x9AD8;&#x94BE;&#x6216;&#x94C5;&#x94A1;&#x6570;&#x636E;data&#x4EE5;&#x53CA;&#x98CE;&#x5316;&#x91C7;&#x6837;&#x70B9;&#x7C7B;&#x578B;
def get_mean(data, label):
    d_ = data[data['&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;'] == label].iloc[:,6:-1].copy()
    # &#x6807;&#x51C6;&#x5316;
    d_scaler = (d_ - d_.mean(axis = 0))/(d_.std(axis = 0))
    # &#x52A0;&#x6743;&#x5E73;&#x5747;
    mean_ = (zhengtai(d_scaler.T).T * d_).sum(axis = 0)/zhengtai(d_scaler.T).T.sum(axis = 0)
    mean_ = mean_.fillna(0)
    # &#x8FD4;&#x56DE;&#x5747;&#x503C;&#x4E0E;&#x52A0;&#x6743;&#x5747;&#x503C;
    return d_.mean(), mean_

获取高钾数据均值与加权均值:

a1, a2 = get_mean(data_merge.query("&#x7C7B;&#x578B; == '&#x9AD8;&#x94BE;'"), '&#x672A;&#x98CE;&#x5316;&#x70B9;')
b1, b2 = get_mean(data_merge.query("&#x7C7B;&#x578B; == '&#x9AD8;&#x94BE;'"), '&#x98CE;&#x5316;&#x70B9;')

gj_mean = pd.concat((a1,a2,b1,b2),axis = 1)
gj_mean.columns = ['&#x672A;&#x98CE;&#x5316;&#x70B9;&#x5747;&#x503C;','&#x672A;&#x98CE;&#x5316;&#x70B9;&#x52A0;&#x6743;&#x5747;&#x503C;','&#x98CE;&#x5316;&#x70B9;&#x5747;&#x503C;','&#x98CE;&#x5316;&#x70B9;&#x52A0;&#x6743;&#x5747;&#x503C;']
gj_mean

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

进行可视化:

d_ = data_merge.query("&#x7C7B;&#x578B; == '&#x9AD8;&#x94BE;'")
fig, axes = plt.subplots(4,4,figsize = (16,16))
axes = axes.ravel()
for num,fea in enumerate(data_merge.columns[6:-1]):
    sns.stripplot(x = '&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;',palette = sns.color_palette('deep',3),
                  y = fea,
                  data =d_,ax = axes[num],
                  jitter = True) # &#x2018;&#x6296;
    wfh_mean,wfh_mean_jiaquan = gj_mean[['&#x672A;&#x98CE;&#x5316;&#x70B9;&#x5747;&#x503C;','&#x672A;&#x98CE;&#x5316;&#x70B9;&#x52A0;&#x6743;&#x5747;&#x503C;']].loc[fea,:]
    fh_mean, fh_mean_jiaquan = gj_mean[['&#x98CE;&#x5316;&#x70B9;&#x5747;&#x503C;','&#x98CE;&#x5316;&#x70B9;&#x52A0;&#x6743;&#x5747;&#x503C;']].loc[fea,:]

    color = ['b','r']
    axes[num].plot([-0.5,0.5],[wfh_mean]*2, c = color[0], label = '&#x672A;&#x98CE;&#x5316;&#x5747;&#x503C;')
    axes[num].plot([-0.5,0.5],[wfh_mean_jiaquan]*2, '--', c = color[0], label = '&#x672A;&#x98CE;&#x5316;&#x52A0;&#x6743;&#x5747;&#x503C;')

    axes[num].plot([0.5, 1.5], [fh_mean]*2, c = color[1], label = '&#x98CE;&#x5316;&#x5747;&#x503C;')
    axes[num].plot([0.5, 1.5],[fh_mean_jiaquan]*2, '--', c= color[1], label = '&#x98CE;&#x5316;&#x52A0;&#x6743;&#x5747;&#x503C;')
    if num==1:
        axes[num].legend()
axes[-1].axis('off')
axes[-2].axis('off')
plt.subplots_adjust(0.2,0.2)
plt.show()

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

获取铅钡数据均值与加权均值:

a1, a2 = get_mean(data_merge.query("&#x7C7B;&#x578B; == '&#x94C5;&#x94A1;'"), '&#x672A;&#x98CE;&#x5316;&#x70B9;')
b1, b2 = get_mean(data_merge.query("&#x7C7B;&#x578B; == '&#x94C5;&#x94A1;'"), '&#x98CE;&#x5316;&#x70B9;')
c1, c2 = get_mean(data_merge.query("&#x7C7B;&#x578B; == '&#x94C5;&#x94A1;'"), '&#x4E25;&#x91CD;&#x98CE;&#x5316;&#x70B9;')
qb_mean = pd.concat((a1,a2,b1,b2,c1,c2),axis = 1)
qb_mean.columns = ['&#x672A;&#x98CE;&#x5316;&#x70B9;&#x5747;&#x503C;','&#x672A;&#x98CE;&#x5316;&#x70B9;&#x52A0;&#x6743;&#x5747;&#x503C;','&#x98CE;&#x5316;&#x70B9;&#x5747;&#x503C;','&#x98CE;&#x5316;&#x70B9;&#x52A0;&#x6743;&#x5747;&#x503C;','&#x4E25;&#x91CD;&#x98CE;&#x5316;&#x70B9;&#x5747;&#x503C;','&#x4E25;&#x91CD;&#x98CE;&#x5316;&#x70B9;&#x52A0;&#x6743;&#x5747;&#x503C;']
qb_mean

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

可视化:

d_ = data_merge.query("&#x7C7B;&#x578B; == '&#x94C5;&#x94A1;'")
fig, axes = plt.subplots(4,4,figsize = (16,16))
axes = axes.ravel()
for num,fea in enumerate(data_merge.columns[6:-1]):
    sns.stripplot(x = '&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;',palette = sns.color_palette('deep',3),
                  y = fea,
                  data =d_,ax = axes[num],
                  order = ['&#x672A;&#x98CE;&#x5316;&#x70B9;','&#x98CE;&#x5316;&#x70B9;','&#x4E25;&#x91CD;&#x98CE;&#x5316;&#x70B9;'],
                  jitter = True) # &#x2018;&#x6296;

    wfh_mean,wfh_mean_jiaquan = qb_mean[['&#x672A;&#x98CE;&#x5316;&#x70B9;&#x5747;&#x503C;','&#x672A;&#x98CE;&#x5316;&#x70B9;&#x52A0;&#x6743;&#x5747;&#x503C;']].loc[fea,:]
    fh_mean, fh_mean_jiaquan = qb_mean[['&#x98CE;&#x5316;&#x70B9;&#x5747;&#x503C;','&#x98CE;&#x5316;&#x70B9;&#x52A0;&#x6743;&#x5747;&#x503C;']].loc[fea,:]
    yz_fh_mean, yz_fh_mean_jiaquan = qb_mean[['&#x4E25;&#x91CD;&#x98CE;&#x5316;&#x70B9;&#x5747;&#x503C;','&#x4E25;&#x91CD;&#x98CE;&#x5316;&#x70B9;&#x52A0;&#x6743;&#x5747;&#x503C;']].loc[fea,:]

    color = ['b', 'orange', 'g']
    axes[num].plot([-0.5, 0.5],[wfh_mean]*2, c = color[0], label = '&#x672A;&#x98CE;&#x5316;&#x5747;&#x503C;')
    axes[num].plot([-0.5, 0.5],[wfh_mean_jiaquan]*2, '--', c = color[0], label = '&#x672A;&#x98CE;&#x5316;&#x52A0;&#x6743;&#x5747;&#x503C;')

    axes[num].plot([0.5, 1.5], [fh_mean]*2, c = color[1], label = '&#x98CE;&#x5316;&#x5747;&#x503C;')
    axes[num].plot([0.5, 1.5],[fh_mean_jiaquan]*2, '--', c= color[1], label = '&#x98CE;&#x5316;&#x52A0;&#x6743;&#x5747;&#x503C;')

    axes[num].plot([1.5, 2.5],[yz_fh_mean]*2, c = color[2], label = '&#x4E25;&#x91CD;&#x98CE;&#x5316;&#x5747;&#x503C;')
    axes[num].plot([1.5, 2.5],[yz_fh_mean_jiaquan]*2, '--',c = color[2], label = '&#x4E25;&#x91CD;&#x98CE;&#x5316;&#x52A0;&#x6743;&#x5747;&#x503C;')

    axes[num].set_xlabel(None)
    if num==1:
        axes[num].legend()
axes[-1].axis('off')
axes[-2].axis('off')
plt.subplots_adjust(0.2,0.2)
plt.show()

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

获取风化前后加权均值比例:

w_gj = (gj_mean.iloc[:,1]/gj_mean.iloc[:,3]).replace({np.inf:0})
w_qb = (qb_mean['&#x672A;&#x98CE;&#x5316;&#x70B9;&#x52A0;&#x6743;&#x5747;&#x503C;']/qb_mean['&#x98CE;&#x5316;&#x70B9;&#x52A0;&#x6743;&#x5747;&#x503C;']).replace({np.inf:0})
w_qb_yz = (qb_mean['&#x672A;&#x98CE;&#x5316;&#x70B9;&#x52A0;&#x6743;&#x5747;&#x503C;']/qb_mean['&#x4E25;&#x91CD;&#x98CE;&#x5316;&#x70B9;&#x52A0;&#x6743;&#x5747;&#x503C;']).replace({np.inf:0})

W = pd.DataFrame([w_gj,w_qb,w_qb_yz],index = ['&#x9AD8;&#x94BE;:&#x98CE;&#x5316;&#x524D;&#x540E;&#x52A0;&#x6743;&#x6BD4;&#x4F8B;','&#x94C5;&#x94A1;:&#x98CE;&#x5316;&#x524D;&#x540E;&#x52A0;&#x6743;&#x6BD4;&#x4F8B;','&#x94C5;&#x94A1;:&#x4E25;&#x91CD;&#x98CE;&#x5316;&#x524D;&#x540E;&#x52A0;&#x6743;&#x6BD4;&#x4F8B;']).T

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

预测:

对风化后的样本点化学成分乘以风化前后比例,即得到风化前化学成分的预测值:

注:但在过程中我们发现还存在一个问题,即当风化采样点某化学成分为0时,不管比例多少相乘的预测结果仍为0,这与未风化采样点的该化学成分大部分情况不一致,若风化后成分为0则风化前预测也只能为0不太符合理想情况,即使未风化采样点中确实有少部分也为0的数据,对此现象我们使用风化前该化学成分的加权均值来作为预测值。

对于预测时风化采样点化学成分为0的处理前后分析:

高钾未风化采样点:

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

高钾风化采样点:

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

如上风化前氧化钾含量大部分都含有值且成分也接近10%, 氧化镁也是大部分都含有不为0的较小值。

直接预测:

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

使用风化前加权均值作为预测值:

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

如上处理后的结果仍然也在有效范围内,因此作者认为该方法可行,避免了过于死板的预测情况。

高钾预测程序:

&#x9AD8;&#x94BE;&#x9884;&#x6D4B;
fh_gj = data_merge.query("&#x7C7B;&#x578B; == '&#x9AD8;&#x94BE;' &  &#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B; == '&#x98CE;&#x5316;&#x70B9;'").iloc[:, 6:-1]
fh_gj = fh_gj.replace({0:np.nan})

data_merge.query("&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B; == '&#x98CE;&#x5316;&#x70B9;' & &#x7C7B;&#x578B; == '&#x9AD8;&#x94BE;'").iloc[:,6:-1]
gj_pred = fh_gj*W['&#x9AD8;&#x94BE;:&#x98CE;&#x5316;&#x524D;&#x540E;&#x52A0;&#x6743;&#x6BD4;&#x4F8B;']

gj_pred = gj_pred.fillna(gj_mean['&#x672A;&#x98CE;&#x5316;&#x70B9;&#x52A0;&#x6743;&#x5747;&#x503C;'])
&#x89C4;&#x6574;&#x5230;100% &#x6CE8;&#xFF1A;&#x81EA;&#x5DF1;&#x5206;&#x6790;&#x662F;&#x5426;&#x5408;&#x7406;
gj_pred = (gj_pred.T/gj_pred.sum(axis = 1)*100).T

&#x8865;&#x4E0A;&#x6210;&#x5206;&#x5916;&#x7684;&#x7279;&#x5F81;
d_ = data_merge.loc[gj_pred.index,:][['&#x6587;&#x7269;&#x7F16;&#x53F7;','&#x7EB9;&#x9970;','&#x7C7B;&#x578B;','&#x989C;&#x8272;',
                                                              '&#x8868;&#x9762;&#x98CE;&#x5316;','&#x6587;&#x7269;&#x91C7;&#x6837;&#x70B9;','&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;']]
gj_pred = pd.concat((d_, gj_pred), axis = 1)

铅钡预测程序:

&#x94C5;&#x94A1;&#x9884;&#x6D4B;
fh_qb = data_merge.query("&#x7C7B;&#x578B; == '&#x94C5;&#x94A1;' &  &#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B; == '&#x98CE;&#x5316;&#x70B9;'").iloc[:, 6:-1]
fh_qb = fh_qb.replace({0:np.nan})

yz_fh_qb = data_merge.query("&#x7C7B;&#x578B; == '&#x94C5;&#x94A1;' &  &#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B; == '&#x4E25;&#x91CD;&#x98CE;&#x5316;&#x70B9;'").iloc[:, 6:-1]
yz_fh_qb = yz_fh_qb.replace({0:np.nan})

qb_pred = (fh_qb * W['&#x94C5;&#x94A1;:&#x98CE;&#x5316;&#x524D;&#x540E;&#x52A0;&#x6743;&#x6BD4;&#x4F8B;'])
yz_qb_pred = (yz_fh_qb * W['&#x94C5;&#x94A1;:&#x4E25;&#x91CD;&#x98CE;&#x5316;&#x524D;&#x540E;&#x52A0;&#x6743;&#x6BD4;&#x4F8B;'])

qb_pred = qb_pred.fillna(qb_mean['&#x672A;&#x98CE;&#x5316;&#x70B9;&#x52A0;&#x6743;&#x5747;&#x503C;'])
yz_qb_pred = yz_qb_pred.fillna(qb_mean['&#x672A;&#x98CE;&#x5316;&#x70B9;&#x52A0;&#x6743;&#x5747;&#x503C;'])

&#x89C4;&#x6574;&#x5230;100%
qb_pred = (qb_pred.T/qb_pred.sum(axis = 1)*100).T
yz_qb_pred = (yz_qb_pred.T/yz_qb_pred.sum(axis = 1)*100).T

&#x5408;&#x5E76;&#x98CE;&#x5316;&#x70B9;&#x4E0E;&#x4E25;&#x91CD;&#x98CE;&#x5316;&#x70B9;&#x9884;&#x6D4B;&#x6570;&#x636E;
qb_pred = pd.concat((yz_qb_pred,qb_pred))

&#x8865;&#x4E0A;&#x6210;&#x5206;&#x5916;&#x7279;&#x5F81;
d_ = data_merge.loc[qb_pred.index,:][['&#x6587;&#x7269;&#x7F16;&#x53F7;','&#x7EB9;&#x9970;','&#x7C7B;&#x578B;','&#x989C;&#x8272;',
                                   '&#x8868;&#x9762;&#x98CE;&#x5316;','&#x6587;&#x7269;&#x91C7;&#x6837;&#x70B9;','&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;']]
qb_pred = pd.concat((d_, qb_pred), axis = 1)

Result = pd.concat((gj_pred, qb_pred)).reset_index().iloc[:, 1:]
Result.to_excel('&#x52A0;&#x6743;&#x5E73;&#x5747;&#x6CD5;&#x9884;&#x6D4B;&#x98CE;&#x5316;&#x524D;&#x542B;&#x91CF;&#x7ED3;&#x679C;.xlsx')
Result

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

问题二

1、依据附件数据分析高钾玻璃、铅钡玻璃的分类规律;

箱线图可视化分析高钾、铅钡玻璃化学成分的差异,以探究决定其玻璃类别的分类规律:

data_merge
data = pd.read_excel('&#x95EE;&#x9898;&#x4E00;&#x8FDE;&#x63A5;&#x4E24;&#x8868;&#x5E76;&#x5904;&#x7406;&#x540E;&#x6570;&#x636E;.xlsx').iloc[:,1:]
&#x4F5C;&#x8005;&#x5C01;&#x88C5;&#x51FD;&#x6570;
boxplot(data,4,4,hue = '&#x7C7B;&#x578B;', vars = data.columns[1:].tolist(),
        figsize=(11, 8), subplots_adjust=(0.52,0.25))
plt.savefig('&#x9AD8;&#x94BE;&#x94C5;&#x94A1;&#x73BB;&#x7483;&#x5316;&#x5B66;&#x6210;&#x5206;&#x7BB1;&#x7EBF;&#x56FE;&#x5206;&#x6790;.jpg')

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

密度图分析特征分布

stat = "count", "frequency", "density", "probability"
def distplot(data, rows = 3, cols = 4, bins = 10, vars = None, hue = None, kind = 'hist',stat = 'count', shade = True,
             figsize = (12, 5), color_style = 'all', alpha = 0.7, subplots_adjust = (0.3, 0.2)):
    assert kind in ['hist', 'kde','both'], "kind must == 'hist' or 'kde'"
    assert stat in ["count", "frequency", "density", "probability"], 'stat must in ["count", "frequency", "density", "probability"]'

    fig = plt.figure(figsize = figsize)
    hue_name = hue  if isinstance(hue,str) or hue==None else hue.name
    hue = data[hue] if isinstance(hue,str) and hue in data.columns else hue
    data = data if not vars else data[vars]

    colors = get_colors(color_style)

    ax_num = 1
    for col in data.columns:
        if isinstance(data[col].values[0],(np.int64,np.int32,np.int16,np.int8,np.float16,np.float32,np.float64)) and col!=hue_name:
            plt.subplot(rows, cols, ax_num)
            if kind == 'hist':
                sns.histplot(x = data.loc[:,col],bins = bins,color=random.sample(colors,1)[0],hue = hue,alpha = alpha,stat = stat)
            elif kind == 'kde':
                sns.kdeplot(x = data.loc[:,col],color=random.sample(colors,1)[0],alpha = alpha,hue = hue,shade = shade)
            else:
                sns.distplot(x = data.loc[:,col],color=random.sample(colors,1)[0],kde=True,bins = bins,)
                plt.xlabel(col)
            ax_num+=1

    plt.subplots_adjust(hspace = subplots_adjust[0],wspace=subplots_adjust[1])
with sns.color_palette('rainbow_r'):
    distplot(data.iloc[:,1:],4,4,kind = 'kde',figsize=(11,7),subplots_adjust=(0.5,0.35),hue = '&#x7C7B;&#x578B;')

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

由以上图分析高钾以及铅钡玻璃的 二氧化硅、氧化钾、氧化铅、氧化钡、五氧化二磷、氧化锶的特征分布差异较大,特别是氧化铅,高钾的氧化铅含量基本分布在0,而铅钡的氧化铅含量较大,所以这些特征特别是 氧化铅很可能是区分高钾以及铅钡的重要特征,随后 建立玻璃类型预测模型进行进一步确定以及验证

在这里建立的模型可以直接用于问题三预测,问题三主要就是预测结果而已。在这里选择的模型比较简单,数据集体量很小且具有明显的区分特征,使用 L1正则逻辑回归、决策树就可以实现高钾、铅钡玻璃的完全区分了,交叉验证精度均达到100%,使用该两个模型的原因不仅在于简单,且具有 筛选重要特征的作用,并且可以不受 多重共线性的影响,我看很多人使用神经网络,一上来就套用太复杂的模型,我感觉没必要,数据集本身很小且逻辑回归就能满足预测,当然也可以使用随机森林或支持向量机。

由于该过程很简单,只需按照传统的进行编码以及标准化处理后通过sklearn库进行模型建立,在这里就介绍一下以上思路,就不展示程序了,展示一下几张关于模型的可视化效果图:

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

对上图权重图进行分析,我们可以发现其主要决定性因素为二氧化硅、氧化钾、氧化铅、氧化钡等,其中氧化铅权重最大,即其对分类结果的决定性最大,这些影响因素均与箱线图分析中得到的结论一致。

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

决策树能对该样本完美分类,由于决策树原理及性质,在此划分条件过于单一,说明 氧化铅特征就能区分高钾以及铅钡,且决策边界为线性超平面,如箱线图中氧化铅特征分析中,能够观察到仅需一条直线就能将其区分,只是依据氧化铅含量进行预测,过于依靠单个特征,使得面对噪声等异常数据或者缺少二氧化硅含量的情况下,模型可用性较差,可改用随机森林。

而逻辑回归与支持向量机均采用了所有特征作为依据进行预测更能达到现实情况中我们想要的效果,考虑支持向量机原理以及上限更高于逻辑回归,因此这里选择最终的模型为支持向量机。

决策平面展示:

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

2、对于每个类别选择合适的化学成分对其进行亚类划分,给出具体的划分方法及划分结果,并对分类结果的合理性和敏感性进行分析。

在这里我们是分别以高钾、铅钡类别的采样点风化类型特征作为聚类依据进行亚分类。依据题意以及数据分析,同一类型玻璃风化前后其化学成分变化较大,因此以将风化、未风化以及严重风化下的玻璃作为亚分类类别,高钾分为未风化、风化两类,铅钡分为未风化、风化、严重风化三类,按照风化程度对原数据样本采样点统计得到以下数据,后续聚类结果评估以此为依据:

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

筛选特征:

筛选特征有多种方式:

可以通过每个化学成分的离散程度(选择标准差大的特征)作为亚分类的依据,因为对于单个玻璃类型数据,若其某个特征离散程度小,即成分含量近似,则不适合且难以作为进一步划分类别的依据,相反离散程度大的特征,可认为其具有可进一步划分的空间。

也可以通过分类模型以化学成分作为变量、风化类型作为标签进行训练,然后通过特征的权重大小,或者是特征重要性进行选取特征。在该问题上这种方式可能较好于通过标准差选取的方式,因为由于聚类目的是明确的,筛选特征需考虑筛选特征后的聚类结果更加拟合于风化情况,而标准差大的特征不一定适合作为该聚类的依据特征,反而可能会影响结果。虽然如此,但在第一种方式的基础上仍然可以通过对聚类结果进行分析来稍微调整选择的特征。

随机森林选取特征:

在这里使用随机森林分类模型进行特征的选取,不使用决策树在于在训练时由于数据集过于简单,很轻易的单个特征就能将其划分,会使得该单特征的重要性为1而其他特征都为0,不能为我们选取多个特征提供依据。

from sklearn.cluster import KMeans, AgglomerativeClustering,DBSCAN
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import f1_score
from sklearn.model_selection import cross_val_score
from itertools import permutations

data = pd.read_excel('&#x95EE;&#x9898;&#x4E00;&#x8FDE;&#x63A5;&#x4E24;&#x8868;&#x5E76;&#x5904;&#x7406;&#x540E;&#x6570;&#x636E;.xlsx').iloc[:,1:]
d1 = data.query("&#x7C7B;&#x578B; == '&#x9AD8;&#x94BE;'")
d1.index = range(len(d1))
d2 = data.query("&#x7C7B;&#x578B; == '&#x94C5;&#x94A1;'")
d2.index = range(len(d2))

高钾:

x = d1.drop('&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;', axis = 1).iloc[:, 6:]
y = d1['&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;']

model = RandomForestClassifier()
&#x53C2;&#x6570;&#x8C03;&#x4F18;
parameters = {'max_depth':range(1,5),'min_samples_leaf':[1,2],'criterion':['gini','entropy'],'min_impurity_decrease':[0.01,0.02,0.025]}

grid_search = GridSearchCV(model, parameters,cv=5)
grid_search.fit(x, y)  # &#x4F20;&#x5165;&#x6570;&#x636E;

print('&#x7F51;&#x683C;&#x641C;&#x7D22;&#x6700;&#x9AD8;&#x7CBE;&#x5EA6;&#x4E3A;&#xFF1A;',grid_search.best_score_)
print('&#x53C2;&#x6570;&#x6700;&#x4F18;&#x503C;&#xFF1A;',grid_search.best_params_)
model.fit(x, y)

gj_fea_df = pd.DataFrame([x.columns,model.feature_importances_],index = ['&#x5316;&#x5B66;&#x6210;&#x5206;','&#x7279;&#x5F81;&#x91CD;&#x8981;&#x6027;']).T
gj_fea_df.sort_values('&#x7279;&#x5F81;&#x91CD;&#x8981;&#x6027;', ascending = False)
"""
&#x5316;&#x5B66;&#x6210;&#x5206;    &#x7279;&#x5F81;&#x91CD;&#x8981;&#x6027;
0   &#x4E8C;&#x6C27;&#x5316;&#x7845;(SiO2)  0.231851
5   &#x6C27;&#x5316;&#x94DD;(Al2O3) 0.170588
2   &#x6C27;&#x5316;&#x94BE;(K2O)   0.146777
3   &#x6C27;&#x5316;&#x9499;(CaO)   0.138207
6   &#x6C27;&#x5316;&#x94C1;(Fe2O3) 0.097733
10  &#x4E94;&#x6C27;&#x5316;&#x4E8C;&#x78F7;(P2O5)  0.096698
7   &#x6C27;&#x5316;&#x94DC;(CuO)   0.034813
4   &#x6C27;&#x5316;&#x9541;(MgO)   0.02908
8   &#x6C27;&#x5316;&#x94C5;(PbO)   0.017656
11  &#x6C27;&#x5316;&#x9536;(SrO)   0.017181
12  &#x6C27;&#x5316;&#x9521;(SnO2)  0.009706
9   &#x6C27;&#x5316;&#x94A1;(BaO)   0.007264
1   &#x6C27;&#x5316;&#x94A0;(Na2O)  0.002448
13  &#x4E8C;&#x6C27;&#x5316;&#x786B;(SO2)   0.0
"""
&#x83B7;&#x53D6;&#x964D;&#x5E8F;&#x540E;&#x7684;&#x91CD;&#x8981;&#x6027;&#x7279;&#x5F81;&#x5217;&#x8868;
gj_fea = gj_fea_df.sort_values('&#x7279;&#x5F81;&#x91CD;&#x8981;&#x6027;', ascending = False)['&#x5316;&#x5B66;&#x6210;&#x5206;'].tolist()

铅钡:

gj_fea = dt.T.loc[:,'&#x9AD8;&#x94BE;&#xFF08;&#x6807;&#x51C6;&#x5DEE;&#xFF09;'].sort_values(ascending = False).index
dt.T.loc[:,'&#x9AD8;&#x94BE;&#xFF08;&#x6807;&#x51C6;&#x5DEE;&#xFF09;'].sort_values(ascending = False)

"""
&#x4E8C;&#x6C27;&#x5316;&#x7845;(SiO2)     14.466726
&#x6C27;&#x5316;&#x94BE;(K2O)        5.307753
&#x6C27;&#x5316;&#x9499;(CaO)        3.308126
&#x6C27;&#x5316;&#x94DD;(Al2O3)      3.076662
&#x6C27;&#x5316;&#x94C1;(Fe2O3)      1.566033
&#x6C27;&#x5316;&#x94DC;(CuO)        1.492236
&#x4E94;&#x6C27;&#x5316;&#x4E8C;&#x78F7;(P2O5)     1.280603
&#x6C27;&#x5316;&#x94A0;(Na2O)       1.088707
&#x6C27;&#x5316;&#x94A1;(BaO)        0.841629
&#x6C27;&#x5316;&#x9541;(MgO)        0.711802
&#x6C27;&#x5316;&#x9521;(SnO2)       0.556257
&#x6C27;&#x5316;&#x94C5;(PbO)        0.514144
&#x4E8C;&#x6C27;&#x5316;&#x786B;(SO2)       0.157164
&#x6C27;&#x5316;&#x9536;(SrO)        0.043866
Name: &#x9AD8;&#x94BE;&#xFF08;&#x6807;&#x51C6;&#x5DEE;&#xFF09;, dtype: float64
"""

铅钡:

x = d2.drop('&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;', axis = 1).iloc[:, 6:]
y = d2['&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;']

&#x53C2;&#x6570;&#x8C03;&#x4F18;
model = RandomForestClassifier()
parameters = {'max_depth':range(1,5),'min_samples_leaf':[1,2],'criterion':['gini','entropy'],'min_impurity_decrease':[0.01,0.02]}

grid_search = GridSearchCV(model, parameters,cv=5)
grid_search.fit(x, y)  # &#x4F20;&#x5165;&#x6570;&#x636E;

print('&#x7F51;&#x683C;&#x641C;&#x7D22;&#x6700;&#x9AD8;&#x7CBE;&#x5EA6;&#x4E3A;&#xFF1A;',grid_search.best_score_)
print('&#x53C2;&#x6570;&#x6700;&#x4F18;&#x503C;&#xFF1A;',grid_search.best_params_)
model.fit(x, y)

qb_fea_df = pd.DataFrame([x.columns,model.feature_importances_],index = ['&#x5316;&#x5B66;&#x6210;&#x5206;','&#x7279;&#x5F81;&#x91CD;&#x8981;&#x6027;']).T
qb_fea_df.sort_values('&#x7279;&#x5F81;&#x91CD;&#x8981;&#x6027;', ascending = False)
"""
&#x5316;&#x5B66;&#x6210;&#x5206;    &#x7279;&#x5F81;&#x91CD;&#x8981;&#x6027;
0   &#x4E8C;&#x6C27;&#x5316;&#x7845;(SiO2)  0.227769
8   &#x6C27;&#x5316;&#x94C5;(PbO)   0.207812
3   &#x6C27;&#x5316;&#x9499;(CaO)   0.092374
10  &#x4E94;&#x6C27;&#x5316;&#x4E8C;&#x78F7;(P2O5)  0.087535
11  &#x6C27;&#x5316;&#x9536;(SrO)   0.06342
5   &#x6C27;&#x5316;&#x94DD;(Al2O3) 0.056736
7   &#x6C27;&#x5316;&#x94DC;(CuO)   0.050561
9   &#x6C27;&#x5316;&#x94A1;(BaO)   0.042228
13  &#x4E8C;&#x6C27;&#x5316;&#x786B;(SO2)   0.03454
4   &#x6C27;&#x5316;&#x9541;(MgO)   0.033355
2   &#x6C27;&#x5316;&#x94BE;(K2O)   0.030859
1   &#x6C27;&#x5316;&#x94A0;(Na2O)  0.027895
6   &#x6C27;&#x5316;&#x94C1;(Fe2O3) 0.027078
12  &#x6C27;&#x5316;&#x9521;(SnO2)  0.017839
"""
&#x83B7;&#x53D6;&#x94C5;&#x94A1;&#x91CD;&#x8981;&#x6027;&#x964D;&#x5E8F;&#x7279;&#x5F81;&#x5217;&#x8868;
qb_fea = qb_fea_df.sort_values('&#x7279;&#x5F81;&#x91CD;&#x8981;&#x6027;', ascending = False)['&#x5316;&#x5B66;&#x6210;&#x5206;'].tolist()

筛选特征:通过从特征重要性高到低不断选取特征,并通过聚类后使用f1-score与采样点风化类型进行匹配,量化拟合效果来选取特征,若特征导致下降则删除该特征。

def pinggu_gj(pred):
    score = 0
    for i in permutations([0,1]):
        true1 = d1['&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;'].replace({'&#x672A;&#x98CE;&#x5316;&#x70B9;':i[0],'&#x98CE;&#x5316;&#x70B9;':i[1]})
        score_ = f1_score(pred, true1, average='weighted')
        score = score_ if score_>score else score
    return score

def pinggu_qb(pred):
    score = 0
    for i in permutations([0,1,2]):
        true2 = d2['&#x91C7;&#x6837;&#x70B9;&#x98CE;&#x5316;&#x7C7B;&#x578B;'].replace({'&#x672A;&#x98CE;&#x5316;&#x70B9;':i[0], '&#x98CE;&#x5316;&#x70B9;':i[1], '&#x4E25;&#x91CD;&#x98CE;&#x5316;&#x70B9;':i[2]})
        score_ = f1_score(pred, true2, average='weighted')
        score = score_ if score_>score else score
    return score

gj_score = 0
qb_score = 0
gj_del_fea = []
qb_del_fea = []
best_gj_fea = []
best_qb_fea = []
for i in range(1, 15):
    fea1 = gj_fea[:i].copy()
    for g in gj_del_fea:
        fea1.remove(g)
    d1_x = d1[fea1]

    fea2 = qb_fea[:i].copy()
    for g in qb_del_fea:
        fea2.remove(g)
    d2_x = d2[fea2]

    model1 = KMeans( n_clusters=2)
    scaler1 = StandardScaler()
    a1 = scaler1.fit_transform(d1_x)
    y1 = model1.fit_predict(a1)
    d1_['label'] = y1
    if pinggu_gj(d1_['label']) > gj_score:
        gj_score = pinggu_gj(d1_['label'])
        best_gj_fea = fea1
    else:
        gj_del_fea.append(gj_fea[i-1])

    scaler2 = StandardScaler()
    model2 = KMeans( n_clusters=3)
    a2 = scaler2.fit_transform(d2_x)
    y2 = model2.fit_predict(a2)
    d2_['label'] = y2
    if pinggu_qb(d2_['label']) > qb_score:
        qb_score = pinggu_qb(d2_['label'])
        best_qb_fea = fea2
    else:
        qb_del_fea.append(qb_fea[i-1])

print(f'&#x9AD8;&#x94BE;&#x6570;&#x636E;&#x9009;&#x62E9;&#x7684;&#x7279;&#x5F81;&#xFF1A;{best_gj_fea}')
&#x9AD8;&#x94BE;&#x6570;&#x636E;&#x9009;&#x62E9;&#x7684;&#x7279;&#x5F81;&#xFF1A;['&#x4E8C;&#x6C27;&#x5316;&#x7845;(SiO2)', '&#x4E94;&#x6C27;&#x5316;&#x4E8C;&#x78F7;(P2O5)']

print(f'&#x94C5;&#x94A1;&#x6570;&#x636E;&#x9009;&#x62E9;&#x7684;&#x7279;&#x5F81;&#xFF1A;{best_qb_fea}')
&#x94C5;&#x94A1;&#x6570;&#x636E;&#x9009;&#x62E9;&#x7684;&#x7279;&#x5F81;&#xFF1A;['&#x4E8C;&#x6C27;&#x5316;&#x7845;(SiO2)', '&#x6C27;&#x5316;&#x94C5;(PbO)', '&#x6C27;&#x5316;&#x94A1;(BaO)', '&#x4E8C;&#x6C27;&#x5316;&#x786B;(SO2)']

print(f'&#x9AD8;&#x94BE;f1-score&#xFF1A;', gj_score, '&#x94C5;&#x94A1;f1-score&#xFF1A;', qb_score )
&#x9AD8;&#x94BE;f1-score&#xFF1A; 0.9435154217762913 &#x94C5;&#x94A1;f1-score&#xFF1A; 0.8987315891105979

如以上结果:

高钾玻璃选取的特征为: 二氧化硅、五氧化二磷

铅钡玻璃选取的特征为: 二氧化硅、氧化铅、 氧化钡、 二氧化硫

高钾、铅钡选取的特征聚类结果与原样本的采样点风化类型匹配精度分别为0.94、0.89

使用选取的特征再次聚类,并将聚类结果保存。

对聚类结果进行可视化,分别绘制二维、三维散点图,选取重要性大的2、3个特征作为二维三维的轴(三维绘制中高钾选取的特征只有两个,只需添加其他成分中重要性最大的即可,这里主要是展示大概的聚类效果)。

d1_ = pd.concat((d1.loc[:,['&#x6587;&#x7269;&#x7F16;&#x53F7;','&#x7C7B;&#x578B;','&#x6587;&#x7269;&#x91C7;&#x6837;&#x70B9;']], d1.loc[:,'&#x4E8C;&#x6C27;&#x5316;&#x7845;(SiO2)':'&#x4E8C;&#x6C27;&#x5316;&#x786B;(SO2)']),axis = 1)
d2_ = pd.concat((d2.loc[:,['&#x6587;&#x7269;&#x7F16;&#x53F7;','&#x6587;&#x7269;&#x91C7;&#x6837;&#x70B9;']], d2.loc[:,'&#x4E8C;&#x6C27;&#x5316;&#x7845;(SiO2)':'&#x4E8C;&#x6C27;&#x5316;&#x786B;(SO2)']),axis = 1)

d1_x = d1[['&#x4E8C;&#x6C27;&#x5316;&#x7845;(SiO2)', '&#x4E94;&#x6C27;&#x5316;&#x4E8C;&#x78F7;(P2O5)']]
d2_x = d2[['&#x4E8C;&#x6C27;&#x5316;&#x7845;(SiO2)', '&#x6C27;&#x5316;&#x94C5;(PbO)', '&#x6C27;&#x5316;&#x94A1;(BaO)', '&#x4E8C;&#x6C27;&#x5316;&#x786B;(SO2)']]

&#x5747;&#x503C;&#x805A;&#x7C7B;
model1 = KMeans( n_clusters=2)
scaler1 = StandardScaler()
a1 = scaler1.fit_transform(d1_x)
y1 = model1.fit_predict(a1)
d1_['label'] = y1

scaler2 = StandardScaler()
model2 = KMeans( n_clusters=3)
a2 = scaler2.fit_transform(d2_x)
y2 = model2.fit_predict(a2)
d2_['label'] = y2

from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(15,8))

ax = fig.add_subplot(121, projection='3d')
ax = plt.subplot(121)
for i in range(d1_['label'].nunique()):
    data = d1_[d1_['label']==i]
    ax.scatter(data['&#x4E8C;&#x6C27;&#x5316;&#x7845;(SiO2)'],data['&#x4E94;&#x6C27;&#x5316;&#x4E8C;&#x78F7;(P2O5)'],c=colors[i],label =i)
    ax.scatter(data['&#x4E8C;&#x6C27;&#x5316;&#x7845;(SiO2)'],data['&#x4E94;&#x6C27;&#x5316;&#x4E8C;&#x78F7;(P2O5)'],data['&#x6C27;&#x5316;&#x94DD;(Al2O3)'],c=colors[i],label =i)
ax.set_xlabel('&#x4E8C;&#x6C27;&#x5316;&#x7845;(SiO2)')
ax.set_ylabel('&#x4E94;&#x6C27;&#x5316;&#x4E8C;&#x78F7;(P2O5)')
ax.set_zlabel('&#x6C27;&#x5316;&#x94DD;(Al2O3)')
plt.title('&#x9AD8;&#x94BE;:Kmeans&#x805A;&#x7C7B;&#x7ED3;&#x679C;&#x56FE;',fontsize = 15)
plt.legend()
plt.savefig('&#x9AD8;&#x94BE;&#x805A;&#x7C7B;&#x6548;&#x679C;&#x4E09;&#x7EF4;&#x6563;&#x70B9;&#x56FE;')

ax = fig.add_subplot(122, projection='3d')
ax = plt.subplot(122)
for i in range(d2_['label'].nunique()):
    data = d2_[d2_['label']==i]
    ax.scatter(data['&#x4E8C;&#x6C27;&#x5316;&#x7845;(SiO2)'],data['&#x6C27;&#x5316;&#x94C5;(PbO)'],c=colors[i],label =i)
    ax.scatter(data['&#x4E8C;&#x6C27;&#x5316;&#x7845;(SiO2)'],data['&#x6C27;&#x5316;&#x94C5;(PbO)'],data['&#x6C27;&#x5316;&#x94A1;(BaO)'],c=colors[i],label =i)
ax.set_xlabel('&#x4E8C;&#x6C27;&#x5316;&#x7845;(SiO2)')
ax.set_ylabel('&#x6C27;&#x5316;&#x94C5;(PbO)')
ax.set_zlabel('&#x6C27;&#x5316;&#x94A1;(BaO)')
plt.title('&#x94C5;&#x94A1;:Kmeans&#x805A;&#x7C7B;&#x805A;&#x7C7B;&#x7ED3;&#x679C;&#x56FE;',fontsize = 15)
plt.legend()
plt.savefig('&#x94C5;&#x94A1;&#x805A;&#x7C7B;&#x6548;&#x679C;&#x4E09;&#x7EF4;&#x6563;&#x70B9;&#x56FE;')
plt.savefig('Kmeans&#x805A;&#x7C7B;&#x805A;&#x7C7B;&#x7ED3;&#x679C;&#x56FE;')
plt.show()

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

三维:

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

层次聚类与均值聚类效果基本一致 。

合理性分析:

如上图高钾三维图中聚成两类,结合样本点风化类型,可知图上二氧化硅含量较高的一类为风化后,另一类含量较低的为风化前数据,符合原数据情况,铅钡玻璃亦如此,如二维三点图中红色点即为严重风化的匹配点,因此认为该聚类结果具有合理性。

敏感性分析:

思路:为探究分类结果的敏感性,我们使用控制变量法,分别对每个特征含量进行范围性变化,期间控制其他特征的含量不变,使用已经训练好的 _K-means_聚类模型对变化后的样本点进行预测,使用 _f1-score_作为指标量化预测结果,若样本点预测结果不变,即分类结果对单个特征变化不敏感,分类结果具有稳定性。

问题三 对附件表单 3 中未知类别玻璃文物的化学成分进行分析,鉴别其所属类型,并对分类结果的敏感性进行分析。

简单分析测试数据的特征分布等情况是否与训练集特征分布差异太大,使用问题二建立的模型对测试数据进行预测即可,使用支持向量机或随机森林的结果都一致。

可视化分析:

def boxplot1(data1,data2, rows = 3, cols = 4,figsize = (13, 8),color_style ='light'):
    fig = plt.figure(figsize = figsize)
    colors = get_colors(color_style=color_style)
    ax_num = 1
    for col in data1.columns:
        if isinstance(data1[col][0],(np.int, np.float)):
            plt.subplot(rows, cols, ax_num)
            data_ = pd.DataFrame([data1[col].values,data2[col].values],index = ['&#x539F;&#x6570;&#x636E;','&#x8868;&#x5355;3&#x6570;&#x636E;']).T
            sns.boxplot(data = data_,color=random.sample(colors,1)[0],width=0.2,)
            sns.histplot(data = data_,color=random.sample(colors,1)[0],kde = True)

            plt.xlabel(col)
            data[col].plot(kind = 'box',color = random.sample(darkcolors,1)[0])
            ax_num+=1
    plt.subplots_adjust(hspace = 0.5)
data3 = data3.fillna(0)
d_ = data_merge.iloc[:,6:-1]

boxplot1(data4,d_,4,4)
plt.savefig('&#x539F;&#x6570;&#x636E;&#x4E0E;&#x8868;&#x5355;3&#x6570;&#x636E;&#x7BB1;&#x7EBF;&#x56FE;&#x5206;&#x6790;&#x5206;&#x5E03;&#x60C5;&#x51B5;')
plt.show()

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

分别对每个特征含量进行范围性变化,期间控制其他特征的含量不变,使用 _f1-score_作为指标量化预测结果,若样本点预测结果不变,即分类结果对单个特征变化不敏感,分类结果具有稳定性。

2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

Original: https://blog.csdn.net/weixin_46707493/article/details/127348898
Author: 小文大数据
Title: 2022全国数学建模-C 题复盘 古代玻璃制品的成分分析与鉴别

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/729617/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球