前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >文本词语挖掘

文本词语挖掘

作者头像
用户2519815
修改2018-07-02 16:41:02
6210
修改2018-07-02 16:41:02
举报
文章被收录于专栏:算法算法

|导语 现在社交网络和视频网站发展都非常迅猛,参与人数非常多,每日UGC(用户原创内容)量非常可观。也因此爆炸性新闻和流行词语也频频出现。不同的社交圈内,由于话题性的不同,其新词分布也不同,若直接引入搜狗等输入法的新词,会造成新词污染。因此,往往需要基于自营社交圈的语料库做新词发现,才能实现更精确的文本语义分析。

算法解析

假设你有一次看到A(男生)和B(女生)两人在街上一起肩并肩地行走,你会觉得两个人应该互相认识(凝固度还比较低);如果两个人牵着手,有说有笑,你可认为两个人很熟悉但还不一定是伴侣,也可能是兄妹吧(凝固度有提高,但是还不够高);如果在你犹豫的时候,两个人相互拥抱,这两个人可能也不算上是伴侣(因为你就只看了一次,自由度太低)。如果,在接下来的一个月内,你经常在不同的地方和时间(情景很多,说明双方比较自由,没有其他伴侣的束缚)看到过两个人亲密接触,这个时候,你基本上有百分九十以上的把握认定二人是伴侣关系。

是的,新词发现的整个判定方式和上面是一致的。你需要从凝固度和自由度两个角度考虑你通过一元分词的相邻词组合而成的“新词”是否是语境中真正的一个词。

算法三大属性

1 凝固度

凝固度是指一个新词单独出现的频次很高,远高于其组合词的概率之和。

假设是二元组词,词A和词B单独出现的概率分别是P(A)和P(B),假设这两个词是独立词,则两个词同时出现的概率为P(A)*P(B)。如果这两个词不是独立的,则两个词同时出现的条件概率会大于P(A)*P(B),即P(C) >>P(A)*P(B)。一般远大于,量级设定为1000倍。

2 自由度

文本片段的自由运用程度也是判断它是否成词的重要标准。如果一个文本片段能够算作一个词的话,它应该能够灵活地出现在各种不同的环境中,具有非常丰富的左邻字集合和右邻字集合。

左(或右)邻接字频 / 词频 > 0.2。说明左(或右)邻接有其他词和该词经常同时出现,往往邻接词比该词更有代表性。比如“欧丽格”

3 新词IDF

IDF表征了新词在文档中出现的次数,如果出现的频次越高,说明这个词在不同的环境中出现的概率更高(这个和自由度有相似性)。IDF在论坛中提取新词具有特定的意义,表征了新词在不同帖子中的认同度。一般IDF越高,说明其倍认可度越高,越有可能是新词。[但是如果IDF非常高,反而代表这个词非常普通,不一定必要进入到新词库,尤其是为了防止造成新词污染,影响词的原子性。

例如: “中国”

假设 一篇文章10000字,其中“中” 出现的词频为 100次,“国”出现的词频为200次,“中国”出现的词频是50次

0.005[中国的概率] >> 0.01[中的概率] * 0.02[国的概率] = 0.0002

例如:“是中国人”

“是中国”中, “是”则为 “中国”的左邻接字

假设“是中国”出现的词频是2次 “中国”的出现的词频是50次

2/50 = 0.04 不大于 0.2

“中国人”同理计算右邻接字自由度

代码实现

代码语言:javascript
复制
import numpy as np
import pandas as pd
import re,datetime
from numpy import log, min

# today = datetime.datetime.now()
# print(today)

f = open('word.txt', 'r')  # 读取文章
s = f.read()  # 读取为一个字符串

# 定义要去掉的标点字
drop_dict = [u',', u',', u'\n', u'。', u'、', u':', u'(', u')', u'(', u')', u'[', u']', u'.', u',', u' ', u'\u3000', u'”' , u'“' , u'?', u'?',
             u'!', u'‘', u'’', u'…',u'》',u'《',u'-',u'>',u'■',u'●',u'』',u'『',u'>',u';',u'&', u' ',u'—']
for i in drop_dict:  # 去掉标点字
    s = s.replace(i, '')

# 为了方便调用,自定义了一个正则表达式的词典
myre = {2: '(..)', 3: '(...)', 4: '(....)', 5: '(.....)', 6: '(......)', 7: '(.......)', 8: '(........)'}

min_count = 10  # 录取词语大于出现次数
min_support = 30  # 录取词语最低支持度,1代表着随机组合
min_s = 2  # 录取词语最低信息熵,越大说明越有可能独立成词
max_sep = 8  # 候选词语的最大字数
t = []  # 保存结果用。

t.append(pd.Series(list(s)).value_counts())  # 逐字统计
tsum = t[0].sum()  # 统计总字数
print(u'共%s个字...' % tsum)

rt = []  # 保存结果用

for m in range(2, max_sep + 1):
    print(u'正在生成%s字词...' % m)
    t.append([])

    for i in range(m):  # 生成所有可能的m字词
        t[m - 1] = t[m - 1] + re.findall(myre[m], s[i:])
    t[m - 1] = pd.Series(t[m - 1]).value_counts()  # 逐词统计
    t[m - 1] = t[m - 1][t[m - 1] > min_count]  # 最小次数筛选
    tt = t[m - 1][:]

    for k in range(m - 1):
        qq = np.array(list(map(lambda ms: tsum * t[m - 1][ms] / t[m - 2 - k][ms[:m - 1 - k]] / t[k][ms[m - 1 - k:]],
                               tt.index))) > min_support  # 最小支持度筛选。
        tt = tt[qq]

    rt.append(tt.index)


def cal_S(sl):  # 信息熵计算函数
    return -((sl / sl.sum()).apply(log) * sl / sl.sum()).sum()




for i in range(2, max_sep + 1):
    print(u'正在进行%s字词的最大熵筛选(%s)...' % (i, len(rt[i - 2])))
    pp = []  # 保存所有的左右邻结果
    for j in range(i):
        pp = pp + re.findall('(.)%s(.)' % myre[i], s[j:])
    pp = pd.DataFrame(pp).set_index(1).sort_index()  # 先排序,这个很重要,可以加快检索速度
    index = np.sort(np.intersect1d(rt[i - 2], pp.index))  # 作交集
    # 下面两句分别是左邻和右邻信息熵筛选
    index = index[np.array(list(map(lambda s: cal_S(pd.Series(pp[0][s]).value_counts()), index))) > min_s]
    rt[i - 2] = index[np.array(list(map(lambda s: cal_S(pd.Series(pp[2][s]).value_counts()), index))) > min_s]


# 下面都是输出前处理
for i in range(len(rt)):
    t[i + 1] = t[i + 1][rt[i]]
    t[i + 1].sort_values(ascending=False)

# # 保存结果并输出
pd.DataFrame(pd.concat(t[1:])).to_csv('all_data_word5.txt', header=False)

today = datetime.datetime.now()
print(today)

代码结果

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档