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 '''
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)
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
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
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 '''