Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I'm pretty new to Mathematica, and I'm mainly a programmer so I don't have a lot of knowledge about maths.

I want to generate a set of UNIQUE incremental numbers (series) according to the following rules:

  • From N1 to N2 INCLUSIVE
  • The count is exactly N e.g. I want 5000 numbers
  • Scales according to a function i.e. I want the distance between each number and the following number to increase sequentially for example I want it to scale such that the first 25% of the range contains 50% of the number (numbers close together) then next 25% contains 30% of the numbers, then 15% then 5%, that way as you move forward the numbers are stretched further apart.


Thanks,
SM

EDIT: The actual situation that makes me think I need this is:
I'm simulating a slot game where you can win an amount of money each spin, I get a long list of all the wins and their frequencies, now I want to "redistribute" or "group up" those range of wins into a smaller set, for example only 5000 numbers instead of having like 1M, I want to do that by basically generating a series as specified in my question and then "grouping" each of the real wins into the closest number in the generated set, so for example 0.9, 1 and 1.1 would be grouped into just 1 with frequency 3 (assuming that 1 is in the generated set of numbers)

EDIT: Now that my question has been answered, my next step should be:

  1. My new set of numbers has a weights list all initialised to 0 {0,0,0,...}
  2. Go through my original list and for each number I get its weight and add it to the weight of the nearest number in the new set.
    For example:
    Original: {1,2,3,4,5,...,10} (from 1 to 10)
    Weights: {1,1,1,1,..} (all have equal weight)
    New set: {1,10}
    so the weights for the new set would be calculated:
    {1 to 5} get "rounded" to 1 (closest number)
    {6 to 10} get "rounded" to 10 (closest number)
    New weights: {5,5}

I can do this in code easily but I'm sure there must be a way to do this in Mathematica? Should I post this as a new question? I don't want to spam

share|improve this question
1  
As a first start you could write one function as Piecewise spreading your values over your Range N. Just in case: Rule of Thumb - never use For- loops –  Sascha Nov 30 '12 at 20:56
    
Thanks that's quite useful actually –  Space monkey Nov 30 '12 at 20:58
    
On second thought: What do you intend to use this list for? Since you said you are new to Mathematica, it could well be that there is a build-in function for what you intend to do. –  Sascha Nov 30 '12 at 22:13
    
Thanks, I have edited my question –  Space monkey Nov 30 '12 at 23:09
    
I am a bit occupied at the moment, but my first guess for solving your problem would be GatherBy or BinCount, or BinList - depending on what exactly your output should look like. –  Sascha Nov 30 '12 at 23:38

2 Answers 2

up vote 4 down vote accepted

This might put you on track. Say your range is 1 to 50000. We can weight these in quartiles so that the first ones have 50% chance of being selected, 30% for the ones in the next quartile, etc. Then form a random sample without duplication using weighted RandomSample. Last sort so the result is ascending. Below is the code for this.

n = 50000;
rng = Range[n];
wts = Join[ConstantArray[1, n/4], ConstantArray[6/10, n/4], 
   ConstantArray[3/10, n/4], ConstantArray[1/10, n/4]];

SeedRandom[1111];
sample = Sort[RandomSample[wts -> rng, 5000]];

To check the quality I'll bin into quartiles, then find the length of each bin.

lens = Map[Length, BinLists[sample, n/4]]

(* Out[25]= {2474, 1505, 773, 248} *)

Let's get the respective fractions.

N[lens/5000]

(* Out[26]= {0.4948, 0.301, 0.1546, 0.0496} *)
share|improve this answer
    
very interesting answer, it seems to solve my problem I need to do some checks to be sure though, cheers for that –  Space monkey Dec 1 '12 at 0:09
    
yup that's what I needed. In my case I already have the weight for each number in the original list. –  Space monkey Dec 1 '12 at 20:15

Here is approach that doesn't rely on random numbers but instead generates a completely deterministic sequence of numbers that tracks the desired distribution optimally.

The distribution given in the example can be written like this, assuming all numbers are in percent:

ρ[x_] := Piecewise[{
           {50, 0 <= x < 25}, 
           {30, 25 <= x < 50}, 
           {15, 50 <= x < 75}, 
           {5, 75 < x <= 100}
         }]
Plot[ρ[x], {x, 0, 100}, Exclusions -> None, 
      AxesLabel -> {x, ρ}, BaseStyle -> Larger]

rho

Now I generate the desired numbers in a list called spacedOut, with a length of 5000 entries:

numberOfValues = 5000;
max = Integrate[ρ[x1], {x1, 0, 100}];
dx = max/numberOfValues;

spacedOut = 
  Most@Rest@NestWhileList[(# + dx/N[ρ[#]]) &, 0, (# <= 100) &];

ListPlot[spacedOut]

spaced

To check that we got the desired result, look at the number of values and their percent distribution:

Length[spacedOut] == numberOfValues
(* ==> True *)

100 BinCounts[spacedOut, {0, 100, 25}]/Length[spacedOut] // N
(* ==> {49.98, 30.02, 15., 5.} *)

The last line shows that the distribution is spot on, without having to rely on the law of large numbers in a random process.

Basically what I did in the NestWhileList was to construct the inverse of the integrated distribution in a discretized form. Or in other words, I used the relation $\Delta y = \rho(x) \Delta x$ where $x$ is in the interval $[0,100]$ and let $y$ increase in constant steps to calculate successive values of the corresponding $x$. The total number of steps is predetermined by calculating the integral of $\rho$ over the whole interval $[0,100]$ and adjusting the step width dx accordingly.

Therefore, the values in spacedOut will all lie between $0$ and $100$, but with a varying spacing to create the correct distribution.

The final step is to uniformly rescale and shift all the numbers in spacedOut so that its minimum and maximum agree with the minimum and maximum values n1 and n2 that you want:

n1 = 17; n2 = 511;
final = n1 + spacedOut*(n2 - n1)/100

This approach doesn't require a piecewise constant distribution. The function $\rho(x)$ can be an arbitrary distribution.

share|improve this answer
    
ha, I learned some new things by trying to understand your answer, still don't fully understand it to be honest (the Δy=ρ(x)Δx par), but thanks that was quite useful –  Space monkey Dec 1 '12 at 20:00

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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