title: pandas - binning with bins definitions based on value in another column
body: <p>I am struggling with such task: I need to discretize values in a column from data frame, with bins definition based on value in other column. </p>
  
  <p>For a minimal working example, lets define a simple dataframe:</p>
  
  <pre><code>import pandas as pd
  df = pd.DataFrame({'A' : ['one', 'one', 'two', 'three'] * 3,'B' : np.random.randn(12)})
  </code></pre>
  
  <p>The dataframe looks like this:</p>
  
  <pre><code>        A       B
  0       one     2.5772143847077427
  1       one     -0.6394141654096013
  2       two     0.964652049995486
  3       three   -0.3922889559403503
  4       one     1.6903991754896424
  5       one     0.5741442025742018
  6       two     0.6300564981683544
  7       three   0.9403680915507433
  8       one     0.7044433078166983
  9       one     -0.1695006646595688
  10      two     0.06376190217285167
  11      three   0.277540580579127
  </code></pre>
  
  <p>Now I would like to introduce column <code>C</code>, which will contain a bin label, with different bins for each of values in column <code>A</code>, i.e.:</p>
  
  <ul>
  <li><code>(-10,-1,0,1,10)</code> for <code>A == 'one'</code>, </li>
  <li><code>(-100,0,100)</code> for <code>A == 'two'</code>, </li>
  <li><code>(-999,0,1,2,3)</code> for <code>A == 'three'</code>.</li>
  </ul>
  
  <p>A desired output is:</p>
  
  <pre><code>        A       B       C
  0       one     2.5772143847077427      (1, 10]
  1       one     -0.6394141654096013     (-1, 0]
  2       two     0.964652049995486       (0, 100]
  3       three   -0.3922889559403503     (-999, 0]
  4       one     1.6903991754896424      (1, 10]
  5       one     0.5741442025742018      (0, 1]
  6       two     0.6300564981683544      (0, 100]
  7       three   0.9403680915507433      (0, 1]
  8       one     0.7044433078166983      (0, 1]
  9       one     -0.1695006646595688     (-1, 0]
  10      two     0.06376190217285167     (0, 100]
  11      three   0.277540580579127       (0, 1]
  </code></pre>
  
  <p>I have tried using <code>pd.cut</code> or <code>np.digitize</code> with different combinations of <code>map</code>, <code>apply</code>, but without success.</p>
  
  <p>Currently I am achieving the result by splitting the frame and applying <code>pd.cut</code> to each subset separately, and then merging to get the frame back, like this:</p>
  
  <pre><code>values_in_column_A = df['A'].unique().tolist()
  bins = {'one':(-10,-1,0,1,10),'two':(-100,0,100),'three':(-999,0,1,2,3)}
  
  def binnize(df):
  
      subdf = []
      for i in range(len(values_in_column_A)):
          subdf.append(df[df['A'] == values_in_column_A[i]])
          subdf[i]['C'] = pd.cut(subdf[i]['B'],bins[values_in_column_A[i]])
  
      return pd.concat(subdf)
  </code></pre>
  
  <p>This works, but I do not think it is elegant enough, I also anticipate some speed or memory problems in production, when I will have frames with millions of rows. Speaking straight, I guess this could be done better.</p>
  
  <p>I wolud appreciate any help or ideas...</p>