zoukankan      html  css  js  c++  java
  • NLP学习笔记:词性标注

    任务目标:通过已有的训练数据,将每个单词的词性标记出来。

    知识储备:

      1.计算语言模型

        思路:假设每句话经过分词表示为  (w1,w2,w3,... wi  ) 对应的每个单词的词性记为(z1,z2,z3,... zi)

              求 则语言模型 z =  P(w1,w2,w3,... wi | z1,z2,z3,... zi)* P (z1,z2,z3,... zi)

                   =   [ P(wi |zi)(i从0到n的连乘)] * P(z1)* [ P(zt | z t-1)(t从2到n的连乘)]

                   =  取各个数的 log 值方便计算。

           假定  :训练样本的单词数为 M  ,词性种类为 N

           记 pi = log (P(z1))  表示词性 tag 出现在句子开头的概率  长度为N的数组

                A =  [ P(wi |zi)(i从0到n的连乘)]     表示单词wi为词性zi的概率  表示 N*M的矩阵

             B =  [ P(zt | z t-1)(t从2到n的连乘)]  表示词性  zt-1 的下一个词的词性为 zt 的概率  N*N的矩阵

      2.维特比算法

        第一步已经计算出了各个单词与词性的关系,下一步就需要根绝维特比算法计算出最优解。    (动态规划的思想)

        找规律,假定  s(n)= P(z1) +P (w1|z1)

                  +P(z2|z1)+P(w2|z2)

                  +P(z3|z2)+P(w3|z3)

                  + ......

                  +P(zn|zn-1)+P(wn|zn)

        根据上述关系式,可以定义数组 dp[i][j]  来表示 第 i  个单词的词性为 第j个tag的概率

                  定义数组 dp[i][j] = dp[i-1][k] + A[][] + B[][]

        思路大概是这样的接下来实现即可

    已有的训练数据的样本格式为:

    目前假定 遇到  .  即判定为一句话的结束,这样方便计算 pi 值

    tag2id,id2tag = {},{}   #两个map ,用来记录位置和词性的关系  ,可以通过位置找到词性,也可通过词性定位置
    word2id,id2word = {},{} #同上,记录单词与位置的关系。
    for line in open("data/traindata.txt"):
        items = line.split("/")
        word , tag = items[0],items[1].rstrip()
    
        #如果单词未在map中,则加入。
        if word not in word2id:
            word2id[word] = len(id2word)
            id2word[len(id2word)] = word
        #tag不在,则加入
        if tag not in tag2id:
            tag2id[tag] = len(id2tag)
            id2tag[len(id2tag)] = tag
    M = len(id2word)  #词典长度
    N = len(id2tag)   #词性种类个数
    print(M,N)
    
    #构建需要的矩阵 ,pi ,A , B  A 是N*M 的矩阵
    #计算使用的数学公式 Z = A + pi + B
    #  A为N*M的矩阵,表示 A[i][j] 表示 tag i 出现单词 j 的概率。    pi 表示 每种词性出现在句子开头的概率   B 表示 N*N  B[i][j] 之前状态是 i 转换成 j  的概率
    import numpy as np
    pi = np.zeros(N)   #每种词性,出现在句子开头的概率
    A = np.zeros((N,M))
    B = np.zeros((N,N))
    
    prev_tag = ""
    for line in open("data/traindata.txt"):
        items = line.split("/")
        wordId ,tagId = word2id[items[0]] , tag2id[items[1].rstrip()]
        if prev_tag == "": #表示句子开始
            pi[tagId] +=1
            A[tagId][wordId] +=1
        else: #不是句子开始
            A[tagId][wordId] += 1
            B[tag2id[prev_tag]][tagId] +=1
    
        if items[0] == ".":
            prev_tag = ""
        else:
            prev_tag = items[1].rstrip()
    
    pi = pi/sum(pi)
    for i in range(N):
        A[i] /= sum(A[i])
        B[i] /= sum(B[i])
    
    def log(v):
        if v ==0:
            return np.log(0.000001)
        else:
            return np.log(v)
    
    
    def vitebi(x,pi,A,B):
        """
        :param x:
        :param pi:
        :param A: 单词概率
        :param B: tag状态转移概率
        :return:
        """
        X = [word2id[word] for word in x.split(" ")]
        T = len(X)
        dp = np.zeros((T,N))  #dp[i][j] 表示 wi 词性是第j 个tag 的概率
        ptr = np.array([[0 for x in range(N)] for y in range(T)])
        for j in range(N):
            dp[0][j] = log(pi[j]) + log(A[j][X[0]])
    
        for i in range(1,T):
            for j in range(N):
                dp[i][j] = -9999
                for k in range(N):
                    score =dp[i-1][k] + log(A[j][X[i]]) + log(B[k][j])
                    if score>dp[i][j]:
                        dp[i][j] = score
                        ptr[i][j] = k
        #输出结果
        best_seq = [0]*T
        #找最后一个单词的词性
        best_seq[T-1] = np.argmax(dp[T-1])
        #从后到前的循环,找每个单词的词性
        for i in range(T-2,-1,-1):
            best_seq[i] = ptr[i + 1][best_seq[i + 1]]
        for i in range(len(best_seq)):
            print(id2tag[best_seq[i]])
    
    mystr = "Social Security number , passport number and details about the services provided for the payment"
    print(vitebi(mystr,pi,A,B))
  • 相关阅读:
    java基础---13. 匿名对象
    java基础---12. scanner
    java基础---11. API
    Web APIs---2. DOM(1)
    Web APIs---1.概述
    java基础---10. 封装性
    java基础---9. 面向对象
    java基础---8. 数组
    9月1日,随便写点啥
    银川行路随感
  • 原文地址:https://www.cnblogs.com/wys-373/p/13570487.html
Copyright © 2011-2022 走看看