網絡表情NLP(一)︱顏文字表情實體識別、屬性檢測、新顏發現

這是一篇一本正經無聊的小研究項目。。
互聯網現在面臨很多新網絡文體,比如彈幕文體、小紅書的種草文體、網名等,這些超短文本中本身字符特徵就比較少,但是表情包占比卻很多,這是重要信息呀。
之前參加比賽,一般都是當作停用詞直接刪掉,在這些超短文本中可就不行了。
在這裏插入圖片描述
在這裏插入圖片描述

相關代碼可見我的github:py-yanwenzi
相關文章:
網絡表情NLP(一)︱顏文字表情實體識別、屬性檢測、新顏發現
網絡表情NLP(二)︱特殊表情包+emoji識別



1 混用的幾個庫

這裏混用了幾個筆者常用的文本處理的庫,

  • jieba_fast,相比jieba,jieba_fast 使用cpython重寫了jieba分詞庫中計算DAG和HMM中的vitrebi函數,速度得到大幅提升
  • flashtext,Flashtext:大規模數據清洗的利器,正則表達式在一個 10k 的詞庫中查找 15k 個關鍵詞的時間差不多是 0.165 秒。但是對於 Flashtext 而言只需要 0.002 秒。因此,在這個問題上 Flashtext 的速度大約比正則表達式快 82 倍。可參考:python︱flashtext高效關鍵詞查找與替換
  • rouge,Rouge-1、Rouge-2、Rouge-L分別是:生成的摘要的1gram-2gram在真實摘要的1gram-2gram的準確率召回率和f1值,還有最長公共子序列在預測摘要中所佔比例是準確率,在真實摘要中所佔比例是召回率,然後可以計算出f1值。

1.1 模塊一:rouge

rouge是自動文本摘要算法的評估指標:

from rouge import Rouge

a = ["i am a student from xx school"]  # 預測摘要 (可以是列表也可以是句子)
b = ["i am a student from school on china"] #真實摘要

rouge = Rouge()
rouge_score = rouge.get_scores(a, b)
print(rouge_score[0]["rouge-1"])
print(rouge_score[0]["rouge-2"])
print(rouge_score[0]["rouge-l"])

>>> {'f': 0.7999999950222222, 'p': 0.8571428571428571, 'r': 0.75}
>>> {'f': 0.6153846104142012, 'p': 0.6666666666666666, 'r': 0.5714285714285714}
>>> {'f': 0.7929824561399953, 'p': 0.8571428571428571, 'r': 0.75}



該模塊是使用在顏文字相似性匹配的時候,當然這邊從實驗效果來看,2-grams的效果比較好。

1.2 模塊二:jieba_fast

使用 c 重寫了jieba分詞庫中的核心函數,速度得到大幅提升。
特點

  • 對兩種分詞模式進行的加速:精確模式,搜索引擎模式
  • 利用cpython重新實現了 viterbi 算法,使默認帶 HMM 的切詞模式速度提升 60%左右
  • 利用cpython重新實現了生成 DAG 以及從 DAG 計算最優路徑的算法,速度提升 50%左右
  • 基本只是替換了核心函數,對源代碼的侵入型修改很少
  • 使用import jieba_fast as jieba 可以無縫銜接原代碼。

其中,
github:https://github.com/deepcs233/jieba_fast
代碼示例:

# encoding=utf-8
import jieba_fast as jieba

text = u'在輸出層後再增加CRF層,加強了文本間信息的相關性,針對序列標註問題,每個句子的每個詞都有一個標註結果,對句子中第i個詞進行高維特徵的抽取,通過學習特徵到標註結果的映射,可以得到特徵到任>      意標籤的概率,通過這些概率,得到最優序列結果'

print("-".join(jieba.lcut(text, HMM=True))
print('-'.join(jieba.lcut(text, HMM=False)))

與jieba基本一致
在這裏插入圖片描述

1.3 關鍵詞查詢組件:flashtext

詳情可參考筆者博客:python︱flashtext高效關鍵詞查找與替換

from flashtext import KeywordProcessor

def build_actree(wordlist):
    '''
        AC自動機進行關鍵詞匹配
        構造AC trie
    '''
    actree = KeywordProcessor()
    for index, word in enumerate(wordlist):
        actree.add_keyword(word)     # 向trie樹中添加單詞
    #self.actree = actree
    return actree

def ac_detect(actree,text,span_info = True):
    '''
        AC自動機進行關鍵詞匹配
        文本匹配
    '''
    region_wds = []
    for w1 in actree.extract_keywords(text,span_info = span_info):
        if len(w1) > 0:
            region_wds.append(w1[0])
    return region_wds

wordlist = ['健康','減肥']
text = '今天你減肥了嗎,今天你健康了嗎,減肥 = 健康!'
actree = build_actree(wordlist)
%time ac_detect(actree,text)

>>> CPU times: user 41 µs, sys: 0 ns, total: 41 µs
>>> Wall time: 47.2 µs
>>> ['減肥', '健康', '減肥', '健康']


2 顏文字檢測與識別

之前文本較多的情況,很多顏文字都是當作停用詞進行刪除;也有一些對錶情進行研究,但是顏文字比較麻煩的一點是,如果是特殊符號,☆,這類的只是一個字符,分詞的時候可以分開;
但是顏文字會佔用多個字符,分詞的時候,自己就會分得非常分散'↖', '(', '^', 'ω', '^', ')', '↗',這個問題就有點像新詞發現中出現得問題,如何分詞得到有效的實體,顏文字本身就是一種帶有情感色彩的實體。
在這裏插入圖片描述
所以比較理想的是不同的表情符號可以對應一些實體詞,比如顏文字網站中標記的一樣。

2.1 顏文字檢測

直接上代碼來說明使用方式:

# 初始化
json_data = {'w(゚Д゚)w': '啊啊', '(ノへ ̄、)': '抽泣', '( ̄_, ̄ )': '蔑視'}
ywz = yanwenzi(json_data)
    
# 檢測位置
text = 'w(゚Д゚)w^O^佳^O^w(゚Д゚)w'
ywz.detect(text,span_info=True)
# [('_啊啊_', 0, 7), ('_啊啊_', 14, 21)]
ywz.detect(text,span_info=False)
# ['_啊啊_', '_啊啊_']
ywz.ywz_replace(text)
# '_啊啊_^O^佳^O^_啊啊_'

該模塊初始化的時候,需要將一些{表情:屬性}作爲輸入,筆者這邊自己整理了1800+,整理的一部分是抓取的,還有一部分是新顏文發現而補充進去的。初始化輸入之後,就會將這些表情包作爲關鍵詞進行匹配,同時這裏是不支持模糊匹配的,只能精準匹配,譬如^O^如果這邊表情沒有計入,則不會被匹配到。

這裏可以看到,detect將表情包w(゚Д゚)w變成了中文屬性_啊啊_,因爲_方便分詞使用,其中參數span_info代表是否返回角標,便於定位該表情包的文字。

另外,ywz_replace是將文本中的表情包直接替換成中文字,並返回原文。

2.2 顏文字實體分詞

ywz.jieba_cut(text)
#['_啊啊_', '^', 'O', '^', '佳', '^', 'O', '^', '_啊啊_']

初始化之後,分詞其實就是jieba.cut,這裏會分出_啊啊_這樣的實體詞。


3 新顏文字發現

上面的匹配都是精準匹配,所以需要新顏文字發現,來不斷擴充顏文字詞典。

3.1 新顏文字發現

text = '璇哥!加油↖(^ω^)↗'
ywz.yanwenzi_find(text,min_n = 2,remove_spacing = True)
>>> ['↖(^ω^)↗']

這裏判定的邏輯還是比較簡單的,是通過正則的方式,最少3個(min_n )連續的特殊字符;

當然這裏要深挖也可以參考:如何精準地識別出文本中的顏文字?glove embedding時候的清洗邏輯

input = input
	.gsub(/https?:\/\/\S+\b|www\.(\w+\.)+\S*/,"<URL>")
	.gsub("/"," / ") # Force splitting words appended with slashes (once we tokenized the URLs, of course)
	.gsub(/@\w+/, "<USER>")
	.gsub(/#{eyes}#{nose}[)d]+|[)d]+#{nose}#{eyes}/i, "<SMILE>")
	.gsub(/#{eyes}#{nose}p+/i, "<LOLFACE>")
	.gsub(/#{eyes}#{nose}\(+|\)+#{nose}#{eyes}/, "<SADFACE>")
	.gsub(/#{eyes}#{nose}[\/|l*]/, "<NEUTRALFACE>")
	.gsub(/<3/,"<HEART>")
	.gsub(/[-+]?[.\d]*[\d]+[:,.\d]*/, "<NUMBER>")
	.gsub(/#\S+/){ |hashtag| # Split hashtags on uppercase letters
		# TODO: also split hashtags with lowercase letters (requires more work to detect splits...)

		hashtag_body = hashtag[1..-1]
		if hashtag_body.upcase == hashtag_body
			result = "<HASHTAG> #{hashtag_body} <ALLCAPS>"
		else
			result = (["<HASHTAG>"] + hashtag_body.split(/(?=[A-Z])/)).join(" ")
		end
		result

當有了單個表情識別,如果在比較多的文本下,就可以根據頻次發現一些高頻出現的表情包了:

corpus = ['d(ŐдŐ๑)crush', '♪ ٩(。•ˇ‸ˇ•。)۶', '〜( ̄▽ ̄〜)', '木木╭(╯ε╰)╮', 'ToT(^(エ)^)', 'HLYS(ー`´ー)',
 'O(∩_∩)O', '(^^)筆尖', '璇哥!加油↖(^ω^)↗', '蛻變(^_^) \ufeff']
ywz_new_list = ywz.yanwenzi_new_discovery(corpus,min_n = 2,remove_spacing = True,topn = 200)
ywz_new_list

>>> [('(ŐдŐ๑)', 1), ('♪٩(。•ˇ‸ˇ•。)۶', 1), ('〜( ̄▽ ̄〜)', 1), ('╭(╯ε╰)╮', 1),
 ('(^(エ)^)', 1), ('(ー`´ー)', 1), ('(∩_∩)', 1), ('(^^)', 1), ('↖(^ω^)↗', 1), ('(^_^)\ufeff', 1)]

其中,remove_spacing是否移除空格;topn一次性返回top多少的高頻表情包

如果有新顏文要新增,那麼需要新增到兩個模塊:分詞模塊 + 顏文識別模塊,

# 新顏文添加到分詞詞典
yanwenzi_dict_list = [ynl[0] for ynl in ywz_new_list]
ywz.add_words(yanwenzi_dict_list,freq = 100,tag = 'ywz')

# 新顏文添加到檢測詞典
ywz.actree_add_word(yanwenzi_dict_list,tag = '顏文字')

當然這裏遇到的問題,顏文字識別出來,是不帶屬性的({'↖(^ω^)↗':'_高興_'}),所以要麼就是人工打標然後給入,當然也可以直接list方式,此時屬性就會都指定爲_顏文字_

3.2 顏文字屬性識別

上面3.1提及到一個問題是新顏文字識別出來之後,沒有附帶上屬性,就像實體詞沒有定義詞性一樣。
所以,這邊通過求相似的方式來找到最相似的表情,將最相似的表情屬性,繼承過來。這邊求相似的方式是使用rouge這是文本摘要評價指標。
從rouge的評分來看,rouge-1太粗糙;rouge-2比較合適,
且幾個統計量中,f/p/r,f效果比較好,p/r可能會有比較多的選項,也就是差異性不明顯

參數:
    - min_s = 0.35,閾值,一定要相似性大於纔會給出;如果是'rouge-1'比較合適的閾值在0.75
    - score_type = 'rouge-2',rouge的得分類型,n-grams
    - stat = 'f',採用的統計量

統計量:
    text_a = '(^_^)'
    new_yanwenzi_find(text_a,min_s = 0.35)
    >>> [['(^&^)/', '噢耶',0.75]]

其中返回的是[最相似顏文字,中文屬性,f值]


最後, 該想法到實踐做的時間比較少,2天時間裏面可能會出現很多瑕疵,
歡迎覺得網絡表情需要深挖得網友,一起進步~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章