如何在python中将多个字符定义为单个组?
from fuzzywuzzy import fuzz
import random
import string
chars = ["T1", "T2", "T3", "T4", "T5", "T6", "T7", "T8", "T9", "R1", "R2", "N1",
"N2", "G1", "G2", "G3", "H1", "H2", "H3", "K1", "K2", "K3", "K4", "D1",
"D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9"]
class Agent:
def __init__(self, length):
self.string = ' '.join(random.choice(chars) for _ in xrange(length))
self.fitness = -1
def __str__(self):
return 'String: ' + str(self.string) + ' Fitness: ' + str(self.fitness)
in_str = None
in_str_len = None
population = 20
generations = 10000
def ga():
agents = init_agents(population, in_str_len)
for generation in xrange(generations):
print 'Generation: ' + str(generation)
agents = fitness(agents)
agents = selection(agents)
agents = crossover(agents)
agents = mutation(agents)
if any(agent.fitness >= 100 for agent in agents):
print 'Threshold met!'
exit(0)
def init_agents(population, length):
return [Agent(length) for _ in xrange(population)]
def fitness(agents):
for agent in agents:
agent.fitness = fuzz.ratio(agent.string, in_str)
return agents
def selection(agents):
agents = sorted(agents, key=lambda agent: agent.fitness, reverse=True)
print '\n'.join(map(str, agents))
agents = agents[:int(0.2 * len(agents))]
return agents
def crossover(agents):
offspring = []
for _ in xrange((population - len(agents))/2):
parent1 = random.choice(agents)
parent2 = random.choice(agents)
child1 = Agent(in_str_len)
child2 = Agent(in_str_len)
split = random.randint(0, in_str_len)
child1.string = parent1.string[0:split] + parent2.string[split:in_str_len]
child2.string = parent2.string[0:split] + parent1.string[split:in_str_len]
offspring.append(child1)
offspring.append(child2)
agents.extend(offspring)
return agents
def mutation(agents):
for agent in agents:
for idx, param in enumerate(agent.string):
if random.uniform(0.0, 1.0) <= 0.1:
agent.string = agent.string[0:idx] + random.choice(chars) + agent.string[idx+1:in_str_len]
return agents
if __name__ == '__main__':
in_str = 'T1T3N1N2H1H2'
in_str_len = len(in_str)
ga()
在此代码中,我使用交叉函数和mutate函数来开发更强大的群体。 但是,我需要这些功能来将输入字符作为一个整体单元处理。 例如: 虽然变异,函数替换1或T从'T1'或K或1从'K1' 我需要它将T1和K1作为一个单元而不是字符串,并将它们替换为整体与其他单位如T2,T3,T4等 任何建议或提示,将不胜感激。 感谢你。如何在python中将多个字符定义为单个组?
正如@Evert和@ user3080953所提到的那样,问题在于您对染色体的表示。
你的遗传算法的目标是什么?
从您提供的代码中,您似乎希望群体朝目标字符串in_str
发展。但是,正如你在你的问题中提到的那样,一些字符串是无效的,因此不应该被考虑(例如T1D8
是有效染色体,而T18D
不是)。
有几个解决方案,这可能会解决这个问题:
方法#1(由@ user3080953提供)
交叉过程中明智地选择你的分割点。由于每个有效基因长度为2
字符串,因此拆分索引必须是偶数。因此,而不是:
split = random.randint(0, in_str_len)
...你可以写:
split = 2 * random.randint(0, in_str_len // 2)
然后,使在mutation()
功能类似的变化。
方法#2(如通过@Evert提供)
编码每个染色体作为字符串的列表,而不是一个单一的字符串。
所以,变化:
self.string = ' '.join(random.choice(chars) for _ in xrange(length))
...到:
self.string = [random.choice(chars) for _ in xrange(length)]
方法3
这可能是矫枉过正,但如果你希望有更好的可扩展性,你应该考虑将每个基因包装成一个物体。例如:
class Gene:
# not literally, but you get the picture hopefully
Gene._gene_set = set([...])
def __init__(self, gene_str):
formatted_gene_str = self._format(gene_str)
assert self._is_valid_gene_str(formatted_gene_str)
self._gene_str = formatted_gene_str
def _is_valid_gene_str(self, gene_str):
return gene_str in Gene._gene_set
def _format(self, gene_str):
return gene_str.strip().upper()
def __str__(self):
return self._gene_str
def __eq__(self, other):
return type(other) is Gene and str(self) == str(other)
此外,您的代码似乎存在潜在的设计缺陷。你写道:
self.string = ' '.join(random.choice(chars) for _ in xrange(length))
......在每个基因之间插入一个空格...;但是,目标字符串没有空格。 fuzz.ratio()
使用Levenshtein Distance来计算序列之间的差异。
谢谢你的详细解释。你已经清除了我的疑惑。 – BladeSama
关于这个缺陷......你能提出任何其他的方法来避开这个问题吗? – BladeSama
@BladeSama如果你选择方法#1,只需通过空字符串'''.join加入(...而不是空格)'''.join(...'。基本上,你只需要将目标染色体的相同表示的对象。 – ljeabmreosn
请创建一个[mcve]。 –
如果你想要这样的行为,你可能不应该在'mutation()'中遍历'agent.string':它将遍历字符串的单个字符。 – Evert
也许更好,不要在初始化时连接各个“基因”,但将它们保存为列表。像'self.string = [random.choice(chars)for _ in xrange(length)]''。也许可以将'string'重命名为'chromosome',并相应地调整其余的代码。 – Evert