fansy1990的专栏

本篇代码可在 (明天更新)下载。

前篇《HotSpot关联规则算法(1)– 挖掘离散型数据》分析了离散型数据的HotSpot关联规则,本篇分析离散型和连续型数据的HotSpot关联规则挖掘。

1. 首先看下数据格式(txt文档):

@attribute outlook {sunny, overcast, rainy}@attribute temperature numeric@attribute humidity numeric@attribute windy {TRUE, FALSE}@attribute play {yes, no}sunny,85,85,FALSE,nosunny,80,90,TRUE,noovercast,83,86,FALSE,yesrainy,70,96,FALSE,yesrainy,68,80,FALSE,yesrainy,65,70,TRUE,noovercast,64,65,TRUE,yessunny,72,95,FALSE,nosunny,69,70,FALSE,yesrainy,75,80,FALSE,yessunny,75,70,TRUE,yesovercast,72,90,TRUE,yesovercast,81,75,FALSE,yesrainy,71,91,TRUE,no此数据参考weka自带数据weather.arff,而且数据格式,比如写上@attribute 等都是参考weka的数据格式来的。下面代码中使用的数据格式如上所述,其格式描述如下:1)前m行以@attribute开头,代码m个属性,其中最后一个为目标属性;2)如果属性是数值型,则在attribute后面空格跟属性名,再空格跟numeric;如果是离散型,那么attribute后面空格跟属性名,再空格使用大括号把离散值括起来,离散值用逗号分隔;3)目标属性必须是离散型的(关于目标属性应该一定要属于离散型的这点要求,其实只是我代码里面这样说而已,一般的HotSpot算法并没有这个要求。如果目标属性一定要求是连续型的,可以在lz代码基础上进行修改)。

2. 数据读取

《HotSpot关联规则算法(1)》中的数据读取是针对离散型的数据的,所以需要进行修改,这里修改后只针对离散型数据进行编码,连续型数据保持即可,同时还需设置一个布尔数组指明属性列属于离散型还是连续型。其读取代码如下所示:

while ((tempString = reader.readLine()) != null) {// 第一行数据是标题if (tempString.indexOf(HSUtils.FILEFORMAT) == 0) {String attr = "";String[] attrStates = null;if (tempString.contains("{")) {attr = tempString.substring(HSUtils.FILEFORMAT.length(),tempString.indexOf("{")).trim();attrStates = tempString.substring(tempString.indexOf("{") + 1,tempString.indexOf("}")).split(",");for (int i = 0; i < attrStates.length; i++) {attrStates[i] = attrStates[i].trim();}numericList.add(false);this.attributeStates.put(attr, attrStates);// 在这里添加即可} else {// numericif (tempString.contains("numeric")) {attr = tempString.substring(HSUtils.FILEFORMAT.length(),tempString.indexOf("numeric")).trim();numericList.add(true);} else {// error 数据格式错误throw new Exception("数据格式错误,请检查!");}}attrList.add(attr);line++;continue;}if (flag) {this.attributes = new String[line];this.isNumeric = new Boolean[line];attrList.toArray(this.attributes);// 复制值到数组中numericList.toArray(this.isNumeric);flag = false;}String[] tempStrings = tempString.split(splitter);lists.add(strArr2IntArr(tempStrings));}这里只贴了while循环里面的代码,这里的代码即针对前面描述的数据格式规则进行变量初始化(其实,,这里使用List存储转换后的数据,一般是可以使用数组来存储的,把List的数据转为数组即可,这样在后面的操作中可以更快,如果要优化,可以从这方面入手)。

3. HotSpot关联规则树的节点定义说明:

由于这里增加了连续型属性数据,所以针对单个节点需增加一个布尔型变量lessThan,用于指明是要大于或者小于该节点数据,同时stateIndex应该是一个数值了(当前节点的值),而不是离散型数据状态的下标了。

4. 算法伪代码(建树过程)

在算法伪代码中的计算潜在节点时,针对连续型变量使用不同的方法,在weka源码中使用方法:evaluateNumeric来进行判断。在lz的代码中此部分是完全参考源码中的代码的,不过有一点就是在调用evaluateNumeric这个算法后,会针对某一列进行排序,即一个二维数组按某列进行全局排序。这个方法在weka源码中是使用Instances的quickSort方法进行排序的(使用了递归,没仔细看)。这里lz则是直接把List转为二维数组然后进行排序的,其方法如下:

/** * 根据attrIndex进行排序,attrIndex必须是numeric的 此方法可能需要优化 * List 使用数组是否更快? 可以考虑使用数组 * @param intData * @param attrIndex * @return */private List<float[]> sortBasedOnAttr(List<float[]> intData, final int attrIndex) {float[][] tmpData = new float[intData.size()][];intData.toArray(tmpData);Arrays.sort(tmpData,new Comparator<float[]>(){@Overridepublic int compare(float[] o1, float[] o2) {if(o1[attrIndex]==o2[attrIndex]){return 0;}return o1[attrIndex]>o2[attrIndex]?1:-1;}});List<float[]> returnList = new ArrayList<float[]>();for (int i = 0; i < tmpData.length; i++) {returnList.add(tmpData[i]);}return returnList;}同时,在递归构建孩子节点时,生成节点规则时,针对数值型和离散型其生成方式也是不同的,如下:double[] newSplitVals = splitVals.clone();byte[] newTests = tests.clone();newSplitVals[attrStateSup.getAttrIndex()] = attrStateSup.getStateIndex() + 1;newTests[attrStateSup.getAttrIndex()] = isNumeric[attrStateSup.getAttrIndex()]?attrStateSup.isLessThan()?(byte)1:(byte)3:(byte) 2;HotSpotHashKey key = new HotSpotHashKey(newSplitVals, newTests);在递归构建孩子节点时,使用的子数据集的生成方式也需要进行调整,如下:/** * 获取和splitAttributeIndex相同下标的属性以及stateIndex的所有数据 * * @param intData * @param splitAttributeIndex * @param splitValue * @return */private List<float[]> getSubData(List<float[]> intData,int splitAttributeIndex, float splitValue,boolean lessThan) {List<float[]> subData = new ArrayList<float[]>();for (float[] d : intData) {if(isNumeric[splitAttributeIndex]){if(lessThan){if (d[splitAttributeIndex] <= splitValue) {subData.add(d);}}else{if (d[splitAttributeIndex] > splitValue) {subData.add(d);}}}else{if (d[splitAttributeIndex] == splitValue) {subData.add(d);}}}return subData;}节点的toString 方法,用于打印HotSpot关联规则树/** * 格式化输出 */public String toString(){String tmp = HSUtils.isNumeric(splitAttrIndex)?this.lessThan?" <= ":" > ":" = ";String attrState = HSUtils.isNumeric(splitAttrIndex)?String.valueOf(this.attrStateIndex):HSUtils.getAttrState(splitAttrIndex, (int)attrStateIndex); return HSUtils.getAttr(this.splitAttrIndex)+tmp+attrState+" ("+HSUtils.formatPercent(this.support)+" ["+this.stateCount+"/"+this.allCount+"])";}在打印关联规则树时,同样需要判断当前的属性是离散型还是连续型的。

让我们从自身的禁锢中放心地飞出去,重新审视自己,

fansy1990的专栏

相关文章:

你感兴趣的文章:

标签云: