×
文章路径: 数学与编程

余弦定理与新闻分类

发表于5个月前(Dec 23, 2019 11:47:00 AM)  阅读 196  评论 0

分类: 数学与编程

标签: 余弦定理 智能分类 分词

1、背景

有些新闻采集程序将各个网站的新闻采集过来,需要进行分类,尽管原新闻在原始网站是有分类的,但是由于每个网站的分类标准不同,类目列表也不同,无法同自己网站的类目进行一一对应,这时如果采集程序能给我们推荐分类目录,甚至自动分类那是最好不过了。其实新闻推荐分类算法早已不是稀奇的事,早在《数学之美》一书中就有过介绍,书中采用余弦定理进行新闻分类,在这里本文对该算法进行测试和实践。

2、新闻的特征向量

“同一类新闻用词都是相似的,不同类的新闻用词各不相同”。我们首先将新闻量化,找一组数字,或者向量来描述一篇新闻。在这里,笔者从腾讯新闻财经版块和体育版块中分别随机找了3篇文章(测试文章可以在代码仓库资源文件中找到)出来,我们先看第一篇文章:

全年商品房成交破15万亿元无悬念 高库存压力短期似消除

从数据来看,前11个月销售金额已接近14万亿元,而去年同期仅12.9万亿元。同时值得关注的是,房企在整个四季度“抢收”的现象依然十分普遍,因此预计商品房成交水平12月份或有可能超过11月份。

主持人陈炜:保持房地产市场稳定,是对宏观经济平稳健康发展的重要贡献。中央经济工作会议指出,全面落实因城施策,稳地价、稳房价、稳预期的长效管理调控机制,促进房地产市场平稳健康发展。今日,本报聚焦房地产市场发展动向,进行相关采访和解读。

本报记者 苏诗钰

今年以来,各地区各部门坚持“房住不炒”定位,一城一策、因城施策,落实房地产长效管理机制,不将房地产作为短期刺激经济的手段,保障了房地产市场总体稳定。

前不久召开的中央经济工作会议指出,要坚持房子是用来住的、不是用来炒的定位,全面落实因城施策,稳地价、稳房价、稳预期的长效管理调控机制,促进房地产市场平稳健康发展。

从数据可以看出,相关政策正在逐步落地。近日,国家统计局发布商品房销售和待售的数据显示,1月份至11月份,商品房销售面积148905万平方米,同比增长0.2%,增速比1月份至10月份加快0.1个百分点。其中,住宅销售面积增长1.6%,办公楼销售面积下降11.9%,商业营业用房销售面积下降14.1%。商品房销售额139006亿元,增长7.3%,增速持平。其中,住宅销售额增长10.7%,办公楼销售额下降11.3%,商业营业用房销售额下降13.5%。

11月末,商品房待售面积49221万平方米,比10月末减少102万平方米。其中,住宅待售面积减少92万平方米,办公楼待售面积增加15万平方米,商业营业用房待售面积增加4万平方米。

58安居客房产研究院分院院长张波12月19日在接受《证券日报》记者采访时表示,商品房成交破15万亿元已无悬念。从数据来看,前11个月销售金额已接近14万亿元,而去年同期仅12.9万亿元。同时值得关注的是,房企在整个四季度“抢收”的现象依然十分普遍,因此预计商品房成交水平12月份或有可能超过11月份,从销售金额增长速度来看,排名第一的是西部区域,西安、成都、重庆等热点城市的带动不可小觑。

诸葛找房市场研究员姜国君在接受《证券日报》记者采访时表示,开发商每到年底都面临诸多压力,如资金周转压力、业绩冲刺压力、改善公司基本面压力等,这时候以价换量是比较常规也比较有效的做法。近两个月也是如此,销量增速由负转正,库存逐渐减少与开发商的销售策略不无关系。

易居研究院智库中心研究总监严跃进12月19日在接受《证券日报》记者采访时表示,虽然当前市场认为房屋销售市场以降温为导向,但降温不代表下跌。从客观情况看,此前有部分购房者是观望状态,到了年底还是会因为降价促销而入市。今年11月份商品房待售面积同比跌幅为6.5%。这条曲线走势和预期是一致的,即继续下跌,但下跌的速度是越来越缓了。这说明库存方面的高库存压力开始解除,未来也要注意到库存数据重新反弹的可能。

第一步,我们对新闻进行分词,这里笔者使用IK进行分词,分词结果如下:

全年, 商品房, 成交, 破, 15, 万, 亿元, 悬念, 高, 库存, 压力, 短期, 似, 消除, 数据, 来看, 前, 11, 个月, 销售, 金额, 接近, 14, 万, 亿元, 去年同期, 仅, 12.9, 万, 亿元, 值得, 关注, 房, 企, 整个, 四季度, 抢收, 现象, 依然, 十分, 普遍, 预计, 商品房, 成交, 水平, 12月份, 或有, 可能, 超过, 11月份, 主持人, 陈, 炜, 保持, 房地产, 市场, 稳定, 宏观经济, 平稳, 健康发展, 重要贡献, 中央, 经济, 工作会议, 指出, 全面落实, 城, 施, 策, 稳, 地价, 稳, 房价, 稳, 预期, 长效, 管理, 调控, 机制, 促进, 房地产, 市场, 平稳, 健康发展, 今日, 本报, 聚焦, 房地产, 市场, 发展, 动向, 进行, 相关, 采访, 解读, 本报记者, 苏, 诗, 钰, 今年以来, 各地区, 各部门, 坚持, 房, 住, 炒, 定位, 城, 策, 城, 施, 策, 落实, 房地产, 长效, 管理机制, 不将, 房地产, 短期, 刺激, 经济, 手段, 保障, 房地产, 市场, 总体, 稳定, 前不久, 召开, 中央, 经济, 工作会议, 指出, 坚持, 房子, 住, 炒, 定位, 全面落实, 城, 施, 策, 稳, 地价, 稳, 房价, 稳, 预期, 长效, 管理, 调控, 机制, 促进, 房地产, 市场, 平稳, 健康发展, 数据, 看出, 相关, 政策, 正在, 落地, 近日, 国家统计局, 发布, 商品房, 销售, 待售, 数据, 显示, 1月份, 11月份, 商品房, 销售, 面积, 148905万平方米, 同比, 增长, 0.2, 增, 速比, 1月份, 10月份, 加快, 0.1个, 百分点, 住宅, 销售, 面积, 增长, 1.6, 办公楼, 销售, 面积, 下降, 11.9, 商业, 营业, 用房, 销售, 面积, 下降, 14.1, 商品房, 销售额, 139006, 亿元, 增长, 7.3, 增速, 持平, 住宅, 销售额, 增长, 10.7, 办公楼, 销售额, 下降, 11.3, 商业, 营业, 用房, 销售额, 下降, 13.5, 11, 月末, 商品房, 待售, 面积, 49221万平方米, 10, 月末, 减少, 102万平方米, 住宅, 待售, 面积, 减少, 92万平方米, 办公楼, 待售, 面积, 增加, 15万平方米, 商业, 营业, 用房, 待售, 面积, 增加, 4万平方米, 58, 安居, 客, 房产, 研究院, 分院, 院长, 张, 波, 12月, 19日, 接受, 证券日报, 记者, 采访, 时, 表示, 商品房, 成交, 破, 15, 万, 亿元, 已无, 悬念, 数据, 来看, 前, 11, 个月, 销售, 金额, 接近, 14, 万, 亿元, 去年同期, 仅, 12.9, 万, 亿元, 值得, 关注, 房, 企, 整个, 四季度, 抢收, 现象, 依然, 十分, 普遍, 预计, 商品房, 成交, 水平, 12月份, 或有, 可能, 超过, 11月份, 销售, 金额, 增长速度, 来看, 排名, 第一, 西部, 区域, 西安, 成都, 重庆, 热点, 城市, 带动, 不可, 小觑, 诸葛, 找, 房市场, 研究员, 姜, 国君, 接受, 证券日报, 记者, 采访, 时, 表示, 开发商, 每到, 年底, 面临, 诸多, 压力, 资金周转, 压力, 业绩, 冲刺, 压力, 改善, 公司, 基本面, 压力, 这时候, 价, 换, 量, 比较, 常规, 比较, 有效, 做法, 近, 两个月, 也是, 销量, 增速, 负, 转正, 库存, 逐渐, 减少, 开发商, 销售策略, 不无关系, 易, 居, 研究院, 智, 库, 中心, 研究, 总监, 严, 跃进, 12月, 19日, 接受, 证券日报, 记者, 采访, 时, 表示, 当前, 市场, 认为, 房屋, 销售市场, 降温, 导向, 降温, 代表, 下跌, 客观情况, 此前, 部分, 购房者, 观望, 状态, 到了, 年底, 会, 降价, 促销, 入市, 今年, 11月份, 商品房, 待售, 面积, 同比, 跌幅, 6.5, 这条, 曲线, 走势, 预期, 一致, 继续, 下跌, 下跌, 速度, 越来越, 缓了, 这说明, 库存, 方面, 高, 库存, 压力, 解除, 未来, 也要, 注意到, 库存, 数据, 重新, 反弹, 可能

这里,我们去掉了一些常见的虚词、语气助词等,这样可以提高我们分类的准确率。然后,我们计算每个词出现的频率,用频率作为该次的权重:

宏观经济=1, 曲线=1, 聚焦=1, 状态=1, 全年=1, 业绩=1, 公司=1, 万=6, 部分=1, 逐渐=1, 研究院=2, 易=1, 调控=2, 销售额=4, 个月=2, 用房=3, 这说明=1, 住宅=3, 10=1, 11=3, 比较=2, 14=2, 15=2, 近日=1, 已无=1, 严=1, 正在=1, 减少=3, 平稳=3, 商品房=9, 机制=2, 全面落实=2, 稳=6, 诸多=1, 破=2, 销售=8, 7.3=1, 房=3, 10.7=1, 看出=1, 待售=6, 增长速度=1, 房产=1, 记者=3, 居=1, 陈=1, 各地区=1, 客观情况=1, 各部门=1, 来看=3, 重庆=1, 每到=1, 前=2, 注意到=1, 经济=3, 今日=1, 92万平方米=1, 这时候=1, 保障=1, 发布=1, 降价=1, 第一=1, 到了=1, 动向=1, 主持人=1, 研究员=1, 基本面=1, 解读=1, 跃进=1, 亿元=7, 两个月=1, 促进=2, 管理机制=1, 总体=1, 速度=1, 销售策略=1, 压力=6, 智=1, 6.5=1, 找=1, 0.1个=1, 落地=1, 营业=3, 常规=1, 管理=2, 房市场=1, 房地产=7, 炒=2, 库=1, 房价=2, 成交=4, 炜=1, 召开=1, 增=1, 58=1, 中央=2, 增长=4, 年底=2, 发展=1, 钰=1, 显示=1, 水平=2, 国君=1, 今年以来=1, 排名=1, 这条=1, 19日=2, 现象=2, 接近=2, 冲刺=1, 悬念=2, 仅=2, 方面=1, 手段=1, 采访=4, 刺激=1, 保持=1, 苏=1, 值得=2, 高=2, 抢收=2, 短期=2, 重要贡献=1, 销量=1, 接受=3, 面积=9, 成都=1, 波=1, 今年=1, 可能=3, 继续=1, 1月份=2, 坚持=2, 研究=1, 四季度=2, 十分=2, 健康发展=3, 解除=1, 超过=2, 12月份=2, 本报=1, 价=1, 定位=2, 139006=1, 房子=1, 金额=3, 证券日报=3, 面临=1, 企=2, 12月=2, 反弹=1, 认为=1, 也要=1, 预期=3, 去年同期=2, 落实=1, 分院=1, 会=1, 负=1, 张=1, 销售市场=1, 15万平方米=1, 下跌=3, 库存=5, 月末=2, 14.1=1, 依然=2, 11月份=4, 入市=1, 整个=2, 148905万平方米=1, 102万平方米=1, 似=1, 中心=1, 加快=1, 同比=2, 带动=1, 增速=2, 住=2, 院长=1, 当前=1, 有效=1, 策=4, 西部=1, 走势=1, 热点=1, 换=1, 此前=1, 转正=1, 本报记者=1, 改善=1, 降温=2, 诸葛=1, 市场=6, 相关=2, 10月份=1, 未来=1, 13.5=1, 速比=1, 观望=1, 不可=1, 购房者=1, 预计=2, 不将=1, 重新=1, 普遍=2, 国家统计局=1, 促销=1, 不无关系=1, 商业=3, 持平=1, 4万平方米=1, 导向=1, 49221万平方米=1, 客=1, 下降=4, 小觑=1, 做法=1, 资金周转=1, 百分点=1, 1.6=1, 也是=1, 12.9=2, 长效=3, 施=3, 或有=2, 进行=1, 表示=3, 稳定=2, 工作会议=2, 增加=2, 地价=2, 城=4, 量=1, 消除=1, 近=1, 诗=1, 安居=1, 前不久=1, 姜=1, 缓了=1, 关注=2, 指出=2, 房屋=1, 跌幅=1, 办公楼=3, 区域=1, 代表=1, 越来越=1, 数据=5, 11.3=1, 0.2=1, 时=3, 开发商=2, 总监=1, 政策=1, 西安=1, 11.9=1, 一致=1, 城市=1

这篇新闻现在已经可以由一个向量来表示了(1,1,1.......),词语为坐标轴,出现的频率为坐标值。

3、余弦定理

如何判断两篇文章的相似程度?如果两篇文章对应的向量方向一致,说明两篇文章相似,如果方向不一致,说明文章相似度不高,所以我们可以通过两个向量的夹角来判断两篇文章的相似度,计算向量的夹角,这里就用到了余弦定理。

根据余弦定理:

因为余弦值在0到1之间,如果余弦值越接近1,说明两者相似度越高。

另,因为两篇文章的词汇量不一致,可能A文章是m维向量,B文章是n维向量,所以我们要先将两篇文章的词汇量取并集,在同一向量空间进行计算。

4、代码实现

package com.cangzhitao.lesson.news_smart_classified;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.StringReader;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wltea.analyzer.cfg.Configuration;
import org.wltea.analyzer.cfg.DefaultConfig;
import org.wltea.analyzer.core.IKSegmenter;
import org.wltea.analyzer.core.Lexeme;

public class CosinCalc {

	private static final Logger logger = LoggerFactory.getLogger(CosinCalc.class);

	public static void main(String[] args) {
		System.out.println(calcNews("new.txt", "new1.txt"));
		System.out.println(calcNews("new.txt", "new2.txt"));
		System.out.println(calcNews("new.txt", "new3.txt"));
		System.out.println(calcNews("new.txt", "new4.txt"));
		System.out.println(calcNews("new.txt", "new5.txt"));
		System.out.println(calcNews("new.txt", "new6.txt"));
	}
	
	public static Double calcNews(String new1, String new2) {
		String text1 = readFromFile(CosinCalc.class.getClassLoader().getResource(new1).getPath());
		Map<String, Integer> map1 = calcFrequency(text1);
		
		String text2 = readFromFile(CosinCalc.class.getClassLoader().getResource(new2).getPath());
		Map<String, Integer> map2 = calcFrequency(text2);
		return calcCosin(map1, map2);
	}

	/**
	 * 读取文本
	 * @param path
	 * @return
	 */
	public static String readFromFile(String path) {
		File file = new File(path);
		try (FileReader fr = new FileReader(file); BufferedReader br = new BufferedReader(fr);) {
			StringBuilder sb = new StringBuilder();
			String temp = null;
			while ((temp = br.readLine()) != null) {
				sb.append(temp);
				sb.append(System.lineSeparator());
			}
			return sb.toString();
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			return null;
		}
	}
	
	/**
	 * 对文章进行分词,并计算词频
	 * @param text
	 * @return
	 */
	public static Map<String, Integer> calcFrequency(String text) {
	    try {
	    	Map<String, Integer> map = new HashMap<>();
	    	if (text == null || "".equals(text.trim())) {
	    		return map;
	    	}
	    	Configuration con = DefaultConfig.getInstance();
	    	con.setUseSmart(true);
	    	IKSegmenter ik = new IKSegmenter(new StringReader(text), con);
	    	List<String> list = new ArrayList<>();
	        Lexeme word = null;
	        while((word=ik.next())!=null) {      
	        	list.add(word.getLexemeText());
	        }
	        list.stream().forEach(temp -> map.put(temp, map.getOrDefault(temp, 0) + 1));
	        return map;
	    } catch (Exception e) {
			logger.error(e.getMessage(), e);
			return new HashMap<>();
		}
	}
	
	/**
	 * 计算余弦值
	 * @param map1
	 * @param map2
	 * @return
	 */
	public static double calcCosin(Map<String, Integer> map1, Map<String, Integer> map2) {
		//如果两者都为空,则认为两者完全一致
		if (map1.isEmpty() && map2.isEmpty()) {
			return 0d;
		//如果两者有一者为空,则认为两者完全不一致
		} else if (map1.isEmpty() || map2.isEmpty()) {
			return 1d;
		}
		// 存储词汇量并集
		Set<String> set = new HashSet<>();
		set.addAll(map1.keySet());
		set.addAll(map2.keySet());
		
		Iterator<String> it = set.iterator();
		
		//获取两者特征量
		List<Integer> list1 = new ArrayList<>();
		List<Integer> list2 = new ArrayList<>();
		while(it.hasNext()) {
			String word = it.next();
			if (map1.get(word) != null) {
				list1.add(map1.get(word));
			} else {
				list1.add(0);
			}
			if (map2.get(word) != null) {
				list2.add(map2.get(word));
			} else {
				list2.add(0);
			}
		}
		//向量积
		Double ab = 0d;
		//a,b向量长度
		Double a = 0d;
		Double b =  0d;
		for (int i = 0; i < list1.size(); i++) {
			ab +=  list1.get(i) * list2.get(i);
			a += list1.get(i) * list1.get(i);
			b += list2.get(i) * list2.get(i);
		}
		a = Math.sqrt(a);
		b = Math.sqrt(b);
		return BigDecimal.valueOf(ab).divide(BigDecimal.valueOf(a * b), 6, BigDecimal.ROUND_HALF_UP).doubleValue();
	}

}

这里笔者又从体育版块中随机选了一篇文章作为未分类的文章,分别计算和6篇已经分类的文章的余弦值,计算结果如下:

0.024358

0.015068

0.009885

0.217838

0.087219

0.070748

可以看到,目标文章和第四篇文章的余弦值最高,所以理应跟第四篇文章归为一类,进一步我们可以发现,第四篇文章是篮球,第五第六篇文章是足球类的,目标文章是足球类的新闻,余弦值的大小,确实反映出了几篇文章的相关度。

5、扩展

在这里,我们假设我们已经对一些新闻分好了类,已经有了一些新闻样本,在实际分类的时候,我们可以从每个分类中取出几篇文章来跟目标文章计算余弦值,从而确定分类。

除了对新闻可以推荐分类,同样的,我们可以想到对各电商平台的商品进行分类。淘宝平台商品细类达6w多个,京东平台商品细类也差不多有5k多个,如果对商品做采集,也可以采用该种方式进行智能分类。一般地,为了使分类更加准确,我们需要采集尽可能多的信息,尽可能有用的信息。商品详情,大部分都是一些图片描述,这时,我们需要将图片进行OCR识别,提取出文字信息。

对于相似度的计算,我们这里采用的是余弦定理,余弦定理比较好理解,计算也简单,其实除了余弦定理,我们还有很多别的计算相似度的算法,如:闵可夫斯基距离,曼哈顿距离,欧式距离,切比雪夫距离,马氏距离等等。不同的场景,可能采用不同的算法能达到最优的效果,这需要具体实践分析。

代码路径:https://github.com/www15119258/czt-lesson/tree/master/news-smart-classified

发表评论