新旧字体の表記ゆれを統一するために互換表を作成した話

こんにちは、PR TIMESのインターンの土屋です。私は現在データ解析インターンとしてプレスリリースを始めとする記事データの解析に携わっています。

今回はデータの前処理用に新旧字体を統一するcsvファイルを作成しました.

目次

どうして新旧字体の表記ゆれを統一しようと思ったか

プレスリリースや各メディアの転載記事に旧字体と新字体が混じっていて解析のノイズになっていることが判明したからです。

例えば、新字体「国」と旧字体「國」が混ざっているようなケースです。

麻雀をしていたら國士無双が出て驚いた。
麻雀をしていたら国士無双が出て驚いた。

このような新旧字体はそれぞれの文字コードが異なるため、別の文字として扱われてしまいます。

実際に二つの文字のベクトルが違うことをword2vecで作成したモデルで確認します。

# ベクトルを表示
print(model.wv['國'][:10])
print(model.wv['国'][:10])
# [-0.7325802  -0.62632436 -0.841284    0.7578425   0.2539938   0.2262604
#   0.3874282   0.17596856 -0.44506177 -0.04973697]
# [ 0.18717308  1.0561227   0.16029984  0.84652656 -1.5607154  -2.0747993
#   0.18328437  0.69604254  

文章を分析する際に単語ベクトルを使用するため、この結果は文章をベクトル化した時にも影響します。

以上のように、データに新旧字体が混ざっていて解析結果に影響が出ていることが判明したので、統一することにしました。

新旧字体の互換表の作成

当初は異体字セレクタを使って変形をしようと考えていたのですが、見つかりませんでした。そこで方針を新旧字体表をスクレイピングして整形する方向に切り替えました。

インターネット上で探したところ、新旧字体表を公開しているサイトが見つかりました

新旧字体表

スクレイピングする方法は複数ありますが、今回のような表データの場合、pandas.read_htmlが簡単にコードを書くことができます。以下のコードはGoogle Colabを立ち上げれば実行できます。(2022年11月17日現在)

# pandasはGoogle Colabにデフォルトで入っているのでinstall不要
import pandas as pd

# 表データをスクレイピング
dfs = pd.read_html(
    '<https://www.asahi-net.or.jp/~ax2s-kmtn/ref/old_chara.html>',
    encoding="utf8"
)

取得したデータを確認します。今回はdfs[1]、dfs[2]で欲しいデータが取得できていることがわかります。

print(len(dfs))
for df in dfs:
    print(df.columns)
    print('='*30)

# 3
# Int64Index([0], dtype='int64')
# ==============================
# Index(['JIS', 'Unicode', '新', '旧', 'JIS.1', 'Unicode.1', 'JIS.2', 'Unicode.2',
#        '新.1', '旧.1', 'JIS.3', 'Unicode.3', 'JIS.4', 'Unicode.4', '新.2', '旧.2',
#        'JIS.5', 'Unicode.5'],
#       dtype='object')
# ==============================
# Index(['JIS', 'Unicode', '新', '異', 'JIS.1', 'Unicode.1', 'JIS.2', 'Unicode.2',
#        '新.1', '異.1', 'JIS.3', 'Unicode.3', 'JIS.4', 'Unicode.4', '新.2', '異.2',
#        'JIS.5', 'Unicode.5'],
#       dtype='object')
# ==============================

データが一行あたり三つ併記されている状態になっているので整形します。

# データ一つ分のdataframeに切り分け
df_tmp_1 = dfs[1].iloc[:,0:6]
df_tmp_2 = dfs[1].iloc[:,6:12]
df_tmp_3 = dfs[1].iloc[:,12:18]
df_tmp_4 = dfs[2].iloc[:,0:6]
df_tmp_5 = dfs[2].iloc[:,6:12]
df_tmp_6 = dfs[2].iloc[:,12:18]

# 列名を統一
new_columns = [
		'new_jis',
    'new_unicode',
    'new_jikei',
    'old_jikei',
    'old_jis',
    'old_unicode',
]

df_tmp_1.columns = new_columns
df_tmp_2.columns = new_columns
df_tmp_3.columns = new_columns
df_tmp_4.columns = new_columns
df_tmp_5.columns = new_columns
df_tmp_6.columns = new_columns

# 表を縦い合体する
new_df = pd.concat([df_tmp_1, df_tmp_2], axis=0)
new_df = pd.concat([new_df, df_tmp_3], axis=0)
new_df = pd.concat([new_df, df_tmp_4], axis=0)
new_df = pd.concat([new_df, df_tmp_5], axis=0)
new_df = pd.concat([new_df, df_tmp_6], axis=0)

# データの入っていない行を削除
new_df = new_df.dropna(how='all')

# インデックスを振り直す
new_df = new_df.reset_index(drop=True)

作成したDataFrameをGoogle Colabの画面で確認してみます。

display(new_df)

問題なければ保存します。

new_df.to_csv('dir_path/file_name.csv', encoding='utf8')

確認する

下記のコードを使って確認することができます

import pandas as pd

# csvファイルを読み込み
df = pd.read_csv('新旧字体表.csv')

# 旧字体と新字体の辞書を作成
old_kanji = list(df['old_jikei'])
new_kanji = list(df['new_jikei'])
jitai_dict = dict(zip(old_kanji, new_kanji))

# 辞書を検索して文字列を置き換える関数を作成
def kyujitai_to_shinjitai(text):
    encoded_text = text.translate(str.maketrans(jitai_dict))
    return encoded_text

print(kyujitai_to_shinjitai('麻雀をしていたら國士無双が出て驚いた。'))
# 麻雀をしていたら国士無双が出て驚いた。

まとめ

今回の出来事を通じて生のデータを見ることの重要さを改めて感じました。

作成した表を用いて、より表記ゆれに強い機械学習モデルにできるように頑張ります。

この記事を書いた人

PR TIMESインターン / ML & Stats

目次
閉じる