Pythonを使った特許解析:IPC活用(4)

スポンサーリンク
Python
スポンサーリンク

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
0ANaN生活必需品1
1A01NaN農業;林業;畜産;狩猟;捕獲;漁業2
2A01BNaN農業または林業における土作業:農業機械または器具の部品,細部または附属具一般(播種,植え付け…3
3A01B 1/00NaN手作業具(芝生の縁切り取り具A01G3/06)4
4A01B 1/02鋤;ショベル5
78517H05K 13/06機械による配線[2006.01]5
78518H05K 13/08組立体の製造の監視[2006.01]5
78519H99NaNこのセクションの中で他に分類されない主題事項[8]2
78520H99ZNaNこのセクションの中で他に分類されない主題事項[8]3
78521H99Z 99/00NaNこのセクションの中で他に分類されない主題事項[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から説明を出力する関数を作成しました。作った関数をご自分の特許解析の処理に組み込めば、わかりやすい特許マップの作成などに応用できると思います。

コメント