👨🦲
LangChainによるデータ分析レポーティング
やること
LLMにCSVデータを渡してデータ分析のレポーティングを試みたいと思います。
前提
最近だとKaggleのベースラインを初手ChatGPTにやらせるのは割と普通ですが、出力結果にハルシネーションがあったり、EDAの内容が毎回異なったりでデータ分析の自動化を社会実装するにはまだまだ課題があるかと思います。今回は、LangChainのProptTemplateとAzureChatOpenAIを用いて、出力される内容をある程度定型化したレポーティングをgpt-4o-miniでどこまでできるのかを試してみます。
参考文献
分析結果のレポート項目についてはこちらの書籍を参考にしました。
依存ライブラリ
pip install azure-search-documents langchain_openai langchain_community
事前準備
今回使用するデータはこちらの記事で使われている2022年4月1日の豊洲市場のデータです。
分類,市場,水産市場ID,日付,種別,品名,販売方法,卸売予定数量(t)
水産,豊洲,Sui_K1,2022/4/1,鮮魚,あじ,相対,19.5
水産,豊洲,Sui_K1,2022/4/1,鮮魚,さば,相対,21.7
水産,豊洲,Sui_K1,2022/4/1,鮮魚,いわし,相対,13.5
水産,豊洲,Sui_K1,2022/4/1,鮮魚,するめいか,相対,10.5
水産,豊洲,Sui_K1,2022/4/1,鮮魚,かつお,相対,14.6
水産,豊洲,Sui_K1,2022/4/1,鮮魚,さんま,相対,2
水産,豊洲,Sui_K1,2022/4/1,鮮魚,かれい,相対,7.6
水産,豊洲,Sui_K1,2022/4/1,鮮魚,きんめだい,相対,7.4
水産,豊洲,Sui_K1,2022/4/1,鮮魚,はまち,相対,22.5
水産,豊洲,Sui_K1,2022/4/1,鮮魚,ぶり・わらさ,相対,25.8
水産,豊洲,Sui_K1,2022/4/1,鮮魚,まだい,相対,14.5
水産,豊洲,Sui_K1,2022/4/1,鮮魚,めじ,相対,4.4
水産,豊洲,Sui_K1,2022/4/1,鮮魚,さけます類,相対,10.5
水産,豊洲,Sui_K1,2022/4/1,鮮魚,たら類,相対,9.6
水産,豊洲,Sui_K1,2022/4/1,鮮魚,いなだ・わかし,相対,18.6
水産,豊洲,Sui_K1,2022/4/1,鮮魚,さわら・さごち,相対,5.6
水産,豊洲,Sui_K1,2022/4/1,鮮魚,あんこう,相対,2
水産,豊洲,Sui_K1,2022/4/1,鮮魚,かき,せり・入札,0.8
水産,豊洲,Sui_K1,2022/4/1,鮮魚,かき,相対,2.7
水産,豊洲,Sui_K1,2022/4/1,鮮魚,その他(鮮魚),せり・入札,3.3
こちらのデータは事前にベクトル化してAI Searchのインデックスに登録しておきます。
import os
import pandas as pd
from azure.identity import DefaultAzureCredential, InteractiveBrowserCredential
from langchain_openai import AzureOpenAIEmbeddings
from langchain_community.vectorstores import AzureSearch
from langchain_community.document_loaders import CSVLoader
from langchain.text_splitter import CharacterTextSplitter
import time
from dotenv import load_dotenv
load_dotenv()
# 環境変数の読み込み
AZURE_OPENAI_API_KEY = os.getenv("AZURE_OPENAI__API_KEY")
AZURE_OPENAI_ENDPOINT = os.getenv("AZURE_OPENAI_ENDPOINT")
AZURE_OPENAI_EMBEDDINGS = os.getenv("AZURE_OPENAI_EMBEDDDINGS")
EMBEDDING_DEPLOYMENT_NAME = os.getenv("EMBEDDING_DEPLOYMENT_NAME")
AZURE_SEARCH_API_KEY = os.getenv("AZURE_SEARCH_API_KEY")
AZURE_SEARCH_ENDPOINT = os.getenv("AZURE_SEARCH_ENDPOINT")
AZURE_SEARCH_SERVICE_NAME = os.getenv("AZURE_SEARCH_SERVICE_NAME")
# Azure OpenAI Embeddingsの初期化
embeddings = AzureOpenAIEmbeddings(
azure_deployment=EMBEDDING_DEPLOYMENT_NAME,
openai_api_version="2023-03-15-preview"
)
# Azure Searchの初期化
index_name = "fish-index"
vector_store = AzureSearch(
azure_search_key=AZURE_SEARCH_API_KEY,
azure_search_endpoint=AZURE_SEARCH_ENDPOINT,
index_name=index_name,
embedding_function=embeddings.embed_query
)
# データの読み込み
loader = CSVLoader("estimate_quantity_fish_ANSI.csv")
documents = loader.load()
# 各ドキュメント(行ごと)のテキストを連結して1つの文字列として扱う
text_data = [" ".join([str(value) for value in doc.metadata.values()]) for doc in documents]
text_splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=0)
docs = text_splitter.split_documents(documents)
vector_store.add_documents(documents=docs)
レポート化
それでは実際にレポート化してもらいます。
from azure.search.documents import SearchClient
from azure.core.credentials import AzureKeyCredential
from langchain.prompts import PromptTemplate
from langchain_openai import AzureChatOpenAI
from dotenv import load_dotenv
import os
load_dotenv()
# 環境変数の読み込み
AZURE_OPENAI_API_KEY = os.getenv("AZURE_OPENAI__API_KEY")
AZURE_OPENAI_ENDPOINT = os.getenv("AZURE_OPENAI_ENDPOINT")
AZURE_SEARCH_API_KEY = os.getenv("AZURE_SEARCH_API_KEY")
AZURE_SEARCH_ENDPOINT = os.getenv("AZURE_SEARCH_ENDPOINT")
# Azure AI Search クライアントを初期化
search_client = SearchClient(
endpoint=AZURE_SEARCH_ENDPOINT,
index_name="fish-index",
credential=AzureKeyCredential(AZURE_SEARCH_API_KEY)
)
def get_ai_search_data():
results = search_client.search(search_text="*", top=20)
search_data = ""
for result in results:
search_data += result["content"] + "\n"
return search_data
def get_report_with_ai_search_data(search_data):
all_data = "\n".join(search_data)
template = PromptTemplate.from_template(
"""以下のデータに基づいて分析結果をレポート化してください。レポート項目は以下の内容を可能な限り含めてください。:
データ:\n{search_data}\n
レポート項目:
1. 目的
目的を見失うことがないよう、「何の課題を解決するためか」記載してください。
2. 背景
分析の「目的」を明確にするため、なぜその課題を解決する必要があるのか記載してください。
3. 分析結果
次の項目を記載してください。
₋ 分析のストーリー(ロジック)
₋ 期間やサンプル数
₋ 使用した分析手法の説明
₋ 分析結果
₋ 考察
4. ネクストアクション
データ分析の結果をもとに、次に何をすべきか記載してください。
₋ 分析結果から検討した施策内容
₋ その施策を行うこととした裏付けの数値
₋ 追加分析の内容
₋ 施策の効果検証を行う方法
"""
)
prompt = template.format(search_data=all_data)
return prompt
search_data = get_ai_search_data()
prompt = get_report_with_ai_search_data(search_data)
chat = AzureChatOpenAI(
api_key=AZURE_OPENAI_API_KEY,
api_version="2023-07-01-preview",
azure_endpoint=AZURE_OPENAI_ENDPOINT,
deployment_name="dev-gpt-4o-mini"
)
output = chat.predict(prompt)
print(output)
実行結果
# 水産市場分析レポート
## 1. 目的
本レポートの目的は、2022年4月1日に豊洲水産市場での鮮魚の卸売予定数量を分析することで、需 要の傾向を把握し、効果的な在庫管理および販売戦略を策定することです。この分析は、鮮魚の供 給と需要のバランスを取るための基礎データを提供します。
## 2. 背景
水産市場は、需給の変動が激しく、適切な在庫管理が求められます。特に鮮魚は賞味期限が短いた め、効率的な仕入れと販売が重要です。需要と供給の正確な理解がなければ、在庫の過剰や不足が 生じ、結果として経済的損失を引き起こす可能性があります。この課題を解決することで、効率的 な運営と収益の最大化を図ることができます。
## 3. 分析結果
### 分析のストーリー(ロジック)
- 豊洲水産市場における鮮魚の卸売予定数量を分析し、需要の傾向と市場の特性を把握します。
- 各品名ごとの予定数量を比較し、特に需要が高い魚種を特定します。
### 期間やサンプル数
- 分析対象期間: 2022年4月1日の1日
- サンプル数: 27品目の鮮魚データ
### 使用した分析手法の説明
- 卸売予定数量を基に、各品目の需給バランスを視覚化するために棒グラフを作成しました。また 、数量の合計を計算し、全体の傾向を把握しました。
### 分析結果
- 卸売予定数量の合計は、**263.4t**であり、最も多かった品目は「ぶり・わらさ」で**25.8t**、次いで「はまち」が**22.5t**、そして「さば」が**21.7t**となりました。
- 一方で、最も少ない予定数量は「かき」の**0.8t**でした。
- 相対販売方法が主流である一方、特定の品目ではせり・入札が使用されています。
### 考察
- 需要が高い魚種に対しては、より多くの仕入れを行い、供給を維持することが求められます。
- 反対に、需要が低い品目については、仕入れ数量を減らすことが必要です。特に「かき」のよう に予定数
### 追加分析の内容
- 過去の販売データを基に、季節ごとの需要変動を分析し、最適な仕入れスケジュールを策定します。
- 消費者の購買動向や嗜好を調査し、需要予測モデルを構築します。
### 施策の効果検証を行う方法
- 施策実施後、実際の売上データを収集し、仕入れ数量との相関分析を行います。
- 定期的に評価を行い、必要に応じて在庫戦略や販売戦略の見直しを行います。
---
以上が、2022年4月1日に豊洲水産市場での鮮魚卸売予定数量に基づいた分析結果のレポートです。データに 基づく戦略的な施策が、経済的な利益を最大化することに寄与することを期待します。
コメントなど
事前準備したインデックスの情報をもとにレポーティングはしてくれましたが、細かく読んでいくとサンプル数や卸売予定数量の数値が誤っていたり、文章が途中で切れていたりでなかなか厳しい内容となっています。。
また、1つ大きな問題としてデータ分析の目的をきちんと与えていないため、GPTの想像で目的や背景、ネクストアクションを出力しています。今回のデータの場合、そもそも数値データは卸売予定数量しか与えていないので深い分析ができるわけないとも言えます。その意味ではデータセットに応じた分析の目的や分析内容をあらかじめ精査し、プロンプトに組み込むなどする必要があると感じました。
Discussion