7. Population dislocation#
7.1 Setup general population data#
pop_dis = PopulationDislocation(client)
value_loss = "60354810e379f22e16560dbd"
bg_data = "603545f2dcda03378087e708"
# hua_result_id = "63ee615d62b9d001e6a2b660" # city
hua_result_id = "63ff8e895367c2261b4cb2ef" # island
pop_dis.load_remote_input_dataset("block_group_data", bg_data)
pop_dis.load_remote_input_dataset("value_loss_param", value_loss)
pop_dis.load_remote_input_dataset("housing_unit_allocation", hua_result_id)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[1], line 1
----> 1 pop_dis = PopulationDislocation(client)
2 value_loss = "60354810e379f22e16560dbd"
3 bg_data = "603545f2dcda03378087e708"
NameError: name 'PopulationDislocation' is not defined
7.2 Initial loop for dislocation#
The following code is used to create a set of dateframes for each hazard type and the combined damage. Each data frame has details on the population dislocation for the hazard.
# Create an empty dictionary to store the results
popdis_results_df = {}
popdis_results_df_mincols = {}
damage_types = {"flood_damage" : flood_damage,
"wind_damage" : wind_damage,
"surge_wave_damage" : surge_wave_damage,
"combined_dmg" : combined_dmg}
# loop through the damage types
for damage, damage_result in damage_types.items():
pop_dis.set_input_dataset("building_dmg", damage_result)
result_name = f"galveston-pop-disl-results_{damage}"
seed = 1111
pop_dis.set_parameter("result_name", result_name)
pop_dis.set_parameter("seed", seed)
pop_dis.run_analysis()
population_dislocation_result = pop_dis.get_output_dataset("result")
popdis_results_df[damage] = population_dislocation_result.get_dataframe_from_csv(low_memory=False)
# Keep HUID, prdis and dislocated columns
popdis_results_df_mincols[damage] = popdis_results_df[damage][['guid','huid', 'prdis', 'dislocated']]
# Print the number of dislocated housholds by HUID
print(f"For {damage} ",popdis_results_df_mincols[damage]['dislocated'].sum(), " households are dislocated")
For flood_damage 10067 households are dislocated
For wind_damage 14292 households are dislocated
For surge_wave_damage 10007 households are dislocated
For combined_dmg 14896 households are dislocated
7.3 Clean and merge dislocation data#
The following code loops through the damage type dataframes, cleans up the columns and prepares the data for a merge.
popdis_merge_df = {}
# loop through the damage types
for damage, damage_result in damage_types.items():
# Read in CSV and convert to dataframe
damage_df = damage_result.get_dataframe_from_csv(low_memory=False)
# For each damage type merge damage states and hazard exposure
popdis_merge_df[damage] = pd.merge(
right = popdis_results_df_mincols[damage],
left = damage_df[['guid','DS_0','DS_1','DS_2','DS_3','haz_expose']],
left_on='guid',
right_on='guid',
how='right')
# flag observations with damage exposure
condition1 = (popdis_merge_df[damage]['haz_expose'] == 'yes')
popdis_merge_df[damage][f'{damage}_exp'] = np.where((condition1), 1, 0)
# flag observations that are not dislocated and DS_3 > .5
# households that do not dislocate but have a high probability of damage
condition1 = (popdis_merge_df[damage]['dislocated'] == 0)
condition2 = (popdis_merge_df[damage]['DS_3'] > .5)
popdis_merge_df[damage]['dsds3flag'] = np.where((condition1) & (condition2), 1, 0)
# flag observations that are dislocated and DS_0 > .5
# households that dislocate but have a low probability of damage
condition1 = (popdis_merge_df[damage]['dislocated'] == 1)
condition2 = (popdis_merge_df[damage]['DS_0'] > .5)
popdis_merge_df[damage]['dsds0flag'] = np.where((condition1) & (condition2), 1, 0)
# rename popdis_merge_df with damage type
popdis_merge_df[damage] = popdis_merge_df[damage].rename(columns={"dsds3flag" : f"dsds3flag_{damage}",
"dsds0flag" : f"dsds0flag_{damage}",
"guid" : f"guid_{damage}",
"prdis" : f"prdis_{damage}",
"dislocated" : f"dislocated_{damage}",
"DS_0": f"DS_0_{damage}",
"DS_1": f"DS_1_{damage}",
"DS_2": f"DS_2_{damage}",
"DS_3": f"DS_3_{damage}",
"haz_expose": f"haz_expose_{damage}"})
# merge all the damage types
popdis_multihazard_df = pd.merge(right = popdis_merge_df['flood_damage'],
left = popdis_merge_df['wind_damage'],
left_on='huid',
right_on='huid',
how='outer')
popdis_multihazard_df = pd.merge(right = popdis_multihazard_df,
left = popdis_merge_df['surge_wave_damage'],
left_on='huid',
right_on='huid',
how='outer')
popdis_multihazard_df = pd.merge(right = popdis_multihazard_df,
left = popdis_merge_df['combined_dmg'],
left_on='huid',
right_on='huid',
how='outer')
# drop all the guid columns and rename guid_x to guid
popdis_multihazard_df = popdis_multihazard_df.drop(columns=['guid_flood_damage','guid_wind_damage','guid_surge_wave_damage'])
popdis_multihazard_df = popdis_multihazard_df.rename(columns={"guid_combined_dmg" : "guid"})
popdis_multihazard_df.columns
#popdis_multihazard_df.to_csv('./output/building/dislocation_results/dislocation_building.csv', index=False)
Index(['guid', 'DS_0_combined_dmg', 'DS_1_combined_dmg', 'DS_2_combined_dmg',
'DS_3_combined_dmg', 'haz_expose_combined_dmg', 'huid',
'prdis_combined_dmg', 'dislocated_combined_dmg', 'combined_dmg_exp',
'dsds3flag_combined_dmg', 'dsds0flag_combined_dmg',
'DS_0_surge_wave_damage', 'DS_1_surge_wave_damage',
'DS_2_surge_wave_damage', 'DS_3_surge_wave_damage',
'haz_expose_surge_wave_damage', 'prdis_surge_wave_damage',
'dislocated_surge_wave_damage', 'surge_wave_damage_exp',
'dsds3flag_surge_wave_damage', 'dsds0flag_surge_wave_damage',
'DS_0_wind_damage', 'DS_1_wind_damage', 'DS_2_wind_damage',
'DS_3_wind_damage', 'haz_expose_wind_damage', 'prdis_wind_damage',
'dislocated_wind_damage', 'wind_damage_exp', 'dsds3flag_wind_damage',
'dsds0flag_wind_damage', 'DS_0_flood_damage', 'DS_1_flood_damage',
'DS_2_flood_damage', 'DS_3_flood_damage', 'haz_expose_flood_damage',
'prdis_flood_damage', 'dislocated_flood_damage', 'flood_damage_exp',
'dsds3flag_flood_damage', 'dsds0flag_flood_damage'],
dtype='object')
7.4 Merge in infrastructure analyses on transportation and power#
# read in insfrastructure result from a CSV file
networkdamage_df = pd.read_csv("./output/final_inf_result/final_df_with_building.csv")
# for network df keep only the first unique guid - todo: This probably needs to be changed
networkdamage_df = networkdamage_df.drop_duplicates(subset=['guid'], keep='first')
networkdamage_df['guid'].describe()
# keep guid, power_back_time, transpo_back_time
networkdamage_df = networkdamage_df[['guid','average_power_back_time','average_transpo_back_time']]
# Considering with and without power/transpo in the next analyses
#networkdamage_df['average_transpo_back_time'] = 0.0 # Uncomment to exclude the impact of transportation on population displacement.
#networkdamage_df['average_power_back_time'] = 0.0 # Uncomment to exclude the impact of power on population displacement.
networkdamage_df
| guid | average_power_back_time | average_transpo_back_time | |
|---|---|---|---|
| 0 | 7916eaa8-0bfa-4b32-84ff-20f19a520f5c | 0.000 | 0.0 |
| 1 | 42167885-ea18-41b4-be8c-5c09c330d312 | 5.836 | 0.0 |
| 2 | 3dab0b4b-42eb-4df6-a5e1-c1882df41704 | 0.000 | 0.0 |
| 3 | e474c4ef-a091-47ab-85b4-ef0459e37834 | 0.000 | 0.0 |
| 73 | 335d18da-7a60-4f4d-8c97-d35e0f3a1360 | 0.000 | 0.0 |
| ... | ... | ... | ... |
| 33297 | 7a415cb6-d212-450b-b139-f005c89b9656 | 0.000 | 0.0 |
| 33298 | 74e5fedf-9e22-4434-9128-65ca793df7d2 | 0.000 | 0.0 |
| 33299 | 1ac5be10-582c-46b2-91ed-469f684bb886 | 0.000 | 0.0 |
| 33300 | fbcfb6d6-de13-42fa-9839-d7c80afc651d | 0.000 | 0.0 |
| 33301 | 2ee961c9-cd94-499e-b1fe-3e0220a440ea | 0.000 | 0.0 |
22015 rows × 3 columns
networkdamage_df['guid'].describe()
count 22015
unique 22015
top 7916eaa8-0bfa-4b32-84ff-20f19a520f5c
freq 1
Name: guid, dtype: object
popdis_multihazard_df['guid'].describe()
count 33302
unique 22015
top 2669f722-ae95-4181-90a8-9c4755b7b29c
freq 191
Name: guid, dtype: object
# merge network damage with popdis_multihazard_df by guid
popdis_multihazard_network_df = pd.merge(right = popdis_multihazard_df,
left = networkdamage_df,
left_on='guid',
right_on='guid',
how='inner')
popdis_multihazard_network_df['guid'].describe()
count 33302
unique 22015
top 2669f722-ae95-4181-90a8-9c4755b7b29c
freq 191
Name: guid, dtype: object
7.5 Add Flag for Power Outage and Road Closure#
Choosing cutoffs for 3 days without power and 7 days without road access.
These cutoffs are expert judgments and could be changed.
# If the power_back_time greater than 7 days then dislocated_power = 1
condition1 = (popdis_multihazard_network_df['average_power_back_time'] > 3)
popdis_multihazard_network_df['powerflag'] = np.where((condition1), 1, 0)
# if transpo_back_time greater than 14 days then dislocated_transpo = 1
condition1 = (popdis_multihazard_network_df['average_transpo_back_time'] > 7)
popdis_multihazard_network_df['transpoflag'] = np.where((condition1), 1, 0)
# loop through the damage types
for damage, damage_result in damage_types.items():
# add case where dislocated = 0 but dislocated_power == 1
condition1 = (popdis_multihazard_network_df[f'dislocated_{damage}'] == 0)
condition2 = (popdis_multihazard_network_df['powerflag'] == 1)
popdis_multihazard_network_df[f'powerflag_{damage}'] = \
np.where((condition1) & (condition2), 1, 0)
# add case where dislocated = 0 but dislocated_transpo == 1
condition1 = (popdis_multihazard_network_df[f'dislocated_{damage}'] == 0)
condition2 = (popdis_multihazard_network_df['transpoflag'] == 1)
popdis_multihazard_network_df[f'transpoflag_{damage}'] = \
np.where((condition1) & (condition2), 1, 0)
# identify safe occupany housholds no flags
condition1 = (popdis_multihazard_network_df[f'dsds3flag_{damage}'] == 0)
condition2 = (popdis_multihazard_network_df[f'dsds0flag_{damage}'] == 0)
condition3 = (popdis_multihazard_network_df[f'powerflag_{damage}'] == 0)
condition4 = (popdis_multihazard_network_df[f'transpoflag_{damage}'] == 0)
popdis_multihazard_network_df[f'safeflag_{damage}'] = \
np.where((condition1) & (condition2) & (condition3) & (condition4), 1, 0)
# how many households have hazard exposure = yes
hazexpose = popdis_multihazard_network_df[f'{damage}_exp'].sum()
# how many households have dsds0flag or dsds3flag true
totaldislocation = popdis_multihazard_network_df[f'dislocated_{damage}'].sum()
choicedislocation = popdis_multihazard_network_df[f'dsds0flag_{damage}'].sum()
hazardnondislocation = popdis_multihazard_network_df[f'dsds3flag_{damage}'].sum()
nopower_nodislocation = popdis_multihazard_network_df[f'powerflag_{damage}'].sum()
notranspo_nodislocation = popdis_multihazard_network_df[f'transpoflag_{damage}'].sum()
safe_occupancy = popdis_multihazard_network_df[f'safeflag_{damage}'].sum()
print(f"{damage} Number of households with hazard exposure: {hazexpose}")
print(f"{damage} Total number of dislocated households: {totaldislocation}")
print(f"{damage} Number of households that dislocate but have a low probability of damage: {choicedislocation}")
print(f"{damage} Number of households that do not dislocate and have no power: {nopower_nodislocation}")
print(f"{damage} Number of households that do not dislocate and have no connectivity to mainland: {notranspo_nodislocation}")
print(f"{damage} Number of households with safe occupancy: {safe_occupancy}")
flood_damage Number of households with hazard exposure: 32964
flood_damage Total number of dislocated households: 10067
flood_damage Number of households that dislocate but have a low probability of damage: 1190
flood_damage Number of households that do not dislocate and have no power: 4821
flood_damage Number of households that do not dislocate and have no connectivity to mainland: 5581
flood_damage Number of households with safe occupancy: 25638
wind_damage Number of households with hazard exposure: 33295
wind_damage Total number of dislocated households: 14292
wind_damage Number of households that dislocate but have a low probability of damage: 1989
wind_damage Number of households that do not dislocate and have no power: 3307
wind_damage Number of households that do not dislocate and have no connectivity to mainland: 3802
wind_damage Number of households with safe occupancy: 26749
surge_wave_damage Number of households with hazard exposure: 30463
surge_wave_damage Total number of dislocated households: 10007
surge_wave_damage Number of households that dislocate but have a low probability of damage: 1391
surge_wave_damage Number of households that do not dislocate and have no power: 4514
surge_wave_damage Number of households that do not dislocate and have no connectivity to mainland: 5372
surge_wave_damage Number of households with safe occupancy: 25756
combined_dmg Number of households with hazard exposure: 33295
combined_dmg Total number of dislocated households: 14896
combined_dmg Number of households that dislocate but have a low probability of damage: 1333
combined_dmg Number of households that do not dislocate and have no power: 3142
combined_dmg Number of households that do not dislocate and have no connectivity to mainland: 3655
combined_dmg Number of households with safe occupancy: 27506
7.6 Modify dislocation for HHSR#
The HHSR model assumes that if a household dislocates then the structure is not safe to occupy and will take time to recover. However, the dislocation model has households that dislocate but the structure has a high probability of being safe to occupy. Vice versa, the model also has households that do not dislcate but the structure has a high probability of being unsafe to occupy.
If a household has choice dislocation (dsds0flag_) then dislocation should be set to 0.
If a household has unsafe occupancy (dsds3flag_) then dislocation should be set to 1.
popdis_hhrs_df = popdis_multihazard_network_df.copy()
# loop through the damage types
for damage, damage_result in damage_types.items():
# update dislocation if dsds0flag_ = 1
totaldislocation1 = popdis_hhrs_df[f'dislocated_{damage}'].sum()
condition1 = (popdis_hhrs_df[f'dsds0flag_{damage}'] == 1)
popdis_hhrs_df[f'dislocated_{damage}'] = \
np.where((condition1), 0, popdis_hhrs_df[f'dislocated_{damage}'])
totaldislocation2 = popdis_hhrs_df[f'dislocated_{damage}'].sum()
print(f"{damage} Swith Choice Dislocation Total number of dislocated households: {totaldislocation1} {totaldislocation2}")
# update dislocation if dsds3flag_ = 1
totaldislocation1 = popdis_hhrs_df[f'dislocated_{damage}'].sum()
condition1 = (popdis_hhrs_df[f'dsds3flag_{damage}'] == 1)
popdis_hhrs_df[f'dislocated_{damage}'] = \
np.where((condition1), 1, popdis_hhrs_df[f'dislocated_{damage}'])
totaldislocation2 = popdis_hhrs_df[f'dislocated_{damage}'].sum()
print(f"{damage} Switch unsafe occupancy Total number of dislocated households: {totaldislocation1} {totaldislocation2}")
flood_damage Swith Choice Dislocation Total number of dislocated households: 10067 8877
flood_damage Switch unsafe occupancy Total number of dislocated households: 8877 8971
wind_damage Swith Choice Dislocation Total number of dislocated households: 14292 12303
wind_damage Switch unsafe occupancy Total number of dislocated households: 12303 12715
surge_wave_damage Swith Choice Dislocation Total number of dislocated households: 10007 8616
surge_wave_damage Switch unsafe occupancy Total number of dislocated households: 8616 8909
combined_dmg Swith Choice Dislocation Total number of dislocated households: 14896 13563
combined_dmg Switch unsafe occupancy Total number of dislocated households: 13563 14288
popdis_hhrs_df.columns
Index(['guid', 'average_power_back_time', 'average_transpo_back_time',
'DS_0_combined_dmg', 'DS_1_combined_dmg', 'DS_2_combined_dmg',
'DS_3_combined_dmg', 'haz_expose_combined_dmg', 'huid',
'prdis_combined_dmg', 'dislocated_combined_dmg', 'combined_dmg_exp',
'dsds3flag_combined_dmg', 'dsds0flag_combined_dmg',
'DS_0_surge_wave_damage', 'DS_1_surge_wave_damage',
'DS_2_surge_wave_damage', 'DS_3_surge_wave_damage',
'haz_expose_surge_wave_damage', 'prdis_surge_wave_damage',
'dislocated_surge_wave_damage', 'surge_wave_damage_exp',
'dsds3flag_surge_wave_damage', 'dsds0flag_surge_wave_damage',
'DS_0_wind_damage', 'DS_1_wind_damage', 'DS_2_wind_damage',
'DS_3_wind_damage', 'haz_expose_wind_damage', 'prdis_wind_damage',
'dislocated_wind_damage', 'wind_damage_exp', 'dsds3flag_wind_damage',
'dsds0flag_wind_damage', 'DS_0_flood_damage', 'DS_1_flood_damage',
'DS_2_flood_damage', 'DS_3_flood_damage', 'haz_expose_flood_damage',
'prdis_flood_damage', 'dislocated_flood_damage', 'flood_damage_exp',
'dsds3flag_flood_damage', 'dsds0flag_flood_damage', 'powerflag',
'transpoflag', 'powerflag_flood_damage', 'transpoflag_flood_damage',
'safeflag_flood_damage', 'powerflag_wind_damage',
'transpoflag_wind_damage', 'safeflag_wind_damage',
'powerflag_surge_wave_damage', 'transpoflag_surge_wave_damage',
'safeflag_surge_wave_damage', 'powerflag_combined_dmg',
'transpoflag_combined_dmg', 'safeflag_combined_dmg'],
dtype='object')
# loop through the damage types to consider dislocation due to power outage and road closure
for damage, damage_result in damage_types.items():
# update dislocation if powerflag & transpoflag = 1
totaldislocation1 = popdis_hhrs_df[f'dislocated_{damage}'].sum()
condition1 = (popdis_hhrs_df[f'powerflag_{damage}'] == 1)
condition2 = (popdis_hhrs_df[f'transpoflag_{damage}'] == 1)
popdis_hhrs_df[f'dislocated_{damage}'] = \
np.where(((condition1) | (condition2)), 1, popdis_hhrs_df[f'dislocated_{damage}'])
totaldislocation2 = popdis_hhrs_df[f'dislocated_{damage}'].sum()
print(f"{damage} Total number of dislocated households without and with power and tranportation effects: {totaldislocation1} {totaldislocation2}")
flood_damage Total number of dislocated households without and with power and tranportation effects: 8971 15351
wind_damage Total number of dislocated households without and with power and tranportation effects: 12715 16867
surge_wave_damage Total number of dislocated households without and with power and tranportation effects: 8909 14771
combined_dmg Total number of dislocated households without and with power and tranportation effects: 14288 18026
# Keep only columns needed for HHSR
# drop all columns with flag
popdis_hhrs_df = popdis_hhrs_df[popdis_hhrs_df.columns.drop(list(popdis_hhrs_df.filter(regex='flag')))]
# drop all columns with DS
popdis_hhrs_df = popdis_hhrs_df[popdis_hhrs_df.columns.drop(list(popdis_hhrs_df.filter(regex='DS')))]
# drop all columns with prdis
popdis_hhrs_df = popdis_hhrs_df[popdis_hhrs_df.columns.drop(list(popdis_hhrs_df.filter(regex='prdis')))]
# drop all columns with haz_expose
popdis_hhrs_df = popdis_hhrs_df[popdis_hhrs_df.columns.drop(list(popdis_hhrs_df.filter(regex='haz_expose')))]
# drop all columns with exp
popdis_hhrs_df = popdis_hhrs_df[popdis_hhrs_df.columns.drop(list(popdis_hhrs_df.filter(regex='exp')))]
# Drop column named dislocated
# popdis_hhrs_df = popdis_hhrs_df.drop(columns=['dislocated'])
popdis_hhrs_df.columns
Index(['guid', 'average_power_back_time', 'average_transpo_back_time', 'huid',
'dislocated_combined_dmg', 'dislocated_surge_wave_damage',
'dislocated_wind_damage', 'dislocated_flood_damage'],
dtype='object')
# Adding required columns for running the HHRS model from IN-CORE
# HHRS code in IN-CORE needs to be edited; race, hispan, ownershp data is no more required
popdis_hhrs_df = pd.merge(right = popdis_results_df[damage][['huid','blockid', 'race', 'hispan', 'ownershp']],
left = popdis_hhrs_df,
left_on='huid',
right_on='huid',
how='inner')
popdis_hhrs_df['guid'].describe()
count 33302
unique 22015
top 2669f722-ae95-4181-90a8-9c4755b7b29c
freq 191
Name: guid, dtype: object
dislocated_types = ['dislocated_flood_damage', 'dislocated_wind_damage', 'dislocated_surge_wave_damage', 'dislocated_combined_dmg']
hhrs_dislocation_dataset_names = {}
for dislocation in dislocated_types:
popdis_hhrs_df_temp = pd.DataFrame()
popdis_hhrs_df_temp = popdis_hhrs_df[['guid', 'huid', 'blockid', 'race', 'hispan', 'ownershp', dislocation]]
popdis_hhrs_df_temp = popdis_hhrs_df_temp.rename(columns={dislocation: 'dislocated'})
popdis_hhrs_df_temp['dislocated'] = popdis_hhrs_df_temp['dislocated'].astype(bool)
popdis_hhrs_dataset = Dataset.from_dataframe(popdis_hhrs_df_temp,
name=f"popdis_hhrs_dataset_{dislocation}",
data_type="incore:popDislocation")
hhrs_dislocation_dataset_names[f"popdis_hhrs_dataset_{dislocation}"] = popdis_hhrs_dataset
