Python 如何将遗传编程算法训练到可变描述符序列上?

Python 如何将遗传编程算法训练到可变描述符序列上?,python,genetic-programming,Python,Genetic Programming,我目前正在尝试设计一种遗传编程算法,该算法分析字符序列,并为这些字符指定一个值。下面,我制作了一个示例集。每一行代表一个数据点。经过训练的值是实值的。 例子: 对于单词ABCDE算法应返回1.0 示例数据集: ABCDE:1 ABCDEF:10 ABCDEGH:3 ABCDELKA:50 AASD:3 数据集可以是所需的最大数据集,因为这一切都是虚构的。让我们假设GP应该理解的规则并不太复杂,并且它可以由数据来解释 当给定输入序列时,我希望该算法能够近似计算数据集中的值。我现在的问题是,每个序列

我目前正在尝试设计一种遗传编程算法,该算法分析字符序列,并为这些字符指定一个值。下面,我制作了一个示例集。每一行代表一个数据点。经过训练的值是实值的。 例子: 对于单词
ABCDE
算法应返回1.0

示例数据集:

ABCDE:1

ABCDEF:10

ABCDEGH:3

ABCDELKA:50

AASD:3

数据集可以是所需的最大数据集,因为这一切都是虚构的。让我们假设GP应该理解的规则并不太复杂,并且它可以由数据来解释

当给定输入序列时,我希望该算法能够近似计算数据集中的值。我现在的问题是,每个序列可以由不同数量的字符组成。如果可能的话,我不想自己写一些花哨的描述词

如何训练我的GP(最好使用
tinyGP
或python)来构建此模型?

因为这里有这么多的讨论——一张图表上写着千言万语: 我想做的就是把一个数据点放到一个函数中。然后我得到一个值,这是我的结果。不幸的是,我不知道这个函数,我只是有一个数据集,其中有一些示例(可能1000个示例只是一个示例)。现在,我使用遗传编程算法来找到一种能够将数据点转换为结果的算法。这是我的模型。在本例中,我遇到的问题是数据点的长度不同。对于设置的长度,我可以只指定字符串中的每个字符作为输入参数。但是,如果我有不同数量的输入参数,我就不知所措了


免责声明:在我的研究中,我已经多次遇到这个问题,但我们永远都无法找到一个解决方案(比如使用窗口、描述符等)。我想使用GP,因为我喜欢这项技术,并且想尝试一下,但在Uni期间,我们也用ANN等进行了尝试,但没有效果可变输入大小的问题仍然存在。

传统的遗传编程不适合可变长度输入

我突然想到,这个问题中预设了某种评价模式

例如,考虑将可变长度输入编码为单个任意精度值,例如,对于10个符号的字母表:

ABCD = 1234; ABCDEF = 123456

然而,如果这种编码对于问题域来说不是自然的,那么很难发展出一个能够很好地处理这种输入的程序

您还可以假设,这个问题可以用遗传衍生的有限状态机来充分表示:

F(F(F(F(init(), A), B), C), D) = 1234
这是一个独立于基因编程的研究领域,谷歌搜索,阅读研究论文,也许你能找到一个能满足你需求的软件包

同样,你的问题也可以用另一种变换来表示,例如bigram的频率——这种变换是有限长度的:

# bigrams
# ABCDE => 1
"AA": 0
"AB": 0.25
"AC": 0
"AD": 0
"AE": 0
"BA": 0
"BC": 0.25
"BD": 0
#... up to end of alphabet ...

(0, 0.25, 0, 0, 0, 0, 0.25, 0, ...., 0, ...) => 1      # ABCDE
(0, 0.20, 0, 0, 0, 0, 0.20, 0, ...., 0.20, ...) => 10  # ABCDEF
# input length N^2

# trigrams
(0, 0.33, 0, 0, ..., 0, ...) => 1      # ABCDE
(0, 0.25, 0, 0, ..., 0.25, ...) => 10  # ABCDEF
# input length N^3
二元图、三元图等都是出人意料的好预测器:

  • 捕获马尔可夫信息(“ab”与“ac”)
  • 捕获相对位置(“ab”和“bc”与“ed”和“bc”)
  • 捕捉非线性语义(“abab”!=“ab”*2)
  • 抗混乱输入(“购买新垃圾邮件”vs“购买新垃圾邮件”)
这些常用于自然语言问题,如文本主题检测、作者检测、垃圾邮件保护;生物技术,如dna和rna序列等

但是,不能保证这种方法适用于您的问题。它确实取决于你的问题域,例如在算术域中考虑字母表<代码> 10 + < /代码>,以下两个输入变得不可区分,但产生不同的结果:

10000+10000 = 20000
1000+100000 = 101000
在这种情况下,您需要注册机之类的设备:

init: tmp = 0; res = 0
"0": tmp *= 10
"1": tmp *= 10; tmp += 1
"+": res += tmp; tmp = 0
end: res += tmp

由于没有适应度函数,因此需要将遗传算法视为分类器。所以你需要想出一种方法来评估一条染色体。正如其他人所建议的,这是一个纯粹的分类问题,而不是优化问题,但是,如果您仍然想继续遗传算法,这里有一些步骤来尝试初始方法:

您将需要:

  • 有效染色体的描述(如何编码)

  • 要使用遗传算法,所有的解都必须具有相同的长度(有更高级的可变长度编码方法,但我不在此赘述)。因此,您需要找到一种最佳的编码方法。知道您的输入是一个可变长度的字符串,您可以将您的染色体编码为字母表的查找表(python中的字典)。然而,当您尝试应用交叉或变异操作时,字典会给您带来一些问题,因此最好将字母表和染色体编码分开。参考语言模型,您可以检查n个字母表,您的染色体长度将与您的字母表长度相同:

    UNIGRAM

    alphabet = "ABCDE"
    chromosome1 = [1, 2, 3, 4, 5]
    chromosome2 = [1, 1, 2, 1, 0]
    
    alphabet = ["AB", "AC", "AD", "AE", "BC", "BD", "BE", "CD", "CE", "DE"]
    chromosome = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    
    alphabet = ["ABC", "ABD", "ABE"...]
    chromosome = as above, a value for each combination
    
    BIGRAM

    alphabet = "ABCDE"
    chromosome1 = [1, 2, 3, 4, 5]
    chromosome2 = [1, 1, 2, 1, 0]
    
    alphabet = ["AB", "AC", "AD", "AE", "BC", "BD", "BE", "CD", "CE", "DE"]
    chromosome = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    
    alphabet = ["ABC", "ABD", "ABE"...]
    chromosome = as above, a value for each combination
    
    三角图

    alphabet = "ABCDE"
    chromosome1 = [1, 2, 3, 4, 5]
    chromosome2 = [1, 1, 2, 1, 0]
    
    alphabet = ["AB", "AC", "AD", "AE", "BC", "BD", "BE", "CD", "CE", "DE"]
    chromosome = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    
    alphabet = ["ABC", "ABD", "ABE"...]
    chromosome = as above, a value for each combination
    
    二,。 解码染色体以评估单个输入

    染色体代表字母表中每个元素的整数值。所以,如果你想知道一个有染色体的输入值(可变长度字符串),你需要尝试一些求值函数,最简单的是每个字母值的总和

    alphabet = "ABC"
    chromosome = [1, 2, 1]
    input = "ABBBC"
    
    # acc = accumulated value
    value = reduce(lambda acc, x: acc + chromosme[alphabet.index(x)], input, 0)
    # Will return ABBBC = 1+2+2+2+1 = 8
    
    三,。 健身功能

    你的适应度函数只是一个简单的误差函数。你可以使用简单的误差和,平方误差。。。单代的简单评估函数:

    def fitnessFunction(inputs, results, alphabet, chromosome):
        error = 0
    
        for i in range(len(inputs)):
            value = reduce(lambda acc, x: acc + chromosome[alphabet.index(x)], inputs[i], 0) 
            diff = abs(results[i] - value)
            error += diff # or diff**2 if you want squared error
    
        return error
    
    # A simple call -> INPUTS, EXPECTED RESULTS, ALPHABET, CURRENT CHROMOSOME
    fitnessFunction(["ABC", "ABB", "ABBC"], [1,2,3], "ABC", [1, 1, 0])
    # returned error will be:
    # A+B+C = 1 + 1 + 0 -- expected value = 1 --> error += 1
    # A+B+B = 1 + 1 + 1 -- expected value = 2 --> error += 1
    # A+B+C = 1 + 1 + 1 + 0 -- expected value = 3 --> error += 0
    # This chromosome has error of 2
    
    现在,使用任何交叉和变异算子