中国語NLPデータプリプロセッサ共有
あっという間にNLPに接触して1年余りになり、ほとんどの時間は雑用をしていたが、多少のものが蓄積された.今日ここで私は自分で書いた中国語NLPデータの前処理コードを共有して、コードは
ファイルアクション
ノイズ除去操作
その他
読み書きテキスト
空白行の削除
分詞
ファイルのマージ
中国語と英語の句読点を削除
品詞表記
データセットの分割
非アクティブ語の削除
エンティティ識別の命名
-
文字化けしと特殊記号を削除する
依存構文解析
-
英語の文字を削除
セマンティックキャラクタ寸法
一般的に、中国語NLPにおけるデータの前処理は、無意味記号の除去、非中国語の除去、分詞の除去、無効語の除去、ベクトル化である.ベクトル化を除いて、他のステップは私のプログラムに書いてありますが、ベクトル化は一般的に
それから私が機能テストを行ったプログラムで、プログラムの
最後に、読者の皆さんがプログラムについて何か質問があったり、私のプログラムにバグがあることや改善に値するところがあることを発見したりしたら、コメントエリアで伝言を歓迎します.私はすぐに返事して訂正します.pyltpのwindowsでのインストール使用、参考リンクは:哈工大自然言語処理ltpのwindows 10でのインストール使用.
python 3.6.5
に基づいてwin 10
でテストに合格して、私自身がよく使ういくつかの操作をカバーしました.プログラムに含まれる機能は以下の表の通りです.ファイルアクション
ノイズ除去操作
その他
読み書きテキスト
空白行の削除
分詞
ファイルのマージ
中国語と英語の句読点を削除
品詞表記
データセットの分割
非アクティブ語の削除
エンティティ識別の命名
-
文字化けしと特殊記号を削除する
依存構文解析
-
英語の文字を削除
セマンティックキャラクタ寸法
一般的に、中国語NLPにおけるデータの前処理は、無意味記号の除去、非中国語の除去、分詞の除去、無効語の除去、ベクトル化である.ベクトル化を除いて、他のステップは私のプログラムに書いてありますが、ベクトル化は一般的に
TF-IDF
とWord2Vec
が多いです.また、上記の表の
の列の機能は、ツールpyltpを使用しています.pyltp
のモデルについては、私が使用している意味ロール表記モデルはpisrl_win.model
であり、別途ダウンロードする必要がありますが、Linuxプラットフォームの下でltp_data_v3.4.0
フォルダの下のpisrl.model
ファイルを直接使用すればいいことに注意してください.ここではすべてのモデルのダウンロードリンクです.コードを使用する前に、いくつかの依存関係をインストールする必要があります.pip install numpy
pip install pyltp
pip install zhon
windows
プラットフォームでpyltpが間違ってインストールされている場合は、このリンクを使用してpython 3.6のバージョンとpython 3.5のバージョンをダウンロードできます.そして、コマンドpip install xxx.whl
を使用して対応するファイルをインストールすればよい.以下、プログラムpreprocess.py
を直接見ます.注釈が詳細なので、説明しません.""" NLP """
import os
import re
import string
import numpy as np
from pyltp import *
from zhon.hanzi import punctuation
class Preprocess(object):
""" NLP """
#
DIGIT_RE = re.compile(r'\d+')
LETTER_RE = re.compile(r'[a-zA-Z]+')
SPECIAL_SYMBOL_RE = re.compile(r'[^\w\s\u4e00-\u9fa5]+') #
NAMED_ENTITY = re.compile(r'[SBIE]+')
STOPS = ['。', '.', '?', '?', '!', '!'] #
# ,
SENTENCE_MIN_LEN = 5
SENTENCE_MAX_LEN = 50
def __init__(self, ltp_model_dir):
self._cws_model_path = os.path.join(ltp_model_dir, 'cws.model')
self._pos_model_path = os.path.join(ltp_model_dir, 'pos.model')
self._ner_model_path = os.path.join(ltp_model_dir, 'ner.model')
self._par_model_path = os.path.join(ltp_model_dir, 'parser.model')
self._srl_model_path = os.path.join(ltp_model_dir, 'pisrl_win.model')
@staticmethod
def read_text_file(text_file):
""" , list."""
with open(text_file, 'r', encoding='utf-8') as file:
lines = [line.strip() for line in file]
return lines
@staticmethod
def write_text_file(text_list, target_file):
"""
Args:
text_list: ,
target_file: ,
"""
with open(target_file, 'w', encoding='utf-8') as writer:
for text in text_list:
writer.write(text + '
')
@staticmethod
def merge_files(filedir, target_file):
"""
。 : 。
Args:
filedir:
target_file:
"""
filenames = os.listdir(filedir)
with open(target_file, 'a', encoding='utf-8') as f:
for filename in filenames:
filepath = os.path.join(filedir, filename)
f.writelines(open(filepath, encoding='utf-8').readlines())
@staticmethod
def partition_dataset(dataset, ratio):
""" 、 、
Args:
dataset: ,
ratio: , 、 、 , 0-1
Returns: train, val, test, 、 、
"""
data_len = len(dataset)
train_len = int(np.floor(data_len * ratio[0]))
val_len = int(np.ceil(data_len * ratio[1]))
test_len = data_len - train_len - val_len
return dataset[:train_len], dataset[train_len: -test_len], dataset[-test_len:]
@staticmethod
def is_equal(sent1, sent2):
""" """
return sent1 == sent2
@staticmethod
def del_blank_lines(sentences):
""" ,
Args:
sentences:
"""
return [s for s in sentences if s.split()]
@staticmethod
def del_punctuation(sentence):
""" .
Args:
sentence:
"""
en_punc_tab = str.maketrans('', '', string.punctuation) # ↓ ① ℃
sent_no_en_punc = sentence.translate(en_punc_tab)
return re.sub(r'[%s]+' % punctuation, "", sent_no_en_punc)
@staticmethod
def del_stopwords(seg_sents, stopwords):
"""
Args:
seg_sents: , ( )
stopwords:
Returns:
"""
return [[word for word in sent if word not in stopwords]for sent in seg_sents]
@classmethod
def is_length_valid(cls, sentence):
""" , ."""
return cls.SENTENCE_MIN_LEN <= len(sentence) <= cls.SENTENCE_MAX_LEN
@classmethod
def is_simple_sentence(cls, sentence):
""" 。
, 。"""
counter = 0
for word in sentence:
if word in cls.STOPS:
counter += 1
if counter > 1:
return False
return True
@classmethod
def del_special_symbol(cls, sentence):
""" 。"""
return cls.SPECIAL_SYMBOL_RE.sub('', sentence)
@classmethod
def del_english_word(cls, sentence):
""" """
return cls.LETTER_RE.sub('', sentence)
@classmethod
def get_ne_index(cls, ne_sent):
""" 。
Args:
ne_sent:
"""
return [idw for idw, word in enumerate(ne_sent) if cls.NAMED_ENTITY.match(word)]
def seg_sentences(self, sentences):
""" , ."""
segmentor = Segmentor()
segmentor.load(self._cws_model_path)
seg_sents = [list(segmentor.segment(sent)) for sent in sentences]
segmentor.release()
return seg_sents
def postag_sentences(self, seg_sents):
""" ,
Args:
seg_sents: ,
"""
postagger = Postagger()
postagger.load(self._pos_model_path)
pos_sents = [list(postagger.postag(sent)) for sent in seg_sents]
postagger.release()
return pos_sents
def rec_named_entity(self, seg_sents, pos_sents):
"""
Args:
seg_sents: ,
pos_sents: ,
Returns: ,
"""
recognizer = NamedEntityRecognizer()
recognizer.load(self._ner_model_path)
ne_sents = [list(recognizer.recognize(seg_sents[i], pos_sents[i])) for i in range(len(seg_sents))]
recognizer.release()
return ne_sents
def parse_dependency(self, seg_sents, pos_sents):
"""
Args:
seg_sents: ,
pos_sents: ,
Returns:
arc_objs: pyltp.VectorOfParseResult , 。
arc_sents: ,
"""
parser = Parser()
parser.load(self._par_model_path)
arc_objs = [parser.parse(seg_sents[i], pos_sents[i]) for i in range(len(seg_sents))]
arc_sents = [[(a.head, a.relation) for a in arc] for arc in arc_objs]
parser.release()
return arc_objs, arc_sents
def label_sementic_role(self, seg_sents, pos_sents, arc_sents):
"""
Args:
seg_sents: ,
pos_sents: ,
arc_sents: ,
Returns: ,
"""
labeler = SementicRoleLabeller()
labeler.load(self._srl_model_path)
roles = [labeler.label(seg_sents[i], pos_sents[i], arc_sents[i]) for i in range(len(seg_sents))]
_ret = []
for role in roles:
_role = []
for r in role:
_role.extend([(r.index, arg.name, arg.range.start, arg.range.end) for arg in r.arguments])
_ret.append(_role)
labeler.release()
return _ret
それから私が機能テストを行ったプログラムで、プログラムの
print
の出力はすべて注釈に書かれています.from preprocess import Preprocess
test_equal1 = " 1"
test_equal2 = " 2"
print(Preprocess.is_equal(test_equal1, test_equal2)) # False
test_blank = [' 1', '', '', '', '
', '\t', '\r', '\f', ' 2']
print(Preprocess.del_blank_lines(test_blank)) # [' 1', ' 2']
test_punc = ", *.s#?.
print(Preprocess.del_punctuation(test_punc)) # s
test_seg_sents = [[' ', ' ', ' ', ' ', ' '], ['Tom', 'and', 'the', 'cat']]
test_stopwords = [' ', ' ', 'the', ' ']
print(Preprocess.del_stopwords(test_seg_sents, test_stopwords))
# [[' ', ' ', ' '], ['Tom', 'and', 'cat']]
test_length = " "
print(Preprocess.is_length_valid(test_length)) # False
test_simple_sent = " 。 。"
print(Preprocess.is_simple_sentence(test_simple_sent)) # False
test_special_symbol = " *&=-! ↓℃ %"
print(Preprocess.del_special_symbol(test_special_symbol)) #
test_en_word = " nobody p20pro come so0n "
print(Preprocess.del_english_word(test_en_word)) # 20 0
proc = Preprocess('./ltp_data_v3.4.0/')
test_ltp = [" , , , ...", " "]
seged = proc.seg_sentences(test_ltp)
print(seged)
# [[' ', ',', ' ', ' ', ' ', ',', ' ', ' ', ' ', ' ', ' ', ',', ' ', ' ', ' ', ' ', '...'],
# [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']]
posed = proc.postag_sentences(seged)
print(posed)
# [['nh', 'wp', 'p', 'n', 'v', 'wp', 'r', 'v', 'a', 'v', 'n', 'wp', 'r', 'v', 'v', 'a', 'wp'],
# ['r', 'r', 'n', 'd', 'v', 'v', 'n', 'u']]
ne = proc.rec_named_entity(seged, posed)
print(ne)
# [['S-Nh', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'],
# ['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O']]
ne_sent = ['S-Nh', 'B-Ns', 'O', 'I-Ni', 'O', 'E-Nh']
print(Preprocess.get_ne_index(ne_sent))
# [0, 1, 3, 5]
arc_objs, arcs = proc.parse_dependency(seged, posed)
print(arcs)
# [[(5, 'SBV'), (1, 'WP'), (5, 'ADV'), (3, 'POB'), (0, 'HED'), (5, 'WP'), (9, 'SBV'), (9, 'ADV'), (5, 'COO'), (9, 'COO'), (10, 'VOB'), (10, 'WP'), (15, 'SBV'), (15, 'ADV'), (10, 'COO'), (15, 'CMP'), (5, 'WP')],
# [(3, 'ATT'), (3, 'ATT'), (6, 'SBV'), (5, 'ADV'), (6, 'ADV'), (0, 'HED'), (6, 'VOB'), (6, 'RAD')]]
roles = proc.label_sementic_role(seged, posed, arc_objs)
print(roles)
# [[(9, 'A1', 10, 10), (14, 'A0', 12, 12)],
# [(5, 'A2', 0, 2), (5, 'ADV', 3, 3), (5, 'A2', 6, 6)]]
最後に、読者の皆さんがプログラムについて何か質問があったり、私のプログラムにバグがあることや改善に値するところがあることを発見したりしたら、コメントエリアで伝言を歓迎します.私はすぐに返事して訂正します.pyltpのwindowsでのインストール使用、参考リンクは:哈工大自然言語処理ltpのwindows 10でのインストール使用.