2012-04-25 10 views
7

Tôi có một danh sách các đối tượng (nhiễm sắc thể) trong đó có một phòng tập thể dục thuộc tính (chromosome.fitness là giữa 0 và 1)Thể hình cân đối lựa chọn (roulette bánh xe lựa chọn) trong Python

Cho một danh sách các đối tượng như vậy, làm thế nào có thể Tôi thực hiện một chức năng mà trả về một nhiễm sắc thể duy nhất có cơ hội được chọn là tỷ lệ thuận với thể dục của nó? Tức là, nhiễm sắc thể với thể dục 0,8 có khả năng được chọn là một với tập thể dục 0,4 lần.

Tôi đã tìm thấy một vài triển khai Python và mã giả, nhưng chúng quá phức tạp đối với yêu cầu này: hàm chỉ cần danh sách các nhiễm sắc thể. Nhiễm sắc thể lưu trữ phòng tập thể dục của riêng mình dưới dạng biến nội bộ.

Việc triển khai tôi đã viết là trước khi tôi quyết định cho phép nhiễm sắc thể lưu trữ phòng tập thể dục của riêng mình, vì vậy có rất nhiều danh sách và thứ phức tạp hơn.

---------------------------- CHỈNH SỬA ---------------- ------------

Cảm ơn Lattyware. Chức năng sau đây dường như hoạt động.

def selectOne(self, population): 
     max  = sum([c.fitness for c in population]) 
     pick = random.uniform(0, max) 
     current = 0 
     for chromosome in population: 
      current += chromosome.fitness 
      if current > pick: 
       return chromosome 

Trả lời

6

Có một cách rất đơn giản để chọn một lựa chọn ngẫu nhiên trọng từ một cuốn từ điển:

def weighted_random_choice(choices): 
    max = sum(choices.values()) 
    pick = random.uniform(0, max) 
    current = 0 
    for key, value in choices.items(): 
     current += value 
     if current > pick: 
      return key 

Nếu bạn không có một từ điển trong tay, bạn có thể sửa đổi này cho phù hợp với lớp học của bạn (như bạn đã không cho biết thêm chi tiết về nó, hoặc tạo ra một từ điển:

choices = {chromosome: chromosome.fitness for chromosome in chromosomes} 

Giả sử rằng tập thể dục là một thuộc tính

.

Dưới đây là một ví dụ về chức năng được sửa đổi để có thể lặp lại các nhiễm sắc thể, một lần nữa, đưa ra giả định tương tự.

def weighted_random_choice(chromosomes): 
    max = sum(chromosome.fitness for chromosome in chromosomes) 
    pick = random.uniform(0, max) 
    current = 0 
    for chromosome in chromosomes: 
     current += chromosome.fitness 
     if current > pick: 
      return chromosome 
+2

Nếu bạn có nhiều sự lựa chọn, hoặc bạn phải chọn nhiều giá trị với cùng một bộ trọng lượng, bạn cũng có thể biến O (n) giải pháp này vào một giải pháp O (log (n)) bằng cách sử dụng một tìm kiếm nhị phân, hoặc thậm chí một giải pháp O (1) bằng cách sử dụng một số loại bảng tra cứu. –

+0

@SvenMarnach Điều này đúng, tôi đưa ra giải pháp đơn giản nhất ở đây, không nhất thiết phải là nhanh nhất - điều đó thực sự đáng chú ý. –

+0

[Bài viết này] (http://www.keithschwarz.com/darts-dice-coins/) đưa ra một giải thích tốt đẹp về việc phát triển một thuật toán O (1) cho mẫu này. – Dougal

-1
import random 

def weighted_choice(items): 
    total_weight = sum(item.weight for item in items) 
    weight_to_target = random.uniform(0, total_weight) 
    for item in items: 
     weight_to_target -= item.weight 
     if weight_to_target <= 0: 
      return item 
1

Tôi muốn ít dòng:

import itertools 

def choose(population): 
    bounds = list(itertools.accumulate(chromosome.fitness for chromosome in population)) 
    pick = random.random() * bounds[-1] 
    return next(chromosome for chromosome, bound in zip(population, bounds) if pick < bound) 
1
from __future__ import division 
import numpy as np 
import random,pdb 
import operator 

def roulette_selection(weights): 
     '''performs weighted selection or roulette wheel selection on a list 
     and returns the index selected from the list''' 

     # sort the weights in ascending order 
     sorted_indexed_weights = sorted(enumerate(weights), key=operator.itemgetter(1)); 
     indices, sorted_weights = zip(*sorted_indexed_weights); 
     # calculate the cumulative probability 
     tot_sum=sum(sorted_weights) 
     prob = [x/tot_sum for x in sorted_weights] 
     cum_prob=np.cumsum(prob) 
     # select a random a number in the range [0,1] 
     random_num=random.random() 

     for index_value, cum_prob_value in zip(indices,cum_prob): 
      if random_num < cum_prob_value: 
       return index_value 


if __name__ == "__main__": 
    weights=[1,2,6,4,3,7,20] 
    print (roulette_selection(weights)) 
    weights=[1,2,2,2,2,2,2] 
    print (roulette_selection(weights))