title: Performance of numpy.random.choice
body: <p><strong><em>I updated the code and the timings.</em></strong></p>
  
  <p>I'm trying to improve the performance of a function in my code. I must generate a list with random elements. However, different parts of the list must be filled with elements taken from different sets. An example of the code is below. I must generate millions of lists like those, one at a time.</p>
  
  <p>Function foo1 is the fastest, but it does not do what I need. It is there for performance reference. Functions foo2 and foo3 do what I need, but spend almost three times the processing time of foo1. </p>
  
  <p>Python 2.7.9 (default, Feb 10 2015, 03:29:19). [GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.56)] on darwin. numpy.<strong>version</strong>
  '1.8.1'</p>
  
  <pre><code>import numpy
  
  import timeit
  
  _ops_1 = ["-123.456", "3.1416", "1", "2"]
  _ops_2 = ["ABC", "XYZ", 'A', 'B', 'C']
  
  size = 10
  
  def foo1 (): 
      return numpy.random.choice(_ops_1 + _ops_2, 5*size)
  
  def foo2 (): 
      return list(numpy.concatenate((numpy.random.choice(_ops_1, 2*size), 
          numpy.random.choice(_ops_1 + _ops_2, size),
          numpy.random.choice(_ops_2, 2*size)), 0))
  
  def foo3 (): 
      return numpy.random.choice(_ops_1, 2*size).tolist() + \
          numpy.random.choice(_ops_1 + _ops_2, size).tolist() + \
          numpy.random.choice(_ops_2, 2*size).tolist()
  
  ### Suggested by Divakar
  def random_choice_replace_True(arr,size):
      return numpy.take(arr,numpy.random.randint(0,len(arr),size))
  
  def foo4 (): 
      return random_choice_replace_True(_ops_1, 2*size).tolist() + \
          random_choice_replace_True(_ops_1 + _ops_2, size).tolist() + \
          random_choice_replace_True(_ops_2, 2*size).tolist()
  
  ### 2nd suggestion by Divakar
  def random_choice_replace_True_idx(arr,size):
      return numpy.array(arr)[numpy.random.randint(0,len(arr),size)]
  
  def foo5 (): 
      return random_choice_replace_True_idx(_ops_1, 2*size).tolist() + \
          random_choice_replace_True_idx(_ops_1 + _ops_2, size).tolist() + \
          random_choice_replace_True_idx(_ops_2, 2*size).tolist()
  
  ###########
  
  setup = '''import numpy
  
  _ops_1 = ["-123.456", "3.1416", "1", "2"]
  _ops_2 = ["ABC", "XYZ", 'A', 'B', 'C']
  
  size = 10'''
  
  # As required, Number was increased to 10 million to get closer to actual timings
  timeit.timeit(foo1, setup=setup, number=10000000)
  
  timeit.timeit(foo2, setup=setup, number=10000000)
  
  timeit.timeit(foo3, setup=setup, number=10000000)
  
  timeit.timeit(foo4, setup=setup, number=10000000)
  
  timeit.timeit(foo5, setup=setup, number=10000000)
  </code></pre>
  
  <p>The running times on my machine were:</p>
  
  <blockquote>
    <p>timeit.timeit(foo1, setup=setup, number=10000000)
    235.22050380706787</p>
    
    <p>timeit.timeit(foo2, setup=setup, number=10000000)
    760.1884841918945</p>
    
    <p>timeit.timeit(foo3, setup=setup, number=10000000)
    560.77258586883545</p>
    
    <p>timeit.timeit(foo4, setup=setup, number=10000000)
    388.69550228118896</p>
    
    <p>timeit.timeit(foo5, setup=setup, number=10000000)
    252.32089233398438</p>
  </blockquote>
  
  <p>Well, for now I'll take the 2nd suggestion made by Divakar, which is pretty good. But other suggestions are welcome!</p>