├── LICENSE ├── README.md └── code ├── ARIMA时间序列分析预测.py ├── Apriori关联规则算法.py ├── BP神经网络.py ├── DBSCAN聚类算法.py ├── GMM聚类模型.py ├── HMM算法.py ├── K均值聚类.py ├── LDA主题分析.py ├── LDA降维.py ├── LOF算法.py ├── LSTM神经网络.py ├── MK趋势检验和突变检验.py ├── Prophet时间序列分析和预测.py ├── TOPSIS法.py ├── XGboost算法回归与分类.py ├── logit回归(逻辑回归).py ├── 主成分分析法.py ├── 假设检验.py ├── 回归分析.py ├── 多因子分析.py ├── 层次分析法.py ├── 层次聚类.py ├── 插值方法.py ├── 数据共线性处理.py ├── 数据分布拟合并随机生成.py ├── 数据预处理.py ├── 时间序列处理与分解.py ├── 机器学习回归与分类.py ├── 标准化与数据变换.py ├── 模糊综合评价法.py ├── 灰色关联分析.py ├── 灰色预测模型.py ├── 熵权法.py ├── 特征选择.py ├── 目标规划.py ├── 相关性分析.py ├── 秩和比综合评价法.py ├── 算法指标.py ├── 粒子群算法.py ├── 自然语言处理.py ├── 蒙特卡洛模拟.py ├── 贝叶斯网络.py └── 高斯过程回归.py /README.md: -------------------------------------------------------------------------------- 1 | # 数学建模算法大全 2 | 3 | **前言**:本项目包含了美赛、国赛等数模赛事的各大常用数学建模算法的Python模板(均为笔者自己整理,里面还有很多的可视化),可供学习参考,欢迎加QQ<2629105870@qq.com>互相学习讨论。 4 | 5 | **算法目录** 6 | 7 | 1. ARIMA时间序列预测模型 8 | 2. BP神经网络 9 | 3. DBSCAN聚类算法 10 | 4. HMM算法 11 | 5. K均值聚类算法 12 | 6. LSTM神经网络 13 | 7. MK趋势检验和突变检验 14 | 8. TOPSIS法 15 | 9. XGboost算法 16 | 10. Logistic Regression(逻辑回归) 17 | 11. 主成分分析法 18 | 12. 假设检验 19 | 13. 多因子分析 20 | 14. 层次分析法 21 | 15. 层次聚类算法 22 | 16. 各种插值法 23 | 17. 数据分布拟合 24 | 18. 数据预处理算法 25 | 19. 模糊综合评价法 26 | 20. 秩和比综合评价法 27 | 21. 灰色关联分析 28 | 22. 灰色预测模型 29 | 23. 熵权法 30 | 24. 规划算法 31 | 25. 粒子群算法 32 | 26. 高斯过程回归 33 | 27. 贝叶斯网络 34 | 28. 蒙特卡洛模拟 35 | 29. 相关性分析 36 | 30. Apriori关联规则算法 37 | 31. LDA主题分析 38 | 32. LDA降维算法 39 | 33. Prophet算法 40 | 34. 数据共线性处理 41 | 42 | --- 43 | 44 | **算法分类大纲** 45 | 46 | ![image-20230419183345023](https://i.postimg.cc/HnTKYRNC/image-20230419183345023.png) 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /code/ARIMA时间序列分析预测.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | import statsmodels.api as sm 5 | from statsmodels.tsa.stattools import adfuller as ADF 6 | import warnings 7 | from statsmodels.stats.diagnostic import acorr_ljungbox 8 | from statsmodels.graphics.api import qqplot 9 | import itertools 10 | import seaborn as sns 11 | from scipy.stats import t 12 | 13 | #主要的思想就是先利用训练数据进行定阶数(其实也就是分成训练集测试集的思想),对训练数据的模型进行检验,最后将全部数据送入模型对后面未知的数据进行预测 14 | 15 | warnings.filterwarnings('ignore') 16 | #首先导入数据 17 | data=pd.read_csv('D:\\学习资源\\学习资料\\数据\\ChinaBank.csv') #将Date列设置为索引,parse_dates是将日期格式进行转化 18 | #或者也可以利用下面的代码进行日期转化 19 | data['Date']=pd.to_datetime(data['Date']) 20 | data=data[['Date','Close']] 21 | total_data=data.iloc[:127,:] #读取需要的数据 22 | 23 | #下面进行展示序列(这里是展示选取的) 24 | '''plt.figure(figsize=(8,6)) 25 | plt.tick_params(size=5,labelsize = 13) #坐标轴 26 | plt.grid(alpha=0.3) #是否加网格线· 27 | plt.plot(train_data['Date'],total_data['Close']) 28 | plt.show()''' 29 | 30 | #下面进行平稳性检验,首先是差分方法同时展示图(这个可以进行主观的观察下数据) 31 | total_data['Close_diff1']=total_data['Close'].diff(1) #一阶差分 32 | total_data['Close_diff2']=total_data['Close_diff1'].diff(1) #二阶差分 33 | total_data['Close_diff1']=total_data['Close_diff1'].fillna(0) #填补空值 34 | total_data['Close_diff2']=total_data['Close_diff2'].fillna(0) #填补空值 35 | print(total_data['Close_diff1']) 36 | print(total_data['Close_diff2']) 37 | train_data=total_data.iloc[:84,:] #划分训练集 38 | test_data=total_data.iloc[83:127,:] #划分测试集 39 | '''fig = plt.figure(figsize=(15,6)) 40 | ax1 = fig.add_subplot(131) 41 | ax1.plot(total_data['Date'],total_data['Close']) 42 | ax2 = fig.add_subplot(132) 43 | ax2.plot(total_data['Date'],total_data['Close_diff1']) 44 | ax3 = fig.add_subplot(133) 45 | ax3.plot(total_data['Date'],total_data['Close_diff2']) 46 | plt.show()''' 47 | 48 | #下面是定阶差分,利用ADF检验(单位根检验)数据的平稳性(注意只要看第2个p值即可,如果小于0.05,则说明数据不存在单位根,平稳性检验通过)这个是更加准确判断 49 | diff0_adf=ADF(total_data['Close']) 50 | diff1_adf=ADF(total_data['Close_diff1']) 51 | diff2_adf=ADF(total_data['Close_diff2']) 52 | print('diff0',diff0_adf) 53 | print('diff1',diff1_adf) 54 | print('diff2',diff2_adf) 55 | #由上面的内容可确定差分为2 56 | 57 | #平稳性检验通过后进行白噪声检验(只有非白噪声序列才能利用ARIMA模型)(可以看第二个和第4个参数,p值小于0.05则说明其是非白噪声序列,序号表示利用几阶滞后) 58 | res_ljungbox=acorr_ljungbox(total_data['Close_diff2'],lags=24, boxpierce=True, return_df=True) #boxpierce是表示不仅返回QLB统计量检验结果还返回QBP统计量检验结果,return_df表示以dataframe的格式进行返回 59 | print('ljungbox检验',res_ljungbox) #可以看出在1到24阶滞后项均通过了检验,p值小于0.05 60 | 61 | #下面进行确定p和q的阶数(注意下面也可以利用原始的所有数据进行操作,并不需要划分训练集和测试集) 62 | #方法1利用acf(自相关系数)和pacf(偏自相关系数)绘制图,利用拖尾和截尾来定阶 63 | plt.figure(figsize=(12,8)) 64 | ax1=plt.subplot(211) 65 | sm.graphics.tsa.plot_acf(train_data['Close_diff2'], lags=20,ax=ax1) #注意要利用差分后的数据进行做 66 | ax1.set_xlabel('Order',fontsize=13) 67 | ax1.set_ylabel('Autocorrelation coefficient',fontsize=13) 68 | ax2=plt.subplot(212) 69 | sm.graphics.tsa.plot_pacf(train_data['Close_diff2'], lags=20,ax=ax2) 70 | #自动调节子图之间的间距,防止一些坐标轴标签重合 71 | plt.tight_layout() 72 | ax2.set_xlabel('Order',fontsize=13) 73 | ax2.set_ylabel('Partial autocorrelation coefficient',fontsize=13) 74 | plt.show() 75 | 76 | #方法2,利用AIC和BIC准则进行参数估计评价,网格搜索最佳的p和q(最小的BIC则是最佳的) 77 | p_min=0 #AR的最小阶数 78 | p_max=5 #AR的最大阶数 79 | q_min=0 #MA的最小阶数 80 | q_max=5 #MA的最大阶数 81 | d=2 #目前求得的差分阶数 82 | #下面进行构建bic的datarame 83 | bic_dataframe=pd.DataFrame(index=[f'AR{i}' for i in range(p_min,p_max+1)], 84 | columns=[f'MA{i}' for i in range(q_min,q_max+1)]) 85 | for p,q in itertools.product(range(p_min,p_max+1),range(q_min,q_max+1)): #这个函数的作用就是嵌套for循环 86 | if p==0 and q==0: #如果AR和MA的阶数都是0的话就没有bic 87 | bic_dataframe.loc[f'MA{p}',f'MA{q}']=np.nan 88 | continue 89 | try: 90 | model=sm.tsa.ARIMA(train_data['Close_diff2'],order=(p,d,q)) #传入训练数据和参数 91 | result = model.fit(method='innovations_mle') #训练模型 92 | bic_dataframe.loc[f'AR{p}',f'MA{q}']=result.aic #计算bic,同理其也可以计算AIC 93 | except: 94 | continue 95 | bic_dataframe=bic_dataframe[bic_dataframe.columns].astype(float) #将数据均变成浮点数 96 | #下面进行绘制bic热点矩阵图 97 | plt.figure(figsize=(8,6)) 98 | sns.heatmap(bic_dataframe, 99 | mask=bic_dataframe.isnull(), 100 | annot=True, 101 | fmt='.2f', 102 | cmap='Spectral') #cmap或者不指定也行 103 | plt.title('BIC',fontsize=15) 104 | plt.show() #从图中我们可以看出最佳的是(p,d,q)为(0,2,3)即MA(3)模型 105 | 106 | #下面是更简单的方式得到最佳p和q(利用AIC和BIC)(速度较慢,不推荐) 107 | #train_results = sm.tsa.arma_order_select_ic(train_data['Close_diff2'], ic=['aic', 'bic'], trend='nc', max_ar=8, max_ma=8) 108 | #print('AIC', train_results.aic_min_order) 109 | #print('BIC', train_results.bic_min_order) 110 | 111 | #下面对模型进行检验(注意对训练集数据进行检验)(残差序列的随机性检验或者也可以检测参数估计的显著性(t检验))残差序列(1阶以后)要全部在2倍标准差以内 112 | model = sm.tsa.ARIMA(train_data['Close_diff2'], order=(0, 2, 3)) 113 | results = model.fit() 114 | resid = results.resid #赋值残差序列 115 | plt.figure(figsize=(12,8)) 116 | sm.graphics.tsa.plot_acf(resid.values.squeeze(), lags=40) 117 | plt.show() 118 | 119 | #下面也是对模型进行检验(对残差序列的正态性进行检验) 120 | qqplot(resid, line='q',fit=True) 121 | plt.tick_params(size=5,labelsize = 13) #坐标轴 122 | plt.grid(alpha=0.3) #是否加网格线 123 | plt.title('QQ-normality test',fontsize=15) 124 | plt.xlabel('Theoretical Quantiles',fontsize=13) 125 | plt.ylabel('Sample Quantiles',fontsize=13) 126 | plt.show() 127 | 128 | #首先重新构建全部的数据(将日期作为索引) 129 | new_total_dataframe=pd.DataFrame({'Close_diff2':total_data['Close_diff2'].tolist()},index=total_data['Date']) 130 | #下面进行创建模型(利用差分后的数据)注意是要进行拟合处理后的数据 131 | model=sm.tsa.ARIMA(new_total_dataframe, order=(0, 2, 3)) #设置模型 132 | result=model.fit(method='innovations_mle') #这里是进行模型的拟合过程 133 | #下面是选取一段时间节点进行测试 134 | test_predict=result.predict(start=str('2014-04'),end=str('2014-06-30'),dynamic=False) #04- 06-30 135 | #下面是计算训练集中预测的置信区间(可以进行绘制置信区间图) 136 | resid=result.resid['2014-04':'2014-06-30'] #注意index是带日期的 137 | # 置信系数 138 | conf_level = 0.95 139 | # 残差标准误差 140 | std_error = np.std(resid) #(p+q+d-1) 141 | # 计算置信区间 142 | n = len(new_total_dataframe['Close_diff2']) 143 | df = n - 4 -2 - 0 + 1 144 | t_value = t.ppf(1 - (1 - conf_level) / 2, df) 145 | lower = result.fittedvalues['2014-04':'2014-06-30'] - t_value * std_error #置信区间上界 146 | upper = result.fittedvalues['2014-04':'2014-06-30'] + t_value * std_error #置信区间下界 147 | 148 | #将小于0的变为0(如果没有这个需求的话就不用了) 149 | """new_lower=[] 150 | for i in lower: 151 | if i>0: 152 | new_lower.append(i) 153 | else: 154 | new_lower.append(0)""" 155 | 156 | #下面进行可视化(测试集预测的数据和原始数据进行对比) 157 | plt.figure(figsize=(8,6)) 158 | plt.tick_params(size=5,labelsize = 13) #坐标轴 159 | plt.grid(alpha=0.3) #是否加网格线 160 | plt.plot(total_data['Date'][62:127],test_predict.tolist(),alpha=0.5,color='#fe0000',label='Predictive value') #62:127 161 | plt.plot(total_data['Date'][62:127],total_data.iloc[62:127,3].tolist(),alpha=0.5,color='b',label='Original value') 162 | plt.scatter(total_data['Date'][62:127],test_predict.tolist(),alpha=0.5,color='#fe0000',s=10) 163 | plt.scatter(total_data['Date'][62:127],total_data.iloc[62:127,3].tolist(),alpha=0.5,color='b',s=10) 164 | #下面进行绘制95%置信区间 165 | plt.fill_between(total_data['Date'][62:127],lower,upper,alpha=0.3,color='#fe0000',label='95% confidence interval') 166 | plt.legend() 167 | plt.xticks(rotation=30) 168 | plt.xlabel('Date',fontsize=13) 169 | plt.ylabel('Close diff2',fontsize=13) 170 | plt.title('Predicted value vs. original value',fontsize=15) 171 | plt.show() 172 | 173 | #下面进行模型的检验(R方等) 174 | #第一种计算R方的方式 175 | def computeCorrelation(x, y): #其中x,y均为序列,x是预测值,y是真实值,这里是计算Pearson相关系数,最后需要平方注意 176 | xBar = np.mean(x) #求预测值均值 177 | yBar = np.mean(y) #求真实值均值 178 | covXY = 0 179 | varX = 0 #计算x的方差和 180 | varY = 0 #计算y的方差和 181 | for i in range(0, len(x)): 182 | diffxx = x[i] - xBar #预测值减预测值均值 183 | diffyy = y[i] - yBar #真实值减真实值均值 184 | covXY += (diffxx * diffyy) 185 | varX += diffxx ** 2 186 | varY += diffyy ** 2 187 | return covXY/np.sqrt(varX*varY) 188 | print('R方',computeCorrelation(test_predict.tolist(),total_data.iloc[62:127,3].tolist())**2) #输出第1种R方指标,注意输入数据一定是可迭代的列表和序列,同时要注意时间要对齐 189 | 190 | #下面进行预测后面的值(未知的值)这里是对差分两次的数据进行预测 191 | steps=20 #往后预测的天数 192 | forcast_diff2=result.forecast(steps=steps,alpha=0.05).tolist()#step就是往后预测值的数量,exog可以忽略,置信区间是1-alpha 193 | # 计算置信区间 194 | # 进行 Monte Carlo 模拟,生成未来预测值的分布 195 | num_simulations = 1000 # 假设进行 1000 次 Monte Carlo 模拟 196 | simulations = np.zeros((num_simulations, steps)) 197 | for i in range(num_simulations): 198 | residuals = np.random.choice(result.resid, size=steps) 199 | simulation = forcast_diff2 + residuals #注意其中的residuals是有正有负的 200 | simulations[i] = simulation 201 | # 计算置信区间 202 | conf_level = 0.95 # 置信水平 203 | lower_diff2 = np.percentile(simulations, (1 - conf_level) / 2 * 100, axis=0) 204 | upper_diff2 = np.percentile(simulations, (1 + conf_level) / 2 * 100, axis=0) 205 | 206 | #注意如果利用了差分还要对最终的预测数据进行还原(这里是对二阶差分进行还原) 207 | forcast_diff1=[] #存储预测的1阶差分数据 208 | forcast_data=[] #存储预测原始值数据 209 | lower=[] 210 | lower_diff1=[] 211 | upper=[] 212 | upper_diff1=[] 213 | 214 | for i in range(len(forcast_diff2)): 215 | if i == 0: 216 | #对原始序列的(注意diff1数据的第一个为空值,diff2前两个数据都为空值) 217 | forcast_diff1.append(total_data['Close_diff1'].tolist()[-1]+forcast_diff2[i]) 218 | forcast_data.append(forcast_diff1[i]+total_data['Close'].tolist()[-1]) 219 | #对下限置信区间 220 | lower_diff1.append(total_data['Close_diff1'].tolist()[-1] + lower_diff2[i]) 221 | lower.append(lower_diff1[i] + total_data['Close'].tolist()[-1]) 222 | #对上限置信区间 223 | upper_diff1.append(total_data['Close_diff1'].tolist()[-1] + upper_diff2[i]) 224 | upper.append(upper_diff1[i] + total_data['Close'].tolist()[-1]) 225 | else: 226 | # 对原始序列的 227 | forcast_diff1.append(forcast_diff1[i-1]+forcast_diff2[i]) 228 | forcast_data.append(forcast_data[i-1]+forcast_diff1[i]) 229 | # 对下限置信区间 230 | lower_diff1.append(forcast_diff1[i-1] + lower_diff2[i]) 231 | lower.append(forcast_data[i-1] + lower_diff1[i]) 232 | # 对上限置信区间 233 | upper_diff1.append(forcast_diff1[i-1] + upper_diff2[i]) 234 | upper.append(forcast_data[i-1] + upper_diff1[i]) 235 | 236 | print('forcast_diff2',forcast_diff2) #预测的2阶差分数据 237 | print('forcast_diff1',forcast_diff1) #预测的1阶差分数据 238 | print('forcast_data',forcast_data) #预测的原始数据 239 | 240 | #最后进行绘制预测的图像(需要连接最后一个数据和第一个预测的数据,同时需要再设置一个时间序列跟预测数据相对应的,然后进行绘制即可) 241 | forecast_date=pd.date_range('30/6/2014',periods=steps+1,freq='D') #表示生成2014年从6月30日开始的20天日期数据 242 | forcast_data.insert(0,total_data.iloc[:,1].tolist()[-1]) #在第一个位置插入原始数据的最后一个数,防止绘图有断 243 | forecast_series=pd.Series(forcast_data,index=forecast_date) #将预测数据变成序列 244 | #下面是置信区间的求解 245 | 246 | #下面进行绘制图 247 | plt.figure(figsize=(8,6)) 248 | plt.tick_params(size=5,labelsize = 13) #坐标轴 249 | plt.grid(alpha=0.3) #是否加网格线 250 | plt.plot(total_data['Date'],total_data['Close'],alpha=0.5,color='b',label='Original value') 251 | plt.plot(forecast_series,alpha=0.5,color='r',label='Predictive value') 252 | #下面进行绘制置信区间 253 | plt.fill_between(forecast_series.index[1:],lower,upper,alpha=0.3,color='#fe0000',label='95% confidence interval') 254 | #plt.scatter(total_data['Date'],total_data['Close'],alpha=0.5,color='b',s=12) 255 | #plt.scatter(forecast_series,alpha=0.5,color='r',s=12) #目前这个会出现bug 256 | plt.legend() 257 | plt.xticks(rotation=30) 258 | plt.xlabel('Date',fontsize=13) 259 | plt.ylabel('Close',fontsize=13) 260 | plt.title('Forecast Data',fontsize=15) 261 | plt.show() -------------------------------------------------------------------------------- /code/Apriori关联规则算法.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from mlxtend.preprocessing import TransactionEncoder 3 | from mlxtend.frequent_patterns import apriori, association_rules 4 | 5 | # 准备数据(可以用于01数据或者分类数据(将其转化为01多个01变量)),注意可以用定义字符串的形式表现 6 | dataset = [['A', 'B', 'C'], 7 | ['A', 'B', 'D', 'E'], 8 | ['B', 'E', 'F']] 9 | 10 | # 转换数据格式 11 | te = TransactionEncoder() #创建转换数据格式的对象 12 | te_ary = te.fit(dataset).transform(dataset) #转换 13 | df = pd.DataFrame(te_ary, columns=te.columns_) #其实就是每个01变量用True或者false的数据格式(可以自己构建) 14 | print(df) 15 | 16 | # 使用Apriori算法找到频繁项集(出现频率高的,先利用各个项集出现的支持度进行筛选)返回的为dataframe格式 17 | frequent_itemsets = apriori(df, min_support=0.5, use_colnames=True) 18 | 19 | # 生成关联规则,可以利用置信度或者提升度进行筛选出关联规则(返回的为dataframe格式) 20 | # 注意其中的metrix包含的指标有:"support"(支持度)"confidence"(置信度)"lift"(提升度)"leverage"(杠杆)"conviction"(确信度)具体公式科参考文档 21 | rules = association_rules(frequent_itemsets, metric="lift", min_threshold=0.7) 22 | 23 | #进行保存关联规则数据 24 | rules.to_csv('',index=None) 25 | 26 | # 输出频繁项集和关联规则 27 | print("频繁项集:") 28 | print(frequent_itemsets) 29 | print("\n关联规则:") 30 | print(rules) #第一个参数表示前项,第二个参数表示后项(对于计算支持度、提升度来说没有先后区分关系),输出筛选后项集的各种指标包括支持度、置信度、提升度等等 31 | -------------------------------------------------------------------------------- /code/BP神经网络.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | import seaborn as sns 5 | from sklearn.model_selection import train_test_split 6 | from sklearn.preprocessing import StandardScaler 7 | import keras 8 | from keras import optimizers 9 | from keras.models import Sequential 10 | from keras.layers import Dense,Dropout,Activation 11 | import tensorflow as tf 12 | from keras.utils.vis_utils import plot_model,model_to_dot #绘制模型配置图 13 | from keras.callbacks import ModelCheckpoint,EarlyStopping,ReduceLROnPlateau 14 | from sklearn.model_selection import StratifiedKFold,KFold 15 | from sklearn import metrics 16 | 17 | #先进行多维输入和单维输出的神经网络(分类、回归均可) 18 | pre_data=pd.DataFrame(pd.read_excel('D:\\国赛数模优秀论文\\2017\\Problems\\B\\附件一:已结束项目任务数据.xls')) #原始训练数据 19 | new_data=pd.DataFrame(pd.read_excel('D:\\国赛数模优秀论文\\2017\\Problems\\B\\附件三:新项目任务数据.xls')) 20 | pre_data.drop(columns='任务号码',inplace=True) 21 | new_data.drop(columns='任务号码',inplace=True) 22 | X=pre_data.iloc[:,:2] #原始X数据 23 | Y=pre_data.iloc[:,-1] #原始标签数据 24 | 25 | #下面进行随机划分数据集(还可以用交叉验证进行更好的改进) 26 | x_train,x_test,y_train,y_test=train_test_split(X,Y,test_size=0.2,shuffle=True) #随机划分训练集和测试集,一定要打乱,能提高精度 27 | 28 | #下面进行数据的标准化(均值标准差的那个) 29 | sc=StandardScaler() #创建归一器 30 | x_train=sc.fit_transform(x_train) 31 | x_test=sc.fit_transform(x_test) 32 | 33 | #定义随机种子(使其能够复现) 34 | #np.random.seed(7) 35 | #先初始化一个BP神经网络 36 | model=Sequential() 37 | #加入输入层 38 | model.add(Dense(units=100,input_dim=2,kernel_initializer='glorot_uniform',activation='relu')) #unit是神经元的数量,input_dim是输入的纬度,activation是激活函数 39 | model.add(Dropout(rate=0.1)) #加入dropout防止过拟合 40 | #加入隐含层 41 | model.add(Dense(units=50,input_dim=100,kernel_initializer='glorot_uniform',activation='relu')) #这里的input_dim要与上一层的神经员个数对上 42 | model.add(Dropout(rate=0.1)) #加入dropout防止过拟合 43 | model.add(Dense(units=50,input_dim=50,kernel_initializer='glorot_uniform',activation='relu')) 44 | model.add(Dropout(rate=0.1)) #加入dropout防止过拟合 45 | model.add(Dense(units=20,input_dim=50,kernel_initializer='glorot_uniform',activation='relu')) 46 | model.add(Dropout(rate=0.1)) #加入dropout防止过拟合 47 | model.add(Dense(units=10,input_dim=20,kernel_initializer='glorot_uniform',activation='relu')) 48 | model.add(Dropout(rate=0.1)) #加入dropout防止过拟合 49 | #添加输出层 50 | model.add(Dense(units=1,input_dim=10,kernel_initializer='glorot_uniform')) 51 | model.add(Activation('sigmoid')) #也可以这么写 在0-1分类的时候最后用sigmoid、 52 | 53 | #下面进行优化器的配置(自定义优化器可以进行微调操作) 54 | SGD=optimizers.gradient_descent_v2.SGD(lr=0.01,decay=1e-6, momentum=0.9, nesterov=True) 55 | Adam=optimizers.adam_v2.Adam(lr=0.01,decay=1e-6, beta_1=0.9, beta_2=0.999, epsilon=None,amsgrad=False) 56 | 57 | #下面进行按照验证集精度保存模型的最佳参数,其中monitor是指用什么参数来衡量,save_best_only表示只保存一种,mode是模式有(min,max,auto) 58 | checkpoint = ModelCheckpoint('weights.hdf5' , monitor = 'val_accuracy' , save_best_only = True,mode='auto') #注意monitor目前这个设置的是分类问题的,回归问题要换成MSE 59 | 60 | #下面进行配置模型的提早退出,如果验证集精度在5轮没有上升则退出训练。 61 | #early_stopping = EarlyStopping(monitor = 'val_accuracy' , patience = 5) 62 | 63 | #下面是微调学习率,如果在5轮内验证集精度未上升,则学习率减半 64 | reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.5,patience=10, min_lr=0.0001) 65 | 66 | #下面进行配置模型参数 67 | model.compile(optimizer=SGD,loss='binary_crossentropy',metrics=['accuracy']) #这里用交叉熵损失函数,注意可以进行转换,回归问题可以用mean_square_error,也就是说模型的loss和精度都用MSE表示,metrix回归问题用’mse‘ 68 | 69 | #可视化模型 70 | plot_model(model,to_file='model.png',show_shapes=True,dpi=96) #绘制模型的配置图 71 | 72 | #下面进行训练操作 73 | history=model.fit(x_train,y_train,batch_size=8,epochs=50,workers=4,validation_split=0.2,callbacks=[checkpoint,reduce_lr]) #设置batch_size和epoch,同时还设置验证集为0.2,同时存储训练过程的各种数据给history 74 | 75 | #读取训练过程中的参数 76 | train_loss=history.history['loss'] #寻来你及 77 | val_loss=history.history['val_loss'] 78 | train_accuracy=history.history['accuracy'] 79 | val_accuracy=history.history['val_accuracy'] 80 | epochs=np.arange(1,len(train_accuracy)+1) #轮数序列 81 | 82 | #下面进行绘制训练精度和验证集精度曲线,还有训练集的loss和验证集的loss曲线 83 | plt.figure(figsize=(12,6)) #长、宽 84 | plt.subplot(121) 85 | plt.tick_params(size=5,labelsize = 13) #坐标轴 86 | plt.grid(alpha=0.3) #是否加网格线 87 | plt.plot(epochs,train_loss,marker='o',lw=2,label='train loss') 88 | plt.plot(epochs,val_loss,marker='*',lw=2,label='val loss') 89 | plt.xlabel('epochs',fontsize=13) 90 | plt.ylabel('loss',fontsize=13) 91 | plt.title('Training set and test set loss change',fontsize=15) 92 | plt.legend() 93 | plt.subplot(122) 94 | plt.tick_params(size=5,labelsize = 13) #坐标轴 95 | plt.grid(alpha=0.3) #是否加网格线 96 | plt.plot(epochs,train_accuracy,marker='o',lw=2,label='train loss') 97 | plt.plot(epochs,val_accuracy,marker='*',lw=2,label='val loss') 98 | plt.xlabel('epochs',fontsize=13) 99 | plt.ylabel('accuracy',fontsize=13) 100 | plt.title('Training set and test set accuracy change',fontsize=15) 101 | plt.legend() 102 | plt.show() 103 | 104 | #下面进行预测 105 | model.load_weights('weights.hdf5') #载入最佳参数的模型 106 | y_pred_prob=model.predict(x_test) #概率预测,可以用于绘制ROC曲线 107 | y_pred=[] #存储预测值 108 | for data in y_pred_prob: 109 | if data>0.5: 110 | y_pred.append(1) 111 | else: 112 | y_pred.append(0) 113 | 114 | fpr,tpr,_=metrics.roc_curve(y_test,y_pred_prob) #计算ROC曲线点值 115 | roc_auc=metrics.auc(fpr,tpr) #计算ROC曲线下的面积 116 | 117 | #下面进行绘制测试集的ROC曲线(前面都是训练集和验证集)注意如果是多分类的话,就对原始数据分类进行one-hot编码,同时最后一层利用sigmoid函数 118 | #绘制ROC曲线 119 | plt.figure(figsize=(8,6)) 120 | plt.plot(fpr, tpr,label='ROC curve (area = {0:0.2f})'''.format(roc_auc), 121 | color='deeppink', linewidth=4) 122 | plt.stackplot(fpr,tpr,colors='steelblue',alpha=0.5,edgecolor='black') 123 | plt.plot([0, 1], [0, 1], 'k--', lw=2) #绘制对角线 124 | plt.text(0.5,0.3,f'ROC curve(area = {roc_auc:.4f})',fontsize=13) #打上标签 125 | plt.legend(loc='lower right') 126 | plt.xlabel('False Positive Rate',fontsize=13) 127 | plt.ylabel('True Positive Rate',fontsize=13) 128 | plt.title('ROC-Kurve',fontsize=15) 129 | plt.show() 130 | 131 | #下面进行绘制测试集的混淆矩阵 132 | confusion_matrix=metrics.confusion_matrix(y_test,y_pred) #求出混淆矩阵 133 | plt.figure(figsize=(8,6)) 134 | sns.heatmap(confusion_matrix,cmap="YlGnBu_r",fmt="d",annot=True) 135 | plt.xlabel('prediction category',fontsize=13) #横轴是预测类别 136 | plt.ylabel('real category',fontsize=13) #数轴是真实类别 137 | plt.title('confusion matrix',fontsize=15) 138 | plt.show() 139 | 140 | 141 | ########################################################################################### 142 | ########################################交叉验证使用######################################### 143 | ########################################################################################### 144 | 145 | #下面进行交叉验证(思路是不将训练集进行分离了,在训练过程中用keras中自带的validation进行每次不断的测试,而把交叉验证分出来验证集作为最终的测试集进行使用) 146 | #先进行多维输入和单维输出的神经网络(分类、回归均可) 147 | pre_data=pd.DataFrame(pd.read_excel('D:\\国赛数模优秀论文\\2017\\Problems\\B\\附件一:已结束项目任务数据.xls')) #原始训练数据 148 | new_data=pd.DataFrame(pd.read_excel('D:\\国赛数模优秀论文\\2017\\Problems\\B\\附件三:新项目任务数据.xls')) 149 | pre_data.drop(columns='任务号码',inplace=True) 150 | new_data.drop(columns='任务号码',inplace=True) 151 | X=pre_data.iloc[:,:2] #原始X数据 152 | Y=pre_data.iloc[:,-1] #原始标签数据 153 | #下面进行数据的标准化(均值标准差的那个,且作用于dataframe,同时还将其转化未nddarry格式) 154 | sc=StandardScaler() #创建归一器 155 | X=sc.fit_transform(X) 156 | 157 | #使用分层交叉验证(每一折中每个标签的类别数相同)同时打乱原始的数据集先 158 | kf=StratifiedKFold(n_splits=5, shuffle=True) #5折交叉验证 159 | score_list=[] #存储每次交叉验证分出的测试集的精确度,注意这里将数据转化成了ndarray的数据格式,使其能够在下面用索引取值 160 | 161 | for train_index,test_index in kf.split(X,Y): 162 | # 先初始化一个BP神经网络 163 | model = Sequential() 164 | # 加入输入层 165 | model.add(Dense(units=100, input_dim=2, kernel_initializer='glorot_uniform', 166 | activation='relu')) # unit是神经元的数量,input_dim是输入的纬度,activation是激活函数 167 | model.add(Dropout(rate=0.1)) # 加入dropout防止过拟合 168 | # 加入隐含层 169 | model.add(Dense(units=50, input_dim=100, kernel_initializer='glorot_uniform', 170 | activation='relu')) # 这里的input_dim要与上一层的神经员个数对上 171 | model.add(Dropout(rate=0.1)) # 加入dropout防止过拟合 172 | model.add(Dense(units=50, input_dim=50, kernel_initializer='glorot_uniform', activation='relu')) 173 | model.add(Dropout(rate=0.1)) # 加入dropout防止过拟合 174 | model.add(Dense(units=20, input_dim=50, kernel_initializer='glorot_uniform', activation='relu')) 175 | model.add(Dropout(rate=0.1)) # 加入dropout防止过拟合 176 | model.add(Dense(units=10, input_dim=20, kernel_initializer='glorot_uniform', activation='relu')) 177 | model.add(Dropout(rate=0.1)) # 加入dropout防止过拟合 178 | # 添加输出层 179 | model.add(Dense(units=1, input_dim=10, kernel_initializer='glorot_uniform')) 180 | model.add(Activation('sigmoid')) # 也可以这么写 在0-1分类的时候最后用sigmoid、 181 | # 下面进行优化器的配置(自定义优化器可以进行微调操作) 182 | SGD = optimizers.gradient_descent_v2.SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True) 183 | Adam = optimizers.adam_v2.Adam(lr=0.01, decay=1e-6, beta_1=0.9, beta_2=0.999, epsilon=None, amsgrad=False) 184 | # 下面进行按照验证集精度保存模型的最佳参数,其中monitor是指用什么参数来衡量,save_best_only表示只保存一种,mode是模式有(min,max,auto) 185 | checkpoint = ModelCheckpoint('weights.hdf5', monitor='val_accuracy', save_best_only=True, mode='auto') 186 | # 下面进行配置模型的提早退出,如果验证集精度在5轮没有上升则退出训练。 187 | # early_stopping = EarlyStopping(monitor = 'val_accuracy' , patience = 5) 188 | # 下面是微调学习率,如果在5轮内验证集精度未上升,则学习率减半 189 | reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=10, min_lr=0.0001) 190 | # 下面进行配置模型参数 191 | model.compile(optimizer=SGD, loss='binary_crossentropy', metrics=['accuracy']) # 这里用交叉熵损失函数,注意可以进行转换 192 | history=model.fit(X[train_index],Y[train_index],batch_size=8,epochs=50,workers=4,validation_split=0.2,callbacks=[checkpoint,reduce_lr]) #设置batch_size和epoch,同时还设置验证集为0.2,同时存储训练过程的各种数据给history 193 | 194 | #下面开始计算每一次交叉验证的测试集精确度 195 | score = model.evaluate(X[test_index], Y[test_index], verbose=0) 196 | score_list.append(score) #存储到列表中 197 | 198 | #读取训练过程中的参数 199 | train_loss=history.history['loss'] #寻来你及 200 | val_loss=history.history['val_loss'] 201 | train_accuracy=history.history['accuracy'] 202 | val_accuracy=history.history['val_accuracy'] 203 | epochs=np.arange(1,len(train_accuracy)+1) #轮数序列 204 | #下面如果想画图的话就和上面一样的操作复制即可 205 | 206 | print(np.mean(score_list)) #输出交叉验证综合精度 207 | 208 | 209 | -------------------------------------------------------------------------------- /code/DBSCAN聚类算法.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | from sklearn.datasets import load_iris #测试的数据集 4 | from sklearn.metrics import silhouette_score 5 | from sklearn.cluster import DBSCAN 6 | from sklearn.neighbors import NearestNeighbors 7 | import matplotlib.pyplot as plt 8 | import seaborn as sns 9 | from mpl_toolkits.mplot3d import Axes3D 10 | from matplotlib import rcParams 11 | 12 | iris=load_iris() #导入数据集 是一个字典类型的数据 13 | X=iris.data[:,2:4] #表示只取特征空间的后两个纬度(但是这里我取了三个特征纬度) 14 | y = iris.target # 将鸢尾花的标签赋值给y 15 | #首先进行数据的标准化 16 | def standardization(data): #data是矩阵,主要功能是进行标准化,输出是经过标准化的矩阵 17 | data_std=[np.std(data[:,i]) for i in range(data.shape[1])] 18 | data_mean=[np.mean(data[:,i]) for i in range(data.shape[1])] 19 | for i in range(data.shape[1]): 20 | data[:,i]=(data[:,i]-data_mean[i])/data_std[i] 21 | return data 22 | scale_X_dataframe=pd.DataFrame(standardization(X),columns=['feature1','feature2']) #对数据进行标准化 23 | #注意如果特征维数过高可以运用降维算法对数据进行降维(但是要确保降维后的数据具有解释意义) 24 | 25 | #下面进行确定两个核心参数(最大半径epsilon和一个簇中最少点数minPts) 26 | #确定epsilon参数,第一种方式(利用肘型图)(注意minPts可以根据经验法则为特征维数的两倍) 27 | nn=NearestNeighbors(n_neighbors=5).fit(scale_X_dataframe) #创建对象,设置K参数,这边是传入被算距离的数据(注意有还可以做一下这个k参数的敏感性分析) 28 | distance,index=nn.kneighbors(scale_X_dataframe) #这里是计算其中的每一个点与原来训练的数据之间每个点的距离,index是与数据最近的训练数据的索引值 29 | #下面进行计算周围K个点的平均距离 30 | mean_distance=np.mean(distance,axis=1)#横向求 31 | #下面进行排序 32 | mean_distance_sort=sorted(mean_distance) #从小到大 33 | #下面进行绘制肘性图进行观察(选择突变的情况就是突然增大的时候) 34 | plt.figure(figsize=(8,6)) 35 | #plt.rc('font',family='Times New Roman') #更改画图字体为Times New Roman 36 | plt.tick_params(size=5,labelsize = 13) #坐标轴 37 | plt.grid(alpha=0.3) #是否加网格线·adwdsdsdsdfgh 38 | plt.plot(np.arange(len(mean_distance_sort)),mean_distance_sort,alpha=0.8,lw=3) 39 | #plt.scatter(np.arange(len(mean_distance_sort)),mean_distance_sort,alpha=0.5,color='b',s=10) 40 | plt.annotate('Mutation point', xy=(140, 0.1668), xytext=(110, 0.2), 41 | arrowprops=dict(arrowstyle='->', connectionstyle='arc3', color='red', lw=2)) #在图中进行标注 42 | plt.xlabel('index',fontsize=13) 43 | plt.ylabel('Average Distance',fontsize=13) 44 | plt.title('The Average Distance From k Points',fontsize=15) 45 | plt.show() #可以观察到epsilon差不多可以取0.17左右 46 | 47 | #第二种方式(利用迭代的思想寻找最优的epsilon和minPts)评价指标是聚类后的轮廓系数 48 | iteration_result=[] #存储最后的结果(里面可以再进行嵌套一层列表存储当前的epsilon、minPts和轮廓系数) 49 | epsilon_iter=np.linspace(0.05,0.3,10) #最大半径的迭代数据 50 | minPts_iter=np.arange(2,9) #最小点数的迭代数据 51 | for epsilon in epsilon_iter: 52 | for minPts in minPts_iter: 53 | DBSCAN_cluster=DBSCAN(eps=epsilon,min_samples=minPts).fit(scale_X_dataframe) #创建DBSCAN模型同时导入参数进行聚类 54 | cluster_num=len(np.unique(DBSCAN_cluster.labels_)) #计算聚类个数(注意其中是包含离群点类别的(如果全部都有类别的话也不一定有离群点,反正要注意观察)) 55 | sil_score=silhouette_score(scale_X_dataframe,DBSCAN_cluster.labels_) #计算轮廓系数 56 | iteration_result.append([epsilon,minPts,cluster_num,sil_score]) #存储数据,分别是最大半径、最小点数、聚类数、轮廓系数 57 | 58 | #下面可以进行可视化操作,(将寻找最优解的过程进行可视化(可以绘制三维图片)) 59 | epsilon_list=[x[0] for x in iteration_result] #存储最大半径列表 60 | minPts_list=[x[1] for x in iteration_result] #存储最少数量点列表 61 | sil_list=[x[3] for x in iteration_result] #存储轮廓系数列表 62 | 63 | #下面开始进行绘制 64 | fig = plt.figure(figsize=(7,5),facecolor='#ffffff') #创建一个画布窗口 65 | ax=Axes3D(fig) #创建三维坐标系(注意要用Axes中才能改拉伸后面的坐标轴) 66 | #下面将背景颜色变透明 67 | ax.w_xaxis.set_pane_color((1.0, 1.0, 1.0, 1.0)) 68 | ax.w_yaxis.set_pane_color((1.0, 1.0, 1.0, 1.0)) 69 | ax.w_zaxis.set_pane_color((1.0, 1.0, 1.0, 1.0)) 70 | #调整背景景网格粗细 71 | ax.xaxis._axinfo["grid"]['linewidth'] = 0.4 72 | ax.yaxis._axinfo["grid"]['linewidth'] = 0.4 73 | ax.zaxis._axinfo["grid"]['linewidth'] = 0.4 74 | #绘制点图 75 | ax.scatter(epsilon_list,minPts_list,sil_list,color='salmon',s=20,alpha=0.8,) #注意一定是ax子图中绘制 76 | #绘制竖线 77 | for i in range(len(epsilon_list)): 78 | ax.plot([epsilon_list[i],epsilon_list[i]],[minPts_list[i],minPts_list[i]],[min(sil_list),sil_list[i]],c='salmon',alpha=0.6,lw=2) 79 | #分别上下旋转和左右旋转,可以自己设置成一个比较好的参数 80 | ax.view_init(20, -32) 81 | #设置z轴的显示范围(注意显示范围) 82 | ax.set_zlim(min(sil_list),max(sil_list)) 83 | #设置坐标轴标签 84 | ax.set_xlabel('Epsilon',fontsize=13) 85 | ax.set_ylabel('MinPts',fontsize=13) 86 | ax.set_zlabel('silhouette coefficient',fontsize=13) 87 | ax.set_title('Silhouette Coefficient For Different Epsilon And MinPts',fontsize=15) 88 | plt.show() 89 | 90 | #下面进行输出最优的参数(根据轮廓系数进行降序排序) 91 | iteration_result_sort=sorted(iteration_result,reverse=True,key=lambda x: x[3]) 92 | best_parameter=iteration_result_sort[2] #存储最优的参数 93 | print(iteration_result_sort) 94 | #根据聚类数轮廓数的最佳,因此我们选择[0.3, 4, 2, 0.743371950414545] 第一个参数是最大半径,第二个参数是最少数量,第三个是聚类数,第四个是轮廓系数 95 | 96 | #下面进行最终聚类 97 | DBSCAN_cluster=DBSCAN(eps=best_parameter[0], min_samples=best_parameter[1]).fit(scale_X_dataframe) 98 | result_data=pd.DataFrame(X,columns=['feature1','feature2']) 99 | result_data['label']=DBSCAN_cluster.labels_ 100 | 101 | #下面进行模型的合理性分析(绘制数据分布图) (针对这种只有两个特征可以直接绘制二维图或者绘制分类矩阵图,或者选取特征进行绘制) 102 | #1分类矩阵图 103 | sns.pairplot(result_data, hue='label', aspect=1.5) 104 | plt.show() 105 | #2特征分类均值簇状柱形图(利用seaborn)具体可参考kmeans-聚类中的绘制过程 106 | #3特征分类箱型图(具体可参考k-means中的绘制过程) 107 | 108 | #下面进行参数敏感性分析(两个核心参数参数)保持一个参数最佳,另外一个参数变化,注意还可以做一下k的最近距离点的平均值的敏感性分析 109 | #先进行epsilon参数的敏感性分析 110 | epsilon_list1=np.linspace(0.05,0.3,10) 111 | sil_list1=[] #存储轮廓系数 112 | cluster_num_list1=[] #存储聚类数目 113 | for epsilon in epsilon_list1: 114 | DBSCAN_cluster = DBSCAN(eps=epsilon, min_samples=best_parameter[1]).fit(scale_X_dataframe) # 创建DBSCAN模型同时导入参数进行聚类 115 | cluster_num_list1.append(len(np.unique(DBSCAN_cluster.labels_))) # 计算并存储聚类个数(注意其中是包含离群点类别的(如果全部都有类别的话也不一定有离群点,反正要注意观察)) 116 | sil_list1.append(silhouette_score(scale_X_dataframe, DBSCAN_cluster.labels_)) # 计算并存储轮廓系数 117 | #下面进行绘制结果图(双坐标轴,一个表示轮廓系数,另外一个表示聚类数) 118 | #config = {"font.family":'Times New Roman'} # 设置字体类型 119 | #rcParams.update(config) 120 | fig, ax1 = plt.subplots(figsize=(8,6)) #设置第一个图 121 | plt.tick_params(size=5,labelsize = 13) #坐标轴 122 | plt.grid(alpha=0.3) #是否加网格线· 123 | #plt.rc('font',family='Times New Roman') #更改画图字体为Times New Roman 124 | plot1=ax1.plot(epsilon_list1,sil_list1,marker='o',alpha=0.5,color='b',lw=2,label='silhouette coefficient Curve') 125 | ax1.set_xlabel('epsilon',fontsize=13) #设置x轴参数 126 | ax1.set_ylabel('silhouette coefficient',fontsize=13) #设置y轴的名称 127 | ax1.set_title('Sensitivity Analysis Of Epsilon',fontsize=15) 128 | ax1.tick_params(axis='y', labelcolor='b',labelsize=13) #设置第一个类型数据y轴的颜色参数 129 | ax1.set_ylim(-0.3,0.9) #调整y轴的显示坐标 130 | ax2 = ax1.twinx() #和第一类数据共享x轴(新设置图) 131 | plot2=ax2.plot(epsilon_list1,cluster_num_list1,color='r',alpha=0.5,marker='*',lw=2,label='Cluster Number Curve') 132 | ax2.set_ylabel('Cluster Number',fontsize=13) #设置ax2的y轴参数 133 | ax2.tick_params(axis='y', labelcolor='r',labelsize=13) #设置ax2的y轴颜色 134 | ax2.set_ylim(1.8,11) 135 | lines=plot1+plot2 136 | ax1.legend(lines,[l.get_label() for l in lines]) #这边进行打上图例 137 | #下面进行打上标签 138 | for i,data in enumerate(sil_list1): 139 | ax1.text(epsilon_list1[i],data+0.001,round(data,3),horizontalalignment='center',fontsize=10) 140 | for i,data in enumerate(cluster_num_list1): 141 | ax2.text(epsilon_list1[i],data+0.1,round(data,0),horizontalalignment='center',fontsize=10) 142 | plt.show() 143 | 144 | #接下来是minPts的敏感性分析 145 | minPts_list1=np.arange(2,16) 146 | sil_list2=[] #存储轮廓系数 147 | cluster_num_list2=[] #存储聚类数目 148 | for minPts in minPts_list1: 149 | DBSCAN_cluster = DBSCAN(eps=best_parameter[0], min_samples=minPts).fit(scale_X_dataframe) # 创建DBSCAN模型同时导入参数进行聚类 150 | cluster_num_list2.append(len(np.unique(DBSCAN_cluster.labels_))) # 计算并存储聚类个数(注意其中是包含离群点类别的(如果全部都有类别的话也不一定有离群点,反正要注意观察)) 151 | sil_list2.append(silhouette_score(scale_X_dataframe, DBSCAN_cluster.labels_)) # 计算并存储轮廓系数 152 | #下面进行绘制结果图(双坐标轴,一个表示轮廓系数,另外一个表示聚类数) 153 | fig, ax1 = plt.subplots(figsize=(8,6)) #设置第一个图 154 | plt.tick_params(size=5,labelsize = 13) #坐标轴 155 | plt.grid(alpha=0.3) #是否加网格线· 156 | #plt.rc('font',family='Times New Roman') #更改画图字体为Times New Roman 157 | plot1=ax1.plot(minPts_list1,sil_list2,marker='o',alpha=0.5,color='b',lw=2,label='silhouette coefficient Curve') 158 | ax1.set_xlabel('MinPts',fontsize=13) #设置x轴参数 159 | ax1.set_ylabel('silhouette coefficient',fontsize=13) #设置y轴的名称 160 | ax1.set_title('Sensitivity Analysis Of MinPts',fontsize=15) 161 | ax1.tick_params(axis='y', labelcolor='b',labelsize=13) #设置第一个类型数据y轴的颜色参数 162 | #ax1.set_ylim(0.45,0.8) 163 | ax2 = ax1.twinx() #和第一类数据共享x轴(新设置图) 164 | plot2=ax2.plot(minPts_list1,cluster_num_list2,color='r',alpha=0.5,marker='*',lw=2,label='Cluster Number Curve') 165 | ax2.set_ylabel('Cluster Number',fontsize=13) #设置ax2的y轴参数 166 | ax2.tick_params(axis='y', labelcolor='r',labelsize=13) #设置ax2的y轴颜色 167 | #ax2.set_ylim(1.8,5) 168 | lines=plot1+plot2 169 | ax1.legend(lines,[l.get_label() for l in lines]) #这边进行打上标签 170 | #下面进行打上标签 171 | for i,data in enumerate(sil_list2): 172 | ax1.text(minPts_list1[i],data+0.001,round(data,3),horizontalalignment='center',fontsize=10) 173 | for i,data in enumerate(cluster_num_list2): 174 | ax2.text(minPts_list1[i],data+0.02,round(data,0),horizontalalignment='center',fontsize=10) 175 | plt.show() 176 | 177 | #下面还可以进行离的最近的个数参数k的敏感性分析(绘制肘形图)(如果前面确定参数是利用肘形图的话可以做一下这个敏感性分析,如果是用迭代出最优的话,就不需要了) 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | -------------------------------------------------------------------------------- /code/GMM聚类模型.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | from sklearn.mixture import GaussianMixture as GMM 4 | from sklearn.metrics import silhouette_score 5 | from matplotlib.patches import Ellipse 6 | from matplotlib import rcParams #导入包 7 | config = {"font.family":'Times New Roman'} # 设置字体类型 8 | rcParams.update(config) #进行更新配置 9 | 10 | # 准备数据 11 | X = np.random.rand(100, 2) 12 | 13 | ######可以先利用AIC、BIC或者轮廓系数确定最优组件个数(也可以用于后续的合理性、准确性和敏感性分析)######### 14 | #先进行拟合模型(各个聚类数) 15 | n_series=np.arange(2,10) 16 | models = [GMM(n_components=n,covariance_type='full',random_state=42).fit(X) for n in n_series] 17 | AIC=[m.aic(X) for m in models] #AIC序列 18 | BIC=[m.bic(X) for m in models] #BIC序列 19 | silhouette=[silhouette_score(X,m.predict(X)) for m in models] #轮廓系数 20 | 21 | #绘制各个指标的可视化曲线,双坐标轴(注意可以加肘点标记),或者利用单个指标均可 22 | fig, ax1 = plt.subplots(figsize=(8,6)) #设置第一个图 23 | plt.tick_params(size=5,labelsize = 13) #坐标轴 24 | plt.grid(alpha=0.3) #是否加网格线· 25 | plot1=ax1.plot(n_series,AIC,linestyle=':',marker='o',lw=2,c='#007172',label='AIC',markersize=3.5) 26 | plot2=ax1.plot(n_series,BIC,linestyle=':',marker='s',lw=2,c='#f29325',label='BIC',markersize=3.5) 27 | ax1.set_title('聚类数变动的各指标可视化',fontsize=15) 28 | ax1.set_xlabel('Clusters',fontsize=13) 29 | ax1.set_ylabel('AIC or BIC value',fontsize=13) 30 | #ax1.set_ylim(min(y1)-0.1,1.1) #设置显示范围 31 | ax2=ax1.twinx() #和第一类数据共享x轴(新设置图) 32 | plot3=ax2.plot(n_series,silhouette,linestyle=':',color='#d94f04',marker='*',lw=2,label='Silhouette score',markersize=3.5) 33 | ax2.set_ylabel('Silhouette score',fontsize=13) #设置ax2的y轴参数 34 | #进行打上图例 35 | lines=plot1+plot2+plot3 #目前只能添加线,如果有不同柱形或者其他的,可以手动将图例一个放左边,一个放右边,下面这两行代码就可以去掉(注意对于辅助线来说可以绘制一个空的线对象再进行添加) 36 | ax1.legend(lines,[l.get_label() for l in lines]) #打上图例 37 | #下面进行打上标签(太乱了的话可不加) 38 | for i,data in enumerate(AIC): 39 | ax1.text(n_series[i],data+0.001,round(data,0),horizontalalignment='center',fontsize=10) 40 | for i,data in enumerate(BIC): 41 | ax1.text(n_series[i],data+0.02,round(data,0),horizontalalignment='center',fontsize=10) 42 | for i,data in enumerate(silhouette): 43 | ax2.text(n_series[i],data+0.001,round(data,3),horizontalalignment='center',fontsize=10) 44 | #plt.savefig('',format='svg',bbox_inches='tight') 45 | plt.show() 46 | 47 | #######假设聚类数选择3进行绘制聚类结果分布图(概率密度图)############ 48 | n=3 49 | gmm=GMM(n_components=3,covariance_type='full',random_state=42) 50 | gmm.fit(X) 51 | print(gmm.covariances_) 52 | 53 | #绘制聚类结果图(二维特征情况下) 54 | #给定的位置和协方差画一个椭圆 55 | def draw_ellipse(position,covariance,n_cluster=3,ax=None, **kwargs): 56 | """ 57 | :param position: 均值 58 | :param covariance: 方差 59 | :param n_cluster: 聚类个数 60 | :param ax: 画板 61 | :param kwargs: 其余参数例如alpha非透明度 62 | :return: 63 | """ 64 | #将协方差转换为主轴 65 | if covariance.shape == (2, 2): 66 | U, s, Vt = np.linalg.svd(covariance) 67 | angle = np.degrees(np.arctan2(U[1, 0], U[0, 0])) 68 | width, height = 2 * np.sqrt(s) 69 | else: 70 | angle = 0 71 | width, height = 2 * np.sqrt(covariance) 72 | 73 | #画出椭圆 74 | for nsig in range(1, n_cluster+1): 75 | ax.add_patch(Ellipse(position, nsig * width, nsig * height,angle,**kwargs)) 76 | 77 | #画图 78 | def plot_gmm(gmm, X,n_cluster=3): 79 | """ 80 | :param gmm: 训练好的模型 81 | :param X: 输入特征集 82 | :param num_cluster: 设定聚类数 83 | :return: 84 | """ 85 | labels = gmm.predict(X) 86 | color_ls=['#007172','#f29325','#d94f04'] 87 | fig,ax = plt.subplots(figsize=(8,6)) 88 | plt.tick_params(size=5, labelsize=13) # 坐标轴 89 | plt.grid(alpha=0.3) # 是否加网格线 90 | #进行绘制散点图 91 | for i in range(n_cluster): #每个类别 92 | ax.scatter(X[labels==i][:,0], X[labels==i][:, 1], c=color_ls[i], s=15,label=f'Category{i+1}') 93 | ax.axis('equal') #画布均衡 94 | w_factor = 0.2 / gmm.weights_.max() #权重 95 | #绘制概率密度的椭圆 96 | for i,(pos, covar, w) in enumerate(zip(gmm.means_,gmm.covariances_,gmm.weights_)): 97 | draw_ellipse(pos, covar, n_cluster=n_cluster,ax=ax,alpha=w * w_factor,color=color_ls[i]) 98 | plt.legend() 99 | plt.title('各类别高斯分布拟合结果', fontsize=15) 100 | plt.xlabel('Feature 1', fontsize=13) 101 | plt.ylabel('Feature 2', fontsize=13) 102 | plt.show() 103 | 104 | #进行绘制 105 | plot_gmm(gmm, X,n_cluster=3) 106 | 107 | ##########得到聚类结果########## 108 | labels=gmm.predict(X) #得到各个样本的标签序列 109 | probs = gmm.predict_proba(X) #得到有一个隐含的概率模型。可以通过其得到簇分配结果的概率(将样本分配到各个聚类簇的概率) 110 | print(labels) 111 | print(probs) 112 | 113 | 114 | -------------------------------------------------------------------------------- /code/HMM算法.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import matplotlib.pyplot as plt 3 | import numpy as np 4 | from hmmlearn import hmm 5 | from sklearn import metrics 6 | from sklearn.preprocessing import label_binarize #用于标签二值化 7 | import seaborn as sns 8 | 9 | #解决第一个和第二个问题:1给定观测序列发生概率(可用于评价模型)2进行预测给定观测序列的隐含状态,,并且注意此时的观测状态是离散的 10 | #设置隐含变量的类别(箱子的类别) 11 | states = ["box 1","box 2","box3"] 12 | n_states=len(states) #类别数 13 | 14 | #设定观察状态的集合(取出球的颜色) 15 | observations = ["red","white"] 16 | n_observations = len(observations) #类别数 17 | 18 | # 设定初始状态分布 19 | start_probability = np.array([0.2, 0.4, 0.4]) 20 | 21 | #设定状态转移概率分布矩阵(有n种隐含状态,矩阵的形状就是n*n) 22 | transition_probability = np.array([ 23 | [0.5, 0.2, 0.3], 24 | [0.3, 0.5, 0.2], 25 | [0.2, 0.3, 0.5]]) 26 | 27 | # 设定观测状态概率矩阵 (有n种隐含状态,m种观测状态,其矩阵形状就是n*m) 28 | emission_probability = np.array([ 29 | [0.5, 0.5], 30 | [0.4, 0.6], 31 | [0.7, 0.3]]) 32 | 33 | #下面进行设置模型的参数 34 | model1=hmm.CategoricalHMM(n_components=n_states) 35 | model1.startprob_=start_probability # 初始状态分布 36 | model1.transmat_=transition_probability # 状态转移概率分布矩阵 37 | model1.emissionprob_=emission_probability # 观测状态概率矩阵 38 | 39 | #下面进行设定未来的一个观测序列(利用维比特算法) 40 | seen=np.array([0,1,0]).astype(int).reshape(-1,1) #注意要转化成二维的形式(如果观测序列是一维的话) 41 | logprob1,pred_state1=model1.decode(seen,algorithm='viterbi') #得到的第一个参数就是求出log下的序列出现概率(后续要进行还原),第二个参数就是预测的隐含状态序列 42 | print(np.exp(logprob1)) #输出观测序列出现的概率,完成问题1 43 | print(pred_state1) #输出预测的隐含状态,完成问题2 44 | 45 | #利用前向算法计算 46 | pred_state2=model1.predict(seen) #得到的第一个参数就是求出log下的序列出现概率(后续要进行还原),第二个参数就是预测的隐含状态序列 47 | print(np.exp(model1.score(seen))) #输出观测序列出现的概率,完成问题1 48 | print(pred_state2) #输出预测的隐含状态,完成问题2 49 | 50 | #下面进行参数估计(事先不知道隐含状态的初始概率、状态转移矩阵、输出矩阵),最终得出(生成式模型(无监督学习)和监督学习的方式) 51 | #设置隐含变量的类别(箱子的类别) 52 | states1 = ["box 1","box 2","box3"] 53 | n_states1=len(states1) #类别数 54 | 55 | #设定观察状态的集合(取出球的颜色) 56 | observations1 = ["red","white"] 57 | n_observations1 = len(observations1) #类别数 58 | 59 | #下面进行设置数据集(注意面对离散的观测变量目前只能用生成式(不能进行有监督学习)) 60 | X2 = np.array([[0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,1,0,1,1,1,0,1]])#自定义观测序列 61 | #y = np.array([[0,1,2,1,2,0,1,0,0,2,1,1,2,1,2,1,2,1,1,2,0,0,1,1,2,1,2,1,0,1]]) #隐含状态(分类标签) 62 | 63 | #下面进行设计模型 64 | model2=hmm.CategoricalHMM(n_components=n_states1,n_iter=20,tol=0.01) #n_components就是隐含状态的种类数,n_iter就是迭代的次数,tol就是停止的一个阈值 65 | 66 | #下面进行模型训练 67 | model2.fit(X2) #进行模型训练(参数学习)注意此时可以是无监督的参数学习(生成式,感觉也可以用于聚类) 68 | 69 | #下面进行输出(一些参数) 70 | print( model2.startprob_) #隐含变量初始概率分布 71 | print( model2.transmat_) #转移概率矩阵 (n*n) 72 | print (model2.emissionprob_) #输出概率矩阵 (n*m) 73 | print (np.exp(model2.score(X2))) #序列出现的概率(似然估计) 74 | 75 | #设置测试集数据 76 | X_test=np.array([0,1,1,0,0,1]) #观测序列 77 | y_test=np.array([2,1,0,2,1,1]) #隐含序列 78 | bina_y_test=label_binarize(y_test,classes=[0,1,2]) #二值化后的标签数据,用于后续绘制ROC曲线 79 | 80 | #下面进行预测(分类操作) 81 | y_pred=model2.predict(X_test.reshape(-1,1)) #进行隐含变量的预测(对新的观测序列) 82 | print(y_pred) 83 | 84 | #下面进行模型的评价 85 | #1首先是分类的精度 86 | print(metrics.accuracy_score(y_test,y_pred)) 87 | 88 | #2绘制ROC曲线,AUC面积 89 | prob_matrix=model2.predict_proba(X_test.reshape(-1,1)) #注意输出的一个一个矩阵类型 90 | 91 | #下面利用ROC曲线进行评价 92 | fpr=dict() 93 | tpr=dict() 94 | roc_auc=dict() 95 | for i in range(n_states1): #遍历类别 96 | fpr[i],tpr[i], _ = metrics.roc_curve(bina_y_test[:, i], prob_matrix[:, i]) #计算x轴和y轴的值 97 | roc_auc[i] = metrics.auc(fpr[i], tpr[i]) #计算auc面积值 98 | # Compute micro-average ROC curve and ROC area(方法二:将每个类别原始值和预测值都进行展平再进行计算ROC) 99 | fpr["micro"], tpr["micro"], _ = metrics.roc_curve(bina_y_test.ravel(), prob_matrix.ravel()) 100 | roc_auc["micro"] = metrics.auc(fpr["micro"], tpr["micro"]) 101 | 102 | #绘制ROC曲线 103 | plt.figure(figsize=(8,6)) 104 | #绘制平均的ROC曲线 105 | plt.plot(fpr["micro"], tpr["micro"], 106 | label='micro-average ROC curve (area = {0:0.2f})' 107 | ''.format(roc_auc["micro"]), 108 | color='deeppink', linestyle=':', linewidth=4) 109 | 110 | colors = ['aqua', 'darkorange', 'cornflowerblue'] #颜色序列有几类用几种 111 | for i ,color in enumerate(colors): 112 | plt.plot(fpr[i],tpr[i],color=color,lw=2,label='ROC curve of class {0} (area = {1:0.2f})' 113 | ''.format(i, roc_auc[i])) #绘制曲线同时打上AUC面积标签 114 | plt.plot([0, 1], [0, 1], 'k--', lw=2) #绘制对角线 115 | plt.xlabel('False Positive Rate',fontsize=13) 116 | plt.ylabel('True Positive Rate',fontsize=13) 117 | plt.title('ROC-Kurve',fontsize=15) 118 | plt.legend(loc="lower right") 119 | plt.show() 120 | 121 | #下面还可以用混淆矩阵进行操作 122 | confusion_matrix=metrics.confusion_matrix(y_test,y_pred) 123 | plt.figure(figsize=(8,6)) 124 | sns.heatmap(confusion_matrix,cmap='YlGnBu_r',fmt="d",annot=True) 125 | plt.xlabel('Prediction category',fontsize=13) #横轴是预测类别 126 | plt.ylabel('Real category',fontsize=13) #数轴是真实类别 127 | plt.title('Confusion matrix',fontsize=15) 128 | plt.show() 129 | 130 | #下面进行构建观测变量是多维的并且还是连续数值类型的(利用GMMHMM)并且进行无监督学习(聚类和嗯)和监督学习 131 | # 定义观察序列和标记序列(表示x一共有3个特征列,10个观测值) 132 | X = np.array([[0.1, 0.2, 0.3], [0.6, 0.5, 0.4], [0.9, 0.8, 0.7], [0.2, 0.3, 0.4], [0.5, 0.4, 0.3], 133 | [0.8, 0.7, 0.6], [0.3, 0.4, 0.5], [0.6, 0.5, 0.4], [0.9, 0.8, 0.7], [0.2, 0.3, 0.4]]) 134 | y = np.array([0,1,1,0,1,1,0,1,1,0]) #原始标签(隐含状态) 135 | 136 | #下面式测试的观测序列 137 | X_test1=np.array([[0.2,0.4,0.6],[0.5,0.2,0.1],[0.1,0.4,0.6]]) #测试数据 138 | 139 | # 定义HMM模型 140 | model3 = hmm.GaussianHMM(n_components=2, covariance_type="full",n_iter=100) 141 | 142 | # 使用标记序列进行训练 143 | model3.fit(X) 144 | 145 | #下面进行预测操作 146 | print('似然为',model3.score(X_test1)) #输出观测序列的最大似然(AIC),可以用于检验模型的精度,选择适合的隐含状态变量 147 | y_pred=model3.predict(X_test1) 148 | y_prob=model3.predict_proba(X_test1) #概率分布预测 149 | print(y_pred) 150 | 151 | #下面可以根据模型生成类似的观测值序列(分别包括观测状态序列和隐含状态序列) 152 | print(model3.sample(100)[0]) #观测状态序列 153 | print(model3.sample(100)[1]) #隐含状态序列 154 | 155 | #如果想进行一定程度的监督学习的话,应该还可以直接设置模型的参数(从原始的人工计算) 156 | """model3.startprob_ = startprob #初始概率分布 157 | model3.transmat_ = transmat #转换概率矩阵 158 | model3.means_ = means #每个类别的每个特征的均值(最好设置)n*m矩阵形状(n为隐含状态种类数,m为特征数) 159 | model3.covars_ = covars """ -------------------------------------------------------------------------------- /code/K均值聚类.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | from sklearn.cluster import KMeans 4 | from sklearn.model_selection import train_test_split 5 | from sklearn.datasets import load_iris #测试的数据集 6 | from sklearn.metrics import silhouette_score 7 | import pandas as pd 8 | import seaborn as sns 9 | 10 | iris=load_iris() #导入数据集 是一个字典类型的数据 11 | X=iris.data[:,2:4] #表示只取特征空间的后两个纬度(但是这里我取了三个特征纬度) 12 | y = iris.target # 将鸢尾花的标签赋值给y 13 | # 随机划分鸢尾花数据集,其中训练集占70%,测试集占30% 14 | X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) 15 | estimator=KMeans(n_clusters=3) #构造聚类器,将样本聚成3类 16 | estimator.fit(X_train) #开始聚类,注意输入数据是向量的形式 17 | label_pred=estimator.labels_ #获取聚类标签 18 | #print(estimator.cluster_centers_) #获取聚类中心点参数(位置) 19 | 20 | #下面将分类标签和特征整合到一个dataframe中便于后续的绘制图形(注意是特征在一列中,数值在一类中,聚类标签也在一列中,一共三列,注意数据的组织方式) 21 | feature_list=[] #存储所有的特征类型 22 | data_list=[] #存储所有的特征数据 23 | label_list=[] #也要将横着的标签转化成竖着的 24 | for i in range(X_train.shape[1]): #每个特征 25 | for j in range(X_train.shape[0]): #每行 26 | feature_list.append(f'feature{i+1}') 27 | data_list.append(X_train[j,i]) 28 | label_list.append(label_pred[j]) 29 | x_dataframe=pd.DataFrame({'feature':feature_list,'value':data_list,'classify':label_list}) 30 | print(x_dataframe) 31 | #下面这个很巧妙,直接将label==0的位置传给了X_train中去,直接读取了出来 32 | x0=X_train[label_pred==0] 33 | x1 = X_train[label_pred == 1] 34 | x2 = X_train[label_pred == 2] 35 | 36 | #进行显示聚类结果,绘制k-means结果,将训练集聚类后的结果绘图展示,三种颜色表示三类,红色表示第一类,绿色表示第二类,蓝色表示第三类 37 | #注意特征如果过多的话就绘制不太出来(最多能绘制3维) 38 | plt.figure(figsize=(8,6)) 39 | plt.scatter(x0[:,0],x0[:,1], c = "red", marker='o', label='label0') 40 | plt.scatter(x1[:, 0], x1[:, 1], c = "green", marker='*', label='label1') 41 | plt.scatter(x2[:, 0], x2[:, 1], c = "blue", marker='+', label='label2') 42 | plt.tick_params(size=5,labelsize = 13) #坐标轴 43 | plt.grid(alpha=0.3) #是否加网格线 44 | # 坐标轴属性 45 | plt.xlabel('petal length') #花瓣属性 46 | plt.ylabel('petal width') #花瓣宽度 47 | plt.legend(loc=2) 48 | plt.show() 49 | 50 | #下面利用训练出来的Kmeans模型(中心点相同)预测测试集中的数据属于哪一类 51 | test_predict=estimator.predict(X_test) 52 | #将各个分类的坐标取出来 53 | predict_0=X_test[test_predict==0] 54 | predict_1=X_test[test_predict==1] 55 | predict_2=X_test[test_predict==2] 56 | 57 | #绘制k-means预测结果,将测试集集聚类后的结果绘图展示,三种颜色表示三类,橘色表示第一类,天蓝色表示第二类,蓝绿色表示第三类。 58 | plt.figure(figsize=(8,6)) 59 | plt.tick_params(size=5,labelsize = 13) #坐标轴 60 | plt.grid(alpha=0.3) #是否加网格线 61 | plt.scatter(predict_0[:, 0], predict_0[:, 1], c = "tomato", marker='o', label='predict0') 62 | plt.scatter(predict_1[:, 0], predict_1[:, 1], c = "skyblue", marker='*', label='predict1') 63 | plt.scatter(predict_2[:, 0], predict_2[:, 1], c = "greenyellow", marker='+', label='predict2') 64 | plt.xlabel('petal length') 65 | plt.ylabel('petal width') 66 | plt.legend(loc=2) 67 | plt.show() 68 | 69 | #下面可以分特征绘制抖动图(观察聚类效果) 70 | #先把数据转化成dataframe的格式 71 | data_train=pd.DataFrame(X_train,columns=['1','2']) 72 | data_train['result']=label_pred 73 | 74 | #下面进行绘制(分特征) 75 | fig=plt.figure(figsize=(8,6)) 76 | ax1=fig.add_subplot(121) 77 | sns.swarmplot(x='result',y='1',data=data_train,ax=ax1) 78 | 79 | ax2=fig.add_subplot(122) 80 | sns.swarmplot(x='result',y='2',data=data_train,ax=ax2) 81 | plt.show() 82 | 83 | #1如果不知道聚类中心数目,为了确定最佳聚类数据可以采用肘方法 84 | clusters = [] #存储SSE 85 | for i in range(2, 12): 86 | km = KMeans(n_clusters=i).fit(X) 87 | clusters.append(km.inertia_) 88 | #进行绘制图片(肘图) 89 | plt.figure(figsize=(8,6)) 90 | plt.tick_params(size=5,labelsize = 13) #坐标轴 91 | plt.grid(alpha=0.3) #是否加网格线 92 | plt.plot(range(2,12),clusters,linestyle=':',marker='o',lw=3) 93 | plt.title('Searching for Elbow',fontsize=15) 94 | plt.xlabel('Clusters',fontsize=13) 95 | plt.ylabel('Inertia',fontsize=13) 96 | # 打上箭头标签 97 | plt.annotate('Possible Elbow Point', xy=(3, 31.8), xytext=(3, 100), xycoords='data', 98 | arrowprops=dict(arrowstyle='->', connectionstyle='arc3', color='blue', lw=2)) 99 | plt.show() 100 | 101 | #下面采用计算轮廓系数的方法(推荐) 102 | silhouette_factor = [] #存储轮廓系数, 103 | for i in range(2, 12):#注意其不能只分1类,因为要计算离散值(至少2类) 104 | km = KMeans(n_clusters=i) 105 | result=km.fit_predict(X) 106 | silhouette_factor.append(silhouette_score(X,result)) 107 | 108 | #下面绘制出轮廓系数图,系数在(-1,1)之间越大越好 109 | plt.figure(figsize=(8,6)) 110 | plt.tick_params(size=5,labelsize = 13) #坐标轴 111 | plt.grid(alpha=0.3) #是否加网格线 112 | plt.plot(range(2,12),silhouette_factor,linestyle=':',marker='o',lw=3) 113 | plt.title('Searching for Elbow',fontsize=15) 114 | plt.xlabel('Clusters',fontsize=13) 115 | plt.ylabel('Inertia',fontsize=13) 116 | # 打上箭头标签 117 | plt.annotate('Possible Elbow Point', xy=(3, 0.67), xytext=(3, 0.7), xycoords='data', 118 | arrowprops=dict(arrowstyle='->', connectionstyle='arc3', color='blue', lw=2)) 119 | plt.show() 120 | 121 | #下面可以进行绘制分类结果各个特征的分类箱型图进行对比 122 | f,ax=plt.subplots(figsize=(8,6)) 123 | sns.boxplot(data=x_dataframe,x='feature',y='value',hue='classify' ,palette="Accent") 124 | #sns.stripplot(data=x_dataframe,x='feature',y='value',hue='classify' ,palette="Accent")# palette="light:m_r" 125 | #sns.despine(trim=True, left=True) 126 | ax.yaxis.grid(True) #加上y轴的网格(横着的网格) 127 | plt.show() 128 | 129 | #下面进行绘制分类均值簇状柱形图(加上误差线)利用seaborn绘制 130 | index=np.arange(x0.shape[1]) #横轴的特征数,这里有两个特征,用于绘制簇状柱形图 131 | feature_index=['feature1','feature2'] #横轴的特征名称 132 | #下面进行计算每一聚类的每一特征的均值 133 | x0_avglist=[np.mean(x0[:,0]),np.mean(x0[:,1])] 134 | x1_avglist=[np.mean(x1[:,0]),np.mean(x1[:,1])] 135 | x2_avglist=[np.mean(x2[:,0]),np.mean(x2[:,1])] 136 | #下面进行计算标准差 137 | x0_stdlist=[np.std(x0[:,0]),np.std(x0[:,1])] 138 | x1_stdlist=[np.std(x1[:,0]),np.std(x1[:,1])] 139 | x2_stdlist=[np.std(x2[:,0]),np.std(x2[:,1])] 140 | #进行绘制 141 | width=0.25 142 | plt.rcParams['font.sans-serif'] = ['SimHei'] 143 | plt.rcParams['axes.unicode_minus'] = False 144 | plt.figure(figsize=(8,6)) 145 | plt.tick_params(size=5,labelsize = 13) #坐标轴 146 | plt.grid(alpha=0.3) #是否加网格线 147 | plt.bar(index,x0_avglist,width=width,yerr=x0_stdlist,error_kw = {'ecolor' : '0.2', 'capsize' :6 }, alpha=0.4,color='b' ,label = '类别1') 148 | plt.bar(index+width,x1_avglist,width=width,yerr=x1_stdlist,error_kw = {'ecolor' : '0.2', 'capsize' :6 }, alpha=0.4,color='r' ,label = '类别2') 149 | plt.bar(index+2*width,x2_avglist,width=width,yerr=x2_stdlist,error_kw = {'ecolor' : '0.2', 'capsize' :6 }, alpha=0.4,color='g' ,label = '类别3') 150 | #下面进行打上标签 151 | for i,data in enumerate(x0_avglist): 152 | plt.text(i,data+0.1,round(data,1),horizontalalignment='center',fontsize=13) 153 | #下面进行打上标签 154 | for i,data in enumerate(x1_avglist): 155 | plt.text(i+width,data+0.1,round(data,1),horizontalalignment='center',fontsize=13) 156 | # 下面进行打上标签 157 | for i, data in enumerate(x2_avglist): 158 | plt.text(i + width*2, data + 0.1, round(data, 1), horizontalalignment='center',fontsize=13) 159 | plt.xlabel('特征类别',fontsize=13) 160 | plt.ylabel('均值',fontsize=13) 161 | plt.title('聚类类别各特征均值',fontsize=15) 162 | plt.legend() 163 | plt.xticks(index+0.3,feature_index) 164 | plt.show() -------------------------------------------------------------------------------- /code/LDA主题分析.py: -------------------------------------------------------------------------------- 1 | import re 2 | import pandas as pd 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | from nltk.tokenize import sent_tokenize,word_tokenize #分别用于分句和分词 6 | from nltk.corpus import stopwords #用于停用词处理 7 | from gensim.models.ldamodel import LdaModel,CoherenceModel 8 | from gensim import corpora 9 | import pyLDAvis.gensim 10 | from matplotlib import rcParams #导入包 11 | 12 | config = {"font.family":'Times New Roman'} # 设置字体类型 13 | rcParams.update(config) #进行更新配置 14 | 15 | #下面进行分词操作,并将所有字母转化成小写字母(结合两步) 16 | def token_data(data): #data为输入的句子列表 17 | result_list=[] #存储每个句子分词的结果,形式为[[]] 18 | for sentence in data: #取出每个句子 19 | sentence=sentence.lower() #将大写字母均转化为小写字母 20 | result_list.append(word_tokenize(sentence)) #添加分完词的结果 21 | return result_list 22 | 23 | #下面是进行去除无用的停用词 24 | def clean_stopwords(data): #data表示分完词后的列表形式为[[]] 25 | result_list=[] #存储最后的结果,注意最后的形式为[[]] 26 | sr=stopwords.words('english') #存储所有停用词的列表 27 | for inner_data in data: #取出大列表中包含的小列表(分完词的列表) 28 | mid_list=[] #存储一个句子中去除所有停用词的词 29 | for token in inner_data: #取出单个词 30 | if token not in sr: 31 | mid_list.append(token) 32 | result_list.append(mid_list) 33 | return result_list 34 | 35 | #计算困惑度perplexity(困惑度越低越好) 36 | def perplexity(corpus,dictionary,num_topics): 37 | """ 38 | :param corpus: 语料库(编码后的文本) 39 | :param dictionary: 构建的词典 40 | :param num_topics: 主题数量 41 | :return: 42 | """ 43 | ldamodel = LdaModel(corpus, num_topics=num_topics, id2word = dictionary, passes=30) 44 | return ldamodel.log_perplexity(corpus) #计算困惑都 45 | 46 | #计算主题一致性coherence(一致性越高越好)并且一般选用这个作为指标 47 | def coherence(data,corpus,dictionary,num_topics): 48 | """ 49 | :param data: 经过分词等操作后的文本序列,形式为[[],[]] 50 | :param corpus: 语料库(编码后的文本) 51 | :param dictionary: 构建的词典 52 | :param num_topics: 主题数量 53 | :return: 54 | """ 55 | #构建LDA模型 56 | ldamodel = LdaModel(corpus, num_topics=num_topics, id2word = dictionary, passes=30,random_state = 1) 57 | #建立CoherenceModel来评估模型的质量和主题之间的连贯性,coherence有定使用哪种一致性得分度量方法,常用的有 'c_v'、'u_mass'、'c_uci' 58 | ldacm = CoherenceModel(model=ldamodel, texts=data, dictionary=dictionary, coherence='u_mass') #推荐使用u_mass 59 | return ldacm.get_coherence() 60 | 61 | #绘制曲线(用于评估选取主题个数) 62 | def plot_curve(x,y,xlabel,ylabel,title): 63 | plt.figure(figsize=(8, 6)) 64 | plt.tick_params(size=5, labelsize=13) # 坐标轴 65 | plt.grid(alpha=0.3) # 是否加网格线 66 | plt.plot(x, y, color='#e74c3c', lw=1.5) 67 | plt.xlabel(xlabel, fontsize=13, family='Times New Roman') 68 | plt.ylabel(ylabel, fontsize=13, family='Times New Roman') 69 | plt.title(title, fontsize=15, family='Times New Roman') 70 | #plt.savefig('.svg',format='svg',bbox_inches='tight') 71 | plt.show() 72 | 73 | #进行正则表达式,提取出对应的单词和概率 74 | def extra_word_prob(str_data): 75 | """ 76 | :param str_data: 单个主题的输出分布情况例如‘0.083*"." + 0.042*"ship" + 0.038*"pirates" + 0.036*"," + 0.019*"crew"’ 77 | :return: 78 | """ 79 | decimal_reg=re.compile(r'(\d*\.\d*)\*') #提取数字部分的正则表达式 80 | word_reg=re.compile(r'"(\S*)"') 81 | decimal_ls=[float(decimal) for decimal in decimal_reg.findall(str_data)] 82 | word_ls=word_reg.findall(str_data) 83 | 84 | return word_ls,decimal_ls #返回词汇序列和其对应的概率序列 85 | 86 | #绘制词汇概率分布柱形图 87 | def plot_distribute(word_ls,decimal_ls,color='#e74c3c',title='title'): 88 | """ 89 | :param word_ls: 90 | :param decimal_ls: 91 | :param title: 图标题 92 | :return: 93 | """ 94 | index = np.arange(len(word_ls)) 95 | # 进行绘制 96 | width = 0.25 97 | plt.figure(figsize=(8, 6)) 98 | plt.tick_params(size=5, labelsize=13) # 坐标轴 99 | plt.grid(alpha=0.3) # 是否加网格线 100 | # 注意下面可以进行绘制误差线,如果是计算均值那种的簇状柱形图的话(注意类别多的话可以用循环的方式搞) 101 | plt.bar(index, decimal_ls, width=width, alpha=0.8,color=color) 102 | # 下面进行打上标签(也可以用循环的方式进行绘制)(颜色就存储在一个列表中) 103 | for i, data in enumerate(decimal_ls): 104 | plt.text(index[i], data + 0.001, round(data, 3), horizontalalignment='center', fontsize=13) 105 | plt.xlabel('Word', fontsize=13,family='Times New Roman') 106 | plt.ylabel('Probability', fontsize=13,family='Times New Roman') 107 | plt.title(title, fontsize=15,family='Times New Roman') 108 | plt.xticks(index,word_ls,rotation=40) 109 | #plt.savefig('.svg',format='svg',bbox_inches='tight') 110 | plt.show() 111 | 112 | if __name__ == '__main__': 113 | data = pd.read_csv('D:\\2023美赛\\海盗问题\\第二题第三题数据\\EA.csv', encoding='gbk')['Incident details'].to_list() 114 | #进行分词并去除无用的停用词(输出形式为[[],[]]) 115 | new_data=clean_stopwords(token_data(data)) 116 | 117 | # 构建词袋模型(TF表示法,另外的一种方式,利用序号和计数来表示) 118 | dictionary = corpora.Dictionary(new_data) #构建词典 119 | corpus = [dictionary.doc2bow(text) for text in new_data] #返回每个text的编码向量 120 | 121 | #利用指标选择合适的主题数(迭代15个主题)(一般用coherence指标) 122 | num=3 123 | """perplexity_ls=[perplexity(corpus,dictionary,num_topics=num_topic) for num_topic in range(1,num+1)] #困惑度序列(越小越好) 124 | coherence_ls = [coherence(new_data,corpus, dictionary, num_topics=num_topic) for num_topic in range(1, num + 1)] #一致度序列(越大越好) 125 | 126 | #绘制迭代曲线(分别两个) 127 | plot_curve(np.arange(1,num+1),perplexity_ls,'Number of topics','perplexity','Perplexity varies with the number of topics') 128 | plot_curve(np.arange(1, num + 1), coherence_ls, 'Number of topics', 'Coherence','Coherence varies with the number of topics') 129 | """ 130 | # 确定主题数量后构建LDA模型 131 | num_topics = 2 # 设置主题数量 132 | lda_model = LdaModel(corpus=corpus, id2word=dictionary, num_topics=num_topics) 133 | #输出每个主题的词分布(每个主题前15个词语) 134 | topics_words_distribute=lda_model.print_topics(num_words=15) 135 | 136 | #绘制主题-词分布图(以主题1为例)这个是概率的展示类型 137 | word_ls1,decimal_ls1=extra_word_prob(topics_words_distribute[0][1]) #输出词序列和概率序列 138 | plot_distribute(word_ls1,decimal_ls1,title='Word probability distribution for topic 1') 139 | 140 | #可视化LDA主题模型结果(保存为html的形式),包括主题间降维后的表示分布,还有各个主体的词分布情况 141 | result = pyLDAvis.gensim.prepare(lda_model, corpus, dictionary) 142 | pyLDAvis.save_html(result, r'D:\学习资源\学习资料\算法学习\软件库和基础学习\topic.html') 143 | 144 | #对新文本进行主题的分析(输出新文本的主题分布概率情况) 145 | new_text=['The pirates took five hostages and fired rockets at the ship'] 146 | new_text=clean_stopwords(token_data(new_text)) #分词和去除停用词 147 | new_bows = [dictionary.doc2bow(text) for text in new_text] #进行构建词袋编码 148 | new_topic_distribution = [lda_model.get_document_topics(bow) for bow in new_bows] #输出每个新文本的主题分布 149 | print(new_topic_distribution) 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /code/LDA降维.py: -------------------------------------------------------------------------------- 1 | from sklearn.datasets import make_classification 2 | from sklearn.discriminant_analysis import LinearDiscriminantAnalysis 3 | import pandas as pd 4 | import numpy as np 5 | import matplotlib.pyplot as plt 6 | from matplotlib import rcParams #导入包 7 | 8 | config = {"font.family":'Times New Roman'} # 设置字体类型 9 | rcParams.update(config) #进行更新配置 10 | 11 | # 生成示例数据集(1000行,7列数据,最后一列是类别,四类)(已经标准化过后的数据) 12 | # n_informative表示与类别相关的特征列数量,n_redundant是冗余特征的数量,冗余特征是信息特征的随机线性组合(不会增加模型中的新信息),n_clusters_per_class表示每类别中的族数(加大分类难度) 13 | X, y = make_classification(n_samples=1000, n_features=6, n_classes=4,n_informative=3, n_redundant=1, n_clusters_per_class=2, random_state=42) 14 | 15 | # 将数据和类别标签合并到DataFrame中(1000*7) 16 | data = pd.DataFrame(np.hstack((X, y.reshape(-1, 1))), columns=[f'Feature_{i+1}' for i in range(6)] + ['Class']) 17 | 18 | # 使用LDA进行降维 19 | X = data.drop('Class', axis=1) # 特征数据 20 | y = data['Class'] # 类别数据 21 | 22 | # 初始化LDA并将数据降维到3列(注意最多只能降维到类别数-1维) 23 | lda = LinearDiscriminantAnalysis(n_components=3) 24 | X_lda = lda.fit_transform(X, y) #数据为矩阵形式 25 | 26 | # 将降维后的数据转换为DataFrame 27 | data_lda = pd.DataFrame(X_lda, columns=['Component_1', 'Component_2', 'Component_3']) 28 | 29 | # 将降维后的数据和类别标签合并到一起 30 | data_final = pd.concat([data_lda, data['Class']], axis=1) 31 | 32 | #绘制三维点图进行展示降维效果(数据分布情况)(不同标签不同颜色) 33 | fig = plt.figure(figsize=(8,6)) #创建一个画布窗口 34 | ax=plt.axes(projection='3d') #注意现在要用这种3d绘图创建方式(直接设置三维坐标轴) 35 | ax.w_xaxis.set_pane_color((1.0, 1.0, 1.0, 1.0)) 36 | ax.w_yaxis.set_pane_color((1.0, 1.0, 1.0, 1.0)) 37 | ax.w_zaxis.set_pane_color((1.0, 1.0, 1.0, 1.0)) 38 | #调整背景景网格粗细 39 | ax.xaxis._axinfo["grid"]['linewidth'] = 0.4 40 | ax.yaxis._axinfo["grid"]['linewidth'] = 0.4 41 | ax.zaxis._axinfo["grid"]['linewidth'] = 0.4 42 | 43 | #开始绘制 44 | color_ls=['#fe0000','#bf0000','#2049ff','#febf00'] 45 | for i in range(4): #每个类别 46 | #取出各类别下的三个特征 47 | x=data_final[data_final['Class']==i]['Component_1'].tolist() 48 | y=data_final[data_final['Class']==i]['Component_2'].tolist() 49 | z = data_final[data_final['Class'] == i]['Component_3'].tolist() 50 | ax.scatter(x,y,z,color=color_ls[i],s=20,label=f'Class{i+1}') #绘制 51 | 52 | #分别上下旋转和左右旋转,可以自己设置成一个比较好的参数 53 | ax.view_init(65,-32) 54 | 55 | #设置坐标轴 56 | plt.legend() 57 | ax.set_xlabel('特征1',fontsize=15,family='SimSun') 58 | ax.set_ylabel('特征2',fontsize=15,family='SimSun') 59 | ax.set_zlabel('特征3',fontsize=15,family='SimSun') 60 | ax.set_title('LDA降维后特征可视化',fontsize=16,family='SimSun') 61 | #plt.savefig('测试图',format='svg',bbox_inches='tight') 62 | plt.show() 63 | 64 | -------------------------------------------------------------------------------- /code/LOF算法.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | import matplotlib.pyplot as plt 4 | import seaborn as sns 5 | from sklearn.neighbors import LocalOutlierFactor 6 | import networkx as nx 7 | from networkx.drawing.nx_agraph import graphviz_layout 8 | from mpl_toolkits.mplot3d import Axes3D 9 | #from __future__ import division 10 | from sklearn.datasets import load_iris #测试的数据集 11 | from sklearn.neighbors import NearestNeighbors 12 | import networkx as nx 13 | 14 | #下面是自构建函数的方式,还可以用sklearn中的函数进行操作 15 | def distance_euclidean(instance1, instance2): 16 | """Computes the distance between two instances. Instances should be tuples of equal length. 17 | Returns: Euclidean distance 18 | Signature: ((attr_1_1, attr_1_2, ...), (attr_2_1, attr_2_2, ...)) -> float""" 19 | 20 | def detect_value_type(attribute): #这个是用于检测输入数据的类型 21 | """Detects the value type (number or non-number). 22 | Returns: (value type, value casted as detected type) 23 | Signature: value -> (str or float type, str or float value)""" 24 | from numbers import Number 25 | attribute_type = None 26 | if isinstance(attribute, Number): 27 | attribute_type = float 28 | attribute = float(attribute) 29 | else: 30 | attribute_type = str 31 | attribute = str(attribute) 32 | return attribute_type, attribute 33 | 34 | # check if instances are of same length 35 | if len(instance1) != len(instance2): 36 | raise AttributeError("Instances have different number of arguments.") 37 | # init differences vector 38 | differences = [0] * len(instance1) 39 | # compute difference for each attribute and store it to differences vector 40 | for i, (attr1, attr2) in enumerate(zip(instance1, instance2)): 41 | type1, attr1 = detect_value_type(attr1) 42 | type2, attr2 = detect_value_type(attr2) 43 | # raise error is attributes are not of same data type. 44 | if type1 != type2: 45 | raise AttributeError("Instances have different data types.") 46 | if type1 is float: 47 | # compute difference for float 48 | differences[i] = attr1 - attr2 49 | else: 50 | # compute difference for string 51 | if attr1 == attr2: 52 | differences[i] = 0 53 | else: 54 | differences[i] = 1 55 | # compute RMSE (root mean squared error) 56 | rmse = (sum(map(lambda x: x ** 2, differences)) / len(differences)) ** 0.5 57 | return rmse #计算欧氏距离并返回 58 | 59 | 60 | class LOF: 61 | """Helper class for performing LOF computations and instances normalization.""" 62 | def __init__(self, instances, normalize=True, distance_function=distance_euclidean): 63 | self.instances = instances #输入的数据 64 | self.normalize = normalize #进行标准化 65 | self.distance_function = distance_function #欧式距离计算 66 | if normalize: 67 | self.normalize_instances() 68 | 69 | def compute_instance_attribute_bounds(self): 70 | min_values = [float("inf")] * len(self.instances[0]) # n.ones(len(self.instances[0])) * n.inf 71 | max_values = [float("-inf")] * len(self.instances[0]) # n.ones(len(self.instances[0])) * -1 * n.inf 72 | for instance in self.instances: 73 | min_values = tuple(map(lambda x, y: min(x, y), min_values, instance)) # n.minimum(min_values, instance) 74 | max_values = tuple(map(lambda x, y: max(x, y), max_values, instance)) # n.maximum(max_values, instance) 75 | self.max_attribute_values = max_values 76 | self.min_attribute_values = min_values 77 | 78 | def normalize_instances(self): #用于标准化数据 79 | """Normalizes the instances and stores the infromation for rescaling new instances.""" 80 | if not hasattr(self, "max_attribute_values"): 81 | self.compute_instance_attribute_bounds() 82 | new_instances = [] 83 | for instance in self.instances: 84 | new_instances.append( 85 | self.normalize_instance(instance)) # (instance - min_values) / (max_values - min_values) 86 | self.instances = new_instances 87 | 88 | def normalize_instance(self, instance): #进行标准化的主体函数 89 | return tuple(map(lambda value, max, min: (value - min) / (max - min) if max - min > 0 else 0, 90 | instance, self.max_attribute_values, self.min_attribute_values)) 91 | 92 | def local_outlier_factor(self, min_pts, instance): #计算LOF 93 | """The (local) outlier factor of instance captures the degree to which we call instance an outlier. 94 | min_pts is a parameter that is specifying a minimum number of instances to consider for computing LOF value. 95 | Returns: local outlier factor 96 | Signature: (int, (attr1, attr2, ...), ((attr_1_1, ...),(attr_2_1, ...), ...)) -> float""" 97 | if self.normalize: 98 | instance = self.normalize_instance(instance) 99 | return local_outlier_factor(min_pts, instance, self.instances, distance_function=self.distance_function) 100 | 101 | #计算第k可达距离 102 | def k_distance(k, instance, instances, distance_function=distance_euclidean): 103 | # TODO: implement caching 104 | """Computes the k-distance of instance as defined in paper. It also gatheres the set of k-distance neighbours. 105 | Returns: (k-distance, k-distance neighbours) 106 | Signature: (int, (attr1, attr2, ...), ((attr_1_1, ...),(attr_2_1, ...), ...)) -> (float, ((attr_j_1, ...),(attr_k_1, ...), ...))""" 107 | distances = {} 108 | for instance2 in instances: 109 | distance_value = distance_function(instance, instance2) 110 | if distance_value in distances: 111 | distances[distance_value].append(instance2) 112 | else: 113 | distances[distance_value] = [instance2] 114 | distances = sorted(distances.items()) 115 | neighbours = [] 116 | k_sero = 0 117 | k_dist = None 118 | for dist in distances: 119 | k_sero += len(dist[1]) 120 | neighbours.extend(dist[1]) 121 | k_dist = dist[0] 122 | if k_sero >= k: 123 | break 124 | return k_dist, neighbours 125 | 126 | #计算可达距离 127 | def reachability_distance(k, instance1, instance2, instances, distance_function=distance_euclidean): 128 | """The reachability distance of instance1 with respect to instance2. 129 | Returns: reachability distance 130 | Signature: (int, (attr_1_1, ...),(attr_2_1, ...)) -> float""" 131 | (k_distance_value, neighbours) = k_distance(k, instance2, instances, distance_function=distance_function) 132 | return max([k_distance_value, distance_function(instance1, instance2)]) 133 | 134 | #计算局部可达密度 135 | def local_reachability_density(min_pts, instance, instances, **kwargs): 136 | """Local reachability density of instance is the inverse of the average reachability 137 | distance based on the min_pts-nearest neighbors of instance. 138 | Returns: local reachability density 139 | Signature: (int, (attr1, attr2, ...), ((attr_1_1, ...),(attr_2_1, ...), ...)) -> float""" 140 | (k_distance_value, neighbours) = k_distance(min_pts, instance, instances, **kwargs) 141 | reachability_distances_array = [0] * len(neighbours) # n.zeros(len(neighbours)) 142 | for i, neighbour in enumerate(neighbours): 143 | reachability_distances_array[i] = reachability_distance(min_pts, instance, neighbour, instances, **kwargs) 144 | sum_reach_dist = sum(reachability_distances_array) 145 | if sum_reach_dist == 0: 146 | return float('inf') 147 | return len(neighbours) / sum_reach_dist 148 | 149 | #计算第k离群因子 150 | def local_outlier_factor(min_pts, instance, instances, **kwargs): 151 | """The (local) outlier factor of instance captures the degree to which we call instance an outlier. 152 | min_pts is a parameter that is specifying a minimum number of instances to consider for computing LOF value. 153 | Returns: local outlier factor 154 | Signature: (int, (attr1, attr2, ...), ((attr_1_1, ...),(attr_2_1, ...), ...)) -> float""" 155 | (k_distance_value, neighbours) = k_distance(min_pts, instance, instances, **kwargs) 156 | instance_lrd = local_reachability_density(min_pts, instance, instances, **kwargs) 157 | lrd_ratios_array = [0] * len(neighbours) 158 | for i, neighbour in enumerate(neighbours): 159 | instances_without_instance = set(instances) 160 | instances_without_instance.discard(neighbour) 161 | neighbour_lrd = local_reachability_density(min_pts, neighbour, instances_without_instance, **kwargs) 162 | lrd_ratios_array[i] = neighbour_lrd / instance_lrd 163 | return sum(lrd_ratios_array) / len(neighbours) 164 | 165 | #下面的这个是主体的函数计算LOF并输出结果 166 | def outliers(k, instances, **kwargs): 167 | """Simple procedure to identify outliers in the dataset.""" 168 | instances_value_backup = instances 169 | inliers = [] #存储正常点的数据 170 | outliers = [] #存储离群点的数据 171 | LOF_list= [] #存储所有数据的LOF 172 | for i, instance in enumerate(instances_value_backup): #进行遍历点的数据 173 | instances = list(instances_value_backup) 174 | #instances.remove(instance) #从列表中移除一个个点 175 | l = LOF(instances, **kwargs) #创建LOF对象 176 | value = l.local_outlier_factor(k, instance) #计算该点的LOF值 177 | LOF_list.append(value) 178 | if value > 1: #如果LOF大于1说明是离群点 179 | outliers.append({"lof": value, "instance": instance, "index": i}) #输出lof值,原始坐标和序号 180 | else: 181 | inliers.append({"lof": value, "instance": instance, "index": i}) 182 | #outliers.sort(key=lambda o: o["lof"], reverse=True) #进行降序 183 | return inliers,outliers,LOF_list #返回正常点序列、离群点序列和所有数据的LOF数据 前两个参数的形式为[{},{}],最后的是列表形式 184 | 185 | #下面是主体的操作流程 186 | #导入测试数据 187 | data=load_iris().data[:,:2] #只要前面两列数据作为测试 188 | 189 | #进行LOF算法 190 | inliers1,outliers1,LOF_list1=outliers(5,data) #返回正常点序列、离群点序列和所有数据的LOF数据 前两个参数的形式为[{},{}],最后的是列表形式 191 | 192 | #下面将正常点和离群点的坐标和LOF值进行读取 193 | inliers_instance=[] #存储正常点的坐标列表[(),()] 194 | inliers_lof=[] #存储正常点的LOF值 195 | outliers_instance=[] #存储离群点的坐标列表[(),()] 196 | outliers_lof=[] #存储离群点的LOF值 197 | for inlier in inliers1: 198 | inliers_instance.append(inlier['instance'].tolist()) 199 | inliers_lof.append(inlier['lof']) 200 | for outlier in outliers1: 201 | outliers_instance.append(outlier['instance'].tolist()) 202 | outliers_lof.append(outlier['lof']) 203 | 204 | #下面利用线图加点图进行可视化各个位置的LOF值(第一种表现方式(这个并没有显示异常点)) 205 | """x=data[:,0] #x轴数据 206 | y=data[:,1] #y轴数据 207 | #三维点图与线图的结合(可以更加直观的展现数据位置点其他变量值的大小) 208 | plt.rcParams['font.sans-serif'] = ['SimHei'] 209 | plt.rcParams['axes.unicode_minus'] = False 210 | fig = plt.figure(figsize=(8,6),facecolor='#ffffff') #创建一个画布窗口 211 | ax=Axes3D(fig) #创建三维坐标系(注意要用Axes中才能改拉伸后面的坐标轴) 212 | #拉伸坐标轴,前3个参数用来调整各坐标轴的缩放比例(目前用不了) 213 | #ax.get_proj = lambda: np.dot(Axes3D.get_proj(ax), np.diag([1,1 ,1 , 1])) 214 | #下面将背景颜色变透明 215 | ax.w_xaxis.set_pane_color((1.0, 1.0, 1.0, 1.0)) 216 | ax.w_yaxis.set_pane_color((1.0, 1.0, 1.0, 1.0)) 217 | ax.w_zaxis.set_pane_color((1.0, 1.0, 1.0, 1.0)) 218 | #调整背景景网格粗细 219 | ax.xaxis._axinfo["grid"]['linewidth'] = 0.4 220 | ax.yaxis._axinfo["grid"]['linewidth'] = 0.4 221 | ax.zaxis._axinfo["grid"]['linewidth'] = 0.4 222 | #绘制点图 223 | scatter=ax.scatter(x,y,LOF_list,color='salmon',s=20,alpha=0.8) #注意一定是ax子图中绘制,注意还可以添加cmap参数,但是输输入的c是序列的形式,并且还可以添加颜色条 224 | #绘制竖线 225 | for i in range(len(x)): 226 | ax.plot([x[i],x[i]],[y[i],y[i]],[min(LOF_list),LOF_list[i]],c='salmon',alpha=0.6,lw=1) 227 | #分别上下旋转和左右旋转,可以自己设置成一个比较好的参数 228 | ax.view_init(20,-32) 229 | #设置z轴的显示范围 230 | ax.set_zlim(min(LOF_list),max(LOF_list)+0.1) 231 | #添加颜色条,注意前面的点图要加cmap,c参数也要改为序列才行 232 | #plt.colorbar(scatter,shrink=0.7) 233 | #设置坐标轴标签 234 | ax.set_xlabel('x轴',fontsize=16) 235 | ax.set_ylabel('y轴',fontsize=16) 236 | ax.set_zlabel('z轴',fontsize=16) 237 | ax.set_title('标题',fontsize=16) 238 | #plt.savefig('测试图',bbox_inches='tight') 239 | plt.show()""" 240 | 241 | #下面绘制可以表现出离群点的散点图(气泡图) 242 | def Normalized2(data): #data是输入序列,这个是极大型指标的处理方式 输出也是序列 243 | min_data=min(data) 244 | max_data=max(data) 245 | return [(x-min_data)/(max_data-min_data) for x in data] 246 | #下面进行图片的一些基础设置 247 | """plt.figure(figsize=(8,6)) 248 | plt.rcParams['font.sans-serif'] = ['SimHei'] 249 | plt.rcParams['axes.unicode_minus'] = False 250 | plt.tick_params(size=5,labelsize = 13) #坐标轴 251 | plt.grid(alpha=0.3) #是否加网格线 252 | #下面进行构建合适的点大小 253 | len_outliers=len(outliers_instance) #统计离群点的个数 254 | total_lof=inliers_lof+outliers_lof #将正常点和离群点放入一个列表中 255 | size=np.array(Normalized2(total_lof))*400 256 | #下面进行分别绘制正常点和离群点 257 | plt.scatter([x[0] for x in inliers_instance],[x[1] for x in inliers_instance],s=size[:-len_outliers],alpha=0.9,c='#F21855',label='正常点') 258 | plt.scatter([x[0] for x in outliers_instance],[x[1] for x in outliers_instance],s=size[-len_outliers:],alpha=1,c='k',label='离群点') 259 | plt.legend() 260 | plt.xlabel('x轴',fontsize=13) 261 | plt.ylabel('y轴',fontsize=13) 262 | plt.title('标题',fontsize=15) 263 | #plt.savefig() 264 | plt.show()""" 265 | 266 | #下面进行绘制近邻网络图 267 | """X = data #数据(矩阵类型(n*2)) 268 | # 生成K近邻网络 269 | nbrs = NearestNeighbors(n_neighbors=6).fit(X) #进行训练,表示6个最近邻的(注意这个是包括自己的),因此当前面LOF为5时,这里是6 270 | distances, indices = nbrs.kneighbors(X) #distances表示每个点到最近的几个点的距离是一个(n,k_neighbors)的一个矩阵形式,indices表示每个点离自己最近的k个点的序号(包括自己) 271 | #下面进行绘制邻接矩阵 272 | plt.figure(figsize=(8,6)) 273 | plt.rcParams['font.sans-serif'] = ['SimHei'] 274 | plt.rcParams['axes.unicode_minus'] = False 275 | plt.tick_params(size=5,labelsize = 13) #坐标轴 276 | plt.grid(alpha=0.3) #是否加网格线 277 | # 绘制点图 278 | plt.scatter(X[:, 0], X[:, 1], s=30, c='#F21855', alpha=1,marker='o',label='正常点') 279 | #标记下异常点 280 | plt.scatter([x[0] for x in outliers_instance],[x[1] for x in outliers_instance],s=55,c='k',alpha=0.8,label='异常点') 281 | # 绘制边 282 | for i in range(len(X)): 283 | for j in indices[i,1:]: 284 | plt.plot([X[i, 0], X[j, 0]], [X[i, 1], X[j, 1]], c='gray', alpha=1) 285 | plt.legend() 286 | plt.xlabel('x轴',fontsize=13) 287 | plt.ylabel('y轴',fontsize=13) 288 | plt.title('标题',fontsize=15) 289 | plt.show()""" 290 | 291 | #下面对k参数进行敏感性分析(绘制6张散点图) 292 | k_list=[5,10,15,20,25,30] 293 | fig,ax=plt.subplots(2,3,figsize=(16,8)) 294 | plt.rcParams['font.sans-serif'] = ['SimHei'] 295 | plt.rcParams['axes.unicode_minus'] = False 296 | for i,k in enumerate(k_list): 297 | inliers2,outliers2,LOF_list1=outliers(k,data) #返回正常点序列、离群点序列和所有数据的LOF数据 前两个参数的形式为[{},{}],最后的是列表形式 298 | #下面将正常点和离群点的坐标和LOF值进行读取 299 | inliers_instance1=[] #存储正常点的坐标列表[(),()] 300 | inliers_lof1=[] #存储正常点的LOF值 301 | outliers_instance1=[] #存储离群点的坐标列表[(),()] 302 | outliers_lof1=[] #存储离群点的LOF值 303 | for inlier in inliers2: 304 | inliers_instance1.append(inlier['instance'].tolist()) 305 | inliers_lof1.append(inlier['lof']) 306 | for outlier in outliers2: 307 | outliers_instance1.append(outlier['instance'].tolist()) 308 | outliers_lof1.append(outlier['lof']) 309 | #下面进行绘制图形(还可以写上有多少个异常值) 310 | ax[i//3][i%3].tick_params(size=5, labelsize=13) # 坐标轴 311 | ax[i//3][i%3].grid(alpha=0.3) # 是否加网格线 312 | ax[i//3][i%3].scatter([x[0] for x in inliers_instance1],[x[1] for x in inliers_instance1],s=35,c='#F21855',alpha=0.8,label='正常点') 313 | ax[i//3][i%3].scatter([x[0] for x in outliers_instance1],[x[1] for x in outliers_instance1],s=70,c='k',alpha=1,label='异常点') 314 | ax[i//3][i%3].legend() 315 | ax[i//3][i%3].set_xlabel('x轴', fontsize=13) 316 | ax[i//3][i%3].set_ylabel('y轴', fontsize=13) 317 | ax[i//3][i%3].set_title(f'k={k}(异常值数目为{len(outliers_instance1)})',fontsize=15) 318 | fig.suptitle('参数k的敏感性分析',fontsize=15) 319 | plt.tight_layout() 320 | plt.show() 321 | 322 | 323 | 324 | 325 | 326 | 327 | -------------------------------------------------------------------------------- /code/LSTM神经网络.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import pandas as pd 3 | import numpy as np 4 | from sklearn.preprocessing import MinMaxScaler 5 | from keras.models import Sequential 6 | from keras.layers import LSTM,Dense,Dropout 7 | from sklearn.metrics import mean_squared_error,mean_absolute_error,r2_score 8 | from keras import optimizers 9 | from keras.callbacks import ModelCheckpoint,EarlyStopping,ReduceLROnPlateau 10 | from keras.wrappers.scikit_learn import KerasRegressor 11 | from sklearn.model_selection import GridSearchCV 12 | 13 | #下面是多维输入预测当前值的(一一对应的拟合) 14 | #首先导入数据 15 | data=pd.read_csv('D:\\数据\\bit_score1.csv') 16 | data['earn_rate']=data['Value'].pct_change() #计算每日收益率(当前值减去前一个值再除去前一个值) 17 | data['Date']=pd.to_datetime(data['Date']) 18 | date_data=data['Date'] #存储下日期后面有用 19 | data.fillna(0,inplace=True) #填补空缺 20 | data.set_index(data['Date'],inplace=True) #将日期设置为索引,并且原地修改 21 | data.drop(columns=['Date','score'],inplace=True,axis=1) #删去不需要的列 22 | 23 | #下面进行数据标准化操作(0-1) 24 | scaler=MinMaxScaler(feature_range=(-1,1)) 25 | scale_data=scaler.fit_transform(data.values[:,:-1]) 26 | 27 | #下面进行划分训练集和测试集(注意还可以设置一个最终的测试集,因为下面的这个是用于验证用的) 28 | n=1500 #训练集截止序号 29 | train_x,train_y=scale_data[:n,:-1],data.values[:n,-1] #训练集 30 | test_x,test_y=scale_data[n:,:-1],data.values[n:,-1] 31 | 32 | #下面进行转化成三维数据 33 | train_X=train_x.reshape(train_x.shape[0],1,train_x.shape[1]) 34 | test_X=test_x.reshape(test_x.shape[0],1,test_x.shape[1]) 35 | train_Y=np.array(train_y) #y值坐标也要进行转换 36 | test_Y=np.array(test_y) 37 | 38 | #下面进行构建LSTM模型(Keras) 39 | model=Sequential() #定义模型 40 | model.add(LSTM(64,input_shape=(train_X.shape[1],train_X.shape[2]))) #注意结构(total_num,1,feature_num) 41 | model.add(Dropout(0.5)) #加入0.5的Dropout 42 | #添加输出层 43 | model.add(Dense(units=1,input_dim=64,kernel_initializer='glorot_uniform')) 44 | #Adam=optimizers.adam_v2.Adam(lr=0.01,decay=1e-6, beta_1=0.9, beta_2=0.999, epsilon=None,amsgrad=False) 45 | #下面进行按照验证集精度保存模型的最佳参数,其中monitor是指用什么参数来衡量,save_best_only表示只保存一种,mode是模式有(min,max,auto) 46 | checkpoint = ModelCheckpoint('weights.hdf5' , monitor = 'val_loss' , save_best_only = True,mode='auto') 47 | #下面是微调学习率,如果在5轮内验证集精度未上升,则学习率减半 48 | reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.5,patience=10, min_lr=0.00001) 49 | #下面进行配置模型参数 50 | model.compile(loss='mse',optimizer='adam') #loss用mse来衡量 51 | #下面进行训练模型操作(用测试集做验证) 52 | history=model.fit(train_X,train_Y,batch_size=100,epochs=100,workers=0,validation_data=(test_X,test_Y), verbose=2,shuffle=False,callbacks=[checkpoint,reduce_lr]) #设置batch_size和epoch,同时还设置验证集为0.2,同时存储训练过程的各种数据给history 53 | 54 | #下面进行绘制损失图 55 | plt.figure(figsize=(8,6)) 56 | plt.tick_params(size=5,labelsize =13) #坐标轴 57 | plt.grid(alpha=0.3) #是否加网格线· 58 | x=np.arange(len(history.history['loss'])) #设置x轴 59 | plt.plot(x,history.history['loss'],label='Training Loss',color='b',alpha=0.7) 60 | plt.plot(x,history.history['val_loss'],label='Valid Loss',color='r',alpha=0.7) 61 | plt.legend() 62 | plt.xlabel('epoch',fontsize=13) 63 | plt.ylabel('loss',fontsize=13) 64 | plt.title('Training Set And Test Set Loss',fontsize=15) 65 | plt.show() 66 | 67 | #下面进行预测验证集 68 | y_valid=model.predict(test_X) 69 | 70 | #下面进行可视化观察预测效果(盈利率) 71 | plt.figure(figsize=(8,6)) 72 | plt.tick_params(size=5,labelsize = 13) #坐标轴(可以调节坐标轴字体来自适应标签,还可以自定义标签) 73 | plt.grid(alpha=0.3) #是否加网格线· 74 | x=np.arange(len(date_data[n:])) #设置x轴 75 | plt.plot(date_data[n:],test_Y,label='original data',color='b',alpha=0.7) 76 | plt.plot(date_data[n:],y_valid,label='predict data',color='r',alpha=0.7) 77 | plt.legend() 78 | plt.xticks(fontsize=13,rotation=30) #调整x轴的字体,进行30度旋转 79 | plt.xlabel('Date',fontsize=13) 80 | plt.ylabel('Earn Rate',fontsize=13) 81 | plt.title('The Predicted Data Is Compared With The Original Data',fontsize=15) 82 | plt.show() 83 | 84 | #下面将盈利率乘进去得到股票的真实价值预测 85 | val_value=[] 86 | for step,i in enumerate(y_valid.ravel().tolist()): 87 | if step==0: 88 | val_value.append(data['Value'][n-2]*(1+i)) #注意这里要取前面的一个计算真实价值 89 | else: 90 | val_value.append(val_value[-1]*(1+i)) 91 | #val_value=pd.DataFrame(val_value).shift(periods=-1).values.tolist() #往前复原一个步长 92 | 93 | #下面进行绘制真实价值预测和原始图对比 94 | plt.figure(figsize=(8,6)) 95 | plt.tick_params(size=5,labelsize = 13) #坐标轴(可以调节坐标轴字体来自适应标签,还可以自定义标签) 96 | plt.grid(alpha=0.3) #是否加网格线· 97 | plt.plot(date_data[n:],data['Value'][1500:],label='original data',color='b',alpha=0.7) 98 | plt.plot(date_data[n:],val_value,label='predict data',color='r',alpha=0.7) 99 | plt.legend() 100 | plt.xticks(fontsize=13,rotation=30) #调整x轴的字体,进行30度旋转 101 | plt.xlabel('Date',fontsize=13) 102 | plt.ylabel('Value',fontsize=13) 103 | plt.title('The Predicted Data Is Compared With The Original Data',fontsize=15) 104 | plt.show() 105 | 106 | #下面继续模型评价(均方误差、均方根误差、R方、MAE) 107 | #均方误差MSE 108 | def mean_square_error(y1,y2): #y1是预测值序列,y2是真实值序列 109 | return np.sum((np.array(y1)-np.array(y2))**2)/len(y1) 110 | 111 | #均方根误差(RMSE) 112 | def root_mean_squard_error(y1,y2): #其中有y1是预测序列,y2是真实序列 113 | return np.sqrt(np.sum(np.square(np.array(y1)-np.array(y2)))/len(y1)) 114 | 115 | #平均绝对误差(MAE) 116 | def mean_absolute_error(y1,y2):#其中y1是预测序列,y2是真实序列 117 | return np.sum(np.abs(np.array(y1)-np.array(y2)))/len(y1) 118 | 119 | def computeCorrelation(x, y): #其中x,y均为序列,x是预测值,y是真实值,这里是计算Pearson相关系数,最后需要平方注意 120 | xBar = np.mean(x) #求预测值均值 121 | yBar = np.mean(y) #求真实值均值 122 | covXY = 0 123 | varX = 0 #计算x的方差和 124 | varY = 0 #计算y的方差和 125 | for i in range(0, len(x)): 126 | diffxx = x[i] - xBar #预测值减预测值均值 127 | diffyy = y[i] - yBar #真实值减真实值均值 128 | covXY += (diffxx * diffyy) 129 | varX += diffxx ** 2 130 | varY += diffyy ** 2 131 | return covXY/np.sqrt(varX*varY) 132 | 133 | #下面进行输出各个指标数值 134 | print(f'MSE:{mean_square_error(y_valid,test_Y)}\n' 135 | f'RMSE:{root_mean_squard_error(y_valid,test_Y)}\n' 136 | f'MAE:{mean_absolute_error(y_valid,test_Y)}\n' 137 | f'R方:{computeCorrelation(y_valid,test_Y)**2}\n') 138 | 139 | ################################################## 140 | #下面进行构造多个维度的输入且是多个时间步长 141 | ################################################## 142 | #下面是超参数 143 | n_feature=6 #特征数量 144 | n_past=30 #,创建数据集的时候,设置步长为30,也就是用前面30组数据预测下一个值(在) 145 | 146 | #下面进行数据缩放(注意也将目标值也进行缩放操作了) 变成shape为(w,h)形式 147 | value=data['Value'].tolist() 148 | data.drop('Value',axis=1,inplace=True) 149 | data['Value']=value #将其变成最后一列 150 | scaler=MinMaxScaler(feature_range=(0,1)) 151 | data_scale=scaler.fit_transform(data.values) 152 | 153 | #下面进行拆分数据(X和Y,设置步长预测下一个值)注意这里是针对多维数据的,仅仅就是时间序列的预测还要单独搞一下 154 | def Resetting_data(data,n_past): #其中data是输入的数据集(矩阵形式(二维)),n_past表示(步长)用之前的几个数据预测后一个值 155 | data_X=[] #存储步长为n_past数量的数据 156 | data_Y=[] #预测的下一个目标值,注意最后一个值就是对应着最后一个 157 | for i in range(n_past,len(data)): 158 | data_X.append(data[i-n_past:i,:-1]) 159 | data_Y.append(data[i,-1]) 160 | return np.array(data_X),np.array(data_Y) #最后的shape为(n,w,h)三维 161 | 162 | new_x,new_y=Resetting_data(data_scale,n_past) #对所有数据集拆分,设置步长为30,返回的是三维数据 163 | 164 | test_split=round(0.2*data.values.shape[0]) #测试集的占比 165 | train_x=new_x[:-test_split,:,:] 166 | test_x=new_x[-test_split:,:,:] 167 | train_y=new_y[:-test_split] 168 | test_y=new_y[-test_split:] 169 | 170 | #下面利用网格搜索的思想寻找最优的batch_size和epoch还有优化器(还未成功) 171 | '''def find_bestmodel(optimizer): #ootimizer是优化器种类 172 | grid_model=Sequential() 173 | grid_model.add(LSTM(50,return_sequences=True,input_shape=(n_past,train_x.shape[2]))) 174 | grid_model.add(LSTM(50)) 175 | grid_model.add(Dropout(0.2)) 176 | #添加输出层 177 | grid_model.add(Dense(units=1,input_dim=50,kernel_initializer='glorot_uniform')) #kernel_initializer='glorot_uniform' 178 | grid_model.compile(loss='mae',optimizer=optimizer) #模型配置 179 | 180 | grid_model = KerasRegressor(build_fn=find_bestmodel, verbose=1, validation_data=(test_x, test_y)) #创建一个训练器 181 | parameters = {'batch_size' : [8,32], 182 | 'epochs' : [8,40], 183 | 'optimizer' : ['adam','Adadelta'] } 184 | grid_search = GridSearchCV(estimator = grid_model, 185 | param_grid = parameters, 186 | cv = 3) #网格搜索加交叉验证(三折) 187 | grid_search=grid_search.fit(train_x,train_y) #进行训练''' 188 | 189 | #下面进行训练数据(可以进行各种调参(利用网格搜索的方式),不过下面就是手动调参)双层LSTM 190 | model=Sequential() 191 | model.add(LSTM(50,return_sequences=True,input_shape=(n_past,train_x.shape[2]))) #隐含层为50个神经元,returen sequences是返回最后的结果 192 | model.add(LSTM(50)) 193 | model.add(Dropout(0.2)) 194 | #添加输出层 195 | model.add(Dense(units=1,input_dim=50,kernel_initializer='glorot_uniform')) #kernel_initializer='glorot_uniform' 196 | 197 | #下面进行按照验证集精度保存模型的最佳参数,其中monitor是指用什么参数来衡量,save_best_only表示只保存一种,mode是模式有(min,max,auto) 198 | checkpoint = ModelCheckpoint('weights.hdf5' , monitor = 'val_loss' , save_best_only = True,mode='auto') 199 | #下面是微调学习率,如果在5轮内验证集精度未上升,则学习率减半 200 | reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.5,patience=5, min_lr=0.00001) 201 | #下面进行配置模型参数 202 | SGD=optimizers.gradient_descent_v2.SGD(lr=0.01,decay=1e-6, momentum=0.9, nesterov=True) 203 | model.compile(loss='mae',optimizer='adam') #loss用mse来衡量 204 | #下面进行训练模型操作(用测试集做验证) 205 | history=model.fit(train_x,train_y,batch_size=8,epochs=30,workers=-1,validation_data=(test_x,test_y), verbose=2,shuffle=False,callbacks=[checkpoint,reduce_lr]) #设置batch_size和epoch,同时还设置验证集为0.2,同时存储训练过程的各种数据给history 206 | 207 | #下面进行绘制损失图 208 | plt.figure(figsize=(8,6)) 209 | plt.tick_params(size=5,labelsize =13) #坐标轴 210 | plt.grid(alpha=0.3) #是否加网格线· 211 | x=np.arange(len(history.history['loss'])) #设置x轴 212 | plt.plot(x,history.history['loss'],label='Training Loss',color='b',alpha=0.7) 213 | plt.plot(x,history.history['val_loss'],label='Valid Loss',color='r',alpha=0.7) 214 | plt.legend() 215 | plt.xlabel('epoch',fontsize=13) 216 | plt.ylabel('loss',fontsize=13) 217 | plt.title('Training Set And Test Set Loss',fontsize=15) 218 | plt.show() 219 | 220 | #下面预测测试集同时将结果进行还原(因为原来对目标值做了标准化) 221 | model.load_weights('weights.hdf5') #加载最佳的模型 222 | predict_y=model.predict(test_x) #得到预测值 223 | predict_y_copy=np.repeat(predict_y,n_feature+1,axis=-1) #表示对predict_y进行数据增广操作,竖向复制成n_feature+1维(所有特征加上一列的目标值列),axis=-1表示新增维度进行增广(这里是指1按列) 224 | predict_y=scaler.inverse_transform(np.reshape(predict_y_copy,(len(test_y),n_feature+1)))[:,-1] #进行特征逆变换,同时只需要取其中一列就可以了,最终输出 225 | 226 | #下面进行可视化最终结果操作(注意需要把原始的值往后移一个步长,因为我们预测出的结果是针对下一个的) 227 | data['Value']=data['Value'].shift(periods=1) #针对于原始值,往后移动一个单位 228 | data['Value'].fillna(method='bfill',inplace=True) #用后一个不是缺失值的数据进行代替缺失值 229 | new_test_y=data['Value'][-test_split:] 230 | #下面进行绘制真实价值预测和原始图对比 231 | plt.figure(figsize=(8,6)) 232 | plt.tick_params(size=5,labelsize = 13) #坐标轴(可以调节坐标轴字体来自适应标签,还可以自定义标签) 233 | plt.grid(alpha=0.3) #是否加网格线· 234 | plt.plot(date_data[-test_split:],new_test_y,label='original data',color='b',alpha=0.7) 235 | plt.plot(date_data[-test_split:],predict_y,label='predict data',color='r',alpha=0.7) 236 | plt.legend() 237 | plt.xticks(fontsize=13,rotation=30) #调整x轴的字体,进行30度旋转 238 | plt.xlabel('Date',fontsize=13) 239 | plt.ylabel('Value',fontsize=13) 240 | plt.title('The Predicted Data Is Compared With The Original Data',fontsize=15) 241 | plt.show() 242 | 243 | #下面就是输出评价指标(针对原始值的) 244 | print('MSE:',mean_square_error(predict_y,new_test_y)) 245 | print('RMSE',root_mean_squard_error(predict_y,new_test_y)) 246 | print('MAE',mean_absolute_error(predict_y,new_test_y)) 247 | print('R方',computeCorrelation(predict_y,new_test_y)**2) 248 | 249 | #再下面就是进行后面未知的(用迭代的思想,用最优模型预测一个步长,再回测特征再送进模型预测) -------------------------------------------------------------------------------- /code/MK趋势检验和突变检验.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import pandas as pd 3 | import numpy as np 4 | import pymannkendall as mk #用于mk检验的包 5 | from scipy import stats 6 | from matplotlib import rcParams #导入包 7 | config = {"font.family":'Times New Roman'} # 设置字体类型 8 | rcParams.update(config) #进行更新配置 9 | 10 | #导入数据并进行预处理 11 | data=pd.read_csv('D:\\2023美赛\\海盗问题\\时间序列测试数据.csv',encoding='gbk') 12 | data['Date']=pd.to_datetime(data['Date']) 13 | 14 | #下面进行MK趋势检验 15 | result1=mk.original_test(data['num'],alpha=0.05) #导入数据并设置置信度 16 | print(result1) #输出结果 17 | """ 18 | trend就是表示趋势,有'no trend,increasing、decreasing三种类型' 19 | p就是p-value的值 20 | z就是计算的z值 21 | Tau是相关性 22 | s就是计算的s值 23 | var_s就是s的方差 24 | slope就是线性回归得到的x前面的参数 25 | """ 26 | 27 | #下面进行MK突变检验(检测时间序列数据的突变点(可能也能用于其他类型的数据)) 28 | #下面是计算UF和UB的函数 29 | def U_algorithm(data):#其中data是一组数据(一般是时间序列数据) 30 | n=len(data) #计算序列的长度 31 | Sk=[0] #Sk序列第一个为0 32 | Uk=[0] #存储UF或者UB的数据 33 | s=0 #作为中间数计算累计数 34 | E=[0] #存储均值的序列 35 | Var=[0] #存储方差的序列 36 | #下面计算累计数Sk,还有E和Var 37 | for i in range(1,n): 38 | for j in range(i): 39 | if data[j]', connectionstyle='arc3', color='blue', lw=2)) 80 | #下面设置坐标轴参数 81 | ax1.set_xlabel('Date',fontsize=13) 82 | ax1.set_ylabel('Statistic',fontsize=13) 83 | ax1.set_title('MK mutation test results',fontsize=15) 84 | ax1.set_ylim(min(total_U)-1,max(total_U)+1) #设置显示范围 85 | #下面进行绘制原始的时间序列数据 86 | ax2 = ax1.twinx() #和第一类数据共享x轴(新设置图) 87 | plot2=ax2.plot(data['Date'],data['num'],color='#FFDD24',alpha=0.5,lw=1.5,label='Raw data') 88 | ax2.set_ylabel('Count',fontsize=13) #设置ax2的y轴参数 89 | ax2.set_ylim(min(data['num'])-10,max(data['num'])+10) 90 | lines=plot1+plot2+plot3 91 | ax1.legend(lines,[l.get_label() for l in lines]) #打上图例 92 | plt.show() 93 | 94 | -------------------------------------------------------------------------------- /code/Prophet时间序列分析和预测.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | from fbprophet import Prophet 5 | from matplotlib import rcParams #导入包 6 | 7 | config = {"font.family":'Times New Roman'} # 设置字体类型 8 | rcParams.update(config) #进行更新配置 9 | 10 | #导入数据,并提取出需要用的数据 11 | data=pd.read_csv('D:\\2023美赛\\2023\\处理后的数据.csv')[['Date','Number of reported results']] 12 | #转化时间格式 13 | data['Date']=pd.to_datetime(data['Date']) 14 | data.rename(columns={'Date':'ds','Number of reported results':'y'},inplace=True) 15 | 16 | #下面进行构Prophet模型 17 | #注意 18 | model = Prophet(growth="linear", #趋势项模型,还可以设置为logistic,注意设置为logistic时,要确保原数据有一列数据为承载力上限(要自己设置),例如data['cap']=3.5 19 | #下面是用于趋势项变点的设置参数,chagepoints表示人为设置变点,传入参数为时间的列表,n_changepoints表示变点的数量,chagepoint_prior_scale表示变点的强度影响 20 | changepoints=None,n_changepoints=25,changepoint_prior_scale=0.05, 21 | #下面是进行添加节假日信息,holidays为传入的节假日时间列表,holidays_prior_scale表示节假日影响因子。 22 | holidays=None,holidays_prior_scale=10.0, 23 | interval_width = 0.95, #获取95%的置信区间 24 | ) 25 | 26 | #下面可以进行自定义周期 27 | #其中name是名称,可以任意取,period是周期,fourier_order是级数的数量(根据经验一般7天选3,一年选择10),prior_scale就是季节性强度参数可以用于后续的敏感性分析 28 | model.add_seasonality(name='weekly',period=7,fourier_order=3,prior_scale=10.0) 29 | 30 | #下面进行添加节假日信息 31 | model.add_country_holidays('CN') #可以添加某个国家的节假日信息,如US、CN等等 32 | 33 | #下面进行拟合模型 34 | model.fit(data) 35 | 36 | #下面进行设置预测的时间列(预测往后的30天)(注意其同时也包括了原始的时间列) 37 | period=30 38 | future=model.make_future_dataframe(periods=period,freq='D') 39 | 40 | #下面进行最终模型的预测 41 | forecast=model.predict(future) #注意其中包含了很多列数据,主要需要的就是yhat/yhat_lower/yhat_uuper/trend/weekly(自己前面设置的周期性因子)/holidays(前面设置的节假日因子) 42 | change_points=model.changepoints #获取变点的x轴坐标(时间) 43 | 44 | #下面进行绘制拟合和预测的曲线(包含置信区间) 45 | plt.figure(figsize=(8,6)) 46 | plt.tick_params(size=5,labelsize = 13) #坐标轴 47 | plt.grid(alpha=0.3) #是否加网格线· 48 | #先绘制原始数据点 49 | plt.scatter(data['ds'],data['y'],marker='o',color='#2049ff',s=20,label='Raw data') 50 | #下面绘制预测的曲线 51 | plt.plot(future,forecast['yhat'],color='#F21855',lw=2,label='Forecast curve') 52 | #下面进行绘制95%置信区间 53 | plt.fill_between(future['ds'].tolist(),forecast['yhat_lower'],forecast['yhat_upper'],color='#F21855',alpha=0.3,label='95% confidence interval') 54 | #划分训练集和预测集 55 | plt.axvline(x=future.iloc[-period], color='#bf0000',lw=2,linestyle=':') 56 | plt.text(future.iloc[-period-30],300000,s='Past',fontsize=15) 57 | plt.text(future.iloc[-period+5],300000,s='Future',fontsize=15) 58 | plt.legend() 59 | plt.title('Model prediction results',fontsize=15) 60 | plt.xlabel('Fate',fontsize=13) 61 | plt.ylabel('Value',fontsize=13) 62 | plt.show() 63 | 64 | #下面进行时间序列分解 65 | fig,ax=plt.subplots(3,1,figsize=(8,6)) 66 | #trend 67 | ax[0].plot(future,forecast['trend'],label='Trend',color='#F21855',lw=1.5,alpha=1) 68 | #下面进行绘制趋势因子的上下限 69 | ax[0].fill_between(future['ds'].tolist(),forecast['trend_lower'],forecast['trend_upper'],alpha=0.3,color='#F21855',label='95% confidence interval') 70 | #下面添加箭头表示趋势(可以根据实际情况操作) 71 | #ax[0].annotate('', xy=(trend.index[-15], 25), xytext=(trend.index[-40],30), 72 | #arrowprops=dict(arrowstyle='->', connectionstyle='arc3', color='blue', lw=2,alpha=0.6)) 73 | print(forecast['weekly']) 74 | ax[0].legend() 75 | ax[0].set_ylabel('Trend',fontsize=13) 76 | ax[0].set_title('Time series decomposition results',fontsize=15) 77 | ax[0].legend() 78 | ax[0].tick_params(size=5,labelsize = 13) #坐标轴 79 | ax[0].grid(alpha=0.3) #是否加网格线 80 | #holidays 81 | ax[1].plot(future,forecast['holidays'],label='Holidays',color='#52D896',lw=1.5,alpha=1) 82 | ax[1].set_ylabel('Holidays',fontsize=13) 83 | ax[1].legend() 84 | ax[1].tick_params(size=5,labelsize = 13) #坐标轴 85 | ax[1].grid(alpha=0.3) #是否加网格线 86 | #seasonal(根据自己设置的周期)注意还可以只绘制出一个周期来表示 87 | ax[2].plot(future,forecast['weekly'],label='Seasonal',color='#FFDD24',alpha=1) 88 | ax[2].set_xlabel('Date',fontsize=13) 89 | ax[2].set_ylabel('Seasonal',fontsize=13) 90 | ax[2].legend() 91 | ax[2].tick_params(size=5,labelsize = 13) #坐标轴 92 | ax[2].grid(alpha=0.3) #是否加网格线""" 93 | plt.tight_layout() #自动调整子图间距 94 | plt.show() 95 | 96 | #下面进行验证模型的验证精度,可以用均方误差、R方,aic、bic,前面分成训练集和验证集来进行等等 97 | #均方误差MSE 98 | def mean_square_error(y1,y2): #y1是预测值序列,y2是真实值序列 99 | return np.sum((np.array(y1)-np.array(y2))**2)/len(y1) 100 | 101 | #第二种计算R方的方式 (1-(SSE/SST)) 102 | def R_Squre2(y_pred,y_real): #其中y_pred是预测值,y_real是真实值,两者都是序列 103 | y_real_mean = np.mean(y_real) 104 | y_pred_var=0 #计算预测值减真实值的平方和 105 | y_real_var=0 106 | for i in range(len(y_pred)): 107 | y_pred_var+=(y_pred[i]-y_real[i])**2 108 | y_real_var+=(y_real[i]-y_real_mean)**2 109 | return 1-y_pred_var/y_real_var 110 | 111 | print('R方为{}'.format(R_Squre2(forecast['yhat'][:-period],data['y']))) 112 | print('均方误差为{}'.format(mean_square_error(forecast['yhat'][:-period],data['y']))) 113 | print(data['ds']) 114 | #下面进行模型的敏感性分析,主要对三个参数changepoint_prior_scale/holidays_prior_scale/seasonal_prior_scale进行分析 115 | #进行趋势项因子强度的敏感性分析(变点强度) 116 | trend_list=[0.1,0.3,0.5,0.7,0.9] 117 | result1=[] #用于存储每一次预测的值形式为[[],[]] 118 | for i in trend_list: 119 | model1 = Prophet(growth="linear", #趋势项模型,还可以设置为logistic,注意设置为logistic时,要确保原数据有一列数据为承载力上限(要自己设置),例如data['cap']=3.5 120 | #下面是用于趋势项变点的设置参数,chagepoints表示人为设置变点,传入参数为时间的列表,n_changepoints表示变点的数量,chagepoint_prior_scale表示变点的强度影响 121 | changepoints=None,n_changepoints=25,changepoint_prior_scale=i, 122 | #下面是进行添加节假日信息,holidays为传入的节假日时间列表,holidays_prior_scale表示节假日影响因子。 123 | holidays=None,holidays_prior_scale=10.0, 124 | interval_width = 0.95, #获取95%的置信区间 125 | ) 126 | #下面可以进行自定义周期 127 | #其中name是名称,可以任意取,period是周期,fourier_order是级数的数量(根据经验一般7天选3,一年选择10),prior_scale就是季节性强度参数可以用于后续的敏感性分析 128 | model1.add_seasonality(name='weekly',period=7,fourier_order=3,prior_scale=10.0) 129 | model1.fit(data) 130 | #下面进行预测并存储数据,注意输入预测的形式的列名一定要有且是'ds'才行 131 | result1.append(model1.predict(pd.DataFrame({'ds':data['ds'].tolist()}))['yhat'].tolist())#只存储预测的值,其余不管 132 | #输出 133 | print(result1) 134 | #下面进行季节性强度因子和节假日强度因子的敏感性分析同理 135 | #注意可以将三个敏感性分析绘制成三个横向的折线图形式(还可以分别加上阴影和箭头标签) 136 | -------------------------------------------------------------------------------- /code/TOPSIS法.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | def vector_normalization1(X): #向量标准化就是一种占比(0,1),主要用于TOPSIS,X是输入的矩阵,输出是经过标准化后的矩阵 3 | for i in range(X.shape[1]): 4 | X[:,i]=X[:,i]/(sum(X[:,i]**2)**0.5) 5 | return X 6 | 7 | def vector_normalization2(X): #向量标准化方式 8 | a=[i**2 for i in X] 9 | return [i/(sum(a)**0.5) for i in X] 10 | 11 | #TOPSIS法(结合权重) 12 | def TOPSIS_method(X,w): #输入是待评价的矩阵和权重列表,包含评价指标和各个项目。输出是各个项目对应的相对接近度,其越大则说明越好 13 | x_max=np.max(X,axis=0) #每个指标的最大值 14 | x_min=np.min(X,axis=0) #每个指标的最小值 15 | result=[] 16 | for i in range(X.shape[0]): 17 | D1 = sum(((X[i,:]-x_max)**2)*np.array(w))**0.5 18 | D2= sum(((X[i,:]-x_min)**2)*np.array(w))**0.5 19 | result.append(D2/(D1+D2)) 20 | return result -------------------------------------------------------------------------------- /code/XGboost算法回归与分类.py: -------------------------------------------------------------------------------- 1 | import xgboost as xgb 2 | from xgboost import XGBClassifier,XGBRegressor 3 | from xgboost import plot_importance 4 | from sklearn.model_selection import cross_val_score 5 | from sklearn.model_selection import StratifiedKFold,KFold 6 | from sklearn.datasets import load_iris 7 | from sklearn.model_selection import train_test_split 8 | import matplotlib.pyplot as plt 9 | import numpy as np 10 | from matplotlib import rcParams #导入包 11 | from sklearn import metrics 12 | import seaborn as sns 13 | from sklearn.datasets import load_boston #导入房价数据 14 | 15 | #改变字体 16 | config = {"font.family":'Times New Roman'} # 设置字体类型 17 | rcParams.update(config) #进行更新配置 18 | #首先导入鸢尾花数据集(分类数据)四维特征 19 | iris=load_iris() 20 | x=np.array(iris.data) #特征集 21 | y=np.array(iris.target) #标签 22 | #下面进行划分训练集和测试集 23 | x_test=x[-6:,:] 24 | y_test=y[-6:] 25 | #下面进行划分训练集和验证集 26 | x_train, x_valid, y_train, y_valid = train_test_split(x[:-6,:], y[:-6], test_size=0.2) 27 | #下面进行重构成xgboost的输入数据(训练集、验证机和测试集都要) 28 | train=xgb.DMatrix(x_train,label=y_train) 29 | valid=xgb.DMatrix(x_valid,label=y_valid) 30 | test=xgb.DMatrix(x_test) #测试集转换可以不用输入标签 31 | # 参数设置 32 | params = { 33 | 'booster': 'gbtree', #基分类器的类型 可以是ugbtree、gblinear和dart 34 | 'objective':'multi:softmax', #目标的类型(具体可以查看文本),多分类的就是multi:softmax 回归就选reg:linear 二分类就选binary:logistic 35 | 'num_class': 3, #标签的分类类别数 36 | 'max_depth':6, #最大树深,越大越容易过拟合。[1,+∞]之间 37 | 'eta':0.3,#即learning_rate。[0,1]之间。 38 | 'silent':1, #0状态会打印信息,1表示不打印信息 39 | 'gamma':0, #在树的叶子节点上进一步划分的最小损失量,值越大,算法就越保守。[0,+∞]之间。 40 | 'min_child_weight':1,#树构建过程中,当节点的权重小于这个值则分支会被丢弃,值越大,算法越保守。[0,+∞]之间。 41 | 'subsample':1, #样本的采样比例,值越大,越容易过拟合。(0,1]之间。 42 | 'colsample_bytree':1, #构建每棵树时列的采样比率。(0,1]之间。 43 | 'colsample_bylevel':1, #每一级的每一次分裂的采样比率。(0,1]之间。 44 | 'lambda':1,#L2正则。 45 | 'alpha':0, #L1正则。 46 | 'nthread':-1, 47 | 'eval_metric':'merror', #评估方法,分类就用merror(错误率)、logloss(交叉熵损失函数),,回归可以用rmse,mae,二分类可以用auc 48 | 'seed':0, 49 | } 50 | #下面进行模型训练(用训练集和验证集) 其中num_boost_round是迭代的次数,也可以称为最终迭代后树的数量,每次增加迭代增加一个弱分类器最终达到 51 | model=xgb.train(params,train,num_boost_round=100, evals=[(valid,'eval')]) #注意训练过程中会不断输出每一轮的验证集评估方法merror 52 | 53 | #下面是绘制特征重要性条形图 54 | #首先获取各特征的重要性并进行升序排序 55 | sort_list=[(name,value) for name,value in model.get_fscore().items()] #注意刚开始的顺序就是从第一列特征f0开始的(也就是后面的name_list可以更换成各特征原始名称) 56 | sort_list=sorted(sort_list,reverse=False,key=lambda x:x[1]) #降序 57 | name_list=[x[0] for x in sort_list] #存储排序后的特征名称列表 58 | value_list=[x[1] for x in sort_list] #存储排序后的特征Fscore值 59 | #下面进行绘制竖着的条形图F score(注意是从下往上绘制的,因此原来的序列是升序的) 60 | height=0.25 #高度(每个条形之间) 61 | index=np.arange(x_train.shape[1]) #特征类别个数 62 | plt.figure(figsize=(7,5)) 63 | plt.tick_params(size=5,labelsize = 13) #坐标轴 64 | plt.grid(alpha=0.3) #是否加网格线· 65 | plt.barh(index,value_list,height=height,color='#F21855',alpha=1) 66 | #下面进行打上标签(注意细节,交换了y/x) 67 | for i,data in enumerate(value_list): 68 | plt.text(data+7,index[i]-0.06,round(data,1),horizontalalignment='center',fontsize=13) #具体位置可以进行微调 69 | plt.xlim(0,max(value_list)+30) #改变x轴的显示范围 70 | plt.yticks(index,name_list) #设置y轴的标签 71 | plt.xlabel('F score',fontsize=13) #注意这个还是横轴的 72 | plt.ylabel('Features',fontsize=13) #竖轴的标签 73 | plt.title('Feature importance',fontsize=15) 74 | plt.show() 75 | 76 | #下面进行测试集的预测 77 | pred=model.predict(test) 78 | 79 | #下面进行计算测试集的精度 80 | acc=metrics.accuracy_score(y_test,pred) 81 | print(acc) 82 | 83 | #下面进行绘制混淆矩阵 84 | confusion_matrix=metrics.confusion_matrix(y_test,pred) 85 | plt.figure(figsize=(8,6)) 86 | sns.heatmap(confusion_matrix,cmap="YlGnBu_r",fmt="d",annot=True) 87 | plt.xlabel('prediction category',fontsize=13) #横轴是预测类别 88 | plt.ylabel('real category',fontsize=13) #数轴是真实类别 89 | plt.title('confusion matrix',fontsize=15) 90 | plt.show() 91 | 92 | #对于分类模型来说(注意还可以输出概率,得到ROC曲线) 93 | 94 | #敏感性分析可以通过改变树的深度(max_depth)、弱分类器的数量(num_round_boost)、迭代次数、输入特征的维度(随机)、损失的选择等等 95 | #注意如果想对模型进行交叉验证的话,用下列的方式 96 | new_model=XGBClassifier(n_estimators=100) #其中n_estimators等价于num_boost_bound 97 | score=cross_val_score(new_model,x[:-6,:],y[:-6],cv=5) #进行五折交叉验证 98 | print(score.mean()) #输出 99 | 100 | #下面进行XGboost回归(波士顿房价数据)十三维的特征 101 | boston = load_boston() 102 | x1=np.array(boston.data) 103 | y1=np.array(boston.target) 104 | #划分测试集 105 | x_test1=x1[-50:,:] 106 | y_test1=y1[-50:] 107 | #下面进行划分训练集和验证集 108 | x_train1, x_valid1, y_train1, y_valid1 = train_test_split(x1[:-50,:], y1[:-50], test_size=0.2) 109 | #转变数据格式 110 | train1 = xgb.DMatrix(x_train1, label=y_train1) 111 | valid1 = xgb.DMatrix(x_valid1, label=y_valid1) 112 | test1 = xgb.DMatrix(x_test1) 113 | total_data1=xgb.DMatrix(x1[:-50,:]) #包含训练集和验证集的数据用于后续的绘制拟合图像 114 | total_data2=xgb.DMatrix(x1) #这里是包含所有数据的,用于后续的模型评价分析 115 | # 参数设置 116 | params1 = { 117 | 'booster': 'gbtree', 118 | 'objective':'reg:linear', 119 | 'max_depth':6, 120 | 'eta':0.1, 121 | 'silent':1, 122 | 'gamma':0, 123 | 'min_child_weight':1, 124 | 'subsample':1, 125 | 'colsample_bytree':1, 126 | 'colsample_bylevel':1, 127 | 'lambda':1, 128 | 'alpha':0, 129 | 'nthread':-1, 130 | 'eval_metric':'rmse', 131 | 'seed':0 132 | } 133 | # 模型训练 134 | model1 = xgb.train(params1,train1,num_boost_round=100,evals=[(valid1,'eval')]) #其中num_boost_round是迭代的次数也可以理解为树的数量 135 | 136 | #下面是绘制特征重要性条形图 137 | #首先获取各特征的重要性并进行升序排序 138 | sort_list1=[(name,value) for name,value in model1.get_fscore().items()] #注意刚开始的顺序就是从第一列特征f0开始的(也就是后面的name_list可以更换成各特征原始名称) 139 | sort_list1=sorted(sort_list1,reverse=False,key=lambda x:x[1]) #降序 140 | name_list1=[x[0] for x in sort_list1] #存储排序后的特征名称列表 141 | value_list1=[x[1] for x in sort_list1] #存储排序后的特征Fscore值 142 | 143 | #下面进行绘制竖着的条形图F score(注意是从下往上绘制的,因此原来的序列是升序的) 144 | height=0.25 #高度(每个条形之间) 145 | index1=np.arange(x_train1.shape[1]) #特征类别个数 146 | plt.figure(figsize=(7,5)) 147 | plt.tick_params(size=5,labelsize = 13) #坐标轴 148 | plt.grid(alpha=0.3) #是否加网格线· 149 | plt.barh(index1,value_list1,height=height,color='#F21855',alpha=1) 150 | #下面进行打上标签(注意细节,交换了y/x) 151 | for i,data in enumerate(value_list1): 152 | plt.text(data+29,index1[i]-0.16,round(data,1),horizontalalignment='center',fontsize=13) #具体位置可以进行微调 153 | plt.xlim(0,max(value_list1)+65) #改变x轴的显示范围 154 | plt.yticks(index1,name_list1) #设置y轴的标签 155 | plt.xlabel('F score',fontsize=13) #注意这个还是横轴的 156 | plt.ylabel('Features',fontsize=13) #竖轴的标签 157 | plt.title('Feature importance',fontsize=15) 158 | plt.show() 159 | 160 | #下面还可以进行绘制模型损失函数在每一轮迭代的变化情况图(将打印的信息全部整合到一个csv文件中再进行绘制即可) 161 | pred_train_valid=model1.predict(total_data1).tolist() #训练集预测 162 | pred_test=model1.predict(test1).tolist() #测试集预测 163 | pred_test1=[pred_train_valid[-1]]+pred_test #注意绘制预测的曲线时要在列表最前面加上train和valid中最后一个数 164 | 165 | #下面进行绘制的拟合效果和测试效果(训练集、验证集和测试集) 166 | plt.figure(figsize=(7,5)) 167 | plt.tick_params(size=5,labelsize = 13) #坐标轴 168 | plt.grid(alpha=0.3) #是否加网格线· 169 | #先绘制原始数据(注意x轴的序号) 170 | plt.scatter(np.arange(1,len(y1[:-50])+1),y1[:-50],marker='o',color='#2049ff',s=15,label='Raw data for training set and validation set') #训练集和验证集 171 | plt.scatter(np.arange(len(y1[:-50])+1,len(y1)+1),y1[-50:],marker='^',color='#FFDD24',s=15,label='Test set raw data') #测试集 172 | #下面进行绘制预测的曲线(注意第二条线x轴的序号,要前移一位) 173 | plt.plot(np.arange(1,len(y1[:-50])+1),pred_train_valid,color='#52D896',lw=1,ls='solid',label='Prediction data for training set and test set') 174 | plt.plot(np.arange(len(y1[:-50]),len(y1)+1),pred_test1,color='#F21855',lw=1,ls='solid',label='Test set prediction data') 175 | #下面进行绘制分割线 176 | plt.axvline(x=len(y1[:-50]), color='#bf0000',lw=2,linestyle='dashed') 177 | #下面进行打上文字标签 178 | plt.text(480,45,s='Test set',fontsize=10) 179 | plt.text(-12,48,s='Training set and validation set',fontsize=10) 180 | #下面进行其余的细节设置 181 | plt.legend() 182 | plt.xlabel('Index',fontsize=13) 183 | plt.ylabel('Price',fontsize=13) 184 | plt.title('Regression prediction of house prices',fontsize=15) 185 | plt.show() 186 | 187 | #下面可以对所有数据进行R方、MSE等指标的运算(注意还可以输出概率,得到ROC曲线) 188 | pred_total=model1.predict(total_data2) #得到所有预测的数据 189 | 190 | #第二种计算R方的方式 (1-(SSE/SST)) 191 | def R_Squre2(y_pred,y_real): #其中y_pred是预测值,y_real是真实值,两者都是序列 192 | y_real_mean = np.mean(y_real) 193 | y_pred_var=0 #计算预测值减真实值的平方和 194 | y_real_var=0 195 | for i in range(len(y_pred)): 196 | y_pred_var+=(y_pred[i]-y_real[i])**2 197 | y_real_var+=(y_real[i]-y_real_mean)**2 198 | return 1-y_pred_var/y_real_var 199 | 200 | print(R_Squre2(pred_total,y1)) #R方值 201 | -------------------------------------------------------------------------------- /code/logit回归(逻辑回归).py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import numpy as np 3 | import statsmodels.api as sm 4 | import pylab as pl 5 | import matplotlib.pyplot as plt 6 | import copy 7 | from sklearn import metrics 8 | from sklearn.ensemble import RandomForestClassifier 9 | from sklearn.linear_model import LogisticRegression 10 | import seaborn as sns 11 | from sklearn.preprocessing import label_binarize 12 | from sklearn.multiclass import OneVsRestClassifier 13 | from sklearn.metrics import roc_curve, auc 14 | 15 | #读取数据(注意数据都已经正向化过了) 16 | df=pd.read_csv('D:\\2022国赛数模练习题\\有风险系数的有信贷信息企业.csv',encoding='gbk') 17 | #展现数据 18 | #print(df.head()) 19 | 20 | #定于需要数据的column 21 | data_columns=['是否违约','信誉评级','合格发票率','年平均利润','净发票总金额','总盈利率','月平均增长盈利率','风险因子','风险系数'] 22 | data=df[data_columns] #选取有用的数据 23 | #简答的看一下数据的总体情况 24 | #print(df.describe()) 25 | """plt.rcParams['font.sans-serif'] = ['SimHei'] 26 | plt.rcParams['axes.unicode_minus'] = False 27 | df.hist()#等于是创建了一个画板并且在里面已经绘制了东西 28 | plt.show()""" 29 | 30 | # 需要自行添加逻辑回归所需的intercept变量 31 | data['intercept'] = 1.0 32 | 33 | #指定作为训练变量的列,不含目标(注意可以用sklearn中的train_test_split进行分割训练集和测试集) 34 | train_cols=data_columns[1:] 35 | #定义logit模型 36 | logit=sm.Logit(data['是否违约'],data[train_cols]) 37 | #拟合模型 38 | result=logit.fit() 39 | #最终查看数据要点 40 | print(result.summary()) #可以看伪R方来看拟合的程度 41 | #下面可以进行预测操作 42 | # 构建预测集 43 | # 与训练集相似,一般也是通过 pd.read_csv() 读入 44 | # 在这边为方便,我们将训练集拷贝一份作为预测集(不包括 admin 列) 45 | combos = copy.deepcopy(data) 46 | # 预测集也要添加intercept变量 47 | combos['intercept'] = 1.0 48 | combos['predict'] = result.predict(combos[data_columns[1:]]) 49 | # 预测完成后,predict 的值是介于 [0, 1] 间的概率值 50 | # 我们可以根据需要,提取预测结果 51 | # 例如,假定 predict > 0.5,则表示会被录取 52 | # 在这边我们检验一下上述选取结果的精确度 53 | combos['预测是否违约']=combos['predict'].apply(lambda x:1 if x>0.5 else 0) 54 | #计算精确度 55 | print(1-sum(np.abs(combos['预测是否违约']-data['是否违约']))/len(combos['预测是否违约'])) 56 | 57 | #第二种方式(注意sklearn中的逻辑回归模型会自动进行正则化,因此求出的参数跟sm中的模型不一致) 58 | #其中penalty是惩罚项,可以选择l1或l2正则化,是防止过拟合用的。solver是优化方法有五种类型。最后的C表示正则化强度的倒数,必须是一个大于0的浮点数,不填写默认1.0,即默认正则项与损失函数的比值是1:1。C越小,损失函数会越小,模型对损失函数的惩罚越重,正则化的效力越强,参数会逐渐被压缩得越来越小。 59 | logit1= LogisticRegression(fit_intercept = False) #其中penalty是惩罚项,可以选择l1或l2正则化,是防止过拟合用的。solver是优化方法有五种类型。最后 60 | #penalty="l2",solver="liblinear",C=0.5,max_iter=1000 参数设置 61 | logit1.fit(data[train_cols], data['是否违约']) #进行训练模型 62 | print(logit1.coef_) #输出逻辑回归方程系数 63 | print(logit1.score(data[train_cols],data['是否违约'])) #得到准确率 64 | #logit1.predict(x_test) #进行预测 65 | logit1_predict=logit1.predict(data[train_cols]) #预测标签 66 | logit1_proba=logit1.predict_proba(data[train_cols])[:,1] #计算二分类概率(计算其为1的概率) 67 | 68 | #下面我们进行可以进行绘制ROC曲线和计算AUC值(这里是计算总体的)注意需要用概率来进行计算 69 | fpr,tpr,_=metrics.roc_curve(combos['是否违约'],combos['predict']) #第一个参数是原始值,第二个参数是预测的概率值,计算ROC曲线点值 70 | roc_auc =metrics.auc(fpr,tpr) 71 | #绘制ROC曲线 72 | plt.figure(figsize=(8,6)) 73 | plt.plot(fpr, tpr,label='ROC curve (area = {0:0.2f})'''.format(roc_auc), 74 | color='deeppink', linewidth=4) 75 | plt.stackplot(fpr,tpr,colors='steelblue',alpha=0.5,edgecolor='black') 76 | plt.plot([0, 1], [0, 1], 'k--', lw=2) #绘制对角线 77 | plt.text(0.5,0.3,f'ROC curve(area = {roc_auc:.4f})',fontsize=13) #打上标签 78 | plt.legend(loc='lower right') 79 | plt.xlabel('False Positive Rate',fontsize=13) 80 | plt.ylabel('True Positive Rate',fontsize=13) 81 | plt.title('ROC-Kurve',fontsize=15) 82 | plt.show() 83 | 84 | #下面进行绘制混淆矩阵 85 | confusion_matrix=metrics.confusion_matrix(combos['是否违约'],logit1_predict) 86 | plt.figure(figsize=(8,6)) 87 | sns.heatmap(confusion_matrix,cmap="YlGnBu_r",fmt="d",annot=True) 88 | plt.xlabel('Prediction category',fontsize=13) #横轴是预测类别 89 | plt.ylabel('Real category',fontsize=13) #数轴是真实类别 90 | plt.title('Confusion matrix',fontsize=15) 91 | plt.show() 92 | 93 | #下面进行一次性得到多分类的逻辑回归参数,并绘制多分类的ROC曲线 94 | new_data=pd.read_csv('D:\\2023美赛\\2023\\带有标签的数据.csv',encoding='gbk') 95 | X=new_data[['same_letter','num_vowel','num_monogram']].values #自变量数据 96 | # 创建多类被逻辑回归对象(有几个分类标签就创建几个逻辑回归模型) 97 | clf = LogisticRegression(multi_class='ovr') 98 | # 拟合模型 99 | clf.fit(X,new_data['label']) 100 | # 计算系数(输出所有逻辑回归模型的回归系数矩阵 ) 101 | coef = clf.coef_ 102 | 103 | #下面进行绘制多类别的ROC曲线(可以采用下面的方式,可以自己通过搭建多个逻辑回归模型搞) 104 | Y=label_binarize(new_data['label'], classes=[0, 1, 2]) #进行标签二值化 105 | n_classes = Y.shape[1] 106 | # 创建逻辑回归对象 107 | clf = OneVsRestClassifier(LogisticRegression()) 108 | # 训练模型 109 | y_score = clf.fit(X, Y).decision_function(X) 110 | 111 | # 计算每个类别的ROC曲线和AUC值 112 | fpr = dict() 113 | tpr = dict() 114 | roc_auc = dict() 115 | for i in range(n_classes): 116 | fpr[i], tpr[i], _ = roc_curve(Y[:, i], y_score[:, i]) 117 | roc_auc[i] = auc(fpr[i], tpr[i]) 118 | #下面是计算均值 119 | fpr["micro"], tpr["micro"], _ = roc_curve(Y.ravel(), y_score.ravel()) 120 | roc_auc["micro"] = auc(fpr["micro"], tpr["micro"]) 121 | 122 | #开始绘制ROC曲线 123 | plt.figure(figsize=(8,6)) 124 | plt.tick_params(size=5,labelsize = 13) #坐标轴 125 | plt.grid(alpha=0.3) #是否加网格线 126 | #绘制平均的ROC曲线 127 | plt.plot(fpr["micro"], tpr["micro"], 128 | label='micro-average ROC curve (area = {0:0.2f})' 129 | ''.format(roc_auc["micro"]), 130 | color='deeppink', linestyle=':', linewidth=4) 131 | 132 | colors = ['#2779ac','#f2811d', '#349d35'] #颜色序列有几类用几种 133 | for i ,color in enumerate(colors): 134 | plt.plot(fpr[i],tpr[i],color=color,lw=2,label='ROC curve of class {0} (area = {1:0.2f})' 135 | ''.format(i, roc_auc[i])) #绘制曲线同时打上AUC面积标签 136 | plt.plot([0, 1], [0, 1], 'k--', lw=2) #绘制对角线 137 | plt.xlabel('False Positive Rate',fontsize=13) 138 | plt.ylabel('True Positive Rate',fontsize=13) 139 | plt.title('ROC-Kurve',fontsize=15) 140 | plt.legend(loc="lower right") 141 | #plt.savefig('D:\\2023美赛\\2023\\图\\ROC曲线.svg',format='svg',bbox_inches='tight') 142 | plt.show() 143 | 144 | -------------------------------------------------------------------------------- /code/主成分分析法.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | from factor_analyzer.factor_analyzer import calculate_bartlett_sphericity #Bartlett’s球状检验 4 | from factor_analyzer.factor_analyzer import calculate_kmo #KMO检验 5 | from sklearn.decomposition import PCA 6 | import matplotlib.pyplot as plt 7 | import seaborn as sns 8 | 9 | #导入数据 10 | data=pd.read_csv('D:\\2022国赛数模练习题\\附件2.csv',encoding='gbk') 11 | #剔除无用的列 12 | data.drop(columns='编号',inplace=True) 13 | 14 | #进行数据标准化操作 15 | def standardization(data): #data是矩阵,主要功能是进行标准化,输出是经过标准化的矩阵 16 | data_std=[np.std(data[:,i]) for i in range(data.shape[1])] 17 | data_mean=[np.mean(data[:,i]) for i in range(data.shape[1])] 18 | for i in range(data.shape[1]): 19 | data[:,i]=(data[:,i]-data_mean[i])/data_std[i] 20 | return data 21 | data_columns=data.columns#存储列名 22 | data=pd.DataFrame(standardization(data.values),columns=data_columns) 23 | 24 | #下面进行充分性检验(下面两步骤在不严格的情况下可以忽略) 25 | #1Bartlett’s球状检验 26 | chi_square_value, p_value = calculate_bartlett_sphericity(data) 27 | print(chi_square_value,p_value) #p值小于0.05,检验通过,能进行主成分分析 28 | 29 | #2KMO检验 30 | kmo_all,kmo_model=calculate_kmo(data) 31 | print(kmo_model) #大于0.6说明变量之间的相关性强,能进行主成分分析 32 | 33 | #下面运用sklearn中的PCA函数进行主成分分析建模 34 | #先观察方差贡献率来选择因子数量 35 | pca=PCA(n_components=8) #提取因子数量(先选多点) 36 | pca.fit(data) 37 | explained_variance=pca.explained_variance_ #贡献方差,即特征根 38 | variance_ratio=pca.explained_variance_ratio_ #方差贡献率(已经从大到小排序) 39 | score_matrix=pca.components_ #成分得分系数矩阵(载荷系数矩阵) 40 | 41 | #下面进行绘制碎石图选取因子数量 42 | '''plt.figure(figsize=(8,6)) 43 | plt.rcParams['font.sans-serif'] = ['SimHei'] 44 | plt.rcParams['axes.unicode_minus'] = False 45 | plt.plot(range(1,data.values.shape[1]+1),variance_ratio,linestyle=':') 46 | plt.scatter(range(1,data.values.shape[1]+1),variance_ratio,marker='o',) 47 | plt.annotate('0.056',xy=(4,0.096),xytext=(4,0.15),bbox=dict(boxstyle='square',fc='firebrick'), 48 | arrowprops=dict(facecolor='steelblue',shrink=0.002),fontsize=9.5,color='white') #打上标签 49 | plt.title('碎石图',fontsize=15) 50 | plt.xlabel('因子个数',fontsize=13) 51 | plt.ylabel('方差贡献率',fontsize=13) 52 | plt.show()''' 53 | 54 | #下面进行观测载荷系数矩阵(选取因子为4) 55 | pca=PCA(n_components=4) 56 | pca.fit(data) 57 | score_matrix=pca.components_.T #原shape是(4,8)要进行转置一下, 58 | data1=pd.DataFrame(score_matrix,index=data_columns) #注意这里要在index上给上标签(竖着的),热点图的规则 59 | 60 | plt.figure(figsize = (8,6)) 61 | #进行绘制热力图 62 | ax = sns.heatmap(data1, annot=True, cmap="BuPu") 63 | # 设置y轴字体大小 64 | ax.yaxis.set_tick_params(labelsize=10) 65 | #设置标题 66 | plt.title("PCA Loading Factor Matrix", fontsize="xx-large") 67 | # 设置y轴标签 68 | plt.ylabel("main ingredient", fontsize="13") 69 | # 显示图片 70 | plt.show() 71 | 72 | #下面进行数据降维操作(最关键的) 73 | trans_data=pca.transform(data) 74 | 75 | #用于主成分分析法的辅助函数 76 | def takefirst(elem): 77 | return elem[0] 78 | 79 | #主成分分析法(自设计算法) 80 | def pca(X,k): #X是待降维的输入矩阵,k是我们想要降维到的维数,输出是降维后的矩阵 81 | n_samples,n_features=X.shape #获取行数和列数 82 | mean=np.array([np.mean(X[:,i]) for i in range(n_features)]) #获取每一列的均值 83 | #进行标准化操作 84 | norm_X=X-mean 85 | #求原矩阵和其逆矩阵的点积 86 | scatter_matrix=np.dot(np.transpose(norm_X),norm_X) 87 | #计算特征值和特征向量 88 | eig_val,eig_vec=np.linalg.eig(scatter_matrix) 89 | eig_pairs=[(np.abs(eig_val[i]),eig_vec[:,i]) for i in range(n_features)] #将特征值和特征向量分别组合在一起 90 | eig_pairs.sort(key=takefirst,reverse=True) #按照特征值进行降序排序 91 | feature=np.array([ele[1] for ele in eig_pairs[:k]]) #选取前面K个特征向量 92 | result=np.dot(norm_X,np.transpose(feature))#进行转换 93 | return result 94 | 95 | -------------------------------------------------------------------------------- /code/假设检验.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import pandas as pd 3 | from scipy.stats import ttest_ind,levene,ttest_rel #T检验和方差齐性检验 4 | from scipy import stats 5 | import statsmodels.stats.weightstats as sw 6 | from scipy.stats import chi2_contingency,chisquare # 卡方检验 7 | from scipy.stats import fisher_exact #fisher精确检验 8 | from statsmodels.formula.api import ols #单因素方差分析 9 | from statsmodels.stats.anova import anova_lm #anova_lm用于一个或多个因素的方差分析,analysis of variance_linear models 10 | import numpy as np 11 | from statsmodels.graphics.api import qqplot 12 | from statsmodels.stats.multicomp import pairwise_tukeyhsd 13 | 14 | data_hpj1=pd.DataFrame(pd.read_excel('D:\\2022国赛数模练习题\\1组红葡萄.xlsx')) 15 | data_hpj2=pd.DataFrame(pd.read_excel('D:\\2022国赛数模练习题\\2组红葡萄.xlsx')) 16 | data_hpj1.drop('组别',axis=1,inplace=True) 17 | data_hpj2.drop('组别',axis=1,inplace=True) 18 | 19 | #第一种正态性检验方式:进行KS正态性检验(注意原假设是符合正态分布) 20 | hpj1_columns=data_hpj1.columns 21 | hpj2_columns=data_hpj2.columns 22 | statistic1=[] 23 | p_value1=[] 24 | judge1=[] 25 | for name in hpj1_columns: #选择那一组 26 | u=data_hpj1[name].mean()#均值 27 | std=data_hpj1[name].std() #方差 28 | a=stats.kstest(data_hpj1[name],'norm',(u,std))#主要的正态分布检验代码,p值大于0.05说明其符合正态分布 29 | statistic1.append(a[0]) 30 | p_value1.append(a[1]) 31 | if a[1] > 0.05 : 32 | judge1.append('yes') 33 | elif a[1] <= 0.05 : 34 | judge1.append('no') 35 | data1=pd.DataFrame({'statistic':statistic1,'p_value1':p_value1,'yes or no':judge1}) 36 | #data1.to_csv('D:\\2022国赛数模练习题\\红葡萄1组正态分布检验.csv',index=None) 37 | #第二种正态性检验方式:绘制QQ图 38 | qqplot(data_hpj1[hpj1_columns[0]], line='q', fit=True) 39 | plt.tick_params(size=5,labelsize = 13) #坐标轴 40 | plt.grid(alpha=0.3) #是否加网格线 41 | plt.title('QQ-normality test',fontsize=15) 42 | plt.xlabel('Theoretical Quantiles',fontsize=13) 43 | plt.ylabel('Sample Quantiles',fontsize=13) 44 | plt.show() 45 | 46 | #下面是进行方差齐性检验和T检验 47 | statistic2=[] 48 | statistic3=[] 49 | p_value2=[] 50 | p_value3=[] 51 | judge2=[] 52 | judge3=[] 53 | #一定要进行方差齐性检验,因为方差齐不齐性会对t检验的自由度计算产生影响 54 | for name in hpj1_columns: 55 | result=levene(data_hpj1[name],data_hpj2[name]) #主要的F检验算法代码 56 | if result[1]>0.05:#判断是否齐性(方差齐次性检验),注意零假设是方差相等,备选假设是方差不相等 57 | judge2.append('yes') 58 | t_result=ttest_ind(data_hpj1[name],data_hpj2[name]) #主要的t检验算法代码 59 | statistic3.append(t_result[0]) 60 | p_value3.append(t_result[1]) 61 | #判断独立样本是否显著(注意零假设是相等,备选假设是不相等) 62 | if t_result[1]<=0.05: 63 | judge3.append('yes') 64 | else: 65 | judge3.append('no') 66 | # 进行独立样本t检验如果方差不齐性还要注意 67 | else: 68 | judge2.append('no') 69 | t_result1=ttest_ind(data_hpj1[name],data_hpj2[name],equal_var=False) 70 | statistic3.append(t_result1[0]) 71 | p_value3.append(t_result1[1]) 72 | if t_result1[1]<=0.05: #注意这里需要去除程序才能正常运行 73 | judge3.append('yes') 74 | else: 75 | judge3.append('no') 76 | statistic2.append(result[0]) 77 | p_value2.append(result[1]) 78 | 79 | #配对样本T检验 80 | x = [20.5, 18.8, 19.8, 20.9, 21.5, 19.5, 21.0, 21.2] 81 | y = [17.7, 20.3, 20.0, 18.8, 19.0, 20.1, 20.0, 19.1] 82 | # 配对样本t检验 83 | print('配对样本',ttest_rel(x, y)) 84 | 85 | """data2=pd.DataFrame({'statistic':statistic2,'p_value1':p_value2,'yes or no':judge2}) 86 | data2.to_csv('D:\\2022国赛数模练习题\\两组红葡萄方差齐性检验.csv',index=None) 87 | data3=pd.DataFrame({'statistic':statistic3,'p_value3':p_value3,'yes or no':judge3}) 88 | data3.to_csv('D:\\2022国赛数模练习题\\红葡萄独立样本t检验结果.csv',index=None) 89 | """ 90 | 91 | #Z检验(U检验)(用于总体方差已知,零假设是与均值相等,备选假设是与均值不相等) 92 | arr=[23,36,42,34,39,34,35,42,53,28,49,39,46,45,39,38, 93 | 45,27,43,54,36,34,48,36,47,44,48,45,44,33,24,40,50,32,39,31] 94 | #看数据的均值是否与39相等(双侧),如果要知道该样本的均值是否大于39,则可以设置alternative="smaller",零假设就是小于等于39 95 | #输出有两个参数,第一个是统计量Z的值,第二个参数是p值 96 | print(sw.ztest(arr, value=39)) 97 | 98 | #卡方检验独立性检验(零假设是两者独立,不相关,备选假设是两者不独立,存在相关性)用于两组分类变量 99 | #首先读取数据 100 | data=pd.read_csv('D:\\Desktop\\2022数模国赛\\支撑材料\\data\\处理后的附件1.csv',encoding='gbk') 101 | #下面进行生成列链表(交叉表)n大于等于40,且所有频数E大于等于5 102 | cross_data1=pd.crosstab(data['纹饰'],data['表面风化']) #表面风化为行,纹饰作为列,这里表示风化是否与纹饰有关系 103 | kf = chi2_contingency(cross_data1,False) #卡方检验主体代码部分,False表示不用yates校正卡方 104 | print('chisq-statistic=%.4f, p-value=%.4f, df=%i \n expected_frep: \n%s'%kf) #第一个参数是统计量卡方的值,第二个是p值,第三个是自由度,最后一个是理论期望值 105 | 106 | #当样本量n大于等于40,但是频数E小于等于5大于等于1的量超过25%时利用yates校正卡方 107 | kf1 = chi2_contingency(cross_data1,True) #卡方检验主体代码部分 108 | print('yates修正卡方:chisq-statistic=%.4f, p-value=%.4f, df=%i \n expected_frep: \n%s'%kf) #第一个参数是统计量卡方的值,第二个是p值,第三个是自由度,最后一个是理论期望值 109 | 110 | #当样本量n小于40,且存在频数小于1则用fisher精确检验(fisher卡方)(注意目前python只能实现2*2的,要实现2*c可以利用spsspro) 111 | c_static,p_value=fisher_exact(np.array([[1,4],[5,9]]),alternative='greater') 112 | print(f'fisher精确检验:chisq-statistic={c_static},p_value={p_value}',) #第一个参数是统计量卡方的值,第二个是p值,第三个是自由度,最后一个是理论期望值 113 | 114 | #卡方拟合优度检验(用于一组分类变量)原假设是没有显著差异,备选假设是有显著差异 115 | test_data=np.array([29,31]) 116 | c_statistic,p=chisquare(test_data) 117 | print(f'卡方拟合优度检验 :chisq-statistic={c_statistic},p_value={p},') #其中chisq-statistic是统计量,p_value是p值 118 | 119 | #方差分析(用于分类变量和数值型变量,不符合正态分布或者方差略有不齐对结果的影响不大) 120 | #首先先读取数据 121 | data=pd.read_csv('D:\\Desktop\\2022数模国赛\\支撑材料\\data\\预测后的数据.csv',encoding='gbk') 122 | data_K=data[data['类型']=='高钾'] 123 | data_B=data[data['类型']=='铅钡'] 124 | #首先进行正态性检验 125 | def normality_test(data): #data是一个列表数据 126 | mean=np.mean(data) 127 | std=np.std(data) 128 | result=stats.kstest(data,'norm',(mean,std)) #主要的正态分布检验代码,p值大于0.05说明其符合正态分布 129 | return result[0],result[1] #第一个是统计量,第二个是p值 130 | print(normality_test(data_K['氧化铅(PbO)'])) 131 | print(normality_test(data_B['氧化铅(PbO)'])) 132 | #下面进行方差齐性检验(可以将所有类别的数据依次进行输入,比如在后面还可以再加data_B['氧化铜(CuO)]') 133 | result=levene(data_K['氧化铅(PbO)'],data_B['氧化铅(PbO)']) 134 | print('方差齐性检验',result[0],result[1]) #第一个是统计量,第二个是p值,p值大于0.05说明方差具有齐性 135 | #下面进行单因素方差分析(第一种)F值越大,p值越小,说明两者之间差异越显著 136 | F_statistic, p = stats.f_oneway(data_K['氧化铅(PbO)'],data_B['氧化铅(PbO)']) 137 | 138 | #第二种方式(注意如果是多因素方差分析,则在后面继续添加即可,例如'height ~ C(water) + C(sun) + C(water):C(sun)',其中最后一个C代表的是交互作用) 139 | data.rename(columns={'类型':'type','氧化铅(PbO)':'PbO','颜色':'color'},inplace=True) #注意第二种方式输入要是英文的 140 | model = ols('PbO ~ C(type)', data).fit() #前面的第一个是数值型变量,第二个是分类型变量,要加C,其表示Catagory 141 | anovaResults = anova_lm(model) #看输出中分类变量的p值和F值即可 142 | print(anovaResults) 143 | 144 | #如果方差分析显著下面就进行多重比较,明确是哪两个因素之间有显著差异(用tukey方法) 145 | print(pairwise_tukeyhsd(data['PbO'],data['type'])) #如果reject为True则说明拒绝原假设,认为两个类别之间有显著差异 146 | 147 | #秩和检验(用于数据分布未知,各种参数也未知的情况,当p值小于0.05时,说明两者具有显著差异,总体分布不同) 148 | result1=stats.ranksums(data_B['氧化铅(PbO)'],data_K['氧化铅(PbO)']) #用于两类 149 | result2=stats.kruskal(data_B['氧化铅(PbO)'],data_K['氧化铅(PbO)']) #用于两类及以上 150 | print(result1,result2) 151 | -------------------------------------------------------------------------------- /code/回归分析.py: -------------------------------------------------------------------------------- 1 | import statsmodels.formula.api as smf 2 | import pandas as pd 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | from scipy.optimize import curve_fit 6 | from sklearn.ensemble import RandomForestRegressor 7 | from fitter import Fitter 8 | from matplotlib import cm 9 | 10 | #进行前向回归分析的函数(用于多元线性回归) 11 | def forward_selected(data, response): #其中data是包含需要回归的数据(dataframe格式),response是因变量的名称 12 | remaining = set(data.columns) 13 | remaining.remove(response) 14 | selected = [] 15 | current_score, best_new_score = 0.0, 0.0 16 | while remaining and current_score == best_new_score: 17 | scores_with_candidates = [] 18 | for candidate in remaining: 19 | formula = "{} ~ {} + 1".format(response, 20 | ' + '.join(selected + [candidate])) 21 | score = smf.ols(formula, data).fit().rsquared_adj 22 | scores_with_candidates.append((score, candidate)) 23 | scores_with_candidates.sort() 24 | best_new_score, best_candidate = scores_with_candidates.pop() 25 | if current_score < best_new_score: 26 | remaining.remove(best_candidate) 27 | selected.append(best_candidate) 28 | current_score = best_new_score 29 | formula = "{} ~ {} + 1".format(response, 30 | ' + '.join(selected)) 31 | model = smf.ols(formula, data).fit() 32 | return model 33 | 34 | ################################## 35 | #下面进行一元多项式拟合 36 | ################################## 37 | 38 | #一个一个进行拟合函数得到三个多项式函数 39 | data_customer_rate=pd.read_csv('D:\\2022国赛数模练习题\\贷款年利率与客户流失率关系.csv',encoding='gbk') 40 | #创建待拟合的数据 41 | x=data_customer_rate['贷款年利率'] 42 | y1=data_customer_rate['信誉评级A'] 43 | #创建多项式拟合函数得到方程 44 | z1=np.polyfit(x,y1,4)#第三个参数表示多项式最高次幂 45 | #将多项式带入方程,得到多项式函数 46 | p1=np.poly1d(z1) 47 | x1=np.linspace(x.min(),x.max(),100)#x给定数据太少,方程曲线不光滑,多取x值得到光滑曲线 48 | pp1=p1(x1) #将x1带入多项式得到多项式曲线(得到对应的函数值) 49 | 50 | #下面还可绘制回归曲线 51 | pp2=pp1 52 | pp3=pp2 53 | plt.rcParams['font.sans-serif'] = ['SimHei'] 54 | plt.rcParams['axes.unicode_minus'] = False 55 | plt.figure(figsize=(13,8)) 56 | plt.tick_params(size=5,labelsize = 13) #坐标轴 57 | plt.grid(alpha=0.3) #是否加网格线 58 | plt.plot(data_customer_rate['贷款年利率'],data_customer_rate['信誉评级A'],label='信誉评级A',linewidth=2,alpha=0.8,linestyle=':') 59 | plt.plot(data_customer_rate['贷款年利率'],data_customer_rate['信誉评级B'],label='信誉评级B',linewidth=2,alpha=0.8,linestyle=':') 60 | plt.plot(data_customer_rate['贷款年利率'],data_customer_rate['信誉评级C'],label='信誉评级C',linewidth=2,alpha=0.8,linestyle=':') 61 | plt.plot(x1,pp1,linewidth=2,alpha=0.8,label='信誉评级A的多项式曲线') 62 | plt.plot(x1,pp2,linewidth=2,alpha=0.8,label='信誉评级B的多项式曲线') 63 | plt.plot(x1,pp3,linewidth=2,alpha=0.8,label='信誉评级C的多项式曲线') 64 | plt.xlabel('贷款年利率',fontsize=13) 65 | plt.ylabel('客户流失率',fontsize=13) 66 | plt.title('贷款年利率与客户流失率关系图',fontsize=15) 67 | plt.legend() 68 | plt.show() 69 | #注意后续可以求R方、均方误差等指标进行模型的检验 70 | 71 | ################################################# 72 | #下面进行自定义函数回归分析(一元的) 73 | ################################################# 74 | 75 | #先自定义一个函数例如:其中有a,b,c三个参数需要回归得出 76 | def func(x, a, b, c,d): 77 | return a*x**3+b*x**2+c*x**1+d 78 | 79 | #接下来直接回归出参数即可(用curve_fit)其中xdata是输入x值,ydata是输入y值,popt是输出的参数 80 | popt, pcov = curve_fit(func, x, y1,maxfev=5000) #maxfev是寻找迭代的次数,如果迭代了maxfev次还未找到最优参数就会退出 81 | print(popt) 82 | print(pcov) 83 | #下面将参数带入就可得到拟合的方程,再将x值带入 84 | plt.figure(figsize=(8,6)) 85 | plt.plot(x, func(x, *popt), 'r-', 86 | label='fit: a=%5.3f, b=%5.3f, c=%5.3f,d=%5.3f' % tuple(popt)) 87 | plt.plot(x,y1) 88 | plt.legend() 89 | plt.show() 90 | 91 | #下面进行模型合理性分析,用R方(两种方式,第一种是Pearson相关系数的平方,第二种是) 92 | def computeCorrelation(x, y): #其中x,y均为序列,x是预测值,y是真实值,这里是计算Pearson相关系数,最后需要平方注意 93 | xBar = np.mean(x) #求预测值均值 94 | yBar = np.mean(y) #求真实值均值 95 | covXY = 0 96 | varX = 0 #计算x的方差和 97 | varY = 0 #计算y的方差和 98 | for i in range(0, len(x)): 99 | diffxx = x[i] - xBar #预测值减预测值均值 100 | diffyy = y[i] - yBar #真实值减真实值均值 101 | covXY += (diffxx * diffyy) 102 | varX += diffxx ** 2 103 | varY += diffyy ** 2 104 | return covXY/np.sqrt(varX*varY) 105 | 106 | #第二种计算R方的方式 107 | def R_Squre2(y_pred,y_real): #其中y_pred是预测值,y_real是真实值,两者都是徐磊 108 | y_real_mean = np.mean(y_real) 109 | y_pred_var=0 #计算预测值减真实值的平方和 110 | y_real_var=0 111 | for i in range(len(y_pred)): 112 | y_pred_var+=(y_pred[i]-y_real_mean)**2 113 | y_real_var+=(y_real[i]-y_real_mean)**2 114 | return y_pred_var/y_real_var 115 | 116 | #下面进行计算均方误差(MSE) 117 | def mean_squared_error(y_pred,y_real): #其中y_pred是预测值,y_real是真实值 118 | result_list=[] 119 | for i in range(len(y_pred)): 120 | result_list.append((y_pred-y_real)**2) 121 | return np.sum(result_list)/len(result_list) 122 | 123 | #AIC准则(越小越好) 124 | def cal_AIC(n,mse,num_params):#其中n是观测数量,mse是均方误差,num_params是模型参数个数 125 | aic=n*np.log(mse)+2*num_params 126 | return aic 127 | 128 | #BIC准则(越小越好,表示模型性能越好和复杂度越低) 129 | def cal_BIC(n,mse,num_params):#其中n是观测数量,mse是均方误差,num_params是模型参数个数 130 | bic=n*np.log(mse)+num_params*np.log(n) 131 | return bic 132 | 133 | y_pred=func(x,*popt) #计算拟合函数的预测值 134 | R2_1=computeCorrelation(y_pred,y1)**2 #一定要平方注意计算R方 135 | R2_2=R_Squre2(y_pred,y1) #j计算第二种R方 136 | MSE=mean_squared_error(y_pred,y1) #计算均方误差 137 | aic=cal_AIC(len(y_pred),MSE,4) #计算AIC 138 | bic=cal_BIC(len(y_pred),MSE,4) #计算BIC 139 | print('第一种R方',R2_1) #越小越好 140 | print('第二种R方',R2_2) #越小越好 141 | print('均方误差',MSE) 142 | print('AIC',aic) 143 | print('BIC',bic) 144 | 145 | ############################################################## 146 | #下面进行多元自定义函数回归(如果是三维点的话可以自己自定义多元多项式回归) 147 | ############################################################## 148 | 149 | #首先导入数据 150 | data=pd.DataFrame(pd.read_excel('D:\\国赛数模优秀论文\\2017\\Problems\\B\\附件一:已结束项目任务数据.xls')) 151 | #选择有用的数据 152 | data=data[['任务gps 纬度','任务gps经度','任务标价']] 153 | 154 | #下面进行二元多项式回归(x2,x,xy,y,y2)设置函数,总共六个参数 155 | def func(data,a,b,c,d,e,f): #注意data是一个dataframe格式的数据,取第一列和第二列为自变量 156 | return a*data.iloc[:,0]*data.iloc[:,0] +b*data.iloc[:,0] +c*data.iloc[:,1]*data.iloc[:,1]+ \ 157 | d*data.iloc[:, 1]+e*data.iloc[:, 0]*data.iloc[:, 1] +f 158 | 159 | #下面进行函数拟合操作(回归出参数) 160 | params, pcov = curve_fit(func, data.iloc[:,:2], data.iloc[:,2]) 161 | 162 | #下面进行绘制三维拟合曲面 163 | x=np.linspace(np.min(data.iloc[:,0]),np.max(data.iloc[:,0]),200) 164 | y=np.linspace(np.min(data.iloc[:,1]),np.max(data.iloc[:,1]),200) 165 | X,Y=np.meshgrid(x,y) 166 | #下面是关键点,直接乘得到Z注意这个Z是二维形式的 167 | Z=params[0]*X*X+params[1]*X+params[2]*Y*Y+params[3]*Y+params[4]*X*Y+params[5] 168 | #下面得到一维形式的z 169 | z=params[0]*data.iloc[:,0]*data.iloc[:,0]+params[1]*data.iloc[:,0] +params[2]*data.iloc[:,0]*data.iloc[:,1]+\ 170 | params[3]*data.iloc[:,1]+params[4]*data.iloc[:,1]*data.iloc[:,1]+params[5] 171 | 172 | #下面进行绘制三维图形 173 | #plt.style.use('') #目前可改变3D图像样式的有ggplot、seaborn、Solarize_Light2、grayscale 174 | plt.rcParams['axes.facecolor'] = '#ffffff' 175 | plt.rcParams['axes.unicode_minus'] = False 176 | fig = plt.figure(figsize=(8,6),facecolor='#ffffff') 177 | ax = fig.gca(projection='3d') 178 | #绘制表面图 179 | surf = ax.plot_wireframe(X, Y, Z,rstride=4, cstride=4,color='black',alpha=0.3, 180 | linewidth=0.05, antialiased=False) 181 | #ax.plot_surface(X, Y, Z,cmap=cm.coolwarm,linewidth=0.1, antialiased=False) 182 | 183 | #下面是进行三维的三角型拟合得出最终的三维图形 184 | """surf=ax.plot_trisurf(data.iloc[:,0],data.iloc[:,1],z, 185 | cmap=cm.coolwarm, edgecolor='none')""" 186 | #绘制等高线 187 | #cset1 = ax.contourf(X, Y, Z, zdir='z', cmap=cm.coolwarm) 188 | #cset2= ax.contourf(X, Y, Z, zdir='x' ,cmap=cm.coolwarm) 189 | #cset3 = ax.contourf(X, Y, Z, zdir='y', cmap=cm.coolwarm) 190 | 191 | #下面将散点绘制到图片中去 192 | ax.scatter(data.iloc[:,0],data.iloc[:,1],data.iloc[:,2],marker='o',c=data.iloc[:,2],cmap=cm.coolwarm) 193 | # Add a color bar which maps values to colors.(这里加上颜色条,同时设置其参数) 194 | #fig.colorbar(surf, shrink=0.5, aspect=5,ticks=np.linspace(81,100,5)) 195 | #打上x、y、z轴的标签和标题 196 | ax.set_xlabel('X Label',fontsize=13) 197 | ax.set_ylabel('Y Label',fontsize=13) 198 | ax.set_zlabel('Z Label',fontsize=13) 199 | ax.set_title('3D Fitted Surface Plot',fontsize=15) 200 | plt.show() 201 | 202 | 203 | -------------------------------------------------------------------------------- /code/多因子分析.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | import seaborn as sns 5 | from factor_analyzer import FactorAnalyzer 6 | from factor_analyzer.factor_analyzer import calculate_bartlett_sphericity #Bartlett’s球状检验 7 | from factor_analyzer.factor_analyzer import calculate_kmo #KMO检验 8 | 9 | #导入数据 10 | data=pd.read_csv('D:\\2022国赛数模练习题\\附件2.csv',encoding='gbk') 11 | #剔除无用的列 12 | data.drop(columns='编号',inplace=True) 13 | 14 | #进行数据标准化操作 15 | def standardization(data): #data是矩阵,主要功能是进行标准化,输出是经过标准化的矩阵 16 | data_std=[np.std(data[:,i]) for i in range(data.shape[1])] 17 | data_mean=[np.mean(data[:,i]) for i in range(data.shape[1])] 18 | for i in range(data.shape[1]): 19 | data[:,i]=(data[:,i]-data_mean[i])/data_std[i] 20 | return data 21 | data_columns=data.columns#存储列名 22 | data=pd.DataFrame(standardization(data.values),columns=data_columns) 23 | 24 | #下面进行充分性检验 25 | #1Bartlett’s球状检验 26 | chi_square_value, p_value = calculate_bartlett_sphericity(data) 27 | print('Bartlett球状检验为:',chi_square_value,p_value) #p值小于0.05,检验通过,能进行因子分析 28 | 29 | #2KMO检验 30 | kmo_all,kmo_model=calculate_kmo(data) 31 | print('KMO检验为:',kmo_model) #大于0.6说明变量之间的相关性强,能进行因子分析 32 | 33 | #下面进行选择因子数量,先计算变量的特征值和特征向量 34 | faa=FactorAnalyzer(8,rotation=None) 35 | faa.fit(data) #将数据导入模型中 36 | 37 | #得到特征值ev和特征向量v 38 | ev,v=faa.get_eigenvalues() 39 | 40 | #下面进行绘制碎石图(绘制特征值和因子个数的变化) 经过观察此时可以选择3个因子 41 | plt.figure(figsize=(8,6)) 42 | plt.rcParams['font.sans-serif'] = ['SimHei'] 43 | plt.rcParams['axes.unicode_minus'] = False 44 | plt.plot(range(1,data.values.shape[1]+1),ev,linestyle=':') 45 | plt.scatter(range(1,data.values.shape[1]+1),ev,marker='o',) 46 | plt.annotate('0.767',xy=(4,0.767),xytext=(4.3,1),bbox=dict(boxstyle='square',fc='firebrick'), 47 | arrowprops=dict(facecolor='steelblue',shrink=0.002),fontsize=9.5,color='white') #打上标签 48 | plt.title('碎石图',fontsize=15) 49 | plt.xlabel('因子个数',fontsize=13) 50 | plt.ylabel('特征值',fontsize=13) 51 | plt.show() 52 | 53 | #下面选择3个因子来进行因子分析的建模过程同时指定矩阵旋转方式为:方差最大化 54 | faa_three=FactorAnalyzer(3,rotation='varimax') #构建模型并设置参数 55 | faa_three.fit(data) #将数据导入到模型中 56 | 57 | #下面进行查看因子贡献率(三种1总方差贡献2方差贡献率3累积方差贡献率) 58 | variance_dataframe=pd.DataFrame(faa_three.get_factor_variance(),columns=['feature1','feature2','feature3']) 59 | print(variance_dataframe) 60 | 61 | #下面进行绘制各个降维特征的方差贡献率和累计方差贡献率 62 | width=0.25 #柱形宽度 63 | index=np.arange(variance_dataframe.values.shape[1]) #序号 64 | feature_index=['feature1','feature2','feature3'] #最总显示的降维特征名称 65 | plt.rc('font',family='Times New Roman') #更改画图字体为Times New Roman 66 | plt.figure(figsize=(8,6)) 67 | plt.tick_params(size=5,labelsize = 13) #坐标轴 68 | plt.grid(alpha=0.3) #是否加网格线 69 | #下面进行绘制累计方差贡献率曲线 70 | plt.plot(index,variance_dataframe.iloc[2,:],marker='o',color='r',alpha=0.5,lw=2,label='Contribution rate curve of cumulative variance') 71 | #下面进行绘制各公共因子的方差贡献率柱形图 72 | plt.bar(index,variance_dataframe.iloc[1,:],width=width, alpha=0.4,color='b' ,label='Variance contribution rate') 73 | #下面进行打上数据标签 74 | for i,data1 in enumerate(variance_dataframe.iloc[1,:]): #方差贡献率 75 | plt.text(i,data1+0.004,round(data1,1),horizontalalignment='center',fontsize=12) 76 | for i,data1 in enumerate(variance_dataframe.iloc[2,:]): #累计方差贡献率 77 | if i!=0: #第一个不打标签,防止重复 78 | plt.text(i,data1+0.004,round(data1,1),horizontalalignment='center',fontsize=12) 79 | plt.xticks(index,feature_index) #打上x轴坐标标签 80 | plt.xlabel('Feature type',fontsize=13) 81 | plt.ylabel('contribution',fontsize=13) 82 | plt.title('Contribution rate of each characteristic variance and cumulative contribution rate',fontsize=15) 83 | plt.legend() 84 | plt.show() 85 | 86 | #下面可以计算系数矩阵并绘制出热力图(最后进行观察分析即可,观察每一列看谁的系数大可以将几个变量分为一组,每个因子都可以分一组) 87 | data1=pd.DataFrame(faa_three.loadings_,index=data_columns) 88 | plt.figure(figsize = (8,6)) 89 | #进行绘制热力图 90 | ax = sns.heatmap(data1, annot=True, cmap="BuPu") #注意这里要在index上给上标签(竖着的),热点图的规则 91 | # 设置y轴字体大小 92 | ax.yaxis.set_tick_params(labelsize=10) 93 | #设置标题 94 | plt.title("Factor Analysis", fontsize="xx-large") 95 | # 设置y轴标签 96 | plt.ylabel("Sepal Width", fontsize="13") 97 | # 显示图片 98 | plt.show() 99 | #plr.savefig() 100 | 101 | #最后还可以将数据降维(转化) 102 | trans_data=faa_three.transform(data) 103 | print(trans_data) 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /code/层次分析法.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import numpy as np 3 | import warnings 4 | 5 | #下面进行构建层次分析法的对象(注意其准则层最多14个,方案层也最多14个,不然无法计算RI) 6 | class AHP: #注意其中算法包括'arithmetic mean'(算术平均) 'geometric mean'(几何平均) ,'Eigenvalues'(特征值法) 'comprehensive'(综合法) 7 | def __init__(self, criteria, b=None,algorithm='comprehensive'): #其中criteria表示准测层的重要性矩阵,b表示方案层的重要性矩阵(对每个准则)列表,可以不用,最后一个表示计算权重的算法 8 | self.RI = (0, 0, 0.52, 0.89, 1.12, 1.26, 1.36, 1.41, 1.46, 1.49,1.52,1.54,1.56,1.58,1.59) #RI的查询列表,用于后续计算一致性比例CR 9 | self.criteria = criteria 10 | self.algorithm = algorithm # 存储权重算法 11 | self.b = b 12 | #下面进行判断准则层和方案层是否输入为空,如果为空则是一般需要只需要计算输入的重要性矩阵的权重 13 | self.num_criteria = criteria.shape[0] #统计准则层元素的个数 14 | #如果只想计算搞准则层(指标层)的权重,就不用设置方案层的重要性矩阵了 15 | if b!=None: 16 | self.num_project = b[0].shape[0] #统计方案个数 17 | 18 | #下面的函数是用于计算权重的,输入为重要性矩阵,输出为权重的列表向量 19 | def cal_weights(self, input_matrix): 20 | input_matrix = np.array(input_matrix) 21 | 22 | #下面进行保证其是个方阵 23 | n, n1 = input_matrix.shape 24 | assert n == n1, '不是一个方阵' 25 | 26 | #下面进行判断此方阵是否为正互反矩阵(要正互反矩阵才行) 27 | for i in range(n): 28 | for j in range(n): 29 | if np.abs(input_matrix[i, j] * input_matrix[j, i] - 1) > 1e-7: 30 | raise ValueError('不是反互对称矩阵') 31 | 32 | #下面得到重要性矩阵的特征值序列和特征向量矩阵 33 | eigenvalues, eigenvectors = np.linalg.eig(input_matrix) #eigenvalues为特征值序列,eigenvectors为特征向量矩阵(竖着看) 34 | max_idx = np.argmax(eigenvalues) # 计算最大特征值 35 | max_eigen = eigenvalues[max_idx].real # 得到最大特征值的实部(原来是个复数) 36 | 37 | #1第一种算术平均法求权重 38 | weights1=np.sum(input_matrix/np.sum(input_matrix,axis=0),axis=1)/n 39 | 40 | #2第二种几何平均法求权重 41 | weights2=input_matrix[:,0] #先取第一列 42 | #先按行相乘得到新的列向量 43 | for i in range(1,n): 44 | weights2=weights2*input_matrix[:,i] 45 | weights2=(weights2**(1/n))/np.sum(weights2**(1/n)) 46 | 47 | # 3下面是利用特征值法求权重 48 | max_eigenvectors = eigenvectors[:, max_idx].real #得到最大特征向量列的实部 49 | weights3 = max_eigenvectors / max_eigenvectors.sum() #得到权重序列 50 | 51 | #4综合上述方法得到一个综合的权重 52 | weights4=(weights1+weights2+weights3)/3 53 | 54 | #下面进行使用的权重算法判断 55 | if self.algorithm == 'arithmetic mean': 56 | weights=weights1 57 | elif self.algorithm == 'geometric mean': 58 | weights=weights2 59 | elif self.algorithm == 'Eigenvalues': 60 | weights=weights3 61 | elif self.algorithm == 'comprehensive': 62 | weights = weights4 63 | 64 | #下面进行计算一致性比例CR,注意当元素数量大于14个无法判断 65 | if n > 14: 66 | CR = None 67 | warnings.warn('无法判断一致性') 68 | else: 69 | CI = (max_eigen - n) / (n - 1) 70 | CR = CI / self.RI[n-1] 71 | 72 | return max_eigen, CR, weights #返回最大特征值、一致性比例(CR)和权重序列 73 | 74 | #主体运行函数 75 | def run(self): 76 | #下面得到准则层的最大特征值、一致性比例(CR)和权重序列 77 | max_eigen, CR, criteria_weights = self.cal_weights(self.criteria) 78 | #下面进行输出信息,注意CR<0.1认为重要性矩阵的一致性通过 79 | print('准则层:最大特征值{:<5f},CR={:<5f},检验{}通过'.format(max_eigen, CR, '' if CR < 0.1 else '不')) 80 | print('准则层权重={}\n'.format(criteria_weights)) 81 | 82 | #下面得到所有方案层的准则层的最大特征值、一致性比例(CR)和权重评分序列(均存储在列表中) 83 | max_eigen_list, CR_list, weights_list = [], [], [] 84 | for i in self.b: 85 | max_eigen, CR, eigen = self.cal_weights(i) 86 | max_eigen_list.append(max_eigen) 87 | CR_list.append(CR) 88 | weights_list.append(eigen) 89 | 90 | #注意输出的结构是column是各个方案,index是各个准则(特征) 91 | pd_print = pd.DataFrame(np.array(weights_list), 92 | index=['准则' + str(i) for i in range(self.num_criteria)], 93 | columns=['方案' + str(i) for i in range(self.num_project)],) 94 | #下面对dataframe添加各个准则下的方案层的最大特征值(由方案层得出)、CR、和一致性检验结果 95 | pd_print.loc[:, '最大特征值'] = max_eigen_list 96 | pd_print.loc[:, 'CR'] = CR_list 97 | pd_print.loc[:, '一致性检验'] = pd_print.loc[:, 'CR'] < 0.1 98 | print('方案层权重评分和其他信息') 99 | print(pd_print) 100 | 101 | # 目标层(下面进行得到综合的评分,通过直接全部权重相乘的形式(准则层和方案层)) 102 | obj = np.dot(criteria_weights.reshape(1, -1), np.array(weights_list)) 103 | print('\n目标层的综合评分', obj) 104 | print('最优选择是方案{}'.format(np.argmax(obj))) 105 | return obj 106 | 107 | if __name__ == '__main__': 108 | # 准则重要性矩阵 (总共有5个特征(准则)) 109 | criteria = np.array([[1, 2, 7, 5, 5], 110 | [1 / 2, 1, 4, 3, 3], 111 | [1 / 7, 1 / 4, 1, 1 / 2, 1 / 3], 112 | [1 / 5, 1 / 3, 2, 1, 1], 113 | [1 / 5, 1 / 3, 3, 1, 1]]) 114 | 115 | # 对每个准则,方案优劣排序(总共有3个方案) 116 | b1 = np.array([[1, 1 / 3, 1 / 8], [3, 1, 1 / 3], [8, 3, 1]]) 117 | b2 = np.array([[1, 2, 5], [1 / 2, 1, 2], [1 / 5, 1 / 2, 1]]) 118 | b3 = np.array([[1, 1, 3], [1, 1, 3], [1 / 3, 1 / 3, 1]]) 119 | b4 = np.array([[1, 3, 4], [1 / 3, 1, 1], [1 / 4, 1, 1]]) 120 | b5 = np.array([[1, 4, 1 / 2], [1 / 4, 1, 1 / 4], [2, 4, 1]]) 121 | # 方案层重要性列表(对每个准则) 122 | b = [b1, b2, b3, b4, b5] 123 | 124 | #最终输出 125 | a = AHP(criteria,b,'comprehensive').run() 126 | #如果只想要知道某个重要性矩阵的权重(比如只需要准则层(特征层)的权重) 127 | max_eigen,CR,weights = AHP(criteria).cal_weights(criteria) #其中max_eigen就是最大特征根,CR是一致性比例,weights就是权重序列 128 | print(weights) 129 | -------------------------------------------------------------------------------- /code/层次聚类.py: -------------------------------------------------------------------------------- 1 | from sklearn.cluster import AgglomerativeClustering 2 | from sklearn.model_selection import train_test_split 3 | from sklearn.datasets import load_iris #测试的数据集 4 | import seaborn as sns 5 | import matplotlib.pyplot as plt 6 | import numpy as np 7 | import pandas as pd 8 | from scipy.cluster import hierarchy 9 | from scipy.spatial import distance_matrix 10 | #层次凝聚分类模型 11 | iris=load_iris() #导入数据集 是一个字典类型的数据 12 | X=iris.data[:,2:4] #表示只取特征空间的后两个纬度 13 | y = iris.target # 将鸢尾花的标签赋值给y 14 | # 随机划分鸢尾花数据集,其中训练集占70%,测试集占30% 15 | #X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) 16 | #计算各个点之间的距离,搞成一个n*n矩阵 17 | dist = distance_matrix(X, X) 18 | #计算树状图所需参数(两种方式) 19 | Z = hierarchy.linkage(dist, 'complete') 20 | #Z = hierarchy.linkage(dist, 'average') 21 | #绘制树状图确定聚类中心个数 22 | plt.figure(figsize=(6,30)) 23 | dendro=hierarchy.dendrogram(Z,leaf_rotation=0,leaf_font_size=5,orientation='right') 24 | plt.show() 25 | #创建层次凝聚聚类模型 26 | agglom = AgglomerativeClustering(n_clusters=3, linkage='average').fit(X) #创建层次凝聚分类模型 27 | output=agglom.labels_ #获取聚类标签 28 | -------------------------------------------------------------------------------- /code/插值方法.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | import matplotlib.pyplot as plt 4 | from matplotlib import cm 5 | from pykrige.ok import OrdinaryKriging 6 | 7 | data=pd.read_csv('D:\\0\\其他\\单子1数据处理\\测试数据.csv',encoding='gbk') 8 | data=data[['情感因子','行为因子','适切因子','认知因子']] 9 | 10 | #一维数据插值(还有其余牛顿插值或者拉格朗日等等) 11 | data['认知因子'].interpolate(method='linear',inplace=True) #一次线性插值法(对开头几个数据没办法填充) 12 | data['认知因子'].interpolate(method='quadratic',inplace=True) #二次插值 13 | data['认知因子'].interpolate(method='cubic',inplace=True) #三次插值 14 | 15 | #牛顿插值法(可以插组内的也可以插组外的)(可以用于任何数据的插值,但是缺点也是有的,具体见文档) 16 | x=np.arange(len(data['认知因子'])) #设置x 17 | #主体的函数,xx 和 y 分别是已知的数据点序列,x0是需要求解的插值点 18 | def newton_interpolation(x, y, x0): 19 | n = len(x) 20 | f =np.zeros((n,n)) #创建一个存储多阶差商的矩阵 21 | for i in range(n): 22 | f[i][0] = y[i] #将第一列的值为原始值 23 | #下面根据差商的性质然后进行递推 24 | for j in range(1, n): 25 | for i in range(j, n): 26 | f[i][j] = (f[i][j - 1] - f[i - 1][j - 1]) / (x[i] - x[i - j]) 27 | #最后一阶的最后一个数 28 | res = f[n - 1][n - 1] 29 | #y用逆推公式求解出x0的函数值 30 | for i in range(n - 2, -1, -1): 31 | res = f[i][i] + (x0 - x[i]) * res 32 | return res 33 | #下面进行输出结果 34 | print(newton_interpolation(x,data['认知因子'],3)) 35 | 36 | #拉格朗日插值法(也是几乎适用于所有数据,得到的多项式与牛顿插值法类似,在数据点上的值相同但是在其他点的数值不一定相同) 37 | def lagrange(x, y, num_points, x_test): #其中x,y就是原始数据点,num_points就是数据点数量,x_test就是需要插值点的x坐标 38 | # 所有的基函数值,每个元素代表一个基函数的值 39 | l = np.zeros(shape=(num_points, )) 40 | # 计算第k个基函数的值 41 | for k in range(num_points): 42 | # 乘法时必须先有一个值 43 | # 由于l[k]肯定会被至少乘n次,所以可以取1 44 | l[k] = 1 45 | # 计算第k个基函数中第k_个项(每一项:分子除以分母) 46 | for k_ in range(num_points): 47 | # 这里没搞清楚,书中公式上没有对k=k_时,即分母为0进行说明 48 | # 有些资料上显示k是不等于k_的 49 | if k != k_: 50 | # 基函数需要通过连乘得到 51 | l[k] = l[k]*(x_test-x[k_])/(x[k]-x[k_]) 52 | else: #如果分母为0直接跳过 53 | pass 54 | # 计算当前需要预测的x_test对应的y_test值 55 | L = 0 56 | for i in range(num_points): 57 | # 求所有基函数值的和 58 | L += y[i]*l[i] 59 | return L 60 | #下面进行输出结果 61 | test_x=np.linspace(0,100,1000) #生成1000个测试样本点 62 | interpolate_data=[lagrange(x,data['认知因子'],len(x),k) for k in test_x] #得到所有测试样本点的插值 63 | print(lagrange(x,data['认知因子'],len(x),3)) 64 | 65 | #样条插值法(在不同的x轴区间用不同的插值函数(多项式)进行操作)结合前面的就行 66 | 67 | #二维的插值方法(可以参考可视化模块中的”插值三维可视化.py文件“) 68 | 69 | #下面是进行克里金空间插值(适用空间分布、时空分布的情况) 70 | #读取数据 71 | data1=pd.read_csv('D:\\2022国赛数模练习题\\2022宁波大学数学建模暑期训练第四轮\\附件1.csv',encoding='gbk') 72 | data2=pd.read_csv('D:\\2022国赛数模练习题\\2022宁波大学数学建模暑期训练第四轮\\附件2.csv',encoding='gbk') 73 | new_data=pd.concat((data1,data2),axis=1) #进行数据组合 74 | new_data.drop(columns=['编号'],inplace=True) #去掉无用的列,目前剩下12列 75 | 76 | #下面进行分出各个区域,用于后续在云图中绘制散点 77 | sheng_data=new_data[new_data['功能区']==1] #生活区 78 | gong_data=new_data[new_data['功能区']==2] #工业区 79 | shan_data=new_data[new_data['功能区']==3] #山区 80 | jiao_data=new_data[new_data['功能区']==4] #交通区 81 | yuan_data=new_data[new_data['功能区']==5] #公园 82 | 83 | #data1是x轴,data2是y轴,data3是z轴数据,title是图的标题,xlabel是x轴标题,ylabel是y轴标题,ctitle是颜色条的标题,file_name是存储图的名称 84 | def kriging_interpolation(data1,data2,data3,title,xlabel,ylabel,ctitle,file_name): 85 | #先生成等长的x,y序列 86 | grid_x=np.linspace(np.min(data1),np.max(data1),300) 87 | grid_y=np.linspace(np.min(data2),np.max(data2),300) 88 | #创建克里金插值的对象,其中的variogram_model表示在克里金插值中使用高斯变异函数(注意还可以设置其他函数,具体看文档),并通过nlags=6 设置了变异函数的参数。 89 | OK=OrdinaryKriging(data1,data2,data3,variogram_model='gaussian',nlags=6) 90 | z1,ss1=OK.execute('grid',grid_x,grid_y) 91 | X,Y=np.meshgrid(grid_x,grid_y) 92 | plt.figure(figsize=(8,6)) 93 | plt.rcParams['font.sans-serif'] = ['SimHei'] 94 | plt.rcParams['axes.unicode_minus'] = False 95 | #绘制云图 96 | levels=range(round(np.min(data3)),round(np.max(data3)),3) #设置渐变范围 97 | a1=plt.contourf(X,Y,z1, levels, cmap=cm.Spectral, alpha=0.7) 98 | #绘制等高线 99 | a2=plt.contour(X,Y,z1,linestyles='solid',linewidth=1) 100 | # 加入收集点的坐标 101 | plt.scatter(sheng_data['x(m)'], sheng_data['y(m)'], marker='o', label='生活区') 102 | plt.scatter(gong_data['x(m)'], gong_data['y(m)'], marker='s', label='工业区') 103 | plt.scatter(shan_data['x(m)'], shan_data['y(m)'], marker='+', label='山区') 104 | plt.scatter(jiao_data['x(m)'], jiao_data['y(m)'], marker='D', label='交通区') 105 | plt.scatter(yuan_data['x(m)'], yuan_data['y(m)'], marker='^', label='公园绿地区') 106 | plt.legend(loc='upper left') 107 | cbar=plt.colorbar(a1) #为云图添加颜色条 108 | cbar.set_label(ctitle, fontsize=13) # 设置颜色条的标题 109 | plt.clabel(a2,inline=True,fontsize=15) #为等高线添加标签 110 | plt.title(title,fontsize=15) 111 | plt.xlabel(xlabel,fontsize=13) 112 | plt.ylabel(ylabel,fontsize=13) 113 | #plt.savefig(file_name,format="svg",bbox_inches='tight') 114 | plt.show() 115 | kriging_interpolation(new_data['x(m)'],new_data['y(m)'],new_data['As (μg/g)'],'As的空间分布','x(m)','y(m)','浓度(μg/g)','As.svg') -------------------------------------------------------------------------------- /code/数据共线性处理.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | from sklearn.datasets import load_boston 4 | from statsmodels.stats.outliers_influence import variance_inflation_factor 5 | import matplotlib.pyplot as plt 6 | import seaborn as sns 7 | import matplotlib.font_manager as fm 8 | from matplotlib import rcParams #导入包 9 | config = {"font.family":'Times New Roman'} # 设置字体类型 10 | rcParams.update(config) #进行更新配置 11 | 12 | #绘制相关性图函数 13 | def corr_heatmap(data,title): #注意其中data是一个输入的dataframe,title是图片的名称 14 | corrmat_data=data.corr() #这个是皮尔森相关系数,如果计算斯皮尔曼相关系数,则用method='spearman' 15 | plt.figure(figsize=(8,6)) 16 | sns.heatmap(corrmat_data,annot=True,cmap='Greens',fmt='.2f') #cmap=Greens、Reds、Blues、Purples 也比较好看 17 | # 下面是进行设置x轴,y轴刻度字体 18 | font_prop1 = fm.FontProperties(family="Times New Roman", size=11, ) # 设置一个字体属性的对象(宋体) 19 | plt.xticks(np.arange(len(data.columns)) + 0.5, data.columns.tolist(), fontproperties=font_prop1, rotation=90) #添加x刻度标签 20 | plt.yticks(np.arange(len(data.columns)) + 0.5, data.columns.tolist(), fontproperties=font_prop1, rotation=360) #添加y刻度标签 21 | plt.title(title,fontsize=15,family='SimSun') 22 | #plt.savefig(title + '.svg', format='svg', bbox_inches='tight') 23 | plt.show() 24 | 25 | def clr_transform(data): #输入是矩阵数据(适用于各种成分数据) 26 | # 计算每个变量的几何平均值 27 | geo_means = np.exp(np.mean(np.log(data), axis=0)) 28 | # 计算CLR变换后的数据 29 | clr_data = np.log(data / geo_means) 30 | return clr_data 31 | 32 | if __name__ == '__main__': 33 | #导入数据 34 | boston=load_boston() 35 | x=boston.data #自变量(总共13个变量) 36 | y=boston.target #因变量 37 | x_data = pd.DataFrame(x, columns=boston.feature_names) # 创建dataframe 38 | 39 | #方法1,利用相关系数矩阵进行观察,相关系数大于0.7或者0.8可以认为有数据共线性 40 | corr_heatmap(x_data,'皮尔森相关系数矩阵') 41 | 42 | #方法2:利用方差膨胀因子(VIF)进行判断 43 | vif_ls=[variance_inflation_factor(x,i) for i in range(x.shape[1])] #计算每个自变量的VIF,一一对应 44 | #下面进行绘制VIF柱形图,加辅助线来直观的观察 45 | index = np.arange(x.shape[1]) #自变量的数量 46 | # 进行绘制 47 | width = 0.25 48 | plt.figure(figsize=(8, 6)) 49 | plt.tick_params(size=5, labelsize=13) # 坐标轴 50 | plt.grid(alpha=0.3) # 是否加网格线 51 | # 注意下面可以进行绘制误差线,如果是计算均值那种的簇状柱形图的话(注意类别多的话可以用循环的方式搞) 52 | plt.bar(index, vif_ls, width=width,color='#bf0000', label='VIF') 53 | #绘制阈值线和标签 54 | plt.axhline(y=10, color='black', lw=1.4, linestyle=':') 55 | plt.axhline(y=100, color='black', lw=1.4, linestyle=':') 56 | plt.text(x=0.8,y=50,s='中等共线性',color='black',family='SimSun',fontsize=13) 57 | plt.text(x=0.8, y=105, s='严重共线性', color='black',family='SimSun',fontsize=13) 58 | # 下面进行打上标签(也可以用循环的方式进行绘制)(颜色就存储在一个列表中) 59 | for i, data in enumerate(vif_ls): 60 | plt.text(index[i], data + 0.1, round(data, 1), horizontalalignment='center', fontsize=13) 61 | plt.xlabel('自变量', fontsize=13,family='SimSun') 62 | plt.ylabel('VIF', fontsize=13,family='Times New Roman') 63 | plt.title('各自变量VIF', fontsize=15,family='SimSun') 64 | plt.legend() 65 | plt.xticks(index, x_data.columns) 66 | plt.show() 67 | 68 | # 进行clr变换,创建一个示例数据集,每列代表一个变量,每行代表一个样本 69 | data = np.array([[1.0, 2.0, 3.0], 70 | [4.0, 5.0, 6.0], 71 | [7.0, 8.0, 9.0]]) 72 | 73 | print(clr_transform(data)) 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /code/数据分布拟合并随机生成.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import numpy as np 3 | from fitter import Fitter 4 | import matplotlib.pyplot as plt 5 | from scipy.stats import t 6 | data=pd.read_csv('D:\\2022国赛数模练习题\\data\\转运商数据.csv',encoding='gbk') 7 | data_column=data.columns.tolist() 8 | 9 | #先观察下数据的分布 10 | '''plt.figure(figsize=(8,6)) 11 | plt.scatter(range(len(data[data_column[0]])),data[data_column[0]]) 12 | plt.show()''' 13 | 14 | #下面先进行测试 15 | distribution=['norm', 't', 'laplace','gamma', 'rayleigh', 'uniform'] #选择拟合的概率分布函数 16 | f=Fitter(data[data_column[0]],distributions=distribution) #创建拟合对象 17 | f.fit() #进行拟合 18 | f.hist() #绘制组数=bins的标准化直方图 19 | f.plot_pdf(names=None, Nbest=5, lw=2) #绘制分布的概率密度函数 20 | plt.title('6 fitted probability density functions',fontsize=13) 21 | plt.show() 22 | #注意下面返回的是均方误差最小的概率分布函数 23 | print(f.summary()) #返回排序好的分布拟合质量(拟合效果从好到坏),并绘制数据分布和Nbest分布,注意其是一个dataframe格式的形式的可以从中进行提取数 24 | 25 | #绘制AIC和BIC的值(双坐标轴)注意还可以绘制均方误差的图,因为本身是按照那个进行筛选的,一般可以看情况如果一个概率分布有两个都是最的话,就用这两个指标进行操作 26 | x_label=f.summary().index.tolist() 27 | aic=f.summary()['aic'].tolist() #aic序列 28 | bic=f.summary()['bic'].tolist() #bic序列 29 | sumsquare_error=f.summary()['sumsquare_error'].tolist() #均方误差序列 30 | 31 | fig,ax1=plt.subplots(figsize=(8,6)) 32 | plt.tick_params(size=5,labelsize = 13) #坐标轴 33 | plt.grid(alpha=0.3) #是否加网格线 34 | ax1.set_xlabel('Distribution function type',fontsize=13) 35 | ax1.set_ylabel('AIC',fontsize=13) 36 | ax1.plot(x_label,aic,lw=3) 37 | ax1.scatter(x_label,aic,marker='o',s=50) 38 | ax2 = ax1.twinx() #相当于再建立一个坐标轴 39 | ax2.set_ylabel('BIC',fontsize=13) 40 | ax2.plot(x_label,bic,lw=3,color='r') 41 | ax2.scatter(x_label,bic,marker='p',s=50,color='r') 42 | 43 | #下面进行打上标签 44 | for i,value in enumerate(aic): 45 | ax1.text(i,value+4,round(value,2), horizontalalignment='center') 46 | for i,value in enumerate(bic): 47 | ax2.text(i, value + 0.3, round(value, 2), horizontalalignment='center') 48 | 49 | #fig.tight_layout() # otherwise the right y-label is slightly clipped 这个是自适应调整子图之间的距离,可以不加 50 | plt.title('AIC and BIC comparison of fitted distribution functions',fontsize=15) 51 | plt.show() 52 | 53 | #下面运用最优拟合优度的模型产生特征估计值。 54 | #下面进行创建具有最优拟合优度的模型 55 | t_model=t(f.get_best(method='sumsquare_error')['t']) #将t的参数传入,首先要先判断什么是最好的拟合模型再进行导入创建模型 56 | r=t.rvs(200,size=20) #第一个参数是自由度,一般是样本总数减去变量个数 57 | r_zheng=[x for x in r if x>0] #取大于零的数 58 | print(f.get_best(method='sumsquare_error')) #返回最佳拟合分布及其参数 59 | random_num=np.mean(r_zheng) #返回估计值(均值) 60 | print(random_num) 61 | 62 | #print(f.fitted_param) #返回拟合分布的参数 63 | #print(f.fitted_pdf) #使用最适合数据分布的分布参数生成的概率密度 64 | #下面的函数的功能:用80种分布进行拟合数据的分布,同时输出最优的前10种参数的AIC,BIC 65 | #def fitted_distribution(): 66 | -------------------------------------------------------------------------------- /code/数据预处理.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | import statistics as stat 4 | from fancyimpute import KNN 5 | import matplotlib.pyplot as plt 6 | import seaborn as sns 7 | 8 | #先导入测试的数据(包括4列的变量,其中有缺失值) 9 | data=pd.read_csv('D:\\0\\其他\\单子1数据处理\\测试数据.csv',encoding='gbk') 10 | data=data[['情感因子','行为因子','适切因子','认知因子']] 11 | 12 | #1进行重复值处理(其中subset是检查哪些列,keep是有重复值就保留第一个,ignore_index表示是否删除重复值后重新进行排序),注意是直接删除整行 13 | #data.drop_duplicates(subset=['情感因子'],keep='first',inplace=True,ignore_index=True) 14 | 15 | #2进行缺失值观测和处理 16 | #print(data.isnull().sum()) #统计各个变量列缺失值的个数 17 | 18 | #下面进行缺失值处理 19 | #(1)直接删除对应的行 20 | #data.dropna(inplace=True) 21 | 22 | #(2)前后补充法 23 | """data.fillna(method='ffill',inplace=True) #前向补充法(对于开头几个数据没办法填充) 24 | data.fillna(method='bfill',inplace=True) #后向补充法(对最后的几个数据没办法填充) 25 | """ 26 | 27 | #(3)用均值、中位数、众数进行填补 28 | #data['情感因子'].fillna(np.mean(data['情感因子']),inplace=True) #中位数:np.median 众数:stat.mode 29 | 30 | #(4)插值法(还有其余牛顿插值或者拉格朗日等等) 31 | #data['情感因子'].interpolate(method='linear',inplace=True) #一次线性插值法(对开头几个数据没办法填充) 32 | #data['情感因子'].interpolate(method='quadratic',inplace=True) #二次插值 33 | #data['情感因子'].interpolate(method='cubic',inplace=True) #三次插值 34 | 35 | #(5)MC算法填补缺失值 36 | class MF(): 37 | def __init__(self, X, k, alpha, beta, iterations): # 38 | """ 39 | Perform matrix factorization to predict np.nan entries in a matrix. 40 | Arguments 41 | - X (ndarray) : sample-feature matrix 输入的矩阵 42 | - k (int) : number of latent dimensions 列的维度,k越大计算量越大 43 | - alpha (float) : learning rate #学习率 44 | - beta (float) : regularization parameter #正则化的参数 45 | - iterations : 迭代的轮数 46 | """ 47 | self.X = X 48 | self.num_samples, self.num_features = X.shape 49 | self.k = k 50 | self.alpha = alpha 51 | self.beta = beta 52 | self.iterations = iterations 53 | # True if not nan 54 | self.not_nan_index = (np.isnan(self.X) == False) 55 | 56 | def train(self): #训练的主体函数 57 | # Initialize factorization matrix U and V 先对U和V矩阵进行初始化 58 | self.U = np.random.normal(scale=1./self.k, size=(self.num_samples, self.k)) 59 | self.V = np.random.normal(scale=1./self.k, size=(self.num_features, self.k)) 60 | 61 | # Initialize the biases 对偏置进行初始化 62 | self.b_u = np.zeros(self.num_samples) 63 | self.b_v = np.zeros(self.num_features) 64 | self.b = np.mean(self.X[np.where(self.not_nan_index)]) 65 | # Create a list of training samples 创建训练样本,注意是选择非空值的 66 | self.samples = [ 67 | (i, j, self.X[i, j]) 68 | for i in range(self.num_samples) 69 | for j in range(self.num_features) 70 | if not np.isnan(self.X[i, j]) 71 | ] 72 | 73 | # Perform stochastic gradient descent for number of iterations 进行梯度下降更新参数 74 | training_process = [] 75 | for i in range(self.iterations): #一轮一轮迭代 76 | np.random.shuffle(self.samples) #随机打乱 77 | self.sgd() #进行梯度下降迭代 78 | # total square error 79 | se = self.square_error() #计算loss也就是误差 80 | training_process.append((i, se)) #存储第几轮和误差 81 | if (i+1) % 10 == 0: 82 | print("Iteration: %d ; error = %.4f" % (i+1, se)) #每10轮输出误差 83 | return training_process 84 | 85 | def square_error(self): #计算误差二次范数 86 | """ 87 | A function to compute the total square error 88 | """ 89 | predicted = self.full_matrix() 90 | error = 0 91 | for i in range(self.num_samples): 92 | for j in range(self.num_features): 93 | if self.not_nan_index[i, j]: 94 | error += pow(self.X[i, j] - predicted[i, j], 2) 95 | return error 96 | 97 | def sgd(self): #进行梯度下降 98 | """ 99 | Perform stochastic graident descent 100 | """ 101 | for i, j, x in self.samples: 102 | # Computer prediction and error 103 | prediction = self.get_x(i, j) #得到预测的矩阵 104 | e = (x - prediction) #求误差(一次范数) 105 | 106 | # Update biases #更新偏置 107 | self.b_u[i] += self.alpha * (2 * e - self.beta * self.b_u[i]) 108 | self.b_v[j] += self.alpha * (2 * e - self.beta * self.b_v[j]) 109 | 110 | # Update factorization matrix U and V #更新U和V矩阵 111 | """ 112 | If RuntimeWarning: overflow encountered in multiply, 113 | then turn down the learning rate alpha. 114 | """ 115 | self.U[i, :] += self.alpha * (2 * e * self.V[j, :] - self.beta * self.U[i,:]) 116 | self.V[j, :] += self.alpha * (2 * e * self.U[i, :] - self.beta * self.V[j,:]) 117 | 118 | def get_x(self, i, j): #得到预测的矩阵(用上U,V,b_u,b_v和b) 119 | """ 120 | Get the predicted x of sample i and feature j 121 | """ 122 | prediction = self.b + self.b_u[i] + self.b_v[j] + self.U[i, :].dot(self.V[j, :].T) 123 | return prediction 124 | 125 | def full_matrix(self): #产生最后的矩阵(预测的)训练完后进行生成 126 | """ 127 | Computer the full matrix using the resultant biases, U and V 128 | """ 129 | return self.b + self.b_u[:, np.newaxis] + self.b_v[np.newaxis, :] + self.U.dot(self.V.T) 130 | 131 | def replace_nan(self, X_hat): #将原始矩阵中的缺失值进行替换 132 | """ 133 | Replace np.nan of X with the corresponding value of X_hat 134 | """ 135 | X = np.copy(self.X) 136 | for i in range(self.num_samples): 137 | for j in range(self.num_features): 138 | if np.isnan(X[i, j]): 139 | X[i, j] = X_hat[i, j] 140 | return X 141 | 142 | # np.random.seed(1) 143 | """mf = MF(data.values, k=2, alpha=0.1, beta=0.1, iterations=100) #创建MF对象 144 | mf.train() #进行训练 145 | X_hat = mf.full_matrix() #得到最后预测的矩阵 146 | X_comp = mf.replace_nan(X_hat) #输出填补缺失值后的原始矩阵 147 | new_data=pd.DataFrame(X_comp,columns=data.columns)""" 148 | 149 | #(6)用机器学习算法补全缺失值(例如KNN和随机森林) 150 | #下面是用KNN进行填补 151 | """fill_knn=KNN(k=3).fit_transform(data) #直接用k近邻算法 152 | new_data=pd.DataFrame(fill_knn,columns=data.columns)""" 153 | 154 | #3进行异常值检测与剔除 155 | #绘制箱型图观察并去除异常点(适用于多列数据) 156 | plt.rcParams['font.sans-serif'] = ['SimHei'] #中文显示 157 | plt.rcParams['axes.unicode_minus'] = False 158 | '''plt.figure(figsize=(8,6)) 159 | plt.tick_params(size=5,labelsize = 13) #坐标轴 160 | plt.grid(alpha=0.3) #是否加网格线· 161 | f=data.boxplot(sym='r*',return_type='dict',patch_artist=True) #sym表示异常点的形态是红色星号的 162 | for box in f['boxes']: 163 | # 箱体边框颜色 164 | box.set( color='#7570b3', linewidth=2) 165 | # 箱体内部填充颜色 166 | box.set( facecolor = '#1b9e77' ) 167 | #虚线的参数 168 | for whisker in f['whiskers']: 169 | whisker.set(color='#bf0000',ls='dashed',linewidth=2) 170 | #四分位数线的参数 171 | for cap in f['caps']: #四分位数线的参数 172 | cap.set(color='g', linewidth=3) 173 | #中位数线的参数 174 | for median in f['medians']: 175 | median.set(color='DarkBlue', linewidth=3) 176 | #异常点的参数(注意如果想给异常值打上标签的话可以用后面删除异常点的行数据代码进行筛选数据) 177 | for flier in f['fliers']: 178 | flier.set(marker='*', color='r', alpha=0.5) 179 | plt.xlabel('类别',fontsize=13) 180 | plt.ylabel('数值',fontsize=13) 181 | plt.title('各变量分布情况箱型图',fontsize=15) 182 | plt.show()''' 183 | 184 | #下面进行删除异常点的行数据 185 | """for column in data.columns: 186 | Q1=data[column].quantile(q=0.25) #下四分位数 187 | Q2=data[column].quantile(q=0.75) #上四分位数 188 | low_whisker = Q1 - 1.5 * (Q2 - Q1) # 下边缘 189 | up_whisker = Q2 + 1.5 * (Q2 - Q1) # 上边缘 190 | #下面进行筛选 191 | data=data[(data[column]>=low_whisker)&(data[column]<=up_whisker)]""" 192 | 193 | #如果是单列的数据可以绘制散点图加上区间来展现(3倍标准差) 194 | """upper=np.mean(data['情感因子'])+3*np.std(data['情感因子']) 195 | lower=np.mean(data['情感因子'])-3*np.std(data['情感因子']) 196 | print(upper,lower) 197 | plt.figure(figsize=(8,6)) 198 | plt.tick_params(size=5,labelsize = 13) #坐标轴 199 | plt.grid(alpha=0.3) #是否加网格线· 200 | plt.scatter(np.arange(len(data['情感因子'])),data['情感因子'],s=15,color='#F21855',alpha=0.9) 201 | #下面进行绘制区间线(注意如果想要对异常点打标签,可以创建一个Dataframe然后进行筛选,然后再绘制(加上特殊形状与颜色和打上标签)) 202 | plt.axhline(y=upper, color='#bf0000', linestyle='dashed') 203 | plt.axhline(y=lower, color='#bf0000', linestyle='dashed') 204 | plt.yticks([2.268,2.5,3.0,3.5,4.0,4.5,5.0,5.5,5.887,6.0],[2.3,2.5,3.0,3.5,4.0,4.5,5.0,5.5,5.9,6.0]) 205 | plt.xlabel('序号',fontsize=13) #上区间 206 | plt.ylabel('情感因子',fontsize=13) #下区间 207 | plt.title('情感因子数据分布图',fontsize=15) 208 | plt.show() 209 | #下面将异常值进行剔除 210 | data=data[(data['情感因子']>=lower)&(data['情感因子']<=upper)]""" 211 | 212 | 213 | 214 | -------------------------------------------------------------------------------- /code/时间序列处理与分解.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import seaborn as sns 4 | import pandas as pd 5 | from statsmodels.tsa.seasonal import seasonal_decompose 6 | from matplotlib import rcParams 7 | from statsmodels.tsa.stattools import adfuller as ADF 8 | 9 | #先设置绘图的全局字体类型 10 | config = {"font.family":'Times New Roman'} # 设置画图字体类型 11 | rcParams.update(config) #进行更新配置 12 | 13 | #下面进行导入数据集 14 | data=pd.read_csv('D:\\2023美赛\\海盗问题\\deal_data.csv',encoding='gbk') 15 | 16 | #时间转换操作 17 | data['Date']=pd.to_datetime(data['Date']) 18 | 19 | #时间筛选 20 | new_data=data[(data['Date']>='2008-5') & (data['Date']<='2020-5')] #可以加上多重筛选利用&和|符号进行 21 | 22 | #数据重采样操作(包括升采样和降采样)原本1天的变为统计3天的就是降采样,反之为升采样 23 | #下面是统计各日、周、月、年海盗事件发生次数的函数(注意输入的只需要时间序列,当然如果想将次数换成其余变量只需要改变'num'的值 即可,) 24 | def count_data(data):#其中data表示为一个时间的序列,注意也可以为一个dataframe,但是需要改变下函数,注意如果需要用其余的统计的话就将sum()改成其余函数即可 25 | date_data = pd.DataFrame(data) # 单独的时间数据 26 | date_data['num'] = 1 # 新设置一列,用于后续统计次数 27 | date_data = date_data.set_index(date_data['Date']) # 注意要将时间设置为索引才可以进行后续的重采样 28 | date_D=date_data.resample('D').sum() #统计每天发生的海盗事件次数 29 | date_W=date_data.resample('W').sum() #统计每周发生的海盗事件次数 30 | date_M=date_data.resample('M').sum() #统计每月发生的海盗事件次数 31 | date_Y=date_data.resample('Y').sum() #统计每年发生的海盗事件次数 32 | return date_D,date_W,date_M,date_Y 33 | data_D,data_W,data_M,data_Y=count_data(data['Date']) #输出 34 | 35 | #插值方式(填补空值的方式) 36 | data_D1=data_D.ffill(1) #取前面的一个数的值 37 | data_D2=data_D.bfill(1) #取后面一个数的值 38 | data_D3=data_D.interpolate('linear') #利用线性拟合填充 39 | data_D4=data_D.interpolate('quadratic') #二次插值 40 | data_D5=data_D.interpolate('cubic') #三次插值 41 | 42 | #滑动窗口进行统计指标(一般搭配绘制图片) 43 | new_data_D1=data_D1.rolling(window=10).mean() #还可以使用sum()、std()等等 44 | 45 | #时间数据的平稳性检测(单位根检验)(注意只要看第2个p值即可,如果小于0.05,则说明数据不存在单位根,平稳性检验通过)这个是更加准确判断 46 | adf=ADF(data_D['num']) 47 | 48 | #对数变换(注意原始数值不能出现小于等于0的数) 49 | data_log=np.log(data_Y['num']) 50 | 51 | #差分(1阶和2阶,一般就是这两种)剔除周期性影响和使时间序列平稳最常用的操作 52 | diff_1=data_Y.diff(1) 53 | diff_2=data_Y.diff(2) 54 | 55 | #平滑法(包括移动平滑法和各种指数平滑法) 56 | size=20 57 | #1移动平均法 58 | rol_mean = data_M.rolling(window=size).mean() 59 | #2加权移动平均(对时间距离目前越近的原始数据赋予越高的权重,注意权重的总和为1(加权),再进行移动平均)注意可以调整参数halflife、com、span、alpha来调节权重 60 | rol_weighted_mean=data_M.ewm(halflife=size,min_periods=0,adjust=True,ignore_na=False).mean() 61 | #3指数平滑法(注意只要调整adjust为False即可,调整权重可以用三个参数为:halflife、span、com和alpha具体公式见文档) 62 | exponential_weight_mean=data_M.ewm(span=2,adjust=False,ignore_na=False).mean() 63 | 64 | #时间序列的季节性分解 65 | #其中输入数据注意index是时间格式(直接输入应该也没什么大问题),period是设置的周期(用于消除季节性因素影响)model的选择有加法和乘法两种类型{“additive”, “multiplicative”},注意选择 66 | result=seasonal_decompose(data_M['num'],period=12,model='additive') #注意选择周期后会出现一些空值,可以用前面的方法进行填补空值 67 | trend=result.trend #趋势因子 68 | seasonal=result.seasonal #季节性因子 69 | resid=result.resid #残差因子 70 | #下面进行绘图 71 | fig,ax=plt.subplots(3,1,figsize=(8,6)) #设置画布,前面两个参数表示行列 72 | #trend 73 | ax[0].plot(trend.index,trend,label='Trend',color='#F21855',lw=1.5,alpha=1) 74 | #下面进行添加阴影 75 | ax[0].fill_between(trend.index,0,trend,alpha=0.3,color='#F21855') 76 | #下面添加箭头表示趋势 77 | ax[0].annotate('', xy=(trend.index[-15], 25), xytext=(trend.index[-40],30), 78 | arrowprops=dict(arrowstyle='->', connectionstyle='arc3', color='blue', lw=2,alpha=0.6)) 79 | ax[0].set_ylabel('Trend',fontsize=13) 80 | ax[0].set_title('Time series decomposition results',fontsize=15) 81 | ax[0].legend() 82 | ax[0].tick_params(size=5,labelsize = 13) #坐标轴 83 | ax[0].grid(alpha=0.3) #是否加网格线 84 | #seasonal 85 | ax[1].plot(trend.index,seasonal,label='Seasonality',marker='o',color='#52D896',markersize=2,lw=1.5,alpha=1) 86 | ax[1].set_ylabel('Seasonality',fontsize=13) 87 | ax[1].legend() 88 | ax[1].tick_params(size=5,labelsize = 13) #坐标轴 89 | ax[1].grid(alpha=0.3) #是否加网格线 90 | #resid 91 | ax[2].scatter(trend.index,resid,label='Residuals',marker='o',color='#FFDD24',s=15,alpha=1) 92 | #在y=0处添加一条辅助线 93 | plt.axhline(y=0, color='#bf0000',lw=2,linestyle='dashed') 94 | ax[2].set_xlabel('Date',fontsize=13) 95 | ax[2].set_ylabel('Residuals',fontsize=13) 96 | ax[2].legend() 97 | ax[2].tick_params(size=5,labelsize = 13) #坐标轴 98 | ax[2].grid(alpha=0.3) #是否加网格线 99 | plt.tight_layout() #自动调整子图间距 100 | plt.show() 101 | 102 | #后面进行提取傅里叶系数(进行傅里叶变换) -------------------------------------------------------------------------------- /code/机器学习回归与分类.py: -------------------------------------------------------------------------------- 1 | from sklearn.model_selection import train_test_split 2 | # machine learning 3 | from sklearn.linear_model import LogisticRegression 4 | from sklearn.svm import SVC, LinearSVC 5 | from sklearn.ensemble import RandomForestClassifier,RandomForestRegressor 6 | from sklearn.neighbors import KNeighborsClassifier,KNeighborsRegressor 7 | from sklearn.naive_bayes import GaussianNB 8 | from sklearn.linear_model import Perceptron 9 | from sklearn.linear_model import SGDClassifier,SGDRegressor 10 | from sklearn.tree import DecisionTreeClassifier ,DecisionTreeRegressor 11 | from sklearn.ensemble import AdaBoostClassifier #注意只有在这个ensemble中的模型可以进行软投票集成,其都是通过概率来得到的 12 | from sklearn.ensemble import GradientBoostingClassifier 13 | from xgboost.sklearn import XGBRegressor 14 | from sklearn.model_selection import cross_val_score 15 | from sklearn.model_selection import KFold,StratifiedKFold 16 | from sklearn.multiclass import OneVsRestClassifier 17 | from sklearn.ensemble import VotingClassifier #集成投票模型 18 | from sklearn.preprocessing import label_binarize #用于标签二值化 19 | from sklearn.calibration import CalibratedClassifierCV 20 | from sklearn.metrics import roc_auc_score 21 | from sklearn import metrics #metrics.accuracy_score(y_test,y_pred) 用于检测分类模型的精度 22 | import joblib 23 | import numpy as np 24 | import pandas as pd 25 | import seaborn as sns 26 | import copy 27 | import matplotlib.pyplot as plt 28 | 29 | #导入数据 30 | #训练集和验证集 31 | deal_data_y=pd.read_csv('D:\\2022国赛数模练习题\\处理后的有信贷信息的企业数据.csv',encoding='gbk') 32 | #预测集 33 | deal_data_w=pd.read_csv('D:\\2022国赛数模练习题\\处理后的无信贷信息的企业数据.csv',encoding='gbk') 34 | #先将无用的数据扔掉,columns=['信誉评级', '是否违约', '合格发票率', '年平均利润', '净发票总金额', '总盈利率', '月平均增长盈利率', '风险因子'] 35 | store_data_y=copy.deepcopy(deal_data_w) 36 | deal_data_y.drop(['企业代号','企业名称'],axis=1,inplace=True) 37 | x_train_ori=deal_data_y.drop('信誉评级',axis=1) 38 | y_train_ori=deal_data_y['信誉评级'] #注意要保留dataframe的格式 39 | #定义没有信贷信息的预测集 40 | deal_data_w.drop(['企业代号','企业名称'],axis=1,inplace=True) 41 | x_predict=deal_data_w 42 | #注意机器学习要学会做敏感性分析画图(参数很多可以) 43 | 44 | #下面是算法的主要部分 45 | #划分训练集和测试集(其中stratify表示标签值在测试集和训练集中所占的比例相同) 46 | x_train,x_test,y_train,y_test=train_test_split(x_train_ori,y_train_ori,test_size=0.2,random_state=42,stratify=y_train_ori,shuffle=True) 47 | #注意需要重置索引才能用后面的K折交叉验证 48 | x_train=x_train.reset_index(drop=True) 49 | x_test=x_test.reset_index(drop=True) 50 | y_train=y_train.reset_index(drop=True) 51 | y_test=y_test.reset_index(drop=True) 52 | print(x_train) 53 | 54 | #注意还有一种方式就是用ndarray的方式(其能用索引来取值,就不用dataframe的格式了) 55 | """x_train=np.ndarray(x_train) 56 | x_test=np.ndarray(x_test) 57 | y_train=np.ndarray(y_train) 58 | y_test=np.ndarray(y_test)""" 59 | 60 | weight=[]#存储交叉验证的平均准确率用于确定软投票的权重 61 | #创建一个随机森林模型(后面进行交叉验证更具说服力) 62 | RF=RandomForestClassifier(n_estimators=100,random_state=20) 63 | #计算交叉验证的各组验证集情况 64 | score=cross_val_score(RF,x_train,y_train,cv=5) 65 | weight.append(score.mean()) 66 | print('随机森林算法',score.mean()) 67 | 68 | #交叉验证进行具体求解,得出每一组的结果,同时用验证集精度最高的一组来进行测试集验证 69 | kf=KFold(n_splits=5,random_state=None) #进行5折交叉验证 还可以调节shuffle=True 70 | #kf=StratifiedKFold(n_splits=5,random_state=None) #分层交叉验证,每折中的分类标签比例均相同 71 | score_list=[] #存储每次交叉验证的验证集准确度 72 | max_score = 0 #存储最好的交叉验证中验证集准确率 73 | for train_index,test_index in kf.split(x_train,y_train): 74 | #下面实现直接取索引来获取数据 75 | X_train=x_train.loc[train_index,:] 76 | Y_train=y_train.loc[train_index] 77 | X_val = x_train.loc[test_index,:] 78 | Y_val = y_train.loc[test_index] 79 | model=RandomForestClassifier(n_estimators=100,random_state=10)#建立模型 80 | model.fit(X_train,Y_train) #模型训练 81 | score=model.score(X_val,Y_val) #计算验证集的准确度 82 | #进行比较将最好的模型参数保存 83 | if score >max_score: 84 | joblib.dump(model,'model.pkl')#将模型的参数保存 85 | score_list.append(score) 86 | model=joblib.load('model.pkl') #将最好的模型参数加载进来 87 | test_score=model.score(x_test,y_test) #对测试集进行预测 88 | print('随机森林算法5折交叉验证综合评分',np.mean(score_list)) #交叉验证平均准确度 89 | print('随机森林算法测试集得分',test_score) #交叉验证精度最高的一组进行测试集的精度测试 90 | 91 | #knn(k紧邻)算法 (当k为3时,测试集acc最大值为54%) 92 | test_scores = [] 93 | train_scores = [] 94 | for i in range(1,15): 95 | knn=KNeighborsClassifier(i)#设置k参数,离最近k个点的距离平均 96 | knn.fit(x_train,y_train) 97 | train_scores.append(knn.score(x_train, y_train)) 98 | test_scores.append(knn.score(x_test, y_test)) 99 | print(max(train_scores),max(test_scores),np.argmax(test_scores)) 100 | knn=KNeighborsClassifier(3) 101 | knn.fit(x_train,y_train) 102 | score=cross_val_score(knn,x_train,y_train,cv=5) 103 | weight.append(score.mean()) 104 | 105 | 106 | #支持向量机算法32.43% 107 | svc=SVC(C=0.6,break_ties=False,cache_size=200,gamma=2000,probability=True) 108 | svc.fit(x_train,y_train) 109 | y_pred=svc.predict(x_test) 110 | acc_svc=round(svc.score(x_test,y_test)*100,2) 111 | acc_svc_train=round(svc.score(x_train,y_train)*100,2) 112 | print('支持向量机训练集精度',acc_svc_train,'支持向量机测试集精度',acc_svc) 113 | score=cross_val_score(svc,x_train,y_train,cv=5) 114 | weight.append(score.mean()) 115 | 116 | #高斯贝叶斯0.44 117 | gassuan=GaussianNB() 118 | gassuan.fit(x_train,y_train) 119 | y_pred=gassuan.predict(x_test) 120 | acc_gassuan=round(gassuan.score(x_test,y_test)*100,2) 121 | acc_gassuan_train=round(gassuan.score(x_train,y_train)*100,2) 122 | print('高斯贝叶斯训练集精度',acc_gassuan_train,'高斯贝叶斯测试集精度',acc_gassuan) 123 | score=cross_val_score(gassuan,x_train,y_train,cv=5) 124 | weight.append(score.mean()) 125 | 126 | #sgd 0.28 127 | sgd=SGDClassifier(loss = 'hinge') 128 | sgd.fit(x_train,y_train) 129 | y_pred = sgd.predict(x_test) 130 | acc_sgd = round(sgd.score(x_test, y_test) * 100, 2) 131 | print('sgd测试集精度',acc_sgd) 132 | score=cross_val_score(sgd,x_train,y_train,cv=5) 133 | weight.append(score.mean()) 134 | 135 | 136 | #决策树 0.52 137 | decision_tree=DecisionTreeClassifier() 138 | decision_tree.fit(x_train,y_train) 139 | Y_pred = decision_tree.predict(x_test) 140 | acc_decision_tree = round(decision_tree.score(x_test,y_test) * 100, 2) 141 | print('决策树算法测试集精度',acc_decision_tree) 142 | score=cross_val_score(decision_tree,x_train,y_train,cv=5) 143 | weight.append(score.mean()) 144 | 145 | #AdaBoostClassifier(0-1分类) 146 | """Ada=AdaBoostClassifier(algorithm='SAMME',base_estimator=None,learning_rate=0.1,n_estimators=100,random_state=100) 147 | Ada.fit(x_train,y_train) 148 | 149 | #GBDT (是0-1分类) 150 | GBDT=GradientBoostingClassifier(ccp_alpha=0,criterion='friedman_mse',init=None,learning_rate=0.7,loss='exponential',max_depth=3) 151 | GBDT.fit(x_train,y_train)""" 152 | 153 | #下面进行集成学习 154 | #下面是硬投票(注意软投票的话只能用于二分类(才能有概率值)) 155 | W=np.array(weight)/sum(weight) #计算各分类器权重6个模型 156 | weight.pop(4) #现在只有5个特征值 157 | 158 | #建立硬投票模型(注意硬投票目前还不能输出概率值绘制ROC曲线,解决方法是用软投票模型,并且将每个模型的权重设置为相等即可) 159 | vote1=VotingClassifier(estimators=[('Randomforest',RF),('KNN',knn), 160 | ('SVC',svc),('gassuan',gassuan), 161 | ('sgd',sgd),('decision_tree',decision_tree)],voting='hard') #voting=soft or hard 162 | 163 | #建立软投票模型(目前还不能添加sgd其不能输出概率值) 164 | vote2=VotingClassifier(estimators=[('Randomforest',RF),('KNN',knn), 165 | ('SVC',svc),('gassuan',gassuan), 166 | ('decision_tree',decision_tree)],voting='soft',weights=weight) #注意目前还不能添加支持向量机 167 | 168 | #下面进行模型训练 169 | vote1.fit(x_train,y_train) 170 | vote2.fit(x_train,y_train) 171 | #下面是得到交叉验证的综合准确率 172 | score=cross_val_score(vote1,x_train,y_train) # 173 | score1=cross_val_score(vote2,x_train,y_train) 174 | print('硬投票交叉验证',score.mean()) 175 | print('软投票交叉验证',score1.mean()) 176 | #下面用模型进行对测试集进行预测 177 | y_pred1=vote1.predict(x_test) 178 | y_pred2=vote2.predict(x_test) 179 | print('硬投票测试集精度',metrics.accuracy_score(y_test,y_pred1)) #计算测试集的准确率(硬投票) 180 | print('软投票测试集精度',metrics.accuracy_score(y_test,y_pred2)) #计算测试集的准确率(软投票) 181 | 182 | #下面进行绘制软投票的混淆矩阵 183 | confusion_matrix=metrics.confusion_matrix(y_test,y_pred2) 184 | plt.figure(figsize=(8,6)) 185 | sns.heatmap(confusion_matrix,cmap="YlGnBu_r",fmt="d",annot=True) 186 | plt.xlabel('prediction category',fontsize=13) #横轴是预测类别 187 | plt.ylabel('real category',fontsize=13) #数轴是真实类别 188 | plt.title('confusion matrix',fontsize=15) 189 | plt.show() 190 | 191 | #下面计算01分类的ROC面积(此时是计算测试集准确率的ROC面积)注意ROC曲线一般只适用于二分类的情况 192 | """下面我们进行可以进行绘制ROC曲线和计算AUC值(这里是计算总体的) 193 | 注意需要用概率来进行计算即后面的combos['predict']是其为1的概率序列具体可看logit回归中的ROC曲线计算 194 | fpr,tpr,_=metrics.roc_curve(combos['是否违约'],combos['predict']) #计算ROC曲线点值 195 | roc_auc=metrics.auc(fpr,tpr)""" 196 | 197 | ################################################################################ 198 | ####################下面进行绘制出多分类的ROC曲线(注意需要重新构造数据)################# 199 | ################################################################################ 200 | #先将标签进行二值化[1 0 0 0] [0 0 1 0] [0 1 0 0] [0 0 0 1] 201 | y=label_binarize(y_train_ori,classes=[0,1,2,3]) 202 | #设置种类 203 | n_classes=y.shape[1] 204 | # shuffle and split training and test sets (划分数据集) 205 | x_train, x_test, y_train, y_test = train_test_split(x_train_ori, y, test_size=0.2) 206 | y_trans_test=np.argmax(y_test,axis=1) #将one-hot类型的测试集标签转化一下,后面便于绘制 207 | # Learn to predict each class against the other(其是一种多类分类的策略们可以为每一种类被配备一个分类器,01) 208 | classifier = OneVsRestClassifier(vote2,n_jobs=-1) #建立多类分类器模型用,用软投票模型 209 | 210 | #进行训练模型(目前也可运用投票模型(软投票) 211 | classifier.fit(x_train,y_train) 212 | y_score=classifier.predict(x_test) #预测各个类别[0 0 0 1] 213 | y_predict=np.argmax(y_score,axis=1) #将one-hot的编码格式转化成分类标签,作为真正的预测分类 214 | y_proba=classifier.predict_proba(x_test) #计算每个类别概率(注意此时相加总和不一定是1) 215 | 216 | #下面开始计算每一类的ROC 217 | fpr=dict() 218 | tpr=dict() 219 | roc_auc=dict() 220 | for i in range(n_classes): #遍历类别 221 | fpr[i],tpr[i], _ = metrics.roc_curve(y_test[:, i], y_proba[:, i]) #计算x轴和y轴的值 222 | roc_auc[i] = metrics.auc(fpr[i], tpr[i]) #计算auc面积值 223 | # Compute micro-average ROC curve and ROC area(方法二:将每个类别原始值和预测值都进行展平再进行计算ROC) 224 | fpr["micro"], tpr["micro"], _ = metrics.roc_curve(y_test.ravel(), y_proba.ravel()) 225 | roc_auc["micro"] = metrics.auc(fpr["micro"], tpr["micro"]) 226 | 227 | #绘制ROC曲线 228 | plt.figure(figsize=(8,6)) 229 | #绘制平均的ROC曲线 230 | plt.plot(fpr["micro"], tpr["micro"], 231 | label='micro-average ROC curve (area = {0:0.2f})' 232 | ''.format(roc_auc["micro"]), 233 | color='deeppink', linestyle=':', linewidth=4) 234 | 235 | colors = ['aqua', 'darkorange', 'cornflowerblue','g'] #颜色序列有几类用几种 236 | for i ,color in enumerate(colors): 237 | plt.plot(fpr[i],tpr[i],color=color,lw=2,label='ROC curve of class {0} (area = {1:0.2f})' 238 | ''.format(i, roc_auc[i])) #绘制曲线同时打上AUC面积标签 239 | plt.plot([0, 1], [0, 1], 'k--', lw=2) #绘制对角线 240 | plt.xlabel('False Positive Rate',fontsize=13) 241 | plt.ylabel('True Positive Rate',fontsize=13) 242 | plt.title('ROC-Kurve',fontsize=15) 243 | plt.legend(loc="lower right") 244 | plt.show() 245 | 246 | #下面进行绘制混淆矩阵 247 | confusion_matrix=metrics.confusion_matrix(y_trans_test,y_predict) 248 | plt.figure(figsize=(8,6)) 249 | sns.heatmap(confusion_matrix,cmap="YlGnBu_r",fmt="d",annot=True) 250 | plt.xlabel('Prediction category',fontsize=13) #横轴是预测类别 251 | plt.ylabel('Real category',fontsize=13) #数轴是真实类别 252 | plt.title('Confusion matrix',fontsize=15) 253 | plt.show() 254 | -------------------------------------------------------------------------------- /code/标准化与数据变换.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | from sklearn.preprocessing import MinMaxScaler 4 | from sklearn.preprocessing import label_binarize 5 | 6 | #标准化功能函数(处理矩阵) 7 | def standardization(data): #data是矩阵,主要功能是进行标准化,输出是经过标准化的矩阵 8 | data_std=[np.std(data[:,i]) for i in range(data.shape[1])] 9 | data_mean=[np.mean(data[:,i]) for i in range(data.shape[1])] 10 | for i in range(data.shape[1]): 11 | data[:,i]=(data[:,i]-data_mean[i])/data_std[i] 12 | return data 13 | 14 | #标准化功能函数(处理序列) 15 | def standardization2(data): #data是序列,主要功能是进行标准化,输出是经过标准化的序列 16 | data_std=np.std(data) 17 | data_mean=np.mean(data) 18 | for i in range(len(data)): 19 | data[i]=(data[i]-data_mean)/data_std 20 | return data 21 | 22 | #进行01标准化操作 23 | def Normalized1(data): #data是csv,这个是极大型指标的处理方式 输出也是序列。 24 | scaler= MinMaxScaler() 25 | return scaler.fit_transform(data) 26 | 27 | #进行极大指标值正向化操作(0,1) 注意会有0的出现,再之后的代码中如果除数为0就会出bug 28 | def Normalized2(data): #data是输入序列,这个是极大型指标的处理方式 输出也是序列 29 | min_data=min(data) 30 | max_data=max(data) 31 | return [(x-min_data)/(max_data-min_data) for x in data] 32 | 33 | #极小型指标指标的正向化方法 34 | def mindata(data): 35 | max_num=max(data) 36 | min_num=min(data) 37 | result=[(max_num-x)/(max_num-min_num) for x in data] 38 | return result 39 | 40 | #将中间型指标正向化的方法 41 | def middata(data): #data是待正向化的序列,输出是经过正向化的序列 42 | max_num=max(data) 43 | min_num=min(data) 44 | result=[] 45 | for x in data: 46 | if x>=min_num and x<=((max_num+min_num)/2): 47 | result.append(2*(x-min_num)/(max_num-min_num)) 48 | elif x>=((max_num+min_num)/2) and x<=max_num: 49 | result.append(2*(max_num-x)/(max_num-min_num)) 50 | return result 51 | 52 | #区间型指标正向化的方法 53 | def interval_data(data,a,b): #data是输入序列,其中a是下界,b是上界,输出是经过正向化的序列 54 | min_data=min(data) 55 | max_data=max(data) 56 | c=max([a-min_data,max_data-b]) 57 | result=[] 58 | for x in data: 59 | if x=a and x<=b: 62 | result.append(1) 63 | elif x>b: 64 | result.append(1-((x-b)/c)) 65 | return result 66 | 67 | #下面的向量标准化并不会出现0的情况,是一种占比 68 | def vector_normalization1(X): #向量标准化就是一种占比(0,1),主要用于TOPSIS,X是输入的矩阵,输出是经过标准化后的矩阵 69 | for i in range(X.shape[1]): 70 | X[:,i]=X[:,i]/(sum(X[:,i]**2)**0.5) 71 | return X 72 | 73 | def vector_normalization2(X): #向量标准化方式,输入是一个序列,输出也是一个序列 74 | a=[i**2 for i in X] 75 | return [i/(sum(a)**0.5) for i in X] 76 | 77 | #下面是进行one-hot编码的函数 78 | def one_hot(data,classes): #data是输入数据,序列的形式,classes是类别名称列表,例如['A','B','C'] 79 | return label_binarize(data,classes=classes) #输出的是多维矩阵的形式,每一个类别都是0/1变量 -------------------------------------------------------------------------------- /code/模糊综合评价法.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | import matplotlib.pyplot as plt 4 | import seaborn as sns 5 | import matplotlib as mpl 6 | from matplotlib import rcParams 7 | 8 | #下面进行导入数据 9 | data=pd.read_csv('D:\\2023美赛\\海盗问题\\第二题第三题数据\\total_MS.csv') 10 | data=data[['loss','weapon','num_pirate','P']].values #留下需要的数据,并转化成矩阵的形式 11 | n=data.shape[0] #样本量 12 | m=data.shape[1] #特征数 13 | 14 | #先得到各个因素(特征)的权重(可以用熵权法、层次分析法、重要性评分等等) 15 | #下面是用熵权法得到 16 | #首先对各个指标进行正向化操作(这里都是极大型指标) 17 | def Normalized2(data): #data是输入序列,这个是极大型指标的处理方式 输出也是序列 18 | min_data=min(data) 19 | max_data=max(data) 20 | return [(x-min_data)/(max_data-min_data) for x in data] 21 | #下面进行输出 22 | for i in range(m): 23 | data[:,i]=Normalized2(data[:,i]) 24 | 25 | def Entropy_weight_method(data): # data是输入的csv文件,输出是权值序列 26 | yij = data.apply(lambda x: x / x.sum(), axis=0) # 第i个学生的第j个指标值的比重yij = xij/sum(xij) i=(1,m) 27 | K = 1 / np.log(len(data)) #常数 28 | tmp = yij * np.log(yij) 29 | tmp = np.nan_to_num(tmp) 30 | ej = -K * (tmp.sum(axis=0)) # 计算第j个指标的信息熵 31 | wj = (1 - ej) / np.sum(1 - ej) # 计算第j个指标的权重 32 | return wj #输出权值序列 33 | #下面得到因素集的权重序列 34 | feature_weights=np.array(Entropy_weight_method(pd.DataFrame(data)))#注意是array的形式 35 | 36 | #下面计算原始数据的对各个评价指标的隶属度 37 | #注意这里假设都是1级:0.2 2级 0.4 3级0.6 4级 0.8 5级 1 (也就是1级是0-0.2的)里面取的都是上限,1级用偏小型,2,3,4用中间型,5级用偏大型 38 | #下面用最常用的梯形型的隶属度函数计算(具体见文档) 39 | a=[0.2,0.4,0.6,0.8,1] #评价等级区分(5级,取上界) 40 | result_list=[] #存储每个因素指标的一个评价矩阵R,在这个例子中,其中存储5个因素的隶属评价矩阵 41 | for i in range(m): #每个因素指标 42 | mid_matrix=np.zeros((n,len(a))) #存储一列中的所有样本的隶属度(对每个指标) 43 | for j in range(n): #每个样本,一列一列来搞 44 | for k in range(len(a)): #对每个评价等级 45 | #注意下面的可以根据需求进行改变每一列的一个隶属度函数计算公式 46 | if k==0: #第一个评价指标,用偏小型隶属度函数 47 | if data[j,i] <= a[k]: 48 | mid_matrix[j,k]=1 49 | elif a[k] <= data[j,i] <= a[k+1]: 50 | mid_matrix[j,k]=(a[k+1]-data[j,i])/(a[k+1]-a[k]) 51 | elif data[j,i] > a[k+1]: 52 | mid_matrix[j,k]=0 53 | elif k==len(a)-1: #最后一个评价指标,用偏大型隶属度函数 54 | if data[j,i] <= a[k-1]: 55 | mid_matrix[j,k]=0 56 | elif a[k-1] <= data[j,i] <= a[k]: 57 | mid_matrix[j,k]=(data[j,i]-a[k-1])/(a[k]-a[k-1]) 58 | elif data[j,i] > a[k]: 59 | mid_matrix[j,k]=1 60 | else: #中间的评价指标用中间型的隶属度函数 61 | if a[k-1]<= data[j,i] <= a[k]: 62 | mid_matrix[j,k]=(data[j,i]-a[k-1])/(a[k]-a[k-1]) 63 | elif a[k] <= data[j,i] <= a[k+1]: 64 | mid_matrix[j,k]=(a[k+1]-data[j,i])/(a[k+1]-a[k]) 65 | else: 66 | mid_matrix[j,k]=0 67 | result_list.append(mid_matrix) 68 | 69 | #下面需要从result_list中得到每个样本的一个评价矩阵 70 | evaluate_list=[] #存储每个样本的评价矩阵的列表 71 | for i in range(n): #每个样本 72 | evaluate_matrix = np.zeros((m, len(a))) # 创建初始评价矩阵,行数为因素的数量,列数为评价等级指标的数量 73 | for j in range(m): #每个因素 74 | evaluate_matrix[j,:]=result_list[j][i,:] 75 | evaluate_list.append(evaluate_matrix) 76 | 77 | #下面进行建立综合评价模型得到每个样本的一个B向量(综合了各个因素后得到的一个评价等级隶属度) 78 | B_list=[] #存储每个 样本的最终评价等级隶属度,形式为[[],[]] 里面的是array形式 79 | for i in range(n): #每个样本 80 | B_list.append(np.dot(feature_weights,evaluate_list[i])) 81 | 82 | #注意可以绘制一些雷达图、柱形图来展现各个最终等级评分的隶属度的均值情况,或者绘制分布图(分类簇状柱形分布)展现各个等级评分隶属度的分布情况 83 | #下面进行绘制各个等级评分的最终隶属度分布情况 84 | class_list=[] #用于隶属度评分等级的标签 85 | for i in range(len(B_list)): #每个样本 86 | class_list+=['Level 1','Level 2','Level 3','Level 4','Level 5'] 87 | #下面构造画图的dataframe数据形式 88 | plot_dataframe=pd.DataFrame({'level':class_list,'value':np.array(B_list).ravel().tolist()}) 89 | #下面进行绘制图片 90 | sns.set_theme(style="ticks") #设置一种绘制的主题风格 91 | f, ax = plt.subplots(figsize=(8, 6)) 92 | sns.despine(f) 93 | sns.histplot( 94 | plot_dataframe, 95 | x="value", hue="level", #注意hue是分类的标签,里面可以是分类的标签(字符和数值型均可),同时数据标签的前后关系是按照读取数据的先后关系的 96 | multiple="stack", 97 | palette="light:m_r", 98 | edgecolor=".3", 99 | linewidth=.5, 100 | log_scale=False, #注意这个是代表进行对数变换,如果原始的值有小于等于0的数就会报错,可以写成False 101 | ) 102 | plt.tick_params(size=5,labelsize = 13) #坐标轴 103 | plt.grid(alpha=0.3) #是否加网格线 104 | plt.ylabel('Count',fontsize=13,family='Times New Roman') 105 | plt.xlabel('Membership',fontsize=13,family='Times New Roman') 106 | plt.title('The membership distribution of each evaluation grade of each sample',fontsize=15,family='Times New Roman') 107 | ax.xaxis.set_major_formatter(mpl.ticker.ScalarFormatter()) 108 | ax.set_xticks(np.linspace(0,1,10)) #设置x轴的标签 109 | plt.show() 110 | 111 | #下面进行计算总得分 112 | score_list=[5,20,40,70,100] #注意要自己主观对每一等级进行打分 113 | #下面开始计算 114 | F_list=[] #存储每个样本的总得分 115 | for i in range(n): 116 | F_list.append(np.dot(np.array(score_list),B_list[i].T)) 117 | #可以绘制一些散点(加范围选择)或者折线面积图进行展现这个最终的总得分 118 | 119 | #注意一些二层、三层指标就是反复调用前面的代码进行操作即可() 120 | 121 | #下面是计算特殊情况的模糊评价分析(适用于直接将各个方案作为各个等级评分的(选方案),然后隶属度的计算就是各个方案的指标) 122 | #创建一个样本数据(假设有4个方案可供选择,有五个指标) 123 | test_data=np.array([[0.2,0.3,0.1,0.3], 124 | [0.3,0.4,0.2,0.3], 125 | [0.1,0.23,0.4,0.1], 126 | [0.12,0.42,0.32,0.14], 127 | [0.14,0.16,0.21,0.58]]) 128 | 129 | #其中data就是输入的数据(矩阵形式),w_list是各个因素(指标)的权重序列(要和指标的数量对上) 130 | def evalue_func(data,w_list): #其中data就是输入的数据(矩阵形式),w_list是各个因素(指标)的权重序列 131 | return np.dot(np.array(w_list),data) 132 | #下面进行输出(选择对应隶属度最高的方案就行了) 133 | test_result=evalue_func(test_data,[0.2,0.3,0.2,0.2,0.1]) 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /code/灰色关联分析.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | import seaborn as sns 5 | 6 | data=pd.read_csv('D:\\2022国赛数模练习题\\data\\附件2.csv',encoding='gbk') 7 | main_data=data['As (μg/g)'] #母序列 8 | data.drop(columns='编号',inplace=True,axis=1) 9 | data.drop(columns='As (μg/g)',inplace=True,axis=1) 10 | data_column=data.columns #列名 11 | #下面进行数据的标准化或者归一化(各种类型的指标处理) 12 | def standardization(data): #data是矩阵,主要功能是进行标准化,输出是经过标准化的矩阵 13 | data_std=[np.std(data[:,i]) for i in range(data.shape[1])] 14 | data_mean=[np.mean(data[:,i]) for i in range(data.shape[1])] 15 | for i in range(data.shape[1]): 16 | data[:,i]=(data[:,i]-data_mean[i])/data_std[i] 17 | return data 18 | 19 | # 标准话功能函数(处理序列) 20 | def standardization2(data): # data是序列,主要功能是进行标准化,输出是经过标准化的序列 21 | data_std = np.std(data) 22 | data_mean = np.mean(data) 23 | for i in range(len(data)): 24 | data[i] = (data[i] - data_mean) / data_std 25 | return data 26 | 27 | stad_data=pd.DataFrame(standardization(data.values),columns=data_column) #经过处理后的子序列dataframe 28 | main_data=standardization2(main_data) #处理后的母序列 29 | 30 | #下面可以进行绘制趋势图(做简单的分析) 31 | plt.figure(figsize=(8,6)) 32 | # 这两行代码解决 plt 中文显示的问题 33 | plt.rcParams['font.sans-serif'] = ['SimHei'] 34 | plt.rcParams['axes.unicode_minus'] = False 35 | plt.tick_params(size=5,labelsize = 13) #坐标轴 36 | plt.grid(alpha=0.3) #是否加网格线 37 | x=np.arange(1,len(main_data)+1) #x坐标 38 | plt.plot(x,main_data,ls=':') #绘制母序列图 39 | for i in range(7): #绘制子序列图 40 | plt.plot(x,stad_data.values[:,i],ls=':') 41 | plt.legend(['As','Cd','Cr','Cu','Hg','Ni','Pb','Zn']) 42 | plt.xlabel('序号',fontsize=13) 43 | plt.ylabel('值',fontsize=13) 44 | plt.title('各个重金属浓度标准后的值',fontsize=15) 45 | plt.show() 46 | 47 | #主体函数 48 | def grey_relation_algorithm(main_data,data,p=0.5): #其中main_data是母序列,data是包含所有子序列的dataframe,p是辨别系数,一般取0.5,输入的数据都是要已经过标准化或者正向化处理的数据。 49 | main_data=np.array(main_data) #转化成向量 50 | data_matrix=data.values #转化成矩阵 51 | #下面求解绝对值矩阵(这里假设第一列是母序列) 52 | for i in range(data_matrix.shape[1]): 53 | data_matrix[:,i]=np.abs(data_matrix[:,i]-main_data) 54 | #下面找全局最小点a和最大点b 55 | a=np.min(data_matrix) #全局最小值 56 | b=np.max(data_matrix) #全局最大值 57 | #计算每一个指标的灰色关联度 58 | result_list=[] 59 | for i in range(data_matrix.shape[1]): 60 | result_list.append(np.mean((a+p*b)/(data_matrix[:,i]+p*b))) 61 | return result_list 62 | 63 | result1=grey_relation_algorithm(main_data,stad_data) #输出最终的各指标灰色关联度 64 | 65 | #下面进行绘制灰色单行关联度矩阵热点图 66 | #首先要创建一个单行的dataframe 67 | trans_data=pd.DataFrame({'Cd':result1[0],'Cr':result1[1],'Cu':result1[2],'Hg':result1[3],'Ni':result1[4],'Pb':result1[5],'Zn':result1[6]},index=['AS']) 68 | trans_data.index=['As'] #修改行号 69 | #下面开始绘制 70 | sns.set(font_scale=0.7) 71 | plt.rcParams['font.sans-serif'] = ['SimHei'] 72 | plt.rcParams['axes.unicode_minus'] = False 73 | # 热力图主要参数调整 74 | ax = sns.heatmap(trans_data.loc[['As'], :], square=True, 75 | cbar_kws={'orientation': 'horizontal', "shrink": 0.8}, 76 | annot=True, annot_kws={"size": 12}, vmax=1.0, cmap='coolwarm') 77 | # 设置标题 78 | ax.set_title('各指标的灰色关联度',fontsize=13) 79 | # 更改坐标轴标签字体大小 80 | ax.tick_params(labelsize=12) 81 | #ax.set_xticklabels(ax.get_xticklabels(), rotation=20) #坐标名进行旋转,当坐标名称很长时可使用 82 | plt.show() 83 | 84 | #下面是基于灰色关联分析的综合评价法 85 | #首先要对数据进行正向化、归一化或标准化操作 86 | new_data=standardization(data.values) #7列变量 87 | 88 | #下面是评价的主体函数 89 | def Gray_comprehensive_evaluation(data,weight=None,p=0.5): #其中data是输入的处理后的矩阵形式的数据,dataframe形式,weight是输入的权重序列,p是分辨系数,默认为0.5 90 | #下面进行构造虚拟样本序列(求每列的最大值) 91 | main_vector=np.max(data,axis=0) 92 | #计算K矩阵(所有样本减去main_vector的绝对值) 93 | K_matrix=np.abs(data-main_vector) 94 | #计算全局最小值a和全局最大值b 95 | a=np.min(K_matrix) 96 | b=np.max(K_matrix) 97 | #下面进行计算关联度(每个数都要) 98 | new_K_matrix=(a+p*b)/(np.abs(K_matrix)+p*b) 99 | #下面得到每个样本的综合评价分数 100 | if weight==None: #如果没有给权重的话,就认为所有指标的权重相等 101 | result=np.sum(new_K_matrix,axis=1)/data.shape[1] 102 | else: #如果有权重的话 103 | result=np.sum(new_K_matrix*np.array(weight),axis=1) 104 | return result #返回各个样本的综合分数,一个序列 105 | #下面进行输出结果 106 | result2=Gray_comprehensive_evaluation(new_data,weight=[0.2,0.1,0.15,0.1,0.1,0.3,0.05],p=0.5) 107 | print(result2) 108 | -------------------------------------------------------------------------------- /code/灰色预测模型.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | 4 | #下面进行构造级比检验的函数 5 | def scale_test(data,n): #data为输入的序列,n为序列元素个数 6 | left_value=np.exp(-(2/(n+1))) #左区间 7 | right_value=np.exp(2/(n+1)) #右区间 8 | new_data1=np.array(data[:-1])+1000 #转化为array类型,取前n-1个 9 | new_data2=np.array(data[1:])+1000 #取后n-1个数据 10 | result=new_data1/new_data2 11 | print(min(result),max(result)) 12 | print(left_value) 13 | print(right_value) 14 | return result,left_value,right_value\ 15 | 16 | """scale_test(new_EA_Y[:-3],14) 17 | scale_test(new_WA_Y[:-3],14) 18 | scale_test(new_AS_Y[:-3],14) 19 | scale_test(new_MS_Y[:-3],14)""" 20 | 21 | #下面进行构造灰色预测模型的函数 22 | 23 | def GM11(x, n): 24 | ''' 25 | 灰色预测 26 | x:序列,numpy对象 27 | n:需要往后预测的个数 28 | ''' 29 | x1 = x.cumsum() # 一次累加 30 | z1 = (x1[:len(x1) - 1] + x1[1:]) / 2.0 # 紧邻均值 31 | z1 = z1.reshape((len(z1), 1)) 32 | B = np.append(-z1, np.ones_like(z1), axis=1) 33 | Y = x[1:].reshape((len(x) - 1, 1)) 34 | # a为发展系数 b为灰色作用量 35 | [[a], [b]] = np.dot(np.dot(np.linalg.inv(np.dot(B.T, B)), B.T), Y) # 计算待估参数 36 | result = (x[0] - b / a) * np.exp(-a * (n - 1)) - (x[0] - b / a) * np.exp(-a * (n - 2)) # 预测方程 37 | S1_2 = x.var() # 原序列方差 38 | e = list() # 残差序列 39 | for index in range(1, x.shape[0] + 1): 40 | predict = (x[0] - b / a) * np.exp(-a * (index - 1)) - (x[0] - b / a) * np.exp(-a * (index - 2)) 41 | e.append(x[index - 1] - predict) 42 | print(predict) # 预测值 43 | print("后验差检验") 44 | S2_2 = np.array(e).var() # 残差方差 45 | C = S2_2 / S1_2 # 后验差比 46 | if C <= 0.35: 47 | assess = '后验差比<=0.35,模型精度等级为好' 48 | elif C <= 0.5: 49 | assess = '后验差比<=0.5,模型精度等级为合格' 50 | elif C <= 0.65: 51 | assess = '后验差比<=0.65,模型精度等级为勉强' 52 | else: 53 | assess = '后验差比>0.65,模型精度等级为不合格' 54 | # 预测数据 55 | predict = list() 56 | for index in range(x.shape[0] + 1, x.shape[0] + n + 1): 57 | predict.append((x[0] - b / a) * np.exp(-a * (index - 1)) - (x[0] - b / a) * np.exp(-a * (index - 2))) 58 | predict = np.array(predict) 59 | 60 | return a,b,predict,C,assess #其中a为发展系数,b为灰色作用量,predict为预测的序列,C为后验差比,assess是后验差比结构 61 | 62 | #a,b,predict,C,assess=GM11(np.array(new_AS_Y[:-3])+1000,3) 63 | -------------------------------------------------------------------------------- /code/熵权法.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | #熵权法 3 | def Entropy_weight_method(data): # data是输入的csv文件,输出是权值序列 4 | yij = data.apply(lambda x: x / x.sum(), axis=0) # 第i个学生的第j个指标值的比重yij = xij/sum(xij) i=(1,m) 5 | K = 1 / np.log(len(data)) #常数 6 | tmp = yij * np.log(yij) 7 | tmp = np.nan_to_num(tmp) 8 | ej = -K * (tmp.sum(axis=0)) # 计算第j个指标的信息熵 9 | wj = (1 - ej) / np.sum(1 - ej) # 计算第j个指标的权重 10 | return wj #输出权值序列 -------------------------------------------------------------------------------- /code/特征选择.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | from sklearn.preprocessing import StandardScaler,MinMaxScaler,Normalizer #第一个是标准化,第二个是归一化,第三个是向量归一化 4 | from sklearn.ensemble import RandomForestRegressor,GradientBoostingRegressor 5 | from sklearn.model_selection import cross_val_score 6 | import matplotlib.pyplot as plt 7 | 8 | #导入数据 9 | data=pd.read_csv('D:\\2022国赛数模练习题\\筛选后的白葡萄理化指标.csv',encoding='gbk') 10 | target_value=data.iloc[:,-1] #假设最后一个特征是因变量 11 | data=data.iloc[:,:-1] 12 | data.drop(columns='样品编号',inplace=True) 13 | data_columns=data.columns #29种自变量特征 14 | #下面是三种类型的数据无量纲化方式 15 | stand_scaler=StandardScaler() 16 | Minmax_scaler=MinMaxScaler() 17 | Normalizer_scaler=Normalizer() 18 | 19 | stand_data=stand_scaler.fit_transform(data.values) #标准化后的原始数据(矩阵形式) 20 | Minmax_data=Minmax_scaler.fit_transform(data.values) #归一化后的数据(矩阵形式) 21 | 22 | #下面进行筛选特征 23 | #第一种方法:方差筛选特征法(适用于量纲相同的,但是不能是经过标准化后的数据,可以用归一化后的数据) 24 | Variance_list=np.std(Minmax_data,axis=0) 25 | sort_list1=sorted(zip(data_columns.tolist(),Variance_list),key=lambda x: x[1],reverse=True) #按照方差值进行降序排序,再定阈值进行筛选即可 26 | 27 | #第二种方式:相关系数法(Pearson相关系数、斯皮尔曼相关系数) 28 | corr_data=pd.DataFrame(stand_data).corr() 29 | corr_list=np.abs(corr_data.iloc[:,-1]) #绝对值相关系数 30 | sort_list2=sorted(zip(data_columns.tolist(),corr_list),key=lambda x: x[1],reverse=True) #按照相关系数绝对值进行降序排序,再定阈值进行筛选即可 31 | 32 | #第三种方式:基于树模型的特征选择法(随机森林算法、GBDT) 33 | #1随机森林算法进行特征筛选 34 | #先利用所有数据训练一个随机森林回归模型 35 | RF=RandomForestRegressor(n_estimators=10,random_state=42)#构建随机森林模型,树的数量根据数据量和维数进行选择 36 | RF.fit(stand_data,target_value.tolist()) #用所有数据训练模型 37 | importances1=RF.feature_importances_ #输出特征重要性评分 38 | sort_list3=sorted(zip(data_columns.tolist(),importances1.tolist()),key=lambda x:x[1],reverse=True) #按重要性评分从小到大进行排序 39 | 40 | #2GBDT算法继续宁特征筛选 41 | GBDT=GradientBoostingRegressor(n_estimators=10,random_state=42) 42 | GBDT.fit(stand_data,target_value.tolist()) 43 | importances2=GBDT.feature_importances_ 44 | sort_list4=sorted(zip(data_columns.tolist(),importances2.tolist()),key=lambda x:x[1],reverse=True) #按重要性评分从小到大进行排序 45 | 46 | #第4种方式:递归特征筛除法(不断剔除重要性最低的特征,并以最终模型的交叉验证精度来评估选择的特征),注意其可以写伪代码 47 | data_columns=data_columns.tolist() 48 | cross_score_list=[] #存储不同数量的特征交叉验证的平均精度 49 | for i in range(10): #这里可以设定最终剔除多少个特征 50 | RF=RandomForestRegressor(10,random_state=42) 51 | RF.fit(stand_data,target_value.tolist()) 52 | #下面进行存储每个组合特征的交叉验证精度 53 | cross_score_list.append(np.abs(np.mean(cross_val_score(RF,stand_data,target_value.tolist(),cv=5,scoring='neg_mean_squared_error')))) #5折的交叉验证,使用的指标函数为R方'r2',或者mse注意利用mse这种越小越好的指标时,sklearn中计算出的会带上负号 54 | #下面进行计算各特征重要性,并降序 55 | importances3=RF.feature_importances_ 56 | sort_list5=sorted(zip(data_columns,importances3),key=lambda x:x[1],reverse=True) 57 | #去除重要性评分最低的特征(最后一个) 58 | drop_feature_index=data_columns.index(str(sort_list5[-1][0])) #得到要剔除特征的序号 59 | #data_columns=data_columns 60 | data_columns.pop(drop_feature_index) 61 | stand_data=stand_scaler.fit_transform(data[data_columns].values) 62 | 63 | #下面进行绘制mse指标图片选择特征数量 64 | plt.figure(figsize=(8,6)) 65 | plt.tick_params(size=5,labelsize = 13) #坐标轴 66 | plt.grid(alpha=0.3) #是否加网格线 67 | x=np.arange(1,len(cross_score_list)+1) 68 | plt.plot(x,cross_score_list,color='b',linewidth=2,alpha=0.6) 69 | plt.scatter(x,cross_score_list,c='b',alpha=0.6,s=20) 70 | #下面打上标签 71 | for i,value in enumerate(cross_score_list): 72 | plt.text(x[i],value+0.05,round(value,1),horizontalalignment='center',fontsize=10) 73 | plt.xlabel('Number of features removed',fontsize=13) 74 | plt.ylabel('MSE',fontsize=13) 75 | plt.title('MSE with different number of removal features',fontsize=15) 76 | plt.show() 77 | 78 | #进行选择好特征后,可以用柱形图展现选择特征的重要性信息 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /code/目标规划.py: -------------------------------------------------------------------------------- 1 | #非线性目标函数的一般解法(利用scipy进行求解) 2 | '''result1='' 3 | for i in range((len(t_list)-1)//2): 4 | # 计算最终的预测影长与真实影长之间的差值的绝对值 5 | a1 = f'np.arcsin(np.sin({Declination_1} * np.pi / 180) * np.sin(x[1] * np.pi / 180) + np.cos({Declination_1} * np.pi / 180) * np.cos(x[1] * np.pi / 180) * np.cos(15 * ({t_list[i + 10]} + (x[0] - 300) / 15) * np.pi / 180))' # 注意这里取的是后10天,这样可以增大偏差 6 | # 也是计算太阳高度角(i*2) 7 | a2 = f'np.arcsin(np.sin({Declination_1} * np.pi / 180) * np.sin(x[1] * np.pi / 180) + np.cos({Declination_1} * np.pi / 180) * np.cos(x[1] * np.pi / 180) * np.cos(15 * ({t_list[i]} + (x[0] - 300) / 15) * np.pi / 180))' 8 | # 计算方位角(i*2+1) 9 | o1 = f'np.arccos((np.sin({Declination_1} * np.pi / 180) * np.cos(x[1] * np.pi / 180) - (np.cos({Declination_1} * np.pi / 180) * np.sin(x[1] * np.pi / 180) * np.cos(15 * ({t_list[i + 10]} + (x[0] - 300) / 15) * np.pi / 180))) / np.cos(a1))' 10 | # 计算方位角(i*2) 11 | o2 = f'np.arccos((np.sin({Declination_1} * np.pi / 180) * np.cos(x[1] * np.pi / 180) - (np.cos({Declination_1} * np.pi / 180) * np.sin(x[1] * np.pi / 180) * np.cos(15 * ({t_list[i]} + (x[0] - 300) / 15) * np.pi / 180))) / np.cos(a2))' 12 | 13 | l = f'np.abs(np.tan({a2})/np.tan({a1})-{l_list6[i+10]}/{l_list6[i]})' 14 | if i!=(len(t_list)-1)//2-1: 15 | result1+=l+'+' 16 | else: 17 | result1+=l 18 | #定义最终的目标函数 19 | def fun(): 20 | v=lambda x:eval(result1) 21 | return v 22 | 23 | #创建限制函数(注意这里的限制条件不足,还需要多设置几个) 24 | def con(): 25 | cons=[] 26 | for t0 in t_list: #注意当type为ineq的时候,默认后面的约束时<=0,如果是等式就将type变为eq。 27 | cons.append({'type': 'ineq', 'fun': lambda x: eval(f'x[2]/np.tan(np.arcsin(np.cos(({t0}+(x[0]-300)/15) * np.pi / 180) * np.cos({Declination_1} * np.pi / 180) * np.cos(x[1] * np.pi / 180) + np.sin({Declination_1} * np.pi / 180) * np.sin(x[1] * np.pi / 180)))')}) 28 | cons=tuple(cons) 29 | return cons 30 | cons=con() #得到约束条件 31 | 32 | #定义初始预测值(经度、纬度、杆高)进行循环遍历取最小目标值,得到最终的经度和纬度(要通过不断的设置初始值来最终得到全局最优解而不是局部最优) 33 | #x0就是初始值 34 | bounds=((0,None),(0,None),(0,None)) #求解参数的范围 35 | new_x_list=[] 36 | result_list=[] 37 | for i in range(180): 38 | for j in range(90): 39 | x0=np.asarray((i,j)) 40 | res = minimize(fun(), x0, method='SLSQP', bounds=bounds,constraints=cons) #bounds就是需要规划求解的参数的范围 41 | result_list.append(res.fun) #目标函数值 42 | new_x_list.append(res.x) #求解的参数结果 43 | print(new_x_list[np.argmin(result_list)])''' 44 | 45 | #用其他解法来求解非线性规划问题(其准确度有待探究) 46 | import cvxpy as cp #只适合解决参数比较少,比较好手输入的式子,不适合约束条件负责或者目标函数很长的式子,不能用eval(),或者直接手输也行 47 | #同时其适合解决0-1规划的问题 48 | def target_func4(x,length,index_list,risk_list): #length是长度这里是99,index_list是评级列表,返回的是字符串类型的函数 49 | result=0 #注意后面是求最小的,因此加个负号求最大 50 | a=0 51 | for i in range(length): 52 | if index_list[i]==3:#评级为A时 53 | a=(1-risk_list[i])*x[i*2]*x[i*2+1]*(1-(-5095*x[i*2]**4+2574*x[i*2]**3-519.3*x[i*2]**2+52.64*x[i*2]-1.41)) #注意这里还需修改多项式回归函数 54 | elif index_list[i]==2:#评级为B时 55 | a = (1-risk_list[i])*x[i * 2]*x[i * 2 + 1]*(1-(-6769*x[i*2]**4+3378*x[i*2]**3-649.2*x[i*2]**2+60.68*x[i*2]-1.589)) 56 | elif index_list[i]==1: #评级为C时 57 | a = (1-risk_list[i])*x[i * 2]*x[i * 2 + 1]*(1-(-2202*x[i*2]**4+1340*x[i*2]**3-320.1*x[i*2]**2+38.5*x[i*2]-1.098)) 58 | if i != length - 1: 59 | result += a 60 | else: 61 | result+=a 62 | result=-(result) 63 | return result 64 | 65 | def money_count1(x,length): 66 | total_money=0 67 | for i in range(length): 68 | if i!= length-1: 69 | total_money+=x[i*2+1] 70 | else: 71 | total_money+=x[i*2+1] 72 | return total_money 73 | 74 | length_y=15 75 | n=15 76 | x=cp.Variable(n) #设置n个变量 77 | #创建目标函数 78 | target_y=target_func4(x,) 79 | obj=cp.Minimize(target_y) 80 | #创建约束条件 81 | total_money_y=money_count1(x,length_y) 82 | cons=[-total_money_y+9900>=0,total_money_y-990>=0] 83 | prob=cp.Problem(obj,cons) 84 | #进行求解 85 | ans=prob.solve(solver='CPLEX') #注意CPLEX是专门进行求解非线性问题的 86 | print(ans) 87 | print(x.value) 88 | 89 | #遍历的方式求解目标规划问题(其实也就是找到目标函数最小的参数) 90 | #定义已知或者固定变量 91 | '''data_1=pd.read_csv('D:\\2022国赛数模练习题\\2022宁波大学数学建模暑期训练第三轮训练题B\\附件1.csv',encoding='gbk') 92 | #计算影子长度并构建影子长度序列 93 | data_1['影子长度']=(data_1['x坐标(米)'].apply(lambda x: x**2)+data_1['y坐标(米)'].apply(lambda x: x**2))**0.5 94 | l_list6=[x for x in data_1['影子长度']] 95 | x_list=[x for x in data_1['x坐标(米)']] #x坐标参数 96 | y_list=[x for x in data_1['y坐标(米)']] #y坐标参数 97 | N=108 #第108天 98 | t_list=[14.7+i*0.05 for i in range(21)] #时间序列,转化成小时来表示 99 | #计算赤纬角 100 | Declination_1=23.45*np.sin(2*np.pi*(284+N)/365) #跟日期有关 101 | 102 | total_error_list=[] #误差序列 103 | latitude_list=[] #纬度序列 104 | longitude_list=[] #经度序列 105 | for i in range(0,180): #经度 106 | for j in range(0,90): #纬度 107 | error=0 #天数累积的误差 108 | # for w in range(1,101): 109 | # new_w=w*0.01 110 | # print(new_w) 111 | for step in range((len(t_list)-1)//2): #这个是时间的步长序列 112 | # 计算太阳高度角(弧度制)i*2+1 113 | a1 = np.arcsin(np.sin(Declination_1* np.pi / 180)*np.sin(j* np.pi / 180)+np.cos(Declination_1* np.pi / 180)*np.cos(j* np.pi / 180)*np.cos(15*(t_list[step+10]+(i-300)/15)*np.pi/180)) #注意这里取的是后10天,这样可以增大偏差 114 | # 也是计算太阳高度角(i*2) 115 | a2 = np.arcsin(np.sin(Declination_1* np.pi / 180)*np.sin(j* np.pi / 180)+np.cos(Declination_1* np.pi / 180)*np.cos(j* np.pi / 180)*np.cos(15*(t_list[step]+(i-300)/15)*np.pi/180)) 116 | # 计算方位角(i*2+1) 117 | o1 = np.arccos((np.sin(Declination_1* np.pi / 180)*np.cos(j* np.pi / 180)-(np.cos(Declination_1* np.pi / 180)*np.sin(j* np.pi / 180)*np.cos(15*(t_list[step+10]+(i-300)/15)*np.pi/180)))/np.cos(a1)) 118 | # 计算方位角(i*2) 119 | o2 = np.arccos((np.sin(Declination_1* np.pi / 180)*np.cos(j* np.pi / 180)-(np.cos(Declination_1* np.pi / 180)*np.sin(j* np.pi / 180)*np.cos(15*(t_list[step]+(i-300)/15)*np.pi/180)))/np.cos(a2)) 120 | #计算偏差影长误差 121 | error += np.abs(np.tan(a2)/np.tan(a1)-l_list6[step+10]/l_list6[step]) 122 | #计算方位角偏差注意这里还可以取权重来减少误差 123 | #error+=np.abs(np.abs(o1-o2)-np.abs(np.arccos((x_list[step+10]*x_list[step]+y_list[step+10]*y_list[step])/(l_list6[step+10]*l_list6[step])))) 124 | total_error_list.append(error) 125 | 126 | print(np.argmin(total_error_list)) 127 | print(min(total_error_list)) 128 | print(f'经度为{np.argmin(total_error_list)//90}') 129 | print(f'纬度为{np.argmin(total_error_list)%90}') 130 | ''' 131 | 132 | #线性规划就是可以用pulp 133 | """for i in range(24): 134 | prob1=pulp.LpProblem('problem2',sense=pulp.LpMinimize) 135 | #进行批量定义决策变量 136 | var1=[pulp.LpVariable(f'x{x}',0,round(6000*avg_rate_23[x][i],0),pulp.LpInteger) for x in range(23)] 137 | #添加目标函数 138 | prob1+=pulp.lpDot(np.array(total_parameter[i*12:(i+1)*12]),var1) 139 | #添加约束条件 140 | prob1+=(pulp.lpDot(np.array(original_product23),var1)>=40000) 141 | prob1.solve() #求解最优解 142 | #输出 143 | #print('Status:',pulp.LpStatus[prob1.status]) #输出求解状态 144 | for i in prob1.variables(): 145 | result_list1.append(i.varValue) 146 | print(i.name, '=', i.varValue) # 输出每个变量的最优解 147 | print('F(x)', '=', pulp.value(prob1.objective)) # 输出最优解的目标函数值 148 | 149 | result_func1.append(pulp.value(prob1.objective))""" 150 | -------------------------------------------------------------------------------- /code/相关性分析.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | import pandas as pd 4 | from scipy import stats 5 | import seaborn as sns 6 | from collections import Counter #拥有计数功能 7 | from sklearn import metrics 8 | 9 | #下面进行读取数据 10 | data=pd.read_csv('C:\\Users\\86137\\Desktop\\2022数模国赛\\支撑材料\\data\\预测后的数据.csv',encoding='gbk') 11 | data['颜色']=data['颜色'].fillna('未知') #填补缺失值 12 | data_K=data[data['类型']=='高钾'] 13 | data_B=data[data['类型']=='铅钡'] 14 | chemical_columns=data.columns[5:] 15 | 16 | #下面是先进行正态性检验 17 | p_value_ks=[] #存储F检验的p值,p值大于0.05说明符合正态分布 18 | for column in chemical_columns: 19 | mean=np.mean(data[column]) #计算每一列数据的均值 20 | std=np.std(data[column])#计算每一列数据的标准差 21 | result=stats.kstest(data[column],'norm',(mean,std))#主要的正态分布检验代码,p值大于0.05说明其符合正态分布 22 | p_value_ks.append(result[1]) 23 | 24 | #下面进行绘制pair图观察数据的分布状况(看是否符合线性相关的分布规律) 25 | """plt.figure(figsize=(8,6)) 26 | plt.rcParams['font.sans-serif'] = ['SimHei'] 27 | plt.rcParams['axes.unicode_minus'] = False 28 | sns.pairplot(data, hue='类型', aspect=1.5) #注意hue是分类变量(其可以看不同类别下的各特征之间的关系分布) 29 | plt.show()""" 30 | 31 | #下面进行pearson相关系数计算与可视化(如果存在线性相关性同时数据呈现正态分布的话就可以用) 32 | #计算并绘制相关性图函数 33 | def corr_heatmap1(data,title): #注意其中data是一个输入的dataframe,注意行名和列名哦都要改,title是图片的名称 34 | corrmat_data=data.corr() 35 | plt.figure(figsize=(8,6)) 36 | sns.heatmap(corrmat_data,annot=True,cmap='Purples') #cmap=Greens、Blues、Reds、Purples 也比较好看 37 | plt.title(title,fontsize=15) 38 | #plt.savefig(title + '.svg', format='svg', bbox_inches='tight') 39 | plt.show() 40 | corr_heatmap1(data_K.iloc[5:],'K') 41 | corr_heatmap1(data_B.iloc[5:],'B') 42 | #皮尔森相关性系数检验 43 | a1=stats.pearsonr(data_K['二氧化硅(SiO2)'],data_K['氧化钠(Na2O)']) #计算显著性检验p值,输出的第一个数是相关性系数,第二个数是p值 44 | 45 | #下面进行斯皮尔曼相关性系数分析(如果数据呈现非正态分布,同时想要看其是否是单调相关的时候) 46 | def corr_heatmap2(data,title): #注意其中data是一个输入的dataframe,注意行名和列名哦都要改,title是图片的名称 47 | corrmat_data=data.corr(method='spearman') 48 | plt.figure(figsize=(8,6)) 49 | sns.heatmap(corrmat_data,annot=True,cmap='Greens') #cmap=Greens 也比较好看 50 | plt.title(title,fontsize=15) 51 | #plt.savefig(title + '.svg', format='svg', bbox_inches='tight') 52 | plt.show() 53 | 54 | corr_heatmap2(data_K.iloc[5:],'K') 55 | corr_heatmap2(data_B.iloc[5:],'B') 56 | #斯皮尔曼相关性系数检验 57 | a2=stats.spearmanr(data_K['二氧化硅(SiO2)'],data_K['氧化钠(Na2O)']) #计算显著性检验p值,输出的第一个数是相关性系数,第二个数是p值 58 | 59 | #下面进行计算信息熵互信息来判断数据之间是否存在相关性(取值从 0~1)(适合应用于分类变量)直接可以使用sklearn中的函数进行实现 60 | x=data['表面风化'] 61 | result=[] 62 | for column in data.columns[1:4]: #注意原始数据不能有缺失值 63 | result.append(metrics.normalized_mutual_info_score(x, data[column])) #直接计算x与y的互信息,越大表示相关性越强 64 | print("result_NMI:",result) #注意最后可以试试绘制热点图进行可视化表示 65 | 66 | '''def Entropy(data): 67 | count=len(data) #计算总数量 68 | counter=Counter(data) #统计每个变量出现的次数,会是一个字典的形式返回 69 | prob={i[0]:i[1]/count for i in counter.items()} #这里先对counter字典中把关键字和值取出,同时计算每个概率p 70 | H=np.sum([i[1]*np.log2(i[1]) for i in prob.items()]) #这里进行计算信息熵(求和) 71 | return H 72 | 73 | x=data['表面风化'] 74 | y=data['类型'] 75 | xy=list(zip(x,y)) #用于接下来计算联合分布概率 76 | Hx=Entropy(x) #x的信息熵 77 | Hy=Entropy(y) #y的信息熵 78 | Hxy=Entropy(xy) #计算联合熵xy 79 | H_x_y=Hxy-Hy #条件熵 X|Y 80 | H_y_x=Hxy-Hx # 条件熵 Y|X''' 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /code/秩和比综合评价法.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | import statsmodels.api as sm 4 | from scipy import stats 5 | import matplotlib.pyplot as plt 6 | from matplotlib import rcParams #导入包 7 | from scipy.stats import levene #T检验和方差齐性检验 8 | from statsmodels.formula.api import ols #单因素方差分析 9 | from statsmodels.stats.anova import anova_lm 10 | 11 | config = {"font.family":'Times New Roman'} # 设置字体类型 12 | rcParams.update(config) #进行更新配置 13 | 14 | #下面进行构建秩和比综合评价的函数,其中data是dataframe的格式,weight是传入的权重列表(可以用其他赋权算法搞,否则就是等权), 15 | # threshold是最后进行分级的Probits范围,列表形式例如[2, 4, 6, 8][(2, 4] < (4, 6] < (6, 8]],默认分成3级,full_rank表示是否是整秩算秩秩,否则用非整秩的算法,一般是非整秩 16 | def rsr(data, weight=None, threshold=None, full_rank=False): 17 | Result = pd.DataFrame() #构建一个dataframe数据结构用于存储原始数据和对应的秩、RSR、Probit、RSR Regression和level 18 | n, m = data.shape #得到数据的行列数 19 | 20 | # 对原始数据编秩 21 | if full_rank: #选择整秩算法 22 | for i, X in enumerate(data.columns): #对每列原始数据 23 | Result[f'X{str(i + 1)}:{X}'] = data.iloc[:, i] 24 | Result[f'R{str(i + 1)}:{X}'] = data.iloc[:, i].rank(method="average") #注意原值越大,排名的数值越大 25 | else:#采用非整秩算法 26 | for i, X in enumerate(data.columns): 27 | Result[f'X{str(i + 1)}:{X}'] = data.iloc[:, i] 28 | Result[f'R{str(i + 1)}:{X}'] = 1 + (n - 1) * (data.iloc[:, i]-data.iloc[:, i].min()) / ( 29 | data.iloc[:, i].max() - data.iloc[:, i].min()) 30 | 31 | # 计算秩和比 32 | weight = 1 / m if weight is None else np.array(weight) / sum(weight) #加入权重 33 | Result['RSR'] = (Result.iloc[:, 1::2] * weight).sum(axis=1) / n #计算RSR值 34 | Result['RSR_Rank'] = Result['RSR'].rank(ascending=False) #计算RSR_rank的值,这里是RSR越大排名的数值越小(1)这个数据意义不大 35 | 36 | # 绘制 RSR 分布表 37 | RSR = Result['RSR'] 38 | RSR_RANK_DICT = dict(zip(RSR.values, RSR.rank().values))#存储RSR和其排名的一个字典元组序列,注意RSR越大,其排名的数值越大 39 | print(RSR_RANK_DICT) 40 | #下面进行构建分布的表格 41 | Distribution = pd.DataFrame(index=sorted(RSR.unique()))#先按照RSR进行升序排列,index 42 | Distribution['f'] = RSR.value_counts().sort_index() #进行计算RSR的频数 43 | Distribution['Σ f'] = Distribution['f'].cumsum() #计算累计频数 44 | Distribution['R-'] = [RSR_RANK_DICT[i] for i in Distribution.index] #得到平均秩次(也就是其原始的一个秩次) 45 | Distribution['R-/n*100%'] = Distribution['R-'] / n # 根据平均秩次计算累计频率 46 | Distribution.iat[-1, -1] = 1 - 1 / (4 * n) # 修正最后一项累计频率 47 | Distribution['Probit'] = 5 - stats.norm.isf(Distribution.iloc[:, -1]) # inverse survival function 将累计频率换算为概率单位 48 | 49 | # 计算回归方差并进行回归分析(下面是进行一元线性回归)RSR=a*Probit+b(r0为一个元组,第一个值为斜率,第二个为截距) 50 | r0 = np.polyfit(Distribution['Probit'], Distribution.index, deg=1) # x,y 51 | 52 | #下面的这个也是进行一元线性回归结果和上面的相同(最小二乘法得到),主要为了得到resid进行后续的残差正态检验,检测回归模型的有效性 53 | model = sm.OLS(Distribution.index, sm.add_constant(Distribution['Probit'])) 54 | result = model.fit() 55 | print(result.summary()) #各种资料打印,还有各种评价模型的指标展示,R方、AIC,BIC等 56 | 57 | # 残差检验,检验残差是否符合正态分布,从而证明模型的有效性,z为统计量,p为p值,p小于0.05则认为拒绝原假设,认为不符合正态分布 58 | z_error, p_error = stats.normaltest( 59 | result.resid.values) # tests the null hypothesis that a sample comes from a normal distribution 60 | print(f"残差分析:统计量为{z_error} p值为{p_error}") 61 | 62 | #输出回归方程 63 | if r0[1] > 0: 64 | print(f"\n回归直线方程为:y = {r0[0]} Probit + {r0[1]}") 65 | else: 66 | print(f"\n回归直线方程为:y = {r0[0]} Probit - {abs(r0[1])}") 67 | 68 | #下面进行绘制拟合曲线 69 | x=Distribution['Probit'] 70 | y1=Distribution.index #原始的RSR值 71 | y2=np.polyval(r0,Distribution['Probit'])#修正后的RSR值(线性曲线) 72 | plt.figure(figsize=(8,6)) 73 | plt.tick_params(size=5, labelsize=13) # 坐标轴 74 | plt.grid(alpha=0.3) # 是否加网格线· 75 | plt.plot(x,y1,label='Original value',marker='o',color='#bf0000') 76 | plt.plot(x, y2, label='Corrected value', marker='*', color='#F21855') 77 | #打上标签 78 | # 下面进行打上标签 79 | for i, data in enumerate(y1): 80 | plt.text(x.tolist()[i], data + 0.002, round(data, 2), horizontalalignment='center', fontsize=13) 81 | for i, data in enumerate(y2): 82 | plt.text(x.tolist()[i], data + 0.002, round(data, 2), horizontalalignment='center', fontsize=13) 83 | plt.legend() 84 | plt.xlabel('Probit',fontsize=13) 85 | plt.ylabel('RSR', fontsize=13) 86 | plt.title('Original value and corrected RSR', fontsize=15) 87 | plt.show() 88 | 89 | # 代入回归方程并分档排序 90 | Result['Probit'] = Result['RSR'].apply(lambda item: Distribution.at[item, 'Probit']) #找到Distribution中RSR(index)对应的Probit 91 | ##下面得到修正后的RSR(将Probit带入回归方程得到) 92 | Result['Regression'] = np.polyval(r0, Result['Probit']) 93 | #下面进行分级,先得到修正后RSR范围 94 | threshold = np.polyval(r0, [2, 4, 6, 8]) if threshold is None else np.polyval(r0, threshold) 95 | #根据范围将修正后的RSR进行分级(注意这里是修正后的RSR越大,则等级的数值越大 96 | Result['Level'] = pd.cut(Result['Regression'], threshold, 97 | labels=range(1,len(threshold))) # Probit分组[(2, 4] < (4, 6] < (6, 8]] 98 | 99 | #下面利用单因素方差分析来检验分档结果的有效性 100 | # 首先进行方差齐性检验 101 | if len(threshold)-1==3: #分成3级的情况 102 | test1 = levene(Result[Result['Level']==1]['Regression'],Result[Result['Level']==2]['Regression'], 103 | Result[Result['Level']==3]['Regression']) 104 | elif len(threshold)-1==4: #分成4级的情况 105 | test1 = levene(Result[Result['Level']==1]['Regression'],Result[Result['Level']==2]['Regression'], 106 | Result[Result['Level']==3]['Regression'],Result[Result['Level']==4]['Regression']) 107 | elif len(threshold) - 1 == 5: # 分成5级的情况 108 | test1 = levene(Result[Result['Level'] == 1]['Regression'], Result[Result['Level'] == 2]['Regression'], 109 | Result[Result['Level'] == 3]['Regression'], Result[Result['Level'] == 4]['Regression'], 110 | Result[Result['Level'] == 3]['Regression']) 111 | #下面输出结果 112 | print(f'方差齐性检验的统计量为{test1[0]},p值为{test1[1]}') # 第一个是统计量,第二个是p值,p值大于0.05说明方差具有齐性 113 | 114 | #方差齐性检验如果通过可以进行单因素方差分析 115 | model = ols('Regression ~ C(Level)',Result).fit() # 前面的第一个是数值型变量,第二个是分类型变量,要加C,其表示Catagory 116 | #F值越大,p值越小,说明两者之间差异越显著 117 | anovaResults = anova_lm(model) # 看输出中分类变量的p值和F值即可 118 | print('单因素方差分析结果为:',anovaResults) 119 | 120 | return Result,Distribution #最终输出原来的结果表,和分布表 121 | 122 | # 读取数据 123 | data1 = pd.DataFrame({'产前检查率': [99.54, 96.52, 99.36, 92.83, 91.71, 95.35, 96.09, 99.27, 94.76, 84.80], 124 | '孕妇死亡率': [60.27, 59.67, 43.91, 58.99, 35.40, 44.71, 49.81, 31.69, 22.91, 81.49], 125 | '围产儿死亡率': [16.15, 20.10, 15.60, 17.04, 15.01, 13.93, 17.43, 13.89, 19.87, 23.63]}, 126 | index=list('ABCDEFGHIJ'), columns=['产前检查率', '孕妇死亡率', '围产儿死亡率']) 127 | 128 | #因为下面两个是成本型指标,需要反向排序(进行正向化操作,注意对结果不影响,因为这个算法主要看排名) 129 | data1["孕妇死亡率"] = 1 / data1["孕妇死亡率"] 130 | data1["围产儿死亡率"] = 1 / data1["围产儿死亡率"] 131 | # 下面是调用子函数进行秩和比几个步骤的计算 132 | a,b=rsr(data1,weight=[0.33,0.33,0.33],threshold=[2,4,6,8],full_rank=False) #注意其中的threshold是设定的Probit范围进行分级的 133 | #print(a['Regression']) #输出修正后的RSR(也就是综合的评分) 134 | #print(a['Level']) #输出分级结果 -------------------------------------------------------------------------------- /code/算法指标.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | from sklearn.metrics import mean_squared_error 4 | 5 | #均方误差MSE 6 | def mean_square_error(y1,y2): #y1是预测值序列,y2是真实值序列 7 | return np.sum((np.array(y1)-np.array(y2))**2)/len(y1) 8 | 9 | #均方根误差(RMSE) 10 | def root_mean_squard_error(y1,y2): #其中有y1是预测序列,y2是真实序列 11 | return np.sqrt(np.sum(np.square(np.array(y1)-np.array(y2)))/len(y1)) 12 | 13 | #平均绝对误差(MAE) 14 | def mean_absolute_error(y1,y2):#其中y1是预测序列,y2是真实序列 15 | return np.sum(np.abs(np.array(y1)-np.array(y2)))/len(y1) 16 | 17 | #AIC准则(越小越好) 18 | def cal_AIC(n,mse,num_params):#其中n是观测数量,mse是均方误差,num_params是模型参数个数 19 | aic=n*np.log(mse)+2*num_params 20 | return aic 21 | 22 | #BIC准则(越小越好,表示模型性能越好和复杂度越低) 23 | def cal_BIC(n,mse,num_params):#其中n是观测数量,mse是均方误差,num_params是模型参数个数 24 | bic=n*np.log(mse)+num_params*np.log(n) 25 | return bic 26 | 27 | #下面进行模型合理性分析,用R方(两种方式,第一种是Pearson相关系数的平方,第二种是) 28 | def computeCorrelation(x, y): #其中x,y均为序列,x是预测值,y是真实值,这里是计算Pearson相关系数,最后需要平方注意 29 | xBar = np.mean(x) #求预测值均值 30 | yBar = np.mean(y) #求真实值均值 31 | covXY = 0 32 | varX = 0 #计算x的方差和 33 | varY = 0 #计算y的方差和 34 | for i in range(0, len(x)): 35 | diffxx = x[i] - xBar #预测值减预测值均值 36 | diffyy = y[i] - yBar #真实值减真实值均值 37 | covXY += (diffxx * diffyy) 38 | varX += diffxx ** 2 39 | varY += diffyy ** 2 40 | return covXY/np.sqrt(varX*varY) 41 | 42 | #第二种计算R方的方式 (1-(SSE/SST)) 43 | def R_Squre2(y_pred,y_real): #其中y_pred是预测值,y_real是真实值,两者都是序列 44 | y_real_mean = np.mean(y_real) 45 | y_pred_var=0 #计算预测值减真实值的平方和 46 | y_real_var=0 47 | for i in range(len(y_pred)): 48 | y_pred_var+=(y_pred[i]-y_real[i])**2 49 | y_real_var+=(y_real[i]-y_real_mean)**2 50 | return 1-y_pred_var/y_real_var 51 | 52 | -------------------------------------------------------------------------------- /code/粒子群算法.py: -------------------------------------------------------------------------------- 1 | #x下面是粒子群算法的一个模板可以对着进行修改即可 2 | import math 3 | import random 4 | import numpy as np 5 | import matplotlib.pyplot as plt 6 | import pylab as mpl 7 | #画图时使其能显示中文 8 | mpl.rcParams['font.sans-serif'] = ['SimHei'] 9 | plt.rcParams['axes.unicode_minus'] = False 10 | #注意下面是求最大值,如果要求最小值直接就可在fitness函数添加负号即可 11 | class PSO: 12 | # 其中dimension是变量的个数,time是循环的次数,low是参数的下限,up是参数的上限(两者均是一个序列), 13 | # v_low是速度参数的下限,v_high是速度参数的上限(两者也都是序列) 14 | def __init__(self, dimension, time, size, low, up, v_low, v_high): 15 | # 初始化 16 | self.dimension = dimension # 变量个数 17 | self.time = time # 迭代的代数 18 | self.size = size # 种群大小 19 | self.bound = [] # 变量的约束范围 20 | self.bound.append(low) 21 | self.bound.append(up) 22 | self.v_low = v_low 23 | self.v_high = v_high 24 | self.x = np.zeros((self.size, self.dimension)) # 所有粒子的位置 25 | self.v = np.zeros((self.size, self.dimension)) # 所有粒子的速度 26 | self.p_best = np.zeros((self.size, self.dimension)) # 每个粒子最优的位置 27 | self.g_best = np.zeros((1, self.dimension))[0] # 全局最优的位置 28 | 29 | # 初始化第0代初始全局最优解(注意如果有其余限制条件的话) 30 | temp = -1000000 31 | for i in range(self.size): 32 | for j in range(self.dimension): 33 | self.x[i][j] = random.uniform(self.bound[0][j], self.bound[1][j]) 34 | self.v[i][j] = random.uniform(self.v_low, self.v_high) 35 | self.p_best[i] = self.x[i] # 储存最优的个体 36 | fit = self.fitness(self.p_best[i]) 37 | # 先初始化最初的全局最大值 38 | if fit > temp: 39 | self.g_best = self.p_best[i] 40 | temp = fit 41 | 42 | #下面就是计算目标函数的大小(复现主要需要修改的地方) 43 | def fitness(self, x): 44 | """ 45 | 个体适应值计算 46 | """ 47 | x1 = x[0] 48 | x2 = x[1] 49 | x3 = x[2] 50 | x4 = x[3] 51 | x5 = x[4] 52 | y = math.floor((x2 * np.exp(x1) + x3 * np.sin(x2) + x4 + x5) * 100) / 100 53 | # print(y) 54 | return y 55 | 56 | def update(self, size): 57 | c1 = 2.0 # 学习因子 58 | c2 = 2.0 59 | w = 0.8 # 自身权重因子 60 | for i in range(size): 61 | # 更新速度(核心公式) 62 | self.v[i] = w * self.v[i] + c1 * random.uniform(0,1) * ( 63 | self.p_best[i] - self.x[i]) + c2 * random.uniform(0, 1) * (self.g_best - self.x[i]) 64 | # 速度限制 65 | for j in range(self.dimension): 66 | if self.v[i][j] < self.v_low: 67 | self.v[i][j] = self.v_low 68 | if self.v[i][j] > self.v_high: 69 | self.v[i][j] = self.v_high 70 | 71 | # 更新位置 72 | self.x[i] = self.x[i] + self.v[i] 73 | # 位置限制 74 | for j in range(self.dimension): 75 | if self.x[i][j] < self.bound[0][j]: 76 | self.x[i][j] = self.bound[0][j] 77 | if self.x[i][j] > self.bound[1][j]: 78 | self.x[i][j] = self.bound[1][j] 79 | # 更新p_best和g_best 80 | if self.fitness(self.x[i]) > self.fitness(self.p_best[i]): 81 | self.p_best[i] = self.x[i] 82 | if self.fitness(self.x[i]) > self.fitness(self.g_best): 83 | self.g_best = self.x[i] 84 | #主函数 85 | def pso(self,final_best): #其中final_best是指初始化的值(x) 86 | best = [] 87 | self.final_best = final_best 88 | for gen in range(self.time): 89 | self.update(self.size) 90 | if self.fitness(self.g_best) > self.fitness(self.final_best): 91 | self.final_best = self.g_best.copy() 92 | print('当前最佳位置:{}'.format(self.final_best)) 93 | temp = self.fitness(self.final_best) 94 | print('当前的最佳适应度:{}'.format(temp)) 95 | best.append(temp) 96 | t = [i for i in range(self.time)] 97 | plt.figure() 98 | plt.plot(t, best, color='red', marker='.', ms=15) 99 | plt.rcParams['axes.unicode_minus'] = False 100 | plt.margins(0) 101 | plt.xlabel(u"迭代次数") # X轴标签 102 | plt.ylabel(u"适应度") # Y轴标签 103 | plt.title(u"迭代过程") # 标题 104 | plt.show() 105 | 106 | if __name__ == '__main__': 107 | #注意目前只能求解不带线性约束条件的解,如果想要加入约束条件的话,可以将不符合约束条件的点将其的适应函数(惩罚因子)设置为无穷小 108 | time = 100 109 | size = 100 #初始化粒子的个数 110 | dimension = 5 111 | v_low = -1 112 | v_high = 1 113 | low = [1, 1, 1, 1, 1] 114 | up = [25, 25, 25, 25, 25] 115 | pso = PSO(dimension, time, size, low, up, v_low, v_high) 116 | final_best=np.array([1, 2, 3, 4, 5]) #其是初始最优解的值(x)的参数变量(随便设置,维数要对上) 117 | pso.pso(final_best) 118 | 119 | -------------------------------------------------------------------------------- /code/蒙特卡洛模拟.py: -------------------------------------------------------------------------------- 1 | import random 2 | import numpy as np 3 | 4 | #下面是随机生成一定数量的符合正态分布的数据 5 | def randomtest_num(mu,sigma,num): #mu是均值,sigma是标准差,num是生成的数量 6 | data=[] 7 | for i in range(num): 8 | data.append(random.normalvariate(mu=mu,sigma=sigma)) 9 | return data 10 | 11 | #生成均匀分布的点 12 | def Evenly_distributed(a,b,num): #a是起始位置,b是结束位置,num是生成的个数 13 | data=[] 14 | for i in range(num): 15 | data.append(a+(b-a)*np.random.rand(1)) 16 | return data 17 | 18 | #生成符合二项分布的点 19 | d1=np.random.binomial(n=9,p=0.5,size=100) #n是实验次数,p是概率,size代表生成的个数 20 | 21 | #生成超几何分布的点 22 | #对以下代码可以解释为:共50个产品,正品有47个,次品有3个,每次从这些产品中取3个出来,共重复这样的试验50次。假设返回的是每一次所抽取的三个产品中的正品数,共50个值。 23 | d2=np.random.hypergeometric(47,3,3,size=30) #对上述代码可以解释为:共50个产品,正品有47个,次品有3个,每次从这些产品中取3个出来,共重复这样的试验50次。假设返回的是每一次所抽取的三个产品中的正品数,共50个值。 24 | 25 | -------------------------------------------------------------------------------- /code/贝叶斯网络.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | from pgmpy.models import BayesianModel 5 | from pgmpy.estimators import BayesianEstimator 6 | from pgmpy.factors.discrete import TabularCPD 7 | import copy 8 | from pgmpy.inference import VariableElimination 9 | from collections import Counter 10 | from pgmpy.estimators import K2Score, BicScore 11 | from pgmpy.estimators import HillClimbSearch 12 | import networkx as nx 13 | from sklearn import metrics 14 | import seaborn as sns 15 | 16 | #导入数据 17 | data=pd.read_csv('D:\\2022国赛数模练习题\\2022数模国赛\\支撑材料\\data\\处理后的附件1.csv',encoding='gbk') 18 | 19 | #下面进行数据预处理 20 | data.drop(columns='文物编号',inplace=True) #丢弃无用的数据列 21 | data.rename(columns={'纹饰':'D','类型':'T','颜色':'C','表面风化':'W'},inplace=True) #更换列名 22 | data['C'].fillna(0,inplace=True) #填补颜色列的缺失值 23 | 24 | #下面进行数值化 25 | D_map={'A':0,'B':1,'C':2} 26 | T_map={'高钾':0,'铅钡':1} 27 | C_map={'黑':0,'蓝绿':1,'绿':2,'浅蓝':3,'浅绿':4,'深蓝':5,'深绿':6,'紫':7,0:8} 28 | W_map={'无风化':0,'风化':1} 29 | data['D']=data['D'].map(D_map) 30 | data['T']=data['T'].map(T_map) 31 | data['C']=data['C'].map(C_map) 32 | data['W']=data['W'].map(W_map) 33 | 34 | #下面用测试的一个数据集进行自己赋值的一个先验概率(就是把颜色只变成有0/1的) 35 | test_data=copy.deepcopy(data) 36 | test_data['C']=test_data['C'].apply(lambda x:1 if x!=0 else 0) 37 | 38 | #1下面进行构建贝叶斯网络(第一种是可以自己来进行构建一个) 39 | model1=BayesianModel([('D','W'),('T','W'),('C','W'),('T','C')]) #这里表示W的父节点为D/T/C,C的父节点有一个T 40 | 41 | #2下面进行构建cpd表(每个节点都需要)就是一个条件概率分布表,第一种方式可以根据先验知识进行设置 42 | """cpd_D=TabularCPD(variable='D', variable_card=3,values=[[0.7], #注意要竖着看 43 | [0.2], 44 | [0.1]]) #第一个参数表示节点的名称,第二个参数是节点有几个分类,第三个就是各分类的概率 45 | cpd_T=TabularCPD(variable='T', variable_card=2,values=[[0.6], 46 | [0.4]]) 47 | cpd_C=TabularCPD(variable='C', variable_card=2,values=[[0.8,0.7], #注意要竖着来看,竖着的表示当其父节点(两种选择)分别为0和为1时其取值的各个概率 48 | [0.2,0.3],],evidence=['T'], evidence_card=[2]) #其中evidence表示其父节点,evidence_card表示父节点有几个分类变量 49 | cpd_W=TabularCPD(variable='W', variable_card=2,values=[[0.1,0.4,0.2,0.4,0.5,0.4,0.3,0.2,0.1,0.2,0.3,0.4], 50 | [0.9,0.6,0.8,0.6,0.5,0.6,0.7,0.8,0.9,0.8,0.7,0.6]],evidence=['D','T','C'], evidence_card=[3,2,2]) #注意其有三个父节点也就是说有3*2*2种类型的条件概率 51 | #下面将概率分布添加到模型中 52 | model1.add_cpds(cpd_D, cpd_T, cpd_C, cpd_W)""" 53 | 54 | #第二种方式添加条件概率(利用参数学习的方式)(这时候用原来的C(9个类别的)) 55 | #先统计各个分类变量(节点)的个数,要将其输入到后面参数学习的模型中(注意顺序,要从0开始往后) 56 | """print(Counter(data['D'])) 57 | print(Counter(data['T'])) 58 | print(Counter(data['C'])) 59 | print(Counter(data['W']))""" 60 | #下面进行参数学习 61 | #pseudo_counts={'D':[[22],[6],[28]],'T':[16,40],'C':[2,15,1,18,3,2,7,4,4],'W':[[22],[34]]} 62 | #model1.fit(data,estimator=BayesianEstimator,prior_type='BDeu') #利用贝叶斯估计器,并用equivalent_sample_size=5无差别客观先验,认定各个概率相等,类似先输入先验的刚开始的正则化操作 63 | #model1.fit(data,estimator=BayesianEstimator,prior_type='dirichlet',pseudo_counts=pseudo_counts) #这个是采用狄利克雷分布,目前这个还用不了 64 | model1.fit(data,estimator=BayesianEstimator,prior_type='K2') #当prior_type= ‘K2’ 意为 ‘dirichlet’ + setting every pseudo_count to 1 65 | 66 | #下面可以进行一些检查操作和查看模型参数操作 67 | # 1检查模型的变量 68 | """print(model1.nodes) 69 | # 2检查模型的边缘依赖关系 70 | print(model1.edges) 71 | # 3检查模型的条件概率分布表 72 | for cpd in model1.get_cpds(): #注意要查看某个节点的话就用model.get_cpds('W').values) 73 | print(cpd) #用cpd.values可以输出全部的值(矩阵形式)""" 74 | 75 | #这样贝叶斯网络模型就构建完毕了,下面就可以进行一些推理和预测 76 | #解决的第一个问题,如果知道其父节点的各个状态(或几个状态),如D是0,T是0,C是1,问W各个值的一个概率(用于分类) 77 | model_infer = VariableElimination(model1) 78 | q1 = model_infer.query(variables=['W'], evidence={'D':0,'T':0,'C':1}) #注意不一定要写出所有的父节点变量(影响因子) 79 | q2 = model_infer.query(variables=['C'],evidence={'T':0}) #注意也可以不给父节点,直接设置子节点,得到所有节点的一个概率分布情况 80 | q3 = model_infer.query(variables=['C']) #直接得到C的概率分布情况,依次类推可以得到所有节点的概率分布情况 81 | print(q1.values,'\nq2为',q2.values) 82 | print('q3',q3.values) #注意可以用q3.values得到其条件概率的一个列表 83 | 84 | #2进行最大后验概率问题,比如W为1时,其各个父节点(影响变量)最有可能是什么状态,3最大可能解释问题(MPE)进行因果(概率相关性的判断),比如我想知道当W等于1,其D为1的一种概率,概率越高说明其实两者之间的相关性越高 85 | q4 = model_infer.map_query(variables=['D','T','C'],evidence={'W':1}) 86 | print(q4) 87 | 88 | #下面进行贝叶斯网络的敏感性分析 89 | # 1利用信息熵互信息得到各个自变量与因变量之间的关系程度(研究自变量的变化对因变量的影响) 90 | mutual_list=[] #存储互信息的列表 91 | for column in data.columns[:-1]: 92 | mutual_list.append(metrics.normalized_mutual_info_score(data['W'], data[column])) 93 | 94 | #下面再对互信息进行可视化(绘制一行的热点图) 95 | #先重新构建一个dataframe数据 96 | mutual_dataframe=pd.DataFrame() 97 | for i,column in enumerate(data.columns[:-1]): 98 | mutual_dataframe[column]=[mutual_list[i]] 99 | print(mutual_dataframe) 100 | mutual_dataframe.index=['W'] 101 | 102 | #下面开始绘制 103 | sns.set(font_scale=0.7) 104 | plt.rcParams['font.sans-serif'] = ['SimHei'] 105 | plt.rcParams['axes.unicode_minus'] = False 106 | ax = sns.heatmap(mutual_dataframe.loc[['W'], :], square=True, 107 | cbar_kws={'orientation': 'horizontal', "shrink": 0.8}, 108 | annot=True, annot_kws={"size": 12}, vmax=1.0, cmap='coolwarm') 109 | # 设置标题 110 | ax.set_title('自变量与因变量的互信息',fontsize=13) 111 | # 更改坐标轴标签字体大小 112 | ax.tick_params(labelsize=12) 113 | plt.show() 114 | 115 | #2进行场景分析 (可以将设置某一个参数发生的情况下变量的概率分布与某一个参数不发生的情况下变量的概率分布进行对比) 116 | #也可以理解不设置其他的值,就设当此变量出现或者不出现时,因变量各分类变量的概率分布变化百分比 117 | #构建求解百分比的函数(注意模型是在已经构建完成的情况下,里面模型用的是全局变量) 118 | def percent(column_name,target_name,length): #其中column_name是自变量的标签,target_name是因变量的标签,length是自变量中分类变量的个数 119 | result_perc=[] #存储D中每个分类变量选取与不选取对因变量W的概率分布变化百分比情况(绝对值),形式为[[],[]] 120 | for i in range(length): #D中有3个分类变量 121 | f1= model_infer.query(variables=[target_name]).values #得到原始的分布情况 122 | f2= model_infer.query(variables=[target_name],evidence={column_name:i}).values #得到当自变量某一个分类变量100%发生时,因变量W概率分布情况 123 | result_perc.append(np.abs((f2-f1)/f1).tolist()) #得到变化的百分比(绝对值) 124 | return result_perc #形式为[[],[]] 125 | #下面进行输出结果 126 | D_perc=percent('D','W',3) 127 | T_perc=percent('T','W',2) 128 | C_perc=percent('C','W',2) 129 | 130 | #下面进行整体分类的预测(给自变量) 131 | y_pred=model1.predict(data[['D','T','C']],n_jobs=1) 132 | print((y_pred['W']==data['W']).sum()/len(y_pred)) #计算分类的准确度 133 | 134 | #下面是利用结构学习的方式得到一个更合理的网络(注意上面的网络是自己设计的,这里进行优化) 135 | #第一种方式是利用评价指标的方法(常见的bdeu,k2,bic),注意指标都是越小越好 136 | k2 = K2Score(data) 137 | bic = BicScore(data) 138 | #构建模型 139 | model1=BayesianModel([('D','W'),('T','W'),('C','W'),('T','C')]) 140 | model2=BayesianModel([('D','W'),('T','W'),('C','W')]) 141 | #下面进行输出评价指标的值进行比较模型的优度 142 | print(k2.score(model1),k2.score(model2)) 143 | print(bic.score(model1),bic.score(model2)) 144 | 145 | #第二种方式是用查找的方式(智能查找方法比如爬山算法(贪婪算法的一种)) 146 | hc = HillClimbSearch(data,state_names=BicScore(data)) #利用爬山算法,评价指标用bic指标 147 | best_model = hc.estimate() 148 | best_edges=best_model.edges() #输出最好的贝叶斯网络结构 149 | 150 | #下面用最好的网络进行参数学习并进行预测决策等 151 | best_model=BayesianModel(best_edges) #构建模型 152 | 153 | #进行参数学习 154 | best_model.fit(data,estimator=BayesianEstimator,prior_type='K2') #当prior_type= ‘K2’ 意为 ‘dirichlet’ + setting every pseudo_count to 1 155 | 156 | #进行决策和预测 157 | best_pred=best_model.predict(data[['D','T','C']],n_jobs=1) 158 | print((best_pred['W']==data['W']).sum()/len(best_pred)) #计算分类的准确度,似乎准确度不高 159 | 160 | #下面进行绘制贝叶斯网络结构图(没有带上条件概率的) 161 | pos = nx.spring_layout(best_model) #定义画板 162 | nx.draw_networkx_nodes(best_model, pos, node_size=500,node_color='#2049ff') #绘制各个节点 163 | nx.draw_networkx_edges(best_model, pos, width=2, arrows=True, arrowstyle='->',arrowsize=20,edge_color='#bf0000') #绘制箭头线段 164 | nx.draw_networkx_labels(best_model, pos, font_size=20, font_family='sans-serif') #对节点打上标签 165 | plt.axis('off') 166 | plt.show() -------------------------------------------------------------------------------- /code/高斯过程回归.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | from sklearn.gaussian_process import GaussianProcessRegressor 5 | from sklearn.gaussian_process.kernels import ConstantKernel, RBF,DotProduct,WhiteKernel 6 | from matplotlib import cm 7 | 8 | #导入数据 9 | data=pd.read_csv('D:\\2022国赛数模练习题\\贷款年利率与客户流失率关系.csv',encoding='gbk') 10 | x=data.iloc[:,0].values.reshape(-1,1) #注意要转化成二维的,相当于列向量 11 | y=data.iloc[:,1].values.reshape(-1,1) 12 | 13 | #初始化核函数(其中ContantKernel相当于对均值会进行改变的核函数) 其中constant_value是设置的初始值,后面的bounds是参数调优的范围 14 | kernel=ConstantKernel(constant_value=0.2, constant_value_bounds=(1e-4, 1e4)) *\ 15 | RBF(length_scale=0.5, length_scale_bounds=(1e-4, 1e4)) #这个是径向基内核,第一个参数是缩放系数,更多的核函数可以看文档说明 16 | #定义高斯过程回归模型 17 | gpr = GaussianProcessRegressor(kernel=kernel, n_restarts_optimizer=9) 18 | ##使用参数的最大似然估计来拟合数据 19 | gpr.fit(x,y) 20 | #进行预测数据 21 | x_test=np.linspace(min(x),max(x),1000) #注意这里是二维的数据(-1,1),因为受原始的x的影响,进行取1000个数,后续画函数图像更加平滑 22 | mu,cov=gpr.predict(x_test,return_cov=True) 23 | y_test=mu.ravel() #将均值向量展平 24 | uncertainty = 1.96 * np.sqrt(np.diag(cov)) #计算95%置信区间,用于后续绘图 25 | 26 | #下面进行绘制拟合曲线 27 | # plotting 28 | x_test=x_test.ravel() #注意这里将数据进行展平 29 | plt.figure(figsize=(8,6)) 30 | plt.tick_params(size=5,labelsize = 13) #坐标轴 31 | plt.grid(alpha=0.3) #是否加网格线· 32 | plt.title("l=%.1f sigma_f=%.1f" % (gpr.kernel_.k2.length_scale, gpr.kernel_.k1.constant_value)) 33 | plt.fill_between(x_test, y_test + uncertainty, y_test - uncertainty,alpha=.5, fc='b', ec='None', label='95% confidence interval') 34 | plt.plot(x_test, y_test, label="Gaussian Process Fitting Curve") 35 | plt.scatter(x, y, label="raw data points", c="red", marker="x") 36 | plt.legend() 37 | plt.show() 38 | 39 | #得出回归函数的R方 40 | print(gpr.score(x,y)) 41 | 42 | #下面进行高维数据的拟合(这里采用三维数据) 43 | #首先导入数据 44 | data=pd.DataFrame(pd.read_excel('D:\\国赛数模优秀论文\\2017\\Problems\\B\\附件一:已结束项目任务数据.xls')) 45 | #选择有用的数据 46 | data=data[['任务gps 纬度','任务gps经度','任务标价']] 47 | x=data.iloc[:,:2].values.reshape(-1,2) #自变量是前两维,同时要进行reshape 48 | y=data.iloc[:,-1].values.reshape(-1,1) 49 | 50 | #初始化核函数(注意对于多维数据,核函数需要更新,可以多试试) 51 | kernel=(ConstantKernel(constant_value=0.2, constant_value_bounds=(1e-4, 1e4))+DotProduct()+WhiteKernel())*RBF(length_scale=0.5, length_scale_bounds=(1e-4, 1e4)) 52 | #定义高斯过程回归模型 53 | gpr = GaussianProcessRegressor(kernel=kernel, n_restarts_optimizer=9) 54 | ##使用参数的最大似然估计来拟合数据 55 | gpr.fit(x,y) 56 | print(gpr.score(x,y)) #得出回归方程的R方 57 | x_test=np.linspace(np.min(x,axis=0),np.max(x,axis=0),200) #这里生成二维的200个测试数据,注意不能设置太多,不然处理速度很慢且很卡 58 | mu,cov=gpr.predict(x_test,return_cov=True) 59 | y_test=mu.ravel() #将均值向量展平 60 | uncertainty = 1.96 * np.sqrt(np.diag(cov)) #计算95%置信区间,用于后续绘图 61 | X,Y=np.meshgrid(x_test[:,0],x_test[:,1]) #创建和X和Y的网格矩阵 62 | Z=np.ones((200,200)) #为了将Z轴也网格化,先创建全是1的200*200网格 63 | Z=y_test*Z 64 | 65 | #plt.style.use('') #目前可改变3D图像样式的有ggplot、seaborn、Solarize_Light2、grayscale 66 | plt.rcParams['axes.facecolor'] = '#ffffff' 67 | plt.rcParams['axes.unicode_minus'] = False 68 | fig = plt.figure(figsize=(8,6),facecolor='#ffffff') 69 | ax = fig.gca(projection='3d') 70 | #绘制表面图 71 | #surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm, 72 | # linewidth=0, antialiased=False) 73 | surf = ax.plot_wireframe(X, Y, Z, cmap=cm.coolwarm,rstride=4,cstride=4, 74 | linewidth=0.1, antialiased=False) 75 | #下面是进行三维的三角型拟合得出最终的三维图形 76 | """surf=ax.plot_trisurf(data.iloc[:,0],data.iloc[:,1],z, 77 | cmap=cm.coolwarm, edgecolor='none')""" 78 | #绘制等高线 79 | """cset1 = ax.contourf(X, Y, Z, zdir='z', cmap=cm.coolwarm) 80 | cset2= ax.contourf(X, Y, Z, zdir='x' ,cmap=cm.coolwarm) 81 | cset3 = ax.contourf(X, Y, Z, zdir='y', cmap=cm.coolwarm) 82 | """ 83 | # Add a color bar which maps values to colors.(这里加上颜色条,同时设置其参数) 84 | fig.colorbar(surf, shrink=0.5, aspect=5) 85 | 86 | #下面将散点绘制到图片中去 87 | ax.scatter(data.iloc[:,0],data.iloc[:,1],data.iloc[:,2],marker='o',c=data.iloc[:,2],cmap=cm.coolwarm) 88 | 89 | #打上x、y、z轴的标签和标题 90 | ax.set_xlabel('X Label',fontsize=13) 91 | ax.set_ylabel('Y Label',fontsize=13) 92 | ax.set_zlabel('Z Label',fontsize=13) 93 | ax.set_title('3D Fitted Surface Plot',fontsize=15) 94 | plt.show() 95 | --------------------------------------------------------------------------------