質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.78%

pythonのlistやtapleについてです。

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 188

score 6

トーナメントのようなアルゴリズムを実装したいのですが、リストやタプルの理解が浅くうまくいきません。
for文の範囲が間違っていると思うのですが、うまくいきません。
どうしたらよいのでしょうか。
<試したこと>
for i in range(0,len(tournament)-1,tour_num):
と変更したが同じエラーのままで、
for i in range(0,len(tournament)-2,tour_num):
としたところ、結果が表示されない。

<変数>
len(tournament) = 10
tour_num = 2
です。

def select(eva):
    tournament = [()]
    tournament.append(random.shuffle(eva))
    while len(tournament) > 1:
        if len(tournament) % 2 != 0:
            for i in range(1,len(tournament),tour_num):
                if tournament[i][0] < tournament[i+1][0]:
                    del tournament[i][0]
                else:
                    del tournament[i+1][0]
        else:
            for i in range(0,len(tournament),tour_num):
                if tournament[i][0] < tournament[i+1][0]:
                    del tournament[i][0]
                else:
                    del tournament[i+1][0]

    return tournament

エラー

38         else:
39             for i in range(0,len(tournament),tour_num):
---> 40                 if tournament[i][0] < tournament[i+1][0]:
41                     del tournament[i][0]
42                 else:

IndexError: tuple index out of range

全体のコードも載せておきます。

import random
import copy

random.seed(1870258)
gene_length = 10
# 遺伝子長
individual_length = 10 # 個体数
generation = 30 # 世代数
tour_num = 2  #トーナメント数

#二次元配列で遺伝子長と個体数を表現
def get_population():
    population = []
    for i in range(individual_length):  #遺伝子長
        population.append([random.randint(0,1) for j in range(gene_length)])  #個体数
    return population

#適応度
def fitness(pop):
    return sum(pop)

#評価
def evaluate(pop):
    pop.sort(reverse=True)
    return pop

#tトーナメント選択(次世代個体生成)
def select(eva):
    tournament = [()]
    tournament.append(random.shuffle(eva))
    while len(tournament) > 1:
        if len(tournament) % 2 != 0:
            for i in range(1,len(tournament),tour_num):
                if tournament[i][0] < tournament[i+1][0]:
                    del tournament[i][0]
                else:
                    del tournament[i+1][0]
        else:
            for i in range(0,len(tournament),tour_num):
                if tournament[i][0] < tournament[i+1][0]:
                    del tournament[i][0]
                else:
                    del tournament[i+1][0]

    return tournament


#一点交叉
def one_point_crossover(parent1, parent2):
    r1 = random.randint(0, gene_length-1)
    child1 = copy.deepcopy(parent1)
    child2 = copy.deepcopy(parent2)
    child1[r1:gene_length-1] = parent2[r1:gene_length-1]
    child2[r1:gene_length-1] = parent1[r1:gene_length-1]
    return child1,child2


def main():
    # 初期個体生成
    pop = evaluate([(fitness(p), p) for p in get_population()])
    print('Generation: 0')
    print('Min : {}'.format(pop[-1][0]))
    print('Max : {}'.format(pop[0][0]))
    print('--------------------------')

    for g in range(generation):
        if 10 != pop[0][0] or 10 != pop[-1][0]:

            g += 1
            print('Generation: ' + str(g))


            eva = evaluate(pop) 
            tournament = select(eva) 
            pop = tournament

            while len(pop) < individual_length:  
                m1 = random.randint(0, len(tournament)-1)  
                m2 = random.randint(0, len(tournament)-1)
                child1,child2 = one_point_crossover(tournament[m1][1], tournament[m2][1])    
                pop.append((fitness(child1), child1)) 
                pop.append((fitness(child2), child2))

            print('Min : {}'.format(pop[-1][0]),'  Result : {}'.format(pop[-1]))
            print('Max : {}'.format(pop[0][0]),'  Result : {}'.format(pop[0]))
            print('--------------------------')
        else:
            break



    print('\n--------------------------End of evolution--------------------------')
    print('Generation: ' + str(g))
    print('Min : {}'.format(pop[-1][0]),'  Result : {}'.format(pop[-1]))
    print('Max : {}'.format(pop[0][0]),'  Result : {}'.format(pop[0]))



if __name__ == '__main__':
    main()
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • BeatStar

    2021/07/23 08:41

    デバッグぐらいはしましょう。
    プログラミングは『書いて終わり』ではありません。
    デバッグは必須の技術です。

    キャンセル

回答 2

checkベストアンサー

+1

簡単な例で示します。

a = [[1, 2], [3, 4], [5, 6]]

for i in range(len(a)):
    print(a[i+1])
# [3, 4]
# [5, 6]
# IndexError: list index out of range


1回目のループでa[1]の中身が表示されます。2回目のループでa[2]の中身が表示されます。3回目のループでa[3]を表示しようとしてIndexError: list index out of rangeが発生します。

対処法としては下記などがあります。

a = [[1, 2], [3, 4], [5, 6]]

for i in range(len(a)-1):
    print(a[i+1])
# [3, 4]
# [5, 6]

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/07/23 20:14

    原因がわかりました。
    i+1ではなく、
    tournament = [()]
    random.shuffle(eva)
    の部分っぽいです。
    ありがとうございました。

    キャンセル

  • 2021/07/23 21:49

    本当ですね。確認したところ、tournament[0]の中身が()ですね。そのためtournament[i][0]の[0]でIndexError発生ですね。

    キャンセル

  • 2021/07/23 22:55

    色々ご迷惑かけてすいません。
    ありがとうございました🙇‍♂️🙇‍♂️

    キャンセル

+1

IndexError: tuple index out of range 

要するに、範囲を超えてるってことです。
tournamentになにが入ってて、iはどうなってるのかチェックしよう

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/07/23 14:56

    回答ありがとうございます。
    範囲というのは、タプルの範囲でしょうか。それとも、for文の終了条件の範囲でしょうか。
    タプルの範囲を超えないように変更しても同じエラーが起きるので教えていただけると幸いです。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.78%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る