Pythonで意匠マップを書いてみる

# はじめに
前回は、J-platpatからダウンロードしたCSVデータから、商標マップを作成しました。そうしますと意匠マップも作りたくなりますので、今回チャレンジしました。
# 意匠データ
J-platpatで、意匠に係る物品に「電動自転車」という用語を含む意匠を検索しました。ヒット件数は、121件でした。以下にダウンロードしたCSVデータの一部（4件）を示します。

このCSVデータを用いて意匠マップを作成します。マップ作成に使用する項目は、意匠に係る物品、出願人/権利者、出願日の３つとなります。

| 登録番号| 出願番号| 国際登録番号 | 意匠に係る物品| 出願人/権利者                   | 日本意匠分類/旧日本意匠分類 | 公報発行日  | 出願日      | ハーグ |
|-------------|--------------|----------|-----------------------|-----------------------------|---------|---------|---------|----|
| 1739009      | 2022-502540   | DM/224185-001 | 電動自転車           | Yadea Technology Group Co., Ltd. | G2-400  | 2023/3/14 | 2022/9/14 | 〇  |
| 1738785      | 2022-023154   |          | 電動自転車のフレーム| 東莞市梵摩科技有限公司              | G2-49100 | 2023/3/10 | 2022/10/26 |    |
| 1738541      | 2022-012460   |          | 電動自転車           | 深セン市随牛科技有限公司              | G2-400  | 2023/3/8  | 2022/6/10  |    | 
| 1737785      | 2022-017782   |          | 電動自転車のフレーム| 深セン市カ西威爾科技有限公司            | G2-49100 | 2023/2/28 | 2022/8/22  |    | 
# プログラム
今までは、ランキングマップ・時系列マップと、バブルチャートと、とは別のプログラムとしていましたが、今回は、ランキングマップ、時系列マップ、バブルチャート３つをひとつのプログラムで処理することに挑戦したいと思います。

これは、両プログラムで重複したコードを共通化することにより、プログラムの作成を効率化できるのではないか、という目論見のためとなります。
## 出願人top20のランキングマップ
まず、出願人top20のランキングマップを作成します。この出願人top20のランキングのリストを使用して、後のバブルチャートを作成します。
```python
import pandas as pd
import matplotlib.pyplot as plt
import japanize_matplotlib
import numpy as np
import matplotlib.cm as cm
from collections import Counter
from google.colab import drive
# Googleドライブのマウント
drive.mount('/content/drive')
# データの読み込み
data = pd.read_csv("/content/drive/MyDrive/電動自転車意匠.csv", encoding="utf-8")
# データ前処理
data = data[['出願人/権利者', '出願日', '日本意匠分類/旧日本意匠分類']]
data['出願人/権利者'] = data['出願人/権利者'].str.replace('▲', '').str.replace('▼', '')
data['出願日'] = pd.to_datetime(data['出願日'])
data['出願人/権利者'] = data['出願人/権利者'].str.split(',')
# Top20出願人の取得
applicant_counts = Counter(sum(data['出願人/権利者'], []))
top20_applicants = pd.DataFrame(applicant_counts.most_common(20))
top20_applicants = top20_applicants.sort_values(by=1, ascending=True)
# 出願人ランキングTop20の棒グラフ
fig1 = plt.figure(figsize=(8.0, 6.0))
plt.rcParams["font.size"] = 11
plt.title("出願人ランキングtop20")
plt.barh(top20_applicants[0], top20_applicants[1])
```
以下が、ランキングマップとなります。パナソニック、パナソニックＩＰマネジメント、松下電器産業は同一の会社となりますが、ここでは、そのままとしたいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3110569/d0fb377b-6d4a-7727-8071-9fb610582d39.png)
## 出願件数の推移
次に出願件数の推移を見たいと思います。
```python
# 件数推移の折れ線グラフ
year_counts = data['出願日'].dt.year.value_counts().sort_index().reset_index()
year_counts.columns = ["出願年", "件数"]
year_range = pd.DataFrame([year.year for year in pd.date_range(start='1997-01-01', end='2023-12-31', freq='y')], columns=["出願年"])
year_counts = pd.merge(year_counts, year_range, how="right", on="出願年").fillna(0)

fig2 = plt.figure(figsize=(12.0, 6.0))
plt.rcParams["font.size"] = 11
plt.title("件数推移（1997年～2023年）")
plt.xticks(np.arange(1997, 2024, 1))
plt.xlim(1996.8, 2023.2)
plt.yticks(np.arange(0, 21, 1))
plt.ylim(0, 20)
plt.plot(year_counts["出願年"], year_counts["件数"], label='物品「電動自転車」含む')
plt.xlabel('出願年')
plt.ylabel('件数')
plt.xticks(rotation=60)
plt.legend()
```
以下が、件数推移のマップとなります。2013年にピークが一つあり、その後、なぜか減少し、近年また増えているように見えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3110569/e6f65f28-9bc4-39bd-266a-c9b002471d02.png)
## 日本意匠分類/旧日本意匠分類-出願人/権利者マップ
次に、意匠分類と出願人のバブルチャートを書きたいと思います。分類と出願人をエクスプロード処理して、出願人を上記top20に限定します。また意匠分類も辞書をつかって置き換えます。
```python
# 散布図用データの前処理
data['日本意匠分類/旧日本意匠分類'] = data['日本意匠分類/旧日本意匠分類'].str.split(',')
data_exploded = data.explode('日本意匠分類/旧日本意匠分類').explode('出願人/権利者')
grouped_data = data_exploded.groupby(['日本意匠分類/旧日本意匠分類', '出願人/権利者']).size().reset_index(name='Counts')
top_applicants_map = grouped_data[grouped_data['出願人/権利者'].isin(top20_applicants[0].tolist())]
# map置き換え用の辞書作成
replace_dict = {
    'G2-30':'G2-30\n自動二輪車',
    'G2-390':'G2-390\n自動二輪車部品',
    'H2-212':'H2-212\n充電器',
    'L3-13':'L3-13\n交通施設物',
    'G2-400':'G2-400\n自転車',
    'G2-49100':'G2-49100\n自転車外装器具',
    'G2-4970':'G2-4970\n自転車用照明灯',
    'G2-490':'G2-490\n自転車部品',
    'H2-2120':'H2-2120\n充電器',
    'G2-500':'G2-500\n運搬車',
    'G2-490W':'G2-490W\n自転車部品',
    'G2-49500':'G2-49500\n自転車用動力関係部品',
    'H1-800':'H1-800\n電池,蓄電池',
    'H1-84':'H1-84\n車両用蓄電池',
    'H1-890':'H1-890\n電池,蓄電池部品',
    'J1-300':'J1-300\n回転計,流量計',
    'H1-3433':'H1-3433\n多極コネクター',
    'H2-1200':'H2-1200\n電動機'
}

# mapメソッドを使用して日本意匠分類/旧日本意匠分類を日本語に置き換える
top_applicants_map.loc[:, '日本意匠分類/旧日本意匠分類'] = top_applicants_map['日本意匠分類/旧日本意匠分類'].map(replace_dict)

# 散布図の描画
categories = list(set(top_applicants_map['出願人/権利者']))
colors = cm.rainbow(np.linspace(0, 1, len(categories)))
colors = {categories[i]: colors[i] for i in range(len(categories))}
colors = [colors[item] for item in top_applicants_map['出願人/権利者']]

sizes = [size * 30 for size in top_applicants_map['Counts'].tolist()]
nums = [num for num in top_applicants_map['Counts'].tolist()]

fig3, ax = plt.subplots(figsize=[10, 10])
ax.scatter(top_applicants_map['日本意匠分類/旧日本意匠分類'], top_applicants_map['出願人/権利者'], s=sizes, c=colors)

for i, txt in enumerate(nums):
    ax.annotate(txt, (top_applicants_map['日本意匠分類/旧日本意匠分類'].tolist()[i], top_applicants_map['出願人/権利者'].tolist()[i]), textcoords="offset points", xytext=(0, 0), ha='left', va='bottom')

ax.set_xlabel("日本意匠分類/旧日本意匠分類")
ax.set_ylabel("出願人/権利者")
ax.set_title("日本意匠分類/旧日本意匠分類-出願人/権利者マップ")
plt.xticks(rotation=70)
```
すると下記の図が出力されました。パナソニックは電動自転車関連の用品を含めて幅広く出願していることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3110569/b24d8049-3467-76ff-8b82-6b3278b75e1c.png)

## 出願年-出願人/権利者マップ
次に、出願年と出願人のバブルチャートを書きたいと思います。出願人と意匠分類をエクスプロード処理したデータフレームについて、出願人を上記top20に限定します。ただし、出願人のみエクスプロード処理したデータフレームを使用した方がよいかもしれません。
```python
# 出願年と出願人/権利者の関係を示す散布図のデータ前処理
top_applicants_year_map = data_exploded[data_exploded['出願人/権利者'].isin(top20_applicants[0].tolist())]
top_applicants_year_map_counts = top_applicants_year_map.groupby(['出願人/権利者', top_applicants_year_map['出願日'].dt.year]).size().reset_index(name='Counts')

# カラーマップの作成
categories_year_map = list(set(top_applicants_year_map_counts['出願人/権利者']))
colors_year_map = cm.rainbow(np.linspace(0, 1, len(categories_year_map)))
colors_year_map = {categories_year_map[i]: colors_year_map[i] for i in range(len(categories_year_map))}

# 新しいcolorsリストの作成
colors_year_map_counts = [colors_year_map[item] for item in top_applicants_year_map_counts['出願人/権利者'].tolist()]

# サイズリストの作成
sizes_year_map_counts = [size * 30 for size in top_applicants_year_map_counts['Counts'].tolist()]

# 散布図の描画
fig4, ax = plt.subplots(figsize=[10, 10])
ax.scatter(top_applicants_year_map_counts['出願日'], top_applicants_year_map_counts['出願人/権利者'], s=sizes_year_map_counts, c=colors_year_map_counts)

# カウント数の表示
for i, txt in enumerate(top_applicants_year_map_counts['Counts'].tolist()):
    ax.annotate(txt, (top_applicants_year_map_counts['出願日'].tolist()[i], top_applicants_year_map_counts['出願人/権利者'].tolist()[i]), textcoords="offset points", xytext=(0, 0), ha='left', va='bottom')

ax.set_xlabel("出願年")
ax.set_ylabel("出願人/権利者")
ax.set_title("出願年-出願人/権利者マップ")
plt.xticks(np.arange(min(top_applicants_year_map_counts['出願日']), max(top_applicants_year_map_counts['出願日'])+1, 1))
plt.xticks(rotation=60)
```
下記が出力された図です。通常このような時系列図は折れ線グラフで書くと思いますが、20社を折れ線グラフとしますと、線がこんがらがってわけがわからなくなります。一方、バブルチャートとしますと、そういうこともないので、すべてバブルチャートで書けばよいような気もしてきました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3110569/2b3a5cee-9696-ccc4-a744-a9778af8f020.png)
## 出願年-意匠分類マップ
最後に、出願年と意匠分類のバブルチャートを書きたいと思います。意匠分類と出願人をエクスプロード処理したデータフレームをコピーしたものを使用していますが、意匠分類のみをエクスプロード処理したデータフレームを使用した方がよいかもしれません。
```python
# 出願年-日本意匠分類/旧日本意匠分類マップのデータを作成
year_design_class_map = data_exploded.copy()
year_design_class_map['出願日'] = year_design_class_map['出願日'].dt.year
year_design_class_map = year_design_class_map.groupby(['出願日', '日本意匠分類/旧日本意匠分類']).size().reset_index(name='Counts')

# mapメソッドを使用して日本意匠分類/旧日本意匠分類を日本語に置き換える
year_design_class_map.loc[:, '日本意匠分類/旧日本意匠分類'] = year_design_class_map['日本意匠分類/旧日本意匠分類'].map(replace_dict)

# カラーマップの設定
categories_design_class = list(set(year_design_class_map['日本意匠分類/旧日本意匠分類']))
colors_design_class = cm.rainbow(np.linspace(0, 1, len(categories_design_class)))
colors_design_class_map = {categories_design_class[i]: colors_design_class[i] for i in range(len(categories_design_class))}
colors_year_design_class_map = [colors_design_class_map[item] for item in year_design_class_map['日本意匠分類/旧日本意匠分類']]

# サイズリストの作成
sizes_year_design_class_map = [size * 30 for size in year_design_class_map['Counts'].tolist()]

# 散布図の描画
fig5, ax = plt.subplots(figsize=[10, 10])
ax.scatter(year_design_class_map['出願日'], year_design_class_map['日本意匠分類/旧日本意匠分類'], s=sizes_year_design_class_map, c=colors_year_design_class_map)

# カウント数の表示
for i, txt in enumerate(year_design_class_map['Counts'].tolist()):
    ax.annotate(txt, (year_design_class_map['出願日'].tolist()[i], year_design_class_map['日本意匠分類/旧日本意匠分類'].tolist()[i]), textcoords="offset points", xytext=(0, 0), ha='left', va='bottom')

ax.set_xlabel("出願年")
ax.set_ylabel("日本意匠分類/旧日本意匠分類")
ax.set_title("出願年-日本意匠分類/旧日本意匠分類マップ")
plt.xticks(np.arange(1997, 2024, 1))
xticklabels = [str(label) for label in np.arange(1997, 2024, 1)]
ax.set_xticklabels(xticklabels)
plt.xticks(rotation=60)

plt.show()
```
下が出力された図です、新旧の意匠分類の変更の時期がなんとなくわかります。意匠の出願の分野については、自転車本体から関連部品に時間とともに広がっているように見えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3110569/eb01f949-d1e7-bf00-1e89-3ff8e66006a6.png)
# 感想
プログラムをまとめるのにGPT-4を使用しましたが、プログラムが長くなりますと、はたしてきちんと動作しているのか初心者には確認が難しくなります。

GPT-4に、プログラムをまとめる方が良いのか、短いプログラムを複数作った方が良いのか聞きますと、どちらも一長一短あるとのことでしたが、まとめる方がよいようなニュアンスでもありました。

初心者は短いプログラムを作り、動作が安定したら、GPT-4にまとめさせる方が無難と感じました。