`

层次聚类的一种实现

 
阅读更多
层次聚类方法对给定的数据集进行层次的分解,直到某种条件满足为止。具体又可分为凝聚的,分裂的两种方案。
1凝聚的层次聚类是一种自底向上的策略,首先将每个对象作为一个簇,然后合并这些原子簇为越来越大的簇,直到所有的对象都在一个簇中,或者某个终结条件被满足,绝大多数层次聚类方法属于这一类,它们只是在簇间相似度的定义上有所不同。
2分裂的层次聚类与凝聚的层次聚类相反,采用自顶向下的策略,它首先将所有对象置于同一个簇中,然后逐渐细分为越来越小的簇,直到每个对象自成一簇,或者达到了某个终止条件。
凝聚的层次聚类可以简单的归纳为以下步骤:
初始样本点:s0,s1,sn...,sn
初始化:开始将每个样本点视为一个类,所有类的集合和样本点的个数相同,记为               cluster{cluster0,...clustern}
聚类条件:取所所有类别中距离最近的两个类,作为一个新的类,这里的距离可以是用户自定义的聚类距离,本方法采用的是minhash来计算不同文本直接的聚类,minhash值为通过tfidf算法获取的关键词之间的集合计算而来。
终止条件:用户可以根据聚类的个数终止也可以根据类之间的距离终止,比如类的个数超过用户自己设定的个数,或者类之间的聚类大于用户预先设定的阈值。这里类之间的聚类可以根据用户需求自己定义,可以是类中每个样本点的最近聚类、最短聚类或者是平均聚类。本方法是用的最近的聚类。
聚类步骤:计算所有类中所有类之间的聚类,取所有类中最近的两个类作为一个新类,将两个类中的样本点合并。直到满足终止条件。
算法如下:
package org.mino.exp.dbconstruct;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileFilter;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.mino.util.FileUtil;

import com.sun.net.httpserver.Filter;
import com.sun.net.httpserver.HttpExchange;


/**
 * 通过minhash方法进行聚类
 * @author 丁杰
 */
public class MinHashCluster {
	static HashMap<String, Double> map = null;
	/**
	 * 任意两篇专利文献之间距离
	 */
	private static String simHashPath = "E:\\research\\experiment_2\\tfidf_filter\\H01M\\simhash.dat";
	static {
		map = loadSimHash(simHashPath);
	}
	
	public static void main(String[] args) {
		/**
		 * 聚类文件绝对目录
		 */
		String clusterFilePath = "E:\\research\\experiment_2\\tfidf_filter\\H01M\\";
		/**
		 * 孤立点目录
		 */
		String isolatePoin = "E:\\research\\experiment_2\\tfidf_filter\\H01M\\IsolatedPoint\\";
		double initThread = 0.80;
		//文件内容为空的剪切到孤立点目录下
//		cutFileNotExist(clusterFilePath, isolatePoin); 
		//文本到其它文本的最小值大于阈值的拷贝到孤立点目录
		preIsolatePoin(simHashPath, clusterFilePath, isolatePoin, initThread);
		
		
		
		double disThreshold = 0.6;//阈值
		MinHashCluster mh = new MinHashCluster();
		String [] fileFilters = {"txt"};
		int clusterNum = 20;
		
		//如果一篇专利文献到其它专利文献的最近的距离大于某一个阈值则将该专利文献视为孤立点
		
		List<DataPoint> iniPoint = mh.getDatePoinFromDir(clusterFilePath, fileFilters);
//		System.out.println(iniPoint.size());
		mh.initialCluster(iniPoint);
		List<Cluster> clusters = mh.startAnalysis(iniPoint, clusterNum, disThreshold);
		String clusterPath = clusterFilePath + File.separator + "fileClustet.dat";
		writeClusterToFile(clusterPath, clusters);
	}

	/**
	 * 剪切
	 * @param simHashPath
	 * @param cutToPath
	 * @param threshold
	 */
	@SuppressWarnings("unused")
	private static void preIsolatePoin(String simHashPath, String cutFromPath, String cutToPath, double threshold) {
		HashMap<String, Double> simMap = FileUtil.getDoubMapFromFile(simHashPath);  //加载simhash文件
		HashMap<String, Double> minSimMap = new HashMap<String, Double>();
		Iterator<String> it = simMap.keySet().iterator();
		while(it.hasNext()) {
			String key = it.next().trim();
			String[] keys = key.split("#");
			double value = simMap.get(key);
			double distance = 1.0 - value;
//			System.out.println(distance);
			////////////////////////////////////////////////
			if(minSimMap.containsKey(keys[0])) {//如果包含
				if(minSimMap.get(keys[0]) > distance) {//如果原有的距离大于distance
					minSimMap.put(keys[0], distance);
				}
			} else {//不包含
//				System.out.println(keys[0] +  " " + distance);
				minSimMap.put(keys[0], distance);
			}
			////////////////////////////////////////////////
			if(minSimMap.containsKey(keys[1])) {//如果包含
				if(minSimMap.get(keys[1]) > distance) {
					minSimMap.put(keys[1], distance);
				}
			} else {//不包含
				minSimMap.put(keys[1], distance);
			}
		   ////////////////////////////////////////////////
		}
		it = minSimMap.keySet().iterator();
		int total =  0;
		while(it.hasNext()) {
			String fileName = it.next();
			double value = minSimMap.get(fileName);
			if(value >= threshold) {
				total ++;
//				System.out.println(value);
				FileUtil.copyFile(cutFromPath + fileName, cutToPath + fileName);
				new File(cutFromPath + fileName).delete();
//				System.out.println(fileName);//如果文本到专利文献的 最小距离大于阈值  则删除该文件
			}
		}
		System.out.println("孤立点 : " + total);
	}
	
	/**
	 * 剪切文件内容为空的文件到 isolatePoin
	 * @param clusterFilePath
	 * @param isolatePoin
	 */
	@SuppressWarnings("unused")
	private static void cutFileNotExist(String clusterFilePath,
			String isolatePoin) {
		// TODO Auto-generated method stub
		File file = new File(clusterFilePath);
		File [] files = file.listFiles(new FileFilter() {
			@Override
			public boolean accept(File pathname) {
				// TODO Auto-generated method stub
				if(pathname.getName().endsWith("txt")) {
					return true;
				}
				return false;
			}});
		
		for(File f : files) {
			if(f.length() == 0) {
				System.out.println(f);
				FileUtil.copyFile(f.getAbsolutePath(), isolatePoin + File.separator + f.getName());
				f.delete();
			}
		}//end_file
	}

	/**
	 * 加载两篇专利文献之间的距离
	 * @param simHashPath2
	 * @return
	 */
	private static HashMap<String, Double> loadSimHash(String simHashPath) {
		// TODO Auto-generated method stub
		return FileUtil.getDoubMapFromFile(simHashPath);
	}

	/**
	 * 将聚类结果写入到文件
	 * @param clusterFilePath
	 * @param clusters
	 */
	private static void writeClusterToFile(String clusterFilePath,
			List<Cluster> clusters) {
		FileWriter fw = null;
		BufferedWriter bw = null;
		try {
			 fw = new FileWriter(clusterFilePath);
			 bw = new BufferedWriter(fw);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		for (Cluster cl : clusters) {
			try {
				bw.write(cl.getClusterName());
				bw.newLine();
				bw.flush();
			} catch (IOException e) {
				e.printStackTrace();
			}
			List<DataPoint> tempDps = cl.getDataPoints();
			
			for (DataPoint tempdp : tempDps) {
				try {
					bw.write(tempdp.getDataPointName().substring(tempdp.getDataPointName().lastIndexOf("\\") + 1));
					bw.write("#");
					bw.newLine();
					bw.flush();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
//				System.out.print(tempdp.getDataPointName()+"#");
			}//end_for
			try {
				bw.newLine();
				bw.flush();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
//			System.out.println();
		}//end_for
	}
	
	/**
	 * @param dataPoints 数据点
	 * @param ClusterNum 需要聚类的个数
	 * @return
	 */
	public List<Cluster> startAnalysis(List<DataPoint> dataPoints,
			int ClusterNum, double threshold) {
		//最聚类结果
		List<Cluster> finalClusters = new ArrayList<Cluster>();
		//初始聚类结果
		List<Cluster> originalClusters = initialCluster(dataPoints);
		finalClusters = originalClusters;
		while (finalClusters.size() > ClusterNum) {
			double min = Double.MAX_VALUE;
			int mergeIndexA = 0;
			int mergeIndexB = 0;
			for (int i = 0; i < finalClusters.size(); i++) {
				for (int j = 0; j < finalClusters.size(); j++) {
					if (i != j) {
						Cluster clusterA = finalClusters.get(i);//获取聚类1
						Cluster clusterB = finalClusters.get(j);//获取聚类2
						List<DataPoint> dataPointsA = clusterA.getDataPoints();
						List<DataPoint> dataPointsB = clusterB.getDataPoints();
						
						//以下两个for循环来确定应聚那两个类
						for (int m = 0; m < dataPointsA.size(); m++) {
							for (int n = 0; n < dataPointsB.size(); n++) {//划分类的标准:两类中最近的两篇文档作为类的距离
								 //计算两个聚类专利文献的距离
//								System.out.println("outer:" + (m + 1) + " / " + dataPointsA.size()+ ",inner:"+ (n + 1) + " / " +dataPointsB.size());
								double tempWeight = getDistance(dataPointsA.get(m).getDataPointName(), dataPointsB.get(n).getDataPointName());
								if(0 <= tempWeight && tempWeight <= 1) {//如果在0-1之间,将相似度转换为距离
									tempWeight = 1 - tempWeight;
								}
								if (tempWeight < min) {
									min = tempWeight;
									mergeIndexA = i;//保存最小距离的专利文献所在的簇
									mergeIndexB = j;//保存最小距离的专利文献所在的簇
								}//end_if
							}//end_for
						}//end_for
					}//end_if
				} // end for j
			}// end for i
			// 合并cluster[mergeIndexA]和cluster[mergeIndexB]
			if(min > threshold) {
				System.out.println("距离超过指定的阈值,聚类结束!");
				break;
			}
			finalClusters = mergeCluster(finalClusters, mergeIndexA, mergeIndexB);
		}// end while
		return finalClusters;
	}

	/**
	 * 获取两篇专利文献之间的相似度
	 * @param dataPointName
	 * @param dataPointName2
	 * @return
	 */
	private double getDistance(String dataPointName1, String dataPointName2) {
		// TODO Auto-generated method stub
		String path1 = dataPointName1.substring(dataPointName1.lastIndexOf("\\")+1);
		String path2 = dataPointName2.substring(dataPointName2.lastIndexOf("\\")+1);
//		System.out.println(path1);
		String key = path1 + "#" + path2;
		if(map.containsKey(path1 + "#" + path2)) {
			double value = map.get(key);
//			System.out.println(key + "$" + value);
			return value;
		}
		return 0;
	}

	/**
	 * 合并两个类
	 * @param clusters
	 * @param mergeIndexA
	 * @param mergeIndexB
	 * @return
	 */
	private List<Cluster> mergeCluster(List<Cluster> clusters, int mergeIndexA,
			int mergeIndexB) {
		if (mergeIndexA != mergeIndexB) {
			// 将cluster[mergeIndexB]中的DataPoint加入到 cluster[mergeIndexA]
			Cluster clusterA = clusters.get(mergeIndexA);
			Cluster clusterB = clusters.get(mergeIndexB);
			System.out.println("合并 " + clusterA.getClusterName()+"["+clusterA.getDataPoints().size()+"] + " + clusterB.getClusterName() + "["+clusterB.getDataPoints().size()+"]");
			List<DataPoint> dpA = clusterA.getDataPoints();
			List<DataPoint> dpB = clusterB.getDataPoints();
			for (DataPoint dp : dpB) {
				DataPoint tempDp = new DataPoint();
				tempDp.setDataPointName(dp.getDataPointName());
				tempDp.setCluster(clusterA);
				dpA.add(tempDp);
			}
			clusterA.setDataPoints(dpA);
			// List<Cluster> clusters中移除cluster[mergeIndexB]
			clusters.remove(mergeIndexB);
		}
		return clusters;
	}

	/**
	 * 返回目录下符合后缀集合的样本集合
	 * @param dir
	 * @param fileSufix
	 * @return
	 */
	@SuppressWarnings("unused")
	private List<DataPoint> getDatePoinFromDir(String dir, final String [] fileSufix) {
		List<DataPoint> list = new ArrayList<DataPoint>();
		if(dir == null || "".equals(dir)) {
			System.out.println("输入路径为空!");
			return list;
		}
		File file = new File(dir);
		String[] files = file.list(new FilenameFilter(){
			@Override
			public boolean accept(File dir, String name) {
				// TODO Auto-generated method stub
				for(String str : fileSufix) {
					if(name.endsWith(str)) {
						return true;
					}
				}
				return false;
			}});
		for(String f : files) {
			DataPoint dp = new DataPoint();
			dp.setDataPointName(dir + f);
			list.add(dp);
		}
		return list;
	}
	// 初始化类簇
	/**
	 * 每个节点属于一个类
	 * @param dataPoints
	 * @return
	 */
	private List<Cluster> initialCluster(List<DataPoint> dataPoints) {
		List<Cluster> originalClusters = new ArrayList<Cluster>();
		for (int i = 0; i < dataPoints.size(); i++) {
			DataPoint tempDataPoint = dataPoints.get(i);
			List<DataPoint> tempDataPoints = new ArrayList<DataPoint>();
			tempDataPoints.add(tempDataPoint);
			Cluster tempCluster = new Cluster();
			tempCluster.setClusterName("Cluster " + String.valueOf(i));
			tempCluster.setDataPoints(tempDataPoints);
			tempDataPoint.setCluster(tempCluster);
			originalClusters.add(tempCluster);
		}
		return originalClusters;
	}
	
}
/**
 * 聚类存放结果
 * @author DingJie
 */
class Cluster {
	private List<DataPoint> dataPoints = new ArrayList<DataPoint>(); // 类簇中的样本点
	private String clusterName;

	public List<DataPoint> getDataPoints() {
		return dataPoints;
	}

	public void setDataPoints(List<DataPoint> dataPoints) {
		this.dataPoints = dataPoints;
	}

	public String getClusterName() {
		return clusterName;
	}

	public void setClusterName(String clusterName) {
		this.clusterName = clusterName;
	}
}

/**
 * 聚类节点类型
 * @author 丁杰
 */
class DataPoint {
	String dataPointName; // 样本点名
	Cluster cluster;      // 样本点所属类簇

	public DataPoint() {
	}

	public Cluster getCluster() {
		return cluster;
	}

	public void setCluster(Cluster cluster) {
		this.cluster = cluster;
	}

	public String getDataPointName() {
		return dataPointName;
	}

	public void setDataPointName(String dataPointName) {
		this.dataPointName = dataPointName;
	}
}
 
分享到:
评论

相关推荐

    python中层次聚类法.docx

    python中层次聚类法 层次聚类法是一种常用的聚类算法,它可以将数据集中的样本分成不同的类别,从而实现数据的分类和分析。在Python中,我们可以使用scikit-learn库中的AgglomerativeClustering类来实现层次聚类。 ...

    论文研究-一种处理混合型数据的层次聚类算法.pdf

    然后定义了新的个体间不可区分度、 类间不可区分度、聚类结果的综合近似精度等概念,提出了新的混合数据类型层次聚类算法。该算法不仅能处 理数值型数据,而且能处理大多数聚类算法不能处理的字符型数据和混合型数据...

    论文研究-一种层次聚类的RDF图语义检索方法研究.pdf

    针对当前信息资源描述框架RDF检索过程中存在的内存使用过大及检索效率低等问题, 提出一个RDF图的层次聚类语义检索模型, 设计并实现了相应的检索方法。首先从RDF图中抽取实体数据, 在本体库的指导下, 通过层次聚类, ...

    一种新的分裂层次聚类SVM 多值分类器

    提出一种分裂层次聚类SVM 分类树分类方法. 该方法通过融合模糊聚类技术和支持向量机算法, 利用分裂 的层次聚类策略, 有选择地重新构造学习样本集和SVM 子分类器, 得到了一种树形多值分类器. 研究结果表明, 对...

    基于C语言实现凝聚层次聚类算法(源码)

    凝聚层次聚类算法(Agglomerative Hierarchical Clustering)是一种将数据集中的样本逐步合并为越来越大的簇的聚类算法。在每一步中,该算法将最接近的样本或簇合并,直到满足某个停止条件。

    利用MATLAB实现聚类分析数学建模算法

    2. **层次聚类(Hierarchical Clustering):** 层次聚类是一种基于树状结构的聚类方法,可以分为凝聚型和分裂型两种。凝聚型层次聚类从底层开始,逐渐合并相似的簇,形成一个层次结构。分裂型层次聚类从顶层开始,...

    『ML』用Python实现聚类效果的评估(轮廓系数、互信息)

      本文介绍两种聚类评估方法,轮廓系数(Silhouette Coefficient)以及标准化互信息(NMI),并且用Python实现。 导航效果评估综述轮廓系数互信息参考文章 效果评估综述   这里直接贴上 聚类算法初探(七)聚类...

    RoutePrediction:使用层次聚类算法进行路线预测

    该 repo 实现了一种算法,可用于根据开始位置预测结束位置。 该方法基于以下假设:司机遵循某些模式,例如从火车站开车到办公室,或者每个工作日早上送孩子上学。 这个想法是根据司机当前的上车位置来确定司机的上车...

    论文研究-基于多空间多层次谱聚类的非监督SAR图像分割算法.pdf

    提出了一种基于多层区域谱聚类的非监督SAR图像分割算法(multi-space and multi-hierarchical region based spectral clustering, MSMHSC)。该算法首先在特征与几何空间求距离, 快速获得初始过分割区域, 然后在过分...

    四种聚类算法实现对控制图时间序列的聚类

    主要针对控制图时间序列数据集的聚类任务,使用了基于划分的(K-Means)、基于层次的(AGNES)、基于密度的(DBSCAN)以及基于图的(spectral clustering)聚类方法,最后可视化结果,用Jupyter Notebook编写...

    python驾驶风格聚类代码.docx

    在Python中,有许多聚类算法的实现,如K-Means、层次聚类、DBSCAN等。本文将介绍一种基于K-Means算法的聚类方法,并给出相应的Python代码实现。 K-Means算法是一种基于距离的聚类算法,它将数据集中的对象分成K个簇...

    HypHC:双曲层次聚类

    基于相似性的层次聚类(HC)是一种经典的无监督机器学习算法,传统上已使用诸如平均链接之类的启发式算法进行了求解。 最近,Dasgupta通过引入衡量给定树质量的全局成本函数,将HC重新构架为离散的优化问题。 在这...

    基于层次聚类的图像超分辨率重建

    多字典学习的图像超分辨率重建过程中常见的K均值聚类、高斯混合模型聚类等方法会导致图像的重建质量欠佳且不稳定,针对这一问题提出一种新的基于层次聚类的图像超分辨率重建算法;首先对样本图像块提取特征并进行...

    MPM_EDA_2013_written:大约2013年实现的一种层次聚类算法实验代码, 包含K-means实现作为benchmark,相关成果已由硕士期间导师发表(SCI)

    大约2013年用Java实现的一种层次聚类算法,源码包中同时包含经典的K-Means算法作为对照组。 在iris和yeast等公开数据集上,该算法在参数调教合适时性能能够超越K-Means和另一种层次聚类算法——BIRTH。 程序发布版...

    一种混合限制层次聚类算法 (2005年)

    分析了CCL算法,基于数据对象间的关联限制定义了类间关联系数,提出了一种混合型限制层次聚类算法HCCL.本算法可以分成2个相对独立的阶段,第一阶段同Complete - link算法几乎一致,依据数据对象的自然分布,把它们合并人...

    一种层次聚类的RDF图语义检索方法研究 (2012年)

    针对当前信息资源描述框架RDF检索过程中存在的内存使用过大及检索效率低等问题, 提出一个RDF图的层次聚类语义检索模型, 设计并实现了相应的检索方法。首先从RDF图中抽取实体数据, 在本体库的指导下, 通过层次聚类, ...

    论文研究 - 购物中心中客户计费预测的聚类方法:一种机器学习机制

    我们正在执行K-Means聚类和层次聚类机制,最后,我们实现了一个混淆矩阵,以实现并确定这两种算法中的最高准确性。 在这里,我们考虑使用机器学习机制根据自变量来预测客户是否可以购买产品的类别。 这项工作为您...

    论文研究-基于时间序列和任务调度的Web数据聚类算法.pdf

    为了实现Web服务请求数据的快速聚类,并提高聚类的准确率,提出一种基于增量式时间序列和任务调度的Web数据聚类算法,该算法进行了Web数据在时间序列上的聚类定义,并采用增量式时间序列聚类方法,通过数据压缩的...

    CLUSTER_分解聚类_cluster_

    层次聚类算法有两种实现思想,一种是初始时将每个待聚类的数据样本视为一个cluster

    层次分析matlab代码-MBHC_WMM:方法的实现:使用沃森混合模型(MBHC-WMM)的基于模型的层次聚类

    聚类方法的实现:使用沃森混合模型(MBHC-WMM)的基于模型的层次聚类 MBHC-WMM方法是对3维轴向数据进行聚类的自动方法。 此存储库为GUI演示提供了MATLAB代码以执行以下任务: 一种。 加载3维轴向(标记/未标记)数据...

Global site tag (gtag.js) - Google Analytics