刘 勇  Email:lyssym@sina.com

简介

  鉴于DBSCAN算法对输入参数,邻域半径E和阈值M比较敏感,在参数调优时比较麻烦,因此本文对另一种基于密度的聚类算法OPTICS(Ordering Points To Identify the Clustering Structure)展开研究,该算法是DBSCAN的改进算法,与DBSCAN相比,该算法对输入参数不敏感。此外,OPTICS算法不显示地生成数据聚类,其只是对数据对象集合中的对象进行排序,获取一个有序的对象列表,其中包含了足够的信息能用来提取聚类。在实际的应用中,可利用该有序的对象序列,对数据的分布展开分析以及对数据的关联进行分析。

基本概念

  由于OPTICS是对DBSCAN算法的一种改进,因此许多概念是共用的,如核心对象、(直接)密度可达、密度相连等,具体内容参考DBSCAN。在上述内容的基础上,本文再引入两个核心概念。

  (1) 核心距离

  在数据集合D中,对于给定的参数EM,称使得p成为核心对象的最小邻域半径为p的核心距离。具体数学表达式如下所示:

  通俗意义上来说,在给定的参数EM上,p的核心距离为距离值中的第M个最小值(最大值),该距离表征可以为欧式距离、余弦相似度或Word2Vec等。

  (2) 可达距离

  在数据集合D中,对于给定的参数EM,称对象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)的更多相关文章

  1. 文本挖掘之文本聚类(MapReduce)

    刘 勇  Email:lyssym@sina.com 简介 针对大数量的文本数据,采用单线程处理时,一方面消耗较长处理时间,另一方面对大量数据的I/O操作也会消耗较长处理时间,同时对内存空间的消耗也是 ...

  2. 文本挖掘之文本聚类(DBSCAN)

    刘 勇   Email:lyssym@sina.com 简介 鉴于基于划分的文本聚类方法只能识别球形的聚类,因此本文对基于密度的文本聚类算法展开研究.DBSCAN(Density-Based Spat ...

  3. 灵玖软件NLPIRParser智能文本聚类

    随着互联网的迅猛发展,信息的爆炸式增加,信息超载问题变的越来越严重,信息的更新率也越来越高,用户在信息海洋里查找信息就像大海捞针一样.搜索引擎服务应运而生,在一定程度上满足了用户查找信息的需要.然而互 ...

  4. 10.HanLP实现k均值--文本聚类

    笔记转载于GitHub项目:https://github.com/NLP-LOVE/Introduction-NLP 10. 文本聚类 正所谓物以类聚,人以群分.人们在获取数据时需要整理,将相似的数据 ...

  5. K-means算法及文本聚类实践

    K-Means是常用的聚类算法,与其他聚类算法相比,其时间复杂度低,聚类的效果也还不错,这里简单介绍一下k-means算法,下图是一个手写体数据集聚类的结果. 基本思想 k-means算法需要事先指定 ...

  6. R语言做文本挖掘 Part4文本分类

    Part4文本分类 Part3文本聚类提到过.与聚类分类的简单差异. 那么,我们需要理清训练集的分类,有明白分类的文本:測试集,能够就用训练集来替代.预測集,就是未分类的文本.是分类方法最后的应用实现 ...

  7. [python] 使用Jieba工具中文分词及文本聚类概念

    声明:由于担心CSDN博客丢失,在博客园简单对其进行备份,以后两个地方都会写文章的~感谢CSDN和博客园提供的平台.        前面讲述了很多关于Python爬取本体Ontology.消息盒Inf ...

  8. pyhanlp 文本聚类详细介绍

    文本聚类 文本聚类简单点的来说就是将文本视作一个样本,在其上面进行聚类操作.但是与我们机器学习中常用的聚类操作不同之处在于. 我们的聚类对象不是直接的文本本身,而是文本提取出来的特征.因此如何提取特征 ...

  9. [转]python进行中文文本聚类(切词以及Kmeans聚类)

    简介 查看百度搜索中文文本聚类我失望的发现,网上竟然没有一个完整的关于Python实现的中文文本聚类(乃至搜索关键词python 中文文本聚类也是如此),网上大部分是关于文本聚类的Kmeans聚类的原 ...

随机推荐

  1. linux-修改时区时间

    所有笔记基于-CentOS release 6.8 (Final) ntpdate 202.120.2.101 同步上海时间 cp -f /usr/share/zoneinfo/Asia/Shangh ...

  2. TQ2440实现触摸屏和qt图形 解决segmentation fault

    使用触摸屏,首先安装触摸屏矫正程序. 下载并解压tslib-1.4,进入主文件夹,运行: 1 [root@localhost ~]#./autogen.sh 2 [root@localhost ~]# ...

  3. 如何使用C++回调函数

         程序猿经常须要实现回调.本文将讨论函数指针的基本原则并说明怎样使用函数指针实现回调.注意这里针对的是普通的函数,不包含全然依赖于不同语法和语义规则的类成员函数(类成员指针将在另文中讨论). ...

  4. Calendar 对象的使用实例

    1.Calendar demo例子 JavaCalendar 类时间操作,示范代码. public class CalendarDemo { private static SimpleDateForm ...

  5. 【HDOJ】【3377】Plan

    插头DP sigh……其实思路很简单的= =就多加一种转移:从(0,0)->(0,0),也就是不走这个格子…… 初始状态就是第一格有一个左插头= =结束状态可以让(n,m)这个位置可以走到(n+ ...

  6. spark读取 kafka nginx网站日志消息 并写入HDFS中(转)

    原文链接:spark读取 kafka nginx网站日志消息 并写入HDFS中 spark 版本为1.0 kafka 版本为0.8 首先来看看kafka的架构图 详细了解请参考官方 我这边有三台机器用 ...

  7. Kmeans聚类算法分析(转帖)

    原帖地址:http://www.opencvchina.com/thread-749-1-1.html       k-means是一种聚类算法,这种算法是依赖于点的邻域来决定哪些点应该分在一个组中. ...

  8. GoLang中 json、map、struct 之间的相互转化

    1. golang 中 json 转 struct <1. 使用 json.Unmarshal 时,结构体的每一项必须是导出项(import field).也就是说结构体的 key 对应的首字母 ...

  9. shell more less cat

    cat 连续显示.查看文件内容 more 分页查看文件内容 less 分页可控制查看文件内容 通俗点说: cat一次性把文件内容全部显示出来,管你看不看得清,显示完了cat命令就返回了,不能进行交互式 ...

  10. linux loop device介绍

    在Linux中,有一种特殊的块设备叫loop device,这种loop device设备是通过影射操作系统上的正常的文件而形成的虚拟块设备.因为这种设备的存在,就为我们提供了一种创建一个存在于其他文 ...