1. 场景描述
一直做java,因项目原因,需要封装一些经典的算法到平台上去,就一边学习python,一边网上寻找经典算法代码,今天介绍下经典的K-means聚类算法,算法原理就不介绍了,只从代码层面进行介绍,包含:rest接口、连接mpp数据库、回传json数据、下载图片及数据。
2. 解决方案
2.1 项目套路
(1)python经典算法是单独的服务器部署,提供rest接口出来,供java平台调用,交互的方式是http+json;
(3)返回的数据包括三个:1是生成聚类图片的地址;2是聚类项目完整数据地址;3是返回给前端的200条json预览数据。
2.2 restapi类
分两个类,第一个是restapi类,封装rest接口类,其他的经典算法在这里都有对应的方法,是个公共类。
完整代码:
# -*- coding: utf-8 -*- from flask import Flask,request,send_from_directory from k_means import exec import logging app = Flask(__name__) #1.服务器上更改为服务器地址,用于存放数据 dirpath = 'E:\\ruanjianlaowang' #2. 测试连通性,软件老王 @app.route('/') def index(): return "Hello,World!" #3. k-means算法 软件老王 @app.route('/getKmeansInfoByLaowang',methods=['POST']) def getKmeansInfoByLaowang(): try: result = exec(request.get_json(),dirpath) except IndexError as e: logging.error(str(e)) return 'exception:' + str(e) except KeyError as e: logging.error(str(e)) return 'exception:' + str(e) except ValueError as e: logging.error(str(e)) return 'exception:' + str(e) except Exception as e: logging.error(str(e)) return 'exception:' + str(e) else: return result #4.文件下载(图片及csv) @app.route("/<path:filename>") def getimages(filename): return send_from_directory(dirpath,filename,as_attachment=True) #5.启动 if __name__ == '__main__': app.run(host="0.0.0.0",port=5000,debug=True)
代码说明:
使用的是第三方的flask提供的rest服务
(1)服务器上更改为服务器地址,用于存放数据
(2)测试连通性,软件老王
(3)k-means算法 软件老王
(5)启动
2.3 k-means算法类
完整代码:
import pandas as pd import dbgp as dbgp from pandas.io import json from numpy import * import matplotlib.pyplot as plt import numpy as np plt.switch_backend('agg') import logging # 执行 软件老王 def exec(params,dirpath): #1.获取参数,软件老王 sql = params.get("sql") xlines = params.get("xlines") ylines = params.get("ylines") xlinesname = params.get("xlinesname") ylinesname = params.get("ylinesname") grouplinesname = params.get("grouplinesname") times = int(params.get("times")) groupnum = int(params.get("groupnum")) url = params.get("url") name = params.get("name") #2. 校验是否为空,软件老王 flag = checkparam(sql,xlines,ylines,times,groupnum) if not flag is None and len(flag) != 0: return flag #3. 从数据库获取数据,软件老王 try: data = dbgp.queryGp(sql) except IndexError: return sql except KeyError: return sql except ValueError: return sql except Exception: return sql if data.empty: return "exception:此数据集无数据,请确认后重试" #4 调用第三方sklearn的KMeans聚类算法,软件老王 # data_zs = 1.0 * (data - data.mean()) / data.std() 数据标准化,不需要标准话 from sklearn.cluster import KMeans model = KMeans(n_clusters=groupnum,n_jobs=4,max_iter=times) model.fit(data) # 开始聚类 return export(model,data,url,dirpath,name,grouplinesname,xlinesname,ylinesname) # 5.生成导出excel 软件老王 def export(model,data_zs,ylinesname): # #详细输出原始数据及其类别 detail_data = pd.DataFrame().append(data) if not grouplinesname is None and len(grouplinesname) != 0: detail_data.columns = grouplinesname.split(',') r_detail_new = pd.concat([detail_data,pd.Series(model.labels_,index=detail_data.index)],axis=1) # 详细输出每个样本对应的类别 r_detail_new.columns = list(detail_data.columns) + [u'聚类类别'] # 重命名表头 outputfile = dirpath + name + '.csv' r_detail_new.to_csv(outputfile,encoding='utf_8_sig') # 保存结果 #重命名表头 r1 = pd.Series(model.labels_).value_counts() # 统计各个类别的数目 r2 = pd.DataFrame(model.cluster_centers_) # 找出聚类中心 r = pd.concat([r2,r1],axis=1) # 横向连接(0是纵向),得到聚类中心对应的类别下的数目 r.columns = list(data.columns) + [u'类别数目'] # 重命名表头 return generateimage(r,model,ylinesname) #6.生成图片及返回json,软件老王 def generateimage(r,ylinesname): image = dirpath + name + '.jpg' #6.1 中文处理,软件老王 plt.rcParams['font.sans-serif'] = ['simhei'] plt.rcParams['font.family'] = 'sans-serif' plt.rcParams['axes.unicode_minus'] = False # 6.2 画图,生成图片,软件老王 labels = model.labels_ centers = model.cluster_centers_ data_zs['label'] = labels data_zs['label'] = data_zs['label'].astype(np.int) # 图标集合 markers = ['o','s','+','x','^','v','<','>'] colors = ['b','c','g','k','m','r','y'] symbols = [] for m in markers: for c in colors: symbols.append((m,c)) # 画每个类别的散点及质心 for i in range(0,len(centers)): df_i = data_zs.loc[data_zs['label'] == i] symbol = symbols[i] center = centers[i] x = df_i[xlines].values.tolist() y = df_i[ylines].values.tolist() plt.scatter(x,y,marker=symbol[0],color=symbol[1],s=10) plt.scatter(center[0],center[1],marker='*',s=50) plt.title(name) plt.xlabel(xlinesname) plt.ylabel(ylinesname) plt.savefig(image,dpi=150) plt.clf() plt.close(0) # 6.3 返回json数据给前端展示,软件老王 result = {} result['image_url'] = url + '/' + name + '.jpg' result['details_url'] = url + '/' + name + '.csv' result['data'] = r[:200] #显示200,多的话,相当于预览 result = json.dumps(result,ensure_ascii=False) result = result.replace('\\','') return result def checkparam(sql,groupnum): if sql is None or sql.strip() == '' or len(sql.strip()) == 0: return "数据集或聚类数据列,不能为空" if xlines is None or xlines.strip() == '' or len(xlines.strip()) == 0: return "X轴,不能为空" if ylines is None or ylines.strip() == '' or len(ylines.strip()) == 0: return "Y轴,不能为空" if times is None or times <= 0: return "聚类个数,不能为空或小于等于0" if groupnum is None or groupnum <= 0: return "迭代次数,不能为空或小于等于0"
代码说明:
(1)获取参数,软件老王;
(2)校验是否为空,软件老王;
(4)第三方sklearn的KMeans聚类算法,软件老王;
(5)生成导出excel 软件老王
? (6.1) 中文处理,软件老王
? (6.3) 返回json数据给前端展示,软件老王
2.4 执行效果
2.4.1 json返回
{"image_url":"http://10.192.168.1:5000/ruanjianlaowang_65652.jpg","details_url":"http://10.192.168.1:5000/ruanjianlaowang_65652.csv","data":{"empno":{"0":7747.2,"1":7699.625,"2":7839.0},"mgr":{"0":7729.8,"1":7745.25,"2":7566.0},"sal":{"0":2855.0,"1":1218.75,"2":5000.0},"comm":{"0":29.5110766,"1":117.383964625,"2":31.281453},"deptno":{"0":20.0,"1":25.0,"2":10.0},"类别数目":{"0":5,"1":8,"2":1}}}
2.4.2 返回图片
2.4.3 返回的数据
另外说明: 目前项目环境上用的是8核16G的虚拟机,执行数据量是30万,运行状况良好。
I’m 「软件老王」,如果觉得还可以的话,关注下呗,后续更新秒知!欢迎讨论区、同名公众号留言交流!