Welcome to Mashykom WebSite



ja_ginzaとspaCyを用いた自然言語処理


 オープンソースの自然言語処理ライブラリの代表格はNLTKと呼ばれるフレームワークでした。近年、 Explosion AI 社が開発した Python/Cython で実装されたオープンソースの自然言語処理ライブラリ spaCy が公開されました。MIT ライセンスで利用が可能です。多くの言語をサポートし、学習済みの統計モデルと単語ベクトルが付属しています。研究用ではなく製品作成環境での本番利用を念頭に開発されていることも NLTK などの自然言語処理ライブラリと異なるところです。

 また、最近までは spaCy の学習済みモデルには日本語に対応したものがなく、 バックエンドでMeCab を用いて形態素解析を行っていました。その結果、spaCy を利用して記述された自然言語処理のアプリケーションやライブラリでは日本語の文書を処理することができない状況が続いていました。

 2019年4月に、リクルートと国立国語研究所の研究成果である日本語処理ライブラリ GiNZA が公開されました。リクルート社の公開ページはこちらです。主な特徴は、以下の通り。

  •   高度な自然言語処理をワンステップで導入完了:
    これまで、高度な自然言語処理を行うためには複雑な導入作業が必要でしたが、spaCyのフレームワーク上で、「GiNZA」はワンステップでモジュールとモデルファイルの導入を完了できます。これにより、エンジニアは即座に解析が可能です。
  •  高速・高精度な解析処理と依存構造解析レベルの国際化に対応:
    産業用途で自然言語処理技術を活用するには、一定の処理速度を保ちながら解析精度を高めるためにチューニングを行うことが一般的です。「GiNZA」は、「spaCy」が提供する高速・高精度な依存構造解析器を使用して、産業用途に耐える性能を備えた高度な自然言語処理機能をライブラリとして提供します。同時に、「spaCy」の国際化機能により、複数の欧米言語と日本語の言語リソースを切り替えて使用することが可能となり、エンジニアは複数言語の解析を単一のライブラリで行うことができます。
  •   国立国語研究所との共同研究成果の学習モデルを提供:
    自然言語処理系の学会を中心に、人類が用いる多様な言語を、一貫した構文構造・品詞体系で解析可能にする「Universal Dependencies」の取組みが、2014年から全世界で始まっています。日本においても当初からUDの日本語への適用に関する研究と日本語版UDコーパス(データ)構築が同時に進められてきました。Megagon Labsは、国立国語研究所と共同で、日本語版UDに基づいた高精度な依存構造解析技術の研究を行い、その成果である学習済みモデルを「GiNZA日本語UDモデル」に組み込みました
  •  これまで、高度な自然言語処理を行うためには複雑な導入作業が必要でしたが、「GiNZA」はワンステップでモジュールとモデルファイルの導入を完了できます。同時に、「spaCy」の国際化機能により、複数の欧米言語と日本語の言語リソースを切り替えて使用することが可能となり、エンジニアは複数言語の解析を単一のライブラリで行うことができます。

    このページでは、 GiNZA と spaCy を用いた日本語の処理について簡単に紹介したいと思います。使用しているOSはMacOS Big Sur 11.2 です。Anaconda で Python 環境はインストールされていて、Python バージョンは Python 3.8 です。

    Last updated: 2021.2.10



    spaCyとGiNZAのインストールと基本的使用方法


    spaCy と GiNZA の関係性について整理しておくと、spaCy のアーキテクチャは以下のような構造となっていて、図中の上段の、 自然言語の文字列を形態素に分割する Tokenizer, spaCy の統計モデルに相当する Language といった部分の実装を GiNZA が提供しているという関係になります。ja が日本語の部分です。

    spacy.svg

    GiNZA は日本語のトークン化に SudachiPy を使用しており、GiNZAが提供する Tokenizer の実装は ginza.sudachi_tokenizer.SudachiTokenizer なので、 SudachiPy のラッパーになります。現在(2020年10月)でのGiNZA のバージョンは ginza-4.0.5 です。Sudachi のGitHub repoはここにあります

     最初に、GiNZA NLP Library をインストールします。

    
    pip install -U ginza
    
    

     ginza 及び sudachipy 関連のモジュールは python 3の site-packages に保存されます。ここでインストールした GiNZA に整合する spacy も同時にインストールされます。Spacy を独立にインストールすると、ginza との間の適合性が破れますので、注意ください。

     エラーが出なければ、GiNZAは正常にインストールされています。GiNZAのGitHub Repoはhttps://github.com/megagonlabs/ginzaです。

     始めに、command line で使用する方法について説明します。ターミナルの command line でginzaを起動するために、

    
    (base) $ ginza
    
    銀座でランチをご一緒しましょう。
    
    

    と入力すると、以下の通りに、日本語の形態素解析が実行されます。品詞タグと依存関係ラベリングが表示されています。

    
    # text = 銀座でランチをご一緒しましょう。
    1	銀座	銀座	PROPN	名詞-固有名詞-地名-一般	_	6	obl	SpaceAfter=No|BunsetuBILabel=B|BunsetuPositionType=SEM_HEAD|NP_B|Reading=ギンザ|NE=B-GPE|ENE=B-City
    2	で	で	ADP	助詞-格助詞	_	1	case	_	SpaceAfter=No|BunsetuBILabel=I|BunsetuPositionType=SYN_HEAD|Reading=デ
    3	ランチ	ランチ	NOUN	名詞-普通名詞-一般	_	6	obj	SpaceAfter=No|BunsetuBILabel=B|BunsetuPositionType=SEM_HEAD|NP_B|Reading=ランチ
    4	を	を	ADP	助詞-格助詞	_	3	case	_	SpaceAfter=No|BunsetuBILabel=I|BunsetuPositionType=SYN_HEAD|Reading=ヲ
    5	ご	ご	NOUN	接頭辞	_	6	compound	_	SpaceAfter=No|BunsetuBILabel=B|BunsetuPositionType=CONT|Reading=ゴ
    6	一緒	一緒	VERB	名詞-普通名詞-サ変可能	_	0	root	SpaceAfter=No|BunsetuBILabel=I|BunsetuPositionType=ROOT|Reading=イッショ
    7	し	する	AUX	動詞-非自立可能	_	6	advcl	_	SpaceAfter=No|BunsetuBILabel=I|BunsetuPositionType=SYN_HEAD|Inf=サ行変格,連用形-一般|Reading=シ
    8	ましょう	ます	AUX	助動詞	_	6	aux	_	SpaceAfter=No|BunsetuBILabel=I|BunsetuPositionType=SYN_HEAD|Inf=助動詞-マス,意志推量形|Reading=マショウ
    9	。	。	PUNCT	補助記号-句点	_	6	punct	_	SpaceAfter=No|BunsetuBILabel=I|BunsetuPositionType=CONT|Reading=。
    
    

    次に、MeCab と同じような機能を持つ ginzame を使ってみましょう。

    
    $ ginzame
    
    銀座でランチをご一緒しましょう。
    
    
    銀座	名詞,固有名詞,地名,一般,*,*,銀座,ギンザ,*
    で	助詞,格助詞,*,*,*,*,で,デ,*
    ランチ	名詞,普通名詞,一般,*,*,*,ランチ,ランチ,*
    を	助詞,格助詞,*,*,*,*,を,ヲ,*
    ご	接頭辞,*,*,*,*,*,御,ゴ,*
    一緒	名詞,普通名詞,サ変可能,*,*,*,一緒,イッショ,*
    し	動詞,非自立可能,*,*,サ行変格,連用形-一般,為る,シ,*
    ましょう	助動詞,*,*,*,助動詞-マス,意志推量形,ます,マショウ,*
    。	補助記号,句点,*,*,*,*,。,。,*
    EOS
    

     と解析されます。次に、spaCyで日本語処理を実行してみます。 spaCy をインポートして、GiNZA のモデルをロードします。また、慣例としてロードしたモデルは nlp という変数名で保持します。jupyter notebookを起動して、以下のように入力します。

    
    import spacy
    nlp = spacy.load('ja_ginza')
    
    

     実際に日本語の文章をトークン化してみます。

    
    import spacy
    
    nlp = spacy.load('ja_ginza')
    doc = nlp('恵比寿にあるあのイタリアンにはよく行く。美味しいんだ。')
    
    for sent in doc.sents:
        for token in sent:
            info = [
                token.i,         # トークン番号
                token.text,     # テキスト
                token.lemma_,    # 基本形
                token.pos_,      # 品詞
                token.tag_,      # 品詞詳細
            ]
            print(info)
            
    

    トークン化された結果は以下の通りです。token._.reading, token._.inf などは以前は使用できましたが、現在使用できません。

    
    [0, '恵比寿', '恵比寿', 'PROPN', '名詞-固有名詞-地名-一般']
    [1, 'に', 'に', 'ADP', '助詞-格助詞']
    [2, 'ある', 'ある', 'VERB', '動詞-非自立可能']
    [3, 'Garden', 'Garden', 'NOUN', '名詞-普通名詞-一般']
    [4, 'Place', 'Place', 'NOUN', '名詞-普通名詞-一般']
    [5, 'に', 'に', 'ADP', '助詞-格助詞']
    [6, 'は', 'は', 'ADP', '助詞-係助詞']
    [7, 'よく', 'よく', 'ADV', '副詞']
    [8, '行く', '行く', 'VERB', '動詞-非自立可能']
    [9, '。', '。', 'PUNCT', '補助記号-句点']
    [10, '三つ星', '三つ星', 'NOUN', '名詞-普通名詞-一般']
    [11, 'フレンチ', 'フレンチ', 'NOUN', '名詞-普通名詞-一般']
    [12, 'の', 'の', 'ADP', '助詞-格助詞']
    [13, 'ロブション', 'ロブション', 'PROPN', '名詞-固有名詞-一般']
    [14, 'に', 'に', 'ADP', '助詞-格助詞']
    [15, 'も', 'も', 'ADP', '助詞-係助詞']
    [16, '行く', '行く', 'VERB', '動詞-非自立可能']
    [17, '。', '。', 'PUNCT', '補助記号-句点']
    [18, '美味しい', '美味しい', 'ADJ', '形容詞-一般']
    [19, 'けど', 'けど', 'SCONJ', '助詞-接続助詞']
    [20, '、', '、', 'PUNCT', '補助記号-読点']
    [21, '高額', '高額', 'ADJ', '名詞-普通名詞-形状詞可能]
    [22, 'な', 'だ', 'AUX', '助動詞', 'aux', 21]
    [23, '店', '店', 'NOUN', '名詞-普通名詞-一般']
    [24, 'だ', 'だ', 'AUX', '助動詞']
    [25, '。', '。', 'PUNCT', '補助記号-句点']
    
    

    nlp(・) を読み込んだ時点で、解析済みの Doc オブジェクトが返ってきます。 つまり、トークン化、品詞のタギング、依存関係のラベリング、固有表現抽出の一通りの処理が終わっています。

    Doc オブジェクトには、以下のような便利なメソッドが定義されています。

  • Doc.ents :ドキュメントにあるトークン化されたentitiesの列を返します
  • Doc.noun_chunks :名詞句の列を返します
  • Doc.sents : 文章ごとの列を返します
  • Doc.vector : 語彙のベクトルを返します
  • Doc.similarity : コサイン類似を予測します
  • 詳しくは、spacyの公式ドキュメントを参照ください。ここでの説明のは、第4回 spaCy/GiNZA を用いた自然言語処理の解説を参考していますが、古いバージョンを用いた解説です。


    spaCyとGiNZAを用いた言語処理


     日本語の文書に対して前処理を行う際、以下のステップが必要とされます。

  • 文に対してMeCabやSudachiなどの形態素解析器を通じて単語に分割
  • 必要に応じて品詞情報や固有表現を抽出
  • 必要に応じて単語のかかり受け情報を抽出
  • 単語を埋め込みベクトルに変換
  •  上で見た通り、spaCyではこれらの処理はパイプラインとして記述され、上記の処理は予めパイプラインに組み込まれています。この結果、nlp()を読み込んだ段階で、いきなりメインの処理から書き始めることが可能です。例えば、

    
    import spacy
    
    # 日本語自然言語処理のパイプラインを構築されたGiNZAをspaCyから読み込む
    nlp = spacy.load('ja_ginza')  
    
    doc = nlp("1976年、ジョブズは友人のスティーブ・ウォズニアックが自作したマイクロコンピュータ「Apple I」を販売するために起業することを決意し、同年4月1日にウォズニアックおよびロナルド・ウェインと共同で「アップルコンピュータ・カンパニー」を創業した。")
    
    for token in doc:
        print(token.text, token.pos_, token.vector[:2]) # 単語ベクトルの最初の2次元のみ出力
    
    

    のような操作が簡単にできます。spacy.loadを通じて事前に定義されたパイプラインと学習済みモデルを読み込み、そこに文を入力することで内部で単語分割と品詞情報を付与したDocオブジェクトが生成されます。各単語はTokenオブジェクトになっており、品詞情報や埋め込みベクトルを呼び出すことが出来ます。

    形態素解析した文章を文単位に分割するときは、doc.sents を用いて

    
    doc =nlp('spaCy はオープンソースの自然言語処理ライブラリです。学習済みの統計モデルと単語ベクトルが付属しています。')
    for s in doc.sents:
        print(s)
    
    

    と入力します。

    
    spaCy はオープンソースの自然言語処理ライブラリです。
    学習済みの統計モデルと単語ベクトルが付属しています。   
    
    

    名詞句のみ抽出するときは、以下のようにします。doc.noun_chunks を用います。

    
    for np in doc.noun_chunks:
        print(np)
    
     spaCy
     オープンソース
     自然言語処理ライブラリ
     学習済み
     統計モデル
     単語ベクトル    
    
    

    依存関係を可視化する機能もあります。jupyter notebook を起動して、以下のコードを実行します。

    
    from spacy import displacy
    displacy.render(doc, style="dep", options={"compact":True})
    
    

    依存関係のグラフが表示されます。

    固有表現抽出は文中の単語がそれぞれどんな固有表現を持つかを予測することです。以下の文に対して固有表現を取り出してみます。

    
    doc = nlp('2018年の夏にフランスに行った。ジベルニー村のジャン・クロード・モネの家で池に浮かぶ睡蓮を見た。')
    for ent in doc.ents:
        print(ent.text, ent.start_char, ent.end_char, ent.label_)
    
    

    以下の結果が表示されます。

    
    2018年 0 5 DATE
    夏 6 7 DATE
    フランス 8 12 LOC
    ジベルニー村 17 23 LOC
    ジャン・クロード・モネ 24 35 PERSON
    
    

    spaCyでは出力の可視化機能が豊富にあります。Jupyter環境で可視化するには以下のspacy.displacyを使います。

    doc = nlp('恵比寿にあるGarden Placeにはよく行く。三つ星フレンチのロブションにも行く。美味しいけど、高額な店だ。')
    
    displacy.render(doc, style="ent")
    
    

    以下のように、固有名詞に色がつきます。

    恵比寿 LOC にあるGarden Placeにはよく行く。三つ星フレンチの ロブション ORG にも行く。美味しいけど、高額な店だ。
    
    

    LOCは場所、ORGは組織名です。Garden Place は固有名詞としてはタグ付きされていません。英文では、普通名詞ですね。

    文章のトークン化で生成された単語のベクトル表現を見るときは、以下のように入力します。

    
    token = doc[6]
    print(token)
    print(token.vector)
    
    以下が結果です
    に
    [-0.3364834  -0.3304015   0.48512152  0.00971493 -0.53814125 -0.40941057
      0.11331341  0.37284666  1.7968493   0.03470068 -0.2087467   0.14600077
      0.5679184   0.6358313   0.74924064 -0.31182808  0.06420083 -1.1553096
      0.7298233   0.5770952  -0.13159536 -0.37240943 -0.16940811 -0.41190833
      0.19864053 -0.9732325   0.02771017  1.039847    1.191609    0.5982838
      0.6307686   1.0688727  -0.8462963  -0.6300568  -0.26891077 -0.11861878
     -0.298805   -0.4609053  -0.03465112 -0.42766702 -0.69790787  0.40475303
     -0.64429235 -0.16863054  0.07201386  0.80741704  1.6020759   0.909806
     -1.3255128  -0.10489891  0.68750393 -0.32993212  0.28356764 -0.18942814
      0.5340779  -0.08497069  0.7528766  -0.13633768 -0.06377768  0.15060464
     -0.28614843 -0.5399209   0.7124946  -0.5067208   0.03513991 -0.43718255
      0.30380574 -0.49380696 -0.09729388  0.1833167   0.56754035  0.5102274
      0.3808821   0.5141533  -1.3498139   0.34355974 -0.04191615  1.0142361
      0.7048285  -0.58027756  0.14902164 -0.31125942  0.07090253 -0.57392216
     -0.03852378 -0.01111794  0.15501869 -0.78775823  0.06303703  0.73310703
     -0.5367188   0.88056207  0.10123526  0.4752925  -0.30720884  0.03859398
     -0.119146    0.15512064  0.78491586 -0.8594853 ]
    
    

    単語のベクトル表現の次数は100です。次に、文章の類似度の計算をしましょう。

    
    doc1 = nlp("これまで様々なセミナーに参加してきましたが、個人的に一番満足できたセミナーでした。プログラミング関係に疎い私でも理解でき、逆にプログラミングに興味を持ち、自分でもプログラミングに携わりたい・作りたいと思いました。")
    doc2 = nlp("難しいように見えますが仕組みは簡単につくれる環境があって誰でもできるところが素晴らしいと思いました。AIに関して全く知識が無く、漠然としていましたが、このセミナーを受けて少し霧が晴れた気がすると同時に、AIへの興味が強くなりました。")
    
    doc1.similarity(doc2)
    
    

    結果は、0.9436557774027887 となりました。どう思いますか?



    *** 続く ***

    BERTによる日本語処理のページに移る

    Chatbots and AI Assistantsのページ

    このページの先頭に戻る