質問
オライリージャパン『集合知プログラミング』11章のサンプルコードがうまく実行できません。
遺伝的プログラミングを使って得られたランダムな座標から関数を同定するプログラムを組んでいます。
関数を500個作成後、それぞれの関数のスコアを算出し要素数500のリストを作ったのですが、そのスコアのリストをソートすることができずに困っています。
どなたかご教授お願いいたします。
再質問
エラーを取り除くことができましたが、原因を知りたいのでご教授下さい。
scoresがタプルのリストになっていたのでrankfunction関数(176行目)の
scores.sort(key = lambda x: x[0])
とするとエラーを解消することができましたが、これはタプル型のどの要素でソートするかを明示していなかったためエラーが出ていたという解釈でよろしいでしょうか。
実現したいこと
スコアのリストをソートする際のエラーを解消したい。
発生している問題・エラーメッセージ
Traceback (most recent call last): File "g:\M1\code\gp\sample_gp.py", line 198, in <module> print(evolve(2, 500, rf, mutationrate=0.2, breedingrate=0.1, pexp=0.7, pnew=0.1)) File "g:\M1\code\gp\sample_gp.py", line 152, in evolve scores = rankfunction(population) File "g:\M1\code\gp\sample_gp.py", line 175, in rankfunction scores.sort() TypeError: '<' not supported between instances of 'node' and 'constnode'
該当のソースコード
python
1from random import random, randint, choice 2from copy import deepcopy 3from math import log 4 5class fwrapper: 6 def __init__(self, function, childcount, name): 7 self.function = function 8 self.childcount = childcount 9 self.name = name 10 11# ノードのクラス 12class node: 13 def __init__(self, fw, children): 14 self.function = fw.function 15 self.name = fw.name 16 self.children = children 17 18 def evaluate(self, inp): 19 results = [n.evaluate(inp) for n in self.children] 20 return self.function(results) 21 22 def display(self, indent=0): 23 print(' '*indent + self.name) 24 for c in self.children: 25 c.display(indent+1) 26 27# 変数ノードのクラス 28class paramnode: 29 def __init__(self, idx): 30 self.idx = idx 31 32 def evaluate(self, inp): 33 return inp[self.idx] 34 35 def display(self, indent=0): 36 print('{}p{}'.format(' '*indent, self.idx)) 37 38# 定数ノードのクラス 39class constnode: 40 def __init__(self, v): 41 self.v = v 42 43 def evaluate(self, inp): 44 return self.v 45 46 def display(self, indent=0): 47 print('{}{}'.format(' '*indent, self.v)) 48 49addw = fwrapper(lambda l: l[0] + l[1], 2, 'add') 50subw = fwrapper(lambda l: l[0] - l[1], 2, 'subtract') 51mulw = fwrapper(lambda l: l[0] * l[1], 2, 'multiply') 52 53def iffunc(l): 54 if l[0] > 0: 55 return l[1] 56 else: 57 return l[2] 58 59ifw = fwrapper(iffunc, 3, 'if') 60 61def isgreater(l): 62 if l[0] > l[1]: 63 return 1 64 else: 65 return 0 66 67gtw = fwrapper(isgreater, 2, 'isgreater') 68flist = [addw, mulw, ifw, gtw, subw] 69 70def exampletree(): 71 return node(ifw, [ 72 node(gtw, [paramnode(0), constnode(3)]), 73 node(addw, [paramnode(1), constnode(5)]), 74 node(subw, [paramnode(1), constnode(2)]) 75 ]) 76 77# 最初の集団をランダムに作成 78def makerandomtree(pc, maxdepth=4, fpr=0.5, ppr=0.6): # pc: 入力変数の数 79 if random() < fpr and maxdepth > 0: 80 f = choice(flist) 81 children = [makerandomtree(pc, maxdepth-1, fpr, ppr) for i in range(f.childcount)] 82 return node(f, children) 83 elif random() < ppr: 84 return paramnode(randint(0, pc-1)) 85 else: 86 return constnode(randint(0, 10)) 87 88def hiddenfunction(x, y): 89 return x**2 + 2*y + 3*x + 5 90 91def buildhiddenset(): 92 rows = [] 93 for i in range(200): 94 x = randint(0, 40) 95 y = randint(0, 40) 96 rows.append([x, y, hiddenfunction(x, y)]) 97 return rows 98 99def scorefunction(tree, s): 100 dif = 0 101 for data in s: 102 v = tree.evaluate([data[0], data[1]]) 103 dif += abs(v-data[2]) 104 return dif 105 106# 突然変異 107def mutate(t, pc, probchange=0.1): 108 # 部分木を突然変異させる 109 if random() < probchange: 110 return makerandomtree(pc) 111 # 突然変異させる部分木を決定する(木に潜っていく) 112 else: 113 result = deepcopy(t) 114 if hasattr(t, "children"): 115 result.children = [mutate(c, pc, probchange) for c in t.children] 116 return result 117 118# 交叉(t1とt2同時に潜っていく) 119def crossover(t1, t2, probswap=0.7, top=1): 120 if random() < probswap and not top: 121 return deepcopy(t2) 122 else: 123 result = deepcopy(t1) 124 if hasattr(t1, 'children') and hasattr(t2, 'children'): 125 result.children = [crossover(c, choice(t2.children), probswap, 0) for c in t1.children] 126 return result 127 128def evolve(pc, popsize, rankfunction, maxgen=500, mutationrate=0.1, breedingrate=0.4, pexp=0.7, pnew=0.05): 129 """_summary_ 130 131 Args: 132 pc (_type_): _description_ 133 popsize (_type_): 初期集団のサイズ. 134 rankfunction (_type_): プログラムのリストに対して用いられ、ベストからワーストの順にランク付けする関数 135 maxgen (int, optional): _description_. Defaults to 500. 136 mutationrate (float, optional): 突然変異を起こす確率. mutateに渡される. Defaults to 0.1. 137 breedingrate (float, optional): 交叉を行う確率. crossoverに渡される. Defaults to 0.4. 138 pexp (float, optional): ランクの低いプログラムが選ばれない確率. 値が高ければ高いほど,選択は厳格なものとなり,ランクの高いもののみが複製のために選ばれるようになる. Defaults to 0.7. 139 pnew (float, optional): 新たな集団を作るとき,完全に新しいランダムなプログラムが作られる確率. Defaults to 0.05. 140 141 Returns: 142 _type_: _description_ 143 """ 144 145 # ランダムな低い数値を返す。pexpが低ければ低いほど得られる数値は小さくなる 146 def selectindex(): 147 return int(log(random())/log(pexp)) 148 149 # 初期集団をランダムに作り上げる 150 population = [makerandomtree(pc) for i in range(popsize)] 151 for i in range(maxgen): 152 scores = rankfunction(population) 153 print(scores[0][0]) 154 if scores[0][0] == 0: break 155 156 # 上位2つは無条件に採用 157 newpop = [scores[0][1], scores[1][1]] 158 159 # 次世代を作る 160 while len(newpop) < popsize: 161 if random() > pnew: 162 newpop.append(mutate(crossover(scores[selectindex()][1], scores[selectindex()][1], probswap=breedingrate), pc, probchange=mutationrate)) 163 else: 164 # ランダムなノードを混ぜる 165 newpop.append(makerandomtree(pc)) 166 167 population=newpop 168 scores[0][1].display() 169 return scores[0][1] 170 171# データセットのランキングを行う関数を返す 172def getrankfunction(dataset): 173 def rankfunction(population): 174 scores = [(scorefunction(t, dataset), t) for t in population] 175 scores.sort() 176 return scores 177 return rankfunction 178 179rf = getrankfunction(buildhiddenset()) 180print(evolve(2, 500, rf, mutationrate=0.2, breedingrate=0.1, pexp=0.7, pnew=0.1))