How to generate numbers in range with specific average with Python?

后端 未结 6 632
感动是毒
感动是毒 2020-12-10 23:08

For example I would like to generate 22 numbers between 20 and 46 with an average value of 27. And I would like the numbers to cover the range as well as possible.

E

6条回答
  •  一个人的身影
    2020-12-10 23:37

    You could sove this in a pure mathematical way.

    1. Randomly pick a number (call it n) within the wanted range
    2. The next number will be avg + abs(n-avg)
    3. repeat this until you fill the amount of numbers you want

    if the amount of needed numbers is no even - just select one of the numbers as the average itself and then you will need to generate k-1 numbers (which is even)

    ** EDIT **
    you can use this code that manipulates an initial list to meet the requirements of a average so the resulting list is not symmetrical. (Better than generating lists until you hit the correct one)

    import random
    
    
    def generate_numbers(wanted_avg, numbers_to_generate, start, end):
        rng = [i for i in range(start, end)]
        initial_selection = [random.choice(rng) for _ in range(numbers_to_generate)]
        initial_avg = reduce(lambda x, y: x+y, initial_selection) / float(numbers_to_generate)
        print "initial selection is: " + str(initial_selection)
        print "initial avg is: " + str(initial_avg)
        if initial_avg == wanted_avg:
            return initial_selection
        off = abs(initial_avg - wanted_avg)
        manipulation = off * numbers_to_generate
    
        sign = -1 if initial_avg > wanted_avg else 1
    
        manipulation_action = dict()
        acceptable_indices = range(numbers_to_generate)
        while manipulation > 0:
            random_index = random.choice(acceptable_indices)
            factor = manipulation_action[random_index] if random_index in manipulation_action else 0
            after_manipulation = initial_selection[random_index] + factor + sign * 1
            if start <= after_manipulation <= end:
                if random_index in manipulation_action:
                    manipulation_action[random_index] += sign * 1
                    manipulation -= 1
                else:
                    manipulation_action[random_index] = sign * 1
                    manipulation -= 1
            else:
                acceptable_indices.remove(random_index)
    
        for key in manipulation_action:
            initial_selection[key] += manipulation_action[key]
    
        print "after manipulation selection is: " + str(initial_selection)
        print "after manipulation avg is: " + str(reduce(lambda x, y: x+y, initial_selection) / float(numbers_to_generate))
        return initial_selection
    

提交回复
热议问题