【python】wiktionaryの見出しのうち日本語、名詞に関するものを抽出する

# 概要
wiktionaryの記事テキストから「日本語」の「名詞」に関する情報を抽出するため、該当するテンプレートの調査をしました。[【python】wiktionaryから語義情報を抽出する](https://qiita.com/shimajiroxyz/items/f75b4f7717643d3fbcf0)の続きです。
wiktionaryのテンプレート情報は、[Wiktionary:テンプレートの一覧/言語表記](https://ja.wiktionary.org/wiki/Wiktionary:%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%81%AE%E4%B8%80%E8%A6%A7/%E8%A8%80%E8%AA%9E%E8%A1%A8%E8%A8%98)、[Wiktionary:テンプレートの一覧](https://ja.wiktionary.org/wiki/Wiktionary:%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%81%AE%E4%B8%80%E8%A6%A7#%E5%93%81%E8%A9%9E%E8%A1%A8%E8%A8%98)、[Wiktionary:テンプレートの一覧/ja](https://ja.wiktionary.org/wiki/Wiktionary:%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%81%AE%E4%B8%80%E8%A6%A7/ja)などから参照できるのですが、同ページに乗っていない書き方の記事もあったので、実際の記事テキストから調査しました。
結果、「日本語」テンプレートの抽出条件として以下を得ました。

```
# 以下のいずれかと完全一致
{{ja}}
{{L|ja}}
日本語
[[:Category:{{ja}}|{{ja}}]]
{{jpn}}
```
また「名詞」テンプレート抽出条件として以下を得ました。

```
# 以下のいずれかの文字列を含む
noun
name
名
```

# 背景
[【python】wiktionaryから語義情報を抽出する](https://qiita.com/shimajiroxyz/items/f75b4f7717643d3fbcf0)にて、wiktionaryの語義情報を抽出したのですがノイズが多く使いにくいです。
wiktionaryには様々な言語、品詞における語義が記載されていますが、今回は、別途作ろうと思っているアプリケーションにおいて「日本語」の「名詞」の語義のみが分かれば十分だったため、それらの情報を抽出したいと思いました。

# 方針
「日本語」テンプレートについては、ja、jpn、日本、など日本語と関連しそうな言葉を含むものを大雑把に抽出して、重要そうなものを残す、という方法で抽出します。
同様に「名詞」テンプレートも、noun、name、名、など名詞と関連しそうな言葉を含むものを大雑把に抽出して重要そうなものを残すようにします。

# コード
目検分析が主ではありますが、対象の抽出等に使ったコードを記録として残しておきます。

## データの読み込み
[【python】wiktionaryから語義情報を抽出する](https://qiita.com/shimajiroxyz/items/f75b4f7717643d3fbcf0)にて作成した、wiktionaryの語義情報のtsvを読み込みます。
データは単語（word）、言語見出し（head2）、品詞見出し（head3）、語義ID（meaning_id）、語義（meaning）の列から構成されます。

```Python
# dfの読み込み
import pandas as pd
df = pd.read_csv("dictionary_meaning.tsv", sep="\t")
print("count",len(df))
print("unique", len(df["word"].unique()))
print(df.head())
```

```
count 517352
unique 259050
  word   head2          head3  meaning_id  \
0    青  [[漢字]]             意義           0   
1    青  {{ja}}       {{noun}}           0   
2    青  {{zh}}  {{adjective}}           0   
3    青  {{zh}}  {{adjective}}           1   
4    青  {{zh}}       {{name}}           0   

                                             meaning  
0  #[[グリーン]]。[[みどり]]。[[あお]]。[[くさき|草木]]の[[は|葉]]のよう...  
1  #（複合語で）（あお）色の一つ、[[グリーン]]。[[くさき|草木]]の[[は|葉]]のような色。  
2           #{{おくりがな2|青|あお|い|あおい}}。[[緑]]の。[[グリーン]]の。  
3                            #{{おくりがな2|黒|くろ|い|くろい}}。  
4                             #（現代）[[w:青海省|青海省]]の略称。
```

## 日本語テンプレートの抽出
言語見出し（head2）のうち、「ja」「jp」「日」を含むものを抽出します。
ついでにDataFrame.value_countsを使って、登場頻度も合わせて出力します。

```Python
head2 = df.head2.value_counts()
for i in head2.index:
  v = head2[i]
  if "ja" in i or "jp" in i or "日" in i:
    print(i, v)
```

```
{{ja}} 56583
{{L|ja}} 16846
{{L|ojp}} 3043
{{ojp}} 2121
日本語 1863
古典{{ja}} 817
古典日本語 91
[[:Category:{{ja}}|{{ja}}]] 11
{{ljp}} 6
[[:Category:古代{{ja}}|古代{{ja}}]] 5
{{jpn}} 4
{{jam}} 4
{{jao}} 4
日本手話 4
{{ajp}} 3
{{jac}} 1
{{ojp}}・漢文 1
{{L|cja}} 1
{{L|ajp}} 1
{{jaa}} 1
古代日本語 1
{{T|ojp}} 1
古典{{ja}}・漢文 1
{{jaz}} 1
```

ここから実際に「日本語」の見出しであるテンプレートとして（目検で）以下を抽出しました。

```
{{ja}}
{{L|ja}}
日本語
[[:Category:{{ja}}|{{ja}}]]
{{jpn}}
```

上記と完全一致する行のみをもとのdataframeから抽出します。

```Python
# 日本語関連テンプレートのリストをつくｒ
jp_templates = r"""
{{ja}}
{{L|ja}}
日本語
[[:Category:{{ja}}|{{ja}}]]
{{jpn}}
""".splitlines()[1:]
print(jp_templates)

# データの抽出
df_jp = df[df["head2"].isin(jp_templates)]
print("count",len(df_jp))
print("unique", len(df_jp["word"].unique()))
print(df_jp.head())
```

```
count 75307
unique 46814
   word     head2                head3  meaning_id  \
1     青    {{ja}}             {{noun}}           0   
6    保護       日本語                   名詞           0   
7    保護       日本語                   名詞           1   
12    靑       日本語                   意味           0   
13   今日  {{L|ja}}  {{noun}}・{{adverb}}           0   

                                              meaning  
1   #（複合語で）（あお）色の一つ、[[グリーン]]。[[くさき|草木]]の[[は|葉]]のような色。  
6                  #ある物が[[破壊]]されたりしないように[[まもる|守る]]こと。  
7                       #社会的弱者や生活力の低い者に対し[[支援]]を行うこと。  
12                                     #（あお）[[あお|青]]。  
13  #（[[きょう]]:[[熟字訓]]、古:[[こんにち]]）今過ごしているその[[日]]、この...  
```

約75000行、約47000単語が抽出されました。

## 名詞テンプレートの抽出

品詞見出し（head3）のうち、名詞と関連しそうなものの候補を出力します。
具体的には、noun、name、名のいずれかを含むテンプレートを出力します。
検索対象は前小節で抽出したdf_jpです。

```Python
head3 = df_jp.head3.value_counts()
for i in head3.index:
  v = head3[i]
  if "noun" in i or "name" in i or "名" in i:
    print(i, v)
```

```
{{noun}} 47757
{{name}} 1788
名詞 1187
{{adjectivenoun}} 966
{{noun}}・{{adjectivenoun}} 573
固有名詞 245
{{noun}}1 239
{{pronoun}} 189
{{noun}}2 170
{{noun}}・サ変動詞 95
人名 91
{{noun}}・形容動詞 60
{{noun}}・{{adverb}} 53
{{noun}}:植物 51
{{noun}}: {{ja}} 43
名詞・形容動詞 39
代名詞 36
{{noun}}・事 27
{{noun}}:魚 26
{{noun}}・{{verb}} 22
{{noun}}3 21
{{noun}}:形式名詞 15
{{noun}}:鳥 15
{{noun}}：裏 14
名詞・サ変動詞 14
...(結果略）...
{{noun}}: 穂並 1
{{noun}}: 穂波 1
{{noun}}: おしん 1
{{noun}}:瑞 1
{{noun}}：かいしょく 1
```

1600行以上候補が出てきたため、出力の一部を省略しています。「{{noun}}:形式名詞」などのように「{{noun}}」や「名詞」の後ろに属性を限定するための文字列がくっついているケースが多量にあるようです。
結果を眺めたところ、特に明確に名詞ではないと考えられる頻度の大きいテンプレートはなかったので、候補の抽出条件をそのまま、名詞に関するテンプレートの抽出条件として用いることにします。


```Python
# head3がnounを含む行を抽出
df_noun = df_jp[df_jp["head3"].str.contains("noun|name|名")]
print("count",len(df_noun))
print("unique", len(df_noun["word"].unique()))
print(df_noun.head())
```

```
count 56818
unique 37897
   word     head2                head3  meaning_id  \
1     青    {{ja}}             {{noun}}           0   
6    保護       日本語                   名詞           0   
7    保護       日本語                   名詞           1   
13   今日  {{L|ja}}  {{noun}}・{{adverb}}           0   
14   今日  {{L|ja}}  {{noun}}・{{adverb}}           1   

                                              meaning  
1   #（複合語で）（あお）色の一つ、[[グリーン]]。[[くさき|草木]]の[[は|葉]]のような色。  
6                  #ある物が[[破壊]]されたりしないように[[まもる|守る]]こと。  
7                       #社会的弱者や生活力の低い者に対し[[支援]]を行うこと。  
13  #（[[きょう]]:[[熟字訓]]、古:[[こんにち]]）今過ごしているその[[日]]、この...  
14                              #（こんにち）[[現代]]、[[現在]]。 
```

56818行、37897単語が抽出されました。

必要があれば結果を保存しておきます。

```Python
# 保存
df_noun.to_csv("dictionary_meaning_jp_noun.tsv", sep="\t", index=False)
```

# おわりに
wiktionaryの見出し（テンプレート）のうち、日本語、名詞に関するものが何かを調査し、データの抽出を実施ました。
テンプレートの一覧自体は、wiktionrayのテンプレート一覧ページから参照可能ですが、記事テキストが人手で更新されているためか、一覧ページに含まれないテンプレートが使われているケースも多く、抽出も少し苦労しました。
今回は、日本語」「名詞」に絞って調査しましたが、他言語、他品詞でも同様に一度候補をゆるい条件で抽出してから目検で絞ることが安全かと思われます。