Pythonのpandasを使って国際特許分類(IPC)からその説明を出力する関数を作っている。前回はHセクションのデータから、IPCを入力すると、その説明を出力する関数を作成した。今回は、Hセクション以外についても、IPCの情報をDataFrameに追加し、情報を出力できるようにする。
ここまでの流れについて、以前までの記事をご参照ください。
複数のExcelファイルからデータを読み込んでDataFrameを作成
特許庁のWebサイトから読み込んできたExcel形式のIPCデータを読み込んでDataFrameを作成します。WebサイトのExcelファイルはZip形式で配布されているので、ローカルにダウンロードし、解凍し、わかりやすいディレクトリに保存します。ここでは、作業するディレクトの直下に「data/」というディレクトリを作成してその中に入れています。
ここでも、インタラクティブ開発環境のJupyter Labを用いてデータの処理をしていきます。ここでは、IPCというディレクトを作業フォルダとしてその中のdata/ディレクトリを作成し、解凍したExcelファイルをコピーしました。IPCのデータは各セクションごとに1つのExcelファイルになっています。
ここでは、最初に前回の関数の時にも使ったpandas, numpy, reのライブラリに加え、ファイル名を取得するためにPythonに標準で入っているglobライブラリと全角文字を半角に変換するためのunicodedataライブラリをインポートします。(ライブラリの使い方は後述)
data/ディレクト以下のExcelファイルのファイル名を取得し、filesの変数にリストとして代入してやります。
files = glob.glob(‘data/*.xls’)
そして、それをfor文で回して呼び出し、DataFrameにconcatで追加していきました。追加が確実にされていることを確認するために、print文で進捗状況を出力しています。
最終的に、86791行のExcelファイルを読み込み、DataFrameに統合しました。
import pandas as pd
import numpy as np
import re
import glob
import unicodedata
files = glob.glob('data/*.xls')
print('File names')
print(files)
print('Length of DataFrame')
for i, file in enumerate(files):
if i == 0:
df = pd.read_excel(file)
else:
df = pd.concat([df, pd.read_excel(file)])
print(len(df), end=', ')
print('finished')
File names ['data\\IPC_Ver2022-Asection.xls', 'data\\IPC_Ver2022-Bsection.xls', 'data\\IPC_Ver2022-Csection.xls', 'data\\IPC_Ver2022-Dsection.xls', 'data\\IPC_Ver2022-Esection.xls', 'data\\IPC_Ver2022-Fsection.xls', 'data\\IPC_Ver2022-Gsection.xls', 'data\\IPC_Ver2022-Hsection.xls'] Length of DataFrame 10556, 30745, 47346, 51061, 54817, 65903, 75963, 86791, finished
データ処理用の関数の準備
すべてのセクションのIPCのデータを1つのDataFrameに統合できたので、ここからは、2回目、3回目で行った処理と同様の処理をしていきます。以下の3つの関数を記述します。
関数名 | 引数 | 出力 |
level_checker(IPC_code) | 解析したいIPC記号 | IPC記号の型からセクション、クラス、サブクラス、メイングループ、サブグループ、それ以外のどの形式なのかを判断し、0~5までの整数値を返します |
check_IPC(IPC_code) | 解析したいIPC記号 | IPC記号の型に一致するかをTrue/Falseで返します |
show_IPC(IPC_code) | 解析したいIPC記号 | DataFrameからIPC記号の説明の説明を返します |
# level列を追加
# level :表現形式:判断ロジック
# level = 0 : 不要な行:先頭がA~Hのアルファベットではない
# level = 1 : セクション(アルファベット1文字):A~Hのアルファベット
# level = 2 : クラス(アルファベット1文字+数字2桁:3桁
# level = 3 : サブクラス(アルファベット1文字+数字1~2桁+アルファベット1文字):4桁
# level = 4 : メイングループ(アルファベット1文字+数字2桁+アルファベット1文字+スペース+数字1~2桁+スラッシュ+00):スラッシュを含み、スラッシュの右が00
# level = 5 : サブグループ(アルファベット1文字+数字2桁+アルファベット1文字+スペース+数字1~2桁+スラッシュ+00以外の数字):スラッシュを含み、スラッシュの右が00以外
def level_checker(IPC_code):
if type(IPC_code) is float:
return 0
if re.match('[A-H]', IPC_code):
if len(IPC_code) == 1:
return 1
elif len(IPC_code) == 3:
return 2
elif len(IPC_code) == 4:
return 3
elif IPC_code.split('/')[1] == '00':
return 4
else:
return 5
else:
return 0
def check_IPC(IPC_code):
if re.match('[A-H][0-9][0-9][A-Z]\s+[0-9]+/[0-9]+',IPC_code):
return True
else:
return False
def show_IPC(IPC_code):
# 入力値を半角文字に変換
IPC_code = unicodedata.normalize("NFKD",IPC_code)
# 入力値がIPCのルールに合致するか確認
if check_IPC(IPC_code) == False:
return ['IPCコードが間違っています']
IPC_code = " ".join(IPC_code.split())
IPC = []
result = []
# level = 1 : セクション(アルファベット1文字)
result.append(df[df['記号']==IPC_code[0:1]]['タイトル'])
# level = 2 : クラス(アルファベット1文字+数字2桁
result.append(df[df['記号']==IPC_code[0:3]]['タイトル'])
# level = 3 : サブクラス(アルファベット1文字+数字1~2桁+アルファベット1文字)
result.append(df[df['記号']==IPC_code[0:4]]['タイトル'])
# level = 4 : メイングループ(アルファベット1文字+数字2桁+アルファベット1文字+スペース+数字1~2桁+スラッシュ+00)
result.append(df[df['記号']==(IPC_code.split('/')[0]+'/00')]['タイトル'])
# level = 5 : サブグループ(アルファベット1文字+数字2桁+アルファベット1文字+スペース+数字1~2桁+スラッシュ+00以外の数字)
result.append(df[df['記号']==IPC_code]['タイトル'])
for i in range(0,5):
if len(result[i]):
IPC.append(result[i].values[0])
else:
IPC.append("")
return IPC
今回新たにshow_IPC関数に全角入力のIPC記号に対しても対応可能なように、引数に入力された文字列を半角に変換するコードを追加しました。(特許データは全角で記載されることも多いので。。。)
IPC_code = unicodedata.normalize(“NFKD”,IPC_code)
unicodedata.normalizeは”NFKD”のフォーマットに合わせた文字列の標準化をしてくれます。
DataFrameの加工
前回と同様に、DataFrameの各行の分類をしたり、不要行を削除をするコードを記述し、DataFrameを利用しやすい形に加工します。一応、不要行削除前に各分類の行数をカウントし、削除される行を確認しています。
# インデキシングフラグ列を削除
df = df.drop("インデキシングフラグ",axis=1)
# level列追加
df['level'] = df['記号'].apply(level_checker)
df.reset_index(inplace=True, drop=True)
# level確認
print('BEFORE: List of IPC level')
print(df['level'].value_counts())
# level=0の行を削除
index_nums = df[df['level']== 0].index
df.drop(index_nums, inplace = True)
df.reset_index(inplace=True, drop=True)
# 記号列のスペースを調整
df['記号'] = df['記号'].apply(lambda x : " ".join(x.split()))
# level確認
print('AFTER: List of IPC level')
print(df['level'].value_counts())
BEFORE: List of IPC level 5 70191 0 8269 4 7545 3 647 2 131 1 8 Name: level, dtype: int64 AFTER: List of IPC level 5 70191 4 7545 3 647 2 131 1 8 Name: level, dtype: int64
上記より、78522行の記号を8つのセクションと131個のクラス、647個のサブクラス、7545個のメイングループ、70191個のサブグループに分類できました。
念のため、中身を確認します。
df
記号 | ドット | タイトル | level | |
---|---|---|---|---|
0 | A | NaN | 生活必需品 | 1 |
1 | A01 | NaN | 農業;林業;畜産;狩猟;捕獲;漁業 | 2 |
2 | A01B | NaN | 農業または林業における土作業:農業機械または器具の部品,細部または附属具一般(播種,植え付け… | 3 |
3 | A01B 1/00 | NaN | 手作業具(芝生の縁切り取り具A01G3/06) | 4 |
4 | A01B 1/02 | ・ | 鋤;ショベル | 5 |
… | … | … | … | … |
78517 | H05K 13/06 | ・ | 機械による配線[2006.01] | 5 |
78518 | H05K 13/08 | ・ | 組立体の製造の監視[2006.01] | 5 |
78519 | H99 | NaN | このセクションの中で他に分類されない主題事項[8] | 2 |
78520 | H99Z | NaN | このセクションの中で他に分類されない主題事項[8] | 3 |
78521 | H99Z 99/00 | NaN | このセクションの中で他に分類されない主題事項[8] | 4 |
78522 rows × 4 columns
IPCを説明する関数の出力確認
実際に作成したshow_IPCの関数を使ってみました。各IPCに対応する説明が出力されるのを確認しました。
print(show_IPC('H01M 10/052'))
print(show_IPC('H04N 7/137'))
print(show_IPC('H04N 7/15'))
['電気', '基本的電気素子', '化学的エネルギーを電気的エネルギーに直接変換するための方法または手段,例.電池[2]', '二次電池;その製造[2]', 'リチウム二次電池[2010.01]'] ['電気', '電気通信技術', '画像通信,例.テレビジョン[4]', 'テレビジョン方式(細部H04N3/00,H04N5/00;デジタルビデオ信号を符号化,復号化,圧縮または伸張するための方法または装置H04N19/00;選択的なコンテンツ配信H04N21/00)[4,2011.01]', ''] ['電気', '電気通信技術', '画像通信,例.テレビジョン[4]', 'テレビジョン方式(細部H04N3/00,H04N5/00;デジタルビデオ信号を符号化,復号化,圧縮または伸張するための方法または装置H04N19/00;選択的なコンテンツ配信H04N21/00)[4,2011.01]', '会議方式[5]']
最後に
ここでは、IPCから説明を出力する関数を作成しました。作った関数をご自分の特許解析の処理に組み込めば、わかりやすい特許マップの作成などに応用できると思います。
コメント