ChatGPT は GitHub Coplilot よりもヒントのないところからそれっぽくソースコードを生成することが得意な印象です。この記事では、KDE(kernel density estimation カーネル密度推定)についてのいい感じの図とふんわりとした指示で ChatGPT が作図する Pythonのコードをどう生成するかを紹介します。
具体的なコード生成の会話ログが次です。中身を見ると分かりますが、きちんとしているのは最初に関数のインタフェースと説明を渡したのみで後は端的にあれして欲しい、これして欲しいの連続です。これでも小さなスクリプトなり単体で完結した関数なりなら割としっかりしたものを作ってくれます。
Plotting Multi-modal Distributions
テキスト版会話ログ
Model: GPT-4
—USER—
次のプログラムを完成させてください def plot\_multi\_modal(arr: ndarray) -> None: “”” 多峰性分布をいい感じに表示する関数。 KDEを使う “””
ChatGPTChatGPT
—ChatGPT—
あなたのプロジェクトにおいてどのようにデータをプロットしたいのかによりますが、ここに一般的なガイドラインを示すPython関数を示しています。これは多峰性分布を表示するための関数で、Kernel Density Estimation (KDE) を使用します。以下は、SciPyとMatplotlibを使用した一例です。
このコードは、与えられた多次元のNumPy配列のKDEを計算し、それをプロットします。
pythonCopy code
`import numpy as np from scipy.stats import gaussian_kde import matplotlib.pyplot as plt def plot_multi_modal(arr: np.ndarray) -> None: “”” 多峰性分布をいい感じに表示する関数。 KDEを使う “”” # Kernel Density Estimationを計算 density = gaussian_kde(arr) # 確率密度関数の描画範囲を設定 xs = np.linspace(np.min(arr), np.max(arr), 200) # 確率密度関数を計算 density.covariance_factor = lambda : .25 density._compute_covariance() ys = density(xs) # プロット plt.figure(figsize=(10, 6)) plt.plot(xs, ys, label=’KDE’) plt.title(‘Kernel Density Estimation’) plt.xlabel(‘Value’) plt.ylabel(‘Density’) plt.grid(True) plt.legend() plt.show()`
注意点として、このコードは1次元配列に対してしか動作しないということが挙げられます。また、KDEのバンド幅を固定的に設定しています(`density.covariance_factor = lambda : .25`)。この値は、データによって最適な値が異なりますので、データを確認しながら調整することを推奨します。
また、このプログラムは密度推定にGaussian KDEを使っていますが、必要に応じて他の密度推定法を使用することもできます。
—USER—
元データのヒストグラムも重ねて描画できるようにしてください
ChatGPTChatGPT
—ChatGPT—
もちろんです、元データのヒストグラムを重ねて描画するために、以下のように関数を修正します:
pythonCopy code
`import numpy as np from scipy.stats import gaussian_kde import matplotlib.pyplot as plt def plot_multi_modal(arr: np.ndarray) -> None: “”” 多峰性分布をいい感じに表示する関数。 KDEを使う “”” # Kernel Density Estimationを計算 density = gaussian_kde(arr) # 確率密度関数の描画範囲を設定 xs = np.linspace(np.min(arr), np.max(arr), 200) # 確率密度関数を計算 density.covariance_factor = lambda : .25 density._compute_covariance() ys = density(xs) # プロット plt.figure(figsize=(10, 6)) # KDEをプロット plt.plot(xs, ys, label=’KDE’) # データのヒストグラムをプロット plt.hist(arr, density=True, alpha=0.5, bins=30, label=’Data’) plt.title(‘Kernel Density Estimation’) plt.xlabel(‘Value’) plt.ylabel(‘Density’) plt.grid(True) plt.legend() plt.show()`
`plt.hist`関数を追加することで、元データのヒストグラムをプロットできます。ここでは`density=True`オプションを使用して、ヒストグラムを正規化(合計が1になるように)しています。これにより、KDEとヒストグラムが同じスケールで比較できます。また、`alpha=0.5`はヒストグラムの透明度を設定し、`bins=30`はヒストグラムの棒の数を設定します。これらのパラメータは、データにより適切な値を設定してください。
—USER—
山の頂点も見えるようにしてください
ChatGPTChatGPT
—ChatGPT—
山の頂点(ピーク)を見つけてプロットするには、一般的には導関数(グラフの傾き)がゼロになる点を見つけることでピークを探します。これを実現するために、SciPyの`argrelextrema`関数を使います。以下に、ピークを探してプロットするコードを示します。
pythonCopy code
`import numpy as np from scipy.stats import gaussian_kde from scipy.signal import argrelextrema import matplotlib.pyplot as plt def plot_multi_modal(arr: np.ndarray) -> None: “”” 多峰性分布をいい感じに表示する関数。 KDEを使う “”” # Kernel Density Estimationを計算 density = gaussian_kde(arr) # 確率密度関数の描画範囲を設定 xs = np.linspace(np.min(arr), np.max(arr), 200) # 確率密度関数を計算 density.covariance_factor = lambda : .25 density._compute_covariance() ys = density(xs) # プロット plt.figure(figsize=(10, 6)) # KDEをプロット plt.plot(xs, ys, label=’KDE’) # データのヒストグラムをプロット plt.hist(arr, density=True, alpha=0.5, bins=30, label=’Data’) # 山の頂点(極大値)を見つける maxima = argrelextrema(ys, np.greater) plt.plot(xs[maxima], ys[maxima], ‘ro’, label=’Peaks’) plt.title(‘Kernel Density Estimation’) plt.xlabel(‘Value’) plt.ylabel(‘Density’) plt.grid(True) plt.legend() plt.show()`
このコードでは、`argrelextrema`関数を使って`ys`の極大値(ピーク)を見つけています。その後、見つけたピークを赤色の点(’ro’)としてプロットしています。
なお、`argrelextrema`は単純な比較による極大値検出を行うため、ノイズが多いデータでは多数の極大値を検出する可能性があります。データによっては、更なる平滑化やピーク検出の方法を検討する必要があるかもしれません。
—USER—
より細かくデータを表示してください
ChatGPTChatGPT
—ChatGPT—
描画範囲やビンの数、ピーク検出の精度を増やすことで、より細かくデータを表示できます。以下に、いくつかのパラメータを調整した関数を示します。
pythonCopy code
`import numpy as np from scipy.stats import gaussian_kde from scipy.signal import argrelextrema import matplotlib.pyplot as plt def plot_multi_modal(arr: np.ndarray) -> None: “”” 多峰性分布をいい感じに表示する関数。 KDEを使う “”” # Kernel Density Estimationを計算 density = gaussian_kde(arr) # 確率密度関数の描画範囲を設定 xs = np.linspace(np.min(arr), np.max(arr), 1000) # 点の数を増やして細かさを増やす # 確率密度関数を計算 density.covariance_factor = lambda : .25 density._compute_covariance() ys = density(xs) # プロット plt.figure(figsize=(10, 6)) # KDEをプロット plt.plot(xs, ys, label=’KDE’) # データのヒストグラムをプロット plt.hist(arr, density=True, alpha=0.5, bins=100, label=’Data’) # ビンの数を増やして細かさを増やす # 山の頂点(極大値)を見つける maxima = argrelextrema(ys, np.greater) plt.plot(xs[maxima], ys[maxima], ‘ro’, label=’Peaks’) plt.title(‘Kernel Density Estimation’) plt.xlabel(‘Value’) plt.ylabel(‘Density’) plt.grid(True) plt.legend() plt.show()`
このコードでは、描画する点の数とヒストグラムのビンの数を増やしました。それにより、より細かな分布が視覚化されます。しかし、これらのパラメータはデータによって最適な値が変わるため、実際のデータに基づいて調整する必要があります。
さらに、KDEのバンド幅パラメータやピーク検出の閾値などを調整することで、表示の細かさを更にコントロールすることも可能です。データの性質により最適な設定が変わりますので、これらのパラメータも調整することを検討してみてください。
ChatGPT may produce inaccurate information about people, places, or facts. [ChatGPT May 24 Version](https://help.openai.com/en/articles/6825453-chatgpt-release-notes)
できあがった関数と図の例が次です。ちゃんとした資料に使うならば各所のラベル名をもっときっちりしたりする必要があります。とはいえ労せずそれなりのものができました。
def plot_multi_modal(arr: np.ndarray) -> None: """ 多峰性分布をいい感じに表示する関数。 KDEを使う """ # Kernel Density Estimationを計算 density = gaussian_kde(arr) # 確率密度関数の描画範囲を設定 xs = np.linspace(np.min(arr), np.max(arr), 1000) # 点の数を増やして細かさを増やす # 確率密度関数を計算 density.covariance_factor = lambda : .25 density._compute_covariance() ys = density(xs) # プロット plt.figure(figsize=(10, 6)) # KDEをプロット plt.plot(xs, ys, label='KDE') # データのヒストグラムをプロット plt.hist(arr, density=True, alpha=0.5, bins=100, label='Data') # ビンの数を増やして細かさを増やす # 山の頂点(極大値)を見つける maxima = argrelextrema(ys, np.greater) plt.plot(xs[maxima], ys[maxima], 'ro', label='Peaks') plt.title('Kernel Density Estimation') plt.xlabel('Value') plt.ylabel('Density') plt.grid(True) plt.legend() plt.show()
似たプログラミング補助ツールとして GitHub Copilot があります。IDEとの連携は Copilot の方が優れており、普段のプログラミングの延長で恩恵を受けることができます。一方で ChatGPT ならではの特徴としてプログラムの大胆な書き直しが行われるという点があります。Copilot はどちらかというと予測変換や補完といった様な「ここに○○を付け足したい」という要望にうまく答えてくれますが ChatGPT はもっとざっくばらんに「今こんな感じだけど○○を追加して欲しい」といった要望に答えてくれます。会話ログにある様に後から要望を付け足してそれに対応してくれる感じです。コードの壊れやすさという観点もあり、うまいこと使い分けることでより快適にプログラミングができます。