摘要:昨天给大家演示简单的文本聚类,但要给每个聚类再提取一两个关键词用于表示该聚类。我们还是用TFIDF算法来做,因为这是比较简单的提取特征算法,不过这里的TF是指某词在本聚类内所有文章的词频,而不是本文章内出现的次数,IDF还是在所有文章里出现的倒文档频率。
原理:1、先给本聚类内的所有文档进行分词,然后用一个字典保存每个词出现的次数
2、遍历每个词,得到每个词在所有文档里的IDF值,和在本聚类内出现的次数(TF)相乘的值
3、用一个字典(key是词,value是TF*IDF权重)来保存所有的词信息,然后按value对字典排序,最后取权重排名靠前的几个词作为关键词

测试输入如下
================================
a 奥运 拳击 入场券 基本 分罄 邹市明 夺冠 对手 浮出 水面
a 股民 要 清楚 自己 的 目的
a 印花税 之 股民 四季
a ASP.NET 自定义 控件 复杂 属性 声明 持久性 浅析
a 运动员 行李 将 “后 上 先 下” 奥运 相关 人员 行李 实名制
a asp.net 控件 开发 显示 控件 内容
a 奥运 票务 网上 成功 订票 后 应 及时 到 银行 代售 网点 付款
a 某 心理 健康 站 开张 后 首 个 咨询 者 是 位 新 股民
a 残疾 女 青年 入围 奥运 游泳 比赛 创 奥运 历史 两 项 第一
a 介绍 一 个 ASP.net MVC 系列 教程
a 在 asp.net 中 实现 观察者 模式 ,或 有 更 好 的 方法 (续)
a 输 大钱 的 股民 给 我们 启迪
a Asp.Net 页面 执行 流程 分析
a 杭州 股民 放 鞭炮 庆祝 印花税 下调
================================
数据还是昨天的数据,但每个文章前面都加了个a,所以这个词的IDF肯定很低,如果单村用词频来提取关键词,这个a肯定被当场关键词了,所以要乘以IDF值来调整特征提取的精度。我们要用程序把上面的文档分成3类,并提取每个类的两个关键词

我给TFIDFMeasure类加了一个GetKeyword的方法,第一个参数是传入几个文档id列表,第二个参数是要在这几个文档里提取几个关键词,下面是使用该方法的代码

//4、初始化k-means算法,第一个参数表示输入数据,第二个参数表示要聚成几个类
WawaKMeans kmeans = new WawaKMeans(data, K);
//5、开始迭代
kmeans.Start();

//6、获取聚类结果并输出
WawaCluster[] clusters = kmeans.Clusters;
StringBuilder sb = new StringBuilder();
foreach (WawaCluster cluster in clusters)
{
    List<int> members = cluster.CurrentMembership;
   
    //获取该聚类的关键词并打印
    IEnumerable<string> keywords = tf.GetKeyword(cluster.CurrentMembership, 2);
    StringBuilder sbTemp = new StringBuilder();
    sbTemp.Append("---------");
    foreach (string s in keywords)
    {
        sbTemp.AppendFormat("{0},", s);
    }
    sbTemp.Append("-------\r\n");
    Console.WriteLine(sbTemp);

    //打印该聚类的成员
    sb.Append(sbTemp.ToString());
    foreach (int i in members)
    {
        Console.WriteLine(docs[i]);
        sb.AppendFormat("{0}\r\n", docs[i]);
    }
}

再看GetKeyword方法的实现

/**//// <summary>
/// 获取某组文档的关键词
/// </summary>
/// <param name="arr"></param>
/// <param name="count"></param>
/// <returns></returns>
public IEnumerable<string> GetKeyword(List<int> arr, int count)
{
    //1、给每个文档分词并保存在一个列表里
    List<string> allWords = new List<string>();
    foreach (int i in arr)
    {
      //这里把一个文档里出现的多个词进行消重
        allWords.AddRange(GetDistinctWords(_tokenizer.Partition(_docs[i])));
    }

    //2、用一个字典保存词的词频,key是词,value是重复次数
    Dictionary<string , int> tfDict = SortByDuplicateCount(allWords);

    //3、遍历已排序的词频字典,并获取每个词的IDF值,并把更新后的结果放入一个tfidfDict词典
    //该词典的key是词,value是tfidf值
    Dictionary<string,float> tfidfDict = new Dictionary<string, float>(tfDict.Count);
    foreach (KeyValuePair<string, int> pair in tfDict)
    {
        int tremIndex;
        if(_tremIndex.TryGetValue(pair.Key,out tremIndex))
        {
            float idf = GetInverseDocumentFrequency(tremIndex);
            tfidfDict.Add(pair.Key, pair.Value * idf);
        }
    }

    //4、给tfidf字典俺权重排序
    tfidfDict = GetSortByValueDict(tfidfDict);

    //5、更新要提取的关键词数量
    int keywordCount = count;
    if (keywordCount > tfidfDict.Count)
        keywordCount = tfidfDict.Count;
   
    //6、用一个数组保存tfidf字典的keys,这些key已排序
    string[] keywordArr = new string[tfidfDict.Count];
    tfidfDict.Keys.CopyTo(keywordArr,0);

    //7、在关键词数组里取出前几个关键词返回给调用者
    List<string> result = new List<string>(keywordCount);
    int tempCount = 0;
    foreach (string str in keywordArr)
    {
        tempCount++;
        result.Add(str);
        if(tempCount >=keywordCount) break;
    }
    return result;
}

这里面用到一个SortByDuplicateCount方法,是对一个集合里的元素按重复次数排序,输出一个字典,字典的key是原始元素,value是出现次数,并按出现次数从大到小排序,像 { "abcd", "ab", "b", "a", "abcd", "ab", "ab", "ab", "cd", "cd", "cd" }这样一个集合应该输入如下结果。
ab-4
cd-3
abcd-2
b-1
a-1
原理是先用一个字典计算每个元素的出现次数,然后把该字典按value的大小排序,下面是实现代码

/**//// <summary>
/// 把一个集合按重复次数排序
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="inputList"></param>
/// <returns></returns>
public static Dictionary<T, int> SortByDuplicateCount<T>(IList<T> inputList)
{
    //用于计算每个元素出现的次数,key是元素,value是出现次数
    Dictionary<T, int> distinctDict = new Dictionary<T, int>();
    for (int i = 0; i < inputList.Count; i++)
    {
        //这里没用trygetvalue,会计算两次hash
        if (distinctDict.ContainsKey(inputList[i]))
            distinctDict[inputList[i]]++;
        else
            distinctDict.Add(inputList[i], 1);
    }

    Dictionary<T, int> sortByValueDict = GetSortByValueDict(distinctDict);
    return sortByValueDict;
}

这里用到一个把一个字典按值的大小排序的方法GetSortByValueDict,代码如下,是泛型的

/**//// <summary>
/// 把一个字典俺value的顺序排序
/// </summary>
/// <typeparam name="K"></typeparam>
/// <typeparam name="V"></typeparam>
/// <param name="distinctDict"></param>
/// <returns></returns>
public static Dictionary<K, V> GetSortByValueDict<K,V>(IDictionary<K, V> distinctDict)
{
    //用于给tempDict.Values排序的临时数组
  V[] tempSortList = new V[distinctDict.Count];
  distinctDict.Values.CopyTo(tempSortList, 0);
  Array.Sort(tempSortList); //给数据排序
  Array.Reverse(tempSortList);//反转

  //用于保存按value排序的字典
  Dictionary<K, V> sortByValueDict =
      new Dictionary<K, V>(distinctDict.Count);
  for (int i = 0; i < tempSortList.Length; i++)
  {
      foreach (KeyValuePair<K, V> pair in distinctDict)
      {
            //比较两个泛型是否相当要用Equals,不能用==操作符
            if (pair.Value.Equals(tempSortList[i]) && !sortByValueDict.ContainsKey(pair.Key))
              sortByValueDict.Add(pair.Key, pair.Value);
      }
  }
  return sortByValueDict;
}

对一个文章内出现的多个词进行消重是因为如果一个文章里堆叠关键词会影响本聚类关键词提取的准确性,所以要排重,算法如下,也是泛型的

/**//// <summary>
/// 对一个数组进行排重
/// </summary>
/// <param name="scanKeys"></param>
/// <returns></returns>
public static IEnumerable<T> GetDistinctWords<T>(IEnumerable<T> scanKeys)
{
    T temp = default(T);
    if (scanKeys.Equals(temp))
        return new T[0];
    else
    {
        Dictionary<T, T> fixKeys = new Dictionary<T, T>();
        foreach (T key in scanKeys)
        {
            fixKeys[key] = key;
        }
        T[] result = new T[fixKeys.Count];
        fixKeys.Values.CopyTo(result, 0);
        return result;
    }
}

最后效果如下
Iteration 0...
Iteration 1...
---------asp,net,-------

a ASP.NET 自定义 控件 复杂 属性 声明 持久性 浅析
a asp.net 控件 开发 显示 控件 内容
a 介绍 一 个 ASP.net MVC 系列 教程
a 在 asp.net 中 实现 观察者 模式 ,或 有 更 好 的 方法 (续)
a Asp.Net 页面 执行 流程 分析
---------股民,印花税,-------

a 股民 要 清楚 自己 的 目的
a 印花税 之 股民 四季
a 某 心理 健康 站 开张 后 首 个 咨询 者 是 位 新 股民
a 输 大钱 的 股民 给 我们 启迪
a 杭州 股民 放 鞭炮 庆祝 印花税 下调
---------奥运,拳击,-------

a 奥运 拳击 入场券 基本 分罄 邹市明 夺冠 对手 浮出 水面
a 运动员 行李 将 “后 上 先 下” 奥运 相关 人员 行李 实名制
a 奥运 票务 网上 成功 订票 后 应 及时 到 银行 代售 网点 付款
a 残疾 女 青年 入围 奥运 游泳 比赛 创 奥运 历史 两 项 第一

可以看到,提取的关键字还是准确的,并没把a当成关键字。

蛙蛙推荐:蛙蛙牌关键词提取算法相关推荐

  1. KeyBert、TextRank等九种本文关键词提取算法(KPE)原理及代码实现

    关键词提取 (Keyphrase Extraction,KPE) 任务可以自动提取文档中能够概括核心内容的短语,有利于下游信息检索和 NLP 任务.当前,由于对文档进行标注需要耗费大量资源且缺乏大规模 ...

  2. 广告行业中那些趣事系列60:详解超好用的无监督关键词提取算法Keybert

    导读:本文是"数据拾光者"专栏的第六十篇文章,这个系列将介绍在广告行业中自然语言处理和推荐系统实践.本篇从理论到实践介绍了超好用的无监督关键词提取算法Keybert,对于希望使用无 ...

  3. 基于TextRank的关键词提取算法

    基于TextRank的关键词提取算法 前沿 TextRank是一种文本排序算法,是基于著名的网页排序算法PageRank改动而来.在介绍TextRank前,我们先简单介绍下什么是PageRank.另外 ...

  4. 关键词提取算法—TF/IDF算法

    关键词提取算法一般可分为有监督学习和无监督学习两类. 有监督的关键词提取方法可以通过分类的方式进行,通过构建一个较为完善的词表,然后判断每个文档与词表中的每个词的匹配程度,以类似打标签的方式,达到关键 ...

  5. 关键词提取算法TextRank

    很久以前,我用过TFIDF做过行业关键词提取.TFIDF仅仅从词的统计信息出发,而没有充分考虑词之间的语义信息.现在本文将介绍一种考虑了相邻词的语义关系.基于图排序的关键词提取算法TextRank. ...

  6. 关键词提取算法之RAKE

    关键词提取算法之RAKE RAKE(Rapid Automatic Keyword Extraction)算法,作者Alyona Medelyan,她的GitHub上有很多关键字提取的项目. RAKE ...

  7. java 文本分析 关键词提取_文本关键词提取算法总结

    1.TF-IDF 昨天给大家演示简单的文本聚类,但要给每个聚类再提取一两个关键词用于表示该聚类.我们还是用TFIDF算法来做,因为这是比较简单的提取特征算法,不过这里的TF是指某词在本聚类内所有文章的 ...

  8. TextRank关键词提取算法

    参考:百度AI Studio课程_学习成就梦想,AI遇见未来_AI课程 - 百度AI Studio - 人工智能学习与实训社区 (baidu.com) 1.关键词提取算法分类 1.有监督 将关键词提取 ...

  9. 自然语言处理TF-IDF关键词提取算法

    1.关键词提取简介 关键词是指能反映文本主题或者主要内容的词语.关键词提取就是从文本里面把跟这篇文档意义最相关的一些词抽取出来,是NLP领域的一个重要的子任务.在信息检索中,准确的关键词提取可以大幅提 ...

最新文章

  1. Go 中切片索引与 Python 中列表索引的差异
  2. C++ 把输出结果写入到文件中
  3. iView 3.3.0 发布,基于 Vue.js 的企业级 UI 组件库
  4. UA STAT687 线性模型II 最小二乘理论3 广义最小二乘
  5. boost::convert模块实现默认转换器的测试程序
  6. android studio 导入项目卡死,AndroidStudio导入新项目一直卡在Building gradle project info...
  7. 关于perl和shell的参数传递
  8. Puma单栏博客Typecho主题
  9. Queue 输出数据
  10. 【搞事情】从零开始做一个微信小程序
  11. 打印学生选课清单 (25 分)
  12. 测试游戏平均帧率的软件,游戏帧数,游戏帧数测试软件
  13. 360os比android,手机系统比拼360OS、Flyme究竟哪个好?
  14. Vagrant启动报错
  15. 云呐AIOps|智能运维管理平台解决服务器运维安全问题
  16. 当“珊瑚虫”遇到腾讯
  17. 小米设备打开了开发者选项和USB调试仍然无法安装成功的问题
  18. c# distinct用法
  19. CSDN新版个人空间介绍之三——代码与收藏
  20. 雅可比行列式和雅可比矩阵

热门文章

  1. 华为vrrp默认优先级_网关冗余VRRP
  2. 【逆向工程】在PE结构空白区段插入代码
  3. WZOI-314石头剪子布
  4. 手机:运行内存,机身内存,内存卡的区分
  5. springboot访问下载/resource/static下的静态资源;下载excel文件损坏,打不开
  6. 浏览器下载的excel文件损坏无法打开
  7. UltraEdit32常用快捷键
  8. 前端开发使用的 安卓模拟器_7个最佳的Android模拟器
  9. HTML+CSS仿写京东页面附代码(web前端大作业)
  10. unity入门2.0