刘 勇   Email:lyssym@sina.com

简介

  鉴于基于划分的文本聚类方法只能识别球形的聚类,因此本文对基于密度的文本聚类算法展开研究。DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一种典型的基于密度的聚类方法,可以找出形状不规则的聚类,而且聚类时无需事先知道聚类的个数。

基本概念

  DBSCAN算法中有两个核心参数:Eps和MinPts(文献与程序中经常使用)。前者定义为邻域半径,后者定义为核心对象的阈值。本文为了描述方便,下文将Eps和MinPts分别简记为EM

  (1)   E 邻域:给定对象半径E内的区域成为该对象的E邻域。该E邻域为球形,其半径的界定可以采用距离(欧式距离)、余弦相似度、Word2Vec等表征,本文实现采用余弦相似度来表征。

  (2)   核心对象:若给定对象E 邻域内的对象(样本点)个数大于等于M,则称该对象为核心对象。

  (3)   直接密度可达:给定一个对象集合D,若对象p在q的E 邻域内,且q是一个核心对象,则称对象p从对象q出发是直接密度可达的(directly density-reachable)。

  (4)   密度可达:给定一个对象集合D,若存在一个对象链p1,p2,p3,...,pn,p1=q,pn=p,对于pi属于D,i属于1~n,p(i+1)是从pi关于EM直接密度可达的,则称对象p从对象q关于EM密度可达的。

  (5)   密度相连:给定一个对象集合D,若存在对象o属于D,使对象p和q均从o关于EM密度可达的,那么对于对象p到q是关于EM密度相连的。

  (6)   边界对象:给定一个对象集合D,若核心对象p中存在对象q,但是q对象自身并非核心对象,则称q为边界对象。

  (7)   噪声对象:给定一个对象集合D,若对象o既不是核心对象,也不是边界对象,则称o为噪声对象。

图1 集合对象

  如图1所示,其设定M=3,红色节点为核心对象,黄色节点为边界节点,蓝色为噪声节点。

  DBSCAN算法不仅能对对象进行聚类,同时还能识别噪声对象,即不属于任何一个聚类。需要指出:密度可达是直接密度可达的传递闭包,这种关系是非对称的,只有核心对象之间相互密度可达;但是,密度相连是一种对称的关系。

  DBSCAN的核心思想:寻找密度相连的最大集合,即从某个选定的核心对象(核心点)出发,不断向密度可达的区域扩张,从而得到一个包含核心对象和边界对象的最大化区域,区域中任意两点密度相连。

  算法伪代码(参考维基百科):

 DBSCAN(D, eps, MinPts) {
C =
for each point P in dataset D {
if P is visited
continue next point
mark P as visited
NeighborPts = regionQuery(P, eps)
if sizeof(NeighborPts) < MinPts
mark P as NOISE
else {
C = next cluster
expandCluster(P, NeighborPts, C, eps, MinPts)
}
}
} expandCluster(P, NeighborPts, C, eps, MinPts) {
add P to cluster C
for each point P' in NeighborPts {
if P' is not visited {
mark P' as visited
NeighborPts' = regionQuery(P', eps)
if sizeof(NeighborPts') >= MinPts
NeighborPts = NeighborPts joined with NeighborPts'
}
if P' is not yet member of any cluster
add P' to cluster C
}
} regionQuery(P, eps)
return all points within P's eps-neighborhood (including P)

  程序源代码如下:

 import java.util.List;

 import com.gta.cosine.ElementDict;

 public class DataNode {
private List<ElementDict> terms;
private boolean isVisited;
private int category; public DataNode(List<ElementDict> terms)
{
this.terms = terms;
this.isVisited = false;
this.category = 0;
} public void setVisitLabel(boolean isVisited)
{
this.isVisited = isVisited;
} public void setCatagory(int category)
{
this.category = category;
} public boolean getVisitLabel()
{
return isVisited;
} public int getCategory()
{
return category;
} public List<ElementDict> getAllElements()
{
return terms;
} }
 import java.util.List;
import java.util.ArrayList; import com.gta.cosine.TextCosine;
import com.gta.cosine.ElementDict; public class DBScan {
private double eps;
private int minPts;
private TextCosine cosine;
private int threshold;
private List<DataNode> dataNodes;
private int delta; public DBScan()
{
this.eps = 0.20;
this.minPts = 3;
this.threshold = 10000;
this.cosine = new TextCosine();
this.delta = 0;
dataNodes = new ArrayList<DataNode>();
} public DBScan(double eps, int minPts, int threshold)
{
this.eps = eps;
this.minPts = minPts;
this.threshold = threshold;
this.cosine = new TextCosine();
this.delta = 0;
dataNodes = new ArrayList<DataNode>();
} public void setThreshold(int threshold)
{
this.threshold = threshold;
} public int getThreshold()
{
return threshold;
} public double getEps()
{
return eps;
} public int getMinPts()
{
return minPts;
} public List<DataNode> getNeighbors(DataNode p, List<DataNode> nodes)
{
List<DataNode> neighbors = new ArrayList<DataNode>();
List<ElementDict> vec1 = p.getAllElements();
List<ElementDict> vec2 = null;
double countDistance = 0;
for (DataNode node : nodes)
{
vec2 = node.getAllElements();
countDistance = cosine.analysisText(vec1, vec2);
if (countDistance >= eps)
{
neighbors.add(node);
}
}
return neighbors;
} public List<DataNode> cluster(List<DataNode> nodes)
{
int category = 1;
for (DataNode node : nodes)
{
if (!node.getVisitLabel())
{
node.setVisitLabel(true);
List<DataNode> neighbors = getNeighbors(node, nodes);
if (neighbors.size() < minPts)
{
node.setCatagory(-1);
}
else
{
node.setCatagory(category);
expandCluster(neighbors, category, nodes);
}
}
category ++;
} return nodes;
} public void expandCluster(List<DataNode> neighbors, int category, List<DataNode> nodes)
{
for (DataNode node : neighbors)
{
if (!node.getVisitLabel())
{
node.setVisitLabel(true);
List<DataNode> newNeighbors = getNeighbors(node, nodes);
if (newNeighbors.size() >= minPts)
{
expandCluster(newNeighbors, category, nodes);
}
} if (node.getCategory() <= 0) // not be any of category
{
node.setCatagory(category);
}
}
} public void showCluster(List<DataNode> nodes)
{
for (DataNode node : nodes)
{
List<ElementDict> ed = node.getAllElements();
for (ElementDict e: ed)
{
System.out.print(e.getTerm() + " ");
}
System.out.println();
System.out.println("所属类别: "+ node.getCategory());
}
} public void addDataNode(String s)
{
List<ElementDict> ed = cosine.tokenizer(s);
DataNode dataNode = new DataNode(ed);
dataNodes.add(dataNode);
delta ++;
} public void analysis()
{
if (delta >= threshold)
{
showCluster(cluster(dataNodes));
delta = 0;
}
}
}

  关于计算余弦相似度及其源代码,见本系列之文本挖掘之文本相似度判定。本文考虑到随着文本数量的递增,文本聚类结果会分化,即刚开始聚类的文本与后面文本数据相差甚远,本文非常粗略地采用门限值进行限定,本文后续系列联合KMeans和DBSCAN进行解决,若有更好的方法,请联系我

  需要指出:DBSCAN算法对输入参数EM非常敏感,即参数稍有变化,其聚类结果则会有明显变化。此外,对EM的选择在实际应用中,需要大规模数据集调优选择(小数据集另当别论),同时对该算法进行改进也是重要研究方向。


  作者:志青云集
  出处:http://www.cnblogs.com/lyssym
  如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
  如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
  如果,您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是【志青云集】。
  本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。


文本挖掘之文本聚类(DBSCAN)的更多相关文章

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

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

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

    刘 勇  Email:lyssym@sina.com 简介 鉴于DBSCAN算法对输入参数,邻域半径E和阈值M比较敏感,在参数调优时比较麻烦,因此本文对另一种基于密度的聚类算法OPTICS(Order ...

  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. Android的基本常用的短信操作

    1.调用系统发送短信界面(传入手机号码+短信内容) 2.隐藏发送短信(指定号码指定内容)(这里隐藏只是没有反写入数据库) 3.获得收件箱接收到的短信 4.Android屏蔽新短信通知提示信息:(Con ...

  2. 在VS 2010上搭建Windows Phone 7开发平台

      如今Windows Phone 7平台越来越火了,刚刚拿到一款新的Windows Phone,于是准备在电脑上搭建WP7的开发环境. 首先,安装VS2010,升级到SP1,并安装Windows P ...

  3. 仿LOL项目开发第八天

    仿LOL项目开发第八天 by 草帽 这节我们继续上节所讲的内容,上节我们初始化好了LoginWindow,当我们点击确认选择服务器按钮的时候,就发送服务器id给游戏服务器. 这里就开始涉及到客户端需要 ...

  4. 在 Sublime Text 2 下开启 Vim 模式

    緣由 由於在 Sublime Text 2 下操作時會想起 Vim 下的鍵盤操作.一時興起在網絡上找了下,發現 Sublime Text 2 是支持類似 Vim 的鍵盤操作的.在此分享下配置過程. 打 ...

  5. SQLAlchemy 操作方法汇总

    参考 1.查询: #简单查询 print(session.query(User).all()) print(session.query(User.name, User.fullname).all()) ...

  6. 判断大小端的方法(java和c++)

    首先我们给出大小端的定义: 小端:较高的有效字节存放在较高的的存储器地址,较低的有效字节存放在较低的存储器地址. 大端:较高的有效字节存放在较低的存储器地址,较低的有效字节存放在较高的存储器地址. 将 ...

  7. JS 中数组字符串索引和数值索引研究

    先来看一个问题: var array = []; array["a"] = "hello"; array["b"] = "worl ...

  8. PHP实战 新闻管理系统 使用到了bootstrap框架

    刚刚接触 PHP 仿照视频 写了个新闻管理系统 当中也使用到了bootstrap框架 写下来整理一下思路. 这是个非常easy的系统.首先是建立数据库表. mysql>create databa ...

  9. java oracle thin 和 oci 连接方式实现多数据库的故障切换

    java oracle thin 和 oci 连接方式实现多数据库的故障切换 一.thin方式 该种方式简便易用非经常见. 当中URL为 jdbc:oracle:thin:@(DESCRIPTION= ...

  10. Endv 博客简介

    Endv 博客简介 此博客收集了 C++.Android.C#.java.php 等优秀的开源项目, 同时也对 Windows.Linux.CentOS 等系列操作系统的开发环境.办公环境的配置写了一 ...