Example #1
0
def initialize_new_units(buildings, residential_units):
    """
    This data maintenance step initializes units for buildings that have been
    newly created, conforming to the data requirements of the
    'residential_units' table.

    Data expectations
    -----------------
    - 'buildings' table has the following columns:
        - index that serves as its identifier
        - 'residential_units' (int, count of units in building)
    - 'residential_units' table has the following columns:
        - index named 'unit_id' that serves as its identifier
        - 'building_id' corresponding to the index of the 'buildings' table

    Results
    -------
    - extends the 'residential_units' table, following the same schema as the
      'initialize_residential_units' model step
    """

    # Verify initial data characteristics
    '''
    ot.assert_orca_spec(OrcaSpec(
        '',
        TableSpec(
            'buildings',
            ColumnSpec('building_id', primary_key=True),
            ColumnSpec('residential_units', min=0)),
        TableSpec(
            'residential_units',
            ColumnSpec('unit_id', primary_key=True),
            ColumnSpec('building_id', foreign_key='buildings.building_id'))))
    '''

    old_units = residential_units.to_frame(residential_units.local_columns)
    bldgs = buildings.to_frame(['residential_units', 'deed_restricted_units', 'building_id'])

    # Filter for residential buildings not currently represented in
    # the units table
    new_bldgs = bldgs[~bldgs.building_id.isin(old_units.building_id)]
    new_bldgs = new_bldgs[new_bldgs.residential_units > 0]
    
    if len(new_bldgs) == 0:
        return

    # Create new units, merge them, and update the table
    new_units = _create_empty_units(new_bldgs)
    all_units = dev.merge(old_units, new_units)
    all_units.index.name = 'unit_id'

    print "Creating %d residential units for %d new buildings" % \
        (len(new_units), len(new_bldgs))

    orca.add_table('residential_units', all_units)

    # Verify final data characteristics
    '''
def initialize_new_units(buildings, residential_units):
    """
    This data maintenance step initializes units for buildings that have been
    newly created, conforming to the data requirements of the
    'residential_units' table.

    Data expectations
    -----------------
    - 'buildings' table has the following columns:
        - index that serves as its identifier
        - 'residential_units' (int, count of units in building)
    - 'residential_units' table has the following columns:
        - index named 'unit_id' that serves as its identifier
        - 'building_id' corresponding to the index of the 'buildings' table

    Results
    -------
    - extends the 'residential_units' table, following the same schema as the
      'initialize_residential_units' model step
    """

    # Verify initial data characteristics
    '''
    ot.assert_orca_spec(OrcaSpec(
        '',
        TableSpec(
            'buildings',
            ColumnSpec('building_id', primary_key=True),
            ColumnSpec('residential_units', min=0)),
        TableSpec(
            'residential_units',
            ColumnSpec('unit_id', primary_key=True),
            ColumnSpec('building_id', foreign_key='buildings.building_id'))))
    '''

    old_units = residential_units.to_frame(residential_units.local_columns)
    bldgs = buildings.to_frame(['residential_units', 'deed_restricted_units'])

    # Filter for residential buildings not currently represented in
    # the units table
    new_bldgs = bldgs[~bldgs.index.isin(old_units.building_id)]
    new_bldgs = new_bldgs[new_bldgs.residential_units > 0]

    # Create new units, merge them, and update the table
    new_units = _create_empty_units(new_bldgs)
    all_units = dev.merge(old_units, new_units)
    all_units.index.name = 'unit_id'

    print "Creating %d residential units for %d new buildings" % \
        (len(new_units), len(new_bldgs))

    orca.add_table('residential_units', all_units)

    # Verify final data characteristics
    '''
Example #3
0
def add_buildings(buildings, new_buildings, remove_developed_buildings=True):

    old_buildings = buildings.to_frame(buildings.local_columns)
    new_buildings = new_buildings[buildings.local_columns]

    if remove_developed_buildings:
        unplace_agents = ["households", "jobs"]
        old_buildings = \
            _remove_developed_buildings(old_buildings, new_buildings,
                                        unplace_agents)

    all_buildings = dev.merge(old_buildings, new_buildings)

    orca.add_table("buildings", all_buildings)
Example #4
0
def add_buildings(buildings, new_buildings,
                  remove_developed_buildings=True):

    old_buildings = buildings.to_frame(buildings.local_columns)
    new_buildings = new_buildings[buildings.local_columns]

    if remove_developed_buildings:
        unplace_agents = ["households", "jobs"]
        old_buildings = \
            _remove_developed_buildings(old_buildings, new_buildings,
                                        unplace_agents)

    all_buildings = dev.merge(old_buildings, new_buildings)

    orca.add_table("buildings", all_buildings)
Example #5
0
def developer_reprocess(buildings, year, years_per_iter, jobs,
                        parcels, summary, parcel_is_allowed_func):
    # this takes new units that come out of the developer, both subsidized
    # and non-subsidized and reprocesses them as required - please read
    # comments to see what this means in detail

    # 20% of base year buildings which are "residential" have job spaces - I
    # mean, there is a ratio of job spaces to res units in residential
    # buildings of 1 to 5 - this ratio should be kept for future year
    # buildings
    s = buildings.general_type == "Residential"
    res_units = buildings.residential_units[s].sum()
    job_spaces = buildings.job_spaces[s].sum()

    to_add = res_units * .05 - job_spaces
    if to_add > 0:
        print "Adding %d job_spaces" % to_add
        res_units = buildings.residential_units[s]
        # bias selection of places to put job spaces based on res units
        print res_units.describe()
        print res_units[res_units < 0]
        add_indexes = np.random.choice(res_units.index.values, size=to_add,
                                       replace=True,
                                       p=(res_units/res_units.sum()))
        # collect same indexes
        add_indexes = pd.Series(add_indexes).value_counts()
        # this is sqft per job for residential bldgs
        add_sizes = add_indexes * 400
        print "Job spaces in res before adjustment: ", \
            buildings.job_spaces[s].sum()
        buildings.local.loc[add_sizes.index,
                            "non_residential_sqft"] += add_sizes.values
        print "Job spaces in res after adjustment: ",\
            buildings.job_spaces[s].sum()

    # the second step here is to add retail to buildings that are greater than
    # X stories tall - presumably this is a ground floor retail policy
    old_buildings = buildings.to_frame(buildings.local_columns)
    new_buildings = old_buildings.query(
       '%d == year_built and stories >= 4' % year)

    print "Attempting to add ground floor retail to %d devs" % \
        len(new_buildings)
    retail = parcel_is_allowed_func("retail")
    new_buildings = new_buildings[retail.loc[new_buildings.parcel_id].values]
    print "Disallowing dev on these parcels:"
    print "    %d devs left after retail disallowed" % len(new_buildings)

    # this is the key point - make these new buildings' nonres sqft equal
    # to one story of the new buildings
    new_buildings.non_residential_sqft = new_buildings.building_sqft / \
        new_buildings.stories * .8

    new_buildings["residential_units"] = 0
    new_buildings["residential_sqft"] = 0
    new_buildings["building_sqft"] = new_buildings.non_residential_sqft
    new_buildings["stories"] = 1
    new_buildings["building_type"] = "RB"

    # this is a fairly arbitrary rule, but we're only adding ground floor
    # retail in areas that are underserved right now - this is defined as
    # the location where the retail ratio (ratio of income to retail sqft)
    # is greater than the median
    ratio = parcels.retail_ratio.loc[new_buildings.parcel_id]
    new_buildings = new_buildings[ratio.values > ratio.median()]

    print "Adding %d sqft of ground floor retail in %d locations" % \
        (new_buildings.non_residential_sqft.sum(), len(new_buildings))

    all_buildings = dev.merge(old_buildings, new_buildings)
    orca.add_table("buildings", all_buildings)

    new_buildings["form"] = "retail"
    # this is sqft per job for retail use - this is all rather
    # ad-hoc so I'm hard-coding
    new_buildings["job_spaces"] = \
        (new_buildings.non_residential_sqft / 445.0).astype('int')
    new_buildings["net_units"] = new_buildings.job_spaces
    summary.add_parcel_output(new_buildings)

    # got to get the frame again because we just added rows
    buildings = orca.get_table('buildings')
    buildings_df = buildings.to_frame(
        ['year_built', 'building_sqft', 'general_type'])
    sqft_by_gtype = buildings_df.query('year_built >= %d' % year).\
        groupby('general_type').building_sqft.sum()
    print "New square feet by general type in millions:\n",\
        sqft_by_gtype / 1000000.0
Example #6
0
def developer_reprocess(buildings, year, years_per_iter, jobs,
                        parcels, summary, parcel_is_allowed_func):
    # this takes new units that come out of the developer, both subsidized
    # and non-subsidized and reprocesses them as required - please read
    # comments to see what this means in detail

    # 20% of base year buildings which are "residential" have job spaces - I
    # mean, there is a ratio of job spaces to res units in residential
    # buildings of 1 to 5 - this ratio should be kept for future year
    # buildings
    s = buildings.general_type == "Residential"
    res_units = buildings.residential_units[s].sum()
    job_spaces = buildings.job_spaces[s].sum()

    to_add = res_units * .05 - job_spaces
    if to_add > 0:
        print "Adding %d job_spaces" % to_add
        res_units = buildings.residential_units[s]
        # bias selection of places to put job spaces based on res units
        print res_units.describe()
        print res_units[res_units < 0]
        add_indexes = np.random.choice(res_units.index.values, size=to_add,
                                       replace=True,
                                       p=(res_units / res_units.sum()))
        # collect same indexes
        add_indexes = pd.Series(add_indexes).value_counts()
        # this is sqft per job for residential bldgs
        add_sizes = add_indexes * 400
        print "Job spaces in res before adjustment: ", \
            buildings.job_spaces[s].sum()
        buildings.local.loc[add_sizes.index,
                            "non_residential_sqft"] += add_sizes.values
        print "Job spaces in res after adjustment: ",\
            buildings.job_spaces[s].sum()

    # the second step here is to add retail to buildings that are greater than
    # X stories tall - presumably this is a ground floor retail policy
    old_buildings = buildings.to_frame(buildings.local_columns)
    new_buildings = old_buildings.query(
       '%d == year_built and stories >= 4' % year)

    print "Attempting to add ground floor retail to %d devs" % \
        len(new_buildings)
    retail = parcel_is_allowed_func("retail")
    new_buildings = new_buildings[retail.loc[new_buildings.parcel_id].values]
    print "Disallowing dev on these parcels:"
    print "    %d devs left after retail disallowed" % len(new_buildings)

    # this is the key point - make these new buildings' nonres sqft equal
    # to one story of the new buildings
    new_buildings.non_residential_sqft = new_buildings.building_sqft / \
        new_buildings.stories * .8

    new_buildings["residential_units"] = 0
    new_buildings["residential_sqft"] = 0
    new_buildings["deed_restricted_units"] = 0
    new_buildings["building_sqft"] = new_buildings.non_residential_sqft
    new_buildings["stories"] = 1
    new_buildings["building_type"] = "RB"

    # this is a fairly arbitrary rule, but we're only adding ground floor
    # retail in areas that are underserved right now - this is defined as
    # the location where the retail ratio (ratio of income to retail sqft)
    # is greater than the median
    ratio = parcels.retail_ratio.loc[new_buildings.parcel_id]
    new_buildings = new_buildings[ratio.values > ratio.median()]

    print "Adding %d sqft of ground floor retail in %d locations" % \
        (new_buildings.non_residential_sqft.sum(), len(new_buildings))

    all_buildings = dev.merge(old_buildings, new_buildings)
    orca.add_table("buildings", all_buildings)

    new_buildings["form"] = "retail"
    # this is sqft per job for retail use - this is all rather
    # ad-hoc so I'm hard-coding
    new_buildings["job_spaces"] = \
        (new_buildings.non_residential_sqft / 445.0).astype('int')
    new_buildings["net_units"] = new_buildings.job_spaces
    summary.add_parcel_output(new_buildings)

    # got to get the frame again because we just added rows
    buildings = orca.get_table('buildings')
    buildings_df = buildings.to_frame(
        ['year_built', 'building_sqft', 'general_type'])
    sqft_by_gtype = buildings_df.query('year_built >= %d' % year).\
        groupby('general_type').building_sqft.sum()
    print "New square feet by general type in millions:\n",\
        sqft_by_gtype / 1000000.0
Example #7
0
def initialize_new_units(buildings, residential_units):
    """
    This data maintenance step initializes units for buildings that have been
    newly created, conforming to the data requirements of the
    'residential_units' table.

    Data expectations
    -----------------
    - 'buildings' table has the following columns:
        - index that serves as its identifier
        - 'residential_units' (int, count of units in building)
    - 'residential_units' table has the following columns:
        - index named 'unit_id' that serves as its identifier
        - 'building_id' corresponding to the index of the 'buildings' table

    Results
    -------
    - extends the 'residential_units' table, following the same schema as the
      'initialize_residential_units' model step
    """

    # Verify initial data characteristics
    '''
    ot.assert_orca_spec(OrcaSpec(
        '',
        TableSpec(
            'buildings',
            ColumnSpec('building_id', primary_key=True),
            ColumnSpec('residential_units', min=0)),
        TableSpec(
            'residential_units',
            ColumnSpec('unit_id', primary_key=True),
            ColumnSpec('building_id', foreign_key='buildings.building_id'))))
    '''

    old_units = residential_units.to_frame(residential_units.local_columns)
    bldgs = buildings.to_frame(['residential_units', 'deed_restricted_units'])

    # Filter for residential buildings not currently represented in
    # the units table, and create new units
    new_bldgs = bldgs[~bldgs.index.isin(old_units.building_id)]
    new_bldgs = new_bldgs[new_bldgs.residential_units > 0]
    new_units = _create_empty_units(new_bldgs)

    # Filter for residential buildings where ADUs were added and
    # create new units
    old_units_by_bldg = old_units.groupby(['building_id']).agg({
        'unit_num':
        max,
        'num_units':
        'count'
    }).reset_index()
    old_units_by_bldg.rename(columns={
        'num_units': 'num_units_old',
        'unit_num': 'max_num_old'
    },
                             inplace=True)
    old_bldgs = bldgs[bldgs.index.isin(old_units.building_id)]
    old_bldgs = old_bldgs[old_bldgs.residential_units > 0]

    adu_bldgs = pd.merge(old_bldgs,
                         old_units_by_bldg,
                         left_index=True,
                         right_on='building_id')
    adu_bldgs['adu_count'] = \
        adu_bldgs.residential_units - adu_bldgs.num_units_old
    adu_bldgs = adu_bldgs[adu_bldgs.adu_count > 0]

    if len(adu_bldgs) > 0:
        new_adus = pd.DataFrame({
            'unit_residential_price':
            0.0,
            'unit_residential_rent':
            0.0,
            'num_units':
            1,
            'building_id':
            np.repeat(adu_bldgs.building_id,
                      adu_bldgs.adu_count.values.astype(int)),
            # counter of the AUDs in a building
            'unit_num_adu':
            np.concatenate([
                np.arange(num_adus)
                for num_adus in adu_bldgs.adu_count.values.astype(int)
            ]),
            # ADUs are not deed restricted
            'deed_restricted':
            0.0,
            'adu_count_start':
            np.repeat(adu_bldgs.max_num_old + 1,
                      adu_bldgs.adu_count.values.astype(int))
        }).sort_values(by=['building_id', 'unit_num_adu']).reset_index(
            drop=True)

        # update unit_num of ADUs to continue with the previous
        # unit_num of non-ADUs in the same buildings
        new_adus.unit_num = \
            new_adus.unit_num_adu + new_adus.adu_count_start
        new_adus.drop(columns=['adu_count_start', 'unit_num_adu'],
                      inplace=True)
        new_adus.index.name = 'unit_id'

        new_units = dev.merge(new_units, new_adus)
    else:
        print('No ADUs were built.')

    # Merge new units with old units and update the table

    all_units = dev.merge(old_units, new_units)
    all_units.index.name = 'unit_id'

    print("Creating %d residential units for %d new buildings" %
          (len(new_units), len(new_bldgs)))

    orca.add_table('residential_units', all_units)

    # Verify final data characteristics
    '''