基于地方政府债券发行公开数据做聚类分析sklearn

sklearn做地方政府债务数据聚类分析


聚类这种无监督学习,我希望的落地方式是:有一组数据,通过聚类能够发现这些数据之间内在关系,从而将这些数据聚类、分类,找出每个类的业务价值,从而为业务人员提供新的分析思路。
目标是能够让不了解机器学习的用户,应用聚类算法,得到聚类结果并可视化,供其进一步分析。
我也是刚接触sklearn机器学习库,结合我的业务目标,写了一些简单的代码,在这里记录我的学习过程
我从网上收集了中国政府近几年的地方政府债券发行数据,经济运行数据。希望通过对这些数据进行聚类,分析出各省债务聚类情况,例如发达省份的债务风险应该较低,欠发达且发债较多的省份风险较高等,希望聚类能带来与预期一致的结果
数据如下:
在这里插入图片描述
基于以上数据我进行了简单的聚类分析,我理解,处理过程主要分为几个阶段:
1 数据预处理
2 聚类
3 评价模型
4 结果可视化

这几个阶段,我觉得最复杂的是数据预处理。后三个都一旦调试没有问题基本就固定了,但是数据的调试我耗了很长时间。主要包括几块:
1 数据的选择
开始,我把所有数据直接进行聚类,但效果并不好,因为数据包含了国民生产总值,银行存款等要素,这些数据体量太大,把债务的要素冲淡了。所以我进行了选择,把一些要素去掉,或者把一些要素扩大几倍或缩小几倍,效果虽然有所提高,但是依然没有达到我的预期,这里我主要是测试了一些numpy array的删、改等方法
2 因子分析
通过拍脑袋处理数据,效果并不好,我想看看Python有没有什么好的办法,于是了解了因子分析,学习了一些公因子方差和成分矩阵的概念,了解各因子的权重关系。但只是做了一些代码实现,似乎也没什么头绪
3 标准化、归一化处理
由于数据体量相差较大,也可以用标准化和归一化的方式进行处理,但我做了代码实现后,聚类的评价结果反而比不做标准化低,这也说明了标准化并不一定提升数据分析的效果
4 按业务进行数据筛选
最终我进行了一些业务上的干预处理,也就是将带入聚类的数据应用的业务上的理解。即各省的当期借债数据/各省的GDP作为一个指标,各省的还本金额/各省的当年财政收入作为一个指标。如果拿我们个人来解释就是说,我们个人总债务/个人总资产以及当年个人借债/当年个人收入。这两个指标进行聚类,最终结果效果较好。
但是,这也一定程度没有达到不做任何干预,即可得到分析结果的预期。所以做数据挖掘,还是要更多的应用业务知识。
5 one-hot处理
在我的数据中,并没有标签类的数据,如高、中、低等。实际数据中很多都是有这种情况的,而且标签还有很多,我觉得一种方式是,简单说就是分别计算高、中、低都对应多少钱,拆出3列新的指标值
还一种就是独热处理,我也简单学习了一下,不做详述了,但这种处理,如果标签值过多,会导致指标的维数极大,还需要降维处理,这块我还没有去实践

数据预处理完,就进行聚类。sklearn的聚类很简单,我试了k-Means和DBSCAN,但DBSCAN效果并不好,这个跟数据关系很大。我的代码里没有进行聚类的模型保存、读取和预测,因为聚类更多的是分析,后续分类才需要预测,这是我的理解。

聚类后对聚类结果的评价,主要是轮廓系数、CH score 、DBI。这些标准实际我也不太理解,但前2个是越高越好,第三个是越小越好。

最后是结果的图表可视化,这里也是找例子照猫画虎,感觉写的也比较烂。聚类的结果见下图:
在这里插入图片描述
分了五类,第一类为青海、贵州,借债占自己资产比重较大,可能存在债务风险比较高;第二类为,辽宁、黑龙江等省,风险次之;第三类的山东省,是一个新的发现,山东一直是GDP大省,但与宁夏、云南等同类,山东确实借债较多,导致它的风险与宁夏,云南在一个等级上;而最后一个类,广东、北京、深圳等都是发达省,所以风险最低,也比较合理,而西藏与它们一个类别,是因为西藏借债很少。
通过聚类分析,看清了一些地方政府债务分类情况,尤其是山东,分析前以为是与广东,北京等同类,但是山东的风险也较高,这是一个数据挖掘的点。
当然我还是初学者,无论在地方政府债业务知识,还是数据挖掘知识,都了解的很浅,这些结果并不能作为参考,可能与实际也相差一定程度。但是,作为学习机器学习的过程,我还是有一定收获的。
下面是我的源码:

# -*- coding: utf-8 -*-
"""
Created on Fri Jul 26 14:08:32 2019

@author: jiyongjie
"""

from sklearn.cluster import KMeans
from sklearn.externals import joblib
import numpy as np
import pandas as pd
from sklearn import preprocessing
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import DBSCAN
from sklearn import metrics
#from factor_analyzer import FactorAnalyzer
'''
数据预处理
'''
df2 = pd.read_csv('e:/c.csv',header=0)  #数据加载
df=np.array(df2.iloc[:,1:])


#因子分析
#fa = FactorAnalyzer(rotation=None)
#fa.fit(df)
#print("公因子方差:\n", fa.get_communalities())#公因子方差
#print("\n成分矩阵:\n", fa.loadings_)#成分矩阵

# 权重处理 删除不需要的列,或者将一些列的值增大,减小
#最终按业务进行处理,并去掉其他的要素
df[:,0:1] = df[:,1:2]/df[:,5:6]
df[:,1:2] = (df[:,3:4]+df[:,4:5])*2/df[:,11:12]
df=np.delete(df, [2,3,4,5,6,7,8,9,10,11], axis=1)
print (df)
#df=np.delete(df, [3,4,6,9], axis=1)
#df[:,0:4] = df[:,0:4]*10
#df[:,9:2] = df[:,9:2]/20df

#标准化 归一化处理
#min_max_scaler = preprocessing.MinMaxScaler()
#df=min_max_scaler.fit_transform(df)
#df= preprocessing.scale(df)


'''
聚类
'''
clf = KMeans(n_clusters=5)
s = clf.fit(df)

#clf=DBSCAN(eps =10, min_samples = 15)
#s=clf.fit(X_scaled)
#print(s.labels_)
'''
评价聚类效果
'''
s1=metrics.silhouette_score(df, s.labels_, metric='euclidean') # 计算轮廓系数 聚类结果的轮廓系数的取值在【-1,1】之间,值越大,说明同类样本相距约近
s2=metrics.calinski_harabaz_score(df,s.labels_) # 计算CH score 分数越高 类别内部数据的协方差越小越好,类别之间的协方差越大越好
s3=metrics.davies_bouldin_score(df,s.labels_)    # 计算 戴维森堡丁指数DBI DBI的值最小是0,值越小,代表聚类效果越好
print (s1)
print (s2)
print (s3)

'''
聚类图表化
'''
a=np.array(clf.labels_)
z=np.column_stack((df,a))
import matplotlib.pyplot as plt
from sklearn.manifold import TSNE
iris_embedded = TSNE(n_components=2).fit_transform(df)
pos = pd.DataFrame(iris_embedded, columns=['X','Y'])
pos['N'] = a
x=pos['X']
y=pos['Y']
plt.figure(figsize=(10, 10))
#
#ax = pos[pos['G']==0].plot(kind='scatter', x='X', y='Y', color='blue', label='0')
#pos[pos['G']==1].plot(kind='scatter', x='X', y='Y', color='green', label='1', ax=ax)
#pos[pos['G']==2].plot(kind='scatter', x='X', y='Y', color='red', label='2', ax=ax)
txt=df2.ix[:,0]
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.scatter(x, y)
for i in range(len(x)):
    if pos['N'][i]==0:
        plt.annotate(txt[i], xy = (x[i], y[i]), xytext = (x[i]+0.1, y[i]+0.1),color='blue') # 这里xy是需要标记的坐标,xytext是对应的标签坐标
    if pos['N'][i]==1:
        plt.annotate(txt[i], xy = (x[i], y[i]), xytext = (x[i]+0.1, y[i]+0.1),color='green')
    if pos['N'][i]==2:
        plt.annotate(txt[i], xy = (x[i], y[i]), xytext = (x[i]+0.1, y[i]+0.1),color='red')
    if pos['N'][i]==3:
        plt.annotate(txt[i], xy = (x[i], y[i]), xytext = (x[i]+0.1, y[i]+0.1),color='orange')
    if pos['N'][i]==4:
        plt.annotate(txt[i], xy = (x[i], y[i]), xytext = (x[i]+0.1, y[i]+0.1),color='grey')

plt.savefig("e:/1.jpg")
plt.show()


数据文件与代码资源已上传csdn:数据文件与源代码

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值