日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

简单词性标注实战

發布時間:2023/12/16 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 简单词性标注实战 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 詞性標注實戰
    • 講解
    • 代碼實現
      • 讀取詞性標注數據集
      • 構建上述三個特征數組
      • 進行詞性標注
      • 查看一下路徑對應的詞性,以及錯誤詞性的dp值

  • 學自NLPCamp

詞性標注實戰

講解

對于一段文本我們要知道其中每個詞的詞性。形式如下:

# Z為詞性總和:{z1,z2,...,zn},S為句子(詞總和):{w1,w2,...,wn} # S中每個詞的詞性肯能有多種,而組合起來的Z就更多了

所以對于要求的P(Z|S),S是一個小概率,Z是大概率。所以其是求不出來的,使用貝葉斯公式求。

我們要求的是:從S的所有詞的詞性組合中選擇一個概率最大的詞性組合(也就是這個詞性最符合語法)

P(Z|S) = P(S|Z) * P(Z) / P(S) # S為已知量,Z為變量。所以省略常數分母 P(Z|S) = P(S|Z) * P(Z)

可以看出這就是一個噪聲信道模型。

由于Z是S中所有詞的詞性的組合,S是S中所有詞的列表。其上式可寫成:

argmax P(Z|S) = P(z1,z2,...,zn|w1,w2,...,wn)# Translation Model * Language Model= P(w1,w2,...,wn|z1,z2,...,zn) * P(z1,z2,...,zn)# 假設獨立= P(w1|z1)*P(w2|z2)*...*P(wn|zn) * P(z1,z2,...,zn)# 使用BiGram= P(w1|z1)*P(w2|z2)*...*P(wn|zn) * P(z1)*P(z2|z1)*...*P(zn|zn-1)= ∏(1<=i<=n)P(wi|zi) * P(z1) * ∏(2<=i<=n)P(zi|zi-1)
  • 假設獨立:假設w之間是獨立的,z之間是獨立的。但是w與z之間不是獨立的,每個w與它對應的z相關。

加個log防止溢出:

argmaxZ∈S中每個單詞詞性的所有組合 logP(Z|S) = ∑1<=i<=nlogP(wi|zi) + logP(z1) + ∑2<=i<=nlogP(zi|zi-1)

  • Z={z1,z2,…,zn},S={w1,w2,…,wn}
還有一個思路是:單獨算每個單詞的 argmax P(zi|wi),然后將所有單詞的這個乘起來作為整個句子的詞性表達。 P(zi|wi) = P(wi|zi) * P(zi) Z = P(w1|z1) * P(w2|z2) * ... * P(wn|zn) * P(z1) * ... * P(zn)這個思路是不太正確的思路,因為沒有考慮到上下文。從上式可以看出后項是Unigram。

上述公式可以得到一下兩個矩陣+一個向量。

這三個矩陣分別對應:

  • A
    • logP(wi|zi)
    • 大小為n * m。n為詞典庫大小,m為詞標注表大小
  • B
    • logP(z1)
    • 大小為m。m為詞標注表大小
  • C
    • logP(zi|zi-1)
    • 大小為m * m。m為詞標注表大小

通過掃描語料庫構建這三個矩陣。三個矩陣中的每一項都是模型的一個參數。

由于Z是句子中所有單詞詞性的一個組合。所以我們可以將組合問題優化為動態規劃問題(Viterbi算法的思想)。

通過動態規劃五部曲來解答問題:

  • DP數組下標及其含義是什么?

    • DP[i] [j]:第 i 個單詞選擇第 j 個詞性時,從第一個單詞到第 i 個單詞的概率大小。
  • 遞推公式是什么?

    • dp[i][j] = max for z in range(0, m): dp[i-1][z] + a[j][i] + b[j] + c[j-1][j]
  • 怎樣初始化?

    • 第一行是第一個單詞,所以對其進行初始化。dp[0][j] = a[j][0] + b[j]
  • 遍歷順序是什么?

    • 從左到右遍歷,從上到下遍歷
  • 終止條件是什么?

    • 遍歷到dp數組尾部

代碼實現

使用人人網詞性標注數據集。

import jieba from collections import defaultdict, Counter import numpy as np import math

讀取詞性標注數據集

讀取詞性標注數據集,并且獲取詞及其詞性。做特征提取并進行token化。

words = [] tags = [] is_head = [] with open('sources/TagData/PeopleDaily199801.txt', 'r', encoding='utf8') as f:while True:line = f.readline()if not line:breakline = line.strip()# 用于組合詞combine_word = ''combine_tag = ''combine_flag = Falsefor i, word in enumerate(line.split()):if i == 0:# 去掉開頭的報紙日期continueif i == 1:is_head.append(1)else:is_head.append(0)if word.find('[') != -1:combine_word += word.split('[')[1].split('/')[0]combine_flag = Truecontinueelif word.rfind(']') != -1:combine_word += word.split(']')[0].split('/')[0]combine_tag = word.split(']')[1]words.append(combine_word)tags.append(combine_tag)combine_word = ''combine_flag = Falsecontinueif combine_flag:combine_word += word.split('/')[0]continuewords.append(word.split('/')[0])tags.append(word.split('/')[1])ids_to_word = list(set(words)) ids_to_tag = list(set(tags)) words_len = len(ids_to_word) tags_len = len(ids_to_tag)word_to_ids = dict((w, i) for i, w in enumerate(ids_to_word)) tag_to_ids = dict((t, i) for i, t in enumerate(ids_to_tag)) word_to_tag = dict((w, t) for w, t in zip(words, tags))

構建上述三個特征數組

A = [[0 for j in range(words_len)] for i in range(tags_len)] B = [0 for i in range(tags_len)] C = [[0 for j in range(tags_len)] for i in range(tags_len)]# 構建A數組 pre_word, pre_tag, pre_head = 0, 0, 0 for word, tag, head in zip(words, tags, is_head):if head:B[tag_to_ids[tag]] += 1else:A[tag_to_ids[tag]][word_to_ids[word]] += 1C[tag_to_ids[pre_tag]][tag_to_ids[tag]] += 1pre_word, pre_tag, pre_head = word, tag, headA = np.array(A, dtype=float) B = np.array(B, dtype=float) C = np.array(C, dtype=float)for i in range(A.shape[0]):summ = A[i].sum()for j in range(A.shape[1]):A[i][j] = (A[i][j] + 1) / (summ + A.shape[1])summ = B.sum() for i in range(B.shape[0]):B[i] = (B[i] + 1) / (summ + B.shape[0])for i in range(C.shape[0]):summ = C[i].sum()for j in range(C.shape[1]):C[i][j] = (C[i][j] + 1) / (summ + C.shape[1])

最后三個for循環是為了進行歸一化、平滑化。防止0的出現。

進行詞性標注

正確詞性:19980103-02-013-001/m 云南/ns 全面/ad 完成/v 黨報/n 黨刊/n 發行/vn 任務/n

content = "云南 全面 完成 黨報 黨刊 發行 任務".split()dp = [[0 for j in range(tags_len)] for i in range(len(content))] path = [0 for i in range(len(content))]res = [] for tag in range(tags_len):dp[0][tag] = -math.log(A[tag][word_to_ids[content[0]]]) - math.log(B[tag])for i in range(1, len(content)):minn = float('inf')minn_tag = ''for z in range(tags_len):if dp[i-1][z] < minn:minn, minn_tag = dp[i-1][z], zpath[i-1] = minn_tagfor j in range(tags_len):dp[i][j] = -math.log(A[j][word_to_ids[content[i]]]) - math.log(C[minn_tag][j]) + minnminn = float('inf') minn_tag = '' for z in range(tags_len):if dp[-1][z] < minn:minn, minn_tag = dp[-1][z], z path[-1] = minn_tag print(path) [6, 16, 7, 30, 30, 7, 30]

查看一下路徑對應的詞性,以及錯誤詞性的dp值

for i in path:print(ids_to_tag[i], end=' ') print() print(sorted(list(enumerate(dp[-2])), key=lambda i: i[1])) ns ad v n n v n [(7, 62.52403804697192), (18, 63.54269168062274), (31, 66.31538434533402), (12, 66.84356020041032), (30, 66.98141761571875), (29, 67.15506401995253), (42, 67.2579442909328), (41, 67.32280128709618), (21, 67.76834136366989), (35, 67.77954985376014), (22, 68.1156403237701), (13, 68.16223680506411), (4, 68.89857138751013), (16, 68.90836896977878), (15, 69.2393456247602), (25, 69.27639029481048), (3, 69.32057529175151), (5, 69.333718912759), (24, 69.38224259821669), (17, 69.5266120576496), (0, 69.69754138240673), (38, 69.96903098819377), (6, 69.97206357901055), (19, 70.0542828964721), (9, 70.06770949242326), (2, 70.20966944201218), (26, 70.30691706175277), (10, 70.40364083385651), (43, 70.97207322317294), (40, 71.36526036755518), (8, 72.02383165009198), (28, 72.2356456654909), (39, 72.31657495384712), (32, 72.34134999730088), (23, 72.62285124657133), (20, 73.24008077749231), (14, 74.84844776211168), (34, 74.84877086114435), (1, 75.25396389279734), (33, 75.2545589639259), (11, 75.94695799781421), (27, 75.94695799781421), (36, 75.94695799781421), (37, 75.94706005077978)]

我們再看一下tag與其對應的id:

print(tag_to_ids) {'j': 0, 'Rg': 1, 'y': 2, 'i': 3, 'r': 4, 'l': 5, 'ns': 6, 'v': 7, 'q': 8, 's': 9, 'Vg': 10, 'Yg': 11, 'u': 12, 'm': 13, 'Bg': 14, 't': 15, 'ad': 16, 'Ng': 17, 'vn': 18, 'nt': 19, 'o': 20, 'p': 21, 'a': 22, 'Tg': 23, 'b': 24, 'k': 25, 'z': 26, 'na': 27, 'Dg': 28, 'd': 29, 'n': 30, 'w': 31, 'Ag': 32, 'h': 33, 'e': 34, 'nr': 35, 'vvn': 36, 'Mg': 37, 'an': 38, 'nx': 39, 'nz': 40, 'c': 41, 'f': 42, 'vd': 43}

我們可以看到輸出錯誤的那個詞性的是動詞,我們再詳細看一下矩陣中的值:

print("發行作為v的概率:", A[7][word_to_ids['發行']]) print("發行作為vn的概率:", A[18][word_to_ids['發行']]) print("n作為前詞性v作為當前詞性的概率:", C[30][7]) print("n作為前詞性vn作為當前詞性的概率:", C[30][18]) 發行作為v的概率: 0.0003537863463443465 發行作為vn的概率: 0.00035066275260241855 n作為前詞性v作為當前詞性的概率: 0.1478553505803919 n作為前詞性vn作為當前詞性的概率: 0.05386328343799666

可以看到,發行這個詞作為v和vn的概率差別不大。但是在整個語料中v作為n的后詞的概率要比vn大,而vn作為n的后詞在語料中出現的次數少。所以受C矩陣影響將“發行”這個詞作為了v詞性。

總結

以上是生活随笔為你收集整理的简单词性标注实战的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。