├── img ├── 课程.png ├── dadeng.png ├── wordcloud.png ├── wordshiftor.png ├── 大邓和他的Python.png └── 词云图测试.html ├── cntext ├── dictionary │ ├── __init__.py │ └── README.md ├── stats │ ├── __init__.py │ └── stats.py ├── similarity │ ├── __init__.py │ ├── README.md │ └── similarity.py ├── visualization │ ├── __init__.py │ └── visualization.py ├── sentiment │ ├── __init__.py │ └── sentiment.py └── __init__.py ├── examples ├── data │ └── w2v_seeds │ │ ├── respect.txt │ │ ├── teamwork.txt │ │ ├── quality.txt │ │ ├── innovation.txt │ │ └── integrity.txt ├── output │ └── w2v_candi_words │ │ ├── teamwork.txt │ │ └── integrity.txt ├── 02-统计信息.ipynb ├── 05-文本相似.ipynb ├── 03-扩充词典.ipynb ├── 04-情感计算.ipynb ├── 01-cntext.ipynb └── 06-可视化.ipynb ├── setup.py └── README.md /img/课程.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhw3051/cntext/HEAD/img/课程.png -------------------------------------------------------------------------------- /cntext/dictionary/__init__.py: -------------------------------------------------------------------------------- 1 | from cntext.dictionary.dictionary import * 2 | -------------------------------------------------------------------------------- /cntext/stats/__init__.py: -------------------------------------------------------------------------------- 1 | from cntext.stats.stats import term_freq, readability -------------------------------------------------------------------------------- /img/dadeng.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhw3051/cntext/HEAD/img/dadeng.png -------------------------------------------------------------------------------- /cntext/similarity/__init__.py: -------------------------------------------------------------------------------- 1 | from cntext.similarity.similarity import similarity_score -------------------------------------------------------------------------------- /img/wordcloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhw3051/cntext/HEAD/img/wordcloud.png -------------------------------------------------------------------------------- /img/wordshiftor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhw3051/cntext/HEAD/img/wordshiftor.png -------------------------------------------------------------------------------- /img/大邓和他的Python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhw3051/cntext/HEAD/img/大邓和他的Python.png -------------------------------------------------------------------------------- /cntext/visualization/__init__.py: -------------------------------------------------------------------------------- 1 | from cntext.visualization.visualization import wordcloud, wordshiftor -------------------------------------------------------------------------------- /examples/data/w2v_seeds/respect.txt: -------------------------------------------------------------------------------- 1 | respectful 2 | talent 3 | talented 4 | employee 5 | dignity 6 | empowerment 7 | empower -------------------------------------------------------------------------------- /cntext/sentiment/__init__.py: -------------------------------------------------------------------------------- 1 | from cntext.sentiment.sentiment import senti_by_dutir, senti_by_hownet, senti_by_diydict, init_jieba 2 | -------------------------------------------------------------------------------- /examples/data/w2v_seeds/teamwork.txt: -------------------------------------------------------------------------------- 1 | teamwork 2 | collaboration 3 | collaborate 4 | collaborative 5 | cooperation 6 | cooperate 7 | cooperative -------------------------------------------------------------------------------- /examples/data/w2v_seeds/quality.txt: -------------------------------------------------------------------------------- 1 | quality 2 | customer 3 | customer_commitment 4 | dedication 5 | dedicated 6 | dedicate 7 | customer_expectation -------------------------------------------------------------------------------- /examples/data/w2v_seeds/innovation.txt: -------------------------------------------------------------------------------- 1 | innovation 2 | innovate 3 | innovative 4 | creativity 5 | creative 6 | create 7 | passion 8 | passionate 9 | efficiency 10 | efficient 11 | excellence 12 | pride -------------------------------------------------------------------------------- /examples/data/w2v_seeds/integrity.txt: -------------------------------------------------------------------------------- 1 | integrity 2 | ethic 3 | ethical 4 | accountable 5 | accountability 6 | trust 7 | honesty 8 | honest 9 | honestly 10 | fairness 11 | responsibility 12 | responsible 13 | transparency 14 | transparent -------------------------------------------------------------------------------- /cntext/__init__.py: -------------------------------------------------------------------------------- 1 | from cntext.dictionary import * 2 | from cntext.sentiment import senti_by_dutir, senti_by_hownet, senti_by_diydict, init_jieba 3 | from cntext.similarity import similarity_score 4 | from cntext.stats import term_freq, readability 5 | from cntext.visualization import wordcloud, wordshiftor 6 | 7 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | import setuptools 3 | 4 | setup( 5 | name='cntext', # 包名字 6 | version='0.9', # 包版本 7 | description='中文文本分析库,可对文本进行词频统计、词典扩充、情绪分析、相似度、可读性等', # 简单描述 8 | author='大邓', # 作者 9 | author_email='thunderhit@qq.com', # 邮箱 10 | url='https://github.com/thunderhit/cntext', # 包的主页 11 | packages=setuptools.find_packages(), 12 | install_requires=['jieba', 'numpy', 'scikit-learn==1.0', 'numpy', 'matplotlib', 'pyecharts', 'shifterator'], 13 | python_requires='>=3.5', 14 | license="MIT", 15 | keywords=['chinese', 'text mining', 'sentiment', 'sentiment analysis', 'natural language processing', 'sentiment dictionary development', 'text similarity'], 16 | long_description=open('README.md').read(), # 读取的Readme文档内容 17 | long_description_content_type="text/markdown") # 指定包文档格式为markdown 18 | #py_modules = ['eventextraction.py'] 19 | -------------------------------------------------------------------------------- /examples/output/w2v_candi_words/teamwork.txt: -------------------------------------------------------------------------------- 1 | teamwork 2 | collaboration 3 | collaborate 4 | collaborative 5 | cooperation 6 | cooperate 7 | cooperative 8 | submissions 9 | conduct 10 | collaborations 11 | nda 12 | alamos 13 | tigit 14 | backbone 15 | subsequently 16 | toxicology 17 | governance 18 | tolerability 19 | ipafricept 20 | svi 21 | compounds 22 | cooperative 23 | 1003 24 | pd1 25 | oncomed 26 | clia 27 | proof 28 | assisting 29 | reel-to-reel 30 | best-in-class 31 | pivotal 32 | interaction 33 | monotherapy 34 | crm 35 | anti-tigit 36 | opt 37 | 3454 38 | comprehensive 39 | establishing 40 | interactive 41 | innovent 42 | non-small 43 | investigative 44 | in-depth 45 | specs 46 | regarded 47 | bispecific 48 | predictive 49 | inhibitors 50 | distributes 51 | investigation 52 | roche 53 | teach 54 | anti-pd1 55 | contacts 56 | militaries 57 | reel 58 | gem 59 | fluor 60 | adopt 61 | inviting 62 | vantictumab 63 | expose 64 | biologic 65 | certification 66 | dispensing 67 | clinic 68 | apc 69 | gitr 70 | communist 71 | celgene 72 | medications 73 | intermediaries 74 | enargas 75 | primes 76 | integral 77 | authority 78 | measuring 79 | freightliner 80 | synchronized 81 | accessible 82 | bayer 83 | independently 84 | listeners 85 | dystrophin 86 | unanimous 87 | proof-of-concept 88 | proceeding 89 | records 90 | alzheimer 91 | seamless 92 | c-12 93 | stakeholders 94 | oversight 95 | coalition 96 | examining 97 | engagement 98 | gsk 99 | motor 100 | jewelfish 101 | pre-ind 102 | managements 103 | modify 104 | attorneys 105 | compliant 106 | venue 107 | instructed 108 | -------------------------------------------------------------------------------- /examples/output/w2v_candi_words/integrity.txt: -------------------------------------------------------------------------------- 1 | integrity 2 | ethic 3 | ethical 4 | accountable 5 | accountability 6 | trust 7 | honesty 8 | honest 9 | honestly 10 | fairness 11 | responsibility 12 | responsible 13 | transparency 14 | transparent 15 | win-win 16 | threat 17 | stakeholders 18 | advice 19 | dissatisfaction 20 | ecosystem 21 | imbalances 22 | integral 23 | reputable 24 | knowledgeable 25 | mindset 26 | professionals 27 | seriously 28 | trusted 29 | intermediaries 30 | responsibility 31 | durability 32 | assistant 33 | deserves 34 | embrace 35 | examine 36 | urge 37 | uniquely 38 | blockchain 39 | friendly 40 | manifested 41 | ourself 42 | redefined 43 | attracting 44 | deeply 45 | specs 46 | inviting 47 | marketers 48 | bottlers 49 | command-and-control 50 | gigantic 51 | oversight 52 | experts 53 | reward 54 | enterprises 55 | attracted 56 | examination 57 | intelligence 58 | reinforce 59 | responsible 60 | educate 61 | engage 62 | workflow 63 | embraced 64 | legitimate 65 | lies 66 | investigate 67 | clever 68 | powerlistings 69 | hr 70 | terror 71 | blame 72 | chose 73 | involves 74 | adopt 75 | incentivized 76 | refocusing 77 | eager 78 | approached 79 | domain 80 | spirit 81 | karat 82 | thrive 83 | beverages 84 | merits 85 | emotional 86 | retailing 87 | reassessed 88 | seamless 89 | advantageous 90 | holistic 91 | viability 92 | selecting 93 | technological 94 | tailor 95 | alignment 96 | in-depth 97 | sponsor 98 | align 99 | fuels 100 | definitively 101 | venue 102 | examining 103 | audiences 104 | credentials 105 | engaging 106 | governance 107 | handled 108 | server-to-server 109 | disdainful 110 | motivation 111 | intrinsic 112 | subsequently 113 | humanly 114 | peace 115 | -------------------------------------------------------------------------------- /cntext/visualization/visualization.py: -------------------------------------------------------------------------------- 1 | import pyecharts.options as opts 2 | from pyecharts.charts import WordCloud 3 | from cntext.stats.stats import term_freq 4 | from shifterator import EntropyShift 5 | 6 | 7 | def wordcloud(text, title, html_path): 8 | """ 9 | 使用pyecharts库绘制词云图 10 | :param text: 中文文本字符串数据 11 | :param title: 词云图标题 12 | :param html_path: 词云图html文件存储路径 13 | :return: 14 | """ 15 | wordfreq_dict = dict(term_freq(text)) 16 | wordfreqs = [(word, str(freq)) for word, freq in wordfreq_dict.items()] 17 | wc = WordCloud() 18 | wc.add(series_name="", data_pair=wordfreqs, word_size_range=[20, 100]) 19 | wc.set_global_opts( 20 | title_opts=opts.TitleOpts(title=title, 21 | title_textstyle_opts=opts.TextStyleOpts(font_size=23) 22 | ), 23 | tooltip_opts=opts.TooltipOpts(is_show=True)) 24 | wc.render(html_path) #存储位置 25 | print('可视化完成,请前往 {} 查看'.format(html_path)) 26 | 27 | 28 | 29 | 30 | def wordshiftor(text1, text2, title, top_n=50, matplotlib_family='Arial Unicode MS'): 31 | """ 32 | 使用shifterator库绘制词移图,可用于查看两文本在词语信息熵上的区别 33 | :param text1: 文本数据1;字符串 34 | :param text2: 文本数据2;字符串 35 | :param title: 词移图标题 36 | :param top_n: 显示最常用的前n词; 默认值15 37 | :param matplotlib_family matplotlib中文字体,默认"Arial Unicode MS";如绘图字体乱码请,请参考下面提示 38 | 39 | 设置参数matplotlib_family,需要先运行下面代码获取本机字体列表 40 | from matplotlib.font_manager import FontManager 41 | mpl_fonts = set(f.name for f in FontManager().ttflist) 42 | print(mpl_fonts) 43 | """ 44 | import matplotlib 45 | matplotlib.rc("font", family=matplotlib_family) 46 | type2freq_1 = term_freq(text1) 47 | 48 | type2freq_2 = term_freq(text2) 49 | 50 | entropy_shift = EntropyShift(type2freq_1=type2freq_1, 51 | type2freq_2=type2freq_2, 52 | base=2) 53 | entropy_shift.get_shift_graph(title=title, top_n=top_n) 54 | 55 | -------------------------------------------------------------------------------- /cntext/stats/stats.py: -------------------------------------------------------------------------------- 1 | from cntext.dictionary.dictionary import ADV_words, CONJ_words, STOPWORDS_zh 2 | import re 3 | import jieba 4 | from collections import Counter 5 | import numpy as np 6 | 7 | 8 | def term_freq(text): 9 | text = ''.join(re.findall('[\u4e00-\u9fa5]+', text)) 10 | words = jieba.lcut(text) 11 | words = [w for w in words if w not in STOPWORDS_zh] 12 | return Counter(words) 13 | 14 | 15 | 16 | def readability(text, language='chinese'): 17 | """ 18 | 文本可读性,指标越大,文章复杂度越高,可读性越差。 19 | ------------ 20 | 【英文可读性】公式 4.71 x (characters/words) + 0.5 x (words/sentences) - 21.43; 21 | 【中文可读性】 参考自 【徐巍,姚振晔,陈冬华.中文年报可读性:衡量与检验[J].会计研究,2021(03):28-44.】 22 | readability1 ---每个分句中的平均字数 23 | readability2 ---每个句子中副词和连词所占的比例 24 | readability3 ---参考Fog Index, readability3=(readability1+readability2)×0.5 25 | 以上三个指标越大,都说明文本的复杂程度越高,可读性越差。 26 | 27 | """ 28 | if language=='english': 29 | text = text.lower() 30 | num_of_characters = len(text) 31 | num_of_words = len(text.split(" ")) 32 | num_of_sentences = len(re.split('[\.!\?\n;]+', text)) 33 | ari = ( 34 | 4.71 * (num_of_characters / num_of_words) 35 | + 0.5 * (num_of_words / num_of_sentences) 36 | - 21.43 37 | ) 38 | 39 | return {"readability": ari} 40 | if language=='chinese': 41 | adv_conj_words = set(ADV_words+CONJ_words) 42 | zi_num_per_sent = [] 43 | adv_conj_ratio_per_sent = [] 44 | sentences = re.split('[\.。!!?\?\n;;]+', text) 45 | for sent in sentences: 46 | adv_conj_num = 0 47 | zi_num_per_sent.append(len(sent)) 48 | words = jieba.lcut(sent) 49 | for w in words: 50 | if w in adv_conj_words: 51 | adv_conj_num+=1 52 | adv_conj_ratio_per_sent.append(adv_conj_num/len(words)) 53 | readability1 = np.mean(zi_num_per_sent) 54 | readability2 = np.mean(adv_conj_ratio_per_sent) 55 | readability3 = (readability1+readability2)*0.5 56 | return {'readability1': readability1, 57 | 'readability2': readability2, 58 | 'readability3': readability3} 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /cntext/similarity/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | # simtext 6 | 7 | simtext可以计算两文档间四大文本相似性指标,分别为: 8 | 9 | - Sim_Cosine cosine相似性 10 | - Sim_Jaccard Jaccard相似性 11 | - Sim_MinEdit 最小编辑距离 12 | - Sim_Simple 微软Word中的track changes 13 | 14 | 具体算法介绍可翻看Cohen, Lauren, Christopher Malloy&Quoc Nguyen(2018) 第60页 15 | 16 | ![](img/论文中的公式.png) 17 | 18 | ### 安装 19 | 20 | ``` 21 | pip install simtext 22 | ``` 23 | 24 | ### 使用 25 | 26 | 中文文本相似性 27 | 28 | ```python 29 | from simtext import similarity 30 | 31 | text1 = '在宏观经济背景下,为继续优化贷款结构,重点发展可以抵抗经济周期不良的贷款' 32 | text2 = '在宏观经济背景下,为继续优化贷款结构,重点发展可三年专业化、集约化、综合金融+物联网金融四大金融特色的基础上' 33 | 34 | sim = similarity() 35 | res = sim.compute(text1, text2) 36 | print(res) 37 | ``` 38 | 39 | Run 40 | 41 | ``` 42 | {'Sim_Cosine': 0.46475800154489, 43 | 'Sim_Jaccard': 0.3333333333333333, 44 | 'Sim_MinEdit': 29, 45 | 'Sim_Simple': 0.9889595182335229} 46 | ``` 47 | 48 | 49 | 50 | 英文文本相似性 51 | 52 | ```python 53 | from simtext import similarity 54 | 55 | A = 'We expect demand to increase.' 56 | B = 'We expect worldwide demand to increase.' 57 | C = 'We expect weakness in sales' 58 | 59 | sim = similarity() 60 | AB = sim.compute(A, B) 61 | AC = sim.compute(A, C) 62 | 63 | print(AB) 64 | print(AC) 65 | ``` 66 | 67 | Run 68 | 69 | ``` 70 | {'Sim_Cosine': 0.9128709291752769, 71 | 'Sim_Jaccard': 0.8333333333333334, 72 | 'Sim_MinEdit': 2, 73 | 'Sim_Simple': 0.9545454545454546} 74 | 75 | {'Sim_Cosine': 0.39999999999999997, 76 | 'Sim_Jaccard': 0.25, 77 | 'Sim_MinEdit': 4, 78 | 'Sim_Simple': 0.9315789473684211} 79 | 80 | ``` 81 | 82 | 83 | 84 | ### 参考文献 85 | 86 | Cohen, Lauren, Christopher Malloy, and Quoc Nguyen. *Lazy prices*. No. w25084. National Bureau of Economic Research, 2018. 87 | 88 | ## 如果 89 | 90 | 如果您是经管人文社科专业背景,编程小白,面临海量文本数据采集和处理分析艰巨任务,个人建议学习[《python网络爬虫与文本数据分析》](https://ke.qq.com/course/482241?tuin=163164df)视频课。作为文科生,一样也是从两眼一抹黑开始,这门课程是用五年时间凝缩出来的。自认为讲的很通俗易懂o(* ̄︶ ̄*)o, 91 | 92 | - python入门 93 | - 网络爬虫 94 | - 数据读取 95 | - 文本分析入门 96 | - 机器学习与文本分析 97 | - 文本分析在经管研究中的应用 98 | 99 | 感兴趣的童鞋不妨 戳一下[《python网络爬虫与文本数据分析》](https://ke.qq.com/course/482241?tuin=163164df)进来看看~ 100 | 101 | [![](img/课程.png)](https://ke.qq.com/course/482241?tuin=163164df) 102 | 103 | 104 | 105 | ## 更多 106 | 107 | - [B站:大邓和他的python](https://space.bilibili.com/122592901/channel/detail?cid=66008) 108 | 109 | - 公众号:大邓和他的python 110 | 111 | - [知乎专栏:数据科学家](https://zhuanlan.zhihu.com/dadeng) 112 | 113 | 114 | ![](img/大邓和他的Python.png) 115 | -------------------------------------------------------------------------------- /examples/02-统计信息.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "name": "stderr", 10 | "output_type": "stream", 11 | "text": [ 12 | "Building prefix dict from the default dictionary ...\n", 13 | "Dumping model to file cache /var/folders/sc/3mnt5tgs419_hk7s16gq61p80000gn/T/jieba.cache\n", 14 | "Loading model cost 0.718 seconds.\n", 15 | "Prefix dict has been built successfully.\n" 16 | ] 17 | }, 18 | { 19 | "data": { 20 | "text/plain": [ 21 | "Counter({'看待': 1,\n", 22 | " '网文': 1,\n", 23 | " '作者': 1,\n", 24 | " '黑客': 1,\n", 25 | " '大佬': 1,\n", 26 | " '盗号': 1,\n", 27 | " '改文因': 1,\n", 28 | " '万分': 1,\n", 29 | " '惭愧': 1,\n", 30 | " '停': 1})" 31 | ] 32 | }, 33 | "execution_count": 1, 34 | "metadata": {}, 35 | "output_type": "execute_result" 36 | } 37 | ], 38 | "source": [ 39 | "from cntext.stats import term_freq, readability\n", 40 | "\n", 41 | "text = '如何看待一网文作者被黑客大佬盗号改文,因万分惭愧而停更'\n", 42 | "term_freq(text)" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": 2, 48 | "metadata": {}, 49 | "outputs": [ 50 | { 51 | "data": { 52 | "text/plain": [ 53 | "{'readability1': 27.0,\n", 54 | " 'readability2': 0.17647058823529413,\n", 55 | " 'readability3': 13.588235294117647}" 56 | ] 57 | }, 58 | "execution_count": 2, 59 | "metadata": {}, 60 | "output_type": "execute_result" 61 | } 62 | ], 63 | "source": [ 64 | "readability(text)" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": null, 70 | "metadata": {}, 71 | "outputs": [], 72 | "source": [] 73 | } 74 | ], 75 | "metadata": { 76 | "kernelspec": { 77 | "display_name": "Python 3", 78 | "language": "python", 79 | "name": "python3" 80 | }, 81 | "language_info": { 82 | "codemirror_mode": { 83 | "name": "ipython", 84 | "version": 3 85 | }, 86 | "file_extension": ".py", 87 | "mimetype": "text/x-python", 88 | "name": "python", 89 | "nbconvert_exporter": "python", 90 | "pygments_lexer": "ipython3", 91 | "version": "3.7.5" 92 | }, 93 | "toc": { 94 | "base_numbering": 1, 95 | "nav_menu": {}, 96 | "number_sections": true, 97 | "sideBar": true, 98 | "skip_h1_title": false, 99 | "title_cell": "Table of Contents", 100 | "title_sidebar": "Contents", 101 | "toc_cell": false, 102 | "toc_position": {}, 103 | "toc_section_display": true, 104 | "toc_window_display": false 105 | } 106 | }, 107 | "nbformat": 4, 108 | "nbformat_minor": 4 109 | } 110 | -------------------------------------------------------------------------------- /cntext/similarity/similarity.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | from sklearn.feature_extraction.text import CountVectorizer 4 | from sklearn.metrics.pairwise import cosine_similarity 5 | from difflib import Differ, SequenceMatcher 6 | import jieba 7 | from math import * 8 | import warnings 9 | 10 | warnings.filterwarnings('ignore') 11 | 12 | 13 | def check_contain_chinese(check_str): 14 | for ch in check_str: 15 | if u'\u4e00' <= ch <= u'\u9fff': 16 | return True 17 | return False 18 | 19 | 20 | def transform(text1, text2): 21 | """ 22 | 把文本text1,text2转化为英文样式的text1,text2和向量vec1,vec2 23 | :param text1: 24 | :param text2: 25 | :return: 26 | """ 27 | 28 | if check_contain_chinese(text1): 29 | text1 = ' '.join(jieba.lcut(text1)) 30 | text2 = ' '.join(jieba.lcut(text2)) 31 | else: 32 | pass 33 | 34 | corpus = [text1, text2] 35 | cv = CountVectorizer(binary=True) 36 | cv.fit(corpus) 37 | vec1 = cv.transform([text1]).toarray() 38 | vec2 = cv.transform([text2]).toarray() 39 | return text1, text2, vec1, vec2 40 | 41 | 42 | #def cosine_similarity(vec1, vec2): 43 | # cos_sim = cosine_similarity(vec1, vec2)[0][0] 44 | # return cos_sim[0][0] 45 | 46 | def jaccard_similarity(vec1, vec2): 47 | """ returns the jaccard similarity between two lists """ 48 | vec1 = set([idx for idx, v in enumerate(vec1[0]) if v > 0]) 49 | vec2 = set([idx for idx, v in enumerate(vec2[0]) if v > 0]) 50 | return len(vec1 & vec2) / len(vec1 | vec2) 51 | 52 | def minedit_similarity(text1, text2): 53 | words1 = jieba.lcut(text1.lower()) 54 | words2 = jieba.lcut(text2.lower()) 55 | leven_cost = 0 56 | s = SequenceMatcher(None, words1, words2) 57 | for tag, i1, i2, j1, j2 in s.get_opcodes(): 58 | if tag == 'replace': 59 | leven_cost += max(i2 - i1, j2 - j1) 60 | elif tag == 'insert': 61 | leven_cost += (j2 - j1) 62 | elif tag == 'delete': 63 | leven_cost += (i2 - i1) 64 | return leven_cost 65 | 66 | def simple_similarity(text1, text2): 67 | words1 = jieba.lcut(text1.lower()) 68 | words2 = jieba.lcut(text2.lower()) 69 | diff = Differ() 70 | diff_manipulate = list(diff.compare(words1, words2)) 71 | c = len(diff_manipulate) / (len(words1) + len(words2)) 72 | cmax = max([len(words1), len(words2)]) 73 | return (cmax - c) / cmax 74 | 75 | 76 | 77 | def similarity_score(text1, text2): 78 | """ 79 | 对输入的text1和text2进行相似性计算,返回相似性信息 80 | :param text1: 文本字符串 81 | :param text2: 文本字符串 82 | :return: 字典, 形如{ 83 | 'Sim_Cosine':0.8, 84 | 'Sim_Jaccard': 0.3, 85 | 'Sim_MinEdit': 0.5, 86 | 'Sim_Simple': 0.8 87 | } 88 | """ 89 | text11, text22, vec1, vec2 = transform(text1, text2) 90 | data = { 91 | 'Sim_Cosine': cosine_similarity(vec1, vec2)[0][0], 92 | 'Sim_Jaccard': jaccard_similarity(vec1, vec2), 93 | 'Sim_MinEdit': minedit_similarity(text11, text22), 94 | 'Sim_Simple': simple_similarity(text11, text22) 95 | } 96 | return data 97 | 98 | -------------------------------------------------------------------------------- /examples/05-文本相似.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "from cntext.similarity import similarity_score" 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 2, 15 | "metadata": {}, 16 | "outputs": [ 17 | { 18 | "name": "stdout", 19 | "output_type": "stream", 20 | "text": [ 21 | "Help on function similarity_score in module cntext.similarity.similarity:\n", 22 | "\n", 23 | "similarity_score(text1, text2)\n", 24 | " 对输入的text1和text2进行相似性计算,返回相似性信息\n", 25 | " :param text1: 文本字符串\n", 26 | " :param text2: 文本字符串\n", 27 | " :return: 字典, 形如{\n", 28 | " 'Sim_Cosine':0.8,\n", 29 | " 'Sim_Jaccard': 0.3,\n", 30 | " 'Sim_MinEdit': 0.5,\n", 31 | " 'Sim_Simple': 0.8\n", 32 | " }\n", 33 | "\n" 34 | ] 35 | } 36 | ], 37 | "source": [ 38 | "help(similarity_score)" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": 3, 44 | "metadata": {}, 45 | "outputs": [ 46 | { 47 | "name": "stderr", 48 | "output_type": "stream", 49 | "text": [ 50 | "Building prefix dict from the default dictionary ...\n", 51 | "Loading model from cache /var/folders/sc/3mnt5tgs419_hk7s16gq61p80000gn/T/jieba.cache\n", 52 | "Loading model cost 0.633 seconds.\n", 53 | "Prefix dict has been built successfully.\n" 54 | ] 55 | }, 56 | { 57 | "data": { 58 | "text/plain": [ 59 | "{'Sim_Cosine': 0.816496580927726,\n", 60 | " 'Sim_Jaccard': 0.6666666666666666,\n", 61 | " 'Sim_MinEdit': 1,\n", 62 | " 'Sim_Simple': 0.9183673469387755}" 63 | ] 64 | }, 65 | "execution_count": 3, 66 | "metadata": {}, 67 | "output_type": "execute_result" 68 | } 69 | ], 70 | "source": [ 71 | "text1 = '编程真好玩编程真好玩'\n", 72 | "text2 = '游戏真好玩编程真好玩'\n", 73 | "\n", 74 | "similarity_score(text1, text2)" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": null, 80 | "metadata": {}, 81 | "outputs": [], 82 | "source": [] 83 | } 84 | ], 85 | "metadata": { 86 | "kernelspec": { 87 | "display_name": "Python 3", 88 | "language": "python", 89 | "name": "python3" 90 | }, 91 | "language_info": { 92 | "codemirror_mode": { 93 | "name": "ipython", 94 | "version": 3 95 | }, 96 | "file_extension": ".py", 97 | "mimetype": "text/x-python", 98 | "name": "python", 99 | "nbconvert_exporter": "python", 100 | "pygments_lexer": "ipython3", 101 | "version": "3.7.5" 102 | }, 103 | "toc": { 104 | "base_numbering": 1, 105 | "nav_menu": {}, 106 | "number_sections": true, 107 | "sideBar": true, 108 | "skip_h1_title": false, 109 | "title_cell": "Table of Contents", 110 | "title_sidebar": "Contents", 111 | "toc_cell": false, 112 | "toc_position": {}, 113 | "toc_section_display": true, 114 | "toc_window_display": false 115 | } 116 | }, 117 | "nbformat": 4, 118 | "nbformat_minor": 4 119 | } 120 | -------------------------------------------------------------------------------- /examples/03-扩充词典.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "name": "stderr", 10 | "output_type": "stream", 11 | "text": [ 12 | "Building prefix dict from the default dictionary ...\n", 13 | "Loading model from cache /var/folders/sc/3mnt5tgs419_hk7s16gq61p80000gn/T/jieba.cache\n" 14 | ] 15 | }, 16 | { 17 | "name": "stdout", 18 | "output_type": "stream", 19 | "text": [ 20 | "step 1/4:...seg corpus ...\n" 21 | ] 22 | }, 23 | { 24 | "name": "stderr", 25 | "output_type": "stream", 26 | "text": [ 27 | "Loading model cost 0.678 seconds.\n", 28 | "Prefix dict has been built successfully.\n" 29 | ] 30 | }, 31 | { 32 | "name": "stdout", 33 | "output_type": "stream", 34 | "text": [ 35 | "step 1/4 finished:...cost 60.78995203971863...\n", 36 | "step 2/4:...collect cowords ...\n", 37 | "step 2/4 finished:...cost 0.6169600486755371...\n", 38 | "step 3/4:...compute sopmi ...\n", 39 | "step 1/4 finished:...cost 0.26422882080078125...\n", 40 | "step 4/4:...save candiwords ...\n", 41 | "finished! cost 61.8965539932251\n" 42 | ] 43 | } 44 | ], 45 | "source": [ 46 | "from cntext.dictionary import SoPmi\n", 47 | "import os\n", 48 | "\n", 49 | "sopmier = SoPmi(cwd=os.getcwd(),\n", 50 | " input_txt_file='data/sopmi_corpus.txt', #原始数据,您的语料\n", 51 | " seedword_txt_file='data/sopmi_seed_words.txt', #人工标注的初始种子词\n", 52 | " ) \n", 53 | "\n", 54 | "sopmier.sopmi()" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": null, 60 | "metadata": {}, 61 | "outputs": [], 62 | "source": [] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": 1, 67 | "metadata": {}, 68 | "outputs": [ 69 | { 70 | "name": "stdout", 71 | "output_type": "stream", 72 | "text": [ 73 | "数据预处理开始.......\n", 74 | "预处理结束...........\n", 75 | "Word2Vec模型训练开始......\n", 76 | "已将模型存入 /Users/thunderhit/Desktop/cntext/test/output/w2v_candi_words/w2v.model \n", 77 | "准备寻找每个seed在语料中所有的相似候选词\n", 78 | "初步搜寻到 572 个相似的候选词\n", 79 | "计算每个候选词 与 integrity 的相似度, 选出相似度最高的前 100 个候选词\n", 80 | "已完成 【integrity 类】 的词语筛选,并保存于 /Users/thunderhit/Desktop/cntext/test/output/w2v_candi_words/integrity.txt, 耗时 46 秒\n", 81 | "准备寻找每个seed在语料中所有的相似候选词\n", 82 | "初步搜寻到 516 个相似的候选词\n", 83 | "计算每个候选词 与 innovation 的相似度, 选出相似度最高的前 100 个候选词\n", 84 | "已完成 【innovation 类】 的词语筛选,并保存于 /Users/thunderhit/Desktop/cntext/test/output/w2v_candi_words/innovation.txt, 耗时 46 秒\n", 85 | "准备寻找每个seed在语料中所有的相似候选词\n", 86 | "初步搜寻到 234 个相似的候选词\n", 87 | "计算每个候选词 与 quality 的相似度, 选出相似度最高的前 100 个候选词\n", 88 | "已完成 【quality 类】 的词语筛选,并保存于 /Users/thunderhit/Desktop/cntext/test/output/w2v_candi_words/quality.txt, 耗时 46 秒\n", 89 | "准备寻找每个seed在语料中所有的相似候选词\n", 90 | "初步搜寻到 243 个相似的候选词\n", 91 | "计算每个候选词 与 respect 的相似度, 选出相似度最高的前 100 个候选词\n", 92 | "已完成 【respect 类】 的词语筛选,并保存于 /Users/thunderhit/Desktop/cntext/test/output/w2v_candi_words/respect.txt, 耗时 46 秒\n", 93 | "准备寻找每个seed在语料中所有的相似候选词\n", 94 | "初步搜寻到 319 个相似的候选词\n", 95 | "计算每个候选词 与 teamwork 的相似度, 选出相似度最高的前 100 个候选词\n", 96 | "已完成 【teamwork 类】 的词语筛选,并保存于 /Users/thunderhit/Desktop/cntext/test/output/w2v_candi_words/teamwork.txt, 耗时 46 秒\n" 97 | ] 98 | } 99 | ], 100 | "source": [ 101 | "from cntext.dictionary import W2VModels\n", 102 | "import os\n", 103 | "\n", 104 | "#初始化模型\n", 105 | "model = W2VModels(cwd=os.getcwd()) #语料数据 w2v_corpus.txt\n", 106 | "model.train(input_txt_file='data/w2v_corpus.txt')\n", 107 | "\n", 108 | "\n", 109 | "#根据种子词,筛选出没类词最相近的前100个词\n", 110 | "model.find(seedword_txt_file='data/w2v_seeds/integrity.txt', \n", 111 | " topn=100)\n", 112 | "model.find(seedword_txt_file='data/w2v_seeds/innovation.txt', \n", 113 | " topn=100)\n", 114 | "model.find(seedword_txt_file='data/w2v_seeds/quality.txt', \n", 115 | " topn=100)\n", 116 | "model.find(seedword_txt_file='data/w2v_seeds/respect.txt', \n", 117 | " topn=100)\n", 118 | "model.find(seedword_txt_file='data/w2v_seeds/teamwork.txt', \n", 119 | " topn=100)" 120 | ] 121 | }, 122 | { 123 | "cell_type": "code", 124 | "execution_count": null, 125 | "metadata": {}, 126 | "outputs": [], 127 | "source": [] 128 | } 129 | ], 130 | "metadata": { 131 | "kernelspec": { 132 | "display_name": "Python 3", 133 | "language": "python", 134 | "name": "python3" 135 | }, 136 | "language_info": { 137 | "codemirror_mode": { 138 | "name": "ipython", 139 | "version": 3 140 | }, 141 | "file_extension": ".py", 142 | "mimetype": "text/x-python", 143 | "name": "python", 144 | "nbconvert_exporter": "python", 145 | "pygments_lexer": "ipython3", 146 | "version": "3.7.5" 147 | }, 148 | "toc": { 149 | "base_numbering": 1, 150 | "nav_menu": {}, 151 | "number_sections": true, 152 | "sideBar": true, 153 | "skip_h1_title": false, 154 | "title_cell": "Table of Contents", 155 | "title_sidebar": "Contents", 156 | "toc_cell": false, 157 | "toc_position": {}, 158 | "toc_section_display": true, 159 | "toc_window_display": false 160 | } 161 | }, 162 | "nbformat": 4, 163 | "nbformat_minor": 4 164 | } 165 | -------------------------------------------------------------------------------- /examples/04-情感计算.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "from cntext.sentiment import senti_by_dutir, senti_by_hownet, senti_by_diydict" 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 2, 15 | "metadata": {}, 16 | "outputs": [ 17 | { 18 | "name": "stdout", 19 | "output_type": "stream", 20 | "text": [ 21 | "Help on function senti_by_dutir in module cntext.sentiment.sentiment:\n", 22 | "\n", 23 | "senti_by_dutir(text)\n", 24 | " 使用大连理工大学情感本体库DUTIR,仅计算文本中各个情绪词出现次数\n", 25 | " :param text: 中文文本字符串\n", 26 | " :return: 返回文本情感统计信息,类似于这样{'words': 22, 'sentences': 2, '好': 0, '乐': 4, '哀': 0, '怒': 0, '惧': 0, '恶': 0, '惊': 0}\n", 27 | "\n" 28 | ] 29 | } 30 | ], 31 | "source": [ 32 | "help(senti_by_dutir)" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": 3, 38 | "metadata": {}, 39 | "outputs": [ 40 | { 41 | "name": "stderr", 42 | "output_type": "stream", 43 | "text": [ 44 | "Building prefix dict from the default dictionary ...\n", 45 | "Loading model from cache /var/folders/sc/3mnt5tgs419_hk7s16gq61p80000gn/T/jieba.cache\n", 46 | "Loading model cost 0.671 seconds.\n", 47 | "Prefix dict has been built successfully.\n" 48 | ] 49 | }, 50 | { 51 | "data": { 52 | "text/plain": [ 53 | "{'word_num': 12,\n", 54 | " 'sentence_num': 2,\n", 55 | " 'stopword_num': 4,\n", 56 | " '好_num': 0,\n", 57 | " '乐_num': 1,\n", 58 | " '哀_num': 0,\n", 59 | " '怒_num': 0,\n", 60 | " '惧_num': 0,\n", 61 | " '恶_num': 0,\n", 62 | " '惊_num': 0}" 63 | ] 64 | }, 65 | "execution_count": 3, 66 | "metadata": {}, 67 | "output_type": "execute_result" 68 | } 69 | ], 70 | "source": [ 71 | "text = '今天股票大涨,心情倍爽,非常开心啊。'\n", 72 | "\n", 73 | "senti_by_dutir(text)" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": 4, 79 | "metadata": {}, 80 | "outputs": [ 81 | { 82 | "name": "stdout", 83 | "output_type": "stream", 84 | "text": [ 85 | "Help on function senti_by_hownet in module cntext.sentiment.sentiment:\n", 86 | "\n", 87 | "senti_by_hownet(text, adj_adv=False)\n", 88 | " 使用知网Hownet词典进行(中)文本数据的情感分析;\n", 89 | " :param text: 待分析的中文文本数据\n", 90 | " :param adj_adv: 是否考虑副词(否定词、程度词)对情绪形容词的反转和情感强度修饰作用,默认False。默认False只统计情感形容词出现个数;\n", 91 | " :return: 返回情感信息\n", 92 | "\n" 93 | ] 94 | } 95 | ], 96 | "source": [ 97 | "help(senti_by_hownet)" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": 5, 103 | "metadata": {}, 104 | "outputs": [ 105 | { 106 | "data": { 107 | "text/plain": [ 108 | "{'word_num': 12,\n", 109 | " 'stopword_num': 4,\n", 110 | " 'sentence_num': 1,\n", 111 | " 'pos_word_num': 2,\n", 112 | " 'neg_word_num': 0}" 113 | ] 114 | }, 115 | "execution_count": 5, 116 | "metadata": {}, 117 | "output_type": "execute_result" 118 | } 119 | ], 120 | "source": [ 121 | "senti_by_hownet(text)" 122 | ] 123 | }, 124 | { 125 | "cell_type": "code", 126 | "execution_count": 6, 127 | "metadata": {}, 128 | "outputs": [ 129 | { 130 | "data": { 131 | "text/plain": [ 132 | "{'sentence_num': 1,\n", 133 | " 'word_num': 12,\n", 134 | " 'stopword_num': 3,\n", 135 | " 'pos_score': 13.0,\n", 136 | " 'neg_score': 0.0}" 137 | ] 138 | }, 139 | "execution_count": 6, 140 | "metadata": {}, 141 | "output_type": "execute_result" 142 | } 143 | ], 144 | "source": [ 145 | "senti_by_hownet(text, adj_adv=True)" 146 | ] 147 | }, 148 | { 149 | "cell_type": "code", 150 | "execution_count": 7, 151 | "metadata": {}, 152 | "outputs": [ 153 | { 154 | "name": "stdout", 155 | "output_type": "stream", 156 | "text": [ 157 | "Help on function senti_by_diydict in module cntext.sentiment.sentiment:\n", 158 | "\n", 159 | "senti_by_diydict(text, sentiwords)\n", 160 | " 使用diy词典进行情感分析,计算各个情绪词出现次数,未考虑强度副词、否定词对情感的复杂影响,\n", 161 | " :param text: 待分析中文文本\n", 162 | " :param sentiwords: 情感词字典;\n", 163 | " {'category1': 'category1 词语列表',\n", 164 | " 'category2': 'category2词语列表',\n", 165 | " 'category3': 'category3词语列表',\n", 166 | " ...\n", 167 | " }\n", 168 | " \n", 169 | " :return:\n", 170 | "\n" 171 | ] 172 | } 173 | ], 174 | "source": [ 175 | "help(senti_by_diydict)" 176 | ] 177 | }, 178 | { 179 | "cell_type": "code", 180 | "execution_count": 8, 181 | "metadata": {}, 182 | "outputs": [ 183 | { 184 | "data": { 185 | "text/plain": [ 186 | "{'pos_num': 1,\n", 187 | " 'neg_num': 0,\n", 188 | " 'adv_num': 1,\n", 189 | " 'stopword_num': 4,\n", 190 | " 'sentence_num': 2,\n", 191 | " 'word_num': 12}" 192 | ] 193 | }, 194 | "execution_count": 8, 195 | "metadata": {}, 196 | "output_type": "execute_result" 197 | } 198 | ], 199 | "source": [ 200 | "sentiwords = {'pos': ['开心', '愉快', '倍爽'],\n", 201 | " 'neg': ['难过', '悲伤'],\n", 202 | " 'adv': ['倍']}\n", 203 | "\n", 204 | "text = '今天股票大涨,心情倍爽,非常开心啊。'\n", 205 | "senti_by_diydict(text, sentiwords)" 206 | ] 207 | }, 208 | { 209 | "cell_type": "code", 210 | "execution_count": null, 211 | "metadata": {}, 212 | "outputs": [], 213 | "source": [] 214 | } 215 | ], 216 | "metadata": { 217 | "kernelspec": { 218 | "display_name": "Python 3", 219 | "language": "python", 220 | "name": "python3" 221 | }, 222 | "language_info": { 223 | "codemirror_mode": { 224 | "name": "ipython", 225 | "version": 3 226 | }, 227 | "file_extension": ".py", 228 | "mimetype": "text/x-python", 229 | "name": "python", 230 | "nbconvert_exporter": "python", 231 | "pygments_lexer": "ipython3", 232 | "version": "3.7.5" 233 | }, 234 | "toc": { 235 | "base_numbering": 1, 236 | "nav_menu": {}, 237 | "number_sections": true, 238 | "sideBar": true, 239 | "skip_h1_title": false, 240 | "title_cell": "Table of Contents", 241 | "title_sidebar": "Contents", 242 | "toc_cell": false, 243 | "toc_position": {}, 244 | "toc_section_display": true, 245 | "toc_window_display": false 246 | } 247 | }, 248 | "nbformat": 4, 249 | "nbformat_minor": 4 250 | } 251 | -------------------------------------------------------------------------------- /cntext/sentiment/sentiment.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | import jieba 4 | import numpy as np 5 | import pathlib 6 | import re 7 | from cntext.dictionary.dictionary import * 8 | 9 | 10 | def init_jieba(diydict=dict()): 11 | """ 12 | jieba词典初始化, 为防止情感词被错分,需要在调用情感函数前,先运行init_jieba() 13 | :param diydict: 自定义词典,默认空字典; 当使用senti_by_diydict时,才设置diydict 14 | :return: 15 | """ 16 | 17 | for key in diydict.keys(): 18 | for word in diydict[key]: 19 | jieba.add_word(word) 20 | dictlists = [DUTIR_Ais, DUTIR_Wus, DUTIR_Haos, DUTIR_Jings, 21 | DUTIR_Jus, DUTIR_Les, DUTIR_Nus, HOWNET_deny, 22 | HOWNET_extreme, HOWNET_ish, HOWNET_more, HOWNET_neg, 23 | HOWNET_pos, HOWNET_very] 24 | for wordlist in dictlists: 25 | for word in wordlist: 26 | jieba.add_word(word) 27 | 28 | 29 | 30 | 31 | 32 | def judgeodd(num): 33 | """ 34 | 判断奇数偶数。当情感词前方有偶数个否定词,情感极性方向不变。奇数会改变情感极性方向。 35 | """ 36 | if (num % 2) == 0: 37 | return 'even' 38 | else: 39 | return 'odd' 40 | 41 | 42 | 43 | 44 | 45 | 46 | def Adj_senti(text): 47 | """ 48 | 简单情感分析,仅计算各个情绪形容词出现次数(占比), 未考虑强度副词、否定词对情感的复杂影响。 49 | :param text: 待分析的中文文本数据 50 | :return: 返回情感信息 51 | """ 52 | length, sentences, pos, neg, stopword_num = 0, 0, 0, 0, 0 53 | sentences = [s for s in re.split('[\.。!!?\?\n;;]+', text) if s] 54 | sentence_num = len(sentences) 55 | words = jieba.lcut(text) 56 | length = len(words) 57 | for w in words: 58 | if w in STOPWORDS_zh: 59 | stopword_num += 1 60 | if w in HOWNET_pos: 61 | pos+=1 62 | elif w in HOWNET_neg: 63 | neg+=1 64 | else: 65 | pass 66 | return {'word_num': length, 67 | 'stopword_num': stopword_num, 68 | 'sentence_num': sentence_num, 69 | 'pos_word_num': pos, 70 | 'neg_word_num': neg} 71 | 72 | 73 | 74 | def AdjAdv_senti(text): 75 | """ 76 | 情感分析,考虑副词对情绪形容词的修饰作用和否定词的反转作用, 77 | 其中副词对情感形容词的情感赋以权重, 78 | 否定词确定情感值正负。 79 | 80 | :param text: 待分析的中文文本数据 81 | :return: 返回情感信息 82 | """ 83 | sentences = [s for s in re.split('[\.。!!?\?\n;;]+', text) if s] 84 | wordnum = len(jieba.lcut(text)) 85 | count1 = [] 86 | count2 = [] 87 | stopword_num = 0 88 | for sen in sentences: 89 | segtmp = jieba.lcut(sen) 90 | i = 0 # 记录扫描到的词的位置 91 | a = 0 # 记录情感词的位置 92 | poscount = 0 # 积极词的第一次分值 93 | poscount2 = 0 # 积极词反转后的分值 94 | poscount3 = 0 # 积极词的最后分值(包括叹号的分值) 95 | negcount = 0 96 | negcount2 = 0 97 | negcount3 = 0 98 | for w in segtmp: 99 | if w in STOPWORDS_zh: 100 | stopword_num+=1 101 | if w in HOWNET_pos: # 判断词语是否是情感词 102 | poscount += 1 103 | c = 0 104 | for w in segtmp[a:i]: # 扫描情感词前的程度词 105 | if w in HOWNET_extreme: 106 | poscount *= 4.0 107 | elif w in HOWNET_very: 108 | poscount *= 3.0 109 | elif w in HOWNET_more: 110 | poscount *= 2.0 111 | elif w in HOWNET_ish: 112 | poscount *= 0.5 113 | elif w in HOWNET_deny: 114 | c += 1 115 | if judgeodd(c) == 'odd': # 扫描情感词前的否定词数 116 | poscount *= -1.0 117 | poscount2 += poscount 118 | poscount = 0 119 | poscount3 = poscount + poscount2 + poscount3 120 | poscount2 = 0 121 | else: 122 | poscount3 = poscount + poscount2 + poscount3 123 | poscount = 0 124 | a = i + 1 # 情感词的位置变化 125 | 126 | elif w in HOWNET_neg: # 消极情感的分析,与上面一致 127 | negcount += 1 128 | d = 0 129 | for w in segtmp[a:i]: 130 | if w in HOWNET_extreme: 131 | negcount *= 4.0 132 | elif w in HOWNET_very: 133 | negcount *= 3.0 134 | elif w in HOWNET_more: 135 | negcount *= 2.0 136 | elif w in HOWNET_ish: 137 | negcount *= 0.5 138 | elif w in HOWNET_deny: 139 | d += 1 140 | if judgeodd(d) == 'odd': 141 | negcount *= -1.0 142 | negcount2 += negcount 143 | negcount = 0 144 | negcount3 = negcount + negcount2 + negcount3 145 | negcount2 = 0 146 | else: 147 | negcount3 = negcount + negcount2 + negcount3 148 | negcount = 0 149 | a = i + 1 150 | elif w == '!' or w == '!': ##判断句子是否有感叹号 151 | for w2 in segtmp[::-1]: # 扫描感叹号前的情感词,发现后权值+2,然后退出循环 152 | if w2 in HOWNET_pos or HOWNET_neg: 153 | poscount3 += 2 154 | negcount3 += 2 155 | break 156 | i += 1 # 扫描词位置前移 157 | 158 | # 以下是防止出现负数的情况 159 | pos_count = 0 160 | neg_count = 0 161 | if poscount3 < 0 and negcount3 > 0: 162 | neg_count += negcount3 - poscount3 163 | pos_count = 0 164 | elif negcount3 < 0 and poscount3 > 0: 165 | pos_count = poscount3 - negcount3 166 | neg_count = 0 167 | elif poscount3 < 0 and negcount3 < 0: 168 | neg_count = -poscount3 169 | pos_count = -negcount3 170 | else: 171 | pos_count = poscount3 172 | neg_count = negcount3 173 | 174 | count1.append([pos_count, neg_count]) 175 | count2.append(count1) 176 | count1 = [] 177 | 178 | pos_result = [] 179 | neg_result = [] 180 | for sentence in count2: 181 | score_array = np.array(sentence) 182 | pos = np.sum(score_array[:, 0]) 183 | neg = np.sum(score_array[:, 1]) 184 | pos_result.append(pos) 185 | neg_result.append(neg) 186 | 187 | pos_score = np.sum(np.array(pos_result)) 188 | neg_score = np.sum(np.array(neg_result)) 189 | score = {'sentence_num': len(count2), 190 | 'word_num':wordnum, 191 | 'stopword_num': stopword_num, 192 | 'pos_score': pos_score, 193 | 'neg_score': neg_score} 194 | return score 195 | 196 | 197 | 198 | def senti_by_hownet(text, adj_adv=False): 199 | """ 200 | 使用知网Hownet词典进行(中)文本数据的情感分析; 201 | :param text: 待分析的中文文本数据 202 | :param adj_adv: 是否考虑副词(否定词、程度词)对情绪形容词的反转和情感强度修饰作用,默认False。默认False只统计情感形容词出现个数; 203 | :return: 返回情感信息 204 | """ 205 | if adj_adv==True: 206 | return AdjAdv_senti(text) 207 | else: 208 | return Adj_senti(text) 209 | 210 | 211 | 212 | def senti_by_dutir(text): 213 | """ 214 | 使用大连理工大学情感本体库DUTIR,仅计算文本中各个情绪词出现次数 215 | :param text: 中文文本字符串 216 | :return: 返回文本情感统计信息,类似于这样{'words': 22, 'sentences': 2, '好': 0, '乐': 4, '哀': 0, '怒': 0, '惧': 0, '恶': 0, '惊': 0} 217 | """ 218 | wordnum, sentences, hao, le, ai, nu, ju, wu, jing, stopwords =0, 0, 0, 0, 0, 0, 0, 0, 0, 0 219 | sentences = len(re.split('[\.。!!?\?\n;;]+', text)) 220 | words = jieba.lcut(text) 221 | wordnum = len(words) 222 | for w in words: 223 | if w in STOPWORDS_zh: 224 | stopwords+=1 225 | if w in DUTIR_Haos: 226 | hao += 1 227 | elif w in DUTIR_Les: 228 | le += 1 229 | elif w in DUTIR_Ais: 230 | ai += 1 231 | elif w in DUTIR_Nus: 232 | nu += 1 233 | elif w in DUTIR_Jus: 234 | ju += 1 235 | elif w in DUTIR_Wus: 236 | wu += 1 237 | elif w in DUTIR_Jings: 238 | jing += 1 239 | else: 240 | pass 241 | result = {'word_num':wordnum, 242 | 'sentence_num':sentences, 243 | 'stopword_num':stopwords, 244 | '好_num':hao, '乐_num':le, '哀_num':ai, '怒_num':nu, '惧_num':ju, '恶_num': wu, '惊_num':jing} 245 | return result 246 | 247 | 248 | 249 | 250 | 251 | """ 252 | 简单情感分析,未考虑强度副词、否定词对情感的复杂影响。仅仅计算各个情绪词出现次数(占比) 253 | :param text: 中文文本字符串 254 | :return: 返回文本情感统计信息 255 | """ 256 | 257 | def senti_by_diydict(text, sentiwords): 258 | """ 259 | 使用diy词典进行情感分析,计算各个情绪词出现次数,未考虑强度副词、否定词对情感的复杂影响, 260 | :param text: 待分析中文文本 261 | :param sentiwords: 情感词字典; 262 | {'category1': 'category1 词语列表', 263 | 'category2': 'category2词语列表', 264 | 'category3': 'category3词语列表', 265 | ... 266 | } 267 | 268 | :return: 269 | """ 270 | result_dict = dict() 271 | senti_categorys = sentiwords.keys() 272 | 273 | for senti_category in senti_categorys: 274 | result_dict[senti_category+'_num'] = 0 275 | 276 | word_num, sentence_num, stopword_num = 0,0,0 277 | sentence_num = len(re.split('[\.。!!?\?\n;;]+', text)) 278 | words = jieba.lcut(text) 279 | wordnum = len(words) 280 | for word in words: 281 | if word in STOPWORDS_zh: 282 | stopword_num+=1 283 | for senti_category in senti_categorys: 284 | if word in sentiwords[senti_category]: 285 | result_dict[senti_category+'_num'] += result_dict[senti_category+'_num'] + 1 286 | result_dict['stopword_num'] = stopword_num 287 | result_dict['sentence_num'] = sentence_num 288 | result_dict['word_num'] = wordnum 289 | return result_dict 290 | 291 | 292 | 293 | 294 | 295 | 296 | -------------------------------------------------------------------------------- /cntext/dictionary/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 一、项目意义 3 | 4 | 情感分析大多是基于情感词典对文本数据进行分析,所以情感词典好坏、是否完备充足是文本分析的关键。 5 | 6 | 目前常用的词典都是基于形容词,有 7 | 8 | - 知网HowNet 9 | - 大连理工大学情感本体库 10 | 11 | 但是形容词类型的词典在某些情况下不适用,比如 12 | 13 | **华为手机外壳采用金属制作,更耐摔** 14 | 15 | 由于句子中没有形容词,使用形容词情感词典计算得到的情感得分为0。但是**耐摔**这个动词具有**正面积极情绪**,这个句子的情感的分理应为**正** 16 | 17 | 18 | 19 | 可见能够简单快速构建不同领域(手机、汽车等)的情感词典十分重要。但是人工构建太慢,如果让机器帮我们把最有可能带情感的候选词找出来,人工再去筛选构建词典,那该多好啊。 那么如何快速自动的新建或者扩充词表呢? 20 | 21 | 22 | 23 |
24 | 25 | # 二、构建思路 26 | 27 | - 共现法,参考https://github.com/liuhuanyong/SentimentWordExpansion 28 | - 词向量,参考https://github.com/MS20190155/Measuring-Corporate-Culture-Using-Machine-Learning 29 | 30 | 31 | 32 | 33 | 34 |
35 | 36 | ## 2.1 共现法扩充词表 37 | 38 | 计算机领域有一个算法叫做SO_PMI,互信息。简单的讲个体之间不是完全独立的,往往物以类聚,人以群分。如果我们一开始设定少量的 39 | 40 | - 初始正面种子词 41 | - 初始负面种子词 42 | 43 | 程序会按照“物以类聚人以群分”的思路, 44 | 45 | - 根据**初始正面种子词**找到很多大概率为**正面情感的候选词** 46 | - 根据**初始负种子词**找到很多大概率为**负面情感的候选词** 47 | 48 | 这个包原始作者刘焕勇,项目地址https://github.com/liuhuanyong/SentimentWordExpansion 我仅仅做了简单的封装 49 | 50 | 51 | 52 | 53 | 54 | ## 2.2 词向量扩充词表 55 | 56 | 共现法,词语之间的独立无相关性依然很强,依然认为词语与词语是不可以比较的。其实词语里潜藏着很多线索,例如中国传统文化中的金木水火土、性别(阴阳)等信息。例如 57 | 58 | - “铁”、“铜”、“钢” 59 | - “国王“、“王后“、“男人“、“女人“ 60 | 61 | 如果能抽取出每个词的特征,将每个词用同样长度的向量表示,例如100维。那么咱们中学阶段的cos余弦公式可以计算任意两个词的相似度。 62 | 63 | 参照论文使用机器学习构建五类企业文化词典 64 | 65 | > Kai Li, Feng Mai, Rui Shen, Xinyan Yan, [**Measuring Corporate Culture Using Machine Learning**](https://academic.oup.com/rfs/advance-article-abstract/doi/10.1093/rfs/hhaa079/5869446?redirectedFrom=fulltext), *The Review of Financial Studies*, 2020 66 | > 67 | > 代码发布在github https://github.com/MS20190155/Measuring-Corporate-Culture-Using-Machine-Learning 68 | 69 | 作者github的代码,我技术水平有限,很难直接拿来用,我修改了两处。 70 | 71 | - 原作者使用的stanfordnlp处理英文分词;wordexpansion改为jieba处理中文、nltk处理英文 72 | 73 | - 原作者在构建word2vec模型,考虑了Ngram;wordexpansion未考虑Ngram 74 | 75 | 76 | 77 | 两处更改,降低了代码的复杂程度,方便自己封装成包,供大家使用。大家也可根据自己能力,直接使用作者提供的代码。 78 | 79 | 80 | 81 | 82 | 83 |
84 | 85 | 86 | # 三、安装 87 | 88 | 89 | 90 | 最简单的安装,现在由于国内外网络不稳定,可能需要尝试几次 91 | 92 | ``` 93 | pip3 install wordexpansion 94 | ``` 95 | 96 | 97 | 98 |
99 | 100 | # 四、test项目文件目录 101 | 102 | >**注意:** 103 | >所有的txt文件,不论输入的还是程序输出的结果,均采用utf-8编码。 104 | 105 | ``` 106 | |---test 107 | |---共现法 108 | |--find_newwords.py #共现法测试代码 109 | |--corpus1.txt #语料(媒体报道)文本数据,5.5M 110 | |--test_seed_words.txt #情感种子词,需要手动构建 111 | |--neg_candi.txt #find_newwords.py运行后发现的负面候选词 112 | |--pos_candi.txt #find_newwords.py运行后发现的正面候选词 113 | 114 | |---词向量法 115 | |--run_w2v.py #词向量法测试代码 116 | |--corpus2.txt #语料(企业文化)文本数据,34M 117 | |--seeds #五种企业文化初始候选词(5个txt) 118 | |--model #word2vec训练过程中的模型(运行时产生的副产品) 119 | |--candidate_words #五种企业文化词典(5个txt) 120 | 121 | 122 | ``` 123 | 124 | 125 | 126 | # 五、共现法代码 127 | 128 | ### 5.1 准备构建种子词 129 | 130 | 可能我们希望的情感词典几万个,但是种子词100个(正面词50个,负面词50个)说不定就可以。 131 | 132 | 手动构建的种子词典**test_seed_words.txt**中 133 | 134 | - 每行一个词 135 | - 每个词用neg或pos标记 136 | - 词与标记用tab键间隔 137 | 138 | ``` 139 | 休克 neg 140 | 如出一辙 neg 141 | 渴求 neg 142 | 扎堆 neg 143 | 休整 neg 144 | 关门 neg 145 | 阴晴不定 neg 146 | 喜忧参半 neg 147 | 起起伏伏 neg 148 | 一厢情愿 neg 149 | 松紧 neg 150 | 最全 pos 151 | 雄风 pos 152 | 稳健 pos 153 | 稳定 pos 154 | 拉平 pos 155 | 保供 pos 156 | 修正 pos 157 | 稳 pos 158 | 稳住 pos 159 | 保养 pos 160 | ... 161 | ... 162 | ``` 163 | 164 | 165 | 166 | ### 5.2 发现情感新词 167 | 168 | 已经安装好了**wordexpansion**,现在我们新建一个名为**find_newwords.py**的测试代码 169 | 170 | 代码中的 171 | 172 | ```python 173 | from wordexpansion import ChineseSoPmi 174 | 175 | sopmier = ChineseSoPmi(inputtext_file='test_corpus.txt', 176 | seedword_txtfile='test_seed_words.txt', 177 | pos_candi_txt_file='pos_candi.txt', 178 | neg_candi_txtfile='neg_candi.txt') 179 | sopmier.sopmi() 180 | ``` 181 | 182 | 183 | 184 | 我们的语料数据**test_corpus.txt** 文件5.5M,100个候选词,运行程序大概耗时60s 185 | 186 | 187 | 188 | ### 5.3 输出的结果 189 | 190 | **find_newwords.py**运行结束后,会在**同文件夹内(find_newwords.py所在的文件夹)**发现有两个新的txt文件 191 | 192 | - pos_candi.txt 193 | - neg_candi.txt 194 | 195 | 打开**pos_candi.txt**, 我们看到 196 | 197 | ``` 198 | word,sopmi,polarity,word_length,postag 199 | 保持,87.28493062512524,pos,2,v 200 | 风险,70.15627986116269,pos,2,n 201 | 货币政策,66.28476448498694,pos,4,n 202 | 发展,64.40272795986517,pos,2,vn 203 | 不要,63.71800916752807,pos,2,df 204 | 理念,61.2024367757337,pos,2,n 205 | 整体,59.415315156715586,pos,2,n 206 | 下,59.321140440512984,pos,1,f 207 | 引导,58.5817208758171,pos,2,v 208 | 投资,57.71720491331896,pos,2,vn 209 | 加强,57.067969337267684,pos,2,v 210 | 自己,53.25503772499689,pos,2,r 211 | 提升,52.80686380719989,pos,2,v 212 | 和,52.12334472663675,pos,1,c 213 | 稳步,51.58193211655792,pos,2,d 214 | 重要,51.095865548255034,pos,2,a 215 | ... 216 | ``` 217 | 218 | 打开**neg_candi.txt**, 我们看到 219 | 220 | ``` 221 | word,sopmi,polarity,word_length,postag 222 | 心灵,33.17993872989303,neg,2,n 223 | 期间,31.77900620939178,neg,2,f 224 | 西溪,30.87839808390589,neg,2,ns 225 | 人事,29.594976229171877,neg,2,n 226 | 复杂,29.47870186147108,neg,2,a 227 | 直到,27.86014637934966,neg,2,v 228 | 宰客,27.27304813428452,neg,2,nr 229 | 保险,26.433136238404746,neg,2,n 230 | 迎来,25.83859896903048,neg,2,v 231 | 至少,25.105021416064616,neg,2,d 232 | 融资,25.09148586460598,neg,2,vn 233 | 或,24.48343281812743,neg,1,c 234 | 列,22.20695894382675,neg,1,v 235 | 存在,22.041049266517774,neg,2,v 236 | ... 237 | ``` 238 | 239 | 240 | 241 | 从上面的结果看,正面候选词较好,负面候选词有点差强人意。虽然差点,但节约了很多很多时间。 242 | 243 | 现在电脑已经帮我们找出候选词,我们人类最擅长找毛病,对neg_candi.txt和pos_candi.txt我们人类只需要一个个挑毛病,把不带正负情感的词剔除掉。这样经过一段时间的剔除工作,针对具体研究领域的专业情感词典就构建出来了。 244 | 245 | 246 | 247 | # 六、词向量法代码 248 | 249 | ## 6.1 准备种子词 250 | 251 | 词向量法程序会挖掘出原始数据中的所有词的词向量,这时候如果给词向量模型传入种子词,会根据向量的远近识别出多个近义词。人工构建了五大类企业文化词典,存放在txt中,即 252 | 253 | - innovation.txt 254 | - integrity.txt 255 | - quality.txt 256 | - respect.txt 257 | - teamwork.txt 258 | 259 | 注意,在txt中,每行一个词语。 260 | 261 | 262 | 263 | ### 6.2 发现情感新词 264 | 265 | 已经安装好了**wordexpansion**,现在我们新建一个名为**run_w2v.py**的测试代码 266 | 267 | 代码中的 268 | 269 | ```python 270 | from wordexpansion import W2VModels 271 | import pandas as pd 272 | import os 273 | 274 | #初始化模型 275 | model = W2VModels(cwd=os.getcwd()) 276 | model.train(documents=list(open('data/documents.txt').readlines())) 277 | 278 | #导入种子词 279 | integrity = [w for w in open('seeds/integrity.txt').read().split('\n') if w!=''] 280 | innovation = [w for w in open('seeds/innovation.txt').read().split('\n') if w!=''] 281 | quality = [w for w in open('seeds/quality.txt').read().split('\n') if w!=''] 282 | respect = [w for w in open('seeds/respect.txt').read().split('\n') if w!=''] 283 | teamwork = [w for w in open('seeds/teamwork.txt').read().split('\n') if w!=''] 284 | 285 | #根据种子词,筛选出没类词最相近的前100个词 286 | model.find(seedwords=integrity, seedwordsname='integrity', topn=100) 287 | model.find(seedwords=innovation, seedwordsname='innovation', topn=100) 288 | model.find(seedwords=quality, seedwordsname='quality', topn=100) 289 | model.find(seedwords=respect, seedwordsname='respect', topn=100) 290 | model.find(seedwords=teamwork, seedwordsname='teamwork', topn=100) 291 | 292 | ``` 293 | 294 | 295 | 296 | 我们的语料数据documents.txt 文件30+M,50多个候选词,运行程序大概耗时30s 297 | 298 |
299 | 300 | ### 6.3 输出的结果 301 | 302 | **run_w2v.py**运行结束后,会在**candidate_words内**发现有5个新的txt文件 303 | 304 | - innovation.txt 305 | - integrity.txt 306 | - quality.txt 307 | - respect.txt 308 | - teamwork.txt 309 | 310 | 打开**innovation.txt**, 我们看到 311 | 312 | ``` 313 | innovation 314 | innovate 315 | innovative 316 | creativity 317 | creative 318 | create 319 | passion 320 | passionate 321 | efficiency 322 | efficient 323 | excellence 324 | pride 325 | enhance 326 | expertise 327 | optimizing 328 | adapt 329 | capability 330 | awareness 331 | creating 332 | value-added 333 | optimize 334 | leveraging 335 | attract 336 | innovative 337 | manufacture 338 | efficient 339 | integrate 340 | better-for-you 341 | enhanced 342 | efficiently 343 | consolidate 344 | automation 345 | resources 346 | infrastructure 347 | innovation 348 | talent 349 | skills 350 | communicate 351 | differentiated 352 | network 353 | supporting 354 | dsd 355 | capture 356 | efficiency 357 | capabilities 358 | productive 359 | speed 360 | organized 361 | manual 362 | manage 363 | cost-effective 364 | simpler 365 | training 366 | technology 367 | merchandising 368 | interact 369 | drive 370 | organization 371 | reliability 372 | backbone 373 | strengthen 374 | attracting 375 | maximizing 376 | fine-tune 377 | enable 378 | headquarter 379 | platform 380 | tightly 381 | aligned 382 | flexible 383 | fulfillment 384 | rationalize 385 | back-office 386 | ensure 387 | manufacturing 388 | efficiencies 389 | effort 390 | technological 391 | retain 392 | proprietary 393 | durable 394 | diligent 395 | wap 396 | talented 397 | excitement 398 | logistical 399 | utilize 400 | bandwidth 401 | invest 402 | diversify 403 | higher-margin 404 | pride 405 | selecting 406 | managing 407 | departments 408 | engaging 409 | coordination 410 | multinational 411 | efforts 412 | store-within-store 413 | procurement 414 | workarounds 415 | nurture 416 | provides 417 | breadth 418 | viable 419 | superb 420 | digital 421 | smarter 422 | introducing 423 | beef 424 | proposition 425 | ``` 426 | 427 | 打开**respec.txt**, 我们看到 428 | 429 | ``` 430 | respectful 431 | talent 432 | talented 433 | employee 434 | dignity 435 | empowerment 436 | empower 437 | skills 438 | backbone 439 | training 440 | database 441 | designers 442 | sdk 443 | recruit 444 | engine 445 | dealers 446 | selecting 447 | resource 448 | onsite 449 | computer 450 | functions 451 | wholesalers 452 | educational 453 | expertise 454 | coordination 455 | value-added 456 | creative 457 | individuals 458 | managers 459 | pride 460 | technological 461 | awareness 462 | salespeople 463 | organized 464 | electrical 465 | reputation 466 | tools 467 | web-based 468 | fulfillment 469 | in-house 470 | staff 471 | motor 472 | crm 473 | communications 474 | attracting 475 | departments 476 | databases 477 | warsaw 478 | optimized 479 | functionality 480 | faces 481 | tool 482 | supported 483 | commission-based 484 | transportation 485 | centralized 486 | sponsor 487 | knowledge 488 | train 489 | assigned 490 | physician 491 | viability 492 | brokerage 493 | networks 494 | culture 495 | interior 496 | connecting 497 | leveraging 498 | mwd 499 | systems 500 | incentivized 501 | mission 502 | affiliated 503 | high-quality 504 | ecosystem 505 | eradication 506 | processes 507 | simplify 508 | on-site 509 | continuously 510 | recruiting 511 | practices 512 | dedicated 513 | adequately 514 | headquarter 515 | var 516 | practice 517 | airclic 518 | police 519 | architectural 520 | painlessly 521 | employing 522 | near-field 523 | corporations 524 | organization 525 | onshore 526 | adjacencies 527 | social 528 | well-known 529 | trained 530 | sap 531 | complement 532 | odms 533 | resources 534 | gasification 535 | salesforce 536 | third-party 537 | 538 | ``` 539 | 540 | 同理,在其他几类企业文化词典txt中产生了符合预期的词语。 541 | 542 | 现在电脑已经帮我们找出5类企业文化候选词,我们人类最擅长找毛病,对5个txt文件,我们人类只需要一个个挑毛病,把不带正负情感的词剔除掉。这样经过一段时间的剔除工作,针对具体研究领域的专业情感词典就构建出来了。 543 | 544 | 545 | 546 | 547 | 548 |
549 | 550 | # 七、注意: 551 | 1. so_pmi算法效果受训练语料影响,语料规模越大,效果越好 552 | 553 | 2. so_pmi算法效率受训练语料影响,语料越大,训练越耗时。100个种子词,5M的数据,大约耗时62.679秒 554 | 555 | 3. 候选词的选择,可根据PMI值,词长,词性设定规则,进行筛选   556 | 557 | 4. **所有的txt文件,不论输入的还是程序输出的结果,均采用utf-8编码。** 558 | 559 | 5. 词向量法没有考虑Ngram,如果采用了Ngram, 可能会挖掘出该场景下的词语组合。但是程序运行时间可能会更慢。 560 | 561 | 6. 如果刚刚好也想使用**企业文化5大类**这个具体场景,记得引用论文 562 | 563 | 7. > Kai Li, Feng Mai, Rui Shen, Xinyan Yan, Measuring Corporate Culture Using Machine Learning, *The Review of Financial Studies*,2020 564 | 565 | 566 | 567 |
568 | 569 | # 如果 570 | 571 | 如果您是经管人文社科专业背景,编程小白,面临海量文本数据采集和处理分析艰巨任务,可以参看[《python网络爬虫与文本数据分析》](https://ke.qq.com/course/482241?tuin=163164df)视频课。作为文科生,一样也是从两眼一抹黑开始,这门课程是用五年时间凝缩出来的。自认为讲的很通俗易懂o(* ̄︶ ̄*)o, 572 | 573 | - python入门 574 | - 网络爬虫 575 | - 数据读取 576 | - 文本分析入门 577 | - 机器学习与文本分析 578 | - 文本分析在经管研究中的应用 579 | 580 | 感兴趣的童鞋不妨 戳一下[《python网络爬虫与文本数据分析》](https://ke.qq.com/course/482241?tuin=163164df)进来看看~ 581 | 582 | [![](img/课程.png)](https://ke.qq.com/course/482241?tuin=163164df) 583 | 584 | 585 | 586 | # 更多 587 | 588 | - [B站:大邓和他的python](https://space.bilibili.com/122592901/channel/detail?cid=66008) 589 | 590 | - 公众号:大邓和他的python 591 | 592 | - [知乎专栏:数据科学家](https://zhuanlan.zhihu.com/dadeng) 593 | 594 | ![](img/大邓和他的Python.png) 595 |
596 | 597 | 598 | 599 | 600 | 601 | -------------------------------------------------------------------------------- /examples/01-cntext.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "name": "stdout", 10 | "output_type": "stream", 11 | "text": [ 12 | "Help on package cntext:\n", 13 | "\n", 14 | "NAME\n", 15 | " cntext\n", 16 | "\n", 17 | "PACKAGE CONTENTS\n", 18 | " description (package)\n", 19 | " dictionary (package)\n", 20 | " sentiment (package)\n", 21 | " similarity (package)\n", 22 | " visualization (package)\n", 23 | "\n", 24 | "DATA\n", 25 | " ADV_words = ['都', '全', '单', '共', '光', '尽', '净', '仅', '就', '只', '一共', '...\n", 26 | " CONJ_words = ['乃', '乍', '与', '无', '且', '丕', '为', '共', '其', '况', '厥', '...\n", 27 | " DUTIR_Ais = {'sigh', '一命呜呼', '一场春梦', '一场空', '一头跌在菜刀上-切肤之痛', '一念之差', .....\n", 28 | " DUTIR_Haos = {'1兒巴经', '3x', '8错', 'BUCUO', 'Cool毙', 'NB', ...}\n", 29 | " DUTIR_Jings = {'848', 'FT', '_god', 'yun', '一个骰子掷七点-出乎意料', '一举成名', ......\n", 30 | " DUTIR_Jus = {'一则以喜,一则以惧', '一发千钧', '一年被蛇咬,三年怕草索', '一座皆惊', '一脸横肉', '一蛇两头...\n", 31 | " DUTIR_Les = {':)', 'CC', 'Happy', 'LOL', '_so', 'haha', ...}\n", 32 | " DUTIR_Nus = {'2气斗狠', 'MD', 'TNND', 'gun', 'kao', '一刀两断', ...}\n", 33 | " DUTIR_Wus = {'B4', 'BD', 'BS', 'HC', 'HJ', 'JJWW', ...}\n", 34 | " HOWNET_deny = {'不', '不可', '不是', '不能', '不要', '休', ...}\n", 35 | " HOWNET_extreme = {'万', '万万', '万分', '万般', '不亦乐乎', '不可开交', ...}\n", 36 | " HOWNET_ish = {'一些', '一点', '一点儿', '不丁点儿', '不大', '不怎么', ...}\n", 37 | " HOWNET_more = {'多', '大不了', '如斯', '尤甚', '强', '愈', ...}\n", 38 | " HOWNET_neg = {'一下子爆发', '一下子爆发的一连串', '一不小心', '一个屁', '一仍旧贯', '一偏', ...}\n", 39 | " HOWNET_pos = {'', '一专多能', '一丝不差', '一丝不苟', '一个心眼儿', '一五一十', ...}\n", 40 | " HOWNET_very = {'不为过', '不少', '不胜', '不过', '何啻', '何止', ...}\n", 41 | " STOPWORDS_en = {'a', 'about', 'above', 'across', 'after', 'afterwards'...\n", 42 | " STOPWORDS_zh = {'、', '。', '〈', '〉', '《', '》', ...}\n", 43 | "\n", 44 | "FILE\n", 45 | " /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/cntext/__init__.py\n", 46 | "\n", 47 | "\n" 48 | ] 49 | } 50 | ], 51 | "source": [ 52 | "import cntext\n", 53 | "\n", 54 | "help(cntext)" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": 2, 60 | "metadata": {}, 61 | "outputs": [ 62 | { 63 | "name": "stdout", 64 | "output_type": "stream", 65 | "text": [ 66 | "\n", 67 | " 【大连理工大学情感本体库】\n", 68 | " 七大情绪分类,依次是哀、恶、好、惊、惧、乐、怒;对应的情绪词表依次:\n", 69 | " DUTIR_Ais = {\"泣血捶膺\", \"望断白云\", \"日暮途穷\", \"身微力薄\"...}\n", 70 | " DUTIR_Wus = {\"饰非遂过\", \"恶语\", \"毁害\", \"恶籍盈指\", \"脾气爆躁\", \"淫贱\", \"凌乱\"...}\n", 71 | " DUTIR_Haos = {\"打破砂锅璺到底\", \"多彩\", \"披沙拣金\", \"见机行事\", \"精神饱满\"...}\n", 72 | " DUTIR_Jings = {\"骇人视听\", \"拍案惊奇\", \"悬念\", \"无翼而飞\", \"原来\", \"冷门\"...}\n", 73 | " DUTIR_Jus ={\"山摇地动\", \"月黑风高\", \"流血\", \"老鼠偷猫饭-心惊肉跳\", \"一发千钧\"...}\n", 74 | " DUTIR_Les ={\"含哺鼓腹\", \"欢呼鼓舞\", \"莺歌蝶舞\", \"将伯之助\", \"逸兴横飞\", \"舒畅\"...}\n", 75 | " DUTIR_Nus = {\"怨气满腹\", \"面有愠色\", \"愤愤\", \"直眉瞪眼\", \"负气斗狠\", \"挑眼\"...}\n", 76 | " \n", 77 | " 【知网Hownet词典】\n", 78 | " 含正负形容词、否定词、副词等词表,对应的词表依次:\n", 79 | " HOWNET_deny = {\"不\", \"不是\", \"不能\", \"不可\"...}\n", 80 | " HOWNET_extreme = {\"百分之百\", \"倍加\", \"备至\", \"不得了\"...}\n", 81 | " HOWNET_ish = {\"点点滴滴\", \"多多少少\", \"怪\", \"好生\", \"还\", \"或多或少\"...}\n", 82 | " HOWNET_more = {\"大不了\", \"多\", \"更\", \"比较\", \"更加\", \"更进一步\", \"更为\", \"还\", \"还要\"...}\n", 83 | " HOWNET_neg = {\"压坏\", \"鲁莽的\", \"被控犯罪\", \"银根紧\", \"警惕的\", \"残缺\", \"致污物\", \"柔弱\"...}\n", 84 | " HOWNET_pos = {\"无误\", \"感激不尽\", \"受大众欢迎\", \"敬礼\", \"文雅\", \"一尘不染\", \"高精度\", \"兴盛\"...}\n", 85 | " HOWNET_very = {\"不为过\", \"超\", \"超额\", \"超外差\", \"超微结构\", \"超物质\", \"出头\"...}\n", 86 | " \n", 87 | " 【停用词表】\n", 88 | " 中英文停用词表,依次\n", 89 | " STOPWORDS_zh = {\"经\", \"得\", \"则甚\", \"跟\", \"好\", \"具体地说\"...}\n", 90 | " STOPWORDS_en = {'a', 'about', 'above', 'across', 'after'...}\n", 91 | " \n", 92 | " 【中文副词/连词】\n", 93 | " 副词ADV、连词CONJ\n", 94 | " ADV_words = ['都', '全', '单', '共', '光'...}\n", 95 | " CONJ_words = ['乃', '乍', '与', '无', '且'...}\n", 96 | " \n" 97 | ] 98 | } 99 | ], 100 | "source": [ 101 | "from cntext import dict_info\n", 102 | "\n", 103 | "dict_info()" 104 | ] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": 3, 109 | "metadata": { 110 | "collapsed": true 111 | }, 112 | "outputs": [ 113 | { 114 | "data": { 115 | "text/plain": [ 116 | "['乃',\n", 117 | " '乍',\n", 118 | " '与',\n", 119 | " '无',\n", 120 | " '且',\n", 121 | " '丕',\n", 122 | " '为',\n", 123 | " '共',\n", 124 | " '其',\n", 125 | " '况',\n", 126 | " '厥',\n", 127 | " '则',\n", 128 | " '那',\n", 129 | " '兼',\n", 130 | " '凭',\n", 131 | " '即',\n", 132 | " '却',\n", 133 | " '今',\n", 134 | " '以',\n", 135 | " '令',\n", 136 | " '会',\n", 137 | " '任',\n", 138 | " '但',\n", 139 | " '使',\n", 140 | " '便',\n", 141 | " '倘',\n", 142 | " '借',\n", 143 | " '假',\n", 144 | " '傥',\n", 145 | " '单',\n", 146 | " '讵',\n", 147 | " '设',\n", 148 | " '谓',\n", 149 | " '及',\n", 150 | " '苟',\n", 151 | " '若',\n", 152 | " '连',\n", 153 | " '迨',\n", 154 | " '适',\n", 155 | " '将',\n", 156 | " '并',\n", 157 | " '当',\n", 158 | " '带',\n", 159 | " '句',\n", 160 | " '同',\n", 161 | " '向',\n", 162 | " '和',\n", 163 | " '唯',\n", 164 | " '噎',\n", 165 | " '噫',\n", 166 | " '宁',\n", 167 | " '如',\n", 168 | " '饶',\n", 169 | " '抑',\n", 170 | " '浸',\n", 171 | " '纵',\n", 172 | " '维',\n", 173 | " '缘',\n", 174 | " '坐',\n", 175 | " '因',\n", 176 | " '惟',\n", 177 | " '就',\n", 178 | " '子',\n", 179 | " '焉',\n", 180 | " '然',\n", 181 | " '载',\n", 182 | " '旋',\n", 183 | " '或',\n", 184 | " '所',\n", 185 | " '既',\n", 186 | " '斯',\n", 187 | " '果',\n", 188 | " '故',\n", 189 | " '是',\n", 190 | " '暨',\n", 191 | " '必',\n", 192 | " '忍',\n", 193 | " '总',\n", 194 | " '恁',\n", 195 | " '更',\n", 196 | " '脱',\n", 197 | " '爰',\n", 198 | " '甚',\n", 199 | " '盖',\n", 200 | " '直',\n", 201 | " '矧',\n", 202 | " '由',\n", 203 | " '用',\n", 204 | " '虽',\n", 205 | " '而',\n", 206 | " '耳',\n", 207 | " '要',\n", 208 | " '至',\n", 209 | " '第',\n", 210 | " '管',\n", 211 | " '自',\n", 212 | " '跟',\n", 213 | " '须',\n", 214 | " '',\n", 215 | " '纵使',\n", 216 | " '纵令',\n", 217 | " '纵然',\n", 218 | " '再说',\n", 219 | " '虚词',\n", 220 | " '至于',\n", 221 | " '至若',\n", 222 | " '至乎',\n", 223 | " '至如',\n", 224 | " '只有',\n", 225 | " '只要',\n", 226 | " '至乃',\n", 227 | " '致使',\n", 228 | " '自然',\n", 229 | " '再不',\n", 230 | " '于是乎',\n", 231 | " '于是',\n", 232 | " '又且',\n", 233 | " '与其',\n", 234 | " '由于',\n", 235 | " '因而',\n", 236 | " '因为',\n", 237 | " '以致',\n", 238 | " '以至',\n", 239 | " '要是',\n", 240 | " '以及',\n", 241 | " '以下',\n", 242 | " '以为',\n", 243 | " '虚字',\n", 244 | " '焉乃',\n", 245 | " '勿然',\n", 246 | " '万一',\n", 247 | " '无论',\n", 248 | " '忘其',\n", 249 | " '亡其',\n", 250 | " '倘然',\n", 251 | " '倘使',\n", 252 | " '所以',\n", 253 | " '顺推',\n", 254 | " '庶几',\n", 255 | " '顺接',\n", 256 | " '是故',\n", 257 | " '是以',\n", 258 | " '甚至',\n", 259 | " '设或',\n", 260 | " '设若',\n", 261 | " '便乃',\n", 262 | " '便做',\n", 263 | " '别管',\n", 264 | " '不然',\n", 265 | " '不论',\n", 266 | " '不怕',\n", 267 | " '不拘',\n", 268 | " '不仅',\n", 269 | " '不但',\n", 270 | " '不过',\n", 271 | " '不管',\n", 272 | " '不料',\n", 273 | " '诚然',\n", 274 | " '词类',\n", 275 | " '除非',\n", 276 | " '但凡',\n", 277 | " '从而',\n", 278 | " '等到',\n", 279 | " '当使',\n", 280 | " '分句',\n", 281 | " '而亦',\n", 282 | " '而乃',\n", 283 | " '尔其',\n", 284 | " '而且',\n", 285 | " '反而',\n", 286 | " '而况',\n", 287 | " '否则',\n", 288 | " '固然',\n", 289 | " '故尔',\n", 290 | " '果然',\n", 291 | " '或曰',\n", 292 | " '或是',\n", 293 | " '或者',\n", 294 | " '何况',\n", 295 | " '及至',\n", 296 | " '及以',\n", 297 | " '既然',\n", 298 | " '即使',\n", 299 | " '假借义',\n", 300 | " '加以',\n", 301 | " '加之',\n", 302 | " '尽管',\n", 303 | " '借如',\n", 304 | " '借令',\n", 305 | " '尽管',\n", 306 | " '借使',\n", 307 | " '就是',\n", 308 | " '可是',\n", 309 | " '况乎',\n", 310 | " '况于',\n", 311 | " '连絶',\n", 312 | " '况且',\n", 313 | " '哪怕',\n", 314 | " '乃至',\n", 315 | " '譬如',\n", 316 | " '丕则',\n", 317 | " '丕乃',\n", 318 | " '且夫',\n", 319 | " '然则',\n", 320 | " '然而',\n", 321 | " '任凭',\n", 322 | " '如其',\n", 323 | " '如果']" 324 | ] 325 | }, 326 | "execution_count": 3, 327 | "metadata": {}, 328 | "output_type": "execute_result" 329 | } 330 | ], 331 | "source": [ 332 | "from cntext import CONJ_words, ADV_words\n", 333 | "\n", 334 | "CONJ_words" 335 | ] 336 | }, 337 | { 338 | "cell_type": "code", 339 | "execution_count": 4, 340 | "metadata": { 341 | "collapsed": true 342 | }, 343 | "outputs": [ 344 | { 345 | "data": { 346 | "text/plain": [ 347 | "['都',\n", 348 | " '全',\n", 349 | " '单',\n", 350 | " '共',\n", 351 | " '光',\n", 352 | " '尽',\n", 353 | " '净',\n", 354 | " '仅',\n", 355 | " '就',\n", 356 | " '只',\n", 357 | " '一共',\n", 358 | " '一起',\n", 359 | " '一同',\n", 360 | " '一道',\n", 361 | " '一齐',\n", 362 | " '一概',\n", 363 | " '一味',\n", 364 | " '统统',\n", 365 | " '总共',\n", 366 | " '仅仅',\n", 367 | " '惟独',\n", 368 | " '可',\n", 369 | " '倒',\n", 370 | " '一定',\n", 371 | " '必定',\n", 372 | " '必然',\n", 373 | " '却',\n", 374 | " '',\n", 375 | " '就',\n", 376 | " '幸亏',\n", 377 | " '难道',\n", 378 | " '何尝',\n", 379 | " '偏偏',\n", 380 | " '索性',\n", 381 | " '简直',\n", 382 | " '反正',\n", 383 | " '多亏',\n", 384 | " '也许',\n", 385 | " '大约',\n", 386 | " '好在',\n", 387 | " '敢情',\n", 388 | " '不',\n", 389 | " '没',\n", 390 | " '没有',\n", 391 | " '别',\n", 392 | " '刚',\n", 393 | " '恰好',\n", 394 | " '正',\n", 395 | " '将',\n", 396 | " '老是',\n", 397 | " '总是',\n", 398 | " '早就',\n", 399 | " '已经',\n", 400 | " '正在',\n", 401 | " '立刻',\n", 402 | " '马上',\n", 403 | " '起初',\n", 404 | " '原先',\n", 405 | " '一向',\n", 406 | " '永远',\n", 407 | " '从来',\n", 408 | " '偶尔',\n", 409 | " '随时',\n", 410 | " '忽然',\n", 411 | " '很',\n", 412 | " '极',\n", 413 | " '最',\n", 414 | " '太',\n", 415 | " '更',\n", 416 | " '更加',\n", 417 | " '格外',\n", 418 | " '十分',\n", 419 | " '极其',\n", 420 | " '比较',\n", 421 | " '相当',\n", 422 | " '稍微',\n", 423 | " '略微',\n", 424 | " '多么',\n", 425 | " '仿佛',\n", 426 | " '渐渐',\n", 427 | " '百般',\n", 428 | " '特地',\n", 429 | " '互相',\n", 430 | " '擅自',\n", 431 | " '几乎',\n", 432 | " '逐渐',\n", 433 | " '逐步',\n", 434 | " '猛然',\n", 435 | " '依然',\n", 436 | " '仍然',\n", 437 | " '当然',\n", 438 | " '毅然',\n", 439 | " '果然',\n", 440 | " '差点儿']" 441 | ] 442 | }, 443 | "execution_count": 4, 444 | "metadata": {}, 445 | "output_type": "execute_result" 446 | } 447 | ], 448 | "source": [ 449 | "ADV_words" 450 | ] 451 | }, 452 | { 453 | "cell_type": "code", 454 | "execution_count": null, 455 | "metadata": {}, 456 | "outputs": [], 457 | "source": [] 458 | } 459 | ], 460 | "metadata": { 461 | "kernelspec": { 462 | "display_name": "Python 3", 463 | "language": "python", 464 | "name": "python3" 465 | }, 466 | "language_info": { 467 | "codemirror_mode": { 468 | "name": "ipython", 469 | "version": 3 470 | }, 471 | "file_extension": ".py", 472 | "mimetype": "text/x-python", 473 | "name": "python", 474 | "nbconvert_exporter": "python", 475 | "pygments_lexer": "ipython3", 476 | "version": "3.7.5" 477 | }, 478 | "toc": { 479 | "base_numbering": 1, 480 | "nav_menu": {}, 481 | "number_sections": true, 482 | "sideBar": true, 483 | "skip_h1_title": false, 484 | "title_cell": "Table of Contents", 485 | "title_sidebar": "Contents", 486 | "toc_cell": false, 487 | "toc_position": {}, 488 | "toc_section_display": true, 489 | "toc_window_display": false 490 | } 491 | }, 492 | "nbformat": 4, 493 | "nbformat_minor": 4 494 | } 495 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cntext 2 | 3 | 中文文本分析库,可对文本进行词频统计、词典扩充、情绪分析、相似度、可读性等 4 | 5 | - [github地址](https://github.com/hidadeng/cntext) ``https://github.com/hidadeng/cntext`` 6 | - [pypi地址](https://pypi.org/project/cntext/) ``https://pypi.org/project/cntext/`` 7 | - [视频课-**Python网络爬虫与文本数据分析**](https://ke.qq.com/course/482241?tuin=163164df) 8 | 9 | 10 | 11 | 功能模块含 12 | 13 | - **cntext** 14 | - **stats** 文本统计,可读性等 15 | - **dictionary** 构建词表(典) 16 | - **sentiment** 情感分析 17 | - **similarity** 文本相似度 18 | - **visualization** 可视化,如词云图 19 | 20 | 21 | 22 |
23 | 24 | ## 安装 25 | 26 | ``` 27 | pip install cntext==0.9 28 | ``` 29 | 30 | 31 | 32 |
33 | 34 | ## 一、cntext 35 | 36 | 查看cntext基本信息 37 | 38 | ```python 39 | import cntext 40 | 41 | help(cntext) 42 | ``` 43 | 44 | Run 45 | 46 | ``` 47 | Help on package cntext: 48 | 49 | NAME 50 | cntext 51 | 52 | PACKAGE CONTENTS 53 | description (package) 54 | dictionary (package) 55 | sentiment (package) 56 | similarity (package) 57 | visualization (package) 58 | 59 | DATA 60 | ADV_words = ['都', '全', '单', '共', '光', '尽', '净', '仅', '就', '只', '一共', '... 61 | CONJ_words = ['乃', '乍', '与', '无', '且', '丕', '为', '共', '其', '况', '厥', '... 62 | DUTIR_Ais = {'sigh', '一命呜呼', '一场春梦', '一场空', '一头跌在菜刀上-切肤之痛', '一念之差', ..... 63 | DUTIR_Haos = {'1兒巴经', '3x', '8错', 'BUCUO', 'Cool毙', 'NB', ...} 64 | DUTIR_Jings = {'848', 'FT', '_god', 'yun', '一个骰子掷七点-出乎意料', '一举成名', ...... 65 | DUTIR_Jus = {'一则以喜,一则以惧', '一发千钧', '一年被蛇咬,三年怕草索', '一座皆惊', '一脸横肉', '一蛇两头... 66 | DUTIR_Les = {':)', 'CC', 'Happy', 'LOL', '_so', 'haha', ...} 67 | DUTIR_Nus = {'2气斗狠', 'MD', 'TNND', 'gun', 'kao', '一刀两断', ...} 68 | DUTIR_Wus = {'B4', 'BD', 'BS', 'HC', 'HJ', 'JJWW', ...} 69 | HOWNET_deny = {'不', '不可', '不是', '不能', '不要', '休', ...} 70 | HOWNET_extreme = {'万', '万万', '万分', '万般', '不亦乐乎', '不可开交', ...} 71 | HOWNET_ish = {'一些', '一点', '一点儿', '不丁点儿', '不大', '不怎么', ...} 72 | HOWNET_more = {'多', '大不了', '如斯', '尤甚', '强', '愈', ...} 73 | HOWNET_neg = {'一下子爆发', '一下子爆发的一连串', '一不小心', '一个屁', '一仍旧贯', '一偏', ...} 74 | HOWNET_pos = {'', '一专多能', '一丝不差', '一丝不苟', '一个心眼儿', '一五一十', ...} 75 | HOWNET_very = {'不为过', '不少', '不胜', '不过', '何啻', '何止', ...} 76 | STOPWORDS_en = {'a', 'about', 'above', 'across', 'after', 'afterwards'... 77 | STOPWORDS_zh = {'、', '。', '〈', '〉', '《', '》', ...} 78 | 79 | FILE 80 | /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/cntext/__init__.py 81 | ``` 82 | 83 |
84 | 85 | ```python 86 | from cntext import dict_info 87 | 88 | dict_info() 89 | ``` 90 | 91 | Run 92 | 93 | ``` 94 | 【大连理工大学情感本体库】 95 | 七大情绪分类,依次是哀、恶、好、惊、惧、乐、怒;对应的情绪词表依次: 96 | DUTIR_Ais = {"泣血捶膺", "望断白云", "日暮途穷", "身微力薄"...} 97 | DUTIR_Wus = {"饰非遂过", "恶语", "毁害", "恶籍盈指", "脾气爆躁", "淫贱", "凌乱"...} 98 | DUTIR_Haos = {"打破砂锅璺到底", "多彩", "披沙拣金", "见机行事", "精神饱满"...} 99 | DUTIR_Jings = {"骇人视听", "拍案惊奇", "悬念", "无翼而飞", "原来", "冷门"...} 100 | DUTIR_Jus ={"山摇地动", "月黑风高", "流血", "老鼠偷猫饭-心惊肉跳", "一发千钧"...} 101 | DUTIR_Les ={"含哺鼓腹", "欢呼鼓舞", "莺歌蝶舞", "将伯之助", "逸兴横飞", "舒畅"...} 102 | DUTIR_Nus = {"怨气满腹", "面有愠色", "愤愤", "直眉瞪眼", "负气斗狠", "挑眼"...} 103 | 104 | 【知网Hownet词典】 105 | 含正负形容词、否定词、副词等词表,对应的词表依次: 106 | HOWNET_deny = {"不", "不是", "不能", "不可"...} 107 | HOWNET_extreme = {"百分之百", "倍加", "备至", "不得了"...} 108 | HOWNET_ish = {"点点滴滴", "多多少少", "怪", "好生", "还", "或多或少"...} 109 | HOWNET_more = {"大不了", "多", "更", "比较", "更加", "更进一步", "更为", "还", "还要"...} 110 | HOWNET_neg = {"压坏", "鲁莽的", "被控犯罪", "银根紧", "警惕的", "残缺", "致污物", "柔弱"...} 111 | HOWNET_pos = {"无误", "感激不尽", "受大众欢迎", "敬礼", "文雅", "一尘不染", "高精度", "兴盛"...} 112 | HOWNET_very = {"不为过", "超", "超额", "超外差", "超微结构", "超物质", "出头"...} 113 | 114 | 【停用词表】 115 | 中英文停用词表,依次 116 | STOPWORDS_zh = {"经", "得", "则甚", "跟", "好", "具体地说"...} 117 | STOPWORDS_en = {'a', 'about', 'above', 'across', 'after'...} 118 | 119 | 【中文副词/连词】 120 | 副词ADV、连词CONJ 121 | ADV_words = ['都', '全', '单', '共', '光'...} 122 | CONJ_words = ['乃', '乍', '与', '无', '且'...} 123 | ``` 124 | 125 |
126 | 127 | 查看词表 128 | 129 | ```python 130 | from cntext import CONJ_words, ADV_words 131 | 132 | #获取连词词表 133 | CONJ_words 134 | ``` 135 | 136 | Run 137 | 138 | ``` 139 | ['乃', 140 | '乍', 141 | '与', 142 | '无', 143 | '且', 144 | '丕', 145 | '为', 146 | '共', 147 | '其', 148 | '况', 149 | '厥', 150 | '则', 151 | '那', 152 | '兼', 153 | ... 154 | ] 155 | ``` 156 | 157 | 158 | 159 |

160 | 161 | ## 二、stats 162 | 163 | 目前含 164 | 165 | - term_freq 词频统计函数,返回Counter类型 166 | - readability 中文可读性 167 | 168 | ```python 169 | from cntext.stats import term_freq, readability 170 | 171 | text = '如何看待一网文作者被黑客大佬盗号改文,因万分惭愧而停更' 172 | term_freq(text) 173 | ``` 174 | 175 | ``` 176 | Counter({'看待': 1, 177 | '网文': 1, 178 | '作者': 1, 179 | '黑客': 1, 180 | '大佬': 1, 181 | '盗号': 1, 182 | '改文因': 1, 183 | '万分': 1, 184 | '惭愧': 1, 185 | '停': 1}) 186 | ``` 187 | 188 | 189 | 190 |
191 | 192 | **中文可读性 ** 算法参考自 193 | 194 | > 徐巍,姚振晔,陈冬华.中文年报可读性:衡量与检验[J].会计研究,2021(03):28-44. 195 | 196 | - readability1 ---每个分句中的平均字数 197 | - readability2 ---每个句子中副词和连词所占的比例 198 | - readability3 ---参考Fog Index, readability3=(readability1+readability2)×0.5 199 | 200 | 201 | 以上三个指标越大,都说明文本的复杂程度越高,可读性越差。 202 | 203 | ```python 204 | readability(text) 205 | ``` 206 | 207 | ``` 208 | {'readability1': 27.0, 209 | 'readability2': 0.17647058823529413, 210 | 'readability3': 13.588235294117647} 211 | ``` 212 | 213 | 214 | 215 | 216 | 217 |

218 | 219 | ## 三、dictionary 220 | 221 | 本模块用于构建词表(典),含 222 | 223 | - SoPmi 共现法扩充词表(典) 224 | - W2VModels 词向量word2vec扩充词表(典) 225 | 226 | ### 3.1 SoPmi 共现法 227 | 228 | ```python 229 | from cntext.dictionary import SoPmi 230 | import os 231 | 232 | sopmier = SoPmi(cwd=os.getcwd(), 233 | input_txt_file='data/sopmi_corpus.txt', #原始数据,您的语料 234 | seedword_txt_file='data/sopmi_seed_words.txt', #人工标注的初始种子词 235 | ) 236 | 237 | sopmier.sopmi() 238 | ``` 239 | 240 | Run 241 | 242 | ``` 243 | step 1/4:...seg corpus ... 244 | Loading model cost 0.678 seconds. 245 | Prefix dict has been built successfully. 246 | step 1/4 finished:...cost 60.78995203971863... 247 | step 2/4:...collect cowords ... 248 | step 2/4 finished:...cost 0.6169600486755371... 249 | step 3/4:...compute sopmi ... 250 | step 1/4 finished:...cost 0.26422882080078125... 251 | step 4/4:...save candiwords ... 252 | finished! cost 61.8965539932251 253 | ``` 254 | 255 | 256 | 257 |
258 | 259 | ### 3.2 W2VModels 词向量 260 | 261 | ```python 262 | from cntext.dictionary import W2VModels 263 | import os 264 | 265 | #初始化模型 266 | model = W2VModels(cwd=os.getcwd()) #语料数据 w2v_corpus.txt 267 | model.train(input_txt_file='data/w2v_corpus.txt') 268 | 269 | 270 | #根据种子词,筛选出没类词最相近的前100个词 271 | model.find(seedword_txt_file='data/w2v_seeds/integrity.txt', 272 | topn=100) 273 | model.find(seedword_txt_file='data/w2v_seeds/innovation.txt', 274 | topn=100) 275 | model.find(seedword_txt_file='data/w2v_seeds/quality.txt', 276 | topn=100) 277 | model.find(seedword_txt_file='data/w2v_seeds/respect.txt', 278 | topn=100) 279 | model.find(seedword_txt_file='data/w2v_seeds/teamwork.txt', 280 | topn=100) 281 | ``` 282 | 283 | Run 284 | 285 | ``` 286 | 数据预处理开始....... 287 | 预处理结束........... 288 | Word2Vec模型训练开始...... 289 | 已将模型存入 /Users/Desktop/cntext/test/output/w2v_candi_words/w2v.model 290 | 291 | 准备寻找每个seed在语料中所有的相似候选词 292 | 初步搜寻到 572 个相似的候选词 293 | 计算每个候选词 与 integrity 的相似度, 选出相似度最高的前 100 个候选词 294 | 已完成 【integrity 类】 的词语筛选,并保存于 /Users/Desktop/cntext/test/output/w2v_candi_words/integrity.txt, 耗时 46 秒 295 | 296 | 准备寻找每个seed在语料中所有的相似候选词 297 | 初步搜寻到 516 个相似的候选词 298 | 计算每个候选词 与 innovation 的相似度, 选出相似度最高的前 100 个候选词 299 | 已完成 【innovation 类】 的词语筛选,并保存于 /Users/Desktop/cntext/test/output/w2v_candi_words/innovation.txt, 耗时 46 秒 300 | 301 | 准备寻找每个seed在语料中所有的相似候选词 302 | 初步搜寻到 234 个相似的候选词 303 | 计算每个候选词 与 quality 的相似度, 选出相似度最高的前 100 个候选词 304 | 已完成 【quality 类】 的词语筛选,并保存于 /Users/Desktop/cntext/test/output/w2v_candi_words/quality.txt, 耗时 46 秒 305 | 306 | 准备寻找每个seed在语料中所有的相似候选词 307 | 初步搜寻到 243 个相似的候选词 308 | 计算每个候选词 与 respect 的相似度, 选出相似度最高的前 100 个候选词 309 | 已完成 【respect 类】 的词语筛选,并保存于 /Users/Desktop/cntext/test/output/w2v_candi_words/respect.txt, 耗时 46 秒 310 | 311 | 准备寻找每个seed在语料中所有的相似候选词 312 | 初步搜寻到 319 个相似的候选词 313 | 计算每个候选词 与 teamwork 的相似度, 选出相似度最高的前 100 个候选词 314 | 已完成 【teamwork 类】 的词语筛选,并保存于 /Users/Desktop/cntext/test/output/w2v_candi_words/teamwork.txt, 耗时 46 秒 315 | ``` 316 | 317 |

318 | 319 | 320 | 321 | ## 四、 sentiment 322 | 323 | - senti_by_hownet 使用知网Hownet词典对文本进行**情感**分析 324 | - senti_by_dutir 使用大连理工大学情感本体库dutir对文本进行**情绪**分析 325 | - senti_by_diydict 使用**自定义词典** 对文本进行**情感**分析 326 | 327 | 328 | 329 | ### 4.1 senti_by_hownet(text, adj_adv=False) 330 | 331 | 使用知网Hownet词典进行(中)文本数据的情感分析,统计正、负情感信息出现次数(得分) 332 | 333 | - text: 待分析的中文文本数据 334 | - adj_adv: 是否考虑副词(否定词、程度词)对情绪形容词的反转和情感强度修饰作用,默认False。默认False只统计情感形容词出现个数; 335 | 336 | ```python 337 | from cntext.sentiment import senti_by_hownet 338 | 339 | text = '今天股票大涨,心情倍爽,非常开心啊。' 340 | 341 | senti_by_dutir(text) 342 | ``` 343 | 344 | Run 345 | 346 | ``` 347 | {'word_num': 12, 348 | 'sentence_num': 2, 349 | 'stopword_num': 4, 350 | '好_num': 0, 351 | '乐_num': 1, 352 | '哀_num': 0, 353 | '怒_num': 0, 354 | '惧_num': 0, 355 | '恶_num': 0, 356 | '惊_num': 0} 357 | ``` 358 | 359 |
360 | 361 | 考虑副词(否定词、程度词)对情绪形容词的反转和情感强度修饰作用 362 | 363 | ```python 364 | senti_by_hownet(text, adj_adv=True) 365 | ``` 366 | 367 | Run 368 | 369 | ``` 370 | {'sentence_num': 1, 371 | 'word_num': 12, 372 | 'stopword_num': 3, 373 | 'pos_score': 13.0, 374 | 'neg_score': 0.0} 375 | ``` 376 | 377 | 378 | 379 |

380 | 381 | ### 4.2 senti_by_dutir(text) 382 | 383 | 使用大连理工大学情感本体库对文本进行情绪分析,统计各情绪词语出现次数。 384 | 385 | ```python 386 | from cntext.sentiment import senti_by_dutir 387 | 388 | text = '今天股票大涨,心情倍爽,非常开心啊。' 389 | 390 | senti_by_dutir(text) 391 | ``` 392 | 393 | Run 394 | 395 | ``` 396 | {'word_num': 12, 397 | 'sentence_num': 2, 398 | 'stopword_num': 4, 399 | '好_num': 0, 400 | '乐_num': 1, 401 | '哀_num': 0, 402 | '怒_num': 0, 403 | '惧_num': 0, 404 | '恶_num': 0, 405 | '惊_num': 0} 406 | ``` 407 | 408 | >情绪分析使用的大连理工大学情感本体库,如发表论文,请注意用户许可协议 409 | > 410 | >如果用户使用该资源发表论文或取得科研成果,请在论文中添加诸如“使用了大连理工大学信息检索研究室的情感词汇本体” 字样加以声明。 411 | > 412 | >参考文献中加入引文“徐琳宏,林鸿飞,潘宇,等.情感词汇本体的构造[J]. 情报学报, 2008, 27(2): 180-185.” 413 | > 414 | > 415 | 416 | 417 | 418 |

419 | 420 | ### 4.3 senti_by_diy(text) 421 | 422 | 使用diy词典进行情感分析,计算各个情绪词出现次数,未考虑强度副词、否定词对情感的复杂影响, 423 | 424 | - text: 待分析中文文本 425 | - sentiwords: 情感词字典; 426 | {'category1': 'category1 词语列表', 427 | 'category2': 'category2词语列表', 428 | 'category3': 'category3词语列表', 429 | ... 430 | } 431 | 432 | ```python 433 | sentiwords = {'pos': ['开心', '愉快', '倍爽'], 434 | 'neg': ['难过', '悲伤'], 435 | 'adv': ['倍']} 436 | 437 | text = '今天股票大涨,心情倍爽,非常开心啊。' 438 | senti_by_diydict(text, sentiwords) 439 | ``` 440 | 441 | Run 442 | 443 | ``` 444 | {'pos_num': 1, 445 | 'neg_num': 0, 446 | 'adv_num': 1, 447 | 'stopword_num': 4, 448 | 'sentence_num': 2, 449 | 'word_num': 12} 450 | ``` 451 | 452 |

453 | 454 | 455 | 456 | ### 4.4 注意 457 | 458 | **返回结果**: **num**表示词语出现次数; score是考虑副词、否定词对情感的修饰,结果不是词频,是情感类别的得分。 459 | 460 |

461 | 462 | 463 | 464 | ## 五、similarity 465 | 466 | 使用cosine、jaccard、miniedit等计算两文本的相似度,算法实现参考自 467 | 468 | > Cohen, Lauren, Christopher Malloy, and Quoc Nguyen. Lazy prices. No. w25084. National Bureau of Economic Research, 2018. 469 | 470 |
471 | 472 | ``` 473 | from cntext.similarity import similarity_score 474 | 475 | text1 = '编程真好玩编程真好玩' 476 | text2 = '游戏真好玩编程真好玩' 477 | 478 | similarity_score(text1, text2) 479 | ``` 480 | 481 | Run 482 | 483 | ``` 484 | {'Sim_Cosine': 0.816496580927726, 485 | 'Sim_Jaccard': 0.6666666666666666, 486 | 'Sim_MinEdit': 1, 487 | 'Sim_Simple': 0.9183673469387755} 488 | ``` 489 | 490 |

491 | 492 | 493 | 494 | ## 六、visualization 495 | 496 | 文本信息可视化,含wordcloud、wordshiftor 497 | 498 | - wordcloud 词云图 499 | - wordshiftor 两文本词移图 500 | 501 | ### 6.1 wordcloud(text, title, html_path) 502 | 503 | - text: 中文文本字符串数据 504 | - title: 词云图标题 505 | - html_path: 词云图html文件存储路径 506 | 507 | ```python 508 | from cntext.visualization import wordcloud 509 | 510 | text1 = """在信息化时代,各种各样的数据被广泛采集和利用,有些数据看似无关紧要甚至好像是公开的,但同样关乎国家安全。11月1日是《反间谍法》颁布实施七周年。近年来,国家安全机关按照《反间谍法》《数据安全法》有关规定,依法履行数据安全监管职责,在全国范围内开展涉外数据专项执法行动,发现一些境外数据公司长期、大量、实时搜集我境内船舶数据,数据安全领域的“商业间谍”魅影重重。 511 | 512 | 2020年6月,国家安全机关在反间谍专项行动中发现,有境外数据公司通过网络在境内私下招募“数据贡献员”。广东省湛江市国家安全局据此开展调查,在麻斜军港附近发现有可疑的无线电设备在持续搜集湛江港口舰船数据,并通过互联网实时传往境外。在临近海港的一个居民楼里,国家安全机关工作人员最终锁定了位置。 513 | 514 | 一套简易的无线电设备是AIS陆基基站,用来接收AIS系统发射的船舶数据。AIS系统是船舶身份自动识别系统,国际海事组织要求300总吨以上船舶必须强制安装。船只在航行过程中,通过AIS系统向其他船只和主管部门发送船只航向、航速、目的港等信息,用于航行避让、交通导航、轨迹回溯等功能。国家安全机关查获的设备虽然看上去简陋,功能却十分强大。 515 | 516 | 国家安全机关进一步调查发现,这个基站的来历并不简单。2016年,湛江市的无线电爱好者郑某偶然收到一封境外某海事数据公司发来的邀请邮件。 517 | 518 | 作为资深的无线电爱好者,能免费领取价值几千元的设备还能获取更多的船舶信息,郑某当然心动。而且,这个基站的架设也非常容易,只要简单组装连上家里的网络,自己的任务就算完成。郑某马上浏览了这家公司申请无线电设备的页面,并按对方要求填写了信息。 519 | 520 | """ 521 | 522 | wordcloud(text=text1, 523 | title='词云图测试', 524 | html_path='output/词云图测试.html') 525 | ``` 526 | 527 | Run 528 | 529 | [**点击查看词云图效果**](examples/output/词云图测试.html) 530 | 531 | ![](img/wordcloud.png) 532 | 533 |
534 | 535 | 536 | 537 | ### 6.2 wordshiftor(text1, text2, title, top_n, matplotlib_family) 538 | 539 | - text1: 文本数据1;字符串 540 | - text2: 文本数据2;字符串 541 | - title: 词移图标题 542 | - top_n: 显示最常用的前n词; 默认值15 543 | - matplotlib_family matplotlib中文字体,默认"Arial Unicode MS";如绘图字体乱码请,请参考下面提示 544 | 545 | ```python 546 | text1 = """在信息化时代,各种各样的数据被广泛采集和利用,有些数据看似无关紧要甚至好像是公开的,但同样关乎国家安全。11月1日是《反间谍法》颁布实施七周年。近年来,国家安全机关按照《反间谍法》《数据安全法》有关规定,依法履行数据安全监管职责,在全国范围内开展涉外数据专项执法行动,发现一些境外数据公司长期、大量、实时搜集我境内船舶数据,数据安全领域的“商业间谍”魅影重重。 547 | 548 | 2020年6月,国家安全机关在反间谍专项行动中发现,有境外数据公司通过网络在境内私下招募“数据贡献员”。广东省湛江市国家安全局据此开展调查,在麻斜军港附近发现有可疑的无线电设备在持续搜集湛江港口舰船数据,并通过互联网实时传往境外。在临近海港的一个居民楼里,国家安全机关工作人员最终锁定了位置。 549 | 550 | 一套简易的无线电设备是AIS陆基基站,用来接收AIS系统发射的船舶数据。AIS系统是船舶身份自动识别系统,国际海事组织要求300总吨以上船舶必须强制安装。船只在航行过程中,通过AIS系统向其他船只和主管部门发送船只航向、航速、目的港等信息,用于航行避让、交通导航、轨迹回溯等功能。国家安全机关查获的设备虽然看上去简陋,功能却十分强大。 551 | 552 | 国家安全机关进一步调查发现,这个基站的来历并不简单。2016年,湛江市的无线电爱好者郑某偶然收到一封境外某海事数据公司发来的邀请邮件。 553 | 554 | 作为资深的无线电爱好者,能免费领取价值几千元的设备还能获取更多的船舶信息,郑某当然心动。而且,这个基站的架设也非常容易,只要简单组装连上家里的网络,自己的任务就算完成。郑某马上浏览了这家公司申请无线电设备的页面,并按对方要求填写了信息。 555 | 556 | """ 557 | 558 | 559 | text2 = """ 560 | 通知强调,各地商务主管部门要紧紧围绕保供稳价工作目标,压实“菜篮子”市长负责制,细化工作措施;强化横向协作与纵向联动,加强与有关部门的工作协调,形成工作合力;建立完善省际间和本地区联保联供机制,健全有关工作方案,根据形势及时开展跨区域调运;加强市场运行监测,每日跟踪蔬菜、肉类等重点生活必需品供求和价格变化情况,及时预测,及早预警。 561 | 562 | 通知要求,各地支持鼓励大型农产品流通企业与蔬菜、粮油、畜禽养殖等农产品生产基地建立紧密合作关系,签订长期供销协议;耐储蔬菜要提前采购,锁定货源,做好本地菜与客菜之间,北菜与南菜之间、设施菜与露天菜之间的梯次轮换和衔接供应;健全完备本地肉类储备规模及管理制度;北方省份要按时完成本年度冬春蔬菜储备计划,南方省份要根据自身情况建立完善蔬菜储备;及时投放肉类、蔬菜等生活必需品储备,补充市场供应。 563 | """ 564 | 565 | from cntext.visualization import wordshiftor 566 | 567 | wordshiftor(text1=text1, 568 | text2=text2, 569 | title='两文本对比') 570 | ``` 571 | 572 | Run 573 | 574 | ![](img/wordshiftor.png) 575 | 576 |
577 | 578 | **注意** 579 | 580 | > 设置参数matplotlib_family,需要先运行下面代码获取本机字体列表 581 | > from matplotlib.font_manager import FontManager 582 | > mpl_fonts = set(f.name for f in FontManager().ttflist) 583 | > print(mpl_fonts) 584 | 585 |

586 | 587 | ## 如果 588 | 589 | 如果您是经管人文社科专业背景,编程小白,面临海量文本数据采集和处理分析艰巨任务,可以参看[《python网络爬虫与文本数据分析》](https://ke.qq.com/course/482241?tuin=163164df)视频课。作为文科生,一样也是从两眼一抹黑开始,这门课程是用五年时间凝缩出来的。自认为讲的很通俗易懂o(* ̄︶ ̄*)o, 590 | 591 | - python入门 592 | - 网络爬虫 593 | - 数据读取 594 | - 文本分析入门 595 | - 机器学习与文本分析 596 | - 文本分析在经管研究中的应用 597 | 598 | 感兴趣的童鞋不妨 戳一下[《python网络爬虫与文本数据分析》](https://ke.qq.com/course/482241?tuin=163164df)进来看看~ 599 | 600 | [![](img/课程.png)](https://ke.qq.com/course/482241?tuin=163164df) 601 | 602 |
603 | 604 | ## 更多 605 | 606 | - [B站:大邓和他的python](https://space.bilibili.com/122592901/channel/detail?cid=66008) 607 | 608 | - 公众号:大邓和他的python 609 | 610 | - [知乎专栏:数据科学家](https://zhuanlan.zhihu.com/dadeng) 611 | 612 | 613 | ![](img/dadeng.png) 614 | 615 | -------------------------------------------------------------------------------- /img/词云图测试.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Awesome-pyecharts 6 | 7 | 8 | 9 | 10 | 11 |
12 | 1427 | 1428 | 1429 | -------------------------------------------------------------------------------- /examples/06-可视化.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "from cntext.visualization import wordcloud, wordshiftor" 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 2, 15 | "metadata": {}, 16 | "outputs": [ 17 | { 18 | "name": "stdout", 19 | "output_type": "stream", 20 | "text": [ 21 | "Help on function wordcloud in module cntext.visualization.visualization:\n", 22 | "\n", 23 | "wordcloud(text, title, html_path)\n", 24 | " 使用pyecharts库绘制词云图\n", 25 | " :param text: 中文文本字符串数据\n", 26 | " :param title: 词云图标题\n", 27 | " :param html_path: 词云图html文件存储路径\n", 28 | " :return:\n", 29 | "\n" 30 | ] 31 | } 32 | ], 33 | "source": [ 34 | "help(wordcloud)" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": 3, 40 | "metadata": {}, 41 | "outputs": [], 42 | "source": [ 43 | "text1 = \"\"\"在信息化时代,各种各样的数据被广泛采集和利用,有些数据看似无关紧要甚至好像是公开的,但同样关乎国家安全。11月1日是《反间谍法》颁布实施七周年。近年来,国家安全机关按照《反间谍法》《数据安全法》有关规定,依法履行数据安全监管职责,在全国范围内开展涉外数据专项执法行动,发现一些境外数据公司长期、大量、实时搜集我境内船舶数据,数据安全领域的“商业间谍”魅影重重。\n", 44 | "\n", 45 | "2020年6月,国家安全机关在反间谍专项行动中发现,有境外数据公司通过网络在境内私下招募“数据贡献员”。广东省湛江市国家安全局据此开展调查,在麻斜军港附近发现有可疑的无线电设备在持续搜集湛江港口舰船数据,并通过互联网实时传往境外。在临近海港的一个居民楼里,国家安全机关工作人员最终锁定了位置。\n", 46 | "\n", 47 | "一套简易的无线电设备是AIS陆基基站,用来接收AIS系统发射的船舶数据。AIS系统是船舶身份自动识别系统,国际海事组织要求300总吨以上船舶必须强制安装。船只在航行过程中,通过AIS系统向其他船只和主管部门发送船只航向、航速、目的港等信息,用于航行避让、交通导航、轨迹回溯等功能。国家安全机关查获的设备虽然看上去简陋,功能却十分强大。\n", 48 | "\n", 49 | "国家安全机关进一步调查发现,这个基站的来历并不简单。2016年,湛江市的无线电爱好者郑某偶然收到一封境外某海事数据公司发来的邀请邮件。\n", 50 | "\n", 51 | "作为资深的无线电爱好者,能免费领取价值几千元的设备还能获取更多的船舶信息,郑某当然心动。而且,这个基站的架设也非常容易,只要简单组装连上家里的网络,自己的任务就算完成。郑某马上浏览了这家公司申请无线电设备的页面,并按对方要求填写了信息。\n", 52 | "\n", 53 | "\"\"\"\n", 54 | "\n", 55 | "\n", 56 | "text2 = \"\"\"\n", 57 | "通知强调,各地商务主管部门要紧紧围绕保供稳价工作目标,压实“菜篮子”市长负责制,细化工作措施;强化横向协作与纵向联动,加强与有关部门的工作协调,形成工作合力;建立完善省际间和本地区联保联供机制,健全有关工作方案,根据形势及时开展跨区域调运;加强市场运行监测,每日跟踪蔬菜、肉类等重点生活必需品供求和价格变化情况,及时预测,及早预警。\n", 58 | "\n", 59 | "通知要求,各地支持鼓励大型农产品流通企业与蔬菜、粮油、畜禽养殖等农产品生产基地建立紧密合作关系,签订长期供销协议;耐储蔬菜要提前采购,锁定货源,做好本地菜与客菜之间,北菜与南菜之间、设施菜与露天菜之间的梯次轮换和衔接供应;健全完备本地肉类储备规模及管理制度;北方省份要按时完成本年度冬春蔬菜储备计划,南方省份要根据自身情况建立完善蔬菜储备;及时投放肉类、蔬菜等生活必需品储备,补充市场供应。\n", 60 | "\"\"\"" 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": 4, 66 | "metadata": {}, 67 | "outputs": [ 68 | { 69 | "name": "stderr", 70 | "output_type": "stream", 71 | "text": [ 72 | "Building prefix dict from the default dictionary ...\n", 73 | "Loading model from cache /var/folders/sc/3mnt5tgs419_hk7s16gq61p80000gn/T/jieba.cache\n", 74 | "Loading model cost 0.652 seconds.\n", 75 | "Prefix dict has been built successfully.\n" 76 | ] 77 | }, 78 | { 79 | "name": "stdout", 80 | "output_type": "stream", 81 | "text": [ 82 | "可视化完成,请前往 output/词云图测试.html 查看\n" 83 | ] 84 | } 85 | ], 86 | "source": [ 87 | "wordcloud(text=text1, \n", 88 | " title='词云图测试', \n", 89 | " html_path='output/词云图测试.html')" 90 | ] 91 | }, 92 | { 93 | "cell_type": "markdown", 94 | "metadata": {}, 95 | "source": [ 96 | "[词云图测试.html](output/词云图测试.html)" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": null, 102 | "metadata": {}, 103 | "outputs": [], 104 | "source": [] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": 5, 109 | "metadata": {}, 110 | "outputs": [ 111 | { 112 | "name": "stdout", 113 | "output_type": "stream", 114 | "text": [ 115 | "Help on function wordshiftor in module cntext.visualization.visualization:\n", 116 | "\n", 117 | "wordshiftor(text1, text2, title, top_n=50, matplotlib_family='Arial Unicode MS')\n", 118 | " 使用shifterator库绘制词移图,可用于查看两文本在词语信息熵上的区别\n", 119 | " :param text1: 文本数据1;字符串\n", 120 | " :param text2: 文本数据2;字符串\n", 121 | " :param title: 词移图标题\n", 122 | " :param top_n: 显示最常用的前n词; 默认值15\n", 123 | " :param matplotlib_family matplotlib中文字体,默认\"Arial Unicode MS\";如绘图字体乱码请,请参考下面提示\n", 124 | " \n", 125 | " 设置参数matplotlib_family,需要先运行下面代码获取本机字体列表\n", 126 | " from matplotlib.font_manager import FontManager\n", 127 | " mpl_fonts = set(f.name for f in FontManager().ttflist)\n", 128 | " print(mpl_fonts)\n", 129 | "\n" 130 | ] 131 | } 132 | ], 133 | "source": [ 134 | "help(wordshiftor)" 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": 6, 140 | "metadata": {}, 141 | "outputs": [ 142 | { 143 | "data": { 144 | "image/png": "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YYh4vevtBx4SEkJ2/P0h4mmMMZssywq9slw9cBG5Jh8fH8qXL293GCJyFboHLiIi4oWUwEVERLyQEriIiIgXUgIXERHxQkrgIiIiXkgJXERExAspgYuIiHghJXAREREvpAQuIiLihbLlSmwHDx6kTZs2dochku3p/zMR+2gtdBHJEGOM1kIXcYNrrYWuIXQREREvpAQuIiLihZTARUREvJASuIiIiBdSAhcREfFCSuAiIiJeSAlcRETECymBi4iIeKFsuRJbTuN0OomMjLQ7DBERcSMl8CzwzTffEBoaytSpUwkMDKRz586sW7eOhg0b0qJFCzZs2JDqnGnTprF27VomT56c7s+LjIxk0sB5FCkQlBnhi9zQqXMn7A5BJMdTAs8CcXFx3HvvvTz88MPEx8fTrFkzunXrRkhICE6n87rnRkREUKFCBfLly5eiPDExke7duzN+/PirnlekQBDFCpXItDaIiIhn85p74MaY3MaYncaYpnbHcj3R0dEULVqUFi1acPToUY4fP06tWrWoUaMGf/zxB2XKlElR3+FwEB4eTmRkJKdOneLAgQNUqFABh8OR4jVu3Dh7GiQiIh7JK3rgxpg8wEygqt2x3Mjhw4cZN24cf/zxBw6HgzJlynDTTTfx6aefUrhwYX788UcCAgKIj4/H19eXn3/+mREjRnD48GGio6OZNm0af/31F35+yX81SUlJAPj6+tK7d287myYiIh7E43vgxphqwHqgot2xpEX16tXp0qULwcHB9O7dmzZt2nD+/Hmef/55vv76a1588UUcDgePPPII8+fP55577uGnn37ipZdeokWLFgwcOJCbb76ZlStXsnLlSpo3b85rr73GypUrad++PWfPnrW7iSIi4gG8oQd+D7ACeBNw2BzLDZ05c4a//vqLb7/9lr59+9KmTRuef/55Xn/9dWrWrMnmzZsB2LJlC6GhybvDWZZFZGQkCxcuZOfOnTidTkaOHAnAjh07OHbsGNu3bwdg9OjRVKtWzZ7GiYiIx/D4BG5Z1sRLPxtj7AwlTQoVKsSbb77Jt99+izGGp59+Gsuy+Oeff5gyZQoPPfQQmzdvxhhDkSJF2Lx5Mx06dOD48ePce++9vP/++9x///0sWrQIgM6dO9OoUSO6d+9uc8tERMSTePwQeloZY541xoQZY8JOnLDvEZf169cTGBhIp06d+OGH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eDghISE4nU5WrlyJr6+vTZGLiOQcSuA53OHDh6lSpYrr/cmTJ1O8r1q1quuedq9evfjtt9+45557+N///seJEyfo1asXq1evZuzYsTRq1IitW7dSp04dt7dDRCSnUQLP4UqVKsWXX355zeNjxoxx/Tx+/HgSExNZsGABL7/8MkFBQQwaNIhffvmFmjVrMnHiRO6//36mTp1Ky5Yt3RG+iEiOpQSew82ZM4cff/zxmscdDgcjR44kOjqaVq1acfDgQdq0aUO/fv24//77ee+991yPlrVv356CBQvSvXt35s+fz2233eauZoiI5DhK4DncE088weTJk695/NJz4IGBgXz99deUKVMGYwzTp0+nQoUKFC1alIULF7rqt2jRgr/++ovcuXNndegiIjmaSes61t4kNDTUCgsLszsMuUJERARz312lpVSzgZNn/ubVz7qleR18Eck4Y8wmy7JCryzXY2QiIiJeSEPo4lbaxSp70N+jiP00hC5uo/3As5eQkBANoYu4wbWG0NUDF7fx8fGhfPnydochIpItKIGLSLo5nU4geWKieLbg4GB8fK493cnpdF73uHguJXARSbdLt0KsbS/aHIlcT9TxGGgy8ZojX/Hx8dSvX5+NGze6yhYtWsScOXOYOXPmVc9JSEigV69eTJw4Ucsm20wJXEQyrHzpALtDkP9g5cqVFC9enPnz5/Pggw+mOh4eHs6aNWvo27evq2z48OFMmTKFuXPnpqh76623snr16iyPWf6lBC4ikkPNmDGDJ554gg8++IDY2Fi6d+9OUlISiYmJnD59mtOnT/Paa6+56k+ZMoWPP/6YevXqsWrVKnLlykVCQgKNGzfmueees7ElOZPH3/gwxrQ3xlhXvObZHZeIiDc7duwYP/74I+3bt2fSpElYloXD4WDu3Ll06NCBWrVqUbt2bR588EGcTie9e/dmxIgRrF+/noYNG/Lwww9z9OhROnfuzN13302nTp3sblKO4w098OrAt8DlX+8u2BSLiEi2MGzYMJxOJ19//TXHjh0jLCyM559/nsTEROLj40lISMDf35+ZM2dy9uxZ7rrrLt59910KFizIyJEjad++PWXLluWBBx5g5MiRdjcnR/L4HjhQDdhhWdbJy17n7A5KRMRbrVmzhu+//x6A6OhoPvroI/73v/8RFRXFBx98QKlSpdizZw8nTpzgyJEj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UAIXuUgbdKSd/qxE7GeyY88kNDTUCgsLszsM8SLaTjT9QkJCNLIh4gbGmE2WZYVeWa4euAjg4+ND+fLl7Q5DRCTN9BiZiIiIF1IPXAQNoYuI91ECF6+QlJSEr69vll0/MjKSSQPnUaRAUJZ9RnaiSWwi9lMCF491/Phx3n//fUaPHs3YsWPx8/OjdOnSBAcHc9ddd2X65xUpEESxQiUy/boiIllB98DFY02dOpXo6GgA/vrrL4oXL07ZsmV58sknmTlzpqvegQMHUm0hOnLkSHx9fVOsi+7r68vatWttao2ISOZSAhePZFkWkydP5rnnngNg69atVK1albvvvptffvklxSIuISEhREdHM2TIELp37050dDQNGjSgYcOGnDp1iho1auBwOGjYsKFNrRERyXwaQhePdOjQIfbt20eLFi0AOH36NM2aNUuxlvm0adO4//77mTFjxjWvExcXx65du7I8XhERd1MCF49UtmxZYmNjAfjhhx/4/PPPU2xccsmliW2BgYHExsZiWRYTJ050rXn+zz//ULRoUbfFLSLiLkrg4pGMMfj7+wOwYMECli9fTrFixVzH8+bNy4kT/86Ejo6OZty4cURFRfH++++77nXv37+fihUrujd4ERE30D1w8WiRkZEsWbKE0NBQZsyYgcPh4IMPPqBly5ZpOn/58uUULVqUpUuXZnGkIiLupR64eLRXXnmFp59+mscee4yHHnqIsmXL8s4777B8+fJrnhMZGcmJEye4cOECU6dOpVOnTkyePNmNUYuIZD0lcPFY7733Hlu3bmX69On4+/vTv39/6tWrx4cffkiFChVc9SIiIvj5559ZtGgRO3fuZP369Xz66afUqVOHYsWKUatWLQ4dOsT8+fMJCAiwsUUiIplHQ+jicSzLYtiwYXz44Yf88MMP+Pv789NPPzFhwgQ6duzI+++/z4wZM3A6nQAUK1YMy7IYOXIkBw8eZNWqVXz//ff89NNPTJkyxXXNQoUK0bVrV9ez5SIi3kwJXDzOsmXL+Oqrr1i2bBmff/45lStXZvDgwUycOJFZs2bx888/88UXX1C2bFn+97//4efnR8+ePQkNDWX//v3Url2b5cuXs27dOooXL0716tVZvHgxAQEB7N+/n8DAQLubKCLyn2kIXTxO06ZN2bJlC7ly5eK+++6jS5cuVK1a1XW8cuXKLFmyhJ07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D0JDQ+nZs6drCVaRq7F9KdWsoKVURbKWllJNvZTqJQcOHKBKlSps3ryZXLly0apVK6pUqcKvv/5KTEwMuXLlIjExEV9fXzZt2kTVqlUBWLp0KR07dmTs2LF07NiRNm3aYFkW06dPp3Tp0m5soXgaj1xKVUQku+nfvz/x8fEYY+jYsSMTJkygQYMGzJkzhylTplC9enX279/PI488QtWqVdm/fz/vvPMOv/zyC3PnzuW+++4D4IcffuD999+nVq1aPPfcczz33HOULaslZORfSuAiIplk9erVHD58mNKlS/PNN98QHh5Ox44dGTlyJNHR0cTFxeFwOGjevDl33303YWFhtG7dmttvv53Y2Fjat2+P0+nk7NmzBAYGAlCwYEEOHjzI/fff7+rVi4ASuIhIprnnnntYsWIFNWvW5M477+THH39k5syZREdHM2fOHCIjIzl16hS7du0iJiaGoUOHcvTo0RSPpO3bt482bdqwa9cuG1si3kAJXEQkE116bCw2NpZ3330Xp9PJgAEDaNOmDa+//jr169enTZs2FC5cGPh3Vbu6deuye/duLMsiNjaWgIDkGf4vvfQSb7/9tj2NEY+mBC4ikgVq1arFhQsXOH/+PEOGDGHp0qXExMSwfPlyRo4cCcC6detck9g2bdoEqAcuaafHyEREskidOnU4f/483bt35+jRozz22GNMmjSJ6Ohojh8/ToUKFewOUbyYEriISBaYOHEiP//8MzNnzuTDDz+kVKlSfP3113Tr1g1fX1/y5MnDjBkzaNasGYGBga7Xbbfdxt69e1OUBQYGahhdUtEQuohIFjDG8Nlnn3Hfffe5Hg27mh49ergxKslOlMBFRDJZTt3kRdxLCVxEMiziiMPuENwu6ngMWk5FPIESuIikW3BwMACm5libI3G/svzbfhE7KYGLSLpdenb5eltqikjW0ix0ERERL6QeuIikm9PpBHLuZK3g4OAUy59mNcuyMMa47fPEOyiBi0i6RUZGAmBte9HmSNwv6ngMNJmYrtsHAQEBnDx5En9//1THTp06xc8//0zHjh1dSTohIYFDhw6xc+dO1q5dy9dff82YMWN4+OGHr3r9ZcuWcc8996TY6OTcuXOuZV0le1ICF5EMK186wO4QPFbt2rVZuXKla1exa3E4HEyfPp3p06fTvHlzBg0ahI+PD35+fhQpUoQuXbrw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sipkEZF0UwKXbOWvv/4iLCyMu+++m+7du3PhwgWMMQDMmjXLdf971qxZAERHR9OxY0eefvppZsyYQc+ePVNcr2jRonz77bc4HA569erl9vaIiFyLErhkK7GxsTz33HMUKFCAcePGsWrVKu68804AOnXq5LoH3qlTJwAKFizIHXfcwa5du655n9vf35/58+dz2223ua0dIiI3ov3ARf6jiIgI5r67KkctpXryzN+8+lk37Qcu4gbX2g9cPXAREREvpIVcRDJBTtudK6e1V8QTaQhd5D/KqfuBh4SEaAhdxA2uNYSuHrjIf+Tj40P58uXtDkNEchglcJHriI+PJykpibx5816zTk7tgYuIvZTAJdv5559/2L59u2sf7yVLltCoUSNy5cp13fMeeughunXrxkMPPeQq+7//+z+2b9/O+PHjr3leZGQkkwbOo0iBoEyJ3xvoHriI/ZTAJdv5559/ePzxx5k3bx7VqlXjiSee4NChQ4waNYqhQ4eSO3du4uPj6dy5M//3f//HCy+8wLJly4iMjGTLli0MGjTIda3Tp08TFxfHypUradWqFe+9995VP7NIgaAc9RiZiNhPCVyynUqVKjFkyBAmT55M5cqV6dq1K/7+/kDyPuCDBg3i1ltv5YEHHgBgxIgRJCQk0LVrVx577DFat27tutb06dP5448/GDt2LLlz57alPSIiV2N7AjfGVAU+BuoBh4GhlmXNunisAjAFuAs4CLxkWdYiu2IV7/Dwww+zZMkSkpKSSEhIwN/fn99//53mzZsD8Omnn5I3b17XUHn+/PkByJUrF927d8fX19d1rcTERLp160ZgYKC7myEicl22LuRijPEDfgQOADWA/wHjjTH3GWN8gO8vHqtMcpKfa4y5+f/bu+/4ms4/gOOfJyEJSYiIIiJi1d4poWgoLSWdVtGaJW3NGrWqtEZao6r0Z1VRSitGba1qjIpN7VFEBCFGwpUlyfn9cZPbTILknuTm+3697kvuc55z7vcc5Huf5zzneXQKV+QSa9aswWAwsHLlStq2bYvBYGDnzp0AxMTEMH78eL788kvTHOnJLV++3DTdqsFgeOS9byGE0JPeLXBX4CAwQNO0KCBIKRUAvJW4vTzQUNO0BxgT+9tAT2C0HsGKnO/AgQM0a9YMwNQCd3BwAKBz5864urqyePFipk+fziuvvEK+fCn/C3z4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\n", 145 | "text/plain": [ 146 | "
" 147 | ] 148 | }, 149 | "metadata": { 150 | "needs_background": "light" 151 | }, 152 | "output_type": "display_data" 153 | } 154 | ], 155 | "source": [ 156 | "wordshiftor(text1=text1, \n", 157 | " text2=text2, \n", 158 | " title='两文本对比')" 159 | ] 160 | }, 161 | { 162 | "cell_type": "code", 163 | "execution_count": null, 164 | "metadata": {}, 165 | "outputs": [], 166 | "source": [] 167 | } 168 | ], 169 | "metadata": { 170 | "kernelspec": { 171 | "display_name": "Python 3", 172 | "language": "python", 173 | "name": "python3" 174 | }, 175 | "language_info": { 176 | "codemirror_mode": { 177 | "name": "ipython", 178 | "version": 3 179 | }, 180 | "file_extension": ".py", 181 | "mimetype": "text/x-python", 182 | "name": "python", 183 | "nbconvert_exporter": "python", 184 | "pygments_lexer": "ipython3", 185 | "version": "3.7.5" 186 | }, 187 | "toc": { 188 | "base_numbering": 1, 189 | "nav_menu": {}, 190 | "number_sections": true, 191 | "sideBar": true, 192 | "skip_h1_title": false, 193 | "title_cell": "Table of Contents", 194 | "title_sidebar": "Contents", 195 | "toc_cell": false, 196 | "toc_position": {}, 197 | "toc_section_display": true, 198 | "toc_window_display": false 199 | } 200 | }, 201 | "nbformat": 4, 202 | "nbformat_minor": 4 203 | } 204 | --------------------------------------------------------------------------------