自然語言處理中連續重複詞的去重
語音識別得到的文字會存在連續詞重複的情況,這可以是語音識別模型或說話內容本身導致的。但這樣重複的連續詞本身並沒有太大的意義,而且得到的文字還會影響之後NLP模型的判斷結果。結合具體的專案需求,本人給出了一種基於n-gram的解決方案。
基本思路
首先給出一個簡單的例子,比如:
“不匹配
門店門店門店門店
很方便,因為我們上了年紀了,你看我們60歲的人那你叫我們在小孩又不在身邊,我的小孩又就又出去了,要是等他回來再搞簽證就好麻煩。”
一種比較樸素的做法是先對上面的文字進行分詞,然後再對連續重複詞(比如“門店”)做去重。但分詞器有可能會造成分詞錯誤,從而影響最終去重。比如,採用pyltp對原始文字分詞,得到的結果如下:
“不 匹 配門店 門店 門店 門店 很 方便 , 因為 我們 上 了 年紀 了 , 你 看 我們 60 歲 的 人 那 你 叫 我們 在 小孩 又 不 在 身邊 , 我 的 小孩 又 就 又 出去 了 , 要是 等 他 回來 再 搞 簽證 就 好 麻煩 。”
顯然,“配門店”作為一個詞導致最終去重失敗。
現在我們換個思路,是否可以用最簡單的n-gram來實現我們的目的呢?答案是肯定的。我們依然以上面作為例子,對其做bigram,得到以下結果:
[‘不匹’, ‘匹配’, ‘配門’,
'門店'
,
'店門'
,
'門店'
,
'店門'
,
'門店'
,
'店門'
,
'門店'
, ‘店很’, ‘很方’, ‘方便’, ‘便,’, ‘,因’, ‘因為’, ‘為我’, ‘我們’, ‘們上’, ‘上了’, ‘了年’, ‘年紀’, ‘紀了’, ‘了,’, ‘,你’, ‘你看’, ‘看我’, ‘我們’, ‘們6’, ‘60’, ‘0歲’, ‘歲的’, ‘的人’, ‘人那’, ‘那你’, ‘你叫’, ‘叫我’, ‘我們’, ‘們在’, ‘在小’, ‘小孩’, ‘孩又’, ‘又不’, ‘不在’, ‘在身’, ‘身邊’, ‘邊,’, ‘,我’, ‘我的’, ‘的小’, ‘小孩’, ‘孩又’, ‘又就’, ‘就又’, ‘又出’, ‘出去’, ‘去了’, ‘了,’, ‘,要’, ‘要是’, ‘是等’, ‘等他’, ‘他回’, ‘回來’, ‘來再’, ‘再搞’, ‘搞籤’, ‘簽證’, ‘證就’, ‘就好’, ‘好麻’, ‘麻煩’, ‘煩。’]
可以看到,對於連續重複的詞,如果該詞是由兩個character組成的,則bigram處理後每3個segment便重複,如連續重複詞“門店門店門店門店”對應的bigram序列為[‘門店’, ‘店門’, ‘門店’, ‘店門’, ‘門店’, ‘店門’, ‘門店’]。那假如連續重複詞是由3個character組成?同樣道理,做trigram後每隔4個segment出現重複,比如“不匹配不匹配”的trigram序列為[‘不匹配’, ‘匹配不’, ‘配不匹’, ‘不匹配’]。
程式碼實現
需要注意的是由於我們不能提前知道原始文字中連續重複詞是由多少個character組成的,所以在我的程式碼中提供了一個引數max_ngram_length,表明對原始文字採用不大於該值的所有ngram來進行分割並去重。完整的python程式碼實現如下。
#! /usr/bin/env python
# -*- coding:utf-8 -*-
def
merge
(
sentence
,
max_ngram_length
=
4
):
‘’‘合併文字中連續重複的詞’‘’
final_merge_sent
=
sentence
max_ngram_length
=
min
(
max_ngram_length
,
len
(
sentence
))
for
i
in
range
(
max_ngram_length
,
0
,
-
1
):
start
=
0
end
=
len
(
final_merge_sent
)
-
i
+
1
ngrams
=
[]
while
start
<
end
:
ngrams
。
append
(
final_merge_sent
[
start
:
start
+
i
])
start
+=
1
result
=
[]
for
cur_word
in
ngrams
:
result
。
append
(
cur_word
)
if
len
(
result
)
>
i
:
pre_word
=
result
[
len
(
result
)
-
i
-
1
]
if
pre_word
==
cur_word
:
for
k
in
range
(
i
):
result
。
pop
()
cur_merge_sent
=
“”
for
word
in
result
:
if
not
cur_merge_sent
:
cur_merge_sent
+=
word
else
:
cur_merge_sent
+=
word
[
-
1
]
final_merge_sent
=
cur_merge_sent
return
final_merge_sent
if
__name__
==
“__main__”
:
text
=
“不匹配門店門店門店門店很方便,因為我們上了年紀了,你看我們60歲的人那你叫我們在小孩又不在身邊,我的小孩又就又出去了,要是等他回來再搞簽證就好麻煩。”
(
merge
(
text
,
max_ngram_length
=
4
))
text
=
“我愛愛北京天安門天安門,天安門上上太陽太陽昇。”
(
merge
(
text
,
max_ngram_length
=
4
))
測試案例的輸出如下:
不匹配門店很方便,因為我們上了年紀了,你看我們60歲的人那你叫我們在小孩又不在身邊,我的小孩又就又出去了,要是等他回來再搞簽證就好麻煩。
我愛北京天安門,天安門上太陽昇。