docs: def perturb(estimator, X, bins, columns=None):
      """
      Predict on peturbations of a feature vector
      estimator: a fitted sklearn estimator
      index: the index of the example to perturb
      bins: a dictionary of column:bins arrays
      columns: list of columns if bins doesn't cover all columns
      TODO make this work when index is multiple rows
      """
      if columns is None:
          if len(bins) != X.shape[1]:
              raise ValueError("Must specify columns when not perturbing all columns")
          else:
              columns = X.columns
  
      n = np.concatenate(([0], np.cumsum([len(b) for b in bins])))
  
      X_test = np.empty((n[-1]*X.shape[0], X.shape[1]))
      r = pd.DataFrame(columns=['value', 'feature', 'index'], index=np.arange(n[-1]*X.shape[0]))
      for j, index in enumerate(X.index):
          X_test[j*n[-1]:(j+1)*n[-1], :] = X.values[j, :]
          for i, c in enumerate(columns):
              s = slice(j*n[-1] + n[i], j*n[-1] + n[i+1])
              r['value'].values[s] = bins[i]
              r['feature'].values[s] = c
              r['index'].values[s] = [index]*(n[i+1]-n[i])
              X_test[s, (X.columns == c).argmax()] = bins[i]
  
      y = estimator.predict_proba(X_test)[:, 1]
      r['y'] = y
      return r