4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Wikiaを用いた固有表現抽出・エンティティリンキングデータセットの作製

Last updated at Posted at 2021-04-25

なんの記事?

Wikiaを用いて、固有表現抽出とエンティティ・リンキング用のデータセットを作製するツールを公開しました。

ツールで作製されるデータセットの中身

固有表現に対して、それに紐づくエンティティがセットでアノテーションされている形になります。下は、VTuberのwikiaを用いて作製されたデータセットの一部です。

    {
        "doc_title": "Melissa Kinrenka",
        "annotation": [
            {
                "0": {
                    "document_title": "Melissa Kinrenka",
                    "anchor_sent": "Melissa Kinrenka (メリッサ・キンレンカ) is a Japanese Virtual YouTuber and member of <a> Nijisanji </a>.",
                    "annotation_doc_entity_title": "Nijisanji",
                    "mention": "Nijisanji",
                    "original_sentence": "Melissa Kinrenka (メリッサ・キンレンカ) is a Japanese Virtual YouTuber and member of Nijisanji.",
                    "original_sentence_mention_start": 75,
                    "original_sentence_mention_end": 84
                },
                "1": {
                    "document_title": "Melissa Kinrenka",
                    "anchor_sent": "<a> Melissa Kinrenka </a> (メリッサ・キンレンカ) is a Japanese Virtual YouTuber and member of Nijisanji.",
                    "annotation_doc_entity_title": "Melissa Kinrenka",
                    "mention": "Melissa Kinrenka",
                    "original_sentence": "Melissa Kinrenka (メリッサ・キンレンカ) is a Japanese Virtual YouTuber and member of Nijisanji.",
                    "original_sentence_mention_start": 0,
                    "original_sentence_mention_end": 16
                }
            }
    }

各キーに紐づく値はそれぞれ以下のようになっています。

key value
document_title アノテーションが存在する記事ページのタイトル
anchor_sent アノテーション部分を <a> および </a> で囲んだ記事。エンティティ・リンキングを行う場合に使用します。
annotation_doc_entity_title アノテーションの紐付け先記事のタイトル
mention 実際の文中のメンション(固有表現)
original_sentence メンションが出現した、アンカー無しオリジナル文。
original_sentence_mention_start アンカー無しオリジナル文において、メンションの開始位置。
original_sentence_mention_end  アンカー無しオリジナル文において、メンションの終端位置。

ライセンスはWikiaのライセンスに従います。

Wikiaとは?

有志によるファンサイトコミュニティで、MediaWikiを利用したウィキ形式のウェブサイトです。MediaWiki形式なので、WikiExtractorを用いて前処理を行うことが可能です。

下はStar Warsからの引用です。

image.png

各コミュニティは、ウィキのページの集合から成り立ちます。それぞれのウィキ(例えば、上の"Ched Varga"の場合)を見てみると、登場人物の説明から始まり、説明文が続きます。

説明文の中には、同じコミュニティ内の別のページに飛ぶハイパーリンクが存在し、この部分を用いることで固有表現抽出とエンティティ・リンキング用のデータセットを作製することが可能です。

実際に行った前処理

Wikiextractorを用いた、リンクあり記事の抽出

前処理を行いたいコミュニティウィキのダンプファイルが[コミュニティ名].fandom.com/wiki/Special:Statisticsに存在するので、それをダウンロードして解凍した後、前処理を行います。(例:リンク)

wikiExtractorを用いて、リンクを残しつつ記事を抽出します。
python -m wikiextractor.WikiExtractor ./dataset/virtualyoutuber_pages_current.xml --links --json

外部リンクの削除

このままだと、外部リンクと<a>タグが残ったままの記事になり、固有表現抽出タスクには使用できません。なので、情報を残しつつ削除を行います。

BeautifulSoupを用いた<a>タグ削除

     soup = BeautifulSoup(sentence, "html.parser")

     for link in soup.find_all("a"):
         if "http" in link.get("href"):
             link.unwrap()

     return str(soup)

これにより、ハイパーリンクを残しつつ外部リンクを削除します。例えば、<a href="Nijisanji">Nijisanji</a>などはハイパーリンクなので残ります。

正規表現を用いた、アノテーションスパンの抽出

この次に行われる、文章分割の精度を上げるため、テキストからハイパーリンク情報を分離します。

今回は正規表現を用いてアノテーション位置を同定し、aタグを除去した文章と位置情報を返す関数を実装しました。

    def _convert_a_tag_to_start_and_end_position(self, text_which_may_contain_a_tag: str):
        a_tag_regex = "<a>(.+?)</a>"
        pattern = re.compile(a_tag_regex)

        a_tag_remaining_text = copy.copy(text_which_may_contain_a_tag)
        mention_positions = list()

        while '<a>' in a_tag_remaining_text:
            result = re.search(pattern=pattern, string=a_tag_remaining_text)
            if result == None:
                break

            original_start, original_end = result.span()
            a_tag_removed_start = copy.copy(original_start)
            a_tag_removed_end = copy.copy(original_end) - 7
            mention = result.group(1)

            original_text_before_mention = a_tag_remaining_text[:original_start]
            original_text_after_mention = a_tag_remaining_text[original_end:]

            one_mention_a_tag_removed_text = original_text_before_mention + mention + original_text_after_mention
            assert mention == one_mention_a_tag_removed_text[a_tag_removed_start: a_tag_removed_end]

            mention_positions.append((a_tag_removed_start, a_tag_removed_end))

            a_tag_remaining_text = copy.copy(one_mention_a_tag_removed_text)

        return a_tag_remaining_text, mention_positions

spaCyを用いた文章分割

aタグを除去することが出来たので、spaCyを用いて文章分割を行います。

wikia はその性質上、lit.という略語がよく現れます。(参考

このlit. による文章分割を防ぎつつ、文章分割を行います。

import spacy
from spacy.language import Language
from spacy.symbols import ORTH

nlp = spacy.load("en_core_web_md")

@Language.component('set_custom_boundaries')
def set_custom_boundaries(doc):
    for token in doc[:-1]:
        if token.text in ('lit.', 'Lit.', 'lit', 'Lit'):
            doc[token.i].is_sent_start = False
    return doc

nlp.add_pipe('set_custom_boundaries', before="parser")
nlp.tokenizer.add_special_case('lit.', [{ORTH: 'lit.'}])
nlp.tokenizer.add_special_case('Lit.', [{ORTH: 'Lit.'}])

アノテーションの追加

wikiaのページでは、コミュニティの運営者によって、ドキュメント内の各文書にハイパーリンクが付与されますが、常にすべての固有表現にアノテーションがされるわけではありません。

例えば、以下の例を見てみましょう。(Geroge Lucas のページから引用)

image.png

George Lucasはこの記事の中でも幾度となく出現しますが、それら全てにはアノテーションは付与されていません。なぜなら、このページがそもそも"George Lucas"を説明する記事であるからです。

また、以下のような例もあります。(同じく"Geroge Lucas"の記事内から引用)

image.png

この場合は"Lucas"が"Geroge Lucas"を指すことは言うまでもありません。

今回のデータセット作製時には、このように、ハイパーリンクが付与されていないものの、エンティティであると認められる場合についてもアノテーションを付与しました。

実際には、コミュニティ内のタイトル集合との文字列マッチを用いて、アノテーションを行うようプログラムを作製しました。

まとめ

wikiaのダンプファイルを用いて、固有表現抽出とエンティティ・リンキングに使用可能なデータセットを生成するツールを作製しました。

このツールを使用することで、wikiaに存在する各コミュニティに特化した固有表現抽出モデルや、エンティティ・リンキングモデルを訓練するためのデータセット作製が可能になります。

コードはこちらになります。

4
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?