Make a list of ranges in numpy
<p>I want to make a list of integer sequences with random start points. The way I would do this in pure python is </p>

<pre>
x = np.zeros(1000, 10) # 1000 sequences of 10 elements each
starts = np.random.randint(1, 1000, 1000)
for i in range(len(x)):
    x[i] = np.arange(starts[i], starts[i] + 10)
</pre>

<p>I wonder if there is a more elegant way of doing this using Numpy functionality.</p>

<p>You can use <a href="http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html" rel="nofollow"><code>broadcasting</code></a> after extending <code>starts</code> to a <code>2D</code> version and adding in the <code>1D</code> range array, like so -</p>

<pre><code>x = starts[:,None] + np.arange(10)
</code></pre>

<p><strong>Explanation</strong></p>

<p>Let's take a small example for <code>starts</code> to see what that <code>broadcasting</code> does in this case.</p>

<pre><code>In [382]: starts
Out[382]: array([3, 1, 3, 2])

In [383]: starts.shape
Out[383]: (4,)

In [384]: starts[:,None]
Out[384]: 
array([[3],
       [1],
       [3],
       [2]])

In [385]: starts[:,None].shape
Out[385]: (4, 1)

In [386]: np.arange(10).shape
Out[386]: (10,)
</code></pre>

<p>Thus, looking at the shapes and putting those together, a schematic diagram of the same would look something like this -</p>

<pre><code>starts         :  4
np.arange(10)  :  10
</code></pre>

<p>After extending <code>starts</code> :</p>

<pre><code>starts[:,None] :  4  x  1
np.arange(10)  :       10
</code></pre>

<p>Thus, when we add <code>starts[:,None]</code> with <code>np.arange(10)</code>, the elems of <code>starts[:,None]</code> would be broadcasted along its second axis <code>10</code> times corresponding to the length of the other array along that axis. For <code>np.arange(10)</code>, it would be converted to <code>2D</code> with its first dim being a singleton dim and its elems being broadcasted along it <code>4</code> times correspoinding to the length of <code>4</code> for the other array <code>starts[:,None]</code> along that axis. Please note that there aren't explicit replications, as under the hood the elems are broadcasted and added on the fly.</p>

<p>Thus, functionally we would have the replications, like so -</p>

<pre><code>In [391]: np.repeat(starts[:,None],10,axis=1)
Out[391]: 
array([[3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
       [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
       [3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
       [2, 2, 2, 2, 2, 2, 2, 2, 2, 2]])

In [392]: np.repeat(np.arange(10)[None],4,axis=0)
Out[392]: 
array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
       [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
       [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
       [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])
</code></pre>

<p>These broadcasted elems are then added to give us the desired output <code>x</code>.</p>

python numpy