docs: def pick(self, form, target_units, parcel_size, ave_unit_size,
               current_units, max_parcel_size=200000, min_unit_size=400,
               drop_after_build=True, residential=True, bldg_sqft_per_job=400.0,
               profit_to_prob_func=None):
          """
          Choose the buildings from the list that are feasible to build in
          order to match the specified demand.
  
          Parameters
          ----------
          form : string or list
              One or more of the building forms from the pro forma specification -
              e.g. "residential" or "mixedresidential" - these are configuration
              parameters passed previously to the pro forma.  If more than one form
              is passed the forms compete with each other (based on profitability)
              for which one gets built in order to meet demand.
          target_units : int
              The number of units to build.  For non-residential buildings this
              should be passed as the number of job spaces that need to be created.
          parcel_size : series
              The size of the parcels.  This was passed to feasibility as well,
              but should be passed here as well.  Index should be parcel_ids.
          ave_unit_size : series
              The average residential unit size around each parcel - this is
              indexed by parcel, but is usually a disaggregated version of a
              zonal or accessibility aggregation.
          bldg_sqft_per_job : float (default 400.0)
              The average square feet per job for this building form.
          min_unit_size : float
              Values less than this number in ave_unit_size will be set to this
              number.  Deals with cases where units are currently not built.
          current_units : series
              The current number of units on the parcel.  Is used to compute the
              net number of units produced by the developer model.  Many times
              the developer model is redeveloping units (demolishing them) and
              is trying to meet a total number of net units produced.
          max_parcel_size : float
              Parcels larger than this size will not be considered for
              development - usually large parcels should be specified manually
              in a development projects table.
          drop_after_build : bool
              Whether or not to drop parcels from consideration after they
              have been chosen for development.  Usually this is true so as
              to not develop the same parcel twice.
          residential: bool
              If creating non-residential buildings set this to false and
              developer will fill in job_spaces rather than residential_units
          profit_to_prob_func: function
              As there are so many ways to turn the development feasibility
              into a probability to select it for building, the user may pass
              a function which takes the feasibility dataframe and returns
              a series of probabilities.  If no function is passed, the behavior
              of this method will not change
  
          Returns
          -------
          None if thar are no feasible buildings
          new_buildings : dataframe
              DataFrame of buildings to add.  These buildings are rows from the
              DataFrame that is returned from feasibility.
          """
  
          if len(self.feasibility) == 0:
              # no feasible buildings, might as well bail
              return
  
          if form is None:
              df = self.feasibility
          elif isinstance(form, list):
              df = self.keep_form_with_max_profit(form)
          else:
              df = self.feasibility[form]
  
          # feasible buildings only for this building type
          df = df[df.max_profit_far > 0]
          ave_unit_size[ave_unit_size < min_unit_size] = min_unit_size
          df["ave_unit_size"] = ave_unit_size
          df["parcel_size"] = parcel_size
          df['current_units'] = current_units
          df = df[df.parcel_size < max_parcel_size]
  
          df['residential_units'] = (df.residential_sqft / df.ave_unit_size).round()
          df['job_spaces'] = (df.non_residential_sqft / bldg_sqft_per_job).round()
  
          if residential:
              df['net_units'] = df.residential_units - df.current_units
          else:
              df['net_units'] = df.job_spaces - df.current_units
          df = df[df.net_units > 0]
  
          if len(df) == 0:
              print("WARNING THERE ARE NO FEASIBLE BUILDING TO CHOOSE FROM")
              return
  
          # print "Describe of net units\n", df.net_units.describe()
          print("Sum of net units that are profitable: {:,}"
                .format(int(df.net_units.sum())))
  
          if profit_to_prob_func:
              p = profit_to_prob_func(df)
          else:
              df['max_profit_per_size'] = df.max_profit / df.parcel_size
              p = df.max_profit_per_size.values / df.max_profit_per_size.sum()
  
          if df.net_units.sum() < target_units:
              print("WARNING THERE WERE NOT ENOUGH PROFITABLE UNITS TO",
                    "MATCH DEMAND")
              build_idx = df.index.values
          elif target_units <= 0:
              build_idx = []
          else:
              # we don't know how many developments we will need, as they differ in net_units.
              # If all developments have net_units of 1 than we need target_units of them.
              # So we choose the smaller of available developments and target_units.
              choices = np.random.choice(df.index.values, size=min(len(df.index), target_units),
                                         replace=False, p=p)
              tot_units = df.net_units.loc[choices].values.cumsum()
              ind = int(np.searchsorted(tot_units, target_units, side="left")) + 1
              build_idx = choices[:ind]
  
          if drop_after_build:
              self.feasibility = self.feasibility.drop(build_idx)
  
          new_df = df.loc[build_idx]
          new_df.index.name = "parcel_id"
          return new_df.reset_index()