FireDucksとチャットしてみませんか?
本記事はFireDucksユーザー記事シリーズの第11弾です.本記事はアリス様に執筆して頂きました.
FireDucksとは?
Pandasは、誰もが知っている非常に有名なデータ処理ライブラリーです。データ処理の仕事をしている人なら、多かれ少なかれ仕事で使ったことがあるはずです。
最近この太いパンダ (Pandas) が進化しているのをご存知ですか?なんと!進化したモンスターは火を吐くアヒル (FireDucks) だった。この火を吐くアヒルの名は 「FireDucks」 🔥🐤 です。NECデジタルテクノロジー開発研究所の博士たち日夜働く一所懸命の努力によって進化された究極のモンスターですよ!
FireDucksは本来のPandasより何倍も速く、Pandasとの互換性が最も優れています。
🔥🐤とチャットしてみませんか?
せっかくここまで進化したのだから、この可愛らしいアヒルと話せたら素敵です。
ちょっと待って?!まじか?! プログラムを書く必要がなく、会話を通じてFireDucksを直接操作できたら、どんなに楽しいでしょうか。
これからの記事では、AI魔法の力を使ってFireDucksと自然会話のかたちで動かす方法をデモンストレーションします。
AI魔法の力 「Prompt Engineering」
最近AIの発展はめまぐるしく進んでいます。 AIがプログラムを書けることをご存知ですか?
例えば
Prompt:
Pythonで時刻を知らせるプログラムを書いてください
結果はかなり良いですね、 じゃあ、Pandasを操作するのプログラムを作成できるか?
Prompt:
PandasのDataFrameには次のようなものがあります
sample_data = {
"student_id" : ["1000", "1001"],
"score" : [50, 60]
}
df = pd.DataFrame(sample_data)
平均点を計算するプログラムを書いてください
できます!
FireDucksはPandasの進化版、Pandasとの互換性によって、 AIは当然にFireDucksを操作するプログラムを作成できます。
われわれの目標にまた一歩近づいたようですね。
しかし、データ量が多い場合、実際のデータをAIとの会話に持ち込むことができません。幸いにもAIには知能がありますので、他の人間に仕事内容を教えるときのように、AIに十分な情報を与えれば、仕事をしてくれるでしょう。
ここで、DataFrameのすべてのデータをAIに渡すの代わりに、DataFrameの抽象的な説明を伝えます。AIには臨機応変な対応力がありますので、厳密なフォーマットに注意する必要はありません。
Prompt:
PandasのDataFrameには次のようなものがあります:
1) DataFrameの形は
"student_id" - string
"score" - int
2) DataFrameのサンプルは
student_id score
0 1000 50
1 1001 60
3) pythonプログラムは以下の関数ように:
def process_data(df)
平均点を計算する関数を書いてください
できましたね。
AIとの会話を試みる中で、皆さんはAIが私たちの望むことを効率的に実行できるように、必要な会話の編成する方法を徐々に理解できるでしょう。この細工の流れは今話題に成っている 「プロンプトエンジニアリング (Prompt Engineering)」 です。
ChatGPTのAPIでゼロから対話用魔法陣を構築
ここまでの予備知識あれば、以下にOpenAIの公式APIでPromptの運用段階に進めできます。ChatGPTにはAPIが用意されており、上記のChatGPT Web画面でプログラムの生成作業はAPIを通じて裏に行うことができます。
例えば:
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Pythonで時刻を知らせるプログラムを書いてください"},
]
)
特に問題ありませんね。
次に、API経由でPandasを操作するプログラムを作成してみましょう。
ここで、ChatGPTは主に英語で訓練されており、生成される内容の精度を高めるためにPromptを英語で記述しています。また、結果に余計な情報を含まないようAIにお願いしました。
from openai import OpenAI
client = OpenAI()
prompt = """
Now you act as a professional data scientist using Pandas in Python.
I will show you the dataframe info and some sample data, and tell you a task.
You need to write python code for me, write it as a function starting with this:
def deal_with_data(dataframe):
...
You only need to write the function itself, and answer me with the content of the function.
### dataframe info ###
"student_id" - string
"score" - int
### sample data in dataframe ###
student_id score
0 1000 50
1 1001 60
### task ###
平均点を計算する関数を書いてください
"""
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": prompt},
]
)
print(response.choices[0].message.content)
Python関数のソースコードが1つだけ生成されていました、良い結果です。
ChatGPT APIの出力である response.choices[0].message.content はMarkdown形式のようですので、後でPython関数をスムーズに構築するために、ここで少し文字列の前処理が必要になります。
ret_message = response.choices[0].message.content
ret_func_text = ret_message[ret_message.find("def deal_with_data(dataframe):"):].strip('`')
ここまで、純粋なPython関数のソースコードをstringの形で取得できました。次にこのソースコード のstring の形に基づいて動的Python関数を構築します:
func_obj = compile(ret_func_text, '<string>', 'exec')
new_func = types.FunctionType(func_obj.co_consts[0], globals())
ChatGPTから生成されたDataFrame操作用関数のソースコードから、最終的に本物の関数 new_func に完成しました。
試してみましょう:
sample_data = {
"student_id" : ["1000", "1001"],
"score" : [50, 60]
}
df = pd.DataFrame(sample_data)
new_func(df)
動きます。
成功まであと一歩、 皆さんお気づきかもしれませんが、上記API利用するときのPromptの内で、DataFrameに対する抽象的な説明はハードコーディングされていますが、この情報は自動で取得できますか?
いくつかの試みの後、ここで df.info() と print(df) の内容が一番適切であることがわかりました。
df.info()は余計な情報ありますが、AIは臨機応変できますので、問題ありませんでしょう。
ようやく準備条件が揃いました、すべての流れをまとめます:
def chat_with_df(df, chat_message):
prompt_template = """
Now you act as a professional data scientist using Pandas in Python.
I will show you the dataframe info and some sample data, and tell you a task.
You need to write python code for me, write it as a function starting with this:
def deal_with_data(dataframe):
...
You only need to write the function itself, and answer me with the content of the function.
"""
# df.info()の内容を文字列化するトリック
_iobuf = io.StringIO()
df.info(buf=_iobuf)
dataframe_info = _iobuf.getvalue()
# dfの最初の一件目データの内容サンプルとして文字列化するトリック
dataframe_sample = str(df.head(1))
dataframe_task = chat_message
prompt_template += "\n### dataframe info ###\n" + dataframe_info + "\n"
prompt_template += "\n### sample data in dataframe ###\n" + dataframe_sample + "\n"
prompt_template += "\n### task ###\n" + dataframe_task + "\n"
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": prompt_template},
]
)
ret_message = response.choices[0].message.content
ret_func_text = ret_message[ret_message.find("def deal_with_data(dataframe):"):].strip('`')
func_obj = compile(ret_func_text, '<string>', 'exec')
new_func = types.FunctionType(func_obj.co_consts[0], globals())
return new_func(df)
試してみましょう:
まず、ダミーデータのCSV students.csv を作成します:
student_id,score
1001,100
1002,80
1003,60
1004,70
1005,99
次はいよいよFireDucksと会話する時間です:
import fireducks.pandas as pd
df = pd.read_csv('students.csv')
# FireDucksのDataFrameと自然会話します:
chat_with_df(df, "平均得点の計算お願い")
chat_with_df(df, "得点は85以上100まではAランク、75以上85まではBランク、他はCランクです")
chat_with_df(df, "学生IDはSを先頭に追加する")
結果は
更に、会話関数chat_with_dfの戻り値はにより、通常どおりプログラミングを続行できます:
group_df = chat_with_df(df, "ランクでグループする")
print(type(group_df))
group_df.size()
これは素晴らしいですね!われわれが一歩一歩ゼロからDIYしたAI魔法陣で、人間とFireDucks 🔥🐤が会話できるようになりました。
その他の実現方法
同じアイデアの実装は他にもあります。たとえば、有名なPandasAIです。
PandasAIの内部実装方法はわれわれ上のDIY方法とは若干異なり、個人的にはPandasAIの方が余計な部分が多くと感じています。興味ある方、ソースコードを比較して見でください。
また、公式によると、現時点ではPandasAIはネイティブのPandasとModinのみをサポートしています。
だが、万能なFireDucksには裏技があります。FireDucksのDataFrameの.to_pandas()メソッドを使えば、PandasAIで利用できます。
SmartDataFrame(df.to_pandas(), config={"llm": llm})
Webアプリケーションにパッケージする方法
せっかくFireDucksと直接会話できるツールができたので、それを他の人とに共有できればさらに良いですね。
ここで、最近人気な機械学習専用のUIフレームワーク Gradio で、簡単に🔥🐤チャット用アプリケーションを作成できます。
#...
with gr.Blocks() as demo:
with gr.Row():
table = gr.Dataframe(label="FireDucks 🔥🐤")
with gr.Row():
status_textbox = gr.Textbox(label="🔥🐤の答え")
with gr.Row():
upload_button = gr.UploadButton(label="アップロード CSV", file_types = ['.csv'], file_count = "single")
reset_btn = gr.Button("リセット")
with gr.Row():
with gr.Column(scale=8):
chat_message = gr.Textbox(label="チャットメッセージ")
with gr.Column(scale=2):
chat_btn = gr.Button("🔥🐤とチャット")
clear_btn = gr.Button("クリア")
upload_button.upload(fn=upload_csv_to_df, inputs=upload_button, outputs=table, api_name="upload_csv")
chat_btn.click(fn=chat_df, inputs=[table, chat_message], outputs=[table, status_textbox], api_name="chat")
reset_btn.click(fn=reset_df,outputs=table, api_name="reset")
clear_btn.click(fn=clear_chat, outputs=[chat_message, status_textbox])
demo.launch(debug=True)
その様子は
さすがFireDucks🔥🐤ですね。 優れた交換性と拡張性を備えており、AIと組み合わせるだけで、すぐに素晴らしいアプリケーションになりました。