概要
固有表現抽出データセットに必要な、文頭表現のデータフレームを作成します。
ポートフォリオとして、自作のデータセットでファインチューニングした言語モデルを使ったアプリを公開しました。
この記事を読むだけでも、この記事の内容をある程度理解できるとは思いますが、データセット作成の導入記事を読んでいる前提で書かれています。
固有表現抽出データセット
この記事で作成されるもの
補足情報
開発はGoogle Colaboratoryで行われ、このノートブックで作成しました。
このノートブックを含むリポジトリの構造は、実際の開発環境と同一です。
from
で参照されている自作モジュールは、このディレクトリにあるものです。
その他のコード内で参照しているパスやディレクトリから/content/drive/MyDrive
を省くと、そのパスやディレクトリの中身をリポジトリから確認することができます。
方針
各固有表現を表す文字列と、各固有表現に続く文字列をもとに、文頭表現のデータフレームを作成します。
大まかな手順
-
”[AREA]”、”[TYPE]”、”[SZN]”、”[INGR]”の4つの固有表現をもとに、全組み合わせと、各組合せの全並び替えのリスト(
token_combs
)の作成token_combs[ ('[AREA]',), ('[TYPE]',), ('[SZN]',), ('[INGR]',), ('[AREA]', '[TYPE]'), ('[TYPE]', '[AREA]'), ('[AREA]', '[SZN]'), ('[SZN]', '[AREA]'), ('[AREA]', '[INGR]'), ('[INGR]', '[AREA]'), ('[TYPE]', '[SZN]'), ('[SZN]', '[TYPE]'), ('[TYPE]', '[INGR]'), ('[INGR]', '[TYPE]'), ('[SZN]', '[INGR]'), ('[INGR]', '[SZN]'), ('[AREA]', '[TYPE]', '[SZN]'), ('[AREA]', '[SZN]', '[TYPE]'), ('[TYPE]', '[AREA]', '[SZN]'), ('[TYPE]', '[SZN]', '[AREA]'), ('[SZN]', '[AREA]', '[TYPE]'), ('[SZN]', '[TYPE]', '[AREA]'), ('[AREA]', '[TYPE]', '[INGR]'), ('[AREA]', '[INGR]', '[TYPE]'), ('[TYPE]', '[AREA]', '[INGR]'), ('[TYPE]', '[INGR]', '[AREA]'), ('[INGR]', '[AREA]', '[TYPE]'), ('[INGR]', '[TYPE]', '[AREA]'), ('[AREA]', '[SZN]', '[INGR]'), ('[AREA]', '[INGR]', '[SZN]'), ('[SZN]', '[AREA]', '[INGR]'), ('[SZN]', '[INGR]', '[AREA]'), ('[INGR]', '[AREA]', '[SZN]'), ('[INGR]', '[SZN]', '[AREA]'), ('[TYPE]', '[SZN]', '[INGR]'), ('[TYPE]', '[INGR]', '[SZN]'), ('[SZN]', '[TYPE]', '[INGR]'), ('[SZN]', '[INGR]', '[TYPE]'), ('[INGR]', '[TYPE]', '[SZN]'), ('[INGR]', '[SZN]', '[TYPE]'), ('[AREA]', '[TYPE]', '[SZN]', '[INGR]'), ('[AREA]', '[TYPE]', '[INGR]', '[SZN]'), ('[AREA]', '[SZN]', '[TYPE]', '[INGR]'), ('[AREA]', '[SZN]', '[INGR]', '[TYPE]'), ('[AREA]', '[INGR]', '[TYPE]', '[SZN]'), ('[AREA]', '[INGR]', '[SZN]', '[TYPE]'), ('[TYPE]', '[AREA]', '[SZN]', '[INGR]'), ('[TYPE]', '[AREA]', '[INGR]', '[SZN]'), ('[TYPE]', '[SZN]', '[AREA]', '[INGR]'), ('[TYPE]', '[SZN]', '[INGR]', '[AREA]'), ('[TYPE]', '[INGR]', '[AREA]', '[SZN]'), ('[TYPE]', '[INGR]', '[SZN]', '[AREA]'), ('[SZN]', '[AREA]', '[TYPE]', '[INGR]'), ('[SZN]', '[AREA]', '[INGR]', '[TYPE]'), ('[SZN]', '[TYPE]', '[AREA]', '[INGR]'), ('[SZN]', '[TYPE]', '[INGR]', '[AREA]'), ('[SZN]', '[INGR]', '[AREA]', '[TYPE]'), ('[SZN]', '[INGR]', '[TYPE]', '[AREA]'), ('[INGR]', '[AREA]', '[TYPE]', '[SZN]'), ('[INGR]', '[AREA]', '[SZN]', '[TYPE]'), ('[INGR]', '[TYPE]', '[AREA]', '[SZN]'), ('[INGR]', '[TYPE]', '[SZN]', '[AREA]'), ('[INGR]', '[SZN]', '[AREA]', '[TYPE]'), ('[INGR]', '[SZN]', '[TYPE]', '[AREA]'), ]
-
token_combs
と、各固有表現に続く文字列をもとに、文頭表現のデータフレームの作成
(各固有表現には、後の処理で、具体的な固有表現を入れます。)
(”[PRON]”には、”料理”、”レシピ”などの、文頭表現の末尾として適切な文字列が入ります。)
コード
import
from google.colab import drive
drive.mount('/content/drive')
from typing import Dict, List, Iterator, Tuple
import itertools
import pandas as pd
import sys
sys.path.append('/content/drive/MyDrive/local_cuisine_search_app/modules')
from pandas_utility import save_csv_df
関数とクラスの定義
def create_and_save(file_name: str, save_dir: str) -> pd.DataFrame:
"""
データフレームの作成と保存
文頭表現のデータフレームを作成して保存する
Parameters
----------
file_name : str
保存するファイル名
save_dir : str
保存先のディレクトリ
Returns
-------
pd.DataFrame
文頭表現のデータフレーム
"""
df = DataframeMaker.create()
save_csv_df(df, file_name, save_dir)
return df
class DataframeMaker:
"""
文頭表現のデータフレームを作成するクラス
Attributes
----------
_token_particles_dic : Dict[str, Tuple[str]]
各トークンと、それに続く表現の辞書
_pronoun_token : str
代名詞のトークン
_not_add_pronoun_tokens : Tuple[str]
直後に代名詞が続かないトークン
_not_last_particles : Tuple[str]
最後のトークンには、これのいずれかの文字列を含む表現を使わない
_not_double_strs : Tuple[str]
これらの文字列は、一つの文頭表現で2回以上は採用しない
"""
_token_particles_dic: Dict[str, Tuple[str]] = {
'[AREA]': ('の', 'で', 'で食べられる', 'に'),
'[TYPE]': ('で', 'に'),
'[SZN]': ('の', 'に', 'に食べられる'),
'[INGR]': ('を使った',)
}
_pronoun_token: str = '[PRON]'
_not_add_pronoun_tokens: Tuple[str] = ('[TYPE]',) # ※1
_not_last_particles: Tuple[str] = ('に', 'で')
_not_double_strs: Tuple[str] = ('に', '食')
@classmethod
def create(cls) -> pd.DataFrame:
"""
データフレームの作成
作成した全トークンの組み合わせのリストをもとに、
文頭表現のデータフレームを作成する
Returns
-------
pd.DataFrame
文頭表現のデータフレーム
"""
tokens = list(cls._token_particles_dic.keys())
token_combs = DataframeMaker._create_token_combs(tokens)
all_start_of_sentences = DataframeMaker._create_all_start_of_sentences(
token_combs
)
df = pd.DataFrame(all_start_of_sentences)
return df
@staticmethod
def _create_token_combs(tokens: List[str]) -> List[Tuple[str]]:
"""
トークンの組み合わせの作成
トークンの全ての組み合わせのイテレータを作成する
Parameters
----------
tokens : List[str]
組み合わせ作成対象のトークン
Returns
-------
List[Tuple[str]]
トークンの全組み合わせのリスト
"""
token_combs: List[Tuple[str]] = []
max_tokens_num = len(tokens) + 1
for tokens_num in range(1, max_tokens_num):
combs: Iterator[Tuple[str]] = itertools.combinations(
tokens, tokens_num
)
for comb in combs:
permutations: Iterator[Tuple[str]] = itertools.permutations(comb)
token_combs.extend(permutations)
return token_combs
@staticmethod
def _create_all_start_of_sentences(
token_combs: List[Tuple[str]]
) -> List[str]:
"""
全ての文頭表現の作成
全ての文頭表現のリストを作成する
Parameters
----------
token_combs : List[Tuple[str]]
トークンの全組み合わせ
Returns
-------
List[str]
全ての文頭表現のリスト
"""
all_start_of_sentences: List[str] = []
for comb in token_combs:
start_of_sentences = DataframeMaker._create_start_of_sentences(comb)
all_start_of_sentences.extend(start_of_sentences)
return all_start_of_sentences
@classmethod
def _create_start_of_sentences(cls, comb: Tuple[str]) -> List[str]:
"""
文頭表現の作成
渡されたトークンの組み合わせに該当する全ての文頭表現を作成する
Parameters
----------
comb : Tuple[str]
トークンの組み合わせ
Returns
-------
List[str]
文頭表現のリスト
"""
start_of_sentences: List[str] = []
soss = start_of_sentences
last_token_idx = len(comb) - 1
for token_idx, token in enumerate(comb):
if token_idx == last_token_idx:
soss = DataframeMaker._add_last_strs(soss, token)
else:
particles = cls._token_particles_dic[token]
tokens_added_particle = [token + partcl for partcl in particles]
if token_idx == 0:
soss = tokens_added_particle
else:
soss = DataframeMaker._add_following_strs(
soss, tokens_added_particle
)
return soss
@classmethod
def _add_last_strs(cls, soss: List[str], token: str) -> List[str]:
"""
最後の表現の追加
特定の組み合わせの最後のトークンの表現を作成し、追加する
Parameters
----------
soss : List[str]
作成途中の文頭表現のリスト
token : str
最後に追加するトークン
Returns
-------
List[str]
文頭表現のリスト
"""
if token in cls._not_add_pronoun_tokens:
if soss:
soss = [sos + token for sos in soss]
else:
soss.append(token)
else:
particles = cls._token_particles_dic[token]
tokens_added_particle = [
token + partcl for partcl in particles
if partcl not in cls._not_last_particles
]
if soss:
soss = DataframeMaker._add_following_strs(
soss, tokens_added_particle
)
soss = [sos + cls._pronoun_token for sos in soss]
else:
soss = [
t_a_p + cls._pronoun_token for t_a_p in tokens_added_particle
]
return soss
@classmethod
def _add_following_strs(
cls, soss: List[str], following_strs: List[str]
) -> List[str]:
"""
続く表現の追加
作成途中の文頭表現に続くトークンと付随する全ての表現を追加する
Parameters
----------
soss : List[str]
作成途中の文頭表現
following_strs : List[str]
トークンとそれに続く表現のリスト
Returns
-------
List[str]
following_strsが付与された文頭表現のリスト
"""
former_soss = soss.copy()
soss.clear()
for fmr_sos in former_soss:
not_double_strs = [
string for string in cls._not_double_strs if string in fmr_sos
]
if not_double_strs:
the_following_strs = [
f_str for f_str in following_strs
if not any(n_d_str in f_str for n_d_str in not_double_strs)
]
else:
the_following_strs = following_strs
soss.extend([fmr_sos + f_str for f_str in the_following_strs])
return soss
実行
file_name = 'start_of_sentences_dataframe_v1'
save_dir = '/content/drive/MyDrive/local_cuisine_search_app/data/processed_data/04_encoded_dataset_dataframe/encoded_dataset_dataframe_dependencies/01_untokenized_dataset_list/untokenized_dataset_list_dependencies/01_dataset_template_list/dataset_template_list_dependencies/01_start_of_sentences_dataframe'
df = create_and_save(file_name, save_dir)
メモ
※1
”[PRON]”に入るのは、”料理”とか、”もの”とか、”やつ”とか、検索対象そのものを示す言葉です。
そして、”[TYPE]”に入るのは、”飯料理”とか、”肉料理”とか、料理の種類を示す言葉です。
”[TYPE]”の直後に、”[PRON]”が続くような表現はおかしいので、(「飯料理の料理」とか、「肉料理のもの」とか)ので、_not_add_pronoun_tokens
で”[PRON]”が続かないトークンを指定しています。