最近收到团队想看看用聚类方法划分理财客户种类的需求,简单做了个demo。
- 特征提取
从收益、交易、持仓行为3个角度搜集了一些客户特征。观察了一下几个特征的分布,基本处于集中、偏度大的状态。在做去极值处理后,情况有所改善。
ret_sel = ['证件号','时间加权收益率(年化)', '资金加权收益率年化', '最近一年收益时间加权收益率', '最近一年资金加权收益率']
trd_sel = ['证件号','首次买入日期', '最后买入日期']
oid_sel = ['证件号','持仓金额', '历史最大持仓金额','持仓集中度', '持仓天数']
- 特征加工
'首次买入日期', '最后买入日期'两个特征数据格式为时间戳,通过两个日期同当前时间的间隔天数,转化为数字标签。
merge_df['最后买入日期'] =merge_df['最后买入日期'].apply(lambda x:datetime.strptime(str(x),"%Y%m%d"))
merge_df['首次买入日期'] =merge_df['首次买入日期'].apply(lambda x:datetime.strptime(str(x),"%Y%m%d"))
merge_df['首次-最后买入间隔'] = (merge_df['最后买入日期']-merge_df['首次买入日期']).apply(lambda x:x.days)
merge_df['当前时间']=datetime.today()
merge_df['距离最后买入日天数'] = (merge_df['当前时间']-merge_df['最后买入日期']).apply(lambda x:x.days)
merge_df['距离首次买入日天数'] = (merge_df['当前时间']-merge_df['首次买入日期']).apply(lambda x:x.days)
从特征相关性来看,收益特征处于高相关状态,只选取其中一个特征即可,其余相关度尚可,暂做保留。
plt.figure(figsize=(19,9))
sns.heatmap(merge_df.corr(),annot=True,cmap='viridis',vmin=-1,vmax=1)
- 建模分析
尝试使用K-Mean做聚类分析处理,在输入模型前需要做一步去量纲处理。
scaler = StandardScaler()
scaled_df = scaler.fit_transform(merge_df)
scaled_df = pd.DataFrame(merge_df,columns=merge_df.columns)
首先看下基础模型的效果,轮廓值达到83.44%
base_kmeans = KMeans(random_state=101)
base_kmeans.fit(temp)
labels = set(base_kmeans.labels_)
print("Silhouette Score:",str(np.round(silhouette_score(temp,base_kmeans.labels_)*100,2)) + '%')
遍历搜索簇值寻找优化参数,根据最小误差选择簇值。
for i in range(4,14):
for init in ['k-means++','random']:
for algo in ['auto','elkan']:
kmeans = KMeans(n_clusters=i,init=init,algorithm=algo,random_state=101)
kmeans.fit(temp)
print("Number of Clusters: {}".format(i))
print("Initialization Algorithm: {}".format(init))
print("Algorithm: {}".format(algo))
print("Sum of Squared Distance: %d" % kmeans.inertia_)
print('-----------------')
del kmeans
- 分组结果
最后看下分类效果,模型将客户群体分为8组,从持仓天数和持仓金额两个维度来看,分组较为集中,其中第0组占据了大部分比例,推测和所用特征的分布较为集中相关。后期优化还是得从特征提取步骤再做精细化处理,也可进一步尝试DBSCAN等模型,提升聚类效果。
plt.figure(figsize=(19,9))
sns.scatterplot(data=temp,x='持仓天数',y='持仓金额',hue=base_kmeans.labels_,s=300,alpha=0.6,palette='summer')