title: numpy parse int into bit groupings
body: <p>I have a <code>np.array</code> of <code>np.uint8</code></p>
  
  <pre><code>a = np.array([randint(1,255) for _ in range(100)],dtype=np.uint8)
  </code></pre>
  
  <p>and I want to split this into low and high nibbles</p>
  
  <p>I could get the low nibble</p>
  
  <pre><code>low = np.bitwise_and(a,0xF)
  </code></pre>
  
  <p>and I could get the high nibble with</p>
  
  <pre><code>high = np.bitwise_and(np.right_shift(a,4),0xF)
  </code></pre>
  
  <p>is there some way to do something like</p>
  
  <pre><code>&gt;&gt;&gt; numpy.keep_bits(a,[(0,3),(4,7)])
  numpy.array([
    [low1,high1],
    [low2,high2],
    ...
    [lowN,highN]
    ])
  </code></pre>
  
  <p>Im not even sure what this would be called ... but I thought maybe some numpy guru would know a cool way to do this (in reality i am looking to do this with uint32's and much more varied nibbles</p>
  
  <p>basically something like <code>struct.unpack</code> but for vectorized numpy operations</p>
  
  <p><strong>EDIT</strong>: I went with a modified version of the accepted answer below</p>
  
  <p>here is my final code for anyone interested</p>
  
  <pre><code>def bitmask(start,end):
      """
      &gt;&gt;&gt; bitmask(0,2) == 0b111
      &gt;&gt;&gt; bitmask(3,5) == 0b111000
  
      :param start: start bit 
      :param end:  end bit (unlike range, end bit is inclusive)
      :return: integer bitmask for the specified bit pattern
      """
      return (2**(end+1-start)-1)&lt;&lt;start
  
  def mask_and_shift(a,mask_a,shift_a):
      """
  
      :param a: np.array 
      :param mask_a: array of masks to apply (must be same size as shift_a)
      :param shift_a: array of shifts to apply (must be same size as mask_a)
      :return: reshaped a, that has masks and shifts applied
      """
      masked_a = numpy.bitwise_and(a.reshape(-1,1), mask_a)
      return numpy.right_shift(masked_a,shift_a)
  
  def bit_partition(rawValues,bit_groups):
      """
      &gt;&gt;&gt; a = numpy.array([1,15,16,17,125,126,127,128,129,254,255])
      &gt;&gt;&gt; bit_partition(a,[(0,2),(3,7)])
      &gt;&gt;&gt; bit_partition(a,[(0,2),(3,5),(6,7)])
  
      :param rawValues: np.array of raw values
      :param bit_groups: list of start_bit,end_bit values for where to bit twiddle
      :return: np.array len(rawValues)xlen(bit_groups)
      """
      masks,shifts = zip(*[(bitmask(s,e),s) for s,e in bit_groups])
      return mask_and_shift(rawValues,masks,shifts)
  </code></pre>