中国語NLPデータプリプロセッサ共有


あっという間にNLPに接触して1年余りになり、ほとんどの時間は雑用をしていたが、多少のものが蓄積された.今日ここで私は自分で書いた中国語NLPデータの前処理コードを共有して、コードはpython 3.6.5に基づいてwin 10でテストに合格して、私自身がよく使ういくつかの操作をカバーしました.プログラムに含まれる機能は以下の表の通りです.
ファイルアクション
ノイズ除去操作
その他
読み書きテキスト
空白行の削除
分詞
ファイルのマージ
中国語と英語の句読点を削除
品詞表記
データセットの分割
非アクティブ語の削除
エンティティ識別の命名
-
文字化けしと特殊記号を削除する
依存構文解析
-
英語の文字を削除
セマンティックキャラクタ寸法
一般的に、中国語NLPにおけるデータの前処理は、無意味記号の除去、非中国語の除去、分詞の除去、無効語の除去、ベクトル化である.ベクトル化を除いて、他のステップは私のプログラムに書いてありますが、ベクトル化は一般的にTF-IDFWord2Vecが多いです.また、上記の表の の列の機能は、ツール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でのインストール使用.