Python 实现 Bi-Gram |Python 主题月

2,385 阅读2分钟

本文正在参加「Python主题月」,详情查看 活动链接

文中实现了 n-gram 中最简单的 bi-gram 的简单案例,具体的原理可以见参考中的详解。

代码

## 这里只给出了几个分词,得到字频和单词集合
import math
    def init():
    texts = ['政苑小区','万家花城','朝晖一区']
    ## 字频统计
    wordcount = {}
    ## 加入了 s 和 e 表示开始和结束,如 政苑小区 --> s政苑小区e ,是为了进行之后的概率计算
    words = []
    for word in texts:
        if word and len(word)>2:
            word = 's' + word + 'e'
            words.append(word)
            for c in word:
                if c not in wordcount:
                    wordcount[c] = 1
                else:
                    wordcount[c] += 1
    return wordcount,words


## 字符和数字互相映射的字典
def createDict(CHAR_FREQ):
    c2n = {}
    n2c = {}
    count = 0
    for c in CHAR_FREQ:
        c2n[c] = count
        n2c[count] = c
        count += 1
    return c2n,n2c

## 字频统计 和 单词
wordcount,words = init()

## 映射字典 
c2n,n2c = createDict(wordcount)

## 得到 bi-gram 矩阵中的频率值
def calMatrix():
    matrix = [[0]*len(wordcount) for i in range(len(wordcount))] 
    ## 统计 bi-gram 出现频率
    for key in words:
        for i,c in enumerate(key):
            if i == 0 or len(key)-1==i:
                continue
            else:
                matrix[c2n[key[i-1]]][c2n[c]] += 1
    ## 计算 bi-gram 概率矩阵          
    for i,line in enumerate(matrix):
        for j,freq in enumerate(line):
            matrix[i][j] = round(matrix[i][j]/wordcount[n2c[i]],7)
    return matrix

## 计算给定单词的概率值
def predict(strings):
    matrix = calMatrix()
    result = []
    for s in strings:
        r = 0
        s = 's' + s + 'e'
        for i,c in enumerate(s):
            if i==0:
                continue
            if c in c2n:
                r += math.log(matrix[c2n[s[i-1]]][c2n[s[i]]]+1)
            else:
                r = 0
                break
        result.append(r)
    return result

print(predict(['政区区区','政朝小区','政苑小区','政家小区']))

结果打印:

[0.28768204745178066, 0.9808292280117259, 2.3671235891316167, 0.9808292280117259]

正确的小区为“政苑小区”字符串,但是假如在不知道的情况下输入“政区区区”、“政朝小区”、“政苑小区”、“政家小区”四个词,从结果可以看出来“政苑小区”是得分最高的分词,所以优先选择这个答案。当然从事先知道的结果来看,这个答案也是正确的答案,所以我们在用 Bi-Gram 的时候,我们也可以找出分数值最大的字符串最为概率最大的结果。

拓展

其实在这个 Bi-Gram 基础之上,还可以拓展出 Tri-Gram ,而这个也是常用的模型,但是 Four-Gram 等等再大的话,虽然会对下一个词或者字的辨别能力更强,约束信息更多,但是生成的矩阵也更加洗漱,最后 N-Gram 的总数更多,为 Vn 个,V 为词典或者字典的大小。

在修改上面代码的时候,只需要修改 calMatrix 方法即可。

参考