原创声明:未经作者允许,
个人公众号
题目来源:_51数学建模_B题 (暂时只更到问题1)
该题是个组合优化问题。老规矩,先上一张问题1的结果图。
图1 各公司间资产配置策略的相似性
1. 问题1解析
附件1给出了各公司购买的股票信息:持股总市值和持股总量。由两个数据我们可以计算出每种股票的单价。问题1要求10家公司之间的资产配置策略的相似性,这个相似性就是公司购买了哪种哪种股票,每种股票购买了多少。公司购买了多少某种股票,这就是附件1中的持股总量。那么,公司购买了哪种哪种股票,这该怎么判断呢?
我们的思路是根据股票的单价,把所有股票划分为不同类型。在划分前,我们先利用箱图看下所有股票的单价分布情况,如图2所示。
图2 股票价格分布从图2左图可以看出,有些公司的箱图确实很相似,如公司H、I、J。从图2右图可以看出 ,异常值(小圆圈)可以分为2类,分别为200-600之间、1200。我们把单价为1200的股票作为1类,而我们把200-600的下限改为150,这是因为左图中大部分公式的上边界在150附近。左图中的大部分公司的下四分位点在80附近,所以我们把(80,150)作为一类。(0,80)采取了等分,间隔为20,因为这部分数据较为集中。综上,股票的价格大体上可以分为(0,80)、(80,150),(150,600),(600,1200)。当然,以上区间可以自己定义,上述只做参考,定义的标准就是异常值、四分位数、中数等。
下面是图2的实现代码。
# -*- coding: utf-8 -*-import pandas as pdimport matplotlib.pyplot as pltfrom collections import Counterimport numpy as npfrom scipy.spatial.distance import pdistimport seaborn as snsfile_path = r'G:\数学建模\题目及原数据\五一数学建模\\_51MCM_B题\附件1.xlsx'data = pd.read_excel(file_path)data['股价'] = data['持股总市值(万元)'] / data['持股总量(万股)']dic = dict()for company_name in Counter(data['公司名称']).keys():lst = data[data['公司名称'] == company_name]['股价'].tolist()dic[company_name[-1]] = lstdf = pd.DataFrame(dic)plt.subplot(121)df.boxplot()plt.rcParams['font.sans-serif'] = ['SimHei']plt.rcParams['axes.unicode_minus'] = Falseplt.grid(linestyle="--", alpha=0.3)plt.title('各公司购买股票类型分析')plt.ylabel('股价(单位:元)')stock_name_lst = []for stock_name in Counter(data['股票名称']).keys():stock_name_lst.append(data[data['股票名称'] == stock_name]['股价'].mean())plt.subplot(122)plt.boxplot(stock_name_lst)plt.grid(linestyle="--", alpha=0.3)plt.ylabel('股价(单位:元)')plt.title('股票单价分布')# plt.show()plt.savefig(r'C:\Users\Desktop\tt.png')
根据上述分析,我们把股票根据单价划分为以下几种:X≤20X\leq20X≤20、20<X≤4020\lt X \leq4020<X≤40、40<X≤6040\lt X \leq6040<X≤60、60<X≤8060\lt X \leq8060<X≤80、80<X≤15080\lt X \leq15080<X≤150、150<X≤600150\lt X \leq600150<X≤600、600<X600\lt X600<X。我们利用余弦相似性来计算公司之间的资产配置策略的相似度。我们定义一个向量,大小为7。每一位表示一种股票,每一位的值表示购买该种股票的数量,如:v=[1,2,3,4,5,6.7]v=[1,2,3,4,5,6.7]v=[1,2,3,4,5,6.7],他表示第一种股票购买的数量为1,第二种股票购买的数量为2,依次类推。最后,我们用热力图来呈现结果,如图1所示。
该部分的实现代码如下。
# -*- coding: utf-8 -*-import pandas as pdimport matplotlib.pyplot as pltfrom collections import Counterimport numpy as npfrom scipy.spatial.distance import pdistimport seaborn as snsfile_path = r'G:\数学建模\题目及原数据\五一数学建模\\_51MCM_B题\附件1.xlsx'data = pd.read_excel(file_path)data['股价'] = data['持股总市值(万元)'] / data['持股总量(万股)']price_lst = [20, 40, 60, 80, 150, 600]asset_allocation_dic = dict()for company_name in Counter(data['公司名称']).keys():info_lst = [0] * 7 # 资产配置信息df_tmp = data[data['公司名称'] == company_name]for i in range(len(info_lst)):if i == 0:info_lst[i] = df_tmp[df_tmp['股价'] <= 20]['持股总量(万股)'].sum()elif i == 1:info_lst[i] = df_tmp[(df_tmp['股价'] > price_lst[i - 1]) & (df_tmp['股价'] <= price_lst[i])]['持股总量(万股)'].sum()elif i == 6:info_lst[i] = df_tmp[df_tmp['股价'] > 600]['持股总量(万股)'].sum()asset_allocation_dic[company_name] = info_lst# 计算相似性similarity_arr = np.zeros((10, 10))company_name_lst = list(Counter(data['公司名称']).keys())print(company_name_lst)for i in range(10):for j in range(10):v1 = asset_allocation_dic[company_name_lst[i]]v2 = asset_allocation_dic[company_name_lst[j]]similarity_arr[i][j] = 1 - pdist(np.vstack([v1, v2]), 'cosine')# 画图plt.figure()plt.rcParams['font.sans-serif'] = ['SimHei']plt.rcParams['axes.unicode_minus'] = Falseax = sns.heatmap(similarity_arr, cmap='Reds')plt.title('10家基金公司之间资产配置策略的相似性', size=16)plt.xlabel('公司名称')plt.ylabel('公司名称')# plt.show()plt.savefig(r'C:\Users\10102\Desktop\tt.png')