文本挖掘之文本聚类(OPTICS)
刘 勇 Email:lyssym@sina.com
简介
鉴于DBSCAN算法对输入参数,邻域半径E和阈值M比较敏感,在参数调优时比较麻烦,因此本文对另一种基于密度的聚类算法OPTICS(Ordering Points To Identify the Clustering Structure)展开研究,该算法是DBSCAN的改进算法,与DBSCAN相比,该算法对输入参数不敏感。此外,OPTICS算法不显示地生成数据聚类,其只是对数据对象集合中的对象进行排序,获取一个有序的对象列表,其中包含了足够的信息能用来提取聚类。在实际的应用中,可利用该有序的对象序列,对数据的分布展开分析以及对数据的关联进行分析。
基本概念
由于OPTICS是对DBSCAN算法的一种改进,因此许多概念是共用的,如核心对象、(直接)密度可达、密度相连等,具体内容参考DBSCAN。在上述内容的基础上,本文再引入两个核心概念。
(1) 核心距离
在数据集合D中,对于给定的参数E和M,称使得p成为核心对象的最小邻域半径为p的核心距离。具体数学表达式如下所示:
通俗意义上来说,在给定的参数E和M上,p的核心距离为距离值中的第M个最小值(最大值),该距离表征可以为欧式距离、余弦相似度或Word2Vec等。
(2) 可达距离
在数据集合D中,对于给定的参数E和M,称对象p的核心距离与对象p和o距离,二者之间最大值为o关于p的可达距离。具体数学表达式如下所示:
程序伪代码(参考维基百科):
OPTICS(DB, eps, MinPts)
for each point p of DB
p.reachability-distance = UNDEFINED
for each unprocessed point p of DB
N = getNeighbors(p, eps)
mark p as processed
output p to the ordered list
if (core-distance(p, eps, Minpts) != UNDEFINED)
Seeds = empty priority queue
update(N, p, Seeds, eps, Minpts)
for each next q in Seeds
N' = getNeighbors(q, eps)
mark q as processed
output q to the ordered list
if (core-distance(q, eps, Minpts) != UNDEFINED)
update(N', q, Seeds, eps, Minpts) update(N, p, Seeds, eps, Minpts)
coredist = core-distance(p, eps, MinPts)
for each o in N
if (o is not processed)
new-reach-dist = max(coredist, dist(p,o))
if (o.reachability-distance == UNDEFINED) // o is not in Seeds
o.reachability-distance = new-reach-dist
Seeds.insert(o, new-reach-dist)
else // o in Seeds, check for improvement
if (new-reach-dist < o.reachability-distance)
o.reachability-distance = new-reach-dist
Seeds.move-up(o, new-reach-dist)
程序源代码:
import java.util.List; import com.gta.cosine.ElementDict; public class DataPoint {
private List<ElementDict> terms;
private double initDistance;
private double coreDistance;
private double reachableDistance;
private boolean isVisited; public DataPoint(List<ElementDict> terms) {
this.terms = terms;
this.initDistance = -1;
this.coreDistance = -1;
this.reachableDistance = -1;
this.isVisited = false;
} public double getCoreDistance() {
return coreDistance;
} public void setCoreDistance(double coreDistance) {
this.coreDistance = coreDistance;
} public double getReachableDistance() {
return reachableDistance;
} public void setReachableDistance(double reachableDistance) {
this.reachableDistance = reachableDistance;
} public boolean getIsVisitLabel() {
return isVisited;
} public void setIsVisitLabel(boolean isVisited) {
this.isVisited = isVisited;
} public double getInitDistance() {
return initDistance;
} public void setInitDistance(double initDistance) {
this.initDistance = initDistance;
} public List<ElementDict> getAllElements() {
return terms;
} public ElementDict getElement(int index) {
return terms.get(index);
} public boolean equals(DataPoint dp)
{
List<ElementDict> ed1 = getAllElements();
List<ElementDict> ed2 = dp.getAllElements();
int len = ed1.size(); if (len != ed2.size())
{
return false;
} for (int i = 0; i < len; i++)
{
if (!ed1.get(i).equals(ed2.get(i)))
{
return false;
}
}
return true;
} }
import java.util.Comparator;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Queue;
import java.util.PriorityQueue; import com.gta.cosine.ElementDict;
import com.gta.cosine.TextCosine; public class OPTICS {
private double eps;
private int minPts;
private TextCosine cosine;
private List<DataPoint> dataPoints;
private List<DataPoint> orderList; public OPTICS(double eps, int minPts)
{
this.eps = eps;
this.minPts = minPts;
this.cosine = new TextCosine();
this.dataPoints = new ArrayList<DataPoint>();
this.orderList = new ArrayList<DataPoint>();
} public void addPoint(String s)
{
List<ElementDict> ed = cosine.tokenizer(s);
dataPoints.add(new DataPoint(ed));
} public double coreDistance(List<DataPoint> neighbors)
{
double ret = -1;
if (neighbors.size() >= minPts)
{
Collections.sort(neighbors, new Comparator<DataPoint>() {
public int compare(DataPoint dp1, DataPoint dp2) {
double cd = dp1.getInitDistance() - dp2.getInitDistance();
if (cd < 0) {
return 1;
} else {
return -1;
}
}
}); ret = neighbors.get(minPts-1).getInitDistance();
}
return ret;
} public double cosineDistance(DataPoint p, DataPoint q)
{
List<ElementDict> vec1 = p.getAllElements();
List<ElementDict> vec2 = q.getAllElements();
return cosine.analysisText(vec1, vec2);
} public List<DataPoint> getNeighbors(DataPoint p, List<DataPoint> points)
{
List<DataPoint> neighbors = new ArrayList<DataPoint>();
double countDistance = -1;
for (DataPoint q : points)
{
countDistance = cosineDistance(p, q);
if (countDistance >= eps)
{
q.setInitDistance(countDistance);
neighbors.add(q);
}
}
return neighbors;
} public void cluster(List<DataPoint> points)
{
for (DataPoint point : points)
{
if (!point.getIsVisitLabel())
{
List<DataPoint> neighbors = getNeighbors(point, points);
point.setIsVisitLabel(true);
orderList.add(point);
double cd = coreDistance(neighbors);
if (cd != -1)
{
point.setCoreDistance(cd);
Queue<DataPoint> seeds = new PriorityQueue<DataPoint>(16, new Comparator<DataPoint>() {
public int compare (DataPoint dp1, DataPoint dp2) {
double rd = dp1.getReachableDistance() - dp2.getReachableDistance();
if (rd < 0) {
return 1;
} else {
return -1;
}
}
}); update(point, neighbors, seeds, orderList);
while (!seeds.isEmpty())
{
DataPoint q = seeds.poll();
List<DataPoint> newNeighbors = getNeighbors(q, points);
q.setIsVisitLabel(true);
orderList.add(q);
if (coreDistance(newNeighbors) != -1)
{
update(q, newNeighbors, seeds, orderList);
}
}
}
}
}
} public void update(DataPoint p, List<DataPoint> neighbors, Queue<DataPoint> seeds, List<DataPoint> seqList)
{
double coreDistance = coreDistance(neighbors);
for (DataPoint point : neighbors)
{
double cosineDistance = cosineDistance(p, point);
double reachableDistance = coreDistance > cosineDistance ? coreDistance : cosineDistance;
if (!point.getIsVisitLabel())
{
if (point.getReachableDistance() == -1)
{
point.setReachableDistance(reachableDistance);
seeds.add(point);
}
else
{
if (point.getReachableDistance() > reachableDistance)
{
if (seeds.remove(point))
{
point.setReachableDistance(reachableDistance);
seeds.add(point);
}
}
}
}
else
{
if (point.getReachableDistance() == -1)
{
point.setReachableDistance(reachableDistance);
if (seqList.remove(point))
{
seeds.add(point);
}
}
}
}
} public void showCluster()
{
for (DataPoint point : orderList)
{ List<ElementDict> ed = point.getAllElements();
for (ElementDict e : ed)
{
System.out.print(e.getTerm() + " ");
}
System.out.println();
System.out.println("core: " + point.getCoreDistance());
System.out.println("reach: " + point.getReachableDistance());
System.out.println("***************************************");
}
} public void analysis()
{
cluster(dataPoints);
showCluster();
} public int IndexOfList(DataPoint o, Queue<DataPoint> points)
{
int index = 0;
for (DataPoint p : points)
{
if (o.equals(p))
{
break;
}
index ++;
}
return index;
} }
本文计算距离时采用余弦相似度,具体内容参考本系列之文本挖掘之文本相似度判定。此外,本文经过分析,某些(个)对象之前已被访问后,例如某个边界对象,其核心距离保持为初始值,若严格按照伪代码所示处理,其结果与DBSCAN的结果有些出入,因此本文作者对OPTICS进行了一点修改,使这类对象的可达距离能被修改,并将其添加至列表中,因此,在整体上其处理结果与DBSCAN算法的处理结果保持一致。本文作者认为这样做是有效的,而且存在一定的必要性,若有更好的解决方案,请联系我。
由于OPTICS算法所获取的是对象的有序列表,对后续数据分析、挖掘,具有较高的应用价值,因此,该算法可以作为数据预处理的前奏部分。但是,该算法由于需要维护优先级队列,因而在效率上有点影响。
作者:志青云集
出处:http://www.cnblogs.com/lyssym
如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
如果,您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是【志青云集】。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
文本挖掘之文本聚类(OPTICS)的更多相关文章
- 文本挖掘之文本聚类(MapReduce)
刘 勇 Email:lyssym@sina.com 简介 针对大数量的文本数据,采用单线程处理时,一方面消耗较长处理时间,另一方面对大量数据的I/O操作也会消耗较长处理时间,同时对内存空间的消耗也是 ...
- 文本挖掘之文本聚类(DBSCAN)
刘 勇 Email:lyssym@sina.com 简介 鉴于基于划分的文本聚类方法只能识别球形的聚类,因此本文对基于密度的文本聚类算法展开研究.DBSCAN(Density-Based Spat ...
- 灵玖软件NLPIRParser智能文本聚类
随着互联网的迅猛发展,信息的爆炸式增加,信息超载问题变的越来越严重,信息的更新率也越来越高,用户在信息海洋里查找信息就像大海捞针一样.搜索引擎服务应运而生,在一定程度上满足了用户查找信息的需要.然而互 ...
- 10.HanLP实现k均值--文本聚类
笔记转载于GitHub项目:https://github.com/NLP-LOVE/Introduction-NLP 10. 文本聚类 正所谓物以类聚,人以群分.人们在获取数据时需要整理,将相似的数据 ...
- K-means算法及文本聚类实践
K-Means是常用的聚类算法,与其他聚类算法相比,其时间复杂度低,聚类的效果也还不错,这里简单介绍一下k-means算法,下图是一个手写体数据集聚类的结果. 基本思想 k-means算法需要事先指定 ...
- R语言做文本挖掘 Part4文本分类
Part4文本分类 Part3文本聚类提到过.与聚类分类的简单差异. 那么,我们需要理清训练集的分类,有明白分类的文本:測试集,能够就用训练集来替代.预測集,就是未分类的文本.是分类方法最后的应用实现 ...
- [python] 使用Jieba工具中文分词及文本聚类概念
声明:由于担心CSDN博客丢失,在博客园简单对其进行备份,以后两个地方都会写文章的~感谢CSDN和博客园提供的平台. 前面讲述了很多关于Python爬取本体Ontology.消息盒Inf ...
- pyhanlp 文本聚类详细介绍
文本聚类 文本聚类简单点的来说就是将文本视作一个样本,在其上面进行聚类操作.但是与我们机器学习中常用的聚类操作不同之处在于. 我们的聚类对象不是直接的文本本身,而是文本提取出来的特征.因此如何提取特征 ...
- [转]python进行中文文本聚类(切词以及Kmeans聚类)
简介 查看百度搜索中文文本聚类我失望的发现,网上竟然没有一个完整的关于Python实现的中文文本聚类(乃至搜索关键词python 中文文本聚类也是如此),网上大部分是关于文本聚类的Kmeans聚类的原 ...
随机推荐
- 怎样防止ddos攻击
所有的主机平台都有抵御DoS的设置,总结一下,基本的有几种: 关闭不必要的服务 限制同时打开的Syn半连接数目 缩短Syn半连接的time out 时间 及时更新系统补丁 网络设置 网络设备可以从防火 ...
- extjs 动态设定 DateField 最大值 最小值
yxrqDate.minValue = new Date();yxrqDate.maxValue = new Date(9000,1,1);yxrqDate.validate(); //var pic ...
- .NET:鲜为人知的 “Load Context”
背景 任何一门语言都要了解其类型加载过程,如:Java 的 Class Loader,NodeJS 的搜索方式等,本文概述一下我对 CLR 如何加载程序集,重点说一下 Load Context. 其编 ...
- Selenium2+python自动化35-获取元素属性
前言 通常在做断言之前,都要先获取界面上元素的属性,然后与期望结果对比.本篇介绍几种常见的获取元素属性方法. 一.获取页面title 1.有很多小伙伴都不知道title长在哪里,看下图左上角. 2.获 ...
- rman多通道全备份脚本
run{ allocate channel d1 type disk; allocate channel d2 type disk; allocate channel d3 type disk; ...
- Git 学习(三)本地仓库操作——git add & commit
Git 学习(三)本地仓库操作——git add & commit Git 和其他版本控制系统如SVN的一个不同之处就是有暂存区的概念.这在上文已有提及,本文具体说明什么是工作区及暂存区,以及 ...
- Java网络编程技术2
3. UDP数据报通信 UDP通信中,需要建立一个DatagramSocket,与Socket不同,它不存在“连接”的概念,取而代之的是一个数据报包——DatagramPacket.这个数据报包必须知 ...
- Informatica 常用组件Lookup之八 查找高速缓存
可以配置查找转换以高速缓存查找文件或表.PowerCenter 将在处理高速缓存查找转换中的第一个数据行时在存储器中建立高速缓存.它将根据您在转换或会话特性中配置的数量来分配高速缓存区内存.Power ...
- iOS开发-简单的图片查看器
现在你只要拿着手机,不管你Android还是iOS,新闻类的App不可避免都有一个功能就是图片查看,做个专题,查看一下内容,App Store中也有专门针对图片浏览的App,鉴于目前所知有限,无法做到 ...
- 使用SqlServer中的float类型时发现的问题
在做项目中,使用了float类型来定义一些列,如:Price,但是发现了很多问题1.当值的位数大于6位是float型再转varchar型的时候会变为科学技术法显示 此时只好将float型转换成n ...