はじめに
「データ分析はデータ成形が9割」というのは本当にそうで、実務ではいつも泣かされている。特別難しいことをしたいわけではないのに想定の100倍の時間と手数がかかる。すぐ使える形式でのデータが存在しないこともありがちである。実務なので時間にも制約がある。とてもつらい。
というわけで、ジャルジャル「国名わけっこ」にかこつけてデータ整形の練習を行った。
ジャルジャル「国名わけっこ」
元データ
国の産業連関表など、e-stat等を探せばExcel化された世界の国名リストは存在しないはずがない。
https://www.e-stat.go.jp/
しかし、現実は厳しく、必要なデータがPDF形式でしか存在しないことも多々あるため、PDF形式の一覧表をソースとして使用する。
https://www.jpo.go.jp/system/patent/pct/tetuzuki/document/kuni-meisho/kuni-meisho-ichiran.pdf
PDFの読み込み
pip install pymupdf
import fitz # PyMuPDF
import pandas as pd
import numpy as np
pdf_document = 'C:/Users/XXXXXXX/Desktop/kuni-meisho-ichiran.pdf'
pdf = fitz.open(pdf_document)
all_text = ""
for page_num in range(len(pdf)):
page = pdf[page_num]
text = page.get_text("text")
all_text += text
pdf.close()
出力
国の名称一覧表
1
英語の国の名称は、「英語名称」または、「2文字コード」のいずれかで記載可能です(特許協力条約に基づく実
施細則第 115 号)
日本語名称
英語名称
2文字
コード
アイスランド共和国
Iceland
IS
アイルランド
Ireland
IE
...
RU
ひとまずPDFの全てを縦持ちで取り込む。
整形
まず、実務でもありがちな変な要素たちをキレイにする。今回は数が少なくて助かった。
ジャルジャル福徳さん曰く、「国名わけっこ」は鬼ごっこ、かくれんぼ、ドロケー等と並ぶ小学生の遊びである。よって、小学生とは縁が薄いであろう英語名称とコードを削除するべく、データフレーム化してから不要列を列ごと削除する、というやり方にしてみた。
# テキストを行に分割して不要な行をフィルタリング
all_text = all_text.split("\n")[9:]
filtered_lines = [line for line in all_text if line not in ["国の名称一覧表 ", " ", "2 ", "3 ", "4 ", "5 ", "6 ", "日本語名称 ", "英語名称 ", "2文字 ", "コード "]]
# リストをデータフレームに変換
kunimei_df = pd.DataFrame(filtered_lines)
# 文字列の置換
kunimei_df[0] = kunimei_df[0].replace("グレート・ブリテン及び北部アイルラン", "グレート・ブリテン及び北部アイルランド連合王国", regex=True)
kunimei_df[0] = kunimei_df[0].replace("セントビンセントおよびグレナディーン", "セントビンセントおよびグレナディーン諸島", regex=True)
kunimei_df[0] = kunimei_df[0].replace("Saint Vincent and the ", "Saint Vincent and the Grenadines ", regex=True)
kunimei_df[0] = kunimei_df[0].replace("Micronesia \(Federated States ", "Micronesia \(Federated States of\) ", regex=True)
kunimei_df[0] = kunimei_df[0].replace("Lao People's Democratic ", "Lao People's Democratic Republic ", regex=True)
# 不要な行を削除
kunimei_df = kunimei_df[~kunimei_df[0].isin(['ド連合王国 ', '諸島 ', 'of) ', 'Republic ', 'Grenadines '])]
# DataFrameのデータを3列に再構成
# 行数を計算,全要素数を3で割り切り上げ
num_rows = np.ceil(len(kunimei_df) / 3).astype(int)
total_items = num_rows * 3
padded_data = np.resize(kunimei_df.values, (total_items,))
padded_data[-(total_items - len(kunimei_df)): ] = np.nan
reshaped_df = pd.DataFrame(np.reshape(padded_data,(num_rows, 3)))
# データを新しいDataFrameに入れていく
for index, row in enumerate(reshaped_df.itertuples(index=False)):
start_index = index * 3
end_index = start_index + 3
reshaped_df.iloc[index] = kunimei_df[0][start_index:end_index].values
# 不要列削除
reshaped_df = reshaped_df[[0]]
加工
ここまでで、国名の正式名称のリストでが作成できた。
次に、ジャルジャル福徳さんの「チュウ」のinputに対して後藤さんは「ゴク」とreturnしているのを反映するため、日本語の略称に変換していく。
「末尾で連続する漢字」を削除するという手もあるが、疲れてきたのでエイヤの力技で処理を行った。
replace_dict = {
"共和国 ": "",
"合衆国 ": "",
"民主": "",
"連邦": "",
"人民": "",
"連合": "",
"独立国": "",
"東方": "",
"王国": "",
"社会主義": "",
"・イスラム": "",
"・ハシェミット": "",
"市": "",
"他民族": "",
"大公国": "",
"公国": "",
"国 ": "",
}
# DataFrameの該当列に対して一括で置換を実行①
reshaped_df[0] = reshaped_df[0].replace(replace_dict, regex=True)
replace_dict = {
"グレート・ブリテン及び北部アイルランド": "イギリス",
"大韓民国 ": "韓国",
"中華 ": "中国",
"アラブ首長": "アラブ首長国連邦"
}
# DataFrameの該当列に対して一括で置換を実行②
reshaped_df[0] = reshaped_df[0].replace(replace_dict, regex=True)
# 結果
print(reshaped_df)
浅学ゆえ、「ハシェミット」という単語を初めて知った。
これは、ヨルダン王国の正式名称である「The Hashemite Kingdom of Jordan」における「Hashemite」を指す。ヨルダン王家が預言者ムハンマドの家系であるハシム家(Hashim)に由来することを示しており、王家の血統を強調するために国名に含まれている。ハシム家は、イスラム教の始祖であるムハンマドの祖父の名前にちなんでおり、ハシェミットはその子孫を指す言葉である。ヨルダン王国は、このハシム家の子孫であるハシェミット家が統治する国として知られている...とのこと。
成果物
0 アイスランド
1 アイルランド
2 アゼルバイジャン
3 アフガニスタン
4 アメリカ
.. ...
191 ルワンダ
192 レソト
193 レバノン
194 ロシア
感想
楽にデータ整形できるようになりたすぎる。実務では毎回「頭おかしなるわ」と思いながらやっている。
参考
「ハシム家」について
https://ja.wikipedia.org/wiki/%E3%83%8F%E3%83%BC%E3%82%B7%E3%83%A0%E5%AE%B6