Python と Excel を ChatGPTで効率的に運用してみる試みです。
今回は ECショッピングモール R*kuten のデータを題材にして、慣れたら簡単にできるんだろうけど、やっぱりちょっと面倒な処理を ChatGPTに手伝ってもらいます。
特に、ChatGPTが出力するソースコードのロジックをできるだけ正確にすることを目指します。
- 元はIT/ソフトウェア系のエンジニア
- 学生時代、本当はAIの研究をしたかったけど下火の時代で断念
- 現在は中小企業診断士 / 社内コンサルタント
- ただしExcelは苦手
- コーディングより上流工程
- デロンギのコーヒーメーカーのお陰でコーヒー充
今回の題材
業務の正確さと効率性
ショッピングモールの商品データベースのメンテナンスを、事務部門に依頼したいが全商品のチェックを依頼すると効率が悪いのと、反発が予想される。
そこで、過去の受注情報をショッピングモールからダウンロードし、最後の受注が古いほどメンテナンスの優先度を上げることを考えました。何故なら、最近受注されている商品の情報に誤りがあった場合、受注チームから訂正依頼が事務部門に行われているはずなので、古ければ古いほど、メンテナンスが行われていない可能性が高いためです。
留意点
受注情報は、最大で60日分しかダウンロードできないため、過去2年分をダウンロードする場合でも合計12ファイルほどに分割される。
これを手動で結合するのは面倒なので、ソフトウェアの機能などを用いて結合せずに処理するものとする。
ChatGPTに聞いてみた
Excel編
ピボットとかテーブルとか、lookupとかsumifとかでプログラムを使わなくてもできるかな? と思ったのでやってみます。
# 問い
Excelを用いて、商品データベースファイルにある各商品を最終受注日が古い順に並べ変えたテーブルを作成したいです。手順と式・またはマクロを提示してください。
#前提
各データベースのcsvファイルの1行目は、ラベル行となっています。以降の指示は列番号ではなく、ラベルで指示をします。
受注されたと見做すのは、受注情報のファイル内の「ステータス」が500の時です。
#ファイル
item.csv が商品データベースです。各商品の行には「商品管理番号」があり、これを用いて一意の商品を特定できます。
c:\受注データ\ フォルダに含まれるcsvファイルに過去の受注情報が分割して格納されています。「商品管理番号」でitem.csvと照合します。受注日時は「注文日時」に「yyyy-mm-dd hh:mm:ss」の形式で格納されています。
#補足
情報に不足があった場合、質問してください。
以下はExcelを用いて、商品データベースファイルにある各商品を最終受注日が古い順に並べ変えたテーブルを作成する手順です。
- 「受注データ」フォルダから、全ての受注情報のファイルを開きます。
- 受注情報のファイルから、受注情報が含まれる行のみを抽出します。つまり、「ステータス」列が500の行を選択します。
- 各商品の最終受注日を計算するために、各商品の受注情報を商品管理番号でグループ化します。
- 各商品の最終受注日を計算するために、各商品の受注情報を注文日時で降順に並べ替えます。これにより、最新の受注情報が最初になります。
- 各商品の最終受注日を計算するために、最初の受注情報の注文日時を取得します。
- 商品データベースファイルを開き、商品管理番号を使用して各商品を検索します。
- 各商品の最終受注日を計算するために、注文日時を最新の受注情報の日時に更新します。
- 各商品の最終受注日を使用して、商品を降順に並べ替えます。
- 並べ替えられた商品リストを新しいテーブルに貼り付けます。
以下は、これらの手順を実行するために使用できるExcel式です。
- 受注情報のファイルを開く:
- 「ファイル」タブを開き、データをインポートします。
- インポート元として、「Delimited」を選択します。
- 区切り記号として、「カンマ」を選択します。
- 「テキストクォート」を空白に設定します。
- データの先頭行にラベルがあることを確認します。
- インポート先として、新しいシートを選択します。
- 受注情報が含まれる行のみを抽出する:
- 「ステータス」列が500の行を選択します。
- 各商品の受注情報を商品管理番号でグループ化する:
- 「商品管理番号」を基準にして、データをグループ化します。
- 各商品の受注情報を注文日時で降順に並べ替える:
- 「注文日時」を基準にして、データを降順に並べ替えます。並べ替えは、以下の手順で行えます。
- データを選択します。
- 「データ」タブを開き、並べ替えツールをクリックします。
- 「注文日時」を基準にして、降順に並べ替えます。
- 各商品の最終受注日を計算するために、最初の受注情報の注文日時を取得する:
- グループ化されたデータの最初の行を選択します。
- 「注文日時」列の値を取得します。
- 商品データベースファイルを開き、商品管理番号を使用して各商品を検索する:
- 「商品管理番号」を基準にして、商品データベースファイルのデータを検索します。
- 各商品の最終受注日を計算するために、注文日時を最新の受注情報の日時に更新する:
- 各商品の「最終受注日」列に、最初の受注情報の注文日時を入力します。
- 各商品を最終受注日が古い順に並べ替える:
- 「最終受注日」を基準にして、データを降順に並べ替えます。
- 並べ替えられた商品リストを新しいテーブルに貼り付ける:
- 新しいシートを作成し、商品リストを貼り付けます。
以上の手順を実行することで、商品データベースファイルにある各商品を最終受注日が古い順に並べ変えたテーブルを作成できます。ただし、手順の具体的な式やマクロを提示することは、データの形式や内容によって異なるため、ここでは記載しておりません。
ながながーっと出て来ましたが、よくよく読んでみると結局のところ操作手順です。いや、これをマクロ化なり式なりでして欲しいんですが……という。まあ、これだと確かに「ChatGPT使えねーな」という感想になってしまう気がします。
Excelで使う場合には、もっと具体的なデータを貼り付けて、式を入力させた方がいいかもしれません。
というか、以降の Python の例でも色々工夫しているので、筆者のプロンプトぢからが不足しているだけかもしれません。
Python編 ダメなプロンプト
ということで、次は Python のスクリプトを書かせてみます。
# 問い
Pythonで、商品データベースファイルにある各商品を最終受注日が古い順に並べ変えたcsvファイルを作成するスクリプトを記述しなさい。
#前提
各データベースのcsvファイルの1行目は、ラベル行となっています。以降の指示は列番号ではなく、ラベルで指示をします。
受注されたと見做すのは、受注情報のファイル内の「ステータス」が500の時です。
受注情報が見つからない商品データは、最終受注日が1900年1月1日であるとして処理します。
#ファイル
item.csv が商品データベースです。各商品の行には「商品管理番号」があり、これを用いて一意の商品を特定できます。
c:\受注データ\ フォルダに含まれるcsvファイルに過去の受注情報が分割して格納されています。「商品管理番号」でitem.csvと照合します。受注日時は「注文日時」に「yyyy-mm-dd hh:mm:ss」の形式で格納されています。
#補足
情報に不足があった場合、質問してください。
Excel で問い合わせた内容とほぼ一緒です。一意の情報があるので、それをキーにしてロジック組んでくれないかなぁという、ダメ上司っぷりが現れた指示ですね。
import csv
import os
# 商品データベースの読み込み
item_data = []
with open("item.csv", "r") as item_file:
item_reader = csv.DictReader(item_file)
for item in item_reader:
item_data.append(item)
# 受注データベースの読み込み
order_data = []
order_folder = "c:\\受注データ\\"
for order_file in os.listdir(order_folder):
with open(os.path.join(order_folder, order_file), "r") as f:
order_reader = csv.DictReader(f)
for order in order_reader:
order_data.append(order)
# 商品の最終受注日を算出
for item in item_data:
item_id = item["商品管理番号"]
latest_order_date = "1900-01-01 00:00:00"
for order in order_data:
if order["商品管理番号"] == item_id and order["ステータス"] == "500":
order_date = order["注文日時"]
if order_date > latest_order_date:
latest_order_date = order_date
item["最終受注日"] = latest_order_date
# 商品を最終受注日が古い順に並べ変え
item_data = sorted(item_data, key=lambda x: x["最終受注日"])
# 結果をcsvファイルに出力
with open("result.csv", "w", newline="") as result_file:
result_writer = csv.DictWriter(result_file, fieldnames=item_data[0].keys())
result_writer.writeheader()
for item in item_data:
result_writer.writerow(item)
結構いい感じに出ていますが、日付データをただの文字列にしてしまっているので、これでは上手く動きません。
この後、プロンプトを変えるのですが、受注データと商品データを無理に結合しようとしてappendメソッドを使ったりして、正解からドンドン遠ざかります。
仕方がないので、プロンプトで処理手順を詳細に書くようにしました。
# 問い
Pythonで、以下の処理に従って、入力となるcsvファイルを処理し、出力するプログラムを記述しなさい。
#処理
item.csvを読み込み、1行目のラベル行を読み取り、そのラベル行を元にデータにアクセスします。
商品データのリストを作成し、全てのフィールドを格納します。「最終受注日」フィールドは空のため、全てに初期値として最終受注日を1900年1月1日とするように設定します。
受注データの読み込み:c:\\受注データ\\フォルダ内のすべてのCSVファイルを読み込みます。1行目のラベル行を読み取り、そのラベル行を元にデータにアクセスします。
「ステータス」が500のものだけ処理します。
処理中の受注データの「商品管理番号」と商品データのリスト内に「商品管理番号(商品URL)」が一致する商品データを検索します。
一致する商品データの最終受注日が受注データの受注日時がより古かった場合、商品データの最終受注日を受注データの受注日時で上書きします。
商品データのリストを最終受注日が古い順にソートします。
商品データを、item_new.csv ファイルに出力します。
#入力に使用するファイル
各ファイルの1行目はラベル行です。
##item.csv
商品データベースです。各商品の行には「商品管理番号(商品URL)」があり、これを用いて一意の商品を特定できます。「最終注文日時」フィールドは空欄です。
##c:\受注データ\ フォルダに含まれるcsvファイル
受注情報が分割して格納されています。受注日時は「注文日時」に「yyyy-mm-dd hh:mm:ss」の形式で格納されています。「商品管理番号」で商品を特定できます。「ステータス」で処理を行うかどうか判定します。
#補足
情報に不足があった場合、質問してください。
最初の #問い ラベルではプログラムを書くということだけを指示します。変に要望を入れてしまうと、ChatGPTが混乱してしまうようでした。
続いて、処理については最初のプログラムではdictで読み込んでいたのに、何故か試行錯誤の段階ではリストのインデックスでアクセスしようとしまう(もちろん、適当な数字なので動作しない)ことが多発したのでラベルデータを元にアクセスすることを明示します。
更に細かく、処理して欲しい内容を日本語で記述していきます。これだと、ほぼ日本語でプログラムを書いているような気分になりますが、それでも手でループを書くよりは(多分)早いです。
そうして出力されたプログラムですが、
# item_new.csvに出力
fieldnames = ["商品管理番号(商品URL)", "最終受注日"]
with open("item_new.csv", "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames)
writer.writeheader()
for item in items:
writer.writerow({"商品管理番号(商品URL)": item["
このように何故か、使用したラベルだけを使って書き出そうと律儀なことをしてくれたので、修正を指示します(途中までしか出力されていないのもそのまま)。
item.csvにある、商品管理番号(商品URL)、最終受注日以外のフィールドが抜け落ちないように、全ての項目がitem_new.csvに出力されるように直してください。
import csv
import os
from datetime import datetime
# 初期値として最終受注日を1900年1月1日とする
default_date = datetime(1900, 1, 1)
# 商品データを格納するリスト
items = []
# item.csvの読み込み
with open("item.csv", "r") as f:
reader = csv.DictReader(f)
# フィールド名のリストを取得
fieldnames = reader.fieldnames
for row in reader:
# 最終受注日を初期値として設定
row["最終受注日"] = default_date
items.append(row)
# 受注データの読み込み
order_folder = r"c:\受注データ\\"
for filename in os.listdir(order_folder):
if filename.endswith(".csv"):
with open(os.path.join(order_folder, filename), "r") as f:
reader = csv.DictReader(f)
for row in reader:
# ステータスが500のものだけ処理
if row["ステータス"] == "500":
# 商品データを検索
for item in items:
if item["商品管理番号(商品URL)"] == row["商品管理番号"]:
# 最終受注日を更新
order_datetime = datetime.strptime(row["受注日時"], "%Y-%m-%d %H:%M:%S")
if item["最終受注日"] < order_datetime:
item["最終受注日"] = order_datetime
# 商品データを最終受注日でソート
items.sort(key=lambda x: x["最終受注日"])
# item_new.csvに出力
with open("item_new.csv", "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames)
writer.writeheader()
for item in items:
writer.writerow(item)
datetime モジュールを適切に用いて、日時の比較がきちんと行われるようになっています。
しかし一方で、ループとifが最初のものより深くなっているという問題があります。これはプロンプトが箇条書きで処理の流れを詳細に説明するものになったため、それを忠実に再現してしまっただめだと思います。これを避けるには、人間の方がより効率的な処理になるよう、日本語でプログラムを書くように指示する必要があります。
欲を言えばふわっと「データAとデータBで両方の表を関連づけられるから、それでうまいこと組み合わせて」とできればいいのですが(最初の出力がかなりいい具合だったのですが)、修正指示も実際には再生成となってしまうようなので、指示したところ以外まで変わってしまい、余計おかしくなるという現象が頻発するという問題が発生します。
そのため、今回のような実験以外では、「ある程度動作してたらOK, モジュールやメソッドが(ChatGPTの)意図通りの動作をしない場合、人間がその意図通りに直してやる」といった扱い方が最も生産性が高くなりそうです。
また、今回のように生成したいデータ形式が決まっている場合は、Excelでのやり方を問い合わせるよりもプログラムを書いてもらう方が、圧倒的に人間は楽ができそうです。
その意味で言うと、ChatGPTをプログラミング言語に変換する通訳(インタープリタ)として扱うのも面白そうです。
引き続き、AIの実験は色々(チャットAI以外にも)やっていって結果を書いて行こうと思います。
楽介でした。