見出し画像

ChatGPTを使って日本語でプログラミングしてみる

はじめに

今、ChatGPTが非常にホットなAI技術として注目されています。そこで、新しい用途の一つとして、「日本語でプログラミングするためのツール」としてのChatGPTの活用例を考えてみました。
ところで、ChatGPTはAIのくせに簡単な算数を間違えることが指摘されています。

[Query]
次の計算をしなさい。
1.1+2+1234500
2.1*20*321
3.100/2+200/5
[Answer by ChatGPT]
1.1234501
2.128400
3.350

AIのくせに計算機が最も得意であるはずの四則演算を間違えるとは不届きですね。

①年号を西暦に直させてみる

役所や学校に提出する書類は基本年号で記載しなければいけないため、毎回、令和〇年って西暦何年だっけ?と悩むことはありませんか?そこで、年号を西暦に関する関数を作らせてみましょう。

[Query]
日本の年号で、昭和x年、平成x年、令和x年と入力されたら、
西暦y年へと変換する関数nengo_to_yearを定義しPythonコードを示しなさい。
[Answer by ChatGPT]
def nengo_to_year(nengo):
    if nengo[0] == '昭和':
        year = 1925 + int(nengo[1:])
    elif nengo[0] == '平成':
        year = 1988 + int(nengo[1:])
    elif nengo[0] == '令和':
        year = 2018 + int(nengo[1:])
    else:
        year = 0
    return year

# 使用例
print(nengo_to_year('昭和30年'))  # 1955
print(nengo_to_year('平成12年'))  # 2000
print(nengo_to_year('令和2年'))  # 2020

惜しいですね。年号と年数を配列で与えられているものという前提の関数のようですが、使用例はそうなっていません。

[Query]
次のような文字列が入力されたら、正規表現を使って年号と数字を別々の配列に格納する関数を
定義しPythonコードを示しなさい。
昭和50年、平成3年、令和4年
[Answer by ChatGPT]
def separate_year_number(input_str):
    # 正規表現を使って年号と数字を別々の配列に格納する関数
    import re
    year_list = []
    number_list = []
    # 正規表現で年号と数字を取得
    pattern = re.compile(r'(昭和|平成|令和)(\d+)年')
    matches = pattern.finditer(input_str)
    # 年号と数字を別々の配列に格納
    for match in matches:
        year_list.append(match.group(1))
        number_list.append(match.group(2))
    return year_list, number_list

# 入力文字列
input_str = '昭和50年、平成3年、令和4年'
# 関数を実行
year_list, number_list = separate_year_number(input_str)
# 結果を表示
print(year_list) # ['昭和', '平成', '令和']
print(number_list) # ['50', '3', '4']

なかなか優秀ですね。最後にこれらの関数を繋げて微調整し、完成版を作りました。

"""
完成版: 年号を西暦に変換
"""
import re

def nengo_to_year(nengo):
    if nengo[0] == '昭和':
        year = 1925 + int(nengo[1])
    elif nengo[0] == '平成':
        year = 1988 + int(nengo[1])
    elif nengo[0] == '令和':
        year = 2018 + int(nengo[1])
    else:
        year = 0
    return year

def separate_year_number(input_str):
    # 正規表現を使って年号と数字を別々の配列に格納する関数
    import re
    year_list = []
    number_list = []
    # 正規表現で年号と数字を取得
    pattern = re.compile(r'(昭和|平成|令和)(\d+)年')
    matches = pattern.finditer(input_str)
    # 年号と数字を別々の配列に格納
    for match in matches:
        year_list.append(match.group(1))
        number_list.append(match.group(2))
    return year_list, number_list

years, numbers = separate_year_number('昭和50年、平成3年、令和4年')
for year, number in zip(years, numbers):
    print(nengo_to_year([year]+[number]))
    
"""出力
1975
1991
2022
"""

②クイックソートをさせてみる

まずは、ChatGPT君の素のソートの実力を見てみましょう。

[Query]
次の数字を昇順に並べ替えなさい。
1,2,30000,1020,80,7,4,6,500,9
[Answer by ChatGPT]
4, 6, 7, 80, 500, 9, 1020, 1, 2, 30000

うーん。ポンコツですねぇ。
そこで、ソートとは何ぞやを叩き込んであげましょう。

[Query]
次にステップを実行するPythonコードを示しなさい。
1.配列xの最初の要素をa、残りの要素をbとする。
2.配列bのうちaより小さいものを配列左に、それ以外のものを配列右に格納する。
3.配列xを受け取り、配列左、a、配列右を返す関数をsplit_xと定義する。
4.配列xを受け取り、left,a,right = split_x(x)を実行した後、
sort(left)、a、sort(right)を結合した配列を返す関数をsortと定義する。
5.上記の関数sortを配列x=[1,2,30000,1020,80,7,4,6,500,9]に対して実行する。
[Answer by ChatGPT]
def split_x(x):
    a = x[0]
    b = x[1:]
    left = []
    right = []
    for i in b:
        if i < a:
            left.append(i)
        else:
            right.append(i)
    return left, a, right

def sort(x):
    left, a, right = split_x(x)
    left = sorted(left)
    right = sorted(right)
    return left + [a] + right

x = [1,2,30000,1020,80,7,4,6,500,9]

print(sort(x))

"""出力
[1, 2, 4, 6, 7, 9, 80, 500, 1020, 30000]
"""

素晴らしいですね。大学生のプログラミングのテストなら満点でしょう。

③動的計画法で最短経路を求めさせてみる

もう少し難しめの課題を出してみましょう。まずは、問題の定義です。

[Query]
次にステップを実行するPythonコードを示しなさい。
1.次のペアの駅名と列車の所要時間を辞書で定義する。
(大宮、新宿)、(大宮、西国分寺)、(西国分寺、新宿)、(新宿、川崎)、(西国分寺、川崎)
2.駅名xが与えられたら、1の辞書に含まれるxでない方の駅名と所要時間の辞書を作成し返す。
3.上記1と2を実行する関数をstation_x(x)と定義する。
[Answer by ChatGPT]
# 1. 次のペアの駅名と列車の所要時間を辞書で定義する
station_time = {("大宮", "新宿"): 25, ("大宮", "西国分寺"): 15, ("西国分寺", "新宿"): 20, ("新宿", "川崎"): 30, ("西国分寺", "川崎"): 25}

# 2. 駅名xが与えられたら、1の辞書に含まれるxでない方の駅名と所要時間の辞書を作成し返す
def get_other_station(x):
    other_station_time = {}
    for key, value in station_time.items():
        if x in key:
            other_station = list(key)
            other_station.remove(x)
            other_station_time[tuple(other_station)] = value
    return other_station_time

# 3. 上記1と2を実行する関数をstation_x(x)と定義する
def station_x(x):
    return get_other_station(x)

ステップ2とステップ3は重複してますね。また、辞書のキーをtupleにする必要はありません。ステップ1は合っているかどうかは分かりませんが、それっぽいですね。変数名が適切に設定されている点もポイントが高いです。
次に、駅間の最短経路を求める関数を定義しましょう。ただし、ここでは乗り換えなしで行ける駅間の所要時間は最短であると仮定します。(巡回する場合を避けるため。)

[Query]
次にステップを実行するPythonコードを示しなさい。
1.駅名xが与えられたら、駅名と所要時間の辞書を返す関数station_xを実行する。
2.1の辞書に駅名yが含まれていれば駅名yの所要時間を返す。
3.1の辞書に駅名yが含まれていなければ
辞書に含まれる各駅zの所要時間とfind_route(z,y)の実行結果を足した結果のうち最小値を返す。
4.上記1~3を実行する関数をfind_route(x,y)と定義する。
[Answer by ChatGPT]
def find_route(x, y):
    station_x = station_x(x)
    if y in station_x:
        return station_x[y]
    else:
        min_time = float("inf")
        for z in station_x:
            min_time = min(min_time, station_x[z] + find_route(z, y))
        return min_time

station_xの戻り値と関数名が重複してしまっていますね。これはバグになります。
上記のコードを修正して、駅間の最短経路を求める関数の完成版を作りました。駅の辞書を充実させれば、もっと実用的に使えるでしょう。

"""
完成版: 駅間最短ルート検索
"""
# 1. 次のペアの駅名と列車の所要時間を辞書で定義する
station_time = {("大宮", "新宿"): 25, ("大宮", "西国分寺"): 15, ("西国分寺", "新宿"): 20, ("新宿", "川崎"): 30, ("西国分寺", "川崎"): 25}

# 2. 駅名xが与えられたら、1の辞書に含まれるxでない方の駅名と所要時間の辞書を作成し返す
def get_other_station(x):
    other_station_time = {}
    for key, value in station_time.items():
        if x in key:
            other_station = list(key)
            other_station.remove(x)
            other_station_time[other_station[0]] = value
    return other_station_time

# 3. 上記1と2を実行する関数をstation_x(x)と定義する
def station_x(x):
    return get_other_station(x)

def find_route(x, y):
    cand_x = station_x(x)
    if y in cand_x:
        return cand_x[y]
    else:
        min_time = float("inf")
        for z in cand_x:
            xtoz = cand_x[z] + find_route(z, y)
            if xtoz < min_time:
                min_time = xtoz
                min_z = z
        print(f"x: {x} to y:{y} via z:{min_z} is {min_time}")
        return min_time
##
find_route('川崎','大宮')

"""出力
x: 川崎 to y:大宮 via z:西国分寺 is 40
"""

ちゃんと川崎⇒新宿⇒大宮ルート(所要時間55)ではなく、川崎⇒西国分寺⇒大宮ルート(所要時間40)が選択されていますね。

おわりに

以上のように、ChaptGPT自身は計算が苦手であるもののプログラミングが大変得意であるという特徴が垣間見えました。この特性を使って、ChaptGPTに計算をさせるにはプログラミング言語を経由させると良さそうです。

[Query]
与えられた数式文字列を計算するPythonの関数calcを定義しなさい。
定義したcalcに次の数式を入力し実行した結果を出力しなさい。
1.1+2+1234500
2.1*20*321
3.100/2+200/5
[Answer by ChatGPT]
以下が解答例です。

def calc(expression):
  return eval(expression)

print(calc('1+2+1234500')) # 1234503
print(calc('1*20*321')) # 6420
print(calc('100/2+200/5')) # 140

多少はましになるようですね。何故か3問目を間違えてますが!!
おそらくChatGPTの内部にPythonインタプリタを内蔵しているのではないかと思いますが、それでも結果を間違えるのは謎です。
もしかしたら、ソースコードを学習した結果、Pythonインタプリタの”振る舞い”を獲得しているのでしょうか?だとしたら末恐ろしいですが…。

プログラミング言語ももちろん言語の一種なので、言語モデルの学習対象になっていることは当然予想されます。
今後は、日本語のような自然言語とプログラミング言語との間を、日本語と外国語との翻訳のように繋いでいく懸け橋の役割をChatGPTが担っていくのではないでしょうか。

#ChatGPT #AI #Python #プログラミング


この記事が気に入ったらサポートをしてみませんか?