本文共 4049 字,大约阅读时间需要 13 分钟。
证券投资书中对K线分了12种,对于输入的股票开盘,收盘,最高,最低好像不太适合完全套用,毕竟不是机器说了算,也是人为分的,总觉得不靠谱(一个屌丝程序员中的毒^_^)。所以还是想要让机器自己判断。之前一直用scikit-learn直接实现,最近一个前端的朋友也想研究,就用javascript帮忙写了一下,算是记录一下心得吧。首先介绍一下K均值聚类算法的原理吧。摘要一下百度百科:K均值聚类算法是先随机选取K个对象作为初始的聚类中心。然后计算每个对象与各个种子聚类中心之间的距离,把每个对象分配给距离它最近的聚类中心。聚类中心以及分配给它们的对象就代表一个聚类。一旦全部对象都被分配了,每个聚类的聚类中心会根据聚类中现有的对象被重新计算。这个过程将不断重复直到满足某个终止条件。终止条件可以是没有(或最小数目)对象被重新分配给不同的聚类,没有(或最小数目)聚类中心再发生变化,误差平方和局部最小。按照百度百科的描述,很容易整理出流程: 创建K个点作为初始中心; 判断是否满足分类结果 遍历数据集中每个数据点 { 计算数据点到每个中心的距离; 分配数据点到最近中心所定义的簇 } 计算每个簇中所有点的均值并使其作为该簇新的中心 满足分类结果输出结果
最重要的是计算两个点的距离,这里直接使用欧式距离作为距离函数,实现代码:
function distEclud(vecA,vecB){ var sum = 0; for(var i = 0;i < vecA.length;i++){ var deta = vecA[i] - vecB[i]; sum = sum + deta * deta; } return Math.sqrt(sum);}
其次就是随机产生K个初始中心:
function randCent(dataSet,k){ //var n = dataSet[0].length; //var minJ = $M.min(dataSet,1); //var rangeJ = $V.sub($M.max(dataSet,1),minJ); var centroids = [] for(var i = 0;i < k;i++){ //centroids.push($V.add(minJ,$V.mul(rangeJ,$V.rand(n)))); centroids.push(dataSet[i]); } return centroids;}
上面非注释代码是将数据集的K个数据点作为中心数据,也可以采用注释的代码,注释代码产生K个随机数据点,$M.min函数计算矩阵(二维数组)列最小值,$M.max计算最大值,$V.add,$V.mul分别计算数组的加与乘,$V.rand生成n维随机数组。
接下来就是对数据集进行聚类,实现代码如下:
function kMeans(dataSet,k){ var m = dataSet.length; var clusterAssment0 = []; var clusterAssment1 = []; for(var i = 0;i < m;i++){ clusterAssment0.push(0); clusterAssment1.push(1); } var centroids = randCent(dataSet,k); var clusterChanged = true; while(clusterChanged){ clusterChanged = false; for(var i = 0;i < m;i++){ var minDist = 10000000;minIndex = -1; for(var j = 0;j < k;j++){ var distJI = distEclud(centroids[j],dataSet[i]); if(distJI < minDist){ minDist = distJI; minIndex = j; } } if(clusterAssment0[i] != minIndex){ clusterChanged = true; } clusterAssment0[i] = minIndex; clusterAssment1[i] = minDist * minDist; } for(var i = 0;i < k;i++){ var ptsInClust = $M.subm(dataSet,$V.where(clusterAssment0,"==",i),0); if(ptsInClust.length == 0){ continue; } centroids[i] = $M.mean(ptsInClust,1); } } return { centroids:centroids, cluster:clusterAssment0 };}
结果返回聚类中心与聚类结果。
以上K均值聚类的代码已经实现。接下来就是使用K均值聚类算法应用到股票数据,股票数据我们使用腾讯数据,我们采用2017年浦发银行的日K作为数据集合,代码:<script src = "http://data.gtimg.cn/flashdata/hushen/daily/17/sh600000.js"></script>
对数据的解析代码如下: var ev_data = daily_data_17.split("\n");var open = [];var high = [], low = [],close = [],volume = [],date = [];bar = [];for(var i = 1;i < ev_data.length - 1;i++){ var es = ev_data[i].split(" "); date.push(es[0]); open.push(es[1]); close.push(es[2]); high.push(es[3]); low.push(es[4]); volume.push(es[5]); bar.push([es[1],es[2],es[4],es[3],es[5]]);}
为了计算K线的形态,股价的大小不能作为特征值的大小,开盘、收盘等之间存在关联,所以我们要对各个数据进行整理,下面是我对数据处理的方式:
var data = [];for(var i = 1;i < close.length;i++){ var mean = (parseFloat(close[i]) + parseFloat(open[i]) + parseFloat(high[i]) + parseFloat(low[i]))/4; var tmp = [((parseFloat(high[i]) - mean) == 0)?1:(parseFloat(close[i]) - mean)/(parseFloat(high[i]) - mean), ((parseFloat(high[i]) - mean) == 0)?1:(parseFloat(low[i]) - mean)/(parseFloat(high[i]) - mean), ((parseFloat(high[i]) - mean) == 0)?1:(parseFloat(open[i]) - mean)/(parseFloat(high[i]) - mean), (volume[i] - volume[i - 1])/volume[i - 1] ] data.push(tmp);}var max = $M.max(data,1);var min = $M.min(data,1);var tz = $M.div_vector($M.sub_vector(data,min,1),$V.sub(max,min),1);
将tz作为数据集输入K均值聚类模型,并画出K线图和分类图:
var result = kMeans(tz,12);聚类结果如下:0:1:
2:3:4:5:6:7:8:9:10:11:转载于:https://blog.51cto.com/janwool/2058124