2
\$\begingroup\$

This is from my own question on Stack Overflow.

I want to get average numbers from a range such that they fit an intended average. I expect something bell-curve-like, but asymmetrical unless the average is the mean of the range. The function should allow for any degree of deviation. In my Overflow question, I wanted it to pick from a list, but that's an easy modification if my idea works.

This is what I've come up with: (imports: numpy and random)

def randlist(minn, maxn, goaln, countn):
    nlist = []
    for i in range(0, countn):
        if len(nlist) > 10:
            ave = numpy.mean(nlist)
            if ave > goaln:
                a = random.uniform(minn, goaln)
            else:
                a = random.uniform(goaln, maxn)
        else:
            a = random.uniform(minn, maxn)
        nlist.append(a)
    return nlist

Trying it out:

b = randlist(1, 10, 7, 1000)
print len(b)
>> 1000
print numpy.mean(b)
>> 6.99951157861

I'm no mathematician; is this as functional as it appears to me to be?

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Did you look at a random.betavariate? \$\endgroup\$
    – vnp
    Commented Nov 19, 2014 at 21:30
  • \$\begingroup\$ That's a "weird" distribution. What do you intend to use it for? \$\endgroup\$ Commented Nov 19, 2014 at 21:37
  • \$\begingroup\$ Quality scores for leads: 400,000 leads to call from call centers. I've already done the work of sorting them into assumed scores - but when I load them to be called, say 10,000 at a time, I don't want to exclude everything below 5.0 in the case of picking an average score of 7.5. Everyone should be potentially called. The bell curve formulas I've seen limit for symmetry. \$\endgroup\$
    – Xodarap777
    Commented Nov 19, 2014 at 23:03

1 Answer 1

4
\$\begingroup\$

If you want to express the field or distribution in a wave form, you should consider doing a Fourier Transformation on the function. Now, I must admit that I haven't understood exactly the sort of distribution function you are looking for. Numpy already has implementations for Gaussian distribution and such in the random module.

You can easily do so by:

numpy.random.normal(loc=7, scale=1.0, size=None)

This will produce a normal distribution with μ=7 and σ2=1.0


Now, about your code


def randlist(minn, maxn, goaln, countn):
    nlist = []

Consider renaming this function to the distribution's name that you are looking for. Such as normal for a normal distribution. Rename minn and maxn to min_ or max_. Since you are trying to avoid clashes with the keywords, you could also try using synonyms such as low and high.

for i in range(0, countn):

range(countn) is enough to start the list from 0.

if len(nlist) > 10:
    ave = numpy.mean(nlist)
    if ave > goaln:
        a = random.uniform(minn, goaln)
    else:
        a = random.uniform(goaln, maxn)
else:
    a = random.uniform(minn, maxn)

Since you are adding the first 10 numbers randomly to the list, you can do so inside the nlist itself in the form of a list comprehension (see sample code below).

def weighted_distribution(low, high, ev, count, start=10):
    result = [random.uniform(low, high) for i in range(start)]
    for i in range(count-start):
        if numpy.mean(result)> ev:
            result.append(random.uniform(low, ev))
        else:
            result.append(random.uniform(ev, high))
    return result

ev is the expected value for this distribution (mean).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.