快来看看招商银行理财产品数据(代码及分析)

浏览: 1949

前言


      近段时间经常收到招商银行关于理财相关的短信,看来我已成了招行的目标客户(虽然我还很穷~)。穷归穷,看看还是不花钱的,于是前往招行的理财产品网站看看,嚯!足足上千种理财产品,让我迸发了了解数据的冲动。于是乎,按照分析师的习惯,先从网站抓取数据,然后基于获得的数据作一个探究

数据爬虫


      当你来到对方的理财产品网站,你会发现网页中的数据并没有直接的存储在网页源代码中,因为当我不停的下拉,并点击下一页时,其链接并没有发生变化。OK,那这样看来,数据一定是作了异步存储,接下来找到这个异步存储数据的链接才是最关键的。下面,把寻找目标链接的方法作一一说明:

image.png

按F12键,选择“Network”选项,并点击网页中的下一页

image.png

“XHR”中你会出现一个文件,去点击它

选择“Preview”预览,发现数据

image.png

双击“XHR”中的文件,得到数据链接

image.png

     接下来要做的就是,发现链接中的规律,调整链接中对应的“pageindex”,得到不同页下的数据,具体爬虫代码如下:

# ===== Python3 =====# 导入第三方包

import requests
import re
import time
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab

# 设置请求头
headers = {'Accept':'*/*','Accept-Encoding':'gzip, deflate','Accept-Language':'zh-CN,zh;q=0.9','Connection':'keep-alive','User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36'
         }
# 拼接URL,用于翻页爬虫
url_phase1 = 'http://www.cmbchina.com/cfweb/svrajax/product.ashx?op=search&type=m&pageindex='
url_phase2 = '&salestatus=&baoben=¤cy=&term=&keyword=&series=01&risk=&city=&date=&pagesize=40&orderby=ord1&t=0.8683289736280901'

urls = []for i in range(1,29):
   urls.append(url_phase1+str(i)+url_phase2)

# 构造空列表,用于后面的数据存储
Finacing = []
# 通过for循环完成URL的遍历

for url in urls:
   # 获取源代码
   res = requests.get(url, headers = headers).text
   # 正则表达式完成信息的获取
   ProdCode = re.findall('PrdCode:"(.*?)",',text)
   ProdName = re.findall('PrdName:"(.*?)",',text)
   TypeCode = re.findall('TypeCode:"(.*?)",',text)
   AreaCode = re.findall('AreaCode:"(.*?)",',text)
   BeginDate = re.findall('BeginDate:"(.*?)",',text)
   EndDate = re.findall('EndDate:"(.*?)",',text)
   ExpireDate = re.findall('ExpireDate:"(.*?)",',text)
   Status = re.findall('Status:"(.*?)",',text)
   NetValue = re.findall('NetValue:"(.*?)",',text)
   IsNewFlag = re.findall('IsNewFlag:"(.*?)",',text)
   NetValue = re.findall('NetValue:"(.*?)",',text)
   Term = re.findall('Term:"(.*?)",',text)
   Style = re.findall('Style:"(.*?)",',text)
   InitMoney = re.findall('InitMoney:"(.*?)",',text)
   IncresingMoney = re.findall('IncresingMoney:"(.*?)",',text)
   Risk = re.findall('Risk:"(.*?)",',text)
   FinDate = re.findall('FinDate:"(.*?)",',text)
   SaleChannel = re.findall('SaleChannel:"(.*?)",',text)
   SaleChannelName = re.findall('SaleChannelName:"(.*?)",',text)
   IsCanBuy = re.findall('IsCanBuy:"(.*?)"}',text)
   
   # 数据存储到字典中
   Finacing.append({'ProdCode':ProdCode,'ProdName':ProdName,'TypeCode':TypeCode,'AreaCode':AreaCode,
               'BeginDate':BeginDate,'EndDate':EndDate,'ExpireDate':ExpireDate,'Status':Status,
               'NetValue':NetValue,'IsNewFlag':IsNewFlag,'NetValue':NetValue,'Term':Term,
               'Style':Style,'InitMoney':InitMoney,'IncresingMoney':IncresingMoney,'Risk':Risk,
               'FinDate':FinDate,'SaleChannel':SaleChannel,'SaleChannelName':SaleChannelName,'IsCanBuy':IsCanBuy})    
   
   # 睡眠3秒
   time.sleep(3)
   
# 将数据转换为数据框
CMB_Finance = pd.concat([pd.DataFrame(data) for data in Finacing])    
# 数据导出
CMB_Finance.to_excel('CMB_Finance.xlsx', index = False)

      很快就可以把招商银行网站中的1000多种理财产品全部获取回来。接下来要做的就是数据的探索性分析,了解数据的特征和分布。

探索性分析


      如果你没有完成上面的爬虫也没有关系,本文后面提供了数据集下载的链接,你可以通过读取的方式进行这部分的探索性分析。

  • 数据类型转换

# 读取数据
cmb = pd.read_excel('CMB_Finance.xlsx')
# 查看数据集的行列数
cmb.shape
# 查看数据前几行
cmb.head()
#  查看数据集的数据类型c
mb.dtypes

image.png

从爬下来的数据表来看,除了InitMoney(最低投资额)、IncresingMoney(投资增加额)和TypeCode(产品类型编码)是数值型的,其他都是字符串型。这里,我们是可以把FinDate(期限)和NetValue(收益率)字段转换为数值型的。

# 数据类型转换# 将FinDate(期限)字段转换为数值型
cmb.FinDate = cmb.FinDate.str[:-1].astype('int')
# 将NetValue(收益率)字段转换为数值型
cmb.NetValue = cmb.NetValue.str[:-1].astype('float')/100
  • 收益率最高和最低的3种产品

      对于大部分理财用户来说,都会非常关心理财产品的收益率,虽然都知道高风险高收益,但还是会权衡收益率最高的产品和最低的产品。接下来,我们借助于条形图来展示收益率:

# 预期收益率最高的3个产品
NetValue_sort_desc = cmb[['ProdCode', 'NetValue']].sort_values(by = 'NetValue', ascending=False)
NetValue_duplicate_top = NetValue_sort_desc.drop_duplicates(subset = 'NetValue').head(3)

# 预期收益率最低的3个产品
NetValue_sort_asc = cmb[['ProdCode', 'NetValue']].sort_values(by = 'NetValue', ascending=True)
NetValue_duplicate_last = NetValue_sort_asc.drop_duplicates(subset = 'NetValue').head(3)

# 中文和负号的正常显示
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
# 设置图形的显示风格
plt.style.use('ggplot')

# 为了让多张子图在一张图中完成,设置子图的位置
ax1 = plt.subplot2grid((2,1),(0,0))
ax2 = plt.subplot2grid((2,1),(1,0))

# 绘制条形图
ax1.bar(range(3), NetValue_duplicate_top.NetValue, align = 'center', color = 'steelblue', alpha = 0.7)
# y轴范围
ax1.set_ylim(0.045,0.051)
# x轴刻度标签
ax1.set_xticks(np.arange(3))
ax1.set_xticklabels(NetValue_duplicate_top.ProdCode)
# x轴标签
ax1.set_xlabel('产品编号')
# y轴刻度标签
ax1.set_yticks(np.arange(0.045,0.051,0.001))
ax1.set_yticklabels([str(i*100) + '%' for i in np.arange(0.045,0.051,0.001)])
# y轴标签
ax1.set_ylabel('预期收益率')
# 标题
ax1.set_title('预期收益率最高的5类产品')

ax2.bar(range(3), NetValue_duplicate_last.NetValue,  align = 'center',color = 'steelblue', alpha = 0.7)
ax2.set_ylim(0.045,0.048)
ax2.set_xticks(np.arange(3))
ax2.set_xticklabels(NetValue_duplicate_last.ProdCode)
# x轴标签
ax2.set_xlabel('产品编号')
# y轴刻度标签
ax2.set_yticks(np.arange(0.045,0.048,0.001))    
ax2.set_yticklabels([str(i*100) + '%' for i in np.arange(0.045,0.048,0.001)])
# y轴标签
ax2.set_ylabel('预期收益率')
ax2.set_title('预期收益率最低的5类产品')

# 调整子图之间的高度间距
plt.subplots_adjust(hspace=0.5)
# 去除图形顶部边界和右边界的刻度
plt.tick_params(top='off', right='off')
# 图形显示
plt.show()

image.png

图中显示,最高的收益率可以达到5%,最低的收益率为4.6%(肯定都比存银行的收益率都高吧~)。

  • 理财产品风险类型分布

      从表中我们得知,这1000多种产品分为三种风险类型,分别是谨慎性、稳健性和平稳性,他们之间的比例如何呢?我们通过饼图来呈现这个比例:

# 先对各风险类型的样本量作统计
stats = cmb.Risk.value_counts()
plt.axes(aspect='equal')
# 控制x轴和y轴的范围
plt.xlim(0,4)
plt.ylim(0,4)

explode = [0,0,0.1,]  
colors=['#9999ff','#ff9999','#7777aa'] # 自定义颜色

# 绘制饼图
plt.pie(x = stats.values, # 绘图数据
       explode=explode, # 突出显示谨慎性产品
       labels=stats.index, # 添加教育水平标签
       colors=colors, # 设置饼图的自定义填充色
       autopct='%.1f%%', # 设置百分比的格式,这里保留一位小数
       pctdistance=0.8,  # 设置百分比标签与圆心的距离
       labeldistance = 1.15,
       startangle = 180, # 设置饼图的初始角度
       radius = 1.5, # 设置饼图的半径
       counterclock = False, # 是否逆时针,这里设置为顺时针方向
       wedgeprops = {'linewidth': 1.5, 'edgecolor':'green'},# 设置饼图内外边界的属性值
       textprops = {'fontsize':12, 'color':'k'}, # 设置文本标签的属性值
       center = (1.8,1.8), # 设置饼图的原点
       frame = 1 )# 是否显示饼图的图框,这里设置显示

# 删除x轴和y轴的刻度
plt.xticks(())
plt.yticks(())

# 添加图标题
plt.title('理财产品风险类型分布')
# 显示图形
plt.show()

image.png

上图显示,谨慎性的产品是最少的,只有10%。这个也比较容易理解,毕竟银行也是想从更多的风险投资人那边获得更多的利益,而谨慎性的产品(收益率不会高,并且是浮动收益)应该是用来起吆喝,吸流量的作用(毕竟大部分人还是停留在保值的心理阶段)。

  • 理财产品期限的描述性统计

      接下来我们来了解一下,这些理财产品的期限FinDate,上面已经将该变量转换为数值型了,首先对改变了作一下描述性统计

# 理财产品期限的描述性统计
cmb.FinDate.describe()

image.png

我们发现,这些理财产品的平均期限为半年(180天),而且四分之三的产品也是在180天以内。我想这应该是招商银行做过统计,例如,什么样的理财产品好卖,这些产品在消费者手中的持有时间都是多少天等。同时,我们也可以针对这个期限作一个直方图,来看看时间上的分布特征:

# 理财产品期限的直方图
plt.hist(cmb.FinDate, # 绘图数据
       bins = np.arange(cmb.FinDate.min(),cmb.FinDate.max(),30), # 指定直方图的组距
       normed = True, # 设置为频率直方图
       color = 'steelblue', # 指定填充色
       edgecolor = 'k') # 指定直方图的边界色

# 设置坐标轴标签和标题
plt.title('理财产品期限直方图')
plt.xlabel('期限(天数)')
plt.ylabel('频率')

# 生成正态曲线的数据
x1 = np.linspace(cmb.FinDate.min(), cmb.FinDate.max(), 1000)
normal = mlab.normpdf(x1, cmb.FinDate.mean(), cmb.FinDate.std())
# 绘制正态分布曲线
line1, = plt.plot(x1,normal,'', linewidth = 2)

# 生成核密度曲线的数据
kde = mlab.GaussianKDE(cmb.FinDate)
x2 = np.linspace(cmb.FinDate.min(), cmb.FinDate.max(), 1000)
# 绘制
line2, = plt.plot(x2,kde(x2),'', linewidth = 2)

# 去除图形顶部边界和右边界的刻度
plt.tick_params(top='off', right='off')
# 显示图例
plt.legend([line1, line2],['正态分布曲线','核密度曲线'],loc='best')
# 显示图形
plt.show()

image.png

不错所料,期限呈现严重的右偏特征,这也是绝大多数经济活动的共性,如消费频次越多的人肯定越少;花费金额越多的人也肯定越少。

  • 基于风险类型的期限分布

      我们可以进一步细化,看看不同类型风险的产品,是不是产品期限存在明显的差异,这里我们就借助于箱线图做一个比较:

# 如果将其划分到不同的Risk(风险类型)中,期限的分布是否存在差异
FinDate = []
Risks = cmb.Risk.unique()
Risks.sort()

for Risk in Risks:
   FinDate.append(cmb.loc[cmb.Risk==Risk,'FinDate'])

# 绘图
plt.boxplot(x = FinDate,
           patch_artist=True,
           labels = Risks, # 添加具体的标签名称
           showmeans=True,
           boxprops = {'color':'black','facecolor':'#9999ff'},
           flierprops = {'marker':'o','markerfacecolor':'red','color':'black'},
           meanprops = {'marker':'D','markerfacecolor':'indianred'},
           medianprops = {'linestyle':'--','color':'orange'})

# 设置坐标轴标签和标题
plt.title('不同风险类型下的产品期限差异盒形图图')
plt.xlabel('风险类型')
plt.ylabel('期限')

# 去除图形顶部边界和右边界的刻度
plt.tick_params(top='off', right='off')
# 显示图形
plt.show()

image.png

图中显示,不同风险类型的理财产品确实在期限上存在差异,对于平衡性的产品,平均期限在500天左右,而稳健性和谨慎性的平均期限只有110天和170天。

结语


      OK,今天关于数据爬虫和数据的探索性分析就分享到这里,希望感兴趣的朋友能够照着做一遍,相信对你一定有帮助。如果你有任何问题,欢迎在公众号的留言区域表达你的疑问。同时,也欢迎各位朋友继续转发与分享文中的内容,让更多的人学习和进步。

关注“每天进步一点点2015”,与小编同进步!

  • 文内代码及数据

链接: https://pan.baidu.com/s/1mi1hUtE 密码: ya9v


推荐 0
本文由 每天进步一点点2015 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

0 个评论

要回复文章请先登录注册