diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index d2e62ec..4ea9e5a 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -23,7 +23,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: - python-version: '3.11' + python-version: '3.12.4' # ADJUST THIS: install all dependencies (including pdoc) - run: pip install pipreqs @@ -52,4 +52,4 @@ jobs: url: ${{ steps.deployment.outputs.page_url }} steps: - id: deployment - uses: actions/deploy-pages@v2 + uses: actions/deploy-pages@v2 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 0bc9d6d..8f94f6f 100644 --- a/.gitignore +++ b/.gitignore @@ -77,15 +77,11 @@ target/ # exclude real data from source control by default /data/raw -/data/processed /data/interim /data/external -# exclude figures until the paper is not on the arxiv -/figures - -# exclude for now, keep later -/features +# exclude reports until the paper is not on the arxiv +/reports # Mac OS-specific storage files .DS_Store @@ -101,27 +97,38 @@ target/ .idea/ cache/ -# Raw country-specific experiment results -experiments/Dominica -experiments/Saint Lucia +# exclude config files but keep Example.yaml +/config/* +!/config/Example.yaml -# Internal reports -/reports +# exclude data_preparation from source control by default +/data_preparation/* +!/data_preparation/Example -# Input data preparation scripts -/scripts +# exclude data_preparation from source control by default +/data/generated/* +!/data/generated/Example -# Exclude Dominica-specific config -/config/Dominica.yaml +# exclude data but keep the Example folder or file +/data/processed/asset_impacts/* +!/data/processed/asset_impacts/Example -# Exclude Saint-Lucia specific config -/config/SaintLucia.yaml +/data/processed/household_survey/* +!/data/processed/household_survey/Example.csv -# Exclude Nigeria specific config -/config/Nigeria.yaml +data/processed/population_impacts/* +!/data/processed/population_impacts/Example -# Exclude reports -/reports +# exclude drafts folder +/drafts + +# exclude notebooks but keep the Example folder +/notebooks/* +!/notebooks/Example + +# exclude results and keep only the Example folder +/results/* +!/results/Example -# Exclude experiment results -/results \ No newline at end of file +# exlcude todo folder +/todo \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..dc0525a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,93 @@ +# Contributing + +We welcome contributions to the Unbreakable project! Whether you're fixing bugs, adding new features, improving documentation, or providing feedback, your help is appreciated. + +## How to Contribute + +### 1. Fork the Repository + +- Click the **Fork** button at the top right of the [repository page](https://github.com/mikhailsirenko/unbreakable) to create your own copy of the project. + +### 2. Clone Your Fork + +- Clone your forked repository to your local machine: + + ```bash + git clone https://github.com/your-username/unbreakable.git + cd unbreakable + ``` + +### 3. Create a New Branch + +- Create a new branch for your feature or bug fix: + + ```bash + git checkout -b my-feature-branch + ``` + +### 4. Make Changes + +- Implement your changes in the codebase. +- Follow the existing code style and conventions. +- Include comments and docstrings where appropriate. +- Update or add documentation as needed. + +### 5. Commit Changes + +- Stage your changes and commit with a descriptive message: + + ```bash + git add . + git commit -m "Description of your changes" + ``` + +### 6. Push to Your Fork + +- Push your branch to your forked repository on GitHub: + + ```bash + git push origin my-feature-branch + ``` + +### 7. Submit a Pull Request + +- Go to the original repository and click on **Pull Requests**, then **New Pull Request**. +- Select your branch from the **compare** dropdown. +- Provide a clear and descriptive title and description for your pull request. +- Submit the pull request for review. + +## Reporting Issues + +- If you encounter a bug or have a feature request, please open an [issue](https://github.com/mikhailsirenko/unbreakable/issues) on GitHub. +- Provide detailed information about the issue, including steps to reproduce it if applicable. + +## Code Style Guidelines + +- Follow the existing coding style and structure. +- Use meaningful variable and function names. +- Keep functions and classes focused and concise. +- Write tests for new features or bug fixes when possible. + +## Testing + +- Ensure that all existing tests pass before submitting a pull request. +- Add new tests to cover your changes. +- Run tests using: + + ```bash + python -m unittest discover tests + ``` + +## Documentation + +- Update the `README.md` or relevant documentation files if your changes affect them. +- Ensure that code is well-documented with comments and docstrings. + +## Communication + +- Feel free to contact the project maintainers for guidance. +- Be respectful and considerate in all interactions. + +## License + +By contributing to Unbreakable, you agree that your contributions will be licensed under Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0). diff --git a/README.md b/README.md index 36b279e..a33457e 100644 --- a/README.md +++ b/README.md @@ -1,46 +1,225 @@ -# What is unbreakable? -Unbreakable is a stochastic simulation model for assessing the resilience of households to natural disasters. +# unbreakable -## Background +Unbreakable is a simulation tool that helps estimate how disasters affect households, showing how different social groups recover and how policies can reduce the damage. -## Model Overview +## Motivation -## Getting Started +Natural disasters are becoming more frequent and intense, with a significant rise in events over recent decades. According to the [UNDRR](https://www.undrr.org/media/48008/download?startDownload=20240603), the number of recorded disasters nearly doubled from 4,212 between 1980-1999 to 7,348 between 2000-2019. In 2023, extreme weather events caused massive economic losses of 280 million USD ([PreventionWeb](https://www.preventionweb.net/news/europe-spotlight-global-economic-losses-catastrophes-reach-usd-280-billion-2023)) and impacted 93.1 million people globally ([EM-DAT](https://civil-protection-knowledge-network.europa.eu/media/2023-disasters-numbers-significant-year-disaster-impact)). + +Disasters do not affect all populations equally. Lower-income households are more vulnerable, as they often lack adequate resources for protection and recovery ([Bangalore et al., 2016](http://hdl.handle.net/10986/25335); [Walsh & Hallegatte, 2020](https://link.springer.com/article/10.1007/s41885-019-00047-x)). Vulnerable groups like female-headed households and people with disabilities are also disproportionately impacted. + +Beyond economic loss, disasters affect overall well-being, which isn’t fully captured by traditional metrics. To better understand these broader impacts, we need alternative approaches. + +Unbreakable is a simulation tool designed to: + +1. Estimate disaster impacts on different social groups. +2. Analyze effects across economic, poverty, and well-being dimensions. +3. Explore how policy interventions can reduce these impacts. + +## Project Structure -### Prerequisites -The model is developed in Python 3.9 and relies on standard packages. The easiest way to install them is to use [Anaconda](https://www.anaconda.com/products/individual) with the `requirements.txt` file: ```bash -conda create --name unbreakable --file requirements.txt +unbreakable/ +├── config/ # Simulation model run configuration files +├── data/ # Data directory +│ ├── generated/ # Generated data, e.g., pre-computed reconstruction rates +│ ├── processed/ # Processed data used as an input into simulation model +│ └── raw/ # Raw data +├── data_preparation/ # Data preprocessing notebooks +├── docs/ # Documentation +├── notebooks/ # Analysis notebooks +├── unbreakable/ # Main package +│ ├── analysis/ # Analysis modules +│ ├── experiments/ # Experiment setup and runner +│ ├── modules/ # Core simulation modules +│ └── utils/ # Utility functions mainly for data preparation +├── results/ # Simulation results +├── tests/ # Unit tests +├── CONTRIBUTING.md # Guidelines for contributing to the project +├── README.md # Project overview and instructions +├── requirements.txt # List of dependencies +└── setup.py # Installation script ``` -### Installation -Clone the repository from GitHub using the following: -```bash -git clone https://github.com/mikhailsirenko/unbreakable +## Installation + +1. Clone the repository: + + ```bash + git clone https://github.com/mikhailsirenko/unbreakable.git + cd unbreakable + ``` + +2. Create a virtual environment with conda (optional but recommended): + + ```bash + conda create --name unbreakable + conda activate unbreakable + ``` + +3. Install dependencies: + + ```bash + pip install -r requirements.txt + ``` + +4. Install the package in editable mode: + + ```bash + pip install -e . + ``` + +## Basic Usage + +To run a simulation: + +```python +python unbreakable/example.py ``` -### Repository Structure +The `example.py` script requires specifying disaster types, their timing (immediate or at a specific year, e.g., year 5), and return periods. By default, `example.py` simulates the immediate impact of a flood with a return period of 100 years. +You also need to specify the number of replications with `n_scenarios`. The model is stochastic, and to obtain robust results, multiple replications are necessary. In each run, the model randomly selects which households are affected and the amount of assets they lose. By default, `n_scenarios = 1,000`. -### Usage -You run the model from the command line with the default parameters using: -```bash -python unbreakable/run.py +For a more comprehensive description, please refer to the User Manual or the detailed documentation in the `docs/` directory. + +## Data + +The model uses three main types of data: + +1. Household survey data (`data/processed/household_survey/`), +2. Asset impact data (`data/processed/asset_impact/`), or +3. Population impact data (`data/processed/population_impacts/`) + +Household survey data contains information on households' socio-economic attributes and dwelling materials. Asset impact data provides information about potential damage to total assets of a spatial unit (e.g., a district). Population impacts data contains information about the number of individuals affected by a disaster. + +The repository contains example data of all types which were generated with `unbreakable/utils/data_generator.py`. + +## Configuration + +Simulations are configured using YAML files in the `config/` directory. The `Example.yaml` file provides an example configuration. You can modify this file to set up your simulation parameters, including: + +- Macro-economic parameters of the case country. +- Disaster-related parameters, including whether households would lose their income due to disaster. +- Which household characteristics must be estimated and randomized. +- Policy interventions, e.g., adaptive social protection. +- Uncertainties. + +## Model Components + +The core model components are located in the `unbreakable/modules/` directory: + +- `disaster_impact.py`: Simulates disaster impacts on households. +- `dwelling_vulnerability.py`: Calculates dwelling vulnerability based on construction materials. +- `household_recovery.py`: Models household recovery processes over time. +- `policy_interventions.py`: Implements policy interventions such as cash transfers or retrofitting. +- `socioeconomic_impact.py`: Assesses economic, poverty, and well-being impacts. + +## How It Works + +The Unbreakable Model stored in `model.py` follows a step-by-step process to simulate disaster events and their impacts. The basic idea is that we pass the households' data frame through a set of functions representing different stages of the simulation. The pipeline works as follows: + +1. **Data Loading and Preparation**: + - Load household data, disaster impact data, and reconstruction rates. + - Prepare the household data, estimate missing attributes (e.g., savings) and randomize them. + +2. **Disaster Impact Calculation**: + - Calculate compound impacts if multiple disaster events are specified. + - Determine the years until the next event for each disaster. + +3. **Spatial Unit Iteration**: + - The model iterates over each specified spatial unit (e.g., regions, cities). + +4. **Disaster Event Simulation**: + - For each spatial unit, the model simulates multiple disaster events sequentially. + - Each event's impact is calculated based on either the percentage of population affected or Probable Maximum Loss (PML). + +5. **Household Impact Distribution**: + - The disaster impact is distributed among households based on their vulnerability. + - Households are classified as affected or unaffected. + +6. **Recovery Simulation**: + - Calculate or use precomputed household reconstruction rates. + - Estimate the socioeconomic impact on households, including consumption, poverty and well-being losses. + +7. **Policy Interventions**: + - The model allows for the application of policy interventions, such as adaptive social protection or retrofitting policies. + +8. **Cumulative Impact Tracking**: + - The model keeps track of cumulative impacts across multiple events. + +9. **Outcome Calculation**: + - Calculate various metrics for each spatial unit after all events have been simulated. + +This pipeline allows for the simulation of multiple disasters over time, assessment of cumulative impacts, and evaluation of policy interventions at various stages. + +```mermaid +graph TD + A[Start] --> B[Load and Prepare Data] + B --> C[Calculate Compound Impact] + C --> D[Calculate Years Until Next Event] + D --> E[Iterate Over Spatial Units] + E --> F[Iterate Over Disaster Events] + F --> G[Simulate Disaster] + G --> H[Apply Policy Interventions] + H --> I[Estimate Socioeconomic Impact] + I --> J[Update Cumulative Impact] + J --> K{More Events?} + K -->|Yes| F + K -->|No| L[Calculate Outcomes for Spatial Unit] + L --> M{More Spatial Units?} + M -->|Yes| E + M -->|No| N[End] + + subgraph Simulate Disaster + G1[Calculate Dwelling Vulnerability] + G2[Distribute Disaster Impact] + G3[Determine Affected Households] + G4[Calculate Reconstruction Rates] + G1 --> G2 --> G3 --> G4 + end ``` -## Documentation -Detailed model documentation, including function descriptions and usage examples, is available [here](https://mikhailsirenko.github.io/unbreakable/src.html). +## Analysis + +Analysis modules in `unbreakable/analysis/` include: + +- `distributional_metrics.py`: Analyzes impacts across different groups +- `economic_metrics.py`: Calculates economic impact metrics +- `metric_calculator.py`: Analyzes household-level impacts +- `poverty_metrics.py`: Computes poverty-related metrics +- `resilience_metrics.py`: Calculates resilience indicators + +Jupyter notebooks for analysis are available in the `notebooks/` directory. These notebooks demonstrate how to interpret the simulation outcomes and visualize results. + +## Results + +Simulation results are stored in the `results/` directory. The `Example/` subdirectory contains example results. + +## Note for Users + +This model uses algorithms and data analysis techniques. While it strives for accuracy, real-world scenarios may differ. Use the results only as a guide for decision-making, always complemented by expert knowledge and local context. ## Contributing -## Authors -*Mikhail Sirenko* and *Bramka Arga Jafino*. +We welcome contributions to the Unbreakable project. Please refer to our [`CONTRIBUTING.md`](CONTRIBUTING.md) for information on submitting pull requests, reporting issues, or suggesting improvements. ## License -The project license is CC BY 3.0 IGO. + +This project is licensed under Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0). + +## Citation + +1. If you use this tool in your research, please cite it as: + + Sirenko, M. & Jafino, B. A. (2024). Unbreakable: A Simulation Tool for Estimating Socio-Economic Impacts of Disaster on Households. GitHub repository: + +2. The original World Bank report and research paper: + + Bangalore, M., Hallegatte, S., Vogt-Schilb, A., Rozenberg, J. (2017). Unbreakable: Building the Resilience of the Poor in the Face of Natural Disasters. Climate Change and Development. Washington, DC: World Bank. . + + Walsh, B., & Hallegatte, S. (2020). Measuring natural risks in the Philippines: Socioeconomic resilience and wellbeing losses. Economics of Disasters and Climate Change, 4(2), 249-293. ## Contact -For inquiries or collaboration, feel free to reach out to [Mikhail Sirenko](https://twitter.com/mikhailsirenko). -## References -Hallegatte, S., Vogt-Schilb, A., Bangalore, M., & Rozenberg, J. (2017). *Unbreakable: Building the Resilience of the Poor in the Face of Natural Disasters*. Climate Change and Development. Washington, DC: World Bank. [http://hdl.handle.net/10986/25335](http://hdl.handle.net/10986/25335) \ No newline at end of file +For questions or feedback, please contact Mikhail Sirenko at msirenko at worldbank.org. diff --git a/config/Example.yaml b/config/Example.yaml new file mode 100644 index 0000000..7f7d243 --- /dev/null +++ b/config/Example.yaml @@ -0,0 +1,111 @@ +# --------------------------------- Constants -------------------------------- # +constants: + country: Example + + # Each spatial unit has an array of outcomes that are calculated for it + spatial_units: + - region_1 + - region_2 + - region_3 + + # Global economic parameters specific to the country + economic_params: + average_productivity: 0.25 # average of cgdpo / cn for the last 5 years from the Penn World Table https://www.rug.nl/ggdc/productivity/pwt/?lang=en + income_and_expenditure_growth: 0.02 # assumption source: ? + consumption_utility: 1.5 # assumption source: Hallegatte et al. (2017) choose a standard value of 1.5 to represent the elasticity of the marginal utility of consumption + discount_rate: 0.04 # assumption source: ? + + # Recovery parameters + recovery_params: + use_precomputed_reconstruction_rates: true + lambda_increment: 0.01 + max_years: 10 + + # Disaster parameters + disaster_params: + impact_data_type: assets # population or assets + disaster_impact_params: + add_income_loss: true + poverty_bias_factor: 1.0 + distribution: uniform + max_bias: 1.5 + min_bias : 0.5 + determine_affected_params: + loss_margin_pct: 0.05 + max_random_threshold: 1.0 + min_random_threshold: 0 + num_simulations: 10000 + + # Estimation and randomization parameters + income_params: + estimate: true + randomize: true + distribution: uniform + inc_exp_ratio: 1.3 # assumption source? + delta: 0.1 # absolute deviation from the base income to expenditure ratio + savings_params: + estimate: true + randomize: true + cap_with_max_savings_rate: false # whether to cap the savings rate with the maximum savings rate + distribution: uniform + delta: 0.01 # absolute deviation from the base savings rate + max_savings_rate: 0.1 # maximum savings rate to prevent unrealistic values during randomization + rent_params: + estimate: true + randomize: true + distribution: uniform + pct_of_income: 0.14 # assumption source? + delta: 0.05 # absolute deviation from the base rent as a percentage of income + dwelling_vulnerability_params: + randomize: true + distribution: uniform + low: 0.9 + high: 1.1 + min_threshold: 0.2 # with vulnerability <= 0.13, recovery rate can be up to 5 + max_threshold: 0.9 # with vulnerability >= 0.98, recovery rate skyrockets to 10 + + min_households: 10000 + atol: 100000 + + # Analysis parameters + analysis_params: + save_households: false + save_consumption_recovery: false + distributional_impacts: true + socioeconomic_attributes: + - female_headed + - urban + - literacy + + +# ------------------------------- Policy levers ------------------------------ # +# ASP: Adaptive social protection +# The naming convention is: + +# The following target groups are currently specified: all, poor, poor_near_poor1.25, poor_near_poor2.0 +# There are no limitations on the top-up percentage + +# Retrofitting: Retrofitting of vulnerable houses +# The naming convention is: +# The following levels are currently specified: Basic, Intermediate, Advanced +# Currently, the retrofitting is available only for Dominica + +# levers: +# 0: none +# 1: asp:all+10 +# 2: asp:all+30 +# 3: asp:all+50 +# 4: asp:poor+10 +# 5: asp:poor+30 +# 6: asp:poor+50 +# 7: asp:poor_near_poor1.25+10 +# 8: asp:poor_near_poor1.25+30 +# 9: asp:poor_near_poor1.25+50 +# 10: asp:poor_near_poor2.0+10 +# 11: asp:poor_near_poor2.0+30 +# 12: asp:poor_near_poor2.0+50 + +# ------------------------------- Uncertainties ------------------------------ # +uncertainties: + +# References +# 1. Hallegatte,Stephane; Vogt-Schilb,Adrien Camille; Bangalore,Mook; Rozenberg,Julie. Unbreakable: building the resilience of the poor in the face of natural disasters (English). Climate Change and Development Washington, D.C.: World Bank Group. http://documents.worldbank.org/curated/en/512241480487839624/Unbreakable-building-the-resilience-of-the-poor-in-the-face-of-natural-disasters \ No newline at end of file diff --git a/config/Nigeria.yaml b/config/Nigeria.yaml deleted file mode 100644 index 194c35d..0000000 --- a/config/Nigeria.yaml +++ /dev/null @@ -1,138 +0,0 @@ -# --------------------------------- Constants -------------------------------- # -constants: - # Case study params - country: Nigeria - regions: - - 'Abia' - - 'Abuja Federal Capital Territory' - - 'Adamawa' - - 'Akwa Ibom' - - 'Anambra' - - 'Bauchi' - - 'Bayelsa' - - 'Benue' - - 'Cross River' - - 'Delta' - - 'Ebonyi' - - 'Edo' - - 'Ekiti' - - 'Enugu' - - 'Gombe' - - 'Imo' - - 'Jigawa' - - 'Kaduna' - - 'Kano' - - 'Katsina' - - 'Kebbi' - - 'Kogi' - - 'Kwara' - - 'Lagos' - - 'Nasarawa' - - 'Niger' - - 'Ogun' - - 'Ondo' - - 'Osun' - - 'Oyo' - - 'Plateau' - - 'Rivers' - - 'Sokoto' - - 'Taraba' - - 'Yobe' - - 'Zamfara' - avg_prod: 0.35 - inc_exp_growth: 0.02 - cons_util: 1.5 - disc_rate: 0.04 - is_conflict: False - - # Disaster params - disaster_type: flood - return_per: 10 - calc_exposure_params: - distr: uniform - high: 1.5 - low: 0.5 - identify_aff_params: - delta_pct: 0.05 - distr: uniform - high: 1.0 - low: 0 - num_masks: 10000 - - # Recovery params - add_inc_loss: True - pov_bias: 1.0 - lambda_incr: 0.01 - yrs_to_rec: 10 - - # Randmoziation params - rnd_house_vuln_params: - randomize: True - distr: uniform - low: 0.8 - high: 1.2 - thresh: 0.9 - rnd_inc_params: - randomize: True - distr: uniform - delta: 0.1 - rnd_sav_params: - randomize: True - distr: uniform - avg: 0.0204 - delta: 0.02 - rnd_rent_params: - randomize: True - distr: uniform - avg: 0.43 # Assumption source: https://livingcost.org/cost/dominica - delta: 0.1 - min_households: 5000 - atol: 100000 - - # Misc params - save_households: False - save_consumption_recovery: True - -# ------------------------------- Policy levers ------------------------------ # -# The naming convention is: + -# The following target groups are currently specified: all, poor, poor_near_poor1.25, poor_near_poor2.0 -# There are no limitations on the top-up percentage -# Top-up percentage is added to `aeexp` or adult equivalent expenditure of a household -# It is applied as a multiplier to `keff*v`: households['aeexp'] += households.eval('keff*v') * top_up / 100 -# where `v` is the vulnerability of the household and `keff` is the effective capital stock -levers: - 0: all+0 - 1: all+10 - 2: all+30 - 3: all+50 - 4: all+100 - 5: poor+0 - 6: poor+10 - 7: poor+30 - 8: poor+50 - 9: poor+100 - 10: poor_near_poor1.25+0 - 11: poor_near_poor1.25+10 - 12: poor_near_poor1.25+30 - 13: poor_near_poor1.25+50 - 14: poor_near_poor1.25+100 - 15: poor_near_poor2.0+0 - 16: poor_near_poor2.0+10 - 17: poor_near_poor2.0+30 - 18: poor_near_poor2.0+50 - 19: poor_near_poor2.0+100 - -# ------------------------------- Uncertainties ------------------------------ # -uncertainties: - avg_prod: - - 0.2 - - 0.4 - cons_util: - - 1.0 - - 1.5 - disc_rate: - - 0.04 - - 0.07 - inc_exp_growth: - - 0.01 - - 0.03 \ No newline at end of file diff --git a/data/processed/asset_impacts/Example/earthquake.csv b/data/processed/asset_impacts/Example/earthquake.csv new file mode 100644 index 0000000..8283229 --- /dev/null +++ b/data/processed/asset_impacts/Example/earthquake.csv @@ -0,0 +1,257 @@ +disaster_type,spatial_unit,residential,non_residential,total_exposed_stock,rp,pml,loss_fraction +earthquake,region_0,687270.06,487678.58,1174948.64,10,219949.67,0.187 +earthquake,region_1,799329.24,289004.66,1088333.9,10,163250.09,0.15 +earthquake,region_2,529041.81,466544.04,995585.84,10,173342.95,0.174 +earthquake,region_3,854036.29,255146.12,1109182.41,10,234027.49,0.211 +earthquake,region_4,916221.32,303084.78,1219306.1,10,182895.91,0.15 +earthquake,region_5,591702.25,326060.56,917762.82,10,152785.16,0.166 +earthquake,region_6,715972.51,322807.29,1038779.79,10,181978.94,0.175 +earthquake,region_7,569746.93,323036.16,892783.09,10,134485.44,0.151 +earthquake,region_8,728034.99,446293.99,1174328.98,10,176149.35,0.15 +earthquake,region_9,757117.22,398103.64,1155220.86,10,173283.13,0.15 +earthquake,region_10,803772.43,292631.03,1096403.46,10,164460.52,0.15 +earthquake,region_11,974442.77,491408.01,1465850.78,10,285605.98,0.195 +earthquake,region_12,652306.88,274418.03,926724.91,10,169056.22,0.182 +earthquake,region_13,720076.25,280509.56,1000585.81,10,163613.48,0.164 +earthquake,region_14,517194.26,477330.1,994524.36,10,149178.65,0.15 +earthquake,region_15,831261.14,327927.77,1159188.91,10,192433.24,0.166 +earthquake,region_16,773355.14,296213.61,1069568.75,10,225634.58,0.211 +earthquake,region_17,887566.41,484874.74,1372441.15,10,279268.08,0.203 +earthquake,region_18,798949.99,480468.56,1279418.55,10,191912.78,0.15 +earthquake,region_19,597991.43,261306.82,859298.25,10,128894.74,0.15 +earthquake,region_20,694338.64,317837.26,1012175.9,10,199270.87,0.197 +earthquake,region_21,678376.66,320233.63,998610.29,10,168035.76,0.168 +earthquake,region_22,570462.11,450549.25,1021011.36,10,153151.7,0.15 +earthquake,region_23,993443.47,443061.19,1436504.66,10,215475.7,0.15 +earthquake,region_24,502761.06,453865.36,956626.42,10,176675.25,0.185 +earthquake,region_25,864503.58,442817.59,1307321.17,10,196098.18,0.15 +earthquake,region_26,679232.86,278967.26,958200.13,10,191937.4,0.2 +earthquake,region_27,811649.06,332724.51,1144373.57,10,171656.04,0.15 +earthquake,region_28,655491.16,331295.83,986786.99,10,184490.31,0.187 +earthquake,region_29,818778.74,471803.19,1290581.92,10,208069.54,0.161 +earthquake,region_30,559797.12,428311.2,988108.32,10,187818.15,0.19 +earthquake,region_31,780638.6,442741.79,1223380.39,10,199875.35,0.163 +earthquake,region_32,761366.41,356885.25,1118251.67,10,167737.75,0.15 +earthquake,region_33,553945.71,257857.3,811803.01,10,144209.53,0.178 +earthquake,region_34,657177.99,377142.67,1034320.66,10,211784.03,0.205 +earthquake,region_35,624646.11,352595.73,977241.85,10,185241.19,0.19 +earthquake,region_36,614399.08,269244.98,883644.06,10,132546.61,0.15 +earthquake,region_37,580610.64,482424.41,1063035.06,10,207092.03,0.195 +earthquake,region_38,816701.88,467865.15,1284567.03,10,249677.71,0.194 +earthquake,region_39,593285.03,473139.75,1066424.78,10,179089.22,0.168 +earthquake,region_40,903720.08,474022.82,1377742.9,10,206661.44,0.15 +earthquake,region_41,555025.96,306983.79,862009.75,10,135086.22,0.157 +earthquake,region_42,909007.38,465182.65,1374190.03,10,206128.5,0.15 +earthquake,region_43,755373.65,354352.75,1109726.4,10,166458.96,0.15 +earthquake,region_44,559932.68,334403.79,894336.48,10,186282.21,0.208 +earthquake,region_45,661601.47,379697.66,1041299.12,10,191913.4,0.184 +earthquake,region_46,681814.8,492945.52,1174760.32,10,246987.17,0.21 +earthquake,region_47,625891.15,374312.13,1000203.27,10,150030.49,0.15 +earthquake,region_48,642420.25,259221.74,901641.98,10,157748.07,0.175 +earthquake,region_49,751339.51,262869.69,1014209.2,10,152131.38,0.15 +earthquake,region_50,954132.94,309890.47,1264023.42,10,189603.51,0.15 +earthquake,region_51,744726.38,496412.61,1241138.99,10,186170.85,0.15 +earthquake,region_52,836067.77,440404.9,1276472.68,10,191470.9,0.15 +earthquake,region_53,864108.17,341945.78,1206053.96,10,213749.65,0.177 +earthquake,region_54,816764.86,383943.67,1200708.53,10,180106.28,0.15 +earthquake,region_55,917651.25,330195.02,1247846.26,10,187176.94,0.15 +earthquake,region_56,520387.57,397723.24,918110.81,10,166872.55,0.182 +earthquake,region_57,508293.91,378023.26,886317.18,10,132947.58,0.15 +earthquake,region_58,822586.4,293591.61,1116178.0,10,204365.24,0.183 +earthquake,region_59,693367.67,484182.5,1177550.17,10,176632.53,0.15 +earthquake,region_60,670533.18,278368.38,948901.56,10,195919.1,0.206 +earthquake,region_61,938669.68,314485.41,1253155.08,10,225565.92,0.18 +earthquake,region_62,908611.1,388800.2,1297411.3,10,216622.35,0.167 +earthquake,region_63,620926.15,273275.69,894201.84,10,182168.21,0.204 +earthquake,region_0,950209.03,408275.36,1358484.39,50,276999.01,0.204 +earthquake,region_1,674604.79,431488.92,1106093.71,50,287264.73,0.26 +earthquake,region_2,943543.21,444968.89,1388512.1,50,325193.93,0.234 +earthquake,region_3,542069.98,290407.18,832477.16,50,216323.7,0.26 +earthquake,region_4,803214.53,252299.26,1055513.79,50,190147.81,0.18 +earthquake,region_5,831750.88,251265.4,1083016.28,50,201528.54,0.186 +earthquake,region_6,774366.89,422973.8,1197340.69,50,281609.89,0.235 +earthquake,region_7,612134.65,428044.81,1040179.46,50,201508.67,0.194 +earthquake,region_8,662699.85,436622.85,1099322.7,50,258300.48,0.235 +earthquake,region_9,924611.71,414403.22,1339014.93,50,303729.91,0.227 +earthquake,region_10,546837.38,341928.95,888766.33,50,174660.57,0.197 +earthquake,region_11,621994.82,493252.64,1115247.46,50,233432.19,0.209 +earthquake,region_12,946023.28,407784.66,1353807.93,50,337749.53,0.249 +earthquake,region_13,751318.55,394225.97,1145544.52,50,251162.66,0.219 +earthquake,region_14,597621.49,430613.03,1028234.52,50,203669.85,0.198 +earthquake,region_15,512157.98,411368.07,923526.06,50,173356.06,0.188 +earthquake,region_16,970229.29,488482.14,1458711.44,50,381433.26,0.261 +earthquake,region_17,685079.35,253864.15,938943.5,50,246784.26,0.263 +earthquake,region_18,714092.07,491663.7,1205755.78,50,321167.52,0.266 +earthquake,region_19,926504.73,323612.22,1250116.95,50,260661.6,0.209 +earthquake,region_20,925568.34,329230.5,1254798.84,50,234583.73,0.187 +earthquake,region_21,778400.63,484038.69,1262439.32,50,302484.22,0.24 +earthquake,region_22,785030.59,274294.12,1059324.71,50,245234.44,0.232 +earthquake,region_23,995026.93,285021.0,1280047.93,50,283956.83,0.222 +earthquake,region_24,938686.54,435192.15,1373878.69,50,329320.88,0.24 +earthquake,region_25,851242.04,339872.79,1191114.83,50,237459.68,0.199 +earthquake,region_26,904680.58,452528.35,1357208.93,50,348405.35,0.257 +earthquake,region_27,956620.28,377835.6,1334455.88,50,293782.64,0.22 +earthquake,region_28,899147.59,412490.98,1311638.57,50,315051.24,0.24 +earthquake,region_29,897896.33,472501.34,1370397.67,50,279286.38,0.204 +earthquake,region_30,687791.48,273495.48,961286.96,50,219008.1,0.228 +earthquake,region_31,517971.14,366399.5,884370.64,50,198332.91,0.224 +earthquake,region_32,643270.63,397708.32,1040978.94,50,180141.43,0.173 +earthquake,region_33,518674.09,455650.14,974324.23,50,200729.37,0.206 +earthquake,region_34,563530.26,380560.82,944091.07,50,233189.89,0.247 +earthquake,region_35,607910.51,405722.62,1013633.13,50,180968.73,0.179 +earthquake,region_36,525840.86,382838.66,908679.52,50,203601.92,0.224 +earthquake,region_37,818714.95,431522.83,1250237.78,50,334545.14,0.268 +earthquake,region_38,758150.17,330739.12,1088889.29,50,271698.15,0.25 +earthquake,region_39,635416.13,359742.86,995158.98,50,176984.68,0.178 +earthquake,region_40,512675.37,490662.1,1003337.48,50,254444.39,0.254 +earthquake,region_41,847987.1,352238.24,1200225.34,50,224837.53,0.187 +earthquake,region_42,578218.52,312560.72,890779.25,50,200356.44,0.225 +earthquake,region_43,857297.96,415049.34,1272347.31,50,251916.36,0.198 +earthquake,region_44,977432.64,434474.23,1411906.87,50,318293.8,0.225 +earthquake,region_45,805860.37,354900.02,1160760.39,50,226084.9,0.195 +earthquake,region_46,677986.34,439461.53,1117447.87,50,191574.53,0.171 +earthquake,region_47,558036.32,261500.66,819536.98,50,142659.16,0.174 +earthquake,region_48,927730.29,425914.46,1353644.76,50,294305.9,0.217 +earthquake,region_49,548917.08,372903.97,921821.05,50,200355.2,0.217 +earthquake,region_50,586600.93,358462.91,945063.85,50,198322.1,0.21 +earthquake,region_51,807925.05,408773.41,1216698.46,50,212350.87,0.175 +earthquake,region_52,687306.31,406464.98,1093771.29,50,240972.72,0.22 +earthquake,region_53,928244.92,414673.41,1342918.33,50,250176.88,0.186 +earthquake,region_54,535284.37,410604.82,945889.19,50,163308.84,0.173 +earthquake,region_55,792887.79,485057.56,1277945.35,50,290793.16,0.228 +earthquake,region_56,694084.96,410822.05,1104907.02,50,238466.88,0.216 +earthquake,region_57,772808.39,485366.2,1258174.6,50,262468.13,0.209 +earthquake,region_58,980595.28,476337.66,1456932.94,50,276204.06,0.19 +earthquake,region_59,534680.65,275194.5,809875.15,50,139154.52,0.172 +earthquake,region_60,547221.48,420751.69,967973.17,50,171446.31,0.177 +earthquake,region_61,659487.82,461218.83,1120706.64,50,193128.23,0.172 +earthquake,region_62,907234.24,320463.69,1227697.93,50,223215.72,0.182 +earthquake,region_63,848368.58,407235.71,1255604.29,50,323628.49,0.258 +earthquake,region_0,867535.52,450870.23,1318405.75,100,353600.98,0.268 +earthquake,region_1,588719.77,437653.69,1026373.46,100,329141.01,0.321 +earthquake,region_2,995252.57,353154.42,1348406.99,100,373780.86,0.277 +earthquake,region_3,888206.48,335200.89,1223407.37,100,407487.3,0.333 +earthquake,region_4,929206.38,357248.51,1286454.88,100,405345.35,0.315 +earthquake,region_5,877271.44,275780.97,1153052.4,100,380801.66,0.33 +earthquake,region_6,752626.19,456614.37,1209240.55,100,328919.43,0.272 +earthquake,region_7,947761.61,347300.42,1295062.03,100,312218.43,0.241 +earthquake,region_8,952690.99,272821.67,1225512.66,100,333255.33,0.272 +earthquake,region_9,975030.98,487651.79,1462682.77,100,434919.64,0.297 +earthquake,region_10,815918.61,362111.38,1178029.99,100,317268.3,0.269 +earthquake,region_11,664332.27,418129.61,1082461.89,100,341232.53,0.315 +earthquake,region_12,895789.52,447404.54,1343194.06,100,334617.32,0.249 +earthquake,region_13,747210.15,264389.69,1011599.84,100,298374.3,0.295 +earthquake,region_14,720765.25,471926.05,1192691.3,100,328099.24,0.275 +earthquake,region_15,558533.51,285747.92,844281.43,100,266920.47,0.316 +earthquake,region_16,809109.03,275280.67,1084389.7,100,269373.98,0.248 +earthquake,region_17,850484.57,268190.75,1118675.32,100,360421.53,0.322 +earthquake,region_18,853121.11,270337.2,1123458.31,100,279161.16,0.248 +earthquake,region_19,993319.79,343567.7,1336887.49,100,370403.68,0.277 +earthquake,region_20,906399.78,486812.14,1393211.93,100,471741.71,0.339 +earthquake,region_21,876689.09,344064.9,1220753.99,100,303174.34,0.248 +earthquake,region_22,888573.46,389601.06,1278174.52,100,360984.86,0.282 +earthquake,region_23,953177.19,277799.37,1230976.56,100,356075.37,0.289 +earthquake,region_24,505676.82,367165.16,872841.98,100,214396.46,0.246 +earthquake,region_25,559408.96,279381.56,838790.52,100,255764.87,0.305 +earthquake,region_26,873022.44,395842.19,1268864.63,100,426614.18,0.336 +earthquake,region_27,687435.29,321428.02,1008863.31,100,329756.97,0.327 +earthquake,region_28,611797.92,490805.63,1102603.55,100,265965.01,0.241 +earthquake,region_29,984939.41,260789.98,1245729.39,100,409987.37,0.329 +earthquake,region_30,763850.55,498241.2,1262091.75,100,312215.82,0.247 +earthquake,region_31,776927.14,492325.63,1269252.78,100,371015.01,0.292 +earthquake,region_32,814699.32,423937.17,1238636.49,100,353573.87,0.285 +earthquake,region_33,813779.04,396078.58,1209857.62,100,399393.12,0.33 +earthquake,region_34,522723.19,320240.8,842963.99,100,282427.62,0.335 +earthquake,region_35,945131.89,363914.19,1309046.08,100,395349.27,0.302 +earthquake,region_36,638690.59,297030.29,935720.88,100,267962.24,0.286 +earthquake,region_37,676676.11,395914.03,1072590.14,100,265759.37,0.248 +earthquake,region_38,987197.4,496552.69,1483750.09,100,459689.77,0.31 +earthquake,region_39,768048.18,327381.9,1095430.09,100,352048.78,0.321 +earthquake,region_40,842365.59,290654.23,1133019.82,100,375134.61,0.331 +earthquake,region_41,911268.62,487449.98,1398718.6,100,437200.2,0.313 +earthquake,region_42,806707.6,354560.76,1161268.36,100,387019.21,0.333 +earthquake,region_43,933031.94,261304.67,1194336.61,100,289789.89,0.243 +earthquake,region_44,688231.68,452638.33,1140870.02,100,386444.18,0.339 +earthquake,region_45,575208.45,398532.68,973741.12,100,270786.78,0.278 +earthquake,region_46,984957.2,460529.73,1445486.93,100,468096.18,0.324 +earthquake,region_47,734346.58,353704.88,1088051.46,100,290880.45,0.267 +earthquake,region_48,528187.75,466180.59,994368.34,100,319480.71,0.321 +earthquake,region_49,999858.84,499159.21,1499018.05,100,443024.55,0.296 +earthquake,region_50,884493.71,486191.43,1370685.14,100,445424.34,0.325 +earthquake,region_51,623674.05,362636.03,986310.08,100,249453.54,0.253 +earthquake,region_52,977025.51,401543.66,1378569.17,100,362376.59,0.263 +earthquake,region_53,835850.34,404532.06,1240382.4,100,342117.65,0.276 +earthquake,region_54,556778.8,417893.3,974672.09,100,284634.24,0.292 +earthquake,region_55,886159.2,380040.88,1266200.07,100,411791.24,0.325 +earthquake,region_56,775953.42,390234.49,1166187.91,100,382119.38,0.328 +earthquake,region_57,701741.43,283503.81,985245.24,100,239294.66,0.243 +earthquake,region_58,877568.63,405077.39,1282646.02,100,398143.55,0.31 +earthquake,region_59,606482.08,284092.87,890574.95,100,215033.3,0.241 +earthquake,region_60,675293.78,397479.42,1072773.2,100,299544.46,0.279 +earthquake,region_61,718737.46,476039.67,1194777.13,100,328355.28,0.275 +earthquake,region_62,756994.74,445913.25,1202908.0,100,336398.37,0.28 +earthquake,region_63,811043.35,465590.93,1276634.28,100,427611.28,0.335 +earthquake,region_0,573536.74,481646.91,1055183.65,250,526759.95,0.499 +earthquake,region_1,629122.19,364783.94,993906.13,250,496953.07,0.5 +earthquake,region_2,746309.05,332187.9,1078496.95,250,539248.47,0.5 +earthquake,region_3,620072.81,268965.83,889038.64,250,411525.29,0.463 +earthquake,region_4,564022.92,287975.67,851998.59,250,395227.42,0.464 +earthquake,region_5,820437.37,295470.02,1115907.39,250,540731.59,0.485 +earthquake,region_6,948394.2,368490.41,1316884.62,250,658442.31,0.5 +earthquake,region_7,586159.94,298072.25,884232.19,250,401518.22,0.454 +earthquake,region_8,584467.53,319647.58,904115.12,250,422855.59,0.468 +earthquake,region_9,544351.27,280158.97,824510.23,250,409021.29,0.496 +earthquake,region_10,603166.86,341067.47,944234.32,250,472117.16,0.5 +earthquake,region_11,845197.41,259828.03,1105025.45,250,552512.72,0.5 +earthquake,region_12,813950.19,270439.76,1084389.95,250,542194.98,0.5 +earthquake,region_13,960436.2,265269.49,1225705.69,250,585504.61,0.478 +earthquake,region_14,903100.64,437064.92,1340165.56,250,627803.37,0.468 +earthquake,region_15,604674.66,342618.03,947292.69,250,472180.22,0.498 +earthquake,region_16,809127.39,342228.41,1151355.8,250,571364.31,0.496 +earthquake,region_17,873735.47,259170.8,1132906.27,250,538406.56,0.475 +earthquake,region_18,856674.79,473801.71,1330476.5,250,665238.25,0.5 +earthquake,region_19,766056.74,276793.0,1042849.75,250,515940.77,0.495 +earthquake,region_20,766308.63,310617.63,1076926.26,250,513612.33,0.477 +earthquake,region_21,688642.08,255017.8,943659.88,250,455040.27,0.482 +earthquake,region_22,605724.0,331874.34,937598.34,250,433148.13,0.462 +earthquake,region_23,945263.64,398398.11,1343661.75,250,671830.88,0.5 +earthquake,region_24,894585.62,374610.55,1269196.17,250,582170.17,0.459 +earthquake,region_25,768553.27,396710.28,1165263.55,250,582631.78,0.5 +earthquake,region_26,715829.77,281895.08,997724.85,250,477289.21,0.478 +earthquake,region_27,681541.15,411479.31,1093020.46,250,546510.23,0.5 +earthquake,region_28,678048.36,496628.81,1174677.18,250,587338.59,0.5 +earthquake,region_29,618613.4,275445.62,894059.01,250,415993.07,0.465 +earthquake,region_30,622978.86,290170.34,913149.21,250,427953.5,0.469 +earthquake,region_31,642547.58,293343.4,935890.98,250,467945.49,0.5 +earthquake,region_32,540116.87,381127.85,921244.72,250,452367.72,0.491 +earthquake,region_33,991189.31,278009.73,1269199.03,250,621635.36,0.49 +earthquake,region_34,984735.22,466376.78,1451112.0,250,725556.0,0.5 +earthquake,region_35,628951.41,292721.9,921673.31,250,460836.66,0.5 +earthquake,region_36,964687.99,389190.72,1353878.72,250,676939.36,0.5 +earthquake,region_37,639989.55,442373.23,1082362.78,250,507308.17,0.469 +earthquake,region_38,661839.62,356359.11,1018198.73,250,509099.36,0.5 +earthquake,region_39,621204.87,278709.21,899914.07,250,449957.04,0.5 +earthquake,region_40,644315.28,395309.56,1039624.83,250,483879.11,0.465 +earthquake,region_41,740570.05,383147.36,1123717.41,250,511496.34,0.455 +earthquake,region_42,668302.14,283603.67,951905.81,250,434390.31,0.456 +earthquake,region_43,994980.12,330588.46,1325568.58,250,662784.29,0.5 +earthquake,region_44,627320.33,420375.68,1047696.01,250,523848.0,0.5 +earthquake,region_45,797819.37,367894.05,1165713.42,250,572579.89,0.491 +earthquake,region_46,674434.13,482382.29,1156816.42,250,578408.21,0.5 +earthquake,region_47,982513.46,281074.31,1263587.76,250,631793.88,0.5 +earthquake,region_48,969170.23,295308.27,1264478.49,250,577423.63,0.457 +earthquake,region_49,870560.32,393618.28,1264178.6,250,632089.3,0.5 +earthquake,region_50,569886.19,448816.83,1018703.02,250,478956.19,0.47 +earthquake,region_51,581827.97,291066.45,872894.42,250,436447.21,0.5 +earthquake,region_52,832598.61,380766.36,1213364.97,250,589553.47,0.486 +earthquake,region_53,938600.27,348111.28,1286711.55,250,643355.77,0.5 +earthquake,region_54,719567.45,344236.11,1063803.56,250,527931.64,0.496 +earthquake,region_55,650688.94,436902.35,1087591.28,250,543795.64,0.5 +earthquake,region_56,616106.35,474893.64,1090999.99,250,532832.53,0.488 +earthquake,region_57,771776.43,476618.03,1248394.46,250,624197.23,0.5 +earthquake,region_58,558449.02,484958.03,1043407.05,250,521703.53,0.5 +earthquake,region_59,667452.81,284818.02,952270.83,250,476135.41,0.5 +earthquake,region_60,810036.38,383365.27,1193401.65,250,596700.83,0.5 +earthquake,region_61,894298.61,287918.72,1182217.33,250,568850.12,0.481 +earthquake,region_62,624244.57,435986.57,1060231.14,250,480659.23,0.453 +earthquake,region_63,784944.84,440614.67,1225559.51,250,612779.76,0.5 diff --git a/data/processed/asset_impacts/Example/flood.csv b/data/processed/asset_impacts/Example/flood.csv new file mode 100644 index 0000000..9df72c5 --- /dev/null +++ b/data/processed/asset_impacts/Example/flood.csv @@ -0,0 +1,257 @@ +disaster_type,spatial_unit,residential,non_residential,total_exposed_stock,rp,pml,loss_fraction +flood,region_0,687270.06,487678.58,1174948.64,10,97755.01,0.083 +flood,region_1,799329.24,289004.66,1088333.9,10,54416.7,0.05 +flood,region_2,529041.81,466544.04,995585.84,10,69802.02,0.07 +flood,region_3,854036.29,255146.12,1109182.41,10,118672.52,0.107 +flood,region_4,916221.32,303084.78,1219306.1,10,60965.3,0.05 +flood,region_5,591702.25,326060.56,917762.82,10,57337.82,0.062 +flood,region_6,715972.51,322807.29,1038779.79,10,73945.84,0.071 +flood,region_7,569746.93,323036.16,892783.09,10,44639.15,0.05 +flood,region_8,728034.99,446293.99,1174328.98,10,58716.45,0.05 +flood,region_9,757117.22,398103.64,1155220.86,10,57761.04,0.05 +flood,region_10,803772.43,292631.03,1096403.46,10,54820.17,0.05 +flood,region_11,974442.77,491408.01,1465850.78,10,133157.5,0.091 +flood,region_12,652306.88,274418.03,926724.91,10,72676.83,0.078 +flood,region_13,720076.25,280509.56,1000585.81,10,59552.56,0.06 +flood,region_14,517194.26,477330.1,994524.36,10,49726.22,0.05 +flood,region_15,831261.14,327927.77,1159188.91,10,71877.6,0.062 +flood,region_16,773355.14,296213.61,1069568.75,10,114399.43,0.107 +flood,region_17,887566.41,484874.74,1372441.15,10,136534.2,0.099 +flood,region_18,798949.99,480468.56,1279418.55,10,63970.93,0.05 +flood,region_19,597991.43,261306.82,859298.25,10,42964.91,0.05 +flood,region_20,694338.64,317837.26,1012175.9,10,94004.57,0.093 +flood,region_21,678376.66,320233.63,998610.29,10,64180.29,0.064 +flood,region_22,570462.11,450549.25,1021011.36,10,51050.57,0.05 +flood,region_23,993443.47,443061.19,1436504.66,10,71825.23,0.05 +flood,region_24,502761.06,453865.36,956626.42,10,77186.1,0.081 +flood,region_25,864503.58,442817.59,1307321.17,10,65366.06,0.05 +flood,region_26,679232.86,278967.26,958200.13,10,92284.58,0.096 +flood,region_27,811649.06,332724.51,1144373.57,10,57218.68,0.05 +flood,region_28,655491.16,331295.83,986786.99,10,81864.46,0.083 +flood,region_29,818778.74,471803.19,1290581.92,10,73849.02,0.057 +flood,region_30,559797.12,428311.2,988108.32,10,85054.89,0.086 +flood,region_31,780638.6,442741.79,1223380.39,10,72643.79,0.059 +flood,region_32,761366.41,356885.25,1118251.67,10,55912.58,0.05 +flood,region_33,553945.71,257857.3,811803.01,10,59782.02,0.074 +flood,region_34,657177.99,377142.67,1034320.66,10,104214.68,0.101 +flood,region_35,624646.11,352595.73,977241.85,10,83608.04,0.086 +flood,region_36,614399.08,269244.98,883644.06,10,44182.2,0.05 +flood,region_37,580610.64,482424.41,1063035.06,10,96536.38,0.091 +flood,region_38,816701.88,467865.15,1284567.03,10,116082.74,0.09 +flood,region_39,593285.03,473139.75,1066424.78,10,68181.04,0.064 +flood,region_40,903720.08,474022.82,1377742.9,10,68887.15,0.05 +flood,region_41,555025.96,306983.79,862009.75,10,45437.21,0.053 +flood,region_42,909007.38,465182.65,1374190.03,10,68709.5,0.05 +flood,region_43,755373.65,354352.75,1109726.4,10,55486.32,0.05 +flood,region_44,559932.68,334403.79,894336.48,10,93271.22,0.104 +flood,region_45,661601.47,379697.66,1041299.12,10,83618.29,0.08 +flood,region_46,681814.8,492945.52,1174760.32,10,124812.09,0.106 +flood,region_47,625891.15,374312.13,1000203.27,10,50010.16,0.05 +flood,region_48,642420.25,259221.74,901641.98,10,63977.3,0.071 +flood,region_49,751339.51,262869.69,1014209.2,10,50710.46,0.05 +flood,region_50,954132.94,309890.47,1264023.42,10,63201.17,0.05 +flood,region_51,744726.38,496412.61,1241138.99,10,62056.95,0.05 +flood,region_52,836067.77,440404.9,1276472.68,10,63823.63,0.05 +flood,region_53,864108.17,341945.78,1206053.96,10,88320.03,0.073 +flood,region_54,816764.86,383943.67,1200708.53,10,60035.43,0.05 +flood,region_55,917651.25,330195.02,1247846.26,10,62392.31,0.05 +flood,region_56,520387.57,397723.24,918110.81,10,71389.02,0.078 +flood,region_57,508293.91,378023.26,886317.18,10,44315.86,0.05 +flood,region_58,822586.4,293591.61,1116178.0,10,88282.73,0.079 +flood,region_59,693367.67,484182.5,1177550.17,10,58877.51,0.05 +flood,region_60,670533.18,278368.38,948901.56,10,97233.34,0.102 +flood,region_61,938669.68,314485.41,1253155.08,10,95237.79,0.076 +flood,region_62,908611.1,388800.2,1297411.3,10,81691.58,0.063 +flood,region_63,620926.15,273275.69,894201.84,10,89171.22,0.1 +flood,region_0,950209.03,408275.36,1358484.39,50,113980.89,0.084 +flood,region_1,674604.79,431488.92,1106093.71,50,154533.49,0.14 +flood,region_2,943543.21,444968.89,1388512.1,50,158572.48,0.114 +flood,region_3,542069.98,290407.18,832477.16,50,116426.44,0.14 +flood,region_4,803214.53,252299.26,1055513.79,50,63486.15,0.06 +flood,region_5,831750.88,251265.4,1083016.28,50,71566.59,0.066 +flood,region_6,774366.89,422973.8,1197340.69,50,137929.01,0.115 +flood,region_7,612134.65,428044.81,1040179.46,50,76687.14,0.074 +flood,region_8,662699.85,436622.85,1099322.7,50,126381.75,0.115 +flood,region_9,924611.71,414403.22,1339014.93,50,143048.12,0.107 +flood,region_10,546837.38,341928.95,888766.33,50,68008.61,0.077 +flood,region_11,621994.82,493252.64,1115247.46,50,99602.5,0.089 +flood,region_12,946023.28,407784.66,1353807.93,50,175292.58,0.129 +flood,region_13,751318.55,394225.97,1145544.52,50,113697.32,0.099 +flood,region_14,597621.49,430613.03,1028234.52,50,80281.71,0.078 +flood,region_15,512157.98,411368.07,923526.06,50,62532.94,0.068 +flood,region_16,970229.29,488482.14,1458711.44,50,206387.89,0.141 +flood,region_17,685079.35,253864.15,938943.5,50,134111.04,0.143 +flood,region_18,714092.07,491663.7,1205755.78,50,176476.82,0.146 +flood,region_19,926504.73,323612.22,1250116.95,50,110647.57,0.089 +flood,region_20,925568.34,329230.5,1254798.84,50,84007.87,0.067 +flood,region_21,778400.63,484038.69,1262439.32,50,150991.5,0.12 +flood,region_22,785030.59,274294.12,1059324.71,50,118115.47,0.112 +flood,region_23,995026.93,285021.0,1280047.93,50,130351.08,0.102 +flood,region_24,938686.54,435192.15,1373878.69,50,164455.44,0.12 +flood,region_25,851242.04,339872.79,1191114.83,50,94525.9,0.079 +flood,region_26,904680.58,452528.35,1357208.93,50,185540.28,0.137 +flood,region_27,956620.28,377835.6,1334455.88,50,133647.93,0.1 +flood,region_28,899147.59,412490.98,1311638.57,50,157654.61,0.12 +flood,region_29,897896.33,472501.34,1370397.67,50,114838.66,0.084 +flood,region_30,687791.48,273495.48,961286.96,50,103653.66,0.108 +flood,region_31,517971.14,366399.5,884370.64,50,92208.43,0.104 +flood,region_32,643270.63,397708.32,1040978.94,50,55223.96,0.053 +flood,region_33,518674.09,455650.14,974324.23,50,83810.46,0.086 +flood,region_34,563530.26,380560.82,944091.07,50,119898.96,0.127 +flood,region_35,607910.51,405722.62,1013633.13,50,59332.76,0.059 +flood,region_36,525840.86,382838.66,908679.52,50,94560.38,0.104 +flood,region_37,818714.95,431522.83,1250237.78,50,184516.6,0.148 +flood,region_38,758150.17,330739.12,1088889.29,50,141031.44,0.13 +flood,region_39,635416.13,359742.86,995158.98,50,57565.61,0.058 +flood,region_40,512675.37,490662.1,1003337.48,50,134043.89,0.134 +flood,region_41,847987.1,352238.24,1200225.34,50,80810.49,0.067 +flood,region_42,578218.52,312560.72,890779.25,50,93462.93,0.105 +flood,region_43,857297.96,415049.34,1272347.31,50,99234.68,0.078 +flood,region_44,977432.64,434474.23,1411906.87,50,148864.97,0.105 +flood,region_45,805860.37,354900.02,1160760.39,50,86793.65,0.075 +flood,region_46,677986.34,439461.53,1117447.87,50,57480.79,0.051 +flood,region_47,558036.32,261500.66,819536.98,50,44314.73,0.054 +flood,region_48,927730.29,425914.46,1353644.76,50,131868.53,0.097 +flood,region_49,548917.08,372903.97,921821.05,50,89736.68,0.097 +flood,region_50,586600.93,358462.91,945063.85,50,84914.43,0.09 +flood,region_51,807925.05,408773.41,1216698.46,50,66347.05,0.055 +flood,region_52,687306.31,406464.98,1093771.29,50,109720.16,0.1 +flood,region_53,928244.92,414673.41,1342918.33,50,89026.68,0.066 +flood,region_54,535284.37,410604.82,945889.19,50,49802.14,0.053 +flood,region_55,792887.79,485057.56,1277945.35,50,137439.72,0.108 +flood,region_56,694084.96,410822.05,1104907.02,50,105878.03,0.096 +flood,region_57,772808.39,485366.2,1258174.6,50,111487.18,0.089 +flood,region_58,980595.28,476337.66,1456932.94,50,101372.1,0.07 +flood,region_59,534680.65,275194.5,809875.15,50,41969.5,0.052 +flood,region_60,547221.48,420751.69,967973.17,50,55289.53,0.057 +flood,region_61,659487.82,461218.83,1120706.64,50,58643.43,0.052 +flood,region_62,907234.24,320463.69,1227697.93,50,75891.97,0.062 +flood,region_63,848368.58,407235.71,1255604.29,50,172955.98,0.138 +flood,region_0,867535.52,450870.23,1318405.75,100,169024.18,0.128 +flood,region_1,588719.77,437653.69,1026373.46,100,185448.72,0.181 +flood,region_2,995252.57,353154.42,1348406.99,100,185003.88,0.137 +flood,region_3,888206.48,335200.89,1223407.37,100,236210.27,0.193 +flood,region_4,929206.38,357248.51,1286454.88,100,225241.66,0.175 +flood,region_5,877271.44,275780.97,1153052.4,100,219374.32,0.19 +flood,region_6,752626.19,456614.37,1209240.55,100,159625.75,0.132 +flood,region_7,947761.61,347300.42,1295062.03,100,130909.75,0.101 +flood,region_8,952690.99,272821.67,1225512.66,100,161683.56,0.132 +flood,region_9,975030.98,487651.79,1462682.77,100,230144.05,0.157 +flood,region_10,815918.61,362111.38,1178029.99,100,152344.11,0.129 +flood,region_11,664332.27,418129.61,1082461.89,100,189687.86,0.175 +flood,region_12,895789.52,447404.54,1343194.06,100,146570.16,0.109 +flood,region_13,747210.15,264389.69,1011599.84,100,156750.32,0.155 +flood,region_14,720765.25,471926.05,1192691.3,100,161122.46,0.135 +flood,region_15,558533.51,285747.92,844281.43,100,148721.07,0.176 +flood,region_16,809109.03,275280.67,1084389.7,100,117559.43,0.108 +flood,region_17,850484.57,268190.75,1118675.32,100,203806.99,0.182 +flood,region_18,853121.11,270337.2,1123458.31,100,121876.99,0.108 +flood,region_19,993319.79,343567.7,1336887.49,100,183239.43,0.137 +flood,region_20,906399.78,486812.14,1393211.93,100,276692.04,0.199 +flood,region_21,876689.09,344064.9,1220753.99,100,132268.78,0.108 +flood,region_22,888573.46,389601.06,1278174.52,100,182040.43,0.142 +flood,region_23,953177.19,277799.37,1230976.56,100,183738.65,0.149 +flood,region_24,505676.82,367165.16,872841.98,100,92198.58,0.106 +flood,region_25,559408.96,279381.56,838790.52,100,138334.2,0.165 +flood,region_26,873022.44,395842.19,1268864.63,100,248973.13,0.196 +flood,region_27,687435.29,321428.02,1008863.31,100,188516.11,0.187 +flood,region_28,611797.92,490805.63,1102603.55,100,111600.51,0.101 +flood,region_29,984939.41,260789.98,1245729.39,100,235585.26,0.189 +flood,region_30,763850.55,498241.2,1262091.75,100,135522.98,0.107 +flood,region_31,776927.14,492325.63,1269252.78,100,193319.62,0.152 +flood,region_32,814699.32,423937.17,1238636.49,100,180164.76,0.145 +flood,region_33,813779.04,396078.58,1209857.62,100,230013.05,0.19 +flood,region_34,522723.19,320240.8,842963.99,100,164412.66,0.195 +flood,region_35,945131.89,363914.19,1309046.08,100,212082.82,0.162 +flood,region_36,638690.59,297030.29,935720.88,100,136961.32,0.146 +flood,region_37,676676.11,395914.03,1072590.14,100,115596.75,0.108 +flood,region_38,987197.4,496552.69,1483750.09,100,251964.76,0.17 +flood,region_39,768048.18,327381.9,1095430.09,100,198688.56,0.181 +flood,region_40,842365.59,290654.23,1133019.82,100,216511.84,0.191 +flood,region_41,911268.62,487449.98,1398718.6,100,241379.6,0.173 +flood,region_42,806707.6,354560.76,1161268.36,100,224441.64,0.193 +flood,region_43,933031.94,261304.67,1194336.61,100,122582.77,0.103 +flood,region_44,688231.68,452638.33,1140870.02,100,226722.37,0.199 +flood,region_45,575208.45,398532.68,973741.12,100,134463.02,0.138 +flood,region_46,984957.2,460529.73,1445486.93,100,265728.01,0.184 +flood,region_47,734346.58,353704.88,1088051.46,100,138553.24,0.127 +flood,region_48,528187.75,466180.59,994368.34,100,180269.14,0.181 +flood,region_49,999858.84,499159.21,1499018.05,100,233162.02,0.156 +flood,region_50,884493.71,486191.43,1370685.14,100,253528.42,0.185 +flood,region_51,623674.05,362636.03,986310.08,100,111370.13,0.113 +flood,region_52,977025.51,401543.66,1378569.17,100,169376.91,0.123 +flood,region_53,835850.34,404532.06,1240382.4,100,168464.11,0.136 +flood,region_54,556778.8,417893.3,974672.09,100,148180.15,0.152 +flood,region_55,886159.2,380040.88,1266200.07,100,234523.23,0.185 +flood,region_56,775953.42,390234.49,1166187.91,100,218853.07,0.188 +flood,region_57,701741.43,283503.81,985245.24,100,101360.32,0.103 +flood,region_58,877568.63,405077.39,1282646.02,100,218573.11,0.17 +flood,region_59,606482.08,284092.87,890574.95,100,90352.81,0.101 +flood,region_60,675293.78,397479.42,1072773.2,100,149356.21,0.139 +flood,region_61,718737.46,476039.67,1194777.13,100,161086.48,0.135 +flood,region_62,756994.74,445913.25,1202908.0,100,167991.25,0.14 +flood,region_63,811043.35,465590.93,1276634.28,100,248882.49,0.195 +flood,region_0,573536.74,481646.91,1055183.65,250,315723.22,0.299 +flood,region_1,629122.19,364783.94,993906.13,250,298171.84,0.3 +flood,region_2,746309.05,332187.9,1078496.95,250,323549.08,0.3 +flood,region_3,620072.81,268965.83,889038.64,250,233717.57,0.263 +flood,region_4,564022.92,287975.67,851998.59,250,224827.7,0.264 +flood,region_5,820437.37,295470.02,1115907.39,250,317550.12,0.285 +flood,region_6,948394.2,368490.41,1316884.62,250,395065.38,0.3 +flood,region_7,586159.94,298072.25,884232.19,250,224671.78,0.254 +flood,region_8,584467.53,319647.58,904115.12,250,242032.56,0.268 +flood,region_9,544351.27,280158.97,824510.23,250,244119.24,0.296 +flood,region_10,603166.86,341067.47,944234.32,250,283270.3,0.3 +flood,region_11,845197.41,259828.03,1105025.45,250,331507.63,0.3 +flood,region_12,813950.19,270439.76,1084389.95,250,325316.99,0.3 +flood,region_13,960436.2,265269.49,1225705.69,250,340363.47,0.278 +flood,region_14,903100.64,437064.92,1340165.56,250,359770.26,0.268 +flood,region_15,604674.66,342618.03,947292.69,250,282721.68,0.298 +flood,region_16,809127.39,342228.41,1151355.8,250,341093.15,0.296 +flood,region_17,873735.47,259170.8,1132906.27,250,311825.31,0.275 +flood,region_18,856674.79,473801.71,1330476.5,250,399142.95,0.3 +flood,region_19,766056.74,276793.0,1042849.75,250,307370.82,0.295 +flood,region_20,766308.63,310617.63,1076926.26,250,298227.08,0.277 +flood,region_21,688642.08,255017.8,943659.88,250,266308.29,0.282 +flood,region_22,605724.0,331874.34,937598.34,250,245628.46,0.262 +flood,region_23,945263.64,398398.11,1343661.75,250,403098.53,0.3 +flood,region_24,894585.62,374610.55,1269196.17,250,328330.93,0.259 +flood,region_25,768553.27,396710.28,1165263.55,250,349579.07,0.3 +flood,region_26,715829.77,281895.08,997724.85,250,277744.24,0.278 +flood,region_27,681541.15,411479.31,1093020.46,250,327906.14,0.3 +flood,region_28,678048.36,496628.81,1174677.18,250,352403.15,0.3 +flood,region_29,618613.4,275445.62,894059.01,250,237181.26,0.265 +flood,region_30,622978.86,290170.34,913149.21,250,245323.65,0.269 +flood,region_31,642547.58,293343.4,935890.98,250,280767.29,0.3 +flood,region_32,540116.87,381127.85,921244.72,250,268118.77,0.291 +flood,region_33,991189.31,278009.73,1269199.03,250,367795.55,0.29 +flood,region_34,984735.22,466376.78,1451112.0,250,435333.6,0.3 +flood,region_35,628951.41,292721.9,921673.31,250,276501.99,0.3 +flood,region_36,964687.99,389190.72,1353878.72,250,406163.62,0.3 +flood,region_37,639989.55,442373.23,1082362.78,250,290835.61,0.269 +flood,region_38,661839.62,356359.11,1018198.73,250,305459.62,0.3 +flood,region_39,621204.87,278709.21,899914.07,250,269974.22,0.3 +flood,region_40,644315.28,395309.56,1039624.83,250,275954.14,0.265 +flood,region_41,740570.05,383147.36,1123717.41,250,286752.85,0.255 +flood,region_42,668302.14,283603.67,951905.81,250,244009.15,0.256 +flood,region_43,994980.12,330588.46,1325568.58,250,397670.57,0.3 +flood,region_44,627320.33,420375.68,1047696.01,250,314308.8,0.3 +flood,region_45,797819.37,367894.05,1165713.42,250,339437.2,0.291 +flood,region_46,674434.13,482382.29,1156816.42,250,347044.93,0.3 +flood,region_47,982513.46,281074.31,1263587.76,250,379076.33,0.3 +flood,region_48,969170.23,295308.27,1264478.49,250,324527.93,0.257 +flood,region_49,870560.32,393618.28,1264178.6,250,379253.58,0.3 +flood,region_50,569886.19,448816.83,1018703.02,250,275215.59,0.27 +flood,region_51,581827.97,291066.45,872894.42,250,261868.33,0.3 +flood,region_52,832598.61,380766.36,1213364.97,250,346880.48,0.286 +flood,region_53,938600.27,348111.28,1286711.55,250,386013.46,0.3 +flood,region_54,719567.45,344236.11,1063803.56,250,315170.93,0.296 +flood,region_55,650688.94,436902.35,1087591.28,250,326277.38,0.3 +flood,region_56,616106.35,474893.64,1090999.99,250,314632.53,0.288 +flood,region_57,771776.43,476618.03,1248394.46,250,374518.34,0.3 +flood,region_58,558449.02,484958.03,1043407.05,250,313022.12,0.3 +flood,region_59,667452.81,284818.02,952270.83,250,285681.25,0.3 +flood,region_60,810036.38,383365.27,1193401.65,250,358020.5,0.3 +flood,region_61,894298.61,287918.72,1182217.33,250,332406.65,0.281 +flood,region_62,624244.57,435986.57,1060231.14,250,268613.0,0.253 +flood,region_63,784944.84,440614.67,1225559.51,250,367667.85,0.3 diff --git a/data/processed/asset_impacts/Example/hurricane.csv b/data/processed/asset_impacts/Example/hurricane.csv new file mode 100644 index 0000000..b9cf43c --- /dev/null +++ b/data/processed/asset_impacts/Example/hurricane.csv @@ -0,0 +1,257 @@ +disaster_type,spatial_unit,residential,non_residential,total_exposed_stock,rp,pml,loss_fraction +hurricane,region_0,687270.06,487678.58,1174948.64,10,158852.34,0.135 +hurricane,region_1,799329.24,289004.66,1088333.9,10,108833.39,0.1 +hurricane,region_2,529041.81,466544.04,995585.84,10,121572.48,0.122 +hurricane,region_3,854036.29,255146.12,1109182.41,10,176350.0,0.159 +hurricane,region_4,916221.32,303084.78,1219306.1,10,121930.61,0.1 +hurricane,region_5,591702.25,326060.56,917762.82,10,105061.49,0.114 +hurricane,region_6,715972.51,322807.29,1038779.79,10,127962.39,0.123 +hurricane,region_7,569746.93,323036.16,892783.09,10,89278.31,0.1 +hurricane,region_8,728034.99,446293.99,1174328.98,10,117432.9,0.1 +hurricane,region_9,757117.22,398103.64,1155220.86,10,115522.09,0.1 +hurricane,region_10,803772.43,292631.03,1096403.46,10,109640.35,0.1 +hurricane,region_11,974442.77,491408.01,1465850.78,10,209381.74,0.143 +hurricane,region_12,652306.88,274418.03,926724.91,10,120866.52,0.13 +hurricane,region_13,720076.25,280509.56,1000585.81,10,111583.02,0.112 +hurricane,region_14,517194.26,477330.1,994524.36,10,99452.44,0.1 +hurricane,region_15,831261.14,327927.77,1159188.91,10,132155.42,0.114 +hurricane,region_16,773355.14,296213.61,1069568.75,10,170017.0,0.159 +hurricane,region_17,887566.41,484874.74,1372441.15,10,207901.14,0.151 +hurricane,region_18,798949.99,480468.56,1279418.55,10,127941.85,0.1 +hurricane,region_19,597991.43,261306.82,859298.25,10,85929.83,0.1 +hurricane,region_20,694338.64,317837.26,1012175.9,10,146637.72,0.145 +hurricane,region_21,678376.66,320233.63,998610.29,10,116108.03,0.116 +hurricane,region_22,570462.11,450549.25,1021011.36,10,102101.14,0.1 +hurricane,region_23,993443.47,443061.19,1436504.66,10,143650.47,0.1 +hurricane,region_24,502761.06,453865.36,956626.42,10,126930.68,0.133 +hurricane,region_25,864503.58,442817.59,1307321.17,10,130732.12,0.1 +hurricane,region_26,679232.86,278967.26,958200.13,10,142110.99,0.148 +hurricane,region_27,811649.06,332724.51,1144373.57,10,114437.36,0.1 +hurricane,region_28,655491.16,331295.83,986786.99,10,133177.38,0.135 +hurricane,region_29,818778.74,471803.19,1290581.92,10,140959.28,0.109 +hurricane,region_30,559797.12,428311.2,988108.32,10,136436.52,0.138 +hurricane,region_31,780638.6,442741.79,1223380.39,10,136259.57,0.111 +hurricane,region_32,761366.41,356885.25,1118251.67,10,111825.17,0.1 +hurricane,region_33,553945.71,257857.3,811803.01,10,101995.78,0.126 +hurricane,region_34,657177.99,377142.67,1034320.66,10,157999.36,0.153 +hurricane,region_35,624646.11,352595.73,977241.85,10,134424.61,0.138 +hurricane,region_36,614399.08,269244.98,883644.06,10,88364.41,0.1 +hurricane,region_37,580610.64,482424.41,1063035.06,10,151814.2,0.143 +hurricane,region_38,816701.88,467865.15,1284567.03,10,182880.22,0.142 +hurricane,region_39,593285.03,473139.75,1066424.78,10,123635.13,0.116 +hurricane,region_40,903720.08,474022.82,1377742.9,10,137774.29,0.1 +hurricane,region_41,555025.96,306983.79,862009.75,10,90261.71,0.105 +hurricane,region_42,909007.38,465182.65,1374190.03,10,137419.0,0.1 +hurricane,region_43,755373.65,354352.75,1109726.4,10,110972.64,0.1 +hurricane,region_44,559932.68,334403.79,894336.48,10,139776.72,0.156 +hurricane,region_45,661601.47,379697.66,1041299.12,10,137765.85,0.132 +hurricane,region_46,681814.8,492945.52,1174760.32,10,185899.63,0.158 +hurricane,region_47,625891.15,374312.13,1000203.27,10,100020.33,0.1 +hurricane,region_48,642420.25,259221.74,901641.98,10,110862.68,0.123 +hurricane,region_49,751339.51,262869.69,1014209.2,10,101420.92,0.1 +hurricane,region_50,954132.94,309890.47,1264023.42,10,126402.34,0.1 +hurricane,region_51,744726.38,496412.61,1241138.99,10,124113.9,0.1 +hurricane,region_52,836067.77,440404.9,1276472.68,10,127647.27,0.1 +hurricane,region_53,864108.17,341945.78,1206053.96,10,151034.84,0.125 +hurricane,region_54,816764.86,383943.67,1200708.53,10,120070.85,0.1 +hurricane,region_55,917651.25,330195.02,1247846.26,10,124784.63,0.1 +hurricane,region_56,520387.57,397723.24,918110.81,10,119130.79,0.13 +hurricane,region_57,508293.91,378023.26,886317.18,10,88631.72,0.1 +hurricane,region_58,822586.4,293591.61,1116178.0,10,146323.99,0.131 +hurricane,region_59,693367.67,484182.5,1177550.17,10,117755.02,0.1 +hurricane,region_60,670533.18,278368.38,948901.56,10,146576.22,0.154 +hurricane,region_61,938669.68,314485.41,1253155.08,10,160401.85,0.128 +hurricane,region_62,908611.1,388800.2,1297411.3,10,149156.97,0.115 +hurricane,region_63,620926.15,273275.69,894201.84,10,135669.71,0.152 +hurricane,region_0,950209.03,408275.36,1358484.39,50,195489.95,0.144 +hurricane,region_1,674604.79,431488.92,1106093.71,50,220899.11,0.2 +hurricane,region_2,943543.21,444968.89,1388512.1,50,241883.2,0.174 +hurricane,region_3,542069.98,290407.18,832477.16,50,166375.07,0.2 +hurricane,region_4,803214.53,252299.26,1055513.79,50,126816.98,0.12 +hurricane,region_5,831750.88,251265.4,1083016.28,50,136547.56,0.126 +hurricane,region_6,774366.89,422973.8,1197340.69,50,209769.45,0.175 +hurricane,region_7,612134.65,428044.81,1040179.46,50,139097.9,0.134 +hurricane,region_8,662699.85,436622.85,1099322.7,50,192341.12,0.175 +hurricane,region_9,924611.71,414403.22,1339014.93,50,223389.01,0.167 +hurricane,region_10,546837.38,341928.95,888766.33,50,121334.59,0.137 +hurricane,region_11,621994.82,493252.64,1115247.46,50,166517.34,0.149 +hurricane,region_12,946023.28,407784.66,1353807.93,50,256521.06,0.189 +hurricane,region_13,751318.55,394225.97,1145544.52,50,182429.99,0.159 +hurricane,region_14,597621.49,430613.03,1028234.52,50,141975.78,0.138 +hurricane,region_15,512157.98,411368.07,923526.06,50,117944.5,0.128 +hurricane,region_16,970229.29,488482.14,1458711.44,50,293910.57,0.201 +hurricane,region_17,685079.35,253864.15,938943.5,50,190447.65,0.203 +hurricane,region_18,714092.07,491663.7,1205755.78,50,248822.17,0.206 +hurricane,region_19,926504.73,323612.22,1250116.95,50,185654.58,0.149 +hurricane,region_20,925568.34,329230.5,1254798.84,50,159295.8,0.127 +hurricane,region_21,778400.63,484038.69,1262439.32,50,226737.86,0.18 +hurricane,region_22,785030.59,274294.12,1059324.71,50,181674.95,0.172 +hurricane,region_23,995026.93,285021.0,1280047.93,50,207153.95,0.162 +hurricane,region_24,938686.54,435192.15,1373878.69,50,246888.16,0.18 +hurricane,region_25,851242.04,339872.79,1191114.83,50,165992.79,0.139 +hurricane,region_26,904680.58,452528.35,1357208.93,50,266972.81,0.197 +hurricane,region_27,956620.28,377835.6,1334455.88,50,213715.28,0.16 +hurricane,region_28,899147.59,412490.98,1311638.57,50,236352.93,0.18 +hurricane,region_29,897896.33,472501.34,1370397.67,50,197062.52,0.144 +hurricane,region_30,687791.48,273495.48,961286.96,50,161330.88,0.168 +hurricane,region_31,517971.14,366399.5,884370.64,50,145270.67,0.164 +hurricane,region_32,643270.63,397708.32,1040978.94,50,117682.7,0.113 +hurricane,region_33,518674.09,455650.14,974324.23,50,142269.91,0.146 +hurricane,region_34,563530.26,380560.82,944091.07,50,176544.42,0.187 +hurricane,region_35,607910.51,405722.62,1013633.13,50,120150.75,0.119 +hurricane,region_36,525840.86,382838.66,908679.52,50,149081.15,0.164 +hurricane,region_37,818714.95,431522.83,1250237.78,50,259530.87,0.208 +hurricane,region_38,758150.17,330739.12,1088889.29,50,206364.8,0.19 +hurricane,region_39,635416.13,359742.86,995158.98,50,117275.15,0.118 +hurricane,region_40,512675.37,490662.1,1003337.48,50,194244.14,0.194 +hurricane,region_41,847987.1,352238.24,1200225.34,50,152824.01,0.127 +hurricane,region_42,578218.52,312560.72,890779.25,50,146909.69,0.165 +hurricane,region_43,857297.96,415049.34,1272347.31,50,175575.52,0.138 +hurricane,region_44,977432.64,434474.23,1411906.87,50,233579.39,0.165 +hurricane,region_45,805860.37,354900.02,1160760.39,50,156439.27,0.135 +hurricane,region_46,677986.34,439461.53,1117447.87,50,124527.66,0.111 +hurricane,region_47,558036.32,261500.66,819536.98,50,93486.94,0.114 +hurricane,region_48,927730.29,425914.46,1353644.76,50,213087.22,0.157 +hurricane,region_49,548917.08,372903.97,921821.05,50,145045.94,0.157 +hurricane,region_50,586600.93,358462.91,945063.85,50,141618.26,0.15 +hurricane,region_51,807925.05,408773.41,1216698.46,50,139348.96,0.115 +hurricane,region_52,687306.31,406464.98,1093771.29,50,175346.44,0.16 +hurricane,region_53,928244.92,414673.41,1342918.33,50,169601.78,0.126 +hurricane,region_54,535284.37,410604.82,945889.19,50,106555.49,0.113 +hurricane,region_55,792887.79,485057.56,1277945.35,50,214116.44,0.168 +hurricane,region_56,694084.96,410822.05,1104907.02,50,172172.46,0.156 +hurricane,region_57,772808.39,485366.2,1258174.6,50,186977.66,0.149 +hurricane,region_58,980595.28,476337.66,1456932.94,50,188788.08,0.13 +hurricane,region_59,534680.65,275194.5,809875.15,50,90562.01,0.112 +hurricane,region_60,547221.48,420751.69,967973.17,50,113367.92,0.117 +hurricane,region_61,659487.82,461218.83,1120706.64,50,125885.83,0.112 +hurricane,region_62,907234.24,320463.69,1227697.93,50,149553.84,0.122 +hurricane,region_63,848368.58,407235.71,1255604.29,50,248292.24,0.198 +hurricane,region_0,867535.52,450870.23,1318405.75,100,261312.58,0.198 +hurricane,region_1,588719.77,437653.69,1026373.46,100,257294.86,0.251 +hurricane,region_2,995252.57,353154.42,1348406.99,100,279392.37,0.207 +hurricane,region_3,888206.48,335200.89,1223407.37,100,321848.79,0.263 +hurricane,region_4,929206.38,357248.51,1286454.88,100,315293.51,0.245 +hurricane,region_5,877271.44,275780.97,1153052.4,100,300087.99,0.26 +hurricane,region_6,752626.19,456614.37,1209240.55,100,244272.59,0.202 +hurricane,region_7,947761.61,347300.42,1295062.03,100,221564.09,0.171 +hurricane,region_8,952690.99,272821.67,1225512.66,100,247469.44,0.202 +hurricane,region_9,975030.98,487651.79,1462682.77,100,332531.84,0.227 +hurricane,region_10,815918.61,362111.38,1178029.99,100,234806.21,0.199 +hurricane,region_11,664332.27,418129.61,1082461.89,100,265460.2,0.245 +hurricane,region_12,895789.52,447404.54,1343194.06,100,240593.74,0.179 +hurricane,region_13,747210.15,264389.69,1011599.84,100,227562.31,0.225 +hurricane,region_14,720765.25,471926.05,1192691.3,100,244610.85,0.205 +hurricane,region_15,558533.51,285747.92,844281.43,100,207820.77,0.246 +hurricane,region_16,809109.03,275280.67,1084389.7,100,193466.7,0.178 +hurricane,region_17,850484.57,268190.75,1118675.32,100,282114.26,0.252 +hurricane,region_18,853121.11,270337.2,1123458.31,100,200519.08,0.178 +hurricane,region_19,993319.79,343567.7,1336887.49,100,276821.56,0.207 +hurricane,region_20,906399.78,486812.14,1393211.93,100,374216.87,0.269 +hurricane,region_21,876689.09,344064.9,1220753.99,100,217721.56,0.178 +hurricane,region_22,888573.46,389601.06,1278174.52,100,271512.64,0.212 +hurricane,region_23,953177.19,277799.37,1230976.56,100,269907.01,0.219 +hurricane,region_24,505676.82,367165.16,872841.98,100,153297.52,0.176 +hurricane,region_25,559408.96,279381.56,838790.52,100,197049.53,0.235 +hurricane,region_26,873022.44,395842.19,1268864.63,100,337793.66,0.266 +hurricane,region_27,687435.29,321428.02,1008863.31,100,259136.54,0.257 +hurricane,region_28,611797.92,490805.63,1102603.55,100,188782.76,0.171 +hurricane,region_29,984939.41,260789.98,1245729.39,100,322786.31,0.259 +hurricane,region_30,763850.55,498241.2,1262091.75,100,223869.4,0.177 +hurricane,region_31,776927.14,492325.63,1269252.78,100,282167.31,0.222 +hurricane,region_32,814699.32,423937.17,1238636.49,100,266869.32,0.215 +hurricane,region_33,813779.04,396078.58,1209857.62,100,314703.08,0.26 +hurricane,region_34,522723.19,320240.8,842963.99,100,223420.14,0.265 +hurricane,region_35,945131.89,363914.19,1309046.08,100,303716.05,0.232 +hurricane,region_36,638690.59,297030.29,935720.88,100,202461.78,0.216 +hurricane,region_37,676676.11,395914.03,1072590.14,100,190678.06,0.178 +hurricane,region_38,987197.4,496552.69,1483750.09,100,355827.27,0.24 +hurricane,region_39,768048.18,327381.9,1095430.09,100,275368.67,0.251 +hurricane,region_40,842365.59,290654.23,1133019.82,100,295823.23,0.261 +hurricane,region_41,911268.62,487449.98,1398718.6,100,339289.9,0.243 +hurricane,region_42,806707.6,354560.76,1161268.36,100,305730.43,0.263 +hurricane,region_43,933031.94,261304.67,1194336.61,100,206186.33,0.173 +hurricane,region_44,688231.68,452638.33,1140870.02,100,306583.28,0.269 +hurricane,region_45,575208.45,398532.68,973741.12,100,202624.9,0.208 +hurricane,region_46,984957.2,460529.73,1445486.93,100,366912.1,0.254 +hurricane,region_47,734346.58,353704.88,1088051.46,100,214716.84,0.197 +hurricane,region_48,528187.75,466180.59,994368.34,100,249874.92,0.251 +hurricane,region_49,999858.84,499159.21,1499018.05,100,338093.28,0.226 +hurricane,region_50,884493.71,486191.43,1370685.14,100,349476.38,0.255 +hurricane,region_51,623674.05,362636.03,986310.08,100,180411.84,0.183 +hurricane,region_52,977025.51,401543.66,1378569.17,100,265876.75,0.193 +hurricane,region_53,835850.34,404532.06,1240382.4,100,255290.88,0.206 +hurricane,region_54,556778.8,417893.3,974672.09,100,216407.2,0.222 +hurricane,region_55,886159.2,380040.88,1266200.07,100,323157.24,0.255 +hurricane,region_56,775953.42,390234.49,1166187.91,100,300486.23,0.258 +hurricane,region_57,701741.43,283503.81,985245.24,100,170327.49,0.173 +hurricane,region_58,877568.63,405077.39,1282646.02,100,308358.33,0.24 +hurricane,region_59,606482.08,284092.87,890574.95,100,152693.05,0.171 +hurricane,region_60,675293.78,397479.42,1072773.2,100,224450.33,0.209 +hurricane,region_61,718737.46,476039.67,1194777.13,100,244720.88,0.205 +hurricane,region_62,756994.74,445913.25,1202908.0,100,252194.81,0.21 +hurricane,region_63,811043.35,465590.93,1276634.28,100,338246.88,0.265 +hurricane,region_0,573536.74,481646.91,1055183.65,250,421241.58,0.399 +hurricane,region_1,629122.19,364783.94,993906.13,250,397562.45,0.4 +hurricane,region_2,746309.05,332187.9,1078496.95,250,431398.78,0.4 +hurricane,region_3,620072.81,268965.83,889038.64,250,322621.43,0.363 +hurricane,region_4,564022.92,287975.67,851998.59,250,310027.56,0.364 +hurricane,region_5,820437.37,295470.02,1115907.39,250,429140.86,0.385 +hurricane,region_6,948394.2,368490.41,1316884.62,250,526753.85,0.4 +hurricane,region_7,586159.94,298072.25,884232.19,250,313095.0,0.354 +hurricane,region_8,584467.53,319647.58,904115.12,250,332444.08,0.368 +hurricane,region_9,544351.27,280158.97,824510.23,250,326570.26,0.396 +hurricane,region_10,603166.86,341067.47,944234.32,250,377693.73,0.4 +hurricane,region_11,845197.41,259828.03,1105025.45,250,442010.18,0.4 +hurricane,region_12,813950.19,270439.76,1084389.95,250,433755.98,0.4 +hurricane,region_13,960436.2,265269.49,1225705.69,250,462934.04,0.378 +hurricane,region_14,903100.64,437064.92,1340165.56,250,493786.82,0.368 +hurricane,region_15,604674.66,342618.03,947292.69,250,377450.95,0.398 +hurricane,region_16,809127.39,342228.41,1151355.8,250,456228.73,0.396 +hurricane,region_17,873735.47,259170.8,1132906.27,250,425115.93,0.375 +hurricane,region_18,856674.79,473801.71,1330476.5,250,532190.6,0.4 +hurricane,region_19,766056.74,276793.0,1042849.75,250,411655.8,0.395 +hurricane,region_20,766308.63,310617.63,1076926.26,250,405919.7,0.377 +hurricane,region_21,688642.08,255017.8,943659.88,250,360674.28,0.382 +hurricane,region_22,605724.0,331874.34,937598.34,250,339388.3,0.362 +hurricane,region_23,945263.64,398398.11,1343661.75,250,537464.7,0.4 +hurricane,region_24,894585.62,374610.55,1269196.17,250,455250.55,0.359 +hurricane,region_25,768553.27,396710.28,1165263.55,250,466105.42,0.4 +hurricane,region_26,715829.77,281895.08,997724.85,250,377516.72,0.378 +hurricane,region_27,681541.15,411479.31,1093020.46,250,437208.18,0.4 +hurricane,region_28,678048.36,496628.81,1174677.18,250,469870.87,0.4 +hurricane,region_29,618613.4,275445.62,894059.01,250,326587.16,0.365 +hurricane,region_30,622978.86,290170.34,913149.21,250,336638.58,0.369 +hurricane,region_31,642547.58,293343.4,935890.98,250,374356.39,0.4 +hurricane,region_32,540116.87,381127.85,921244.72,250,360243.24,0.391 +hurricane,region_33,991189.31,278009.73,1269199.03,250,494715.46,0.39 +hurricane,region_34,984735.22,466376.78,1451112.0,250,580444.8,0.4 +hurricane,region_35,628951.41,292721.9,921673.31,250,368669.32,0.4 +hurricane,region_36,964687.99,389190.72,1353878.72,250,541551.49,0.4 +hurricane,region_37,639989.55,442373.23,1082362.78,250,399071.89,0.369 +hurricane,region_38,661839.62,356359.11,1018198.73,250,407279.49,0.4 +hurricane,region_39,621204.87,278709.21,899914.07,250,359965.63,0.4 +hurricane,region_40,644315.28,395309.56,1039624.83,250,379916.62,0.365 +hurricane,region_41,740570.05,383147.36,1123717.41,250,399124.59,0.355 +hurricane,region_42,668302.14,283603.67,951905.81,250,339199.73,0.356 +hurricane,region_43,994980.12,330588.46,1325568.58,250,530227.43,0.4 +hurricane,region_44,627320.33,420375.68,1047696.01,250,419078.4,0.4 +hurricane,region_45,797819.37,367894.05,1165713.42,250,456008.54,0.391 +hurricane,region_46,674434.13,482382.29,1156816.42,250,462726.57,0.4 +hurricane,region_47,982513.46,281074.31,1263587.76,250,505435.1,0.4 +hurricane,region_48,969170.23,295308.27,1264478.49,250,450975.78,0.357 +hurricane,region_49,870560.32,393618.28,1264178.6,250,505671.44,0.4 +hurricane,region_50,569886.19,448816.83,1018703.02,250,377085.89,0.37 +hurricane,region_51,581827.97,291066.45,872894.42,250,349157.77,0.4 +hurricane,region_52,832598.61,380766.36,1213364.97,250,468216.97,0.386 +hurricane,region_53,938600.27,348111.28,1286711.55,250,514684.62,0.4 +hurricane,region_54,719567.45,344236.11,1063803.56,250,421551.29,0.396 +hurricane,region_55,650688.94,436902.35,1087591.28,250,435036.51,0.4 +hurricane,region_56,616106.35,474893.64,1090999.99,250,423732.53,0.388 +hurricane,region_57,771776.43,476618.03,1248394.46,250,499357.78,0.4 +hurricane,region_58,558449.02,484958.03,1043407.05,250,417362.82,0.4 +hurricane,region_59,667452.81,284818.02,952270.83,250,380908.33,0.4 +hurricane,region_60,810036.38,383365.27,1193401.65,250,477360.66,0.4 +hurricane,region_61,894298.61,287918.72,1182217.33,250,450628.39,0.381 +hurricane,region_62,624244.57,435986.57,1060231.14,250,374636.11,0.353 +hurricane,region_63,784944.84,440614.67,1225559.51,250,490223.81,0.4 diff --git a/data/processed/household_survey/Example.csv b/data/processed/household_survey/Example.csv new file mode 100644 index 0000000..5b25ac8 --- /dev/null +++ b/data/processed/household_survey/Example.csv @@ -0,0 +1,101 @@ +spatial_unit,household_id,household_weight,inc,exp,sav,owns_home,exp_house,keff,roof,walls,floor,poverty_line,is_poor,female_headed,urban,literacy +region_46,1,92.35290441231118,2882.026172983832,2401.688477486527,480.33769549730505,True,0.0,8234.360494239521,Shingle (wood),Plywood,Rudimentary – Wood planks,1571.281989361122,False,False,True,High +region_55,2,30.113589575933442,2200.078604183612,1833.3988368196765,366.6797673639353,True,0.0,6285.938869096034,Shingle (other),Concrete/Concrete Blocks,Finished – Parquet or polished wood,1571.281989361122,False,False,False,Medium +region_37,3,45.856330299438966,2489.3689920528695,2074.474160044058,414.8948320088116,True,0.0,7112.482834436771,Shingle (asphalt),Concrete/Concrete Blocks,Finished – Parquet or polished wood,1571.281989361122,False,True,False,High +region_63,4,49.90182556473513,3000.0,2500.0,500.0,True,0.0,8571.428571428572,"Sheet metal (galvanize, galvalume)",Wood/Timber,Finished – Parquet or polished wood,1571.281989361122,False,False,True,High +region_1,5,78.03898794957516,2933.778995074984,2444.815829229153,488.96316584583064,True,0.0,8382.22570021424,"Sheet metal (galvanize, galvalume)",Finished – Cement blocks,Finished – Cement/red bricks,1571.281989361122,False,False,False,High +region_5,6,84.57926119374939,1511.3610600617944,1259.4675500514954,251.893510010299,True,0.0,4318.174457319413,Finished – Metal,Natural – Other,Finished – Cement/red bricks,1571.281989361122,True,False,False,Low +region_6,7,14.768197413712668,2475.044208762795,2062.5368406356624,412.5073681271324,True,0.0,7071.554882179414,Concrete,Concrete/Concrete Blocks,Finished – Cement/red bricks,1571.281989361122,False,False,True,High +region_12,8,43.2635316608963,1924.321395851151,1250.8089073032481,96.21606979255762,False,577.2964187553453,5498.061131003289,Finished – Concrete,Wood & Concrete,Finished – Cement/red bricks,1571.281989361122,False,False,True,Medium +region_26,9,84.44263389571026,1948.390574103221,1623.6588117526842,324.7317623505369,True,0.0,5566.830211723489,Concrete,Finished – Cement blocks,Finished – Cement/red bricks,1571.281989361122,False,True,False,Medium +region_10,10,81.98529726982801,2205.2992509691862,1837.7493758076553,367.54987516153096,True,0.0,6300.8550027691035,Finished – Metal,Concrete/Concrete blocks,Rudimentary – Wood planks,1571.281989361122,False,False,True,High +region_59,11,11.138962086789224,2072.021785580439,1346.8141606272852,103.60108927902206,False,621.6065356741317,5920.06224451554,Concrete,Finished – Stone with lime/cement,Finished – Cement/red bricks,1571.281989361122,False,False,True,Medium +region_54,12,16.48195153792834,2727.1367534814876,2272.6139612345733,454.5227922469144,True,0.0,7791.819295661393,Tile,Concrete/Concrete Blocks,Finished – Parquet or polished wood,1571.281989361122,False,False,True,High +region_14,13,31.115670468341374,2380.518862573497,1983.7657188112473,396.75314376224946,True,0.0,6801.482464495705,Finished – Concrete,Concrete/Concrete blocks,Finished – Parquet or polished wood,1571.281989361122,False,False,True,High +region_62,14,8.460547839250694,2060.837508246414,1717.3645902053452,343.47291804106885,True,0.0,5888.1071664183255,Shingle (wood),Concrete/Concrete blocks,Finished – Parquet or polished wood,1571.281989361122,False,False,True,Medium +region_8,15,43.0416372812187,2221.9316163727126,1851.6096803105938,370.32193606211877,True,0.0,6348.376046779179,"Sheet metal (galvanize, galvalume)",Concrete/Concrete blocks,Other,1571.281989361122,False,False,True,High +region_7,16,11.65415280980861,2166.8371636871334,1805.6976364059446,361.13952728118875,True,0.0,6190.963324820381,Tile,Natural – Other,Finished – Cement/red bricks,1571.281989361122,False,False,False,Medium +region_45,17,57.25354177331466,2747.039536578803,2289.199613815669,457.8399227631339,True,0.0,7848.684390225152,Finished – Concrete,Finished – Stone with lime/cement,Rudimentary – Wood planks,1571.281989361122,False,False,False,High +region_5,18,25.409137041304454,1897.4208681170996,1581.1840567642498,316.2368113528498,True,0.0,5421.20248033457,Tile,Natural – Other,Finished – Cement/red bricks,1571.281989361122,False,False,True,Medium +region_47,19,60.04687346961265,2156.533850825451,1797.1115423545425,359.4223084709083,True,0.0,6161.525288072717,Shingle (wood),Finished – Stone with lime/cement,Finished – Parquet or polished wood,1571.281989361122,False,False,True,Medium +region_59,20,12.635038647460128,1572.9521303491376,1310.7934419576147,262.1586883915229,True,0.0,4494.148943854679,Finished – Metal,Brick/Blocks,Finished – Cement/red bricks,1571.281989361122,False,False,True,Low +region_42,21,97.6125029734348,1000.0,650.0,50.0,False,300.0,2857.1428571428573,Tile,Concrete/Concrete Blocks,Finished – Parquet or polished wood,1571.281989361122,True,False,False,Low +region_3,22,93.3235591818767,2326.8092977201804,1939.0077481001504,387.8015496200301,True,0.0,6648.026564914801,Finished – Concrete,Rudimentary – Plywood,Finished – Cement/red bricks,1571.281989361122,False,False,True,High +region_10,23,39.78789691790191,2432.218099429753,2026.8484161914607,405.36968323829205,True,0.0,6949.194569799294,Finished – Metal,Finished – Cement blocks,Finished – Cement/red bricks,1571.281989361122,False,True,True,High +region_50,24,24.97568081848246,1628.9174897967791,1357.431241497316,271.4862482994631,True,0.0,4654.04997084794,Finished – Metal,Brick/Blocks,Finished – Cement/red bricks,1571.281989361122,False,False,True,Low +region_57,25,25.789423072503705,3000.0,2500.0,500.0,True,0.0,8571.428571428572,Finished – Concrete,Finished – Cement blocks,Finished – Parquet or polished wood,1571.281989361122,False,False,True,High +region_27,26,48.85595998503681,1272.8171627006177,827.3311557554016,63.64085813503078,False,381.8451488101853,3636.620464858908,Finished – Metal,Rudimentary – Plywood,Rudimentary – Wood planks,1571.281989361122,True,False,False,Low +region_25,27,4.95928738817098,2022.879258650723,1685.7327155422693,337.14654310845367,True,0.0,5779.655024716351,Finished – Concrete,Concrete/Concrete Blocks,Finished – Cement/red bricks,1571.281989361122,False,True,True,Medium +region_3,28,64.33080550143757,1906.4080749870832,1588.6733958225693,317.73467916451386,True,0.0,5446.880214248809,Finished – Concrete,Finished – Cement blocks,Finished – Cement/red bricks,1571.281989361122,False,False,False,Medium +region_61,29,41.42198792563474,2766.3896071792287,2305.3246726493576,461.06493452987115,True,0.0,7903.970306226368,Tile,Finished – Stone with lime/cement,Finished – Cement/red bricks,1571.281989361122,False,False,False,High +region_14,30,38.36325068629984,2734.679384950143,2278.8994874584523,455.77989749169046,True,0.0,7813.369671286122,Shingle (other),Concrete/Concrete blocks,Finished – Cement/red bricks,1571.281989361122,False,False,False,High +region_18,31,81.12713217743064,2077.473712848458,1731.2280940403818,346.2456188080762,True,0.0,5935.639179567023,Finished – Concrete,Wood & Concrete,Finished – Cement/red bricks,1571.281989361122,False,True,False,Medium +region_5,32,71.19451055814571,2189.0812598010866,1824.2343831675723,364.8468766335143,True,0.0,6254.517885145962,Shingle (wood),Brick/Blocks,Finished – Cement/red bricks,1571.281989361122,False,False,True,Medium +region_58,33,95.4790477238765,1556.1071261849436,1296.755938487453,259.35118769749056,True,0.0,4446.0203605284105,Finished – Asbestos,Concrete/Concrete Blocks,Finished – Cement/red bricks,1571.281989361122,True,False,False,Low +region_4,34,35.841687809073385,1009.6017658880365,841.3348049066972,168.26696098133937,True,0.0,2884.576473965819,Concrete,Concrete/Concrete Blocks,Finished – Cement/red bricks,1571.281989361122,True,False,False,Low +region_17,35,89.85673370029114,1826.0439253369236,1521.703271114103,304.3406542228206,True,0.0,5217.268358105496,Finished – Concrete,Brick/Blocks,Finished – Cement/red bricks,1571.281989361122,False,False,False,Medium +region_5,36,77.2267514387588,2078.17448455199,1350.8134149587936,103.90872422759958,False,623.452345365597,5937.641384434258,Finished – Metal,Finished – Cement blocks,Rudimentary – Wood planks,1571.281989361122,False,True,True,Medium +region_63,37,36.38504050787659,2615.14534036386,2179.28778363655,435.8575567273101,True,0.0,7471.843829611029,Concrete,Brick/Blocks,Finished – Cement/red bricks,1571.281989361122,False,False,True,High +region_30,38,62.54487820887252,2601.1899243922057,1690.7734508549333,130.05949621961065,False,780.3569773176617,7431.97121254916,Finished – Concrete,Finished – Cement blocks,Finished – Parquet or polished wood,1571.281989361122,False,False,True,High +region_24,39,29.568425807517862,1806.336591296024,1505.2804927466866,301.0560985493373,True,0.0,5160.961689417211,Shingle (other),Plywood,Rudimentary – Wood planks,1571.281989361122,False,False,True,Low +region_3,40,87.56559179040939,1848.8486247123321,1540.707187260277,308.14143745205524,True,0.0,5282.424642035235,Shingle (asphalt),Concrete/Concrete blocks,Finished – Parquet or polished wood,1571.281989361122,False,False,False,Medium +region_5,41,12.130304404018814,1475.7235174664538,959.220286353195,73.78617587332269,False,442.71705523993614,4216.352907047011,Tile,Concrete/Concrete blocks,Finished – Cement/red bricks,1571.281989361122,True,False,False,Low +region_40,42,22.031001768110062,1289.9910314105123,1074.992526175427,214.9985052350853,True,0.0,3685.6886611728924,Shingle (asphalt),Finished – Cement blocks,Finished – Cement/red bricks,1571.281989361122,True,False,False,Low +region_36,43,19.120295915912195,1146.8649046874937,745.4621880468708,57.34324523437482,False,344.05947140624806,3276.756870535696,Finished – Concrete,Wood & Concrete,Finished – Cement/red bricks,1571.281989361122,True,True,False,Low +region_58,44,40.89957423802458,2975.387697615895,2479.489748013246,495.8979496026491,True,0.0,8501.107707473986,Finished – Concrete,Wood & Concrete,Finished – Parquet or polished wood,1571.281989361122,False,False,True,High +region_49,45,74.77806304318078,1745.1739091241732,1134.3630409307125,87.25869545620878,False,523.5521727372519,4986.211168926209,Shingle (asphalt),Finished – Cement blocks,Finished – Cement/red bricks,1571.281989361122,False,False,True,Low +region_55,46,53.16383745616585,1780.9628491944068,1157.6258519763644,89.04814245972034,False,534.288854758322,5088.465283412591,Finished – Asbestos,Rudimentary – Plywood,Rudimentary – Wood planks,1571.281989361122,False,True,False,Low +region_24,47,49.27995603028255,1373.602319975037,892.841507983774,68.68011599875194,False,412.0806959925111,3924.5780570715347,Tile,Finished – Cement blocks,Rudimentary – Wood planks,1571.281989361122,True,False,False,Low +region_33,48,1.0540505248025698,2388.745177915955,1990.6209815966292,398.12419631932585,True,0.0,6824.986222617014,Finished – Concrete,Finished – Stone with lime/cement,Other,1571.281989361122,False,True,False,High +region_18,49,43.11477081015042,1193.0510762210242,775.4831995436657,59.65255381105129,False,357.91532286630724,3408.7173606314977,Concrete,Wood & Concrete,Finished – Cement/red bricks,1571.281989361122,True,True,False,Low +region_33,50,7.291823708779685,1893.6298598930157,1578.0248832441798,315.6049766488359,True,0.0,5410.371028265759,Shingle (asphalt),Finished – GRC/Gypsum/Asbestos,Rudimentary – Wood planks,1571.281989361122,False,True,False,Medium +region_14,51,21.617071960026898,1552.2667194031621,1293.5555995026352,258.7111199005269,True,0.0,4435.047769723321,Concrete,Rudimentary – Plywood,Finished – Cement/red bricks,1571.281989361122,True,False,True,Low +region_49,52,93.30699995708895,2193.451248929631,1827.8760407746927,365.57520815493854,True,0.0,6267.003568370375,Finished – Concrete,Wood/Timber,Rudimentary – Wood planks,1571.281989361122,False,False,False,Medium +region_7,53,22.32442222998058,1744.5974312155636,1133.9883302901162,87.22987156077829,False,523.3792293646691,4984.5640891873245,Tile,Finished – GRC/Gypsum/Asbestos,Finished – Parquet or polished wood,1571.281989361122,False,False,False,Low +region_53,54,85.97542622479199,1409.683907938794,916.2945401602159,70.48419539693987,False,422.9051723816382,4027.668308396554,Shingle (wood),Finished – Stone with lime/cement,Other,1571.281989361122,True,False,False,Low +region_43,55,80.48644378457209,1985.9088858306725,1654.9240715255605,330.98481430511197,True,0.0,5674.025388087636,Concrete,Finished – Cement blocks,Rudimentary – Wood planks,1571.281989361122,False,False,False,Medium +region_46,56,16.75547745728204,2214.1659352652086,1845.138279387674,369.0276558775347,True,0.0,6326.188386472025,Finished – Metal,Concrete/Concrete blocks,Finished – Cement/red bricks,1571.281989361122,False,True,False,High +region_48,57,60.965483769757604,2033.258611191584,1321.6180972745294,101.66293055957931,False,609.9775833574752,5809.31031769024,Concrete,Concrete/Concrete blocks,Finished – Parquet or polished wood,1571.281989361122,False,True,True,Medium +region_52,58,12.450525318596318,2151.2359488698908,1792.6966240582424,358.5393248116484,True,0.0,6146.388425342545,Finished – Concrete,Concrete/Concrete Blocks,Finished – Cement/red bricks,1571.281989361122,False,False,False,Medium +region_63,59,73.06092767858163,1682.8389531595183,1093.8453195536867,84.14194765797606,False,504.85168594785546,4808.111294741481,Tile,Finished – Cement blocks,Finished – Cement/red bricks,1571.281989361122,False,False,False,Low +region_33,60,64.10876545984846,1818.629417006431,1515.5245141720259,303.10490283440504,True,0.0,5196.0840485898025,Finished – Concrete,Brick/Blocks,Finished – Cement/red bricks,1571.281989361122,False,False,True,Medium +region_17,61,81.38191760741091,1663.7697761120244,1081.450354472816,83.1884888056012,False,499.1309328336073,4753.6279317486415,Finished – Concrete,Finished – GRC/Gypsum/Asbestos,Finished – Parquet or polished wood,1571.281989361122,False,False,True,Low +region_29,62,48.45907038952962,1820.2234192297294,1183.145222499324,91.01117096148653,False,546.0670257689188,5200.63834065637,Concrete,Plywood,Finished – Parquet or polished wood,1571.281989361122,False,False,True,Medium +region_12,63,91.5714456955049,1593.426858977773,1035.7274583355525,79.67134294888865,False,478.0280576933319,4552.648168507923,Tile,Concrete/Concrete blocks,Finished – Cement/red bricks,1571.281989361122,False,False,False,Low +region_54,64,5.885545732055531,1136.8586988341617,947.3822490284681,189.47644980569362,True,0.0,3248.1677109547477,Shingle (asphalt),Concrete/Concrete blocks,Finished – Parquet or polished wood,1571.281989361122,True,False,False,Low +region_46,65,29.99596793767445,2088.7130711268765,1740.5942259390638,348.11884518781267,True,0.0,5967.751631791076,Shingle (asphalt),Wood & Concrete,Finished – Cement/red bricks,1571.281989361122,False,False,True,Medium +region_54,66,71.79020714905154,1799.1095318958692,1499.2579432465577,299.85158864931145,True,0.0,5140.312948273912,Shingle (wood),Finished – Stone with lime/cement,Finished – Cement/red bricks,1571.281989361122,False,False,False,Low +region_32,67,42.39281196305208,1184.9008265169778,987.4173554308148,197.48347108616292,True,0.0,3385.430932905651,Concrete,Wood/Timber,Finished – Cement/red bricks,1571.281989361122,True,False,False,Low +region_34,68,18.12218407284448,2231.391127762887,1859.4926064690728,371.8985212938144,True,0.0,6375.403222179678,Shingle (asphalt),Natural – Other,Other,1571.281989361122,False,False,True,High +region_51,69,11.613863797426056,1546.350817808379,1288.6256815069826,257.72513630139633,True,0.0,4418.145193738225,Tile,Rudimentary – Plywood,Finished – Cement/red bricks,1571.281989361122,True,True,False,Low +region_23,70,81.91657203470052,2025.9726978980696,1316.882253633745,101.29863489490367,False,607.7918093694209,5788.4934225659135,Tile,Finished – Cement blocks,Finished – Cement/red bricks,1571.281989361122,False,False,True,Medium +region_60,71,47.841154868098776,2364.545281088768,1970.454400907307,394.0908801814612,True,0.0,6755.843660253624,"Sheet metal (galvanize, galvalume)",Finished – Cement blocks,Finished – Parquet or polished wood,1571.281989361122,False,False,True,High +region_25,72,88.34608351999164,2064.4914553787053,1341.9194459961584,103.22457276893533,False,619.3474366136115,5898.54701536773,Concrete,Concrete/Concrete blocks,Finished – Cement/red bricks,1571.281989361122,False,False,True,Medium +region_46,73,73.59562429735588,2569.7003422716502,2141.416951893042,428.28339037860815,True,0.0,7342.000977919,Shingle (asphalt),Finished – Stone with lime/cement,Rudimentary – Wood planks,1571.281989361122,False,False,True,High +region_50,74,41.56289435744361,1382.5870898231738,1152.1559081859782,230.43118163719555,True,0.0,3950.248828066211,Shingle (other),Wood & Concrete,Finished – Parquet or polished wood,1571.281989361122,True,True,False,Low +region_43,75,37.977590401412684,2201.1708205887744,1834.3090171573122,366.86180343146225,True,0.0,6289.059487396498,Finished – Metal,Wood/Timber,Other,1571.281989361122,False,True,False,High +region_52,76,52.04819631847392,1657.5949545298433,1381.3291287748696,276.2658257549738,True,0.0,4735.985584370981,Finished – Concrete,Concrete/Concrete blocks,Finished – Parquet or polished wood,1571.281989361122,False,False,False,Low +region_41,77,89.01693536578314,1564.6014254090592,1303.834521174216,260.7669042348432,True,0.0,4470.289786883026,Shingle (other),Brick/Blocks,Finished – Cement/red bricks,1571.281989361122,True,False,False,Low +region_46,78,73.99057939170262,1710.5751676177922,1111.873858951565,85.52875838088971,False,513.1725502853376,4887.357621765121,Concrete,Wood & Concrete,Finished – Parquet or polished wood,1571.281989361122,False,False,False,Low +region_0,79,1.5101434626333,1844.2237339363137,1536.8531116135948,307.3706223227189,True,0.0,5269.210668389468,Finished – Metal,Concrete/Concrete Blocks,Other,1571.281989361122,False,False,True,Medium +region_12,80,69.72162728554343,2028.0826711148727,1318.2537362246671,101.40413355574378,False,608.4248013344618,5794.521917471065,Finished – Metal,Concrete/Concrete Blocks,Finished – Parquet or polished wood,1571.281989361122,False,True,True,Medium +region_54,81,92.03123328367624,1417.4250796083218,921.326301745409,70.87125398041627,False,425.22752388249654,4049.7859417380623,Shingle (asphalt),Wood/Timber,Finished – Cement/red bricks,1571.281989361122,True,True,False,Low +region_9,82,71.33512019094466,2450.4132434770936,2042.0110362309115,408.4022072461821,True,0.0,7001.180695648839,Concrete,Concrete/Concrete blocks,Rudimentary – Wood planks,1571.281989361122,False,True,True,High +region_18,83,18.523572375182095,2232.8312198652297,1860.692683221025,372.1385366442048,True,0.0,6379.517771043514,Finished – Concrete,Brick/Blocks,Finished – Cement/red bricks,1571.281989361122,False,False,True,High +region_4,84,48.86829461531841,1231.878156861388,1026.5651307178234,205.31302614356468,True,0.0,3519.6518767468233,Finished – Metal,Concrete/Concrete blocks,Finished – Cement/red bricks,1571.281989361122,True,False,True,Low +region_7,85,14.891285774418522,2744.1260968978,2286.7717474148335,457.3543494829664,True,0.0,7840.360276850857,Shingle (asphalt),Brick/Blocks,Finished – Cement/red bricks,1571.281989361122,False,False,False,High +region_3,86,36.54053255562358,2947.9445880152916,2456.620490012743,491.32409800254845,True,0.0,8422.698822900833,Shingle (wood),Rudimentary – Plywood,Finished – Cement/red bricks,1571.281989361122,False,False,True,High +region_48,87,93.77458715211125,2589.3897855798255,2157.824821316521,431.5649642633043,True,0.0,7398.256530228073,Tile,Finished – Cement blocks,Rudimentary – Wood planks,1571.281989361122,False,False,False,High +region_12,88,92.40722544831212,1910.0375820938245,1591.6979850781872,318.3395970156373,True,0.0,5457.250234553784,Concrete,Wood/Timber,Finished – Parquet or polished wood,1571.281989361122,False,False,True,Medium +region_37,89,29.00084836543221,1464.6236892447287,1220.519741037274,244.10394820745478,True,0.0,4184.639112127797,"Sheet metal (galvanize, galvalume)",Concrete/Concrete blocks,Finished – Cement/red bricks,1571.281989361122,True,False,True,Low +region_52,90,34.62347337245372,2527.225863465568,2106.0215528879735,421.2043105775947,True,0.0,7220.645324187338,Finished – Asbestos,Concrete/Concrete Blocks,Finished – Cement/red bricks,1571.281989361122,False,False,True,High +region_45,91,60.4210739449981,1798.41152651341,1498.6762720945085,299.7352544189016,True,0.0,5138.318647181171,Finished – Metal,Finished – Cement blocks,Rudimentary – Wood planks,1571.281989361122,False,True,False,Low +region_48,92,96.35653223077762,2611.222535191214,2176.0187793260116,435.2037558652023,True,0.0,7460.63581483204,Shingle (wood),Finished – Cement blocks,Other,1571.281989361122,False,False,True,High +region_45,93,15.632332072473652,2104.13748903843,1753.447907532025,350.6895815064049,True,0.0,6011.821397252657,Tile,Finished – Stone with lime/cement,Other,1571.281989361122,False,False,True,Medium +region_18,94,26.43474772498024,2488.3195182418563,2073.5995985348804,414.7199197069758,True,0.0,7109.4843378338755,Shingle (wood),Finished – Cement blocks,Finished – Cement/red bricks,1571.281989361122,False,False,True,High +region_51,95,87.48212590178638,2178.183198587201,1815.1526654893341,363.03053309786674,True,0.0,6223.380567392002,Finished – Asbestos,Finished – Stone with lime/cement,Other,1571.281989361122,False,False,False,Medium +region_49,96,49.697330939126104,2353.286584095974,1961.0721534133118,392.21443068266217,True,0.0,6723.675954559925,"Sheet metal (galvanize, galvalume)",Wood & Concrete,Rudimentary – Wood planks,1571.281989361122,False,False,False,High +region_7,97,89.99714813047613,2005.2500103604102,1303.4125067342666,100.2625005180206,False,601.575003108123,5729.285743886887,Shingle (wood),Finished – Cement blocks,Finished – Parquet or polished wood,1571.281989361122,False,False,True,Medium +region_26,98,19.36627185479445,2892.9352469529176,1880.4079105193964,144.6467623476459,False,867.8805740858753,8265.529277008336,Concrete,Finished – Cement blocks,Finished – Cement/red bricks,1571.281989361122,False,False,True,High +region_49,99,53.734190159664706,2063.45604635181,1719.5467052931751,343.90934105863494,True,0.0,5895.588703862315,Concrete,Wood & Concrete,Finished – Cement/red bricks,1571.281989361122,False,False,True,Medium +region_46,100,33.30069363228787,2200.994681722351,1834.1622347686257,366.83244695372514,True,0.0,6288.556233492431,Finished – Concrete,Concrete/Concrete blocks,Finished – Cement/red bricks,1571.281989361122,False,False,True,Medium diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index 0ef869b..0000000 --- a/docs/index.html +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/docs/search.js b/docs/search.js deleted file mode 100644 index c969eea..0000000 --- a/docs/search.js +++ /dev/null @@ -1,46 +0,0 @@ -window.pdocSearch = (function(){ -/** elasticlunr - http://weixsong.github.io * Copyright (C) 2017 Oliver Nightingale * Copyright (C) 2017 Wei Song * MIT Licensed */!function(){function e(e){if(null===e||"object"!=typeof e)return e;var t=e.constructor();for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.9.5",lunr=t,t.utils={},t.utils.warn=function(e){return function(t){e.console&&console.warn&&console.warn(t)}}(this),t.utils.toString=function(e){return void 0===e||null===e?"":e.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var e=Array.prototype.slice.call(arguments),t=e.pop(),n=e;if("function"!=typeof t)throw new TypeError("last argument must be a function");n.forEach(function(e){this.hasHandler(e)||(this.events[e]=[]),this.events[e].push(t)},this)},t.EventEmitter.prototype.removeListener=function(e,t){if(this.hasHandler(e)){var n=this.events[e].indexOf(t);-1!==n&&(this.events[e].splice(n,1),0==this.events[e].length&&delete this.events[e])}},t.EventEmitter.prototype.emit=function(e){if(this.hasHandler(e)){var t=Array.prototype.slice.call(arguments,1);this.events[e].forEach(function(e){e.apply(void 0,t)},this)}},t.EventEmitter.prototype.hasHandler=function(e){return e in this.events},t.tokenizer=function(e){if(!arguments.length||null===e||void 0===e)return[];if(Array.isArray(e)){var n=e.filter(function(e){return null===e||void 0===e?!1:!0});n=n.map(function(e){return t.utils.toString(e).toLowerCase()});var i=[];return n.forEach(function(e){var n=e.split(t.tokenizer.seperator);i=i.concat(n)},this),i}return e.toString().trim().toLowerCase().split(t.tokenizer.seperator)},t.tokenizer.defaultSeperator=/[\s\-]+/,t.tokenizer.seperator=t.tokenizer.defaultSeperator,t.tokenizer.setSeperator=function(e){null!==e&&void 0!==e&&"object"==typeof e&&(t.tokenizer.seperator=e)},t.tokenizer.resetSeperator=function(){t.tokenizer.seperator=t.tokenizer.defaultSeperator},t.tokenizer.getSeperator=function(){return t.tokenizer.seperator},t.Pipeline=function(){this._queue=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in t.Pipeline.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[n]=e},t.Pipeline.getRegisteredFunction=function(e){return e in t.Pipeline.registeredFunctions!=!0?null:t.Pipeline.registeredFunctions[e]},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.getRegisteredFunction(e);if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._queue.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i+1,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i,0,n)},t.Pipeline.prototype.remove=function(e){var t=this._queue.indexOf(e);-1!==t&&this._queue.splice(t,1)},t.Pipeline.prototype.run=function(e){for(var t=[],n=e.length,i=this._queue.length,o=0;n>o;o++){for(var r=e[o],s=0;i>s&&(r=this._queue[s](r,o,e),void 0!==r&&null!==r);s++);void 0!==r&&null!==r&&t.push(r)}return t},t.Pipeline.prototype.reset=function(){this._queue=[]},t.Pipeline.prototype.get=function(){return this._queue},t.Pipeline.prototype.toJSON=function(){return this._queue.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Index=function(){this._fields=[],this._ref="id",this.pipeline=new t.Pipeline,this.documentStore=new t.DocumentStore,this.index={},this.eventEmitter=new t.EventEmitter,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},t.Index.prototype.on=function(){var e=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,e)},t.Index.prototype.off=function(e,t){return this.eventEmitter.removeListener(e,t)},t.Index.load=function(e){e.version!==t.version&&t.utils.warn("version mismatch: current "+t.version+" importing "+e.version);var n=new this;n._fields=e.fields,n._ref=e.ref,n.documentStore=t.DocumentStore.load(e.documentStore),n.pipeline=t.Pipeline.load(e.pipeline),n.index={};for(var i in e.index)n.index[i]=t.InvertedIndex.load(e.index[i]);return n},t.Index.prototype.addField=function(e){return this._fields.push(e),this.index[e]=new t.InvertedIndex,this},t.Index.prototype.setRef=function(e){return this._ref=e,this},t.Index.prototype.saveDocument=function(e){return this.documentStore=new t.DocumentStore(e),this},t.Index.prototype.addDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.addDoc(i,e),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));this.documentStore.addFieldLength(i,n,o.length);var r={};o.forEach(function(e){e in r?r[e]+=1:r[e]=1},this);for(var s in r){var u=r[s];u=Math.sqrt(u),this.index[n].addToken(s,{ref:i,tf:u})}},this),n&&this.eventEmitter.emit("add",e,this)}},t.Index.prototype.removeDocByRef=function(e){if(e&&this.documentStore.isDocStored()!==!1&&this.documentStore.hasDoc(e)){var t=this.documentStore.getDoc(e);this.removeDoc(t,!1)}},t.Index.prototype.removeDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.hasDoc(i)&&(this.documentStore.removeDoc(i),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));o.forEach(function(e){this.index[n].removeToken(e,i)},this)},this),n&&this.eventEmitter.emit("remove",e,this))}},t.Index.prototype.updateDoc=function(e,t){var t=void 0===t?!0:t;this.removeDocByRef(e[this._ref],!1),this.addDoc(e,!1),t&&this.eventEmitter.emit("update",e,this)},t.Index.prototype.idf=function(e,t){var n="@"+t+"/"+e;if(Object.prototype.hasOwnProperty.call(this._idfCache,n))return this._idfCache[n];var i=this.index[t].getDocFreq(e),o=1+Math.log(this.documentStore.length/(i+1));return this._idfCache[n]=o,o},t.Index.prototype.getFields=function(){return this._fields.slice()},t.Index.prototype.search=function(e,n){if(!e)return[];e="string"==typeof e?{any:e}:JSON.parse(JSON.stringify(e));var i=null;null!=n&&(i=JSON.stringify(n));for(var o=new t.Configuration(i,this.getFields()).get(),r={},s=Object.keys(e),u=0;u0&&t.push(e);for(var i in n)"docs"!==i&&"df"!==i&&this.expandToken(e+i,t,n[i]);return t},t.InvertedIndex.prototype.toJSON=function(){return{root:this.root}},t.Configuration=function(e,n){var e=e||"";if(void 0==n||null==n)throw new Error("fields should not be null");this.config={};var i;try{i=JSON.parse(e),this.buildUserConfig(i,n)}catch(o){t.utils.warn("user configuration parse failed, will use default configuration"),this.buildDefaultConfig(n)}},t.Configuration.prototype.buildDefaultConfig=function(e){this.reset(),e.forEach(function(e){this.config[e]={boost:1,bool:"OR",expand:!1}},this)},t.Configuration.prototype.buildUserConfig=function(e,n){var i="OR",o=!1;if(this.reset(),"bool"in e&&(i=e.bool||i),"expand"in e&&(o=e.expand||o),"fields"in e)for(var r in e.fields)if(n.indexOf(r)>-1){var s=e.fields[r],u=o;void 0!=s.expand&&(u=s.expand),this.config[r]={boost:s.boost||0===s.boost?s.boost:1,bool:s.bool||i,expand:u}}else t.utils.warn("field name in user configuration not found in index instance fields");else this.addAllFields2UserConfig(i,o,n)},t.Configuration.prototype.addAllFields2UserConfig=function(e,t,n){n.forEach(function(n){this.config[n]={boost:1,bool:e,expand:t}},this)},t.Configuration.prototype.get=function(){return this.config},t.Configuration.prototype.reset=function(){this.config={}},lunr.SortedSet=function(){this.length=0,this.elements=[]},lunr.SortedSet.load=function(e){var t=new this;return t.elements=e,t.length=e.length,t},lunr.SortedSet.prototype.add=function(){var e,t;for(e=0;e1;){if(r===e)return o;e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o]}return r===e?o:-1},lunr.SortedSet.prototype.locationFor=function(e){for(var t=0,n=this.elements.length,i=n-t,o=t+Math.floor(i/2),r=this.elements[o];i>1;)e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o];return r>e?o:e>r?o+1:void 0},lunr.SortedSet.prototype.intersect=function(e){for(var t=new lunr.SortedSet,n=0,i=0,o=this.length,r=e.length,s=this.elements,u=e.elements;;){if(n>o-1||i>r-1)break;s[n]!==u[i]?s[n]u[i]&&i++:(t.add(s[n]),n++,i++)}return t},lunr.SortedSet.prototype.clone=function(){var e=new lunr.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},lunr.SortedSet.prototype.union=function(e){var t,n,i;this.length>=e.length?(t=this,n=e):(t=e,n=this),i=t.clone();for(var o=0,r=n.toArray();o

\n"}, "src.data": {"fullname": "src.data", "modulename": "src.data", "kind": "module", "doc": "

\n"}, "src.data.analyse": {"fullname": "src.data.analyse", "modulename": "src.data.analyse", "kind": "module", "doc": "

\n"}, "src.data.analyse.prepare_outcomes": {"fullname": "src.data.analyse.prepare_outcomes", "modulename": "src.data.analyse", "qualname": "prepare_outcomes", "kind": "function", "doc": "

Convert outcomes dict into a data frame.

\n\n

Args:\n results (tuple): The results of the experiments in the EMA Workbench format.\n add_policies (bool): Whether to add policy values to the data frame.\n add_uncertainties (bool): Whether to add uncertainty values to the data frame.

\n\n

Returns:\n pd.DataFrame: Outcomes data frame.

\n", "signature": "(\tresults: tuple,\tadd_policies: bool,\tadd_uncertainties: bool) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.analyse.get_spatial_outcomes": {"fullname": "src.data.analyse.get_spatial_outcomes", "modulename": "src.data.analyse", "qualname": "get_spatial_outcomes", "kind": "function", "doc": "

\n", "signature": "(\toutcomes: pandas.core.frame.DataFrame,\toutcomes_of_interest: list = [],\tcountry: str = 'Saint Lucia',\taggregation: str = 'mean') -> geopandas.geodataframe.GeoDataFrame:", "funcdef": "def"}, "src.data.analyse.get_policy_effectiveness_tab": {"fullname": "src.data.analyse.get_policy_effectiveness_tab", "modulename": "src.data.analyse", "qualname": "get_policy_effectiveness_tab", "kind": "function", "doc": "

\n", "signature": "(outcomes: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.prepare": {"fullname": "src.data.prepare", "modulename": "src.data.prepare", "kind": "module", "doc": "

\n"}, "src.data.prepare.prepare_asset_damage": {"fullname": "src.data.prepare.prepare_asset_damage", "modulename": "src.data.prepare", "qualname": "prepare_asset_damage", "kind": "function", "doc": "

Prepare district-level asset damage data and save it into a XLSX file.

\n", "signature": "(country: str, scale: str, return_period: int = 100) -> None:", "funcdef": "def"}, "src.data.prepare.prepare_household_survey": {"fullname": "src.data.prepare.prepare_household_survey", "modulename": "src.data.prepare", "qualname": "prepare_household_survey", "kind": "function", "doc": "

Prepare data for the simulation model.

\n\n

Parameters

\n\n

country : str

\n\n

Raises

\n\n

ValueError\n If the country is not supported.

\n", "signature": "(country: str) -> None:", "funcdef": "def"}, "src.data.prepare.load_data": {"fullname": "src.data.prepare.load_data", "modulename": "src.data.prepare", "qualname": "load_data", "kind": "function", "doc": "

Load the raw data.

\n", "signature": "(print_statistics: bool = True) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.prepare.start_pipeline": {"fullname": "src.data.prepare.start_pipeline", "modulename": "src.data.prepare", "qualname": "start_pipeline", "kind": "function", "doc": "

Start the data processing pipeline.

\n", "signature": "(data: pandas.core.frame.DataFrame):", "funcdef": "def"}, "src.data.prepare.add_is_rural_column": {"fullname": "src.data.prepare.add_is_rural_column", "modulename": "src.data.prepare", "qualname": "add_is_rural_column", "kind": "function", "doc": "

Create a new column that indicates whether the household is rural or not.

\n", "signature": "(\tdata: pandas.core.frame.DataFrame,\tprint_statistics: bool = True) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.prepare.rename_assets_column": {"fullname": "src.data.prepare.rename_assets_column", "modulename": "src.data.prepare", "qualname": "rename_assets_column", "kind": "function", "doc": "

Rename the assets column to be more descriptive.

\n", "signature": "(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.prepare.rename_other_columns": {"fullname": "src.data.prepare.rename_other_columns", "modulename": "src.data.prepare", "qualname": "rename_other_columns", "kind": "function", "doc": "

Rename a set of columns. See function for details.

\n", "signature": "(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.prepare.calculate_household_attributes": {"fullname": "src.data.prepare.calculate_household_attributes", "modulename": "src.data.prepare", "qualname": "calculate_household_attributes", "kind": "function", "doc": "

\n", "signature": "(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.prepare.get_bank_or_credit_union": {"fullname": "src.data.prepare.get_bank_or_credit_union", "modulename": "src.data.prepare", "qualname": "get_bank_or_credit_union", "kind": "function", "doc": "

\n", "signature": "(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.prepare.decode_demographic_attributes": {"fullname": "src.data.prepare.decode_demographic_attributes", "modulename": "src.data.prepare", "qualname": "decode_demographic_attributes", "kind": "function", "doc": "

Decode the demographic attributes.

\n", "signature": "(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.prepare.decode_income_attributes": {"fullname": "src.data.prepare.decode_income_attributes", "modulename": "src.data.prepare", "qualname": "decode_income_attributes", "kind": "function", "doc": "

Decode the income-related attributes.

\n", "signature": "(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.prepare.calculate_income_attributes": {"fullname": "src.data.prepare.calculate_income_attributes", "modulename": "src.data.prepare", "qualname": "calculate_income_attributes", "kind": "function", "doc": "

\n", "signature": "(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.prepare.decode_housing_attributes": {"fullname": "src.data.prepare.decode_housing_attributes", "modulename": "src.data.prepare", "qualname": "decode_housing_attributes", "kind": "function", "doc": "

Decode the housing-related attributes.

\n", "signature": "(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.prepare.add_housing_attributes": {"fullname": "src.data.prepare.add_housing_attributes", "modulename": "src.data.prepare", "qualname": "add_housing_attributes", "kind": "function", "doc": "

Introduce new housing attributes.

\n", "signature": "(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.prepare.add_insurance_attributes": {"fullname": "src.data.prepare.add_insurance_attributes", "modulename": "src.data.prepare", "qualname": "add_insurance_attributes", "kind": "function", "doc": "

\n", "signature": "(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.prepare.calculate_housing_attributes": {"fullname": "src.data.prepare.calculate_housing_attributes", "modulename": "src.data.prepare", "qualname": "calculate_housing_attributes", "kind": "function", "doc": "

\n", "signature": "(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.prepare.calculate_poverty_attributes": {"fullname": "src.data.prepare.calculate_poverty_attributes", "modulename": "src.data.prepare", "qualname": "calculate_poverty_attributes", "kind": "function", "doc": "

\n", "signature": "(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.prepare.assign_housing_vulnerability": {"fullname": "src.data.prepare.assign_housing_vulnerability", "modulename": "src.data.prepare", "qualname": "assign_housing_vulnerability", "kind": "function", "doc": "

\n", "signature": "(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.prepare.subset_columns": {"fullname": "src.data.prepare.subset_columns", "modulename": "src.data.prepare", "qualname": "subset_columns", "kind": "function", "doc": "

Subset columns of interest.

\n", "signature": "(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.prepare.check_columns": {"fullname": "src.data.prepare.check_columns", "modulename": "src.data.prepare", "qualname": "check_columns", "kind": "function", "doc": "

\n", "signature": "(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.prepare.add_missing_columns": {"fullname": "src.data.prepare.add_missing_columns", "modulename": "src.data.prepare", "qualname": "add_missing_columns", "kind": "function", "doc": "

Manually add missing columns to the data.

\n", "signature": "(\tdata: pandas.core.frame.DataFrame,\tmissing_columns: list) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.prepare.merge_districts": {"fullname": "src.data.prepare.merge_districts", "modulename": "src.data.prepare", "qualname": "merge_districts", "kind": "function", "doc": "

\n", "signature": "(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.prepare.exponential_regression": {"fullname": "src.data.prepare.exponential_regression", "modulename": "src.data.prepare", "qualname": "exponential_regression", "kind": "function", "doc": "

\n", "signature": "(\tdata: pandas.core.frame.DataFrame,\tX_column: str,\ty_column: str,\tweights: <built-in function array> = None,\treturn_model: bool = False) -> tuple[numpy.array, float]:", "funcdef": "def"}, "src.data.prepare.polynomial_regression": {"fullname": "src.data.prepare.polynomial_regression", "modulename": "src.data.prepare", "qualname": "polynomial_regression", "kind": "function", "doc": "

\n", "signature": "(\tdata: pandas.core.frame.DataFrame,\tX_column: str,\ty_column: str,\tpower: int,\tweights: <built-in function array> = None,\tX_new: <built-in function array> = None,\tX_start: int = 0,\tX_end: int = 40,\tX_num: int = 100):", "funcdef": "def"}, "src.data.prepare.linear_regression": {"fullname": "src.data.prepare.linear_regression", "modulename": "src.data.prepare", "qualname": "linear_regression", "kind": "function", "doc": "

Do a linear regression on the data and return the predicted values, the coefficient and the r2 score.

\n", "signature": "(\tdata: pandas.core.frame.DataFrame,\tX_column: str,\ty_column: str,\tweights: <built-in function array> = None,\treturn_model: bool = False) -> tuple[numpy.array, float, float]:", "funcdef": "def"}, "src.data.read": {"fullname": "src.data.read", "modulename": "src.data.read", "kind": "module", "doc": "

\n"}, "src.data.read.read_asset_damage": {"fullname": "src.data.read.read_asset_damage", "modulename": "src.data.read", "qualname": "read_asset_damage", "kind": "function", "doc": "

Read asset damage for all districts from a XLSX file and load it into the memory.

\n", "signature": "(country) -> None:", "funcdef": "def"}, "src.data.read.get_asset_damage": {"fullname": "src.data.read.get_asset_damage", "modulename": "src.data.read", "qualname": "get_asset_damage", "kind": "function", "doc": "

Get asset damage for a specific district.

\n\n

Args:\n all_damage (pd.DataFrame): Asset damage data for all districts.\n scale (str): Scale of the analysis. Only district is supported.\n district (str): District name.\n return_period (int): Return period.\n print_statistics (bool): Print the statistics.

\n\n

Returns:\n tuple: Event damage, total asset stock, expected loss fraction.

\n\n

Raises:\n ValueError: If the scale is not district.
\n ValueError: If the expected loss fraction is greater than 1.

\n", "signature": "(\tall_damage: pandas.core.frame.DataFrame,\tscale: str,\tdistrict: str,\treturn_period: int,\tprint_statistics: bool) -> tuple:", "funcdef": "def"}, "src.data.read.read_household_survey": {"fullname": "src.data.read.read_household_survey", "modulename": "src.data.read", "qualname": "read_household_survey", "kind": "function", "doc": "

Reads household survey from a CSV file.

\n\n

Args:\n country (str): Country name.

\n\n

Returns:\n pd.DataFrame: Household survey data.

\n\n

Raises:\n ValueError: If the country is not Saint Lucia.

\n", "signature": "(country: str) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.visualise": {"fullname": "src.data.visualise", "modulename": "src.data.visualise", "kind": "module", "doc": "

\n"}, "src.data.visualise.rainclouds": {"fullname": "src.data.visualise.rainclouds", "modulename": "src.data.visualise", "qualname": "rainclouds", "kind": "function", "doc": "

\n", "signature": "(\toutcomes: pandas.core.frame.DataFrame,\tsavefigs: bool,\tx_columns: list = [],\tx_titles: list = [],\tplot_years_in_poverty: bool = False,\tcolor_palette: str = 'Set2',\tsharex: bool = True):", "funcdef": "def"}, "src.data.visualise.bivariate_choropleth": {"fullname": "src.data.visualise.bivariate_choropleth", "modulename": "src.data.visualise", "qualname": "bivariate_choropleth", "kind": "function", "doc": "

\n", "signature": "(data, x_name, y_name, x_label, y_label, scale, figsize, return_table):", "funcdef": "def"}, "src.data.visualise.nine_quadrants_plot": {"fullname": "src.data.visualise.nine_quadrants_plot", "modulename": "src.data.visualise", "qualname": "nine_quadrants_plot", "kind": "function", "doc": "

\n", "signature": "(data, x_name, y_name, scale=True):", "funcdef": "def"}, "src.data.visualise.get_colors": {"fullname": "src.data.visualise.get_colors", "modulename": "src.data.visualise", "qualname": "get_colors", "kind": "function", "doc": "

\n", "signature": "(data):", "funcdef": "def"}, "src.data.visualise.bin_data": {"fullname": "src.data.visualise.bin_data", "modulename": "src.data.visualise", "qualname": "bin_data", "kind": "function", "doc": "

\n", "signature": "(data, x_name, y_name, scale, print_statistics=True):", "funcdef": "def"}, "src.data.write": {"fullname": "src.data.write", "modulename": "src.data.write", "kind": "module", "doc": "

\n"}, "src.data.write.add_columns": {"fullname": "src.data.write.add_columns", "modulename": "src.data.write", "qualname": "add_columns", "kind": "function", "doc": "

Add columns/outcomes of interest from affected households to the households dataframe.

\n", "signature": "(\thouseholds: pandas.core.frame.DataFrame,\taffected_households: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.data.write.get_outcomes": {"fullname": "src.data.write.get_outcomes", "modulename": "src.data.write", "qualname": "get_outcomes", "kind": "function", "doc": "

Calculate outcomes of interest from the simulation model.

\n\n

Args:\n households (pd.DataFrame): Households data frame.\n event_damage (float): Event damage.\n total_asset_stock (float): Total asset stock.\n expected_loss_fraction (float): Expected loss fraction.\n average_productivity (float): Average productivity.\n n_years (float): Number of years to consider for calculations (same as for optimization algorithm).

\n\n

Returns:\n dict: Outcomes of interest.

\n", "signature": "(\thouseholds,\tevent_damage,\ttotal_asset_stock,\texpected_loss_fraction,\taverage_productivity,\tn_years) -> dict:", "funcdef": "def"}, "src.data.write.find_poor": {"fullname": "src.data.write.find_poor", "modulename": "src.data.write", "qualname": "find_poor", "kind": "function", "doc": "

Get the poor at the beginning of the simulation and the poor at the end of the simulation

\n\n

Args:\n households (pd.DataFrame): Household dataframe\n poverty_line (float): Poverty line

\n\n

Returns:\n tuple: Number of poor at the beginning of the simulation, number of new poor at the end of the simulation, and the new poor dataframe

\n", "signature": "(\thouseholds: pandas.core.frame.DataFrame,\tpoverty_line: float,\tn_years: int) -> tuple:", "funcdef": "def"}, "src.data.write.get_people_by_years_in_poverty": {"fullname": "src.data.write.get_people_by_years_in_poverty", "modulename": "src.data.write", "qualname": "get_people_by_years_in_poverty", "kind": "function", "doc": "

Get the number of people in poverty for each year in poverty.

\n\n

Args:\n new_poor (pd.DataFrame): New poor dataframe

\n\n

Returns:\n dict: Number of people in poverty for each year in poverty

\n", "signature": "(new_poor: pandas.core.frame.DataFrame) -> dict:", "funcdef": "def"}, "src.data.write.calculate_poverty_gap": {"fullname": "src.data.write.calculate_poverty_gap", "modulename": "src.data.write", "qualname": "calculate_poverty_gap", "kind": "function", "doc": "

Calculate the poverty gap at the beginning and at the end of the simulation.

\n\n

Args:\n poor_initial (pd.DataFrame): Poor at the beginning of the simulation\n new_poor (pd.DataFrame): New poor at the end of the simulation\n poverty_line (float): Poverty line\n n_years (int): Number of years of the optimization algorithm

\n\n

Returns:\n tuple: Poverty gap at the beginning and at the end of the simulation

\n\n

Raises:\n Exception: If the index is duplicated\n Exception: If the poverty gap is greater than 1

\n", "signature": "(\tpoor_initial: pandas.core.frame.DataFrame,\tnew_poor: pandas.core.frame.DataFrame,\tpoverty_line: float,\tn_years: int) -> tuple:", "funcdef": "def"}, "src.data.write.calculate_average_annual_consumption_loss": {"fullname": "src.data.write.calculate_average_annual_consumption_loss", "modulename": "src.data.write", "qualname": "calculate_average_annual_consumption_loss", "kind": "function", "doc": "

Get the average annual consumption loss and the average annual consumption loss as a percentage of average annual consumption.

\n\n

Args:\n affected_households (pd.DataFrame): Affected households dataframe\n n_years (int): Number of years of the optimization algorithm

\n\n

Returns:\n tuple: Average annual consumption loss and average annual consumption loss as a percentage of average annual consumption

\n\n

Raises:\n Exception: If the average annual consumption loss is greater than 1

\n", "signature": "(affected_households: pandas.core.frame.DataFrame, n_years: int) -> tuple:", "funcdef": "def"}, "src.data.write.calculate_resilience": {"fullname": "src.data.write.calculate_resilience", "modulename": "src.data.write", "qualname": "calculate_resilience", "kind": "function", "doc": "

Calculate the resilience of the affected households.

\n\n

Args:\n affected_households (pd.DataFrame): Affected households dataframe\n pml (float): Probable maximum loss

\n\n

Returns:\n tuple: Resilience and number of times resilience is greater than 1

\n\n

Raises:\n Exception: If the total consumption loss is 0

\n", "signature": "(affected_households: pandas.core.frame.DataFrame, pml: float) -> tuple:", "funcdef": "def"}, "src.model": {"fullname": "src.model", "modulename": "src.model", "kind": "module", "doc": "

\n"}, "src.model.initialize_model": {"fullname": "src.model.initialize_model", "modulename": "src.model", "qualname": "initialize_model", "kind": "function", "doc": "

Initialize the model by reading household survey and asset damage files.

\n\n

Args:\n country (str): Country name.\n min_households (int): Minimum number of households that we need to have in a sample to be representative.

\n\n

Returns:\n tuple: Household survey and asset damage files.

\n", "signature": "(country: str, min_households: int) -> tuple:", "funcdef": "def"}, "src.model.run_model": {"fullname": "src.model.run_model", "modulename": "src.model", "qualname": "run_model", "kind": "function", "doc": "

Run the model.

\n", "signature": "(**kwargs):", "funcdef": "def"}, "src.modules": {"fullname": "src.modules", "modulename": "src.modules", "kind": "module", "doc": "

\n"}, "src.modules.households": {"fullname": "src.modules.households", "modulename": "src.modules.households", "kind": "module", "doc": "

\n"}, "src.modules.households.duplicate_households": {"fullname": "src.modules.households.duplicate_households", "modulename": "src.modules.households", "qualname": "duplicate_households", "kind": "function", "doc": "

Duplicates households if the number of households is less than min_households threshold.

\n\n

Args:\n household_survey (pd.DataFrame): Household survey data.\n min_households (int): Minimum number of households.

\n\n

Returns:\n pd.DataFrame: Household survey data with duplicated households.

\n\n

Raises:\n ValueError: If the total weights after duplication is not equal to the initial total weights.

\n", "signature": "(\thousehold_survey: pandas.core.frame.DataFrame,\tmin_households: int) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.modules.households.calculate_average_productivity": {"fullname": "src.modules.households.calculate_average_productivity", "modulename": "src.modules.households", "qualname": "calculate_average_productivity", "kind": "function", "doc": "

Calculate average productivity as aeinc \\ k_house_ae.

\n\n

Args:\n households (pd.DataFrame): Household survey data.\n print_statistics (bool, optional): Whether to print the average productivity. Defaults to False.

\n\n

Returns:\n float: Average productivity.

\n", "signature": "(households: pandas.core.frame.DataFrame, print_statistics: bool) -> float:", "funcdef": "def"}, "src.modules.households.adjust_assets_and_expenditure": {"fullname": "src.modules.households.adjust_assets_and_expenditure", "modulename": "src.modules.households", "qualname": "adjust_assets_and_expenditure", "kind": "function", "doc": "

Adjust assets and expenditure of household to match data of asset damage file.

\n\n

There can be a mismatch between the data in the household survey and the of the asset damage.\nThe latest was created independently.

\n\n

Args:\n households (pd.DataFrame): Household survey data.\n total_asset_stock (float): Total asset stock.\n poverty_line (float): Poverty line.\n indigence_line (float): Indigence line.\n print_statistics (bool, optional): Whether to print the statistics. Defaults to False.

\n\n

Returns:\n pd.DataFrame: Household survey data with adjusted assets and expenditure.

\n", "signature": "(\thouseholds: pandas.core.frame.DataFrame,\ttotal_asset_stock: float,\tpoverty_line: float,\tindigence_line: float,\tprint_statistics: bool) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.modules.households.calculate_pml": {"fullname": "src.modules.households.calculate_pml", "modulename": "src.modules.households", "qualname": "calculate_pml", "kind": "function", "doc": "

Calculate probable maximum loss as a product of population weight, effective capital stock and expected loss fraction.

\n\n

Args:\n households (pd.DataFrame): Household survey data.\n expected_loss_fraction (float): Expected loss fraction.\n print_statistics (bool, optional): Whether to print the statistics. Defaults to False.

\n\n

Returns:\n pd.DataFrame: Household survey data with probable maximum loss.

\n", "signature": "(\thouseholds: pandas.core.frame.DataFrame,\texpected_loss_fraction: float,\tprint_statistics: bool) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.modules.households.select_district": {"fullname": "src.modules.households.select_district", "modulename": "src.modules.households", "qualname": "select_district", "kind": "function", "doc": "

Select households for a specific district.

\n", "signature": "(\thousehold_survey: pandas.core.frame.DataFrame,\tdistrict: str) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.modules.households.estimate_savings": {"fullname": "src.modules.households.estimate_savings", "modulename": "src.modules.households", "qualname": "estimate_savings", "kind": "function", "doc": "

Estimate savings of households.

\n\n

We assume that savings are a product of expenditure and saving rate with Gaussian noise.

\n\n

Args:\n households (pd.DataFrame): Household survey data for a specific district.\n saving_rate (float): Saving rate.\n estimate_savings_params (dict): Parameters for estimating savings function.

\n\n

Returns:\n pd.DataFrame: Household survey data with estimated savings.

\n", "signature": "(\thouseholds: pandas.core.frame.DataFrame,\tsaving_rate: float,\testimate_savings_params: dict) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.modules.households.set_vulnerability": {"fullname": "src.modules.households.set_vulnerability", "modulename": "src.modules.households", "qualname": "set_vulnerability", "kind": "function", "doc": "

Set vulnerability of households.

\n\n

Vulnerability can be random or based on v_init with uniform noise.

\n\n

Args:\n households (pd.DataFrame): Household survey data for a specific district.\n is_vulnerability_random (bool): If True, vulnerability is random.

\n\n

Returns:\n pd.DataFrame: Household survey data with assigned vulnerability.

\n\n

Raises:\n ValueError: If the distribution is not supported.

\n", "signature": "(\thouseholds: pandas.core.frame.DataFrame,\tis_vulnerability_random: bool,\tset_vulnerability_params: dict) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.modules.households.calculate_exposure": {"fullname": "src.modules.households.calculate_exposure", "modulename": "src.modules.households", "qualname": "calculate_exposure", "kind": "function", "doc": "

Calculate exposure of households.

\n\n

Exposure is a function of poverty bias, effective capital stock, \nvulnerability and probable maximum loss.

\n\n

Args:\n households (pd.DataFrame): Household survey data for a specific district.\n poverty_bias (float): Poverty bias.\n calculate_exposure_params (dict): Parameters for calculating exposure function.\n print_statistics (bool): If True, print statistics.

\n\n

Returns:\n pd.DataFrame: Household survey data with calculated exposure.

\n", "signature": "(\thouseholds: pandas.core.frame.DataFrame,\tpoverty_bias: float,\tcalculate_exposure_params: dict,\tprint_statistics: bool) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.modules.households.determine_affected": {"fullname": "src.modules.households.determine_affected", "modulename": "src.modules.households", "qualname": "determine_affected", "kind": "function", "doc": "

Determines affected households.

\n\n

We assume that all households have the same probability of being affected, \nbut based on fa calculated in calculate_exposure.

\n\n

Args:\n households (pd.DataFrame): Household survey data for a specific district.\n determine_affected_params (dict): Parameters for determining affected households function.

\n\n

Returns:\n tuple: Household survey data with determined affected households and asset loss for each household.

\n\n

Raises:\n ValueError: If total asset is less than PML.\n ValueError: If no mask was found.

\n", "signature": "(\thouseholds: pandas.core.frame.DataFrame,\tdetermine_affected_params: dict) -> tuple:", "funcdef": "def"}, "src.modules.households.apply_individual_policy": {"fullname": "src.modules.households.apply_individual_policy", "modulename": "src.modules.households", "qualname": "apply_individual_policy", "kind": "function", "doc": "

Apply a policy to a specific target group.

\n\n

Args:\n households (pd.DataFrame): Household survey data for a specific district.\n my_policy (str): Policy to apply. The structure of the policy is target_group+top_up in a single string. target_group can be all, poor, poor_near_poor1.25, poor_near_poor2.0, and the top_up 0, 10, 30 or 50.

\n\n

Returns:\n tuple: Household survey data with applied policy and affected households.

\n", "signature": "(households: pandas.core.frame.DataFrame, my_policy: str) -> tuple:", "funcdef": "def"}, "src.modules.optimize": {"fullname": "src.modules.optimize", "modulename": "src.modules.optimize", "kind": "module", "doc": "

\n"}, "src.modules.optimize.run_optimization": {"fullname": "src.modules.optimize.run_optimization", "modulename": "src.modules.optimize", "qualname": "run_optimization", "kind": "function", "doc": "

This function calculates the recovery rate for each affected household.

\n\n

Args:\n affected_households (pd.DataFrame): A data frame containing the affected households.\n consumption_utility (float): The coefficient of relative risk aversion.\n discount_rate (float): The discount rate.\n average_productivity (float): The average productivity.\n optimization_timestep (float): The timestep for the optimization.\n n_years (int): The number of years in the optimization algorithm.

\n\n

Returns:\n pd.DataFrame: A data frame containing the affected households with the recovery rate.

\n", "signature": "(\taffected_households: pandas.core.frame.DataFrame,\tconsumption_utility: float,\tdiscount_rate: float,\taverage_productivity: float,\toptimization_timestep: float,\tn_years: int) -> pandas.core.frame.DataFrame:", "funcdef": "def"}, "src.modules.optimize.optimize_recovery_rate": {"fullname": "src.modules.optimize.optimize_recovery_rate", "modulename": "src.modules.optimize", "qualname": "optimize_recovery_rate", "kind": "function", "doc": "

\n", "signature": "(\tx,\toptimization_results: pandas.core.frame.DataFrame,\tconsumption_utility: float,\tdiscount_rate: float,\taverage_productivity: float,\toptimization_timestep: float,\tn_years: int) -> float:", "funcdef": "def"}, "src.modules.optimize.integrate_wellbeing": {"fullname": "src.modules.optimize.integrate_wellbeing", "modulename": "src.modules.optimize", "qualname": "integrate_wellbeing", "kind": "function", "doc": "

\n", "signature": "(\taffected_households: pandas.core.frame.DataFrame,\tconsumption_utility: float,\tdiscount_rate: float,\tincome_and_expenditure_growth: float,\taverage_productivity: float,\tpoverty_line: float,\tn_years: int,\tadd_income_loss: bool,\tcash_transfer: dict = {}) -> pandas.core.frame.DataFrame:", "funcdef": "def"}}, "docInfo": {"src": {"qualname": 0, "fullname": 1, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 3}, "src.data": {"qualname": 0, "fullname": 2, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 3}, "src.data.analyse": {"qualname": 0, "fullname": 3, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 3}, "src.data.analyse.prepare_outcomes": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 59, "bases": 0, "doc": 62}, "src.data.analyse.get_spatial_outcomes": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 110, "bases": 0, "doc": 3}, "src.data.analyse.get_policy_effectiveness_tab": {"qualname": 4, "fullname": 7, "annotation": 0, "default_value": 0, "signature": 49, "bases": 0, "doc": 3}, "src.data.prepare": {"qualname": 0, "fullname": 3, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 3}, "src.data.prepare.prepare_asset_damage": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 47, "bases": 0, "doc": 16}, "src.data.prepare.prepare_household_survey": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 19, "bases": 0, "doc": 30}, "src.data.prepare.load_data": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 42, "bases": 0, "doc": 7}, "src.data.prepare.start_pipeline": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 31, "bases": 0, "doc": 8}, "src.data.prepare.add_is_rural_column": {"qualname": 4, "fullname": 7, "annotation": 0, "default_value": 0, "signature": 69, "bases": 0, "doc": 16}, "src.data.prepare.rename_assets_column": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 49, "bases": 0, "doc": 11}, "src.data.prepare.rename_other_columns": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 49, "bases": 0, "doc": 12}, "src.data.prepare.calculate_household_attributes": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 49, "bases": 0, "doc": 3}, "src.data.prepare.get_bank_or_credit_union": {"qualname": 5, "fullname": 8, "annotation": 0, "default_value": 0, "signature": 49, "bases": 0, "doc": 3}, "src.data.prepare.decode_demographic_attributes": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 49, "bases": 0, "doc": 7}, "src.data.prepare.decode_income_attributes": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 49, "bases": 0, "doc": 8}, "src.data.prepare.calculate_income_attributes": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 49, "bases": 0, "doc": 3}, "src.data.prepare.decode_housing_attributes": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 49, "bases": 0, "doc": 8}, "src.data.prepare.add_housing_attributes": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 49, "bases": 0, "doc": 7}, "src.data.prepare.add_insurance_attributes": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 49, "bases": 0, "doc": 3}, "src.data.prepare.calculate_housing_attributes": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 49, "bases": 0, "doc": 3}, "src.data.prepare.calculate_poverty_attributes": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 49, "bases": 0, "doc": 3}, "src.data.prepare.assign_housing_vulnerability": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 49, "bases": 0, "doc": 3}, "src.data.prepare.subset_columns": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 49, "bases": 0, "doc": 7}, "src.data.prepare.check_columns": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 49, "bases": 0, "doc": 3}, "src.data.prepare.add_missing_columns": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 62, "bases": 0, "doc": 10}, "src.data.prepare.merge_districts": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 49, "bases": 0, "doc": 3}, "src.data.prepare.exponential_regression": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 132, "bases": 0, "doc": 3}, "src.data.prepare.polynomial_regression": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 199, "bases": 0, "doc": 3}, "src.data.prepare.linear_regression": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 138, "bases": 0, "doc": 21}, "src.data.read": {"qualname": 0, "fullname": 3, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 3}, "src.data.read.read_asset_damage": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 19}, "src.data.read.get_asset_damage": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 82, "bases": 0, "doc": 94}, "src.data.read.read_household_survey": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 34, "bases": 0, "doc": 42}, "src.data.visualise": {"qualname": 0, "fullname": 3, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 3}, "src.data.visualise.rainclouds": {"qualname": 1, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 143, "bases": 0, "doc": 3}, "src.data.visualise.bivariate_choropleth": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 51, "bases": 0, "doc": 3}, "src.data.visualise.nine_quadrants_plot": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 33, "bases": 0, "doc": 3}, "src.data.visualise.get_colors": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 11, "bases": 0, "doc": 3}, "src.data.visualise.bin_data": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 39, "bases": 0, "doc": 3}, "src.data.write": {"qualname": 0, "fullname": 3, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 3}, "src.data.write.add_columns": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 77, "bases": 0, "doc": 18}, "src.data.write.get_outcomes": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 52, "bases": 0, "doc": 74}, "src.data.write.find_poor": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 59, "bases": 0, "doc": 63}, "src.data.write.get_people_by_years_in_poverty": {"qualname": 6, "fullname": 9, "annotation": 0, "default_value": 0, "signature": 35, "bases": 0, "doc": 40}, "src.data.write.calculate_poverty_gap": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 87, "bases": 0, "doc": 96}, "src.data.write.calculate_average_annual_consumption_loss": {"qualname": 5, "fullname": 8, "annotation": 0, "default_value": 0, "signature": 46, "bases": 0, "doc": 78}, "src.data.write.calculate_resilience": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 45, "bases": 0, "doc": 52}, "src.model": {"qualname": 0, "fullname": 2, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 3}, "src.model.initialize_model": {"qualname": 2, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 30, "bases": 0, "doc": 53}, "src.model.run_model": {"qualname": 2, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 13, "bases": 0, "doc": 6}, "src.modules": {"qualname": 0, "fullname": 2, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 3}, "src.modules.households": {"qualname": 0, "fullname": 3, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 3}, "src.modules.households.duplicate_households": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 63, "bases": 0, "doc": 69}, "src.modules.households.calculate_average_productivity": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 45, "bases": 0, "doc": 44}, "src.modules.households.adjust_assets_and_expenditure": {"qualname": 4, "fullname": 7, "annotation": 0, "default_value": 0, "signature": 99, "bases": 0, "doc": 100}, "src.modules.households.calculate_pml": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 75, "bases": 0, "doc": 65}, "src.modules.households.select_district": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 62, "bases": 0, "doc": 9}, "src.modules.households.estimate_savings": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 75, "bases": 0, "doc": 68}, "src.modules.households.set_vulnerability": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 76, "bases": 0, "doc": 72}, "src.modules.households.calculate_exposure": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 87, "bases": 0, "doc": 76}, "src.modules.households.determine_affected": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 48, "bases": 0, "doc": 95}, "src.modules.households.apply_individual_policy": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 45, "bases": 0, "doc": 99}, "src.modules.optimize": {"qualname": 0, "fullname": 3, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 3}, "src.modules.optimize.run_optimization": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 111, "bases": 0, "doc": 91}, "src.modules.optimize.optimize_recovery_rate": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 102, "bases": 0, "doc": 3}, "src.modules.optimize.integrate_wellbeing": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 157, "bases": 0, "doc": 3}}, "length": 69, "save": true}, "index": {"qualname": {"root": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}, "src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.prepare.prepare_household_survey": {"tf": 1}}, "df": 3}}}}}, "o": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "y": {"docs": {"src.modules.households.calculate_average_productivity": {"tf": 1}}, "df": 1}}}}}}}}}}}, "o": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "y": {"docs": {"src.data.analyse.get_policy_effectiveness_tab": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 2}}}, "y": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"src.data.prepare.polynomial_regression": {"tf": 1}}, "df": 1}}}}}}}}, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "y": {"docs": {"src.data.prepare.calculate_poverty_attributes": {"tf": 1}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}}, "df": 3}}}}}, "o": {"docs": {}, "df": 0, "r": {"docs": {"src.data.write.find_poor": {"tf": 1}}, "df": 1}}}, "i": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.start_pipeline": {"tf": 1}}, "df": 1}}}}}}}, "l": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "t": {"docs": {"src.data.visualise.nine_quadrants_plot": {"tf": 1}}, "df": 1}}}, "e": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"src.data.write.get_people_by_years_in_poverty": {"tf": 1}}, "df": 1}}}}}, "m": {"docs": {}, "df": 0, "l": {"docs": {"src.modules.households.calculate_pml": {"tf": 1}}, "df": 1}}}, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}, "src.data.analyse.get_spatial_outcomes": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1}}, "df": 3}}}}}}}, "t": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"src.data.prepare.rename_other_columns": {"tf": 1}}, "df": 1}}}}, "r": {"docs": {"src.data.prepare.get_bank_or_credit_union": {"tf": 1}}, "df": 1}, "p": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "z": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.modules.optimize.run_optimization": {"tf": 1}}, "df": 1}}}}}, "e": {"docs": {"src.modules.optimize.optimize_recovery_rate": {"tf": 1}}, "df": 1}}}}}}}}, "g": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {"src.data.analyse.get_spatial_outcomes": {"tf": 1}, "src.data.analyse.get_policy_effectiveness_tab": {"tf": 1}, "src.data.prepare.get_bank_or_credit_union": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.visualise.get_colors": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1}}, "df": 7}}, "a": {"docs": {}, "df": 0, "p": {"docs": {"src.data.write.calculate_poverty_gap": {"tf": 1}}, "df": 1}}}, "s": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"src.data.analyse.get_spatial_outcomes": {"tf": 1}}, "df": 1}}}}}}, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "y": {"docs": {"src.data.prepare.prepare_household_survey": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}}, "df": 2}}}}, "b": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {"src.data.prepare.subset_columns": {"tf": 1}}, "df": 1}}}}}, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "t": {"docs": {"src.data.prepare.start_pipeline": {"tf": 1}}, "df": 1}}}}, "e": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {"src.modules.households.select_district": {"tf": 1}}, "df": 1}}}}, "t": {"docs": {"src.modules.households.set_vulnerability": {"tf": 1}}, "df": 1}}, "a": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "s": {"docs": {"src.modules.households.estimate_savings": {"tf": 1}}, "df": 1}}}}}}}, "e": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {"src.data.analyse.get_policy_effectiveness_tab": {"tf": 1}}, "df": 1}}}}}}}}}}}}, "x": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"src.data.prepare.exponential_regression": {"tf": 1}}, "df": 1}}}}}}}, "s": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.calculate_exposure": {"tf": 1}}, "df": 1}}}}}, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.adjust_assets_and_expenditure": {"tf": 1}}, "df": 1}}}}}}}}}}, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.estimate_savings": {"tf": 1}}, "df": 1}}}}}}}}, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "b": {"docs": {"src.data.analyse.get_policy_effectiveness_tab": {"tf": 1}}, "df": 1}}}, "a": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {"src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.read.read_asset_damage": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}}, "df": 3, "s": {"docs": {"src.data.prepare.rename_assets_column": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}}, "df": 2}}}, "i": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "n": {"docs": {"src.data.prepare.assign_housing_vulnerability": {"tf": 1}}, "df": 1}}}}}, "d": {"docs": {}, "df": 0, "d": {"docs": {"src.data.prepare.add_is_rural_column": {"tf": 1}, "src.data.prepare.add_housing_attributes": {"tf": 1}, "src.data.prepare.add_insurance_attributes": {"tf": 1}, "src.data.prepare.add_missing_columns": {"tf": 1}, "src.data.write.add_columns": {"tf": 1}}, "df": 5}, "j": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {"src.modules.households.adjust_assets_and_expenditure": {"tf": 1}}, "df": 1}}}}}, "t": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"src.data.prepare.calculate_household_attributes": {"tf": 1}, "src.data.prepare.decode_demographic_attributes": {"tf": 1}, "src.data.prepare.decode_income_attributes": {"tf": 1}, "src.data.prepare.calculate_income_attributes": {"tf": 1}, "src.data.prepare.decode_housing_attributes": {"tf": 1}, "src.data.prepare.add_housing_attributes": {"tf": 1}, "src.data.prepare.add_insurance_attributes": {"tf": 1}, "src.data.prepare.calculate_housing_attributes": {"tf": 1}, "src.data.prepare.calculate_poverty_attributes": {"tf": 1}}, "df": 9}}}}}}}}}, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {"src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.modules.households.calculate_average_productivity": {"tf": 1}}, "df": 2}}}}}}, "n": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}}, "df": 1}}}}, "d": {"docs": {"src.modules.households.adjust_assets_and_expenditure": {"tf": 1}}, "df": 1}}, "f": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"src.modules.households.determine_affected": {"tf": 1}}, "df": 1}}}}}}}, "p": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "y": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 1}}}}}, "d": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.read.read_asset_damage": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}}, "df": 3}}}}, "t": {"docs": {}, "df": 0, "a": {"docs": {"src.data.prepare.load_data": {"tf": 1}, "src.data.visualise.bin_data": {"tf": 1}}, "df": 2}}}, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.decode_demographic_attributes": {"tf": 1}, "src.data.prepare.decode_income_attributes": {"tf": 1}, "src.data.prepare.decode_housing_attributes": {"tf": 1}}, "df": 3}}}}, "m": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {"src.data.prepare.decode_demographic_attributes": {"tf": 1}}, "df": 1}}}}}}}}}, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.determine_affected": {"tf": 1}}, "df": 1}}}}}}}}, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {"src.modules.households.select_district": {"tf": 1}}, "df": 1, "s": {"docs": {"src.data.prepare.merge_districts": {"tf": 1}}, "df": 1}}}}}}}}, "u": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.duplicate_households": {"tf": 1}}, "df": 1}}}}}}}}}, "h": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "d": {"docs": {"src.data.prepare.prepare_household_survey": {"tf": 1}, "src.data.prepare.calculate_household_attributes": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}}, "df": 3, "s": {"docs": {"src.modules.households.duplicate_households": {"tf": 1}}, "df": 1}}}}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"src.data.prepare.decode_housing_attributes": {"tf": 1}, "src.data.prepare.add_housing_attributes": {"tf": 1}, "src.data.prepare.calculate_housing_attributes": {"tf": 1}, "src.data.prepare.assign_housing_vulnerability": {"tf": 1}}, "df": 4}}}}}}}, "l": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "d": {"docs": {"src.data.prepare.load_data": {"tf": 1}}, "df": 1}}, "s": {"docs": {}, "df": 0, "s": {"docs": {"src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}}, "df": 1}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {"src.data.prepare.linear_regression": {"tf": 1}}, "df": 1}}}}}}, "i": {"docs": {}, "df": 0, "s": {"docs": {"src.data.prepare.add_is_rural_column": {"tf": 1}}, "df": 1}, "n": {"docs": {"src.data.write.get_people_by_years_in_poverty": {"tf": 1}}, "df": 1, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.decode_income_attributes": {"tf": 1}, "src.data.prepare.calculate_income_attributes": {"tf": 1}}, "df": 2}}}}, "s": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.add_insurance_attributes": {"tf": 1}}, "df": 1}}}}}}}, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "z": {"docs": {}, "df": 0, "e": {"docs": {"src.model.initialize_model": {"tf": 1}}, "df": 1}}}}}}}}, "d": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 1}}}}}}}}, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 1}}}}}}}}}, "r": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"src.data.prepare.add_is_rural_column": {"tf": 1}}, "df": 1}}}, "n": {"docs": {"src.model.run_model": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}}, "df": 2}}, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.rename_assets_column": {"tf": 1}, "src.data.prepare.rename_other_columns": {"tf": 1}}, "df": 2}}}}, "g": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.polynomial_regression": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 1}}, "df": 3}}}}}}}}, "a": {"docs": {}, "df": 0, "d": {"docs": {"src.data.read.read_asset_damage": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}}, "df": 2}}, "s": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {"src.data.write.calculate_resilience": {"tf": 1}}, "df": 1}}}}}}}}, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "y": {"docs": {"src.modules.optimize.optimize_recovery_rate": {"tf": 1}}, "df": 1}}}}}}}, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "s": {"docs": {"src.data.visualise.rainclouds": {"tf": 1}}, "df": 1}}}}}}}}, "t": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.optimize.optimize_recovery_rate": {"tf": 1}}, "df": 1}}}}, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "n": {"docs": {"src.data.prepare.add_is_rural_column": {"tf": 1}, "src.data.prepare.rename_assets_column": {"tf": 1}}, "df": 2, "s": {"docs": {"src.data.prepare.rename_other_columns": {"tf": 1}, "src.data.prepare.subset_columns": {"tf": 1}, "src.data.prepare.check_columns": {"tf": 1}, "src.data.prepare.add_missing_columns": {"tf": 1}, "src.data.write.add_columns": {"tf": 1}}, "df": 5}}}}, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "s": {"docs": {"src.data.visualise.get_colors": {"tf": 1}}, "df": 1}}}}, "n": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}}, "df": 1}}}}}}}}}}, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.calculate_household_attributes": {"tf": 1}, "src.data.prepare.calculate_income_attributes": {"tf": 1}, "src.data.prepare.calculate_housing_attributes": {"tf": 1}, "src.data.prepare.calculate_poverty_attributes": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}}, "df": 10}}}}}}}}, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {"src.data.prepare.get_bank_or_credit_union": {"tf": 1}}, "df": 1}}}}}, "h": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "k": {"docs": {"src.data.prepare.check_columns": {"tf": 1}}, "df": 1}}}, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "h": {"docs": {"src.data.visualise.bivariate_choropleth": {"tf": 1}}, "df": 1}}}}}}}}}}, "b": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "k": {"docs": {"src.data.prepare.get_bank_or_credit_union": {"tf": 1}}, "df": 1}}}, "i": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"src.data.visualise.bivariate_choropleth": {"tf": 1}}, "df": 1}}}}}}}, "n": {"docs": {"src.data.visualise.bin_data": {"tf": 1}}, "df": 1}}, "y": {"docs": {"src.data.write.get_people_by_years_in_poverty": {"tf": 1}}, "df": 1}}, "u": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.data.prepare.get_bank_or_credit_union": {"tf": 1}}, "df": 1}}}}}, "v": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "y": {"docs": {"src.data.prepare.assign_housing_vulnerability": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}}, "df": 2}}}}}}}}}}}}}, "m": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"src.data.prepare.add_missing_columns": {"tf": 1}}, "df": 1}}}}}}, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.merge_districts": {"tf": 1}}, "df": 1}}}}, "o": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "l": {"docs": {"src.model.initialize_model": {"tf": 1}, "src.model.run_model": {"tf": 1}}, "df": 2}}}}}, "n": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {"src.data.visualise.nine_quadrants_plot": {"tf": 1}}, "df": 1}}}}, "q": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "s": {"docs": {"src.data.visualise.nine_quadrants_plot": {"tf": 1}}, "df": 1}}}}}}}}}, "f": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "d": {"docs": {"src.data.write.find_poor": {"tf": 1}}, "df": 1}}}}, "y": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "s": {"docs": {"src.data.write.get_people_by_years_in_poverty": {"tf": 1}}, "df": 1}}}}}, "w": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 1}}}}}}}}}}}, "fullname": {"root": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "c": {"docs": {"src": {"tf": 1}, "src.data": {"tf": 1}, "src.data.analyse": {"tf": 1}, "src.data.analyse.prepare_outcomes": {"tf": 1}, "src.data.analyse.get_spatial_outcomes": {"tf": 1}, "src.data.analyse.get_policy_effectiveness_tab": {"tf": 1}, "src.data.prepare": {"tf": 1}, "src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.prepare.prepare_household_survey": {"tf": 1}, "src.data.prepare.load_data": {"tf": 1}, "src.data.prepare.start_pipeline": {"tf": 1}, "src.data.prepare.add_is_rural_column": {"tf": 1}, "src.data.prepare.rename_assets_column": {"tf": 1}, "src.data.prepare.rename_other_columns": {"tf": 1}, "src.data.prepare.calculate_household_attributes": {"tf": 1}, "src.data.prepare.get_bank_or_credit_union": {"tf": 1}, "src.data.prepare.decode_demographic_attributes": {"tf": 1}, "src.data.prepare.decode_income_attributes": {"tf": 1}, "src.data.prepare.calculate_income_attributes": {"tf": 1}, "src.data.prepare.decode_housing_attributes": {"tf": 1}, "src.data.prepare.add_housing_attributes": {"tf": 1}, "src.data.prepare.add_insurance_attributes": {"tf": 1}, "src.data.prepare.calculate_housing_attributes": {"tf": 1}, "src.data.prepare.calculate_poverty_attributes": {"tf": 1}, "src.data.prepare.assign_housing_vulnerability": {"tf": 1}, "src.data.prepare.subset_columns": {"tf": 1}, "src.data.prepare.check_columns": {"tf": 1}, "src.data.prepare.add_missing_columns": {"tf": 1}, "src.data.prepare.merge_districts": {"tf": 1}, "src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.polynomial_regression": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 1}, "src.data.read": {"tf": 1}, "src.data.read.read_asset_damage": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}, "src.data.visualise": {"tf": 1}, "src.data.visualise.rainclouds": {"tf": 1}, "src.data.visualise.bivariate_choropleth": {"tf": 1}, "src.data.visualise.nine_quadrants_plot": {"tf": 1}, "src.data.visualise.get_colors": {"tf": 1}, "src.data.visualise.bin_data": {"tf": 1}, "src.data.write": {"tf": 1}, "src.data.write.add_columns": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1}, "src.data.write.find_poor": {"tf": 1}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}, "src.model": {"tf": 1}, "src.model.initialize_model": {"tf": 1}, "src.model.run_model": {"tf": 1}, "src.modules": {"tf": 1}, "src.modules.households": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.select_district": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}, "src.modules.optimize": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}, "src.modules.optimize.optimize_recovery_rate": {"tf": 1}, "src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 69}}, "p": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"src.data.analyse.get_spatial_outcomes": {"tf": 1}}, "df": 1}}}}}}, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "y": {"docs": {"src.data.prepare.prepare_household_survey": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}}, "df": 2}}}}, "b": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {"src.data.prepare.subset_columns": {"tf": 1}}, "df": 1}}}}}, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "t": {"docs": {"src.data.prepare.start_pipeline": {"tf": 1}}, "df": 1}}}}, "e": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {"src.modules.households.select_district": {"tf": 1}}, "df": 1}}}}, "t": {"docs": {"src.modules.households.set_vulnerability": {"tf": 1}}, "df": 1}}, "a": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "s": {"docs": {"src.modules.households.estimate_savings": {"tf": 1}}, "df": 1}}}}}}}, "d": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "a": {"docs": {"src.data": {"tf": 1}, "src.data.analyse": {"tf": 1}, "src.data.analyse.prepare_outcomes": {"tf": 1}, "src.data.analyse.get_spatial_outcomes": {"tf": 1}, "src.data.analyse.get_policy_effectiveness_tab": {"tf": 1}, "src.data.prepare": {"tf": 1}, "src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.prepare.prepare_household_survey": {"tf": 1}, "src.data.prepare.load_data": {"tf": 1.4142135623730951}, "src.data.prepare.start_pipeline": {"tf": 1}, "src.data.prepare.add_is_rural_column": {"tf": 1}, "src.data.prepare.rename_assets_column": {"tf": 1}, "src.data.prepare.rename_other_columns": {"tf": 1}, "src.data.prepare.calculate_household_attributes": {"tf": 1}, "src.data.prepare.get_bank_or_credit_union": {"tf": 1}, "src.data.prepare.decode_demographic_attributes": {"tf": 1}, "src.data.prepare.decode_income_attributes": {"tf": 1}, "src.data.prepare.calculate_income_attributes": {"tf": 1}, "src.data.prepare.decode_housing_attributes": {"tf": 1}, "src.data.prepare.add_housing_attributes": {"tf": 1}, "src.data.prepare.add_insurance_attributes": {"tf": 1}, "src.data.prepare.calculate_housing_attributes": {"tf": 1}, "src.data.prepare.calculate_poverty_attributes": {"tf": 1}, "src.data.prepare.assign_housing_vulnerability": {"tf": 1}, "src.data.prepare.subset_columns": {"tf": 1}, "src.data.prepare.check_columns": {"tf": 1}, "src.data.prepare.add_missing_columns": {"tf": 1}, "src.data.prepare.merge_districts": {"tf": 1}, "src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.polynomial_regression": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 1}, "src.data.read": {"tf": 1}, "src.data.read.read_asset_damage": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}, "src.data.visualise": {"tf": 1}, "src.data.visualise.rainclouds": {"tf": 1}, "src.data.visualise.bivariate_choropleth": {"tf": 1}, "src.data.visualise.nine_quadrants_plot": {"tf": 1}, "src.data.visualise.get_colors": {"tf": 1}, "src.data.visualise.bin_data": {"tf": 1.4142135623730951}, "src.data.write": {"tf": 1}, "src.data.write.add_columns": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1}, "src.data.write.find_poor": {"tf": 1}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}}, "df": 49}}, "m": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.read.read_asset_damage": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}}, "df": 3}}}}}, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.decode_demographic_attributes": {"tf": 1}, "src.data.prepare.decode_income_attributes": {"tf": 1}, "src.data.prepare.decode_housing_attributes": {"tf": 1}}, "df": 3}}}}, "m": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {"src.data.prepare.decode_demographic_attributes": {"tf": 1}}, "df": 1}}}}}}}}}, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.determine_affected": {"tf": 1}}, "df": 1}}}}}}}}, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {"src.modules.households.select_district": {"tf": 1}}, "df": 1, "s": {"docs": {"src.data.prepare.merge_districts": {"tf": 1}}, "df": 1}}}}}}}}, "u": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.duplicate_households": {"tf": 1}}, "df": 1}}}}}}}}}, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "y": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {"src.data.analyse": {"tf": 1}, "src.data.analyse.prepare_outcomes": {"tf": 1}, "src.data.analyse.get_spatial_outcomes": {"tf": 1}, "src.data.analyse.get_policy_effectiveness_tab": {"tf": 1}}, "df": 4}}}}}, "n": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}}, "df": 1}}}}, "d": {"docs": {"src.modules.households.adjust_assets_and_expenditure": {"tf": 1}}, "df": 1}}, "s": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {"src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.read.read_asset_damage": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}}, "df": 3, "s": {"docs": {"src.data.prepare.rename_assets_column": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}}, "df": 2}}}, "i": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "n": {"docs": {"src.data.prepare.assign_housing_vulnerability": {"tf": 1}}, "df": 1}}}}}, "d": {"docs": {}, "df": 0, "d": {"docs": {"src.data.prepare.add_is_rural_column": {"tf": 1}, "src.data.prepare.add_housing_attributes": {"tf": 1}, "src.data.prepare.add_insurance_attributes": {"tf": 1}, "src.data.prepare.add_missing_columns": {"tf": 1}, "src.data.write.add_columns": {"tf": 1}}, "df": 5}, "j": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {"src.modules.households.adjust_assets_and_expenditure": {"tf": 1}}, "df": 1}}}}}, "t": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"src.data.prepare.calculate_household_attributes": {"tf": 1}, "src.data.prepare.decode_demographic_attributes": {"tf": 1}, "src.data.prepare.decode_income_attributes": {"tf": 1}, "src.data.prepare.calculate_income_attributes": {"tf": 1}, "src.data.prepare.decode_housing_attributes": {"tf": 1}, "src.data.prepare.add_housing_attributes": {"tf": 1}, "src.data.prepare.add_insurance_attributes": {"tf": 1}, "src.data.prepare.calculate_housing_attributes": {"tf": 1}, "src.data.prepare.calculate_poverty_attributes": {"tf": 1}}, "df": 9}}}}}}}}}, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {"src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.modules.households.calculate_average_productivity": {"tf": 1}}, "df": 2}}}}}}, "f": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"src.modules.households.determine_affected": {"tf": 1}}, "df": 1}}}}}}}, "p": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "y": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 1}}}}}, "p": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}, "src.data.prepare": {"tf": 1}, "src.data.prepare.prepare_asset_damage": {"tf": 1.4142135623730951}, "src.data.prepare.prepare_household_survey": {"tf": 1.4142135623730951}, "src.data.prepare.load_data": {"tf": 1}, "src.data.prepare.start_pipeline": {"tf": 1}, "src.data.prepare.add_is_rural_column": {"tf": 1}, "src.data.prepare.rename_assets_column": {"tf": 1}, "src.data.prepare.rename_other_columns": {"tf": 1}, "src.data.prepare.calculate_household_attributes": {"tf": 1}, "src.data.prepare.get_bank_or_credit_union": {"tf": 1}, "src.data.prepare.decode_demographic_attributes": {"tf": 1}, "src.data.prepare.decode_income_attributes": {"tf": 1}, "src.data.prepare.calculate_income_attributes": {"tf": 1}, "src.data.prepare.decode_housing_attributes": {"tf": 1}, "src.data.prepare.add_housing_attributes": {"tf": 1}, "src.data.prepare.add_insurance_attributes": {"tf": 1}, "src.data.prepare.calculate_housing_attributes": {"tf": 1}, "src.data.prepare.calculate_poverty_attributes": {"tf": 1}, "src.data.prepare.assign_housing_vulnerability": {"tf": 1}, "src.data.prepare.subset_columns": {"tf": 1}, "src.data.prepare.check_columns": {"tf": 1}, "src.data.prepare.add_missing_columns": {"tf": 1}, "src.data.prepare.merge_districts": {"tf": 1}, "src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.polynomial_regression": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 1}}, "df": 27}}}}}, "o": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "y": {"docs": {"src.modules.households.calculate_average_productivity": {"tf": 1}}, "df": 1}}}}}}}}}}}, "o": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "y": {"docs": {"src.data.analyse.get_policy_effectiveness_tab": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 2}}}, "y": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"src.data.prepare.polynomial_regression": {"tf": 1}}, "df": 1}}}}}}}}, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "y": {"docs": {"src.data.prepare.calculate_poverty_attributes": {"tf": 1}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}}, "df": 3}}}}}, "o": {"docs": {}, "df": 0, "r": {"docs": {"src.data.write.find_poor": {"tf": 1}}, "df": 1}}}, "i": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.start_pipeline": {"tf": 1}}, "df": 1}}}}}}}, "l": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "t": {"docs": {"src.data.visualise.nine_quadrants_plot": {"tf": 1}}, "df": 1}}}, "e": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"src.data.write.get_people_by_years_in_poverty": {"tf": 1}}, "df": 1}}}}}, "m": {"docs": {}, "df": 0, "l": {"docs": {"src.modules.households.calculate_pml": {"tf": 1}}, "df": 1}}}, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}, "src.data.analyse.get_spatial_outcomes": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1}}, "df": 3}}}}}}}, "t": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"src.data.prepare.rename_other_columns": {"tf": 1}}, "df": 1}}}}, "r": {"docs": {"src.data.prepare.get_bank_or_credit_union": {"tf": 1}}, "df": 1}, "p": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "z": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.optimize": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}, "src.modules.optimize.optimize_recovery_rate": {"tf": 1.4142135623730951}, "src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 4}, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.modules.optimize.run_optimization": {"tf": 1}}, "df": 1}}}}}}}}}}}}, "g": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {"src.data.analyse.get_spatial_outcomes": {"tf": 1}, "src.data.analyse.get_policy_effectiveness_tab": {"tf": 1}, "src.data.prepare.get_bank_or_credit_union": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.visualise.get_colors": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1}}, "df": 7}}, "a": {"docs": {}, "df": 0, "p": {"docs": {"src.data.write.calculate_poverty_gap": {"tf": 1}}, "df": 1}}}, "e": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {"src.data.analyse.get_policy_effectiveness_tab": {"tf": 1}}, "df": 1}}}}}}}}}}}}, "x": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"src.data.prepare.exponential_regression": {"tf": 1}}, "df": 1}}}}}}}, "s": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.calculate_exposure": {"tf": 1}}, "df": 1}}}}}, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.adjust_assets_and_expenditure": {"tf": 1}}, "df": 1}}}}}}}}}}, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.estimate_savings": {"tf": 1}}, "df": 1}}}}}}}}, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "b": {"docs": {"src.data.analyse.get_policy_effectiveness_tab": {"tf": 1}}, "df": 1}}}, "h": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "d": {"docs": {"src.data.prepare.prepare_household_survey": {"tf": 1}, "src.data.prepare.calculate_household_attributes": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}}, "df": 3, "s": {"docs": {"src.modules.households": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1.4142135623730951}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.select_district": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 11}}}}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"src.data.prepare.decode_housing_attributes": {"tf": 1}, "src.data.prepare.add_housing_attributes": {"tf": 1}, "src.data.prepare.calculate_housing_attributes": {"tf": 1}, "src.data.prepare.assign_housing_vulnerability": {"tf": 1}}, "df": 4}}}}}}}, "l": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "d": {"docs": {"src.data.prepare.load_data": {"tf": 1}}, "df": 1}}, "s": {"docs": {}, "df": 0, "s": {"docs": {"src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}}, "df": 1}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {"src.data.prepare.linear_regression": {"tf": 1}}, "df": 1}}}}}}, "i": {"docs": {}, "df": 0, "s": {"docs": {"src.data.prepare.add_is_rural_column": {"tf": 1}}, "df": 1}, "n": {"docs": {"src.data.write.get_people_by_years_in_poverty": {"tf": 1}}, "df": 1, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.decode_income_attributes": {"tf": 1}, "src.data.prepare.calculate_income_attributes": {"tf": 1}}, "df": 2}}}}, "s": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.add_insurance_attributes": {"tf": 1}}, "df": 1}}}}}}}, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "z": {"docs": {}, "df": 0, "e": {"docs": {"src.model.initialize_model": {"tf": 1}}, "df": 1}}}}}}}}, "d": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 1}}}}}}}}, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 1}}}}}}}}}, "r": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"src.data.prepare.add_is_rural_column": {"tf": 1}}, "df": 1}}}, "n": {"docs": {"src.model.run_model": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}}, "df": 2}}, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.rename_assets_column": {"tf": 1}, "src.data.prepare.rename_other_columns": {"tf": 1}}, "df": 2}}}}, "g": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.polynomial_regression": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 1}}, "df": 3}}}}}}}}, "a": {"docs": {}, "df": 0, "d": {"docs": {"src.data.read": {"tf": 1}, "src.data.read.read_asset_damage": {"tf": 1.4142135623730951}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1.4142135623730951}}, "df": 4}}, "s": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {"src.data.write.calculate_resilience": {"tf": 1}}, "df": 1}}}}}}}}, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "y": {"docs": {"src.modules.optimize.optimize_recovery_rate": {"tf": 1}}, "df": 1}}}}}}}, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "s": {"docs": {"src.data.visualise.rainclouds": {"tf": 1}}, "df": 1}}}}}}}}, "t": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.optimize.optimize_recovery_rate": {"tf": 1}}, "df": 1}}}}, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "n": {"docs": {"src.data.prepare.add_is_rural_column": {"tf": 1}, "src.data.prepare.rename_assets_column": {"tf": 1}}, "df": 2, "s": {"docs": {"src.data.prepare.rename_other_columns": {"tf": 1}, "src.data.prepare.subset_columns": {"tf": 1}, "src.data.prepare.check_columns": {"tf": 1}, "src.data.prepare.add_missing_columns": {"tf": 1}, "src.data.write.add_columns": {"tf": 1}}, "df": 5}}}}, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "s": {"docs": {"src.data.visualise.get_colors": {"tf": 1}}, "df": 1}}}}, "n": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}}, "df": 1}}}}}}}}}}, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.calculate_household_attributes": {"tf": 1}, "src.data.prepare.calculate_income_attributes": {"tf": 1}, "src.data.prepare.calculate_housing_attributes": {"tf": 1}, "src.data.prepare.calculate_poverty_attributes": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}}, "df": 10}}}}}}}}, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {"src.data.prepare.get_bank_or_credit_union": {"tf": 1}}, "df": 1}}}}}, "h": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "k": {"docs": {"src.data.prepare.check_columns": {"tf": 1}}, "df": 1}}}, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "h": {"docs": {"src.data.visualise.bivariate_choropleth": {"tf": 1}}, "df": 1}}}}}}}}}}, "b": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "k": {"docs": {"src.data.prepare.get_bank_or_credit_union": {"tf": 1}}, "df": 1}}}, "i": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"src.data.visualise.bivariate_choropleth": {"tf": 1}}, "df": 1}}}}}}}, "n": {"docs": {"src.data.visualise.bin_data": {"tf": 1}}, "df": 1}}, "y": {"docs": {"src.data.write.get_people_by_years_in_poverty": {"tf": 1}}, "df": 1}}, "u": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.data.prepare.get_bank_or_credit_union": {"tf": 1}}, "df": 1}}}}}, "v": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "y": {"docs": {"src.data.prepare.assign_housing_vulnerability": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}}, "df": 2}}}}}}}}}}}}, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {"src.data.visualise": {"tf": 1}, "src.data.visualise.rainclouds": {"tf": 1}, "src.data.visualise.bivariate_choropleth": {"tf": 1}, "src.data.visualise.nine_quadrants_plot": {"tf": 1}, "src.data.visualise.get_colors": {"tf": 1}, "src.data.visualise.bin_data": {"tf": 1}}, "df": 6}}}}}}}}}, "m": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"src.data.prepare.add_missing_columns": {"tf": 1}}, "df": 1}}}}}}, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.merge_districts": {"tf": 1}}, "df": 1}}}}, "o": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "l": {"docs": {"src.model": {"tf": 1}, "src.model.initialize_model": {"tf": 1.4142135623730951}, "src.model.run_model": {"tf": 1.4142135623730951}}, "df": 3}}, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"src.modules": {"tf": 1}, "src.modules.households": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.select_district": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}, "src.modules.optimize": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}, "src.modules.optimize.optimize_recovery_rate": {"tf": 1}, "src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 16}}}}}}}, "n": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {"src.data.visualise.nine_quadrants_plot": {"tf": 1}}, "df": 1}}}}, "q": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "s": {"docs": {"src.data.visualise.nine_quadrants_plot": {"tf": 1}}, "df": 1}}}}}}}}}, "w": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"src.data.write": {"tf": 1}, "src.data.write.add_columns": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1}, "src.data.write.find_poor": {"tf": 1}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}}, "df": 8}}}}, "e": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 1}}}}}}}}}, "f": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "d": {"docs": {"src.data.write.find_poor": {"tf": 1}}, "df": 1}}}}, "y": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "s": {"docs": {"src.data.write.get_people_by_years_in_poverty": {"tf": 1}}, "df": 1}}}}}}}, "annotation": {"root": {"docs": {}, "df": 0}}, "default_value": {"root": {"docs": {}, "df": 0}}, "signature": {"root": {"0": {"docs": {"src.data.prepare.polynomial_regression": {"tf": 1}}, "df": 1}, "1": {"0": {"0": {"docs": {"src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.prepare.polynomial_regression": {"tf": 1}}, "df": 2}, "docs": {}, "df": 0}, "docs": {}, "df": 0}, "3": {"9": {"docs": {"src.data.analyse.get_spatial_outcomes": {"tf": 2}, "src.data.visualise.rainclouds": {"tf": 1.4142135623730951}}, "df": 2}, "docs": {}, "df": 0}, "4": {"0": {"docs": {"src.data.prepare.polynomial_regression": {"tf": 1}}, "df": 1}, "docs": {}, "df": 0}, "docs": {"src.data.analyse.prepare_outcomes": {"tf": 6.855654600401044}, "src.data.analyse.get_spatial_outcomes": {"tf": 9.327379053088816}, "src.data.analyse.get_policy_effectiveness_tab": {"tf": 6.324555320336759}, "src.data.prepare.prepare_asset_damage": {"tf": 6.164414002968976}, "src.data.prepare.prepare_household_survey": {"tf": 4}, "src.data.prepare.load_data": {"tf": 5.830951894845301}, "src.data.prepare.start_pipeline": {"tf": 5.0990195135927845}, "src.data.prepare.add_is_rural_column": {"tf": 7.483314773547883}, "src.data.prepare.rename_assets_column": {"tf": 6.324555320336759}, "src.data.prepare.rename_other_columns": {"tf": 6.324555320336759}, "src.data.prepare.calculate_household_attributes": {"tf": 6.324555320336759}, "src.data.prepare.get_bank_or_credit_union": {"tf": 6.324555320336759}, "src.data.prepare.decode_demographic_attributes": {"tf": 6.324555320336759}, "src.data.prepare.decode_income_attributes": {"tf": 6.324555320336759}, "src.data.prepare.calculate_income_attributes": {"tf": 6.324555320336759}, "src.data.prepare.decode_housing_attributes": {"tf": 6.324555320336759}, "src.data.prepare.add_housing_attributes": {"tf": 6.324555320336759}, "src.data.prepare.add_insurance_attributes": {"tf": 6.324555320336759}, "src.data.prepare.calculate_housing_attributes": {"tf": 6.324555320336759}, "src.data.prepare.calculate_poverty_attributes": {"tf": 6.324555320336759}, "src.data.prepare.assign_housing_vulnerability": {"tf": 6.324555320336759}, "src.data.prepare.subset_columns": {"tf": 6.324555320336759}, "src.data.prepare.check_columns": {"tf": 6.324555320336759}, "src.data.prepare.add_missing_columns": {"tf": 7.0710678118654755}, "src.data.prepare.merge_districts": {"tf": 6.324555320336759}, "src.data.prepare.exponential_regression": {"tf": 10.246950765959598}, "src.data.prepare.polynomial_regression": {"tf": 12.529964086141668}, "src.data.prepare.linear_regression": {"tf": 10.488088481701515}, "src.data.read.read_asset_damage": {"tf": 3.4641016151377544}, "src.data.read.get_asset_damage": {"tf": 8.06225774829855}, "src.data.read.read_household_survey": {"tf": 5.291502622129181}, "src.data.visualise.rainclouds": {"tf": 10.723805294763608}, "src.data.visualise.bivariate_choropleth": {"tf": 6.164414002968976}, "src.data.visualise.nine_quadrants_plot": {"tf": 5.0990195135927845}, "src.data.visualise.get_colors": {"tf": 3.1622776601683795}, "src.data.visualise.bin_data": {"tf": 5.477225575051661}, "src.data.write.add_columns": {"tf": 7.874007874011811}, "src.data.write.get_outcomes": {"tf": 6.164414002968976}, "src.data.write.find_poor": {"tf": 6.855654600401044}, "src.data.write.get_people_by_years_in_poverty": {"tf": 5.291502622129181}, "src.data.write.calculate_poverty_gap": {"tf": 8.246211251235321}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 6}, "src.data.write.calculate_resilience": {"tf": 6}, "src.model.initialize_model": {"tf": 4.898979485566356}, "src.model.run_model": {"tf": 3.4641016151377544}, "src.modules.households.duplicate_households": {"tf": 7.0710678118654755}, "src.modules.households.calculate_average_productivity": {"tf": 6}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 8.774964387392123}, "src.modules.households.calculate_pml": {"tf": 7.681145747868608}, "src.modules.households.select_district": {"tf": 7.0710678118654755}, "src.modules.households.estimate_savings": {"tf": 7.681145747868608}, "src.modules.households.set_vulnerability": {"tf": 7.681145747868608}, "src.modules.households.calculate_exposure": {"tf": 8.246211251235321}, "src.modules.households.determine_affected": {"tf": 6.164414002968976}, "src.modules.households.apply_individual_policy": {"tf": 6}, "src.modules.optimize.run_optimization": {"tf": 9.273618495495704}, "src.modules.optimize.optimize_recovery_rate": {"tf": 8.888194417315589}, "src.modules.optimize.integrate_wellbeing": {"tf": 10.954451150103322}}, "df": 58, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "s": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}, "src.modules.optimize.optimize_recovery_rate": {"tf": 1}}, "df": 2}}}}}, "t": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "n": {"docs": {"src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.visualise.bivariate_choropleth": {"tf": 1}}, "df": 5}}}}}, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.estimate_savings": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}, "src.modules.optimize.optimize_recovery_rate": {"tf": 1}, "src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 4}}, "n": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "m": {"docs": {"src.modules.households.set_vulnerability": {"tf": 1}}, "df": 1}}}}}}, "t": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}, "src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.write.find_poor": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}, "src.model.initialize_model": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 11}}}}, "r": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.load_data": {"tf": 1}, "src.data.prepare.add_is_rural_column": {"tf": 1}, "src.data.visualise.rainclouds": {"tf": 1}, "src.data.visualise.nine_quadrants_plot": {"tf": 1}, "src.data.visualise.bin_data": {"tf": 1}}, "df": 5}}, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 1}}}}}}}, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"src.data.visualise.rainclouds": {"tf": 1}}, "df": 1}}}}, "m": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "p": {"docs": {"src.modules.optimize.run_optimization": {"tf": 1}, "src.modules.optimize.optimize_recovery_rate": {"tf": 1}}, "df": 2}}}}}}}, "a": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"src.data.visualise.bivariate_choropleth": {"tf": 1}}, "df": 1}}}}, "o": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"src.data.write.get_outcomes": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}}, "df": 2}}}}}, "a": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "d": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1.4142135623730951}, "src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 2}}, "g": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.data.analyse.get_spatial_outcomes": {"tf": 1}}, "df": 1}}}}}}}}}}, "r": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "y": {"docs": {"src.data.prepare.exponential_regression": {"tf": 1.4142135623730951}, "src.data.prepare.polynomial_regression": {"tf": 1.4142135623730951}, "src.data.prepare.linear_regression": {"tf": 1.4142135623730951}}, "df": 3}}}}, "l": {"docs": {}, "df": 0, "l": {"docs": {"src.data.read.get_asset_damage": {"tf": 1}}, "df": 1}}, "f": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"src.data.write.add_columns": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}, "src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 6}}}}}}}, "s": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {"src.data.write.get_outcomes": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}}, "df": 2}}}}, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {"src.data.write.get_outcomes": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}, "src.modules.optimize.optimize_recovery_rate": {"tf": 1}, "src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 4}}}}}}, "n": {"docs": {}, "df": 0, "d": {"docs": {"src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 1}}}, "p": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}}, "df": 1}}}, "y": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 1}}}}, "w": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"src.data.prepare.polynomial_regression": {"tf": 1}}, "df": 1}}}, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "y": {"docs": {"src.data.visualise.rainclouds": {"tf": 1}, "src.data.write.find_poor": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 6}}}}}, "o": {"docs": {}, "df": 0, "r": {"docs": {"src.data.write.get_people_by_years_in_poverty": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1.4142135623730951}}, "df": 2}}}, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "s": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}, "src.data.analyse.get_spatial_outcomes": {"tf": 1}, "src.data.analyse.get_policy_effectiveness_tab": {"tf": 1.4142135623730951}, "src.data.prepare.load_data": {"tf": 1}, "src.data.prepare.start_pipeline": {"tf": 1}, "src.data.prepare.add_is_rural_column": {"tf": 1.4142135623730951}, "src.data.prepare.rename_assets_column": {"tf": 1.4142135623730951}, "src.data.prepare.rename_other_columns": {"tf": 1.4142135623730951}, "src.data.prepare.calculate_household_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.get_bank_or_credit_union": {"tf": 1.4142135623730951}, "src.data.prepare.decode_demographic_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.decode_income_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.calculate_income_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.decode_housing_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.add_housing_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.add_insurance_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.calculate_housing_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.calculate_poverty_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.assign_housing_vulnerability": {"tf": 1.4142135623730951}, "src.data.prepare.subset_columns": {"tf": 1.4142135623730951}, "src.data.prepare.check_columns": {"tf": 1.4142135623730951}, "src.data.prepare.add_missing_columns": {"tf": 1.4142135623730951}, "src.data.prepare.merge_districts": {"tf": 1.4142135623730951}, "src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.polynomial_regression": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}, "src.data.visualise.rainclouds": {"tf": 1}, "src.data.write.add_columns": {"tf": 1.7320508075688772}, "src.data.write.find_poor": {"tf": 1}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1.4142135623730951}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1.4142135623730951}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1.4142135623730951}, "src.modules.households.calculate_pml": {"tf": 1.4142135623730951}, "src.modules.households.select_district": {"tf": 1.4142135623730951}, "src.modules.households.estimate_savings": {"tf": 1.4142135623730951}, "src.modules.households.set_vulnerability": {"tf": 1.4142135623730951}, "src.modules.households.calculate_exposure": {"tf": 1.4142135623730951}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1.4142135623730951}, "src.modules.optimize.optimize_recovery_rate": {"tf": 1}, "src.modules.optimize.integrate_wellbeing": {"tf": 1.4142135623730951}}, "df": 48}}}}, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"src.data.visualise.rainclouds": {"tf": 1}}, "df": 1}}}}}, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "s": {"docs": {"src.modules.households.estimate_savings": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}}, "df": 4}}}}}, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "d": {"docs": {"src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}}, "df": 2}}}}}, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"src.data.prepare.load_data": {"tf": 1}, "src.data.prepare.add_is_rural_column": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.visualise.bin_data": {"tf": 1}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}}, "df": 8}}}, "o": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "y": {"docs": {"src.data.write.get_outcomes": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}, "src.modules.optimize.optimize_recovery_rate": {"tf": 1}, "src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 4}}}}}}}}}}}, "l": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "t": {"docs": {"src.data.visualise.rainclouds": {"tf": 1}}, "df": 1}}}, "m": {"docs": {}, "df": 0, "l": {"docs": {"src.data.write.calculate_resilience": {"tf": 1}}, "df": 1}}}, "b": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "l": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1.4142135623730951}, "src.data.prepare.load_data": {"tf": 1}, "src.data.prepare.add_is_rural_column": {"tf": 1}, "src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.visualise.rainclouds": {"tf": 1.7320508075688772}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 13}}}, "u": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "t": {"docs": {"src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.polynomial_regression": {"tf": 1.4142135623730951}, "src.data.prepare.linear_regression": {"tf": 1}}, "df": 3}}}}, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "s": {"docs": {"src.modules.households.calculate_exposure": {"tf": 1}}, "df": 1}}}}, "u": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}}, "df": 1}}}}}}}}}}}}, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "y": {"docs": {"src.modules.optimize.run_optimization": {"tf": 1}, "src.modules.optimize.optimize_recovery_rate": {"tf": 1}, "src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 3}}}}}}}, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}, "src.data.analyse.get_spatial_outcomes": {"tf": 1}, "src.data.analyse.get_policy_effectiveness_tab": {"tf": 1.4142135623730951}, "src.data.prepare.load_data": {"tf": 1}, "src.data.prepare.start_pipeline": {"tf": 1}, "src.data.prepare.add_is_rural_column": {"tf": 1.4142135623730951}, "src.data.prepare.rename_assets_column": {"tf": 1.4142135623730951}, "src.data.prepare.rename_other_columns": {"tf": 1.4142135623730951}, "src.data.prepare.calculate_household_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.get_bank_or_credit_union": {"tf": 1.4142135623730951}, "src.data.prepare.decode_demographic_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.decode_income_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.calculate_income_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.decode_housing_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.add_housing_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.add_insurance_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.calculate_housing_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.calculate_poverty_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.assign_housing_vulnerability": {"tf": 1.4142135623730951}, "src.data.prepare.subset_columns": {"tf": 1.4142135623730951}, "src.data.prepare.check_columns": {"tf": 1.4142135623730951}, "src.data.prepare.add_missing_columns": {"tf": 1.4142135623730951}, "src.data.prepare.merge_districts": {"tf": 1.4142135623730951}, "src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.polynomial_regression": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}, "src.data.visualise.rainclouds": {"tf": 1}, "src.data.write.add_columns": {"tf": 1.7320508075688772}, "src.data.write.find_poor": {"tf": 1}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1.4142135623730951}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1.4142135623730951}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1.4142135623730951}, "src.modules.households.calculate_pml": {"tf": 1.4142135623730951}, "src.modules.households.select_district": {"tf": 1.4142135623730951}, "src.modules.households.estimate_savings": {"tf": 1.4142135623730951}, "src.modules.households.set_vulnerability": {"tf": 1.4142135623730951}, "src.modules.households.calculate_exposure": {"tf": 1.4142135623730951}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1.4142135623730951}, "src.modules.optimize.optimize_recovery_rate": {"tf": 1}, "src.modules.optimize.integrate_wellbeing": {"tf": 1.4142135623730951}}, "df": 48}}, "u": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "y": {"docs": {"src.data.analyse.get_spatial_outcomes": {"tf": 1}, "src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.prepare.prepare_household_survey": {"tf": 1}, "src.data.read.read_asset_damage": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}, "src.model.initialize_model": {"tf": 1}}, "df": 6}}}}}, "l": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "n": {"docs": {"src.data.prepare.exponential_regression": {"tf": 1.4142135623730951}, "src.data.prepare.polynomial_regression": {"tf": 1.4142135623730951}, "src.data.prepare.linear_regression": {"tf": 1.4142135623730951}}, "df": 3, "s": {"docs": {"src.data.prepare.add_missing_columns": {"tf": 1}, "src.data.visualise.rainclouds": {"tf": 1}}, "df": 2}}}}, "o": {"docs": {}, "df": 0, "r": {"docs": {"src.data.visualise.rainclouds": {"tf": 1}}, "df": 1}}}, "n": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.modules.optimize.run_optimization": {"tf": 1}, "src.modules.optimize.optimize_recovery_rate": {"tf": 1}, "src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 3}}}}}}}}}}, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.calculate_exposure": {"tf": 1}}, "df": 1}}}}}}}, "s": {"docs": {}, "df": 0, "h": {"docs": {"src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 1}}}}, "f": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}, "src.data.analyse.get_spatial_outcomes": {"tf": 1}, "src.data.analyse.get_policy_effectiveness_tab": {"tf": 1.4142135623730951}, "src.data.prepare.load_data": {"tf": 1}, "src.data.prepare.start_pipeline": {"tf": 1}, "src.data.prepare.add_is_rural_column": {"tf": 1.4142135623730951}, "src.data.prepare.rename_assets_column": {"tf": 1.4142135623730951}, "src.data.prepare.rename_other_columns": {"tf": 1.4142135623730951}, "src.data.prepare.calculate_household_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.get_bank_or_credit_union": {"tf": 1.4142135623730951}, "src.data.prepare.decode_demographic_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.decode_income_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.calculate_income_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.decode_housing_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.add_housing_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.add_insurance_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.calculate_housing_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.calculate_poverty_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.assign_housing_vulnerability": {"tf": 1.4142135623730951}, "src.data.prepare.subset_columns": {"tf": 1.4142135623730951}, "src.data.prepare.check_columns": {"tf": 1.4142135623730951}, "src.data.prepare.add_missing_columns": {"tf": 1.4142135623730951}, "src.data.prepare.merge_districts": {"tf": 1.4142135623730951}, "src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.polynomial_regression": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}, "src.data.visualise.rainclouds": {"tf": 1}, "src.data.write.add_columns": {"tf": 1.7320508075688772}, "src.data.write.find_poor": {"tf": 1}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1.4142135623730951}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1.4142135623730951}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1.4142135623730951}, "src.modules.households.calculate_pml": {"tf": 1.4142135623730951}, "src.modules.households.select_district": {"tf": 1.4142135623730951}, "src.modules.households.estimate_savings": {"tf": 1.4142135623730951}, "src.modules.households.set_vulnerability": {"tf": 1.4142135623730951}, "src.modules.households.calculate_exposure": {"tf": 1.4142135623730951}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1.4142135623730951}, "src.modules.optimize.optimize_recovery_rate": {"tf": 1}, "src.modules.optimize.integrate_wellbeing": {"tf": 1.4142135623730951}}, "df": 48}}, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.data.write.get_outcomes": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}}, "df": 2}}}}}}}, "u": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.polynomial_regression": {"tf": 1.4142135623730951}, "src.data.prepare.linear_regression": {"tf": 1}}, "df": 3}}}}}}}, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 1}, "src.data.visualise.rainclouds": {"tf": 1}}, "df": 3}}}}, "l": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {"src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 1.4142135623730951}, "src.data.write.find_poor": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1.7320508075688772}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 2}, "src.modules.optimize.optimize_recovery_rate": {"tf": 2.23606797749979}, "src.modules.optimize.integrate_wellbeing": {"tf": 2.23606797749979}}, "df": 13}}}}, "i": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "z": {"docs": {}, "df": 0, "e": {"docs": {"src.data.visualise.bivariate_choropleth": {"tf": 1}}, "df": 1}}}}}}}, "d": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "a": {"docs": {"src.data.prepare.start_pipeline": {"tf": 1}, "src.data.prepare.add_is_rural_column": {"tf": 1}, "src.data.prepare.rename_assets_column": {"tf": 1}, "src.data.prepare.rename_other_columns": {"tf": 1}, "src.data.prepare.calculate_household_attributes": {"tf": 1}, "src.data.prepare.get_bank_or_credit_union": {"tf": 1}, "src.data.prepare.decode_demographic_attributes": {"tf": 1}, "src.data.prepare.decode_income_attributes": {"tf": 1}, "src.data.prepare.calculate_income_attributes": {"tf": 1}, "src.data.prepare.decode_housing_attributes": {"tf": 1}, "src.data.prepare.add_housing_attributes": {"tf": 1}, "src.data.prepare.add_insurance_attributes": {"tf": 1}, "src.data.prepare.calculate_housing_attributes": {"tf": 1}, "src.data.prepare.calculate_poverty_attributes": {"tf": 1}, "src.data.prepare.assign_housing_vulnerability": {"tf": 1}, "src.data.prepare.subset_columns": {"tf": 1}, "src.data.prepare.check_columns": {"tf": 1}, "src.data.prepare.add_missing_columns": {"tf": 1}, "src.data.prepare.merge_districts": {"tf": 1}, "src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.polynomial_regression": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 1}, "src.data.visualise.bivariate_choropleth": {"tf": 1}, "src.data.visualise.nine_quadrants_plot": {"tf": 1}, "src.data.visualise.get_colors": {"tf": 1}, "src.data.visualise.bin_data": {"tf": 1}}, "df": 26, "f": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}, "src.data.analyse.get_spatial_outcomes": {"tf": 1}, "src.data.analyse.get_policy_effectiveness_tab": {"tf": 1.4142135623730951}, "src.data.prepare.load_data": {"tf": 1}, "src.data.prepare.start_pipeline": {"tf": 1}, "src.data.prepare.add_is_rural_column": {"tf": 1.4142135623730951}, "src.data.prepare.rename_assets_column": {"tf": 1.4142135623730951}, "src.data.prepare.rename_other_columns": {"tf": 1.4142135623730951}, "src.data.prepare.calculate_household_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.get_bank_or_credit_union": {"tf": 1.4142135623730951}, "src.data.prepare.decode_demographic_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.decode_income_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.calculate_income_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.decode_housing_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.add_housing_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.add_insurance_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.calculate_housing_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.calculate_poverty_attributes": {"tf": 1.4142135623730951}, "src.data.prepare.assign_housing_vulnerability": {"tf": 1.4142135623730951}, "src.data.prepare.subset_columns": {"tf": 1.4142135623730951}, "src.data.prepare.check_columns": {"tf": 1.4142135623730951}, "src.data.prepare.add_missing_columns": {"tf": 1.4142135623730951}, "src.data.prepare.merge_districts": {"tf": 1.4142135623730951}, "src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.polynomial_regression": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}, "src.data.visualise.rainclouds": {"tf": 1}, "src.data.write.add_columns": {"tf": 1.7320508075688772}, "src.data.write.find_poor": {"tf": 1}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1.4142135623730951}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1.4142135623730951}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1.4142135623730951}, "src.modules.households.calculate_pml": {"tf": 1.4142135623730951}, "src.modules.households.select_district": {"tf": 1.4142135623730951}, "src.modules.households.estimate_savings": {"tf": 1.4142135623730951}, "src.modules.households.set_vulnerability": {"tf": 1.4142135623730951}, "src.modules.households.calculate_exposure": {"tf": 1.4142135623730951}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1.4142135623730951}, "src.modules.optimize.optimize_recovery_rate": {"tf": 1}, "src.modules.optimize.integrate_wellbeing": {"tf": 1.4142135623730951}}, "df": 48}}}}}}}, "m": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {"src.data.read.get_asset_damage": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1}}, "df": 2}}}}}, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {"src.data.read.get_asset_damage": {"tf": 1}, "src.modules.households.select_district": {"tf": 1}}, "df": 2}}}}}, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"src.modules.optimize.run_optimization": {"tf": 1}, "src.modules.optimize.optimize_recovery_rate": {"tf": 1}, "src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 3}}}}}}, "c": {"docs": {}, "df": 0, "t": {"docs": {"src.data.write.get_outcomes": {"tf": 1}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 7}}}, "e": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.determine_affected": {"tf": 1}}, "df": 1}}}}}}}}}, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"src.data.analyse.get_spatial_outcomes": {"tf": 1.4142135623730951}, "src.data.analyse.get_policy_effectiveness_tab": {"tf": 1}, "src.data.visualise.rainclouds": {"tf": 1}}, "df": 3}}}}}}}, "f": {"docs": {"src.data.analyse.get_spatial_outcomes": {"tf": 1}}, "df": 1}, "p": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "z": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.modules.optimize.run_optimization": {"tf": 1}, "src.modules.optimize.optimize_recovery_rate": {"tf": 1.4142135623730951}}, "df": 2}}}}}}}}}}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {"src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.polynomial_regression": {"tf": 1.4142135623730951}, "src.data.prepare.linear_regression": {"tf": 1}, "src.data.visualise.rainclouds": {"tf": 1}}, "df": 4, "t": {"docs": {"src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.prepare.polynomial_regression": {"tf": 2}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.write.find_poor": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.model.initialize_model": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}, "src.modules.optimize.optimize_recovery_rate": {"tf": 1}, "src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 11, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {"src.data.analyse.get_spatial_outcomes": {"tf": 1}}, "df": 1}}}}}}, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"src.data.write.calculate_poverty_gap": {"tf": 1}}, "df": 1}}}}}, "d": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.adjust_assets_and_expenditure": {"tf": 1}}, "df": 1}}}}}}}, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.optimize.integrate_wellbeing": {"tf": 1.4142135623730951}}, "df": 1}}}}}, "s": {"docs": {"src.modules.households.set_vulnerability": {"tf": 1}}, "df": 1}}, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {"src.data.analyse.get_spatial_outcomes": {"tf": 1}, "src.data.prepare.add_missing_columns": {"tf": 1}, "src.data.visualise.rainclouds": {"tf": 1.4142135623730951}}, "df": 3}}, "n": {"docs": {}, "df": 0, "e": {"docs": {"src.data.write.find_poor": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1.4142135623730951}, "src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 4}}}, "u": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "a": {"docs": {"src.data.analyse.get_spatial_outcomes": {"tf": 1}}, "df": 1}}}}, "t": {"docs": {"src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.polynomial_regression": {"tf": 1.4142135623730951}, "src.data.prepare.linear_regression": {"tf": 1}}, "df": 3}, "a": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "l": {"docs": {"src.data.visualise.bivariate_choropleth": {"tf": 1.4142135623730951}}, "df": 1}}}}, "o": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {"src.data.write.get_outcomes": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 3}}}}, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {"src.data.analyse.get_spatial_outcomes": {"tf": 1.4142135623730951}, "src.data.prepare.prepare_asset_damage": {"tf": 1.4142135623730951}, "src.data.prepare.prepare_household_survey": {"tf": 1}, "src.data.prepare.exponential_regression": {"tf": 1.4142135623730951}, "src.data.prepare.polynomial_regression": {"tf": 1.4142135623730951}, "src.data.prepare.linear_regression": {"tf": 1.4142135623730951}, "src.data.read.get_asset_damage": {"tf": 1.4142135623730951}, "src.data.read.read_household_survey": {"tf": 1}, "src.data.visualise.rainclouds": {"tf": 1}, "src.model.initialize_model": {"tf": 1}, "src.modules.households.select_district": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 12}, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "s": {"docs": {"src.data.prepare.load_data": {"tf": 1}, "src.data.prepare.add_is_rural_column": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.visualise.bin_data": {"tf": 1}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}}, "df": 8}}}}}}}, "r": {"docs": {}, "df": 0, "t": {"docs": {"src.data.prepare.polynomial_regression": {"tf": 1}}, "df": 1}}}, "o": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "k": {"docs": {"src.data.write.get_outcomes": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}}, "df": 2}}}}, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"src.data.analyse.get_spatial_outcomes": {"tf": 1}}, "df": 1}}}, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "s": {"docs": {"src.data.visualise.rainclouds": {"tf": 1}}, "df": 1}}}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"src.modules.households.estimate_savings": {"tf": 1}}, "df": 1, "s": {"docs": {"src.modules.households.estimate_savings": {"tf": 1}}, "df": 1}}}}}}, "c": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.visualise.bivariate_choropleth": {"tf": 1}, "src.data.visualise.nine_quadrants_plot": {"tf": 1}, "src.data.visualise.bin_data": {"tf": 1}}, "df": 5}}}}, "e": {"docs": {}, "df": 0, "t": {"2": {"docs": {"src.data.visualise.rainclouds": {"tf": 1}}, "df": 1}, "docs": {"src.modules.households.set_vulnerability": {"tf": 1}}, "df": 1}}, "h": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "x": {"docs": {"src.data.visualise.rainclouds": {"tf": 1}}, "df": 1}}}}}, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "y": {"docs": {"src.modules.households.duplicate_households": {"tf": 1}, "src.modules.households.select_district": {"tf": 1}}, "df": 2}}}}}}, "m": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "n": {"docs": {"src.data.analyse.get_spatial_outcomes": {"tf": 1}}, "df": 1}}}, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"src.data.prepare.add_missing_columns": {"tf": 1}}, "df": 1}}}}}, "n": {"docs": {"src.model.initialize_model": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1}}, "df": 2}}, "o": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "l": {"docs": {"src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 1}}, "df": 2}}}}, "y": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 1}}, "g": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "s": {"docs": {"src.data.analyse.get_spatial_outcomes": {"tf": 1}}, "df": 1}}}}}}, "d": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"src.data.analyse.get_spatial_outcomes": {"tf": 1.4142135623730951}}, "df": 1}}}}}}}}}}}, "t": {"docs": {"src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.polynomial_regression": {"tf": 1.4142135623730951}, "src.data.prepare.linear_regression": {"tf": 1}}, "df": 3}, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "w": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "h": {"docs": {"src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 1}}}}}}, "n": {"docs": {"src.data.write.get_outcomes": {"tf": 1}, "src.data.write.find_poor": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}, "src.modules.optimize.optimize_recovery_rate": {"tf": 1}, "src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 7, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.prepare.prepare_household_survey": {"tf": 1}, "src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.polynomial_regression": {"tf": 1.4142135623730951}, "src.data.prepare.linear_regression": {"tf": 1}, "src.data.read.read_asset_damage": {"tf": 1}}, "df": 6}}}, "u": {"docs": {}, "df": 0, "m": {"docs": {"src.data.prepare.polynomial_regression": {"tf": 1}}, "df": 1, "p": {"docs": {}, "df": 0, "y": {"docs": {"src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 1}}, "df": 2}}}}, "e": {"docs": {}, "df": 0, "w": {"docs": {"src.data.prepare.polynomial_regression": {"tf": 1}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}}, "df": 3}}, "a": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"src.data.visualise.bivariate_choropleth": {"tf": 1.4142135623730951}, "src.data.visualise.nine_quadrants_plot": {"tf": 1.4142135623730951}, "src.data.visualise.bin_data": {"tf": 1.4142135623730951}}, "df": 3}}}}, "x": {"docs": {"src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.polynomial_regression": {"tf": 2.23606797749979}, "src.data.prepare.linear_regression": {"tf": 1}, "src.data.visualise.rainclouds": {"tf": 1.4142135623730951}, "src.data.visualise.bivariate_choropleth": {"tf": 1.4142135623730951}, "src.data.visualise.nine_quadrants_plot": {"tf": 1}, "src.data.visualise.bin_data": {"tf": 1}, "src.modules.optimize.optimize_recovery_rate": {"tf": 1}}, "df": 8}, "y": {"docs": {"src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.polynomial_regression": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 1}, "src.data.visualise.bivariate_choropleth": {"tf": 1.4142135623730951}, "src.data.visualise.nine_quadrants_plot": {"tf": 1}, "src.data.visualise.bin_data": {"tf": 1}}, "df": 6, "e": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "s": {"docs": {"src.data.visualise.rainclouds": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1}, "src.data.write.find_poor": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}, "src.modules.optimize.optimize_recovery_rate": {"tf": 1}, "src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 8}}}}}, "w": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "s": {"docs": {"src.data.prepare.exponential_regression": {"tf": 1}, "src.data.prepare.polynomial_regression": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 1}}, "df": 3}}}}}}}, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "d": {"docs": {"src.data.prepare.polynomial_regression": {"tf": 1}}, "df": 1}}, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"src.data.write.get_outcomes": {"tf": 1}}, "df": 1}}}}, "x": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"src.data.write.get_outcomes": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}}, "df": 2}}}}, "n": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 1}}}}}}}}, "o": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.calculate_exposure": {"tf": 1}}, "df": 1}}}}}}}, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.estimate_savings": {"tf": 1}}, "df": 1}}}}}}}}, "h": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "d": {"docs": {"src.modules.households.duplicate_households": {"tf": 1}, "src.modules.households.select_district": {"tf": 1}}, "df": 2, "s": {"docs": {"src.data.write.add_columns": {"tf": 1.4142135623730951}, "src.data.write.get_outcomes": {"tf": 1}, "src.data.write.find_poor": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}, "src.model.initialize_model": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}, "src.modules.optimize.integrate_wellbeing": {"tf": 1}}, "df": 17}}}}}}}}}}, "k": {"docs": {}, "df": 0, "w": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "s": {"docs": {"src.model.run_model": {"tf": 1}}, "df": 1}}}}}}, "v": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "y": {"docs": {"src.modules.households.set_vulnerability": {"tf": 1.4142135623730951}}, "df": 1}}}}}}}}}}}}}}}, "bases": {"root": {"docs": {}, "df": 0}}, "doc": {"root": {"0": {"docs": {"src.data.write.calculate_resilience": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1.4142135623730951}}, "df": 2}, "1": {"0": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 1}, "docs": {"src.data.read.get_asset_damage": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}}, "df": 4}, "2": {"5": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 1}, "docs": {}, "df": 0}, "3": {"0": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 1}, "docs": {}, "df": 0}, "5": {"0": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 1}, "docs": {}, "df": 0}, "docs": {"src": {"tf": 1.7320508075688772}, "src.data": {"tf": 1.7320508075688772}, "src.data.analyse": {"tf": 1.7320508075688772}, "src.data.analyse.prepare_outcomes": {"tf": 3.4641016151377544}, "src.data.analyse.get_spatial_outcomes": {"tf": 1.7320508075688772}, "src.data.analyse.get_policy_effectiveness_tab": {"tf": 1.7320508075688772}, "src.data.prepare": {"tf": 1.7320508075688772}, "src.data.prepare.prepare_asset_damage": {"tf": 1.7320508075688772}, "src.data.prepare.prepare_household_survey": {"tf": 3.605551275463989}, "src.data.prepare.load_data": {"tf": 1.7320508075688772}, "src.data.prepare.start_pipeline": {"tf": 1.7320508075688772}, "src.data.prepare.add_is_rural_column": {"tf": 1.7320508075688772}, "src.data.prepare.rename_assets_column": {"tf": 1.7320508075688772}, "src.data.prepare.rename_other_columns": {"tf": 1.7320508075688772}, "src.data.prepare.calculate_household_attributes": {"tf": 1.7320508075688772}, "src.data.prepare.get_bank_or_credit_union": {"tf": 1.7320508075688772}, "src.data.prepare.decode_demographic_attributes": {"tf": 1.7320508075688772}, "src.data.prepare.decode_income_attributes": {"tf": 1.7320508075688772}, "src.data.prepare.calculate_income_attributes": {"tf": 1.7320508075688772}, "src.data.prepare.decode_housing_attributes": {"tf": 1.7320508075688772}, "src.data.prepare.add_housing_attributes": {"tf": 1.7320508075688772}, "src.data.prepare.add_insurance_attributes": {"tf": 1.7320508075688772}, "src.data.prepare.calculate_housing_attributes": {"tf": 1.7320508075688772}, "src.data.prepare.calculate_poverty_attributes": {"tf": 1.7320508075688772}, "src.data.prepare.assign_housing_vulnerability": {"tf": 1.7320508075688772}, "src.data.prepare.subset_columns": {"tf": 1.7320508075688772}, "src.data.prepare.check_columns": {"tf": 1.7320508075688772}, "src.data.prepare.add_missing_columns": {"tf": 1.7320508075688772}, "src.data.prepare.merge_districts": {"tf": 1.7320508075688772}, "src.data.prepare.exponential_regression": {"tf": 1.7320508075688772}, "src.data.prepare.polynomial_regression": {"tf": 1.7320508075688772}, "src.data.prepare.linear_regression": {"tf": 1.7320508075688772}, "src.data.read": {"tf": 1.7320508075688772}, "src.data.read.read_asset_damage": {"tf": 1.7320508075688772}, "src.data.read.get_asset_damage": {"tf": 4.795831523312719}, "src.data.read.read_household_survey": {"tf": 3.872983346207417}, "src.data.visualise": {"tf": 1.7320508075688772}, "src.data.visualise.rainclouds": {"tf": 1.7320508075688772}, "src.data.visualise.bivariate_choropleth": {"tf": 1.7320508075688772}, "src.data.visualise.nine_quadrants_plot": {"tf": 1.7320508075688772}, "src.data.visualise.get_colors": {"tf": 1.7320508075688772}, "src.data.visualise.bin_data": {"tf": 1.7320508075688772}, "src.data.write": {"tf": 1.7320508075688772}, "src.data.write.add_columns": {"tf": 2.6457513110645907}, "src.data.write.get_outcomes": {"tf": 3.872983346207417}, "src.data.write.find_poor": {"tf": 2.8284271247461903}, "src.data.write.get_people_by_years_in_poverty": {"tf": 2.8284271247461903}, "src.data.write.calculate_poverty_gap": {"tf": 3.605551275463989}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 3.3166247903554}, "src.data.write.calculate_resilience": {"tf": 3.3166247903554}, "src.model": {"tf": 1.7320508075688772}, "src.model.initialize_model": {"tf": 3.3166247903554}, "src.model.run_model": {"tf": 1.7320508075688772}, "src.modules": {"tf": 1.7320508075688772}, "src.modules.households": {"tf": 1.7320508075688772}, "src.modules.households.duplicate_households": {"tf": 4}, "src.modules.households.calculate_average_productivity": {"tf": 3.4641016151377544}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 4.123105625617661}, "src.modules.households.calculate_pml": {"tf": 3.4641016151377544}, "src.modules.households.select_district": {"tf": 1.7320508075688772}, "src.modules.households.estimate_savings": {"tf": 3.872983346207417}, "src.modules.households.set_vulnerability": {"tf": 4.358898943540674}, "src.modules.households.calculate_exposure": {"tf": 4}, "src.modules.households.determine_affected": {"tf": 4.58257569495584}, "src.modules.households.apply_individual_policy": {"tf": 5.0990195135927845}, "src.modules.optimize": {"tf": 1.7320508075688772}, "src.modules.optimize.run_optimization": {"tf": 3.872983346207417}, "src.modules.optimize.optimize_recovery_rate": {"tf": 1.7320508075688772}, "src.modules.optimize.integrate_wellbeing": {"tf": 1.7320508075688772}}, "df": 69, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "t": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}}, "df": 1}}}}, "s": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"src.data.write.get_outcomes": {"tf": 1}}, "df": 1}}}}, "u": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.data.write.calculate_average_annual_consumption_loss": {"tf": 2.6457513110645907}, "src.data.write.calculate_resilience": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}}, "df": 3}}}}}}}}, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"src.modules.optimize.run_optimization": {"tf": 1.4142135623730951}}, "df": 1}}}}}}}}, "u": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "y": {"docs": {"src.data.prepare.prepare_household_survey": {"tf": 1.4142135623730951}, "src.data.read.read_household_survey": {"tf": 1.7320508075688772}, "src.model.initialize_model": {"tf": 1.4142135623730951}}, "df": 3}}}}}, "l": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "n": {"docs": {"src.data.prepare.add_is_rural_column": {"tf": 1}, "src.data.prepare.rename_assets_column": {"tf": 1}}, "df": 2, "s": {"docs": {"src.data.prepare.rename_other_columns": {"tf": 1}, "src.data.prepare.subset_columns": {"tf": 1}, "src.data.prepare.add_missing_columns": {"tf": 1}}, "df": 3, "/": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"src.data.write.add_columns": {"tf": 1}}, "df": 1}}}}}}}}}}}}}}, "e": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"src.data.prepare.linear_regression": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}}, "df": 2}}}}}}}}}}, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.add_is_rural_column": {"tf": 1}}, "df": 1, "d": {"docs": {"src.modules.households.adjust_assets_and_expenditure": {"tf": 1}}, "df": 1}}}}}}, "s": {"docs": {}, "df": 0, "v": {"docs": {"src.data.read.read_household_survey": {"tf": 1}}, "df": 1}}, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"src.data.write.get_outcomes": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1.4142135623730951}, "src.modules.households.determine_affected": {"tf": 1}}, "df": 7, "d": {"docs": {"src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}}, "df": 2}, "s": {"docs": {"src.modules.optimize.run_optimization": {"tf": 1}}, "df": 1}}, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "s": {"docs": {"src.data.write.get_outcomes": {"tf": 1}}, "df": 1}}}, "n": {"docs": {}, "df": 0, "g": {"docs": {"src.modules.households.calculate_exposure": {"tf": 1}}, "df": 1}}}}}}}}}, "n": {"docs": {"src.modules.households.adjust_assets_and_expenditure": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 3}, "p": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}}, "df": 2}}}}}}}, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1.4142135623730951}, "src.data.write.get_outcomes": {"tf": 1.4142135623730951}}, "df": 2}}}}}}}, "f": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}, "src.data.prepare.rename_other_columns": {"tf": 1}, "src.data.prepare.subset_columns": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.write.add_columns": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1.7320508075688772}, "src.data.write.find_poor": {"tf": 2.449489742783178}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1.4142135623730951}, "src.data.write.calculate_poverty_gap": {"tf": 2.449489742783178}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 2}, "src.data.write.calculate_resilience": {"tf": 1.4142135623730951}, "src.model.initialize_model": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1.4142135623730951}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1.7320508075688772}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1.4142135623730951}, "src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1.4142135623730951}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1.4142135623730951}}, "df": 21}, "r": {"docs": {"src.data.prepare.add_is_rural_column": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 3}, "n": {"docs": {"src.data.prepare.linear_regression": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}}, "df": 3, "l": {"docs": {}, "df": 0, "y": {"docs": {"src.data.read.get_asset_damage": {"tf": 1}}, "df": 1}}}, "p": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "z": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.data.write.get_outcomes": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1.7320508075688772}}, "df": 4}}}}}}}}, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}}, "df": 3}}}}}}}}, "d": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}}, "df": 6}}, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {"src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 2.23606797749979}, "src.modules.households.select_district": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 8, "s": {"docs": {"src.data.read.read_asset_damage": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}}, "df": 2}}}, "b": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.modules.households.set_vulnerability": {"tf": 1}}, "df": 1}}}}}}}}}, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"src.modules.optimize.run_optimization": {"tf": 1.4142135623730951}}, "df": 1}}}}}}}, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "a": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 2}, "src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.prepare.prepare_household_survey": {"tf": 1}, "src.data.prepare.load_data": {"tf": 1}, "src.data.prepare.start_pipeline": {"tf": 1}, "src.data.prepare.add_missing_columns": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1.4142135623730951}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 2}, "src.modules.households.calculate_pml": {"tf": 1.4142135623730951}, "src.modules.households.estimate_savings": {"tf": 1.4142135623730951}, "src.modules.households.set_vulnerability": {"tf": 1.4142135623730951}, "src.modules.households.calculate_exposure": {"tf": 1.4142135623730951}, "src.modules.households.determine_affected": {"tf": 1.4142135623730951}, "src.modules.households.apply_individual_policy": {"tf": 1.4142135623730951}, "src.modules.optimize.run_optimization": {"tf": 1.4142135623730951}}, "df": 20, "f": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}, "src.data.write.add_columns": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1}, "src.data.write.find_poor": {"tf": 1.7320508075688772}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1.4142135623730951}, "src.data.write.calculate_poverty_gap": {"tf": 1.4142135623730951}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1.4142135623730951}, "src.data.write.calculate_resilience": {"tf": 1.4142135623730951}, "src.modules.households.duplicate_households": {"tf": 1.4142135623730951}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1.4142135623730951}, "src.modules.households.calculate_pml": {"tf": 1.4142135623730951}, "src.modules.households.estimate_savings": {"tf": 1.4142135623730951}, "src.modules.households.set_vulnerability": {"tf": 1.4142135623730951}, "src.modules.households.calculate_exposure": {"tf": 1.4142135623730951}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1.4142135623730951}}, "df": 20}}}}}}}, "m": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.read.read_asset_damage": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 2}, "src.data.write.get_outcomes": {"tf": 1.4142135623730951}, "src.model.initialize_model": {"tf": 1.4142135623730951}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1.4142135623730951}}, "df": 6}}}}}, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.rename_assets_column": {"tf": 1}}, "df": 1}}}}}}}}}, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "s": {"docs": {"src.data.prepare.rename_other_columns": {"tf": 1}}, "df": 1}}}}, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.determine_affected": {"tf": 1}}, "df": 1, "s": {"docs": {"src.modules.households.determine_affected": {"tf": 1}}, "df": 1}, "d": {"docs": {"src.modules.households.determine_affected": {"tf": 1}}, "df": 1}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"src.modules.households.determine_affected": {"tf": 1}}, "df": 1}}}}}}}}}, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.decode_demographic_attributes": {"tf": 1}, "src.data.prepare.decode_income_attributes": {"tf": 1}, "src.data.prepare.decode_housing_attributes": {"tf": 1}}, "df": 3}}}}, "m": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {"src.data.prepare.decode_demographic_attributes": {"tf": 1}}, "df": 1}}}}}}}}}, "f": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "s": {"docs": {"src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}}, "df": 3}}}}}}}, "o": {"docs": {"src.data.prepare.linear_regression": {"tf": 1}}, "df": 1}, "u": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"src.data.write.calculate_poverty_gap": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1}}, "df": 2}, "s": {"docs": {"src.modules.households.duplicate_households": {"tf": 1}}, "df": 1}}, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.modules.households.duplicate_households": {"tf": 1}}, "df": 1}}}}}}}}}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}, "src.data.write.get_people_by_years_in_poverty": {"tf": 2}, "src.model.initialize_model": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}}, "df": 7, "t": {"docs": {"src.data.read.get_asset_damage": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.model.initialize_model": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}}, "df": 6, "o": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}, "src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.read.read_asset_damage": {"tf": 1}}, "df": 3}, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.add_housing_attributes": {"tf": 1}}, "df": 1}}}}}}, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {"src.data.prepare.subset_columns": {"tf": 1}, "src.data.write.add_columns": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1.4142135623730951}}, "df": 3}}}}}}, "d": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"src.data.prepare.add_is_rural_column": {"tf": 1}}, "df": 1}}}}}, "g": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.adjust_assets_and_expenditure": {"tf": 1.4142135623730951}}, "df": 1}}}}}}, "e": {"docs": {}, "df": 0, "x": {"docs": {"src.data.write.calculate_poverty_gap": {"tf": 1}}, "df": 1}, "p": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "y": {"docs": {"src.modules.households.adjust_assets_and_expenditure": {"tf": 1}}, "df": 1}}}}}}}}}}}, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.decode_income_attributes": {"tf": 1}}, "df": 1}}}}, "i": {"docs": {}, "df": 0, "t": {"docs": {"src.modules.households.set_vulnerability": {"tf": 1}}, "df": 1, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"src.data.write.calculate_poverty_gap": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1}}, "df": 2, "i": {"docs": {}, "df": 0, "z": {"docs": {}, "df": 0, "e": {"docs": {"src.model.initialize_model": {"tf": 1}}, "df": 1}}}}}}}}}, "t": {"docs": {"src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.read.read_asset_damage": {"tf": 1}}, "df": 2}, "f": {"docs": {"src.data.prepare.prepare_household_survey": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1.4142135623730951}, "src.data.read.read_household_survey": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1.4142135623730951}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1.4142135623730951}, "src.modules.households.set_vulnerability": {"tf": 1.4142135623730951}, "src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1.4142135623730951}}, "df": 10}, "s": {"docs": {"src.data.prepare.prepare_household_survey": {"tf": 1}, "src.data.prepare.add_is_rural_column": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1.7320508075688772}, "src.data.read.read_household_survey": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1.4142135623730951}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1.4142135623730951}, "src.modules.households.duplicate_households": {"tf": 1.4142135623730951}, "src.modules.households.set_vulnerability": {"tf": 1.7320508075688772}, "src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 12}}, "a": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}, "src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.prepare.add_is_rural_column": {"tf": 1}, "src.data.prepare.rename_other_columns": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 1}, "src.data.read.read_asset_damage": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1.4142135623730951}, "src.model.initialize_model": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.select_district": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1.4142135623730951}, "src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1.4142135623730951}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 2}, "src.modules.optimize.run_optimization": {"tf": 1.4142135623730951}}, "df": 19, "r": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "s": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1}, "src.data.write.find_poor": {"tf": 1}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}, "src.model.initialize_model": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}}, "df": 20}}, "e": {"docs": {"src.modules.households.estimate_savings": {"tf": 1}}, "df": 1}}, "d": {"docs": {}, "df": 0, "d": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 2}, "src.data.prepare.add_missing_columns": {"tf": 1}, "src.data.write.add_columns": {"tf": 1}}, "df": 3}, "j": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {"src.modules.households.adjust_assets_and_expenditure": {"tf": 1}}, "df": 1, "e": {"docs": {}, "df": 0, "d": {"docs": {"src.modules.households.adjust_assets_and_expenditure": {"tf": 1}}, "df": 1}}}}}}}, "s": {"docs": {"src.data.write.get_outcomes": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1.4142135623730951}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}}, "df": 4, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {"src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.read.read_asset_damage": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1.7320508075688772}, "src.data.write.get_outcomes": {"tf": 1.4142135623730951}, "src.model.initialize_model": {"tf": 1.4142135623730951}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 2}, "src.modules.households.determine_affected": {"tf": 1.4142135623730951}}, "df": 7, "s": {"docs": {"src.data.prepare.rename_assets_column": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1.4142135623730951}}, "df": 2}}}, "u": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.estimate_savings": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}}, "df": 2}}}, "i": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"src.modules.households.set_vulnerability": {"tf": 1}}, "df": 1}}}}}}}, "n": {"docs": {}, "df": 0, "d": {"docs": {"src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 1.4142135623730951}, "src.data.read.read_asset_damage": {"tf": 1}, "src.data.write.find_poor": {"tf": 1.4142135623730951}, "src.data.write.calculate_poverty_gap": {"tf": 1.4142135623730951}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1.4142135623730951}, "src.data.write.calculate_resilience": {"tf": 1}, "src.model.initialize_model": {"tf": 1.4142135623730951}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1.7320508075688772}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1.4142135623730951}}, "df": 14}, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "y": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {"src.data.read.get_asset_damage": {"tf": 1}}, "df": 1}}}}}}, "n": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"src.data.write.calculate_average_annual_consumption_loss": {"tf": 2.6457513110645907}}, "df": 1}}}}}, "t": {"docs": {"src.data.write.find_poor": {"tf": 2}, "src.data.write.calculate_poverty_gap": {"tf": 2.449489742783178}}, "df": 2, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"src.data.prepare.decode_demographic_attributes": {"tf": 1}, "src.data.prepare.decode_income_attributes": {"tf": 1}, "src.data.prepare.decode_housing_attributes": {"tf": 1}, "src.data.prepare.add_housing_attributes": {"tf": 1}}, "df": 4}}}}}}}}}, "l": {"docs": {}, "df": 0, "l": {"docs": {"src.data.read.read_asset_damage": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1.4142135623730951}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 4}, "g": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "m": {"docs": {"src.data.write.get_outcomes": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}}, "df": 4}}}}}}}}, "f": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"src.data.write.add_columns": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1.4142135623730951}, "src.data.write.calculate_resilience": {"tf": 1.7320508075688772}, "src.modules.households.determine_affected": {"tf": 2.23606797749979}, "src.modules.households.apply_individual_policy": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 2}}, "df": 6}}}}}}, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"src.modules.households.duplicate_households": {"tf": 1}}, "df": 1}}}}, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {"src.data.write.get_outcomes": {"tf": 1.4142135623730951}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 2.6457513110645907}, "src.modules.households.calculate_average_productivity": {"tf": 1.7320508075688772}, "src.modules.optimize.run_optimization": {"tf": 1.4142135623730951}}, "df": 4}}}, "s": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.modules.optimize.run_optimization": {"tf": 1}}, "df": 1}}}}}}}, "e": {"docs": {"src.modules.households.calculate_average_productivity": {"tf": 1}}, "df": 1, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {"src.modules.households.calculate_average_productivity": {"tf": 1}}, "df": 1}}}}, "p": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "y": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1.4142135623730951}}, "df": 1}, "i": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 1}}}}}}}, "f": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 2}, "src.data.write.get_outcomes": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1.4142135623730951}}, "df": 3}}, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.data.read.get_asset_damage": {"tf": 1.4142135623730951}, "src.data.write.get_outcomes": {"tf": 1.4142135623730951}, "src.modules.households.calculate_pml": {"tf": 1.7320508075688772}}, "df": 3}}}}}}, "o": {"docs": {}, "df": 0, "m": {"docs": {"src.data.read.read_asset_damage": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}, "src.data.write.add_columns": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1}}, "df": 4}}}, "o": {"docs": {}, "df": 0, "r": {"docs": {"src.data.prepare.prepare_household_survey": {"tf": 1}, "src.data.prepare.rename_other_columns": {"tf": 1}, "src.data.read.read_asset_damage": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1.4142135623730951}, "src.data.write.get_outcomes": {"tf": 1.4142135623730951}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1.4142135623730951}, "src.modules.households.select_district": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1.4142135623730951}, "src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1.4142135623730951}, "src.modules.households.determine_affected": {"tf": 1.7320508075688772}, "src.modules.households.apply_individual_policy": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1.4142135623730951}}, "df": 13, "m": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}}, "df": 1}}}}, "u": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "d": {"docs": {"src.modules.households.determine_affected": {"tf": 1}}, "df": 1}}}}, "i": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.read.read_asset_damage": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}}, "df": 4, "s": {"docs": {"src.model.initialize_model": {"tf": 1.4142135623730951}}, "df": 1}}}}, "u": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.data.prepare.rename_other_columns": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1.4142135623730951}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}}, "df": 5}}}}}}}, "l": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {"src.data.write.get_outcomes": {"tf": 2.23606797749979}, "src.data.write.find_poor": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1.7320508075688772}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 2}}, "df": 10}}}}, "a": {"docs": {"src.modules.households.determine_affected": {"tf": 1}}, "df": 1, "l": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}}, "df": 3}}}}}, "r": {"2": {"docs": {"src.data.prepare.linear_regression": {"tf": 1}}, "df": 1}, "docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "s": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1.4142135623730951}}, "df": 1}}}}, "i": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {"src.data.write.calculate_resilience": {"tf": 1.7320508075688772}}, "df": 1}}}}}}}}, "t": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "n": {"docs": {"src.data.prepare.linear_regression": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1.4142135623730951}}, "df": 2, "s": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1}, "src.data.write.find_poor": {"tf": 1}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}, "src.model.initialize_model": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}}, "df": 20}}}}}, "n": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.rename_assets_column": {"tf": 1}, "src.data.prepare.rename_other_columns": {"tf": 1}}, "df": 2}}}}, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"src.data.prepare.decode_income_attributes": {"tf": 1}, "src.data.prepare.decode_housing_attributes": {"tf": 1}}, "df": 2}}, "i": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.optimize.run_optimization": {"tf": 1}}, "df": 1}}}}}}, "g": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.data.prepare.linear_regression": {"tf": 1}}, "df": 1}}}}}}}}, "a": {"docs": {}, "df": 0, "d": {"docs": {"src.data.read.read_asset_damage": {"tf": 1}}, "df": 1, "s": {"docs": {"src.data.read.read_household_survey": {"tf": 1}}, "df": 1}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"src.model.initialize_model": {"tf": 1}}, "df": 1}}}}}, "p": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {"src.model.initialize_model": {"tf": 1}}, "df": 1}}}}}}}}}}}}, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "y": {"docs": {"src.modules.optimize.run_optimization": {"tf": 1.4142135623730951}}, "df": 1}}}}}}}, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"src.data.prepare.prepare_household_survey": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}}, "df": 9}}}}, "w": {"docs": {"src.data.prepare.load_data": {"tf": 1}}, "df": 1}, "t": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.estimate_savings": {"tf": 1.7320508075688772}, "src.modules.optimize.run_optimization": {"tf": 2}}, "df": 2}}, "n": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "m": {"docs": {"src.modules.households.set_vulnerability": {"tf": 1.7320508075688772}}, "df": 1}}}}}, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"src.data.prepare.add_is_rural_column": {"tf": 1}}, "df": 1}}}, "n": {"docs": {"src.model.run_model": {"tf": 1}}, "df": 1}}, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "k": {"docs": {"src.modules.optimize.run_optimization": {"tf": 1}}, "df": 1}}}}, "t": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.write.find_poor": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}, "src.model.initialize_model": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 9}}}}, "h": {"docs": {}, "df": 0, "e": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 2.23606797749979}, "src.data.prepare.prepare_household_survey": {"tf": 1.4142135623730951}, "src.data.prepare.load_data": {"tf": 1}, "src.data.prepare.start_pipeline": {"tf": 1}, "src.data.prepare.add_is_rural_column": {"tf": 1}, "src.data.prepare.rename_assets_column": {"tf": 1}, "src.data.prepare.decode_demographic_attributes": {"tf": 1}, "src.data.prepare.decode_income_attributes": {"tf": 1}, "src.data.prepare.decode_housing_attributes": {"tf": 1}, "src.data.prepare.add_missing_columns": {"tf": 1}, "src.data.prepare.linear_regression": {"tf": 2}, "src.data.read.read_asset_damage": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 2}, "src.data.read.read_household_survey": {"tf": 1}, "src.data.write.add_columns": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1}, "src.data.write.find_poor": {"tf": 3.3166247903554}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 3.7416573867739413}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 2}, "src.data.write.calculate_resilience": {"tf": 1.7320508075688772}, "src.model.initialize_model": {"tf": 1}, "src.model.run_model": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1.7320508075688772}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 2.449489742783178}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1.7320508075688772}, "src.modules.optimize.run_optimization": {"tf": 3.3166247903554}}, "df": 31, "r": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.adjust_assets_and_expenditure": {"tf": 1}}, "df": 1}}}, "a": {"docs": {}, "df": 0, "t": {"docs": {"src.data.prepare.add_is_rural_column": {"tf": 1}, "src.model.initialize_model": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}}, "df": 4}, "n": {"docs": {"src.data.read.get_asset_damage": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}}, "df": 6}}, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "d": {"docs": {"src.modules.households.duplicate_households": {"tf": 1}}, "df": 1}}}}}}}, "i": {"docs": {}, "df": 0, "s": {"docs": {"src.modules.optimize.run_optimization": {"tf": 1}}, "df": 1}}}, "o": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 2}, "src.data.prepare.rename_assets_column": {"tf": 1}, "src.data.prepare.add_missing_columns": {"tf": 1}, "src.data.write.add_columns": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1}, "src.model.initialize_model": {"tf": 1.4142135623730951}, "src.modules.households.duplicate_households": {"tf": 1}, "src.modules.households.calculate_average_productivity": {"tf": 1.4142135623730951}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1.7320508075688772}, "src.modules.households.calculate_pml": {"tf": 1.4142135623730951}, "src.modules.households.apply_individual_policy": {"tf": 1.4142135623730951}}, "df": 11, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"src.data.read.get_asset_damage": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1.4142135623730951}, "src.data.write.calculate_resilience": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1.4142135623730951}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1.4142135623730951}, "src.modules.households.determine_affected": {"tf": 1}}, "df": 6}}}, "p": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1.4142135623730951}}, "df": 1}}, "i": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"src.data.write.calculate_resilience": {"tf": 1}}, "df": 1, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "p": {"docs": {"src.modules.optimize.run_optimization": {"tf": 1.4142135623730951}}, "df": 1}}}}}}}, "r": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}}, "df": 2}}}, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1.7320508075688772}}, "df": 1}}}}}}, "e": {"docs": {}, "df": 0, "x": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "s": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}}, "df": 1}}}}}}}, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"src.data.read.get_asset_damage": {"tf": 1.4142135623730951}, "src.data.write.get_outcomes": {"tf": 1.4142135623730951}, "src.modules.households.calculate_pml": {"tf": 1.7320508075688772}}, "df": 3}}}}, "n": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.adjust_assets_and_expenditure": {"tf": 1.4142135623730951}, "src.modules.households.estimate_savings": {"tf": 1}}, "df": 2}}}}}}}}, "o": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.calculate_exposure": {"tf": 2.23606797749979}, "src.modules.households.determine_affected": {"tf": 1}}, "df": 2}}}}}}, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.data.write.calculate_poverty_gap": {"tf": 1.4142135623730951}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}}, "df": 3}}}}}}}}, "m": {"docs": {}, "df": 0, "a": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}}, "df": 1}}, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"src.data.read.get_asset_damage": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1.4142135623730951}}, "df": 2}}}}, "n": {"docs": {}, "df": 0, "d": {"docs": {"src.data.write.find_poor": {"tf": 1.4142135623730951}, "src.data.write.calculate_poverty_gap": {"tf": 1.7320508075688772}}, "df": 2}}, "a": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "h": {"docs": {"src.data.write.get_people_by_years_in_poverty": {"tf": 1.4142135623730951}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}}, "df": 3}}}, "q": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"src.modules.households.duplicate_households": {"tf": 1}}, "df": 1}}}}, "f": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}}, "df": 2}}}}}}}}, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.estimate_savings": {"tf": 1.4142135623730951}}, "df": 1, "d": {"docs": {"src.modules.households.estimate_savings": {"tf": 1}}, "df": 1}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"src.modules.households.estimate_savings": {"tf": 1}}, "df": 1}}}}}}}}}}, "w": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "k": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "h": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}}, "df": 1}}}}}}}}, "h": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1.4142135623730951}, "src.data.prepare.add_is_rural_column": {"tf": 1}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}}, "df": 5}}}}}}, "e": {"docs": {"src.model.initialize_model": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}}, "df": 3, "i": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "t": {"docs": {"src.modules.households.calculate_pml": {"tf": 1}}, "df": 1, "s": {"docs": {"src.modules.households.duplicate_households": {"tf": 1.4142135623730951}}, "df": 1}}}}}}, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "h": {"docs": {"src.modules.households.duplicate_households": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1.4142135623730951}, "src.modules.households.set_vulnerability": {"tf": 1.4142135623730951}, "src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}}, "df": 9}}}, "a": {"docs": {}, "df": 0, "s": {"docs": {"src.modules.households.adjust_assets_and_expenditure": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}}, "df": 2}}}, "p": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}}, "df": 1}}}, "y": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 2.23606797749979}}, "df": 2}}}}, "o": {"docs": {}, "df": 0, "r": {"1": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 1}, "2": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 1}, "docs": {"src.data.write.find_poor": {"tf": 2.23606797749979}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1.4142135623730951}, "src.data.write.calculate_poverty_gap": {"tf": 2}, "src.modules.households.apply_individual_policy": {"tf": 1.7320508075688772}}, "df": 4}}, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "y": {"docs": {"src.data.write.find_poor": {"tf": 1.4142135623730951}, "src.data.write.get_people_by_years_in_poverty": {"tf": 2}, "src.data.write.calculate_poverty_gap": {"tf": 2.23606797749979}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1.4142135623730951}, "src.modules.households.calculate_exposure": {"tf": 1.7320508075688772}}, "df": 5}}}}}, "p": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.modules.households.calculate_pml": {"tf": 1}}, "df": 1}}}}}}}}}, "d": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1}, "src.data.write.find_poor": {"tf": 1}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1.4142135623730951}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1.4142135623730951}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1.4142135623730951}, "src.modules.households.calculate_pml": {"tf": 1.4142135623730951}, "src.modules.households.estimate_savings": {"tf": 1.4142135623730951}, "src.modules.households.set_vulnerability": {"tf": 1.4142135623730951}, "src.modules.households.calculate_exposure": {"tf": 1.4142135623730951}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1.4142135623730951}}, "df": 19}, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.prepare.prepare_household_survey": {"tf": 1}}, "df": 2}}}}, "d": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"src.data.prepare.linear_regression": {"tf": 1}}, "df": 1}}}}}}}, "o": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"src.data.prepare.start_pipeline": {"tf": 1}}, "df": 1}}}}}}}, "d": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {"src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1}}, "df": 2, "i": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "y": {"docs": {"src.data.write.get_outcomes": {"tf": 1.4142135623730951}, "src.modules.households.calculate_average_productivity": {"tf": 1.7320508075688772}, "src.modules.optimize.run_optimization": {"tf": 1.4142135623730951}}, "df": 3}}}}}}}}}, "b": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"src.data.write.calculate_resilience": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1.4142135623730951}, "src.modules.households.calculate_exposure": {"tf": 1}}, "df": 3}}, "i": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "y": {"docs": {"src.modules.households.determine_affected": {"tf": 1}}, "df": 1}}}}}}}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"src.data.read.get_asset_damage": {"tf": 1.4142135623730951}, "src.modules.households.calculate_average_productivity": {"tf": 1.4142135623730951}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1.4142135623730951}, "src.modules.households.calculate_pml": {"tf": 1.4142135623730951}, "src.modules.households.calculate_exposure": {"tf": 1.4142135623730951}}, "df": 5}}}}, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "s": {"docs": {"src.data.prepare.prepare_household_survey": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}}, "df": 4}}}}}, "s": {"docs": {"src.modules.households.estimate_savings": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}}, "df": 3}}}}}, "i": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.start_pipeline": {"tf": 1}}, "df": 1}}}}}}}, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "d": {"docs": {"src.data.read.get_asset_damage": {"tf": 1.4142135623730951}}, "df": 1}}}, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {"src.data.write.calculate_average_annual_consumption_loss": {"tf": 1.4142135623730951}}, "df": 1}}}}}}}}, "o": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"src.data.write.get_people_by_years_in_poverty": {"tf": 1.4142135623730951}}, "df": 1}}}}}, "m": {"docs": {}, "df": 0, "l": {"docs": {"src.data.write.calculate_resilience": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}}, "df": 2}}}, "b": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "l": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1.4142135623730951}, "src.data.read.get_asset_damage": {"tf": 1}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}}, "df": 7}}}, "e": {"docs": {"src.data.prepare.rename_assets_column": {"tf": 1}, "src.model.initialize_model": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 5, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"src.data.write.find_poor": {"tf": 1.4142135623730951}, "src.data.write.calculate_poverty_gap": {"tf": 1.7320508075688772}}, "df": 2}}}}}}}, "t": {"docs": {}, "df": 0, "w": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {"src.modules.households.adjust_assets_and_expenditure": {"tf": 1}}, "df": 1}}}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"src.modules.households.determine_affected": {"tf": 1}}, "df": 1}}}}, "y": {"docs": {"src.model.initialize_model": {"tf": 1}}, "df": 1}, "a": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}}, "df": 2}}}}, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "s": {"docs": {"src.modules.households.calculate_exposure": {"tf": 1.7320508075688772}}, "df": 1}}}, "u": {"docs": {}, "df": 0, "t": {"docs": {"src.modules.households.determine_affected": {"tf": 1}}, "df": 1}}}, "v": {"docs": {"src.modules.households.set_vulnerability": {"tf": 1}}, "df": 1, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1.4142135623730951}, "src.data.prepare.linear_regression": {"tf": 1}}, "df": 2}, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "r": {"docs": {"src.data.prepare.prepare_household_survey": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1.4142135623730951}, "src.data.read.read_household_survey": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1.4142135623730951}}, "df": 6}}}}}}}}}, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "y": {"docs": {"src.modules.households.set_vulnerability": {"tf": 2.23606797749979}, "src.modules.households.calculate_exposure": {"tf": 1}}, "df": 2}}}}}}}}}}}}}, "u": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}}, "df": 1}}}, "y": {"docs": {"src.data.analyse.prepare_outcomes": {"tf": 1}}, "df": 1}}}}}}}}}, "i": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "m": {"docs": {"src.modules.households.set_vulnerability": {"tf": 1}}, "df": 1}}}}}}, "p": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1.4142135623730951}}, "df": 1}, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "y": {"docs": {"src.modules.optimize.run_optimization": {"tf": 1}}, "df": 1}}}}}}}, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "l": {"docs": {"src.data.prepare.prepare_asset_damage": {"tf": 1}}, "df": 1}}}, "s": {"docs": {}, "df": 0, "s": {"docs": {"src.modules.households.duplicate_households": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}}, "df": 2}}}, "o": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "d": {"docs": {"src.data.prepare.load_data": {"tf": 1}, "src.data.read.read_asset_damage": {"tf": 1}}, "df": 2}}, "s": {"docs": {}, "df": 0, "s": {"docs": {"src.data.read.get_asset_damage": {"tf": 1.4142135623730951}, "src.data.write.get_outcomes": {"tf": 1.4142135623730951}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 2.23606797749979}, "src.data.write.calculate_resilience": {"tf": 1.4142135623730951}, "src.modules.households.calculate_pml": {"tf": 2.23606797749979}, "src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}}, "df": 7}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {"src.data.write.find_poor": {"tf": 1.4142135623730951}, "src.data.write.calculate_poverty_gap": {"tf": 1.4142135623730951}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 2}}, "df": 3, "a": {"docs": {}, "df": 0, "r": {"docs": {"src.data.prepare.linear_regression": {"tf": 1}}, "df": 1}}}}}, "u": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "a": {"docs": {"src.data.read.read_household_survey": {"tf": 1}}, "df": 1}}}}, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {"src.modules.households.adjust_assets_and_expenditure": {"tf": 1}}, "df": 1}}}}}}, "s": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.prepare_asset_damage": {"tf": 1}}, "df": 1}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"src.modules.households.estimate_savings": {"tf": 1.7320508075688772}}, "df": 1, "s": {"docs": {"src.modules.households.estimate_savings": {"tf": 2.23606797749979}}, "df": 1}}}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"src.data.read.read_household_survey": {"tf": 1}}, "df": 1}}}, "m": {"docs": {}, "df": 0, "e": {"docs": {"src.data.write.get_outcomes": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}}, "df": 2}, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"src.model.initialize_model": {"tf": 1}}, "df": 1}}}}}, "i": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"src.data.prepare.prepare_household_survey": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1}, "src.data.write.find_poor": {"tf": 2}, "src.data.write.calculate_poverty_gap": {"tf": 2}}, "df": 4}}}}}}}}, "n": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 1}}}}}, "t": {"docs": {}, "df": 0, "r": {"docs": {"src.data.prepare.prepare_household_survey": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1.4142135623730951}, "src.data.read.read_household_survey": {"tf": 1}, "src.model.initialize_model": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 5, "u": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 1}}}}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 1}}}}, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "t": {"docs": {"src.data.prepare.start_pipeline": {"tf": 1}}, "df": 1}}, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "s": {"docs": {"src.data.read.get_asset_damage": {"tf": 1.4142135623730951}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1.4142135623730951}, "src.modules.households.calculate_pml": {"tf": 1.4142135623730951}, "src.modules.households.calculate_exposure": {"tf": 1.4142135623730951}}, "df": 5}}}}}}}}, "o": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "k": {"docs": {"src.data.read.get_asset_damage": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1.4142135623730951}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1.4142135623730951}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}}, "df": 5}}}}, "u": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"src.data.prepare.prepare_household_survey": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}}, "df": 3}}}}}}}, "b": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {"src.data.prepare.subset_columns": {"tf": 1}}, "df": 1}}}}, "r": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "y": {"docs": {"src.data.read.read_household_survey": {"tf": 1.4142135623730951}, "src.model.initialize_model": {"tf": 1.4142135623730951}, "src.modules.households.duplicate_households": {"tf": 1.7320508075688772}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1.7320508075688772}, "src.modules.households.calculate_pml": {"tf": 1.4142135623730951}, "src.modules.households.estimate_savings": {"tf": 1.4142135623730951}, "src.modules.households.set_vulnerability": {"tf": 1.4142135623730951}, "src.modules.households.calculate_exposure": {"tf": 1.4142135623730951}, "src.modules.households.determine_affected": {"tf": 1.4142135623730951}, "src.modules.households.apply_individual_policy": {"tf": 1.4142135623730951}}, "df": 11}}}}}, "e": {"docs": {}, "df": 0, "t": {"docs": {"src.data.prepare.rename_other_columns": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}}, "df": 2}, "e": {"docs": {"src.data.prepare.rename_other_columns": {"tf": 1}}, "df": 1}, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {"src.modules.households.select_district": {"tf": 1}}, "df": 1}}}}}, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.linear_regression": {"tf": 1}}, "df": 1}}}, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"src.data.read.get_asset_damage": {"tf": 1.7320508075688772}}, "df": 1}}}}, "p": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {"src.data.read.get_asset_damage": {"tf": 1}, "src.modules.households.select_district": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}, "src.modules.households.calculate_exposure": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}, "src.modules.households.apply_individual_policy": {"tf": 1.4142135623730951}}, "df": 7}}}}}}}}, "x": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "x": {"docs": {"src.data.prepare.prepare_asset_damage": {"tf": 1}, "src.data.read.read_asset_damage": {"tf": 1}}, "df": 2}}}}, "m": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "l": {"docs": {"src.data.prepare.prepare_household_survey": {"tf": 1}, "src.data.write.get_outcomes": {"tf": 1}, "src.model.initialize_model": {"tf": 1}, "src.model.run_model": {"tf": 1}}, "df": 4}}}, "r": {"docs": {}, "df": 0, "e": {"docs": {"src.data.prepare.rename_assets_column": {"tf": 1}}, "df": 1}}}, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "y": {"docs": {"src.data.prepare.add_missing_columns": {"tf": 1}}, "df": 1}}}}}}, "x": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "m": {"docs": {"src.data.write.calculate_resilience": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1.4142135623730951}, "src.modules.households.calculate_exposure": {"tf": 1}}, "df": 3}}}}}, "t": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "h": {"docs": {"src.modules.households.adjust_assets_and_expenditure": {"tf": 1}}, "df": 1}}}, "s": {"docs": {}, "df": 0, "k": {"docs": {"src.modules.households.determine_affected": {"tf": 1}}, "df": 1}}}, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"src.data.prepare.add_missing_columns": {"tf": 1}}, "df": 1}}}}, "m": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "h": {"docs": {"src.modules.households.adjust_assets_and_expenditure": {"tf": 1}}, "df": 1}}}}}}, "n": {"docs": {"src.model.initialize_model": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1.4142135623730951}}, "df": 2, "i": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "m": {"docs": {"src.model.initialize_model": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1}}, "df": 2}}}}}}, "e": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "y": {"docs": {"src.data.read.read_asset_damage": {"tf": 1}}, "df": 1}}}}}, "y": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1}}, "df": 1}}, "n": {"docs": {"src.data.write.get_outcomes": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.modules.optimize.run_optimization": {"tf": 1}}, "df": 4, "o": {"docs": {"src.modules.households.determine_affected": {"tf": 1}}, "df": 1, "t": {"docs": {"src.data.prepare.prepare_household_survey": {"tf": 1}, "src.data.prepare.add_is_rural_column": {"tf": 1}, "src.data.read.get_asset_damage": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}}, "df": 6}, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.estimate_savings": {"tf": 1}, "src.modules.households.set_vulnerability": {"tf": 1}}, "df": 2}}}}, "e": {"docs": {}, "df": 0, "w": {"docs": {"src.data.prepare.add_is_rural_column": {"tf": 1}, "src.data.prepare.add_housing_attributes": {"tf": 1}, "src.data.write.find_poor": {"tf": 1.4142135623730951}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1.4142135623730951}, "src.data.write.calculate_poverty_gap": {"tf": 1.4142135623730951}}, "df": 5}, "e": {"docs": {}, "df": 0, "d": {"docs": {"src.model.initialize_model": {"tf": 1}}, "df": 1}}, "a": {"docs": {}, "df": 0, "r": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1.4142135623730951}}, "df": 1}}}, "a": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"src.data.read.get_asset_damage": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1}, "src.model.initialize_model": {"tf": 1}}, "df": 3}}}, "u": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"src.data.write.get_outcomes": {"tf": 1}, "src.data.write.find_poor": {"tf": 1.4142135623730951}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1.4142135623730951}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}, "src.model.initialize_model": {"tf": 1}, "src.modules.households.duplicate_households": {"tf": 1.4142135623730951}, "src.modules.optimize.run_optimization": {"tf": 1}}, "df": 9}}}}}}, "h": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {"src.modules.households.calculate_average_productivity": {"tf": 1}}, "df": 1, "h": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "d": {"docs": {"src.data.prepare.add_is_rural_column": {"tf": 1}, "src.data.read.read_household_survey": {"tf": 1.4142135623730951}, "src.data.write.find_poor": {"tf": 1}, "src.model.initialize_model": {"tf": 1.4142135623730951}, "src.modules.households.duplicate_households": {"tf": 1.7320508075688772}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 2}, "src.modules.households.calculate_pml": {"tf": 1.4142135623730951}, "src.modules.households.estimate_savings": {"tf": 1.4142135623730951}, "src.modules.households.set_vulnerability": {"tf": 1.4142135623730951}, "src.modules.households.calculate_exposure": {"tf": 1.4142135623730951}, "src.modules.households.determine_affected": {"tf": 1.7320508075688772}, "src.modules.households.apply_individual_policy": {"tf": 1.4142135623730951}, "src.modules.optimize.run_optimization": {"tf": 1}}, "df": 14, "s": {"docs": {"src.data.write.add_columns": {"tf": 1.4142135623730951}, "src.data.write.get_outcomes": {"tf": 1.4142135623730951}, "src.data.write.find_poor": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1.4142135623730951}, "src.data.write.calculate_resilience": {"tf": 1.7320508075688772}, "src.model.initialize_model": {"tf": 1.4142135623730951}, "src.modules.households.duplicate_households": {"tf": 2.449489742783178}, "src.modules.households.calculate_average_productivity": {"tf": 1}, "src.modules.households.adjust_assets_and_expenditure": {"tf": 1}, "src.modules.households.calculate_pml": {"tf": 1}, "src.modules.households.select_district": {"tf": 1}, "src.modules.households.estimate_savings": {"tf": 1.4142135623730951}, "src.modules.households.set_vulnerability": {"tf": 1.4142135623730951}, "src.modules.households.calculate_exposure": {"tf": 1.4142135623730951}, "src.modules.households.determine_affected": {"tf": 2.23606797749979}, "src.modules.households.apply_individual_policy": {"tf": 1.4142135623730951}, "src.modules.optimize.run_optimization": {"tf": 1.7320508075688772}}, "df": 17}}}}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"src.data.prepare.decode_housing_attributes": {"tf": 1}, "src.data.prepare.add_housing_attributes": {"tf": 1}}, "df": 2}}}}}}, "a": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {"src.model.initialize_model": {"tf": 1}, "src.modules.households.determine_affected": {"tf": 1}}, "df": 2}}}}, "g": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {"src.data.read.get_asset_damage": {"tf": 1}, "src.data.write.find_poor": {"tf": 1}, "src.data.write.get_people_by_years_in_poverty": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}}, "df": 4}}, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"src.data.read.get_asset_damage": {"tf": 1}, "src.data.write.calculate_poverty_gap": {"tf": 1}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1}, "src.data.write.calculate_resilience": {"tf": 1}}, "df": 4}}}}}, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "p": {"docs": {"src.modules.households.apply_individual_policy": {"tf": 1.7320508075688772}}, "df": 1}}}}, "a": {"docs": {}, "df": 0, "p": {"docs": {"src.data.write.calculate_poverty_gap": {"tf": 1.7320508075688772}}, "df": 1}, "u": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "n": {"docs": {"src.modules.households.estimate_savings": {"tf": 1}}, "df": 1}}}}}}}}, "y": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {"src.data.write.get_people_by_years_in_poverty": {"tf": 1.4142135623730951}}, "df": 1, "s": {"docs": {"src.data.write.get_outcomes": {"tf": 1.4142135623730951}, "src.data.write.calculate_poverty_gap": {"tf": 1.4142135623730951}, "src.data.write.calculate_average_annual_consumption_loss": {"tf": 1.4142135623730951}, "src.modules.optimize.run_optimization": {"tf": 1.4142135623730951}}, "df": 4}}}}}, "k": {"docs": {"src.modules.households.calculate_average_productivity": {"tf": 1}}, "df": 1}}}}, "pipeline": ["trimmer"], "_isPrebuiltIndex": true}; - - // mirrored in build-search-index.js (part 1) - // Also split on html tags. this is a cheap heuristic, but good enough. - elasticlunr.tokenizer.setSeperator(/[\s\-.;&_'"=,()]+|<[^>]*>/); - - let searchIndex; - if (docs._isPrebuiltIndex) { - console.info("using precompiled search index"); - searchIndex = elasticlunr.Index.load(docs); - } else { - console.time("building search index"); - // mirrored in build-search-index.js (part 2) - searchIndex = elasticlunr(function () { - this.pipeline.remove(elasticlunr.stemmer); - this.pipeline.remove(elasticlunr.stopWordFilter); - this.addField("qualname"); - this.addField("fullname"); - this.addField("annotation"); - this.addField("default_value"); - this.addField("signature"); - this.addField("bases"); - this.addField("doc"); - this.setRef("fullname"); - }); - for (let doc of docs) { - searchIndex.addDoc(doc); - } - console.timeEnd("building search index"); - } - - return (term) => searchIndex.search(term, { - fields: { - qualname: {boost: 4}, - fullname: {boost: 2}, - annotation: {boost: 2}, - default_value: {boost: 2}, - signature: {boost: 2}, - bases: {boost: 2}, - doc: {boost: 1}, - }, - expand: true - }); -})(); \ No newline at end of file diff --git a/docs/src.html b/docs/src.html deleted file mode 100644 index 3383478..0000000 --- a/docs/src.html +++ /dev/null @@ -1,234 +0,0 @@ - - - - - - - src API documentation - - - - - - - - - -
-
-

-src

- - - - - -
-
- - \ No newline at end of file diff --git a/docs/src/data.html b/docs/src/data.html deleted file mode 100644 index 4a0147f..0000000 --- a/docs/src/data.html +++ /dev/null @@ -1,241 +0,0 @@ - - - - - - - src.data API documentation - - - - - - - - - -
-
-

-src.data

- - - - - -
-
- - \ No newline at end of file diff --git a/docs/src/data/analyse.html b/docs/src/data/analyse.html deleted file mode 100644 index d01c32f..0000000 --- a/docs/src/data/analyse.html +++ /dev/null @@ -1,876 +0,0 @@ - - - - - - - src.data.analyse API documentation - - - - - - - - - -
-
-

-src.data.analyse

- - - - - - -
  1# Prepare the results of the experiments for the analysis.
-  2
-  3import pandas as pd
-  4import numpy as np
-  5import ast
-  6import geopandas as gpd
-  7from ema_workbench import load_results
-  8
-  9
- 10def prepare_outcomes(results: tuple, add_policies: bool, add_uncertainties: bool) -> pd.DataFrame:
- 11    '''Convert outcomes dict into a data frame.
- 12
- 13    Args:
- 14        results (tuple): The results of the experiments in the EMA Workbench format.
- 15        add_policies (bool): Whether to add policy values to the data frame.
- 16        add_uncertainties (bool): Whether to add uncertainty values to the data frame.
- 17
- 18    Returns:
- 19        pd.DataFrame: Outcomes data frame.
- 20    '''
- 21    # * Note that we specify all outcomes in `get_outcomes` function in `write.py`
- 22    # * Here we just read them in the same sequence that they are written
- 23    outcome_names = [
- 24        'total_population',
- 25        'total_asset_loss',
- 26        'total_consumption_loss',
- 27        'event_damage',
- 28        'total_asset_stock',
- 29        'average_productivity',
- 30        'total_asset_in_survey',
- 31        'expected_loss_fraction',
- 32        'n_affected_people',
- 33        'annual_average_consumption',
- 34        'poverty_line_adjusted',
- 35        'pml',
- 36        'n_poor_initial',
- 37        'n_poor_affected',
- 38        'n_new_poor',
- 39        'initial_poverty_gap',
- 40        'new_poverty_gap',
- 41        'annual_average_consumption_loss',
- 42        'annual_average_consumption_loss_pct',
- 43        'r',
- 44        'recovery_rate',
- 45        'years_in_poverty',
- 46    ]
- 47
- 48    uncertainty_names = ['consumption_utility',
- 49                         'discount_rate',
- 50                         'income_and_expenditure_growth',
- 51                         'poverty_bias']
- 52
- 53    experiments, _ = results
- 54    experiments['random_seed'] = experiments['random_seed'].astype(int)
- 55    experiments['scenario'] = experiments['scenario'].astype(int)
- 56    if len(experiments['random_seed'].unique()) != experiments['scenario'].max() - experiments['scenario'].min() + 1:
- 57        # print(experiments['random_seed'].value_counts())
- 58        print('WARNING! Random seeds are not unique.')
- 59        # raise ValueError('Random seeds are not unique')
- 60
- 61    policy_names = ['my_policy']
- 62
- 63    if add_policies:
- 64        if add_uncertainties:
- 65            columns = ['scenario', 'policy', 'district', 'random_seed'] + \
- 66                policy_names + uncertainty_names + outcome_names
- 67        else:
- 68            columns = ['scenario', 'policy', 'district', 'random_seed'] + \
- 69                policy_names + outcome_names
- 70    else:
- 71        if add_uncertainties:
- 72            columns = ['scenario', 'policy', 'district', 'random_seed'] + \
- 73                uncertainty_names + outcome_names
- 74        else:
- 75            columns = ['scenario', 'policy', 'district',
- 76                       'random_seed'] + outcome_names
- 77
- 78    scenarios = results[0]['scenario'].values
- 79    n_scenarios = results[0]['scenario'].unique().size
- 80    policies = results[0]['policy'].values
- 81    random_seeds = results[0]['random_seed'].values
- 82    n_policies = results[0]['policy'].unique().size
- 83    n_districts = len(results[1].keys())
- 84
- 85    if add_policies:
- 86        policy_values = results[0][policy_names].values
- 87
- 88    if add_uncertainties:
- 89        uncertainty_values = results[0][uncertainty_names].values
- 90
- 91    n_columns = len(columns)
- 92    n_rows = n_scenarios * n_policies * n_districts
- 93    outcomes = np.zeros((n_rows, n_columns), dtype=object)
- 94
- 95    i = 0  # To iterate over rows = scenarios * policies * districts
- 96    for district, district_outcomes in results[1].items():
- 97        # To iterate over rows = scenarios * policies (experiments dataframe)
- 98        k = 0
- 99        # We reset k every time we change district
-100        for arr in district_outcomes:
-101            # The first 3 rows for scenario, policy and district
-102            outcomes[i, 0] = scenarios[k]
-103            outcomes[i, 1] = policies[k]
-104            outcomes[i, 2] = district
-105            outcomes[i, 3] = random_seeds[k]
-106
-107            if add_policies:
-108                if add_uncertainties:
-109                    # Add policy values
-110                    # From 4 to 4 + len(policy_names) policy values
-111                    for j, name in enumerate(policy_names):
-112                        outcomes[i, 4 + j] = policy_values[k, j]
-113
-114                    # Add uncertainty values
-115                    # From 4 + len(policy_names) to 4 + len(policy_names) + len(uncertainty_names) uncertainty values
-116                    for j, name in enumerate(uncertainty_names):
-117                        outcomes[i, 4 + len(policy_names) + j] = uncertainty_values[k, j]
-118
-119                    # Add outcomes
-120                    # From 4 + len(policy_names) + len(uncertainty_names) to 4 + len(policy_names) + len(uncertainty_names) + len(outcome_names) outcomes
-121                    l = 4 + len(policy_names) + len(uncertainty_names)
-122                    for v, name in zip(arr, outcome_names):
-123                        if name == 'years_in_poverty':
-124                            outcomes[i, l] = ast.literal_eval(v)
-125                        else:
-126                            outcomes[i, l] = v
-127                        l += 1
-128                else:
-129                    # Add policy values
-130                    # From 4 to 4 + len(policy_names) policy values
-131                    for j, name in enumerate(policy_names):
-132                        outcomes[i, 4 + j] = policy_values[k, j]
-133
-134                    # Add outcomes
-135                    # From 4 + len(policy_names) to 4 + len(policy_names) + len(outcome_names) outcomes
-136                    l = 4 + len(policy_names)
-137                    for v, name in zip(arr, outcome_names):
-138                        if name == 'years_in_poverty':
-139                            outcomes[i, l] = ast.literal_eval(v)
-140                        else:
-141                            outcomes[i, l] = v
-142                        l += 1
-143            else:
-144                if add_uncertainties:
-145                    # Add uncertainty values
-146                    # From 4 to 4 + len(uncertainty_names) uncertainty values
-147                    for j, name in enumerate(uncertainty_names):
-148                        outcomes[i, 4 + j] = uncertainty_values[k, j]
-149
-150                    # Add outcomes
-151                    # From 4 + len(uncertainty_names) to 4 + len(uncertainty_names) + len(outcome_names) outcomes
-152                    l = 4 + len(uncertainty_names)
-153                    for v, name in zip(arr, outcome_names):
-154                        if name == 'years_in_poverty':
-155                            outcomes[i, l] = ast.literal_eval(v)
-156                        else:
-157                            outcomes[i, l] = v
-158                        l += 1
-159                else:
-160                    # Add outcomes
-161                    # From 4 to 4 + len(outcome_names) outcomes
-162                    l = 4
-163                    for v, name in zip(arr, outcome_names):
-164                        if name == 'years_in_poverty':
-165                            outcomes[i, l] = ast.literal_eval(v)
-166                        else:
-167                            outcomes[i, l] = v
-168                        l += 1
-169            k += 1  # increase row index to get next experiment for the current district
-170            i += 1  # increase row index of the outcomes dataframe
-171    outcomes = pd.DataFrame(outcomes, columns=columns)
-172
-173    # Convert numeric columns to numeric
-174    if add_policies:
-175        numeric_columns = outcomes.columns[5:-1].tolist()
-176        outcomes[numeric_columns] = outcomes[numeric_columns].apply(
-177            pd.to_numeric)
-178    else:
-179        numeric_columns = outcomes.columns[4:-1].tolist()
-180        outcomes[numeric_columns] = outcomes[numeric_columns].apply(
-181            pd.to_numeric)
-182
-183    # Rename a district
-184    outcomes['district'].replace(
-185        {'AnseLaRayeCanaries': 'Anse-La-Raye & Canaries'}, inplace=True)
-186
-187    # Convert pct columns to percentage
-188    outcomes['annual_average_consumption_loss_pct'] = outcomes['annual_average_consumption_loss_pct'] * 100
-189    outcomes['initial_poverty_gap'] = outcomes['initial_poverty_gap'] * 100
-190    outcomes['new_poverty_gap'] = outcomes['new_poverty_gap'] * 100
-191
-192    # Calculate the percentage of new poor
-193    outcomes = outcomes.assign(n_new_poor_increase_pct=outcomes['n_new_poor'].div(
-194        outcomes['total_population']).multiply(100))
-195
-196    # outcomes['pct_poor_before'] = outcomes['n_poor_initial'].div(
-197    #     outcomes['total_population'])
-198    # outcomes['pct_poor_after'] = outcomes['n_new_poor'].add(
-199    #     outcomes['n_poor_initial']).div(outcomes['total_population'])
-200    # outcomes['pct_poor_increase'] = outcomes['pct_poor_after'].sub(
-201    #     outcomes['pct_poor_before'])
-202
-203    # Move years_in_poverty column to the end of the data frame
-204    outcomes = outcomes[[c for c in outcomes if c not in [
-205        'years_in_poverty']] + ['years_in_poverty']]
-206
-207    return outcomes
-208
-209
-210def get_spatial_outcomes(outcomes: pd.DataFrame, outcomes_of_interest: list = [], country: str = 'Saint Lucia', aggregation: str = 'mean') -> gpd.GeoDataFrame:
-211    # Load country shapefile
-212    country = 'Saint Lucia'
-213    gdf = gpd.read_file(
-214        f'../data/raw/shapefiles/{country}/gadm36_LCA_shp/gadm36_LCA_1.shp')
-215
-216    # Align district names with the ones in the outcomes
-217    gdf['NAME_1'].replace(
-218        {'Soufrière': 'Soufriere', 'Vieux Fort': 'Vieuxfort'}, inplace=True)
-219
-220    # Merge Anse-la-Raye and Canaries into a single geometry
-221    geometry = gdf[gdf['NAME_1'].isin(
-222        ['Anse-la-Raye', 'Canaries'])].unary_union
-223
-224    # Add it to the dataframe
-225    gdf.loc[len(gdf)] = [None, None, 'LCA.11_1', 'Anse-La-Raye & Canaries',
-226                         None, None, None, None, None, None, geometry]
-227    gdf = gdf[gdf['NAME_1'].isin(outcomes['district'].unique())]
-228
-229    if len(outcomes_of_interest) == 0:
-230        outcomes_of_interest = ['total_asset_loss',
-231                                'total_consumption_loss',
-232                                'n_affected_people',
-233                                'n_new_poor',
-234                                'new_poverty_gap',
-235                                'annual_average_consumption_loss',
-236                                'annual_average_consumption_loss_pct',
-237                                'n_new_poor_increase_pct',
-238                                'r']
-239
-240    # Aggregate outcomes
-241    if aggregation == 'mean':
-242        aggregated = outcomes[['district'] +
-243                              outcomes_of_interest].groupby('district').mean()
-244    elif aggregation == 'median':
-245        aggregated = outcomes[['district'] +
-246                              outcomes_of_interest].groupby('district').median()
-247    else:
-248        raise ValueError('Aggregation must be either mean or median')
-249
-250    # Merge with the shapefile
-251    gdf = pd.merge(gdf, aggregated, left_on='NAME_1', right_index=True)
-252    gdf.reset_index(inplace=True, drop=True)
-253    return gdf
-254
-255
-256def get_policy_effectiveness_tab(outcomes: pd.DataFrame) -> pd.DataFrame:
-257    policy_name_mapper = {'all+0': 'None',
-258                          'all+10': '10% to all',
-259                          'all+30': '30% to all',
-260                          'all+50': '50% to all',
-261                          'all+100': '100% to all',
-262                          'poor+0': 'None',
-263                          'poor+10': '10% to poor',
-264                          'poor+30': '30% to poor',
-265                          'poor+50': '50% to poor',
-266                          'poor+100': '100% to poor',
-267                          'poor_near_poor1.25+0': 'None',
-268                          'poor_near_poor1.25+10': '10% to poor and near poor (1.25)',
-269                          'poor_near_poor1.25+30': '30% to poor and near poor (1.25)',
-270                          'poor_near_poor1.25+50': '50% to poor and near poor (1.25)',
-271                          'poor_near_poor1.25+100': '100% to poor and near poor (1.25)',
-272                          'poor_near_poor2.0+0': 'None',
-273                          'poor_near_poor2.0+10': '10% to poor and near poor (2.0)',
-274                          'poor_near_poor2.0+30': '30% to poor and near poor (2.0)',
-275                          'poor_near_poor2.0+50': '50% to poor and near poor (2.0)',
-276                          'poor_near_poor2.0+100': '100% to poor and near poor (2.0)'}
-277    df = outcomes.copy()
-278    df['my_policy'] = df['my_policy'].replace(policy_name_mapper)
-279    df['my_policy'] = pd.Categorical(df['my_policy'], categories=['None', '10% to all', '30% to all', '50% to all', '100% to all',
-280                                                                  '10% to poor', '30% to poor', '50% to poor', '100% to poor',
-281                                                                  '10% to poor and near poor (1.25)', '30% to poor and near poor (1.25)', '50% to poor and near poor (1.25)', '100% to poor and near poor (1.25)',
-282                                                                  '10% to poor and near poor (2.0)', '30% to poor and near poor (2.0)', '50% to poor and near poor (2.0)', '100% to poor and near poor (2.0)'], ordered=True)
-283    df.rename(columns={'my_policy': 'Policy',
-284                       'district': 'District'}, inplace=True)
-285    df.rename(columns={'annual_average_consumption_loss_pct': 'Annual average consumption loss (%)',
-286                       'n_new_poor': 'Number of new poor'},
-287              inplace=True)
-288    df['Policy ID'] = df['Policy'].cat.codes
-289    return df
-
- - -
-
- -
- - def - prepare_outcomes( results: tuple, add_policies: bool, add_uncertainties: bool) -> pandas.core.frame.DataFrame: - - - -
- -
 11def prepare_outcomes(results: tuple, add_policies: bool, add_uncertainties: bool) -> pd.DataFrame:
- 12    '''Convert outcomes dict into a data frame.
- 13
- 14    Args:
- 15        results (tuple): The results of the experiments in the EMA Workbench format.
- 16        add_policies (bool): Whether to add policy values to the data frame.
- 17        add_uncertainties (bool): Whether to add uncertainty values to the data frame.
- 18
- 19    Returns:
- 20        pd.DataFrame: Outcomes data frame.
- 21    '''
- 22    # * Note that we specify all outcomes in `get_outcomes` function in `write.py`
- 23    # * Here we just read them in the same sequence that they are written
- 24    outcome_names = [
- 25        'total_population',
- 26        'total_asset_loss',
- 27        'total_consumption_loss',
- 28        'event_damage',
- 29        'total_asset_stock',
- 30        'average_productivity',
- 31        'total_asset_in_survey',
- 32        'expected_loss_fraction',
- 33        'n_affected_people',
- 34        'annual_average_consumption',
- 35        'poverty_line_adjusted',
- 36        'pml',
- 37        'n_poor_initial',
- 38        'n_poor_affected',
- 39        'n_new_poor',
- 40        'initial_poverty_gap',
- 41        'new_poverty_gap',
- 42        'annual_average_consumption_loss',
- 43        'annual_average_consumption_loss_pct',
- 44        'r',
- 45        'recovery_rate',
- 46        'years_in_poverty',
- 47    ]
- 48
- 49    uncertainty_names = ['consumption_utility',
- 50                         'discount_rate',
- 51                         'income_and_expenditure_growth',
- 52                         'poverty_bias']
- 53
- 54    experiments, _ = results
- 55    experiments['random_seed'] = experiments['random_seed'].astype(int)
- 56    experiments['scenario'] = experiments['scenario'].astype(int)
- 57    if len(experiments['random_seed'].unique()) != experiments['scenario'].max() - experiments['scenario'].min() + 1:
- 58        # print(experiments['random_seed'].value_counts())
- 59        print('WARNING! Random seeds are not unique.')
- 60        # raise ValueError('Random seeds are not unique')
- 61
- 62    policy_names = ['my_policy']
- 63
- 64    if add_policies:
- 65        if add_uncertainties:
- 66            columns = ['scenario', 'policy', 'district', 'random_seed'] + \
- 67                policy_names + uncertainty_names + outcome_names
- 68        else:
- 69            columns = ['scenario', 'policy', 'district', 'random_seed'] + \
- 70                policy_names + outcome_names
- 71    else:
- 72        if add_uncertainties:
- 73            columns = ['scenario', 'policy', 'district', 'random_seed'] + \
- 74                uncertainty_names + outcome_names
- 75        else:
- 76            columns = ['scenario', 'policy', 'district',
- 77                       'random_seed'] + outcome_names
- 78
- 79    scenarios = results[0]['scenario'].values
- 80    n_scenarios = results[0]['scenario'].unique().size
- 81    policies = results[0]['policy'].values
- 82    random_seeds = results[0]['random_seed'].values
- 83    n_policies = results[0]['policy'].unique().size
- 84    n_districts = len(results[1].keys())
- 85
- 86    if add_policies:
- 87        policy_values = results[0][policy_names].values
- 88
- 89    if add_uncertainties:
- 90        uncertainty_values = results[0][uncertainty_names].values
- 91
- 92    n_columns = len(columns)
- 93    n_rows = n_scenarios * n_policies * n_districts
- 94    outcomes = np.zeros((n_rows, n_columns), dtype=object)
- 95
- 96    i = 0  # To iterate over rows = scenarios * policies * districts
- 97    for district, district_outcomes in results[1].items():
- 98        # To iterate over rows = scenarios * policies (experiments dataframe)
- 99        k = 0
-100        # We reset k every time we change district
-101        for arr in district_outcomes:
-102            # The first 3 rows for scenario, policy and district
-103            outcomes[i, 0] = scenarios[k]
-104            outcomes[i, 1] = policies[k]
-105            outcomes[i, 2] = district
-106            outcomes[i, 3] = random_seeds[k]
-107
-108            if add_policies:
-109                if add_uncertainties:
-110                    # Add policy values
-111                    # From 4 to 4 + len(policy_names) policy values
-112                    for j, name in enumerate(policy_names):
-113                        outcomes[i, 4 + j] = policy_values[k, j]
-114
-115                    # Add uncertainty values
-116                    # From 4 + len(policy_names) to 4 + len(policy_names) + len(uncertainty_names) uncertainty values
-117                    for j, name in enumerate(uncertainty_names):
-118                        outcomes[i, 4 + len(policy_names) + j] = uncertainty_values[k, j]
-119
-120                    # Add outcomes
-121                    # From 4 + len(policy_names) + len(uncertainty_names) to 4 + len(policy_names) + len(uncertainty_names) + len(outcome_names) outcomes
-122                    l = 4 + len(policy_names) + len(uncertainty_names)
-123                    for v, name in zip(arr, outcome_names):
-124                        if name == 'years_in_poverty':
-125                            outcomes[i, l] = ast.literal_eval(v)
-126                        else:
-127                            outcomes[i, l] = v
-128                        l += 1
-129                else:
-130                    # Add policy values
-131                    # From 4 to 4 + len(policy_names) policy values
-132                    for j, name in enumerate(policy_names):
-133                        outcomes[i, 4 + j] = policy_values[k, j]
-134
-135                    # Add outcomes
-136                    # From 4 + len(policy_names) to 4 + len(policy_names) + len(outcome_names) outcomes
-137                    l = 4 + len(policy_names)
-138                    for v, name in zip(arr, outcome_names):
-139                        if name == 'years_in_poverty':
-140                            outcomes[i, l] = ast.literal_eval(v)
-141                        else:
-142                            outcomes[i, l] = v
-143                        l += 1
-144            else:
-145                if add_uncertainties:
-146                    # Add uncertainty values
-147                    # From 4 to 4 + len(uncertainty_names) uncertainty values
-148                    for j, name in enumerate(uncertainty_names):
-149                        outcomes[i, 4 + j] = uncertainty_values[k, j]
-150
-151                    # Add outcomes
-152                    # From 4 + len(uncertainty_names) to 4 + len(uncertainty_names) + len(outcome_names) outcomes
-153                    l = 4 + len(uncertainty_names)
-154                    for v, name in zip(arr, outcome_names):
-155                        if name == 'years_in_poverty':
-156                            outcomes[i, l] = ast.literal_eval(v)
-157                        else:
-158                            outcomes[i, l] = v
-159                        l += 1
-160                else:
-161                    # Add outcomes
-162                    # From 4 to 4 + len(outcome_names) outcomes
-163                    l = 4
-164                    for v, name in zip(arr, outcome_names):
-165                        if name == 'years_in_poverty':
-166                            outcomes[i, l] = ast.literal_eval(v)
-167                        else:
-168                            outcomes[i, l] = v
-169                        l += 1
-170            k += 1  # increase row index to get next experiment for the current district
-171            i += 1  # increase row index of the outcomes dataframe
-172    outcomes = pd.DataFrame(outcomes, columns=columns)
-173
-174    # Convert numeric columns to numeric
-175    if add_policies:
-176        numeric_columns = outcomes.columns[5:-1].tolist()
-177        outcomes[numeric_columns] = outcomes[numeric_columns].apply(
-178            pd.to_numeric)
-179    else:
-180        numeric_columns = outcomes.columns[4:-1].tolist()
-181        outcomes[numeric_columns] = outcomes[numeric_columns].apply(
-182            pd.to_numeric)
-183
-184    # Rename a district
-185    outcomes['district'].replace(
-186        {'AnseLaRayeCanaries': 'Anse-La-Raye & Canaries'}, inplace=True)
-187
-188    # Convert pct columns to percentage
-189    outcomes['annual_average_consumption_loss_pct'] = outcomes['annual_average_consumption_loss_pct'] * 100
-190    outcomes['initial_poverty_gap'] = outcomes['initial_poverty_gap'] * 100
-191    outcomes['new_poverty_gap'] = outcomes['new_poverty_gap'] * 100
-192
-193    # Calculate the percentage of new poor
-194    outcomes = outcomes.assign(n_new_poor_increase_pct=outcomes['n_new_poor'].div(
-195        outcomes['total_population']).multiply(100))
-196
-197    # outcomes['pct_poor_before'] = outcomes['n_poor_initial'].div(
-198    #     outcomes['total_population'])
-199    # outcomes['pct_poor_after'] = outcomes['n_new_poor'].add(
-200    #     outcomes['n_poor_initial']).div(outcomes['total_population'])
-201    # outcomes['pct_poor_increase'] = outcomes['pct_poor_after'].sub(
-202    #     outcomes['pct_poor_before'])
-203
-204    # Move years_in_poverty column to the end of the data frame
-205    outcomes = outcomes[[c for c in outcomes if c not in [
-206        'years_in_poverty']] + ['years_in_poverty']]
-207
-208    return outcomes
-
- - -

Convert outcomes dict into a data frame.

- -

Args: - results (tuple): The results of the experiments in the EMA Workbench format. - add_policies (bool): Whether to add policy values to the data frame. - add_uncertainties (bool): Whether to add uncertainty values to the data frame.

- -

Returns: - pd.DataFrame: Outcomes data frame.

-
- - -
-
- -
- - def - get_spatial_outcomes( outcomes: pandas.core.frame.DataFrame, outcomes_of_interest: list = [], country: str = 'Saint Lucia', aggregation: str = 'mean') -> geopandas.geodataframe.GeoDataFrame: - - - -
- -
211def get_spatial_outcomes(outcomes: pd.DataFrame, outcomes_of_interest: list = [], country: str = 'Saint Lucia', aggregation: str = 'mean') -> gpd.GeoDataFrame:
-212    # Load country shapefile
-213    country = 'Saint Lucia'
-214    gdf = gpd.read_file(
-215        f'../data/raw/shapefiles/{country}/gadm36_LCA_shp/gadm36_LCA_1.shp')
-216
-217    # Align district names with the ones in the outcomes
-218    gdf['NAME_1'].replace(
-219        {'Soufrière': 'Soufriere', 'Vieux Fort': 'Vieuxfort'}, inplace=True)
-220
-221    # Merge Anse-la-Raye and Canaries into a single geometry
-222    geometry = gdf[gdf['NAME_1'].isin(
-223        ['Anse-la-Raye', 'Canaries'])].unary_union
-224
-225    # Add it to the dataframe
-226    gdf.loc[len(gdf)] = [None, None, 'LCA.11_1', 'Anse-La-Raye & Canaries',
-227                         None, None, None, None, None, None, geometry]
-228    gdf = gdf[gdf['NAME_1'].isin(outcomes['district'].unique())]
-229
-230    if len(outcomes_of_interest) == 0:
-231        outcomes_of_interest = ['total_asset_loss',
-232                                'total_consumption_loss',
-233                                'n_affected_people',
-234                                'n_new_poor',
-235                                'new_poverty_gap',
-236                                'annual_average_consumption_loss',
-237                                'annual_average_consumption_loss_pct',
-238                                'n_new_poor_increase_pct',
-239                                'r']
-240
-241    # Aggregate outcomes
-242    if aggregation == 'mean':
-243        aggregated = outcomes[['district'] +
-244                              outcomes_of_interest].groupby('district').mean()
-245    elif aggregation == 'median':
-246        aggregated = outcomes[['district'] +
-247                              outcomes_of_interest].groupby('district').median()
-248    else:
-249        raise ValueError('Aggregation must be either mean or median')
-250
-251    # Merge with the shapefile
-252    gdf = pd.merge(gdf, aggregated, left_on='NAME_1', right_index=True)
-253    gdf.reset_index(inplace=True, drop=True)
-254    return gdf
-
- - - - -
-
- -
- - def - get_policy_effectiveness_tab(outcomes: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame: - - - -
- -
257def get_policy_effectiveness_tab(outcomes: pd.DataFrame) -> pd.DataFrame:
-258    policy_name_mapper = {'all+0': 'None',
-259                          'all+10': '10% to all',
-260                          'all+30': '30% to all',
-261                          'all+50': '50% to all',
-262                          'all+100': '100% to all',
-263                          'poor+0': 'None',
-264                          'poor+10': '10% to poor',
-265                          'poor+30': '30% to poor',
-266                          'poor+50': '50% to poor',
-267                          'poor+100': '100% to poor',
-268                          'poor_near_poor1.25+0': 'None',
-269                          'poor_near_poor1.25+10': '10% to poor and near poor (1.25)',
-270                          'poor_near_poor1.25+30': '30% to poor and near poor (1.25)',
-271                          'poor_near_poor1.25+50': '50% to poor and near poor (1.25)',
-272                          'poor_near_poor1.25+100': '100% to poor and near poor (1.25)',
-273                          'poor_near_poor2.0+0': 'None',
-274                          'poor_near_poor2.0+10': '10% to poor and near poor (2.0)',
-275                          'poor_near_poor2.0+30': '30% to poor and near poor (2.0)',
-276                          'poor_near_poor2.0+50': '50% to poor and near poor (2.0)',
-277                          'poor_near_poor2.0+100': '100% to poor and near poor (2.0)'}
-278    df = outcomes.copy()
-279    df['my_policy'] = df['my_policy'].replace(policy_name_mapper)
-280    df['my_policy'] = pd.Categorical(df['my_policy'], categories=['None', '10% to all', '30% to all', '50% to all', '100% to all',
-281                                                                  '10% to poor', '30% to poor', '50% to poor', '100% to poor',
-282                                                                  '10% to poor and near poor (1.25)', '30% to poor and near poor (1.25)', '50% to poor and near poor (1.25)', '100% to poor and near poor (1.25)',
-283                                                                  '10% to poor and near poor (2.0)', '30% to poor and near poor (2.0)', '50% to poor and near poor (2.0)', '100% to poor and near poor (2.0)'], ordered=True)
-284    df.rename(columns={'my_policy': 'Policy',
-285                       'district': 'District'}, inplace=True)
-286    df.rename(columns={'annual_average_consumption_loss_pct': 'Annual average consumption loss (%)',
-287                       'n_new_poor': 'Number of new poor'},
-288              inplace=True)
-289    df['Policy ID'] = df['Policy'].cat.codes
-290    return df
-
- - - - -
-
- - \ No newline at end of file diff --git a/docs/src/data/prepare.html b/docs/src/data/prepare.html deleted file mode 100644 index bb92eb8..0000000 --- a/docs/src/data/prepare.html +++ /dev/null @@ -1,1984 +0,0 @@ - - - - - - - src.data.prepare API documentation - - - - - - - - - -
-
-

-src.data.prepare

- - - - - - -
  1from sklearn.linear_model import LinearRegression
-  2import numpy.polynomial.polynomial as poly
-  3from sklearn.preprocessing import FunctionTransformer
-  4import pandas as pd
-  5import matplotlib.pyplot as plt
-  6import numpy as np
-  7
-  8
-  9# ---------------------------------------------------------------------------- #
- 10#                         Asset damage data preparation                        #
- 11# ---------------------------------------------------------------------------- #
- 12
- 13def prepare_asset_damage(country: str, scale: str, return_period: int = 100) -> None:
- 14    '''Prepare district-level asset damage data and save it into a XLSX file.'''
- 15    if country == 'Saint Lucia':
- 16        if scale == 'district':
- 17            # Load raw data
- 18            df = pd.read_excel(
- 19                '../../data/raw/asset_damage/Saint Lucia/St Lucia 2015 exposure summary.xlsx', sheet_name='total by parish', skiprows=1)
- 20            # Remove redundant columns
- 21            df.drop(df.columns[0], axis=1, inplace=True)
- 22            # Even though the data is by `parish``, let's call the corresponding column `district``
- 23            df.rename(columns={'Unnamed: 1': 'district'}, inplace=True)
- 24            # !: Check whether rp is = 100 given the data
- 25            df['rp'] = 100
- 26            df.rename(
- 27                columns={'Combined Total': 'exposed_value'}, inplace=True)
- 28
- 29            # !: Replace with the real data
- 30            # Let's assume that PML is equal to AAL % by district * by the PML for the whole country
- 31            # These values are from PML Results 19022016 SaintLucia FinalSummary2.xlsx
- 32            total_pml = {10: 351733.75,  # 3,517,337.50
- 33                         50: 23523224.51,  # 2,352,322,451.00
- 34                         100: 59802419.04,  # 5,980,241,904.00
- 35                         250: 147799213.30,  # 14,779,921,330.00
- 36                         500: 248310895.20,  # 24,831,089,520.00
- 37                         1000: 377593847.00}  # 37,759,384,700.00
- 38            aal = pd.read_excel(
- 39                '../../data/processed/asset_damage/Saint Lucia/AAL Results 19022016 StLucia FinalSummary2 adjusted.xlsx', sheet_name='AAL St. Lucia Province')
- 40            aal.set_index('Name', inplace=True)
- 41            aal = aal[['AAL as % of Total AAL']]
- 42            aal.columns = ['pml']
- 43            aal = aal[aal.index.notnull()]
- 44            pml = aal.multiply(total_pml[return_period])
- 45            df = pd.merge(df, pml, left_on='district', right_index=True)
- 46            df.to_excel(
- 47                f'../../data/processed/asset_damage/{country}/{country}.xlsx', index=False)
- 48        else:
- 49            raise ValueError(
- 50                'Only `district` scale is supported for Saint Lucia.')
- 51    else:
- 52        raise ValueError('Only `Saint Lucia` is supported.')
- 53
- 54
- 55# ---------------------------------------------------------------------------- #
- 56#                          Household data preparation                          #
- 57# ---------------------------------------------------------------------------- #
- 58
- 59# Prepare Saint Lucia data as an input into simulation model.
- 60
- 61# There are 5 inputs into the simulation model:
- 62# * 14 parameters in `parameters.xlsx` (incl. constants, uncertainties, simulation, scenario and policy parameters);
- 63# * 3 assest damage parameters from the assest damage file (e.g. `Saint Lucia.xlsx`);
- 64# * N model's algorithms parameters in `algorithms_parameters.xlsx`;
- 65# * Average capital productivity (computed based on some values of household survey data);
- 66# * A household survey (e.g. `saint_lucia.csv`).
- 67
- 68# Here we going to prepare the latest - the household survey.
- 69# Each row of the data is a household and each column is an attribute.
- 70# We need to prepare it to match the format of the simulation model.
- 71# Here is the list of columns that we need to have:
- 72
- 73# * `hhid` - household id,
- 74# * `popwgt` - float: [0,inf] (?: Maybe put a cap on this?),
- 75# * `hhsize` - household size,
- 76# * `hhweight` - household weight,
- 77# * `state` - state, str
- 78# * `aeexp`- float: [0,inf] (?: Maybe put a cap on this?)
- 79# * `hhexp` - float: [0,inf] (?: Maybe put a cap on this?)
- 80# * `is_poor` - boolean: False or True,
- 81# * `aeinc` - float: [0,inf] (?: Maybe put a cap on this?)
- 82# * `aesoc` - float: [0,inf] (?: Maybe put a cap on this?)
- 83# * `k_house_ae` - float: [0,inf (?: Maybe put a cap on this?)]
- 84# * `v_init` - initial vulnerability, float: [0,1]
- 85# * `inc_safetynet_frac` - float: [0,1]
- 86# * `delta_tax_safety` - float
- 87# * `houses_owned` - int: [0,inf] (?: Maybe put a cap on this?)
- 88# * `own_rent` - string: "own" or "rent"
- 89# * `aeexp_house` - float
- 90# * `percentile` - int: [1,100]
- 91# * `decile` - int: [1,10]
- 92# * `quintile` - int: [1,5]
- 93
- 94# Here is the list of what we have at the very end.
- 95# V - we have it, X - we don't have it, ! - we must have it, ? - we don't know what it is.
- 96# hhid V
- 97# popwgt V
- 98# hhsize -> hhsize_ae ?
- 99# hhweight -> hhwgt ?
-100# state X
-101# aaexp V
-102# hhexp X
-103# ispoor V
-104# aeinc V
-105# aesoc V
-106# k_house_ae V
-107# v_init V
-108# inc_safetynet_frac X
-109# delta_tax_safety X !
-110# houses_owned X
-111# own_rent V
-112# aaexp_house V
-113# percentile X
-114# decile V
-115# quintile V
-116
-117def prepare_household_survey(country: str) -> None:
-118    '''Prepare data for the simulation model.
-119
-120    Parameters
-121    ----------
-122    country : str
-123
-124    Raises
-125    ------
-126    ValueError
-127        If the country is not supported.
-128
-129    '''
-130    # Data preprocessing description:
-131    # 0. Load raw data
-132    # 1. Change `parentid1` to `hhid`
-133    # 2. Add `is_rural` column. 0 if `urban` is URBAN, if `urban` is RURAL then 1.
-134    # 3. Rename `tvalassets` to `kreported`.
-135    # 4. Rename a set of columns.
-136    # 5. Calculate some household attributes. Need to figure out what they mean.
-137    # 6. Add `financial_inst` column which has info on bank or credit union.
-138    # 7. Decode income attributes.
-139    # 8. Calculate some income attributes. Need to figure out what they mean.
-140    # 9. Decode housing attributes.
-141    # 10. Add new housing attributes. Need to figure out what they mean.
-142    # 11. Add new insurance attributes. Need to figure out what they mean.
-143    # 12. Calculate some housing attributes. Need to figure out what they mean.
-144    # 13. Calculate povery attributes. Need to figure out what they mean.
-145    # 14. Assign vulnerability by type of house.
-146    # 15. Subset columns of interest.
-147    # 16. Check which columns do we have and which do we miss.
-148    # 17. Add missing columns.
-149    # 18. Merge districts.
-150    # 19. Save data.
-151
-152    if country != 'Saint Lucia':
-153        raise ValueError('Currently only Saint Lucia is supported.')
-154
-155    print_statistics = True
-156    data = load_data(print_statistics=print_statistics)
-157
-158    # * Note that the sequence of the functions is important
-159    result = (start_pipeline(data)
-160              .pipe(add_is_rural_column, print_statistics=print_statistics)
-161              .pipe(rename_assets_column)
-162              .pipe(rename_other_columns)
-163              .pipe(calculate_household_attributes)
-164              .pipe(get_bank_or_credit_union)
-165              .pipe(decode_demographic_attributes)
-166              .pipe(decode_income_attributes)
-167              .pipe(calculate_income_attributes)
-168              .pipe(decode_housing_attributes)
-169              .pipe(add_housing_attributes)
-170              .pipe(add_insurance_attributes)
-171              .pipe(calculate_housing_attributes)
-172              .pipe(calculate_poverty_attributes)
-173              .pipe(assign_housing_vulnerability)
-174              .pipe(subset_columns)
-175              .pipe(check_columns)
-176              .pipe(add_missing_columns, missing_columns=['delta_tax_safety'])
-177              .pipe(merge_districts)
-178              )
-179
-180    result.to_csv(
-181        f'../../data/processed/household_survey/{country}/{country}.csv ')
-182
-183
-184def load_data(print_statistics: bool = True) -> pd.DataFrame:
-185    """Load the raw data."""
-186    # Read the raw data
-187    # * This dataset is the combined version of the household and persons files on parentid1
-188    data = pd.read_csv(
-189        '../../data/raw/household_survey/Saint Lucia/SLCHBS2016PersonV12_Housing.csv', low_memory=False)
-190    data.rename(columns={'parentid1': 'hhid'}, inplace=True)
-191
-192    # Set the index to the household id
-193    data.set_index('hhid', inplace=True)
-194
-195    if print_statistics:
-196        print('Number of rows: ', data.shape[0])
-197        print('Number of columns: ', data.shape[1])
-198        print('Number of duplicates based on index: ',
-199              data.index.duplicated().sum())
-200
-201    return data
-202
-203
-204def start_pipeline(data: pd.DataFrame):
-205    """Start the data processing pipeline."""
-206    return data.copy()
-207
-208
-209def add_is_rural_column(data: pd.DataFrame, print_statistics: bool = True) -> pd.DataFrame:
-210    """Create a new column that indicates whether the household is rural or not."""
-211    data['is_rural'] = 0
-212    data.loc[data['urban'] == 'RURAL', 'is_rural'] = 1
-213    if print_statistics:
-214        print('Number of rural households: ', data['is_rural'].sum())
-215        print('Number of urban households: ',
-216              data.shape[0] - data['is_rural'].sum())
-217    return data
-218
-219
-220def rename_assets_column(data: pd.DataFrame) -> pd.DataFrame:
-221    """Rename the assets column to be more descriptive."""
-222    data.rename(columns={'tvalassets': 'kreported'}, inplace=True)
-223    return data
-224
-225
-226def rename_other_columns(data: pd.DataFrame) -> pd.DataFrame:
-227    '''Rename a set of columns. See function for details.'''
-228    data = data.rename(columns={'DISTRICT_NAME': 'district',
-229                                'persons': 'hhsize',
-230                                'totexp.x': 'hhexp',
-231                                'pcexpae.x': 'aeexp',
-232                                'hincome': 'hhinc',
-233                                'WT.x': 'pwgt',
-234                                'food.x': 'hhexp_food'})
-235    return data
-236
-237# ? What does it mean?
-238# hhwgt = WT.y from full_df with group by parentid1 or WT from House data
-239# pwgt = WT.x from full_df or WT from Person data
-240
-241# hhsize = number of people in a household
-242
-243# ? What does it mean
-244# ! Data doesn't have this column
-245# pcinc = annual consumption per head
-246
-247# ! That's quite an assumption
-248# hhinc = pcinc * hhsize
-249
-250# p4_23 is monthly income
-251# p4_1 is months worked
-252# pincome is monthly income
-253# pincome_oth is annual other income
-254# aincome is pincome * p4_1 + pincome_oth
-255
-256# ! Data doesn't have this column
-257# hincome is the sum of aincome
-258
-259
-260def calculate_household_attributes(data: pd.DataFrame) -> pd.DataFrame:
-261    lower = 1
-262    fill_na = 1
-263    data['popwgt'] = data.groupby('hhid')['pwgt'].transform('sum')
-264    data['hhwgt'] = data['popwgt'] / data['hhsize']
-265    data['hhsize_ae'] = (data['hhexp'] / data['aeexp']
-266                         ).fillna(fill_na).clip(lower=lower)
-267    data['aewgt'] = data['pwgt']*(data['hhsize_ae'] / data['hhsize'])
-268    return data
-269
-270
-271def get_bank_or_credit_union(data: pd.DataFrame) -> pd.DataFrame:
-272    data['financial_inst'] = 0
-273    data.loc[data['p1_11__3'] == 'yes - bank', 'financial_inst'] = 1
-274    data.loc[data['p1_11__2'] == 'yes - bank', 'financial_inst'] = 1
-275    data.loc[data['p1_11__2'] == 'yes - credit union', 'financial_inst'] = 1
-276    data.loc[data['p1_11__1'] == 'yes - bank', 'financial_inst'] = 1
-277    data.loc[data['p1_11__1'] == 'yes - credit union', 'financial_inst'] = 1
-278    return data
-279
-280
-281def decode_demographic_attributes(data: pd.DataFrame) -> pd.DataFrame:
-282    '''Decode the demographic attributes.'''
-283    data = data.rename(columns={'p1_1': 'role',
-284                                'p1_2': 'sex',
-285                                'p1_3': 'age',
-286                                'p1_4': 'race',
-287                                'p1_5': 'religion',
-288                                'p1_6': 'marital_status',
-289                                'p1_7': 'cellphone'})
-290    return data
-291
-292
-293def decode_income_attributes(data: pd.DataFrame) -> pd.DataFrame:
-294    '''Decode the income-related attributes.'''
-295    data = data.rename(columns={
-296        # 'p1_11':'bank_account',
-297        'p4_1': 'months_worked',
-298        'inc2231002': 'other_entrepreneurial',
-299        'inc2331001': 'remits_intl',
-300        'inc2341001': 'rental_income',
-301        'inc2351001': 'dividends',  # other
-302        'inc2361001': 'interest',  # other
-303        'inc2361002': 'other_investment_income',  # other
-304        'inc2371001': 'pension_public',  # UCT
-305        'inc2371002': 'pension_private_LCA',  # pension private
-306        'inc2371003': 'pension_private_int',  # pension private
-307        'inc2371004': 'social_security',  # UCT
-308        # 'inc2381001':'annuity', # other
-309        'inc2381002': 'public_assistance',  # CCT
-310        'inc2381003': 'child_support',  # other
-311        'inc2391001': 'scholarships',  # other
-312        'inc2391002': 'financial_aid',  # other
-313        'inc2391003': 'alimony',  # other
-314        'inc2391099': 'mystery'
-315    })
-316    return data
-317
-318
-319def calculate_income_attributes(data: pd.DataFrame) -> pd.DataFrame:
-320    data['remits_dom'] = 0
-321
-322    # Primary job income
-323    data['primary_income'] = data[['months_worked', 'pincome']].prod(axis=1)
-324
-325    # Secondary income
-326    data['cct'] = data['public_assistance'].copy()
-327    data['uct'] = data[['pension_public', 'social_security']].sum(axis=1)
-328    data['remits'] = data[['remits_intl', 'remits_dom']].sum(axis=1)
-329    data['other_sources'] = data[['dividends', 'interest', 'child_support', 'alimony', 'financial_aid',
-330                                  'scholarships', 'pension_private_LCA', 'pension_private_int', 'other_investment_income', 'mystery']].sum(axis=1)
-331    data['secondary_income'] = data[['other_entrepreneurial', 'cct',
-332                                     'uct', 'remits', 'rental_income', 'other_sources']].sum(axis=1)
-333
-334    # Total income
-335    data['total_income'] = data[[
-336        'primary_income', 'secondary_income']].sum(axis=1)
-337
-338    return data
-339
-340
-341def decode_housing_attributes(data: pd.DataFrame) -> pd.DataFrame:
-342    '''Decode the housing-related attributes.'''
-343    data = data.rename(columns={'s2': 'own_rent',
-344                                # owner-occupied
-345                                'c1900105': 'mortgage_monthly',
-346                                'c1900104': 'domicile_value',
-347                                'c1900101': 'new_home_purchase_price',
-348                                'c1900103': 'new_home_mortgage_monthly',
-349                                'c1800501': 'rental_income_furnished',
-350                                'c1800502': 'rental_income_unfurnished',
-351                                'c1800503': 'rental_income_business',
-352                                'c0421101': 'imputed_rent_monthly',
-353                                'c1252101': 'insurance_premium',
-354                                # rental
-355                                'c0411100': 'actual_rent_monthly',
-356                                # condition & construction
-357                                's9q1': 'had_shock',
-358                                'h1_2': 'walls',
-359                                'h1_3': 'roof',
-360                                'h1_13': 'yr_house_built'})
-361    return data
-362
-363
-364def add_housing_attributes(data: pd.DataFrame) -> pd.DataFrame:
-365    '''Introduce new housing attributes.'''
-366    # ! An assumption
-367    data['own_rent'] = data['own_rent'].replace({'own or rent free': 'own'})
-368    data['home_insured'] = data['insurance_premium'] > 0
-369    return data
-370
-371
-372def add_insurance_attributes(data: pd.DataFrame) -> pd.DataFrame:
-373    # ? What does it mean?
-374    # National insurance corporation (unemployment)
-375    data['NIC_enrolled'] = data['p4_18'].isin(['employer', 'self-employed'])
-376    data['NIC_recipient'] = data['p4_17'].isin(['yes, from the nic'])
-377
-378    # Health insurance
-379    data = data.rename(columns={'p2_5': 'health_insurance'})
-380    return data
-381
-382
-383def calculate_housing_attributes(data: pd.DataFrame) -> pd.DataFrame:
-384    # Predict domicile value for hh that rent
-385    data['k_house'] = data['domicile_value'].copy().fillna(0)
-386    # total rent per capita per year
-387    data['hhexp_house'] = 12 * data['imputed_rent_monthly'].copy()
-388    data['hhexp_house'].update(12 * data['actual_rent_monthly'])
-389    data['hhexp_house'] = data['hhexp_house'].clip(lower=0).fillna(0)
-390
-391    # Urban population
-392    training_slc = (data['domicile_value'] > 10 * data['imputed_rent_monthly']
-393                    ) & (data['domicile_value'] < 1E6) & (data['is_rural'] == 0)
-394    urban_predictor = linear_regression(data.loc[training_slc].dropna(
-395        subset=['domicile_value', 'imputed_rent_monthly']), 'imputed_rent_monthly', 'domicile_value', return_model=True)
-396
-397    prediction_slc = (data['own_rent'] == 'rent') & (
-398        data['is_rural'] == 0) & (data['actual_rent_monthly'] is not None)
-399    data.loc[prediction_slc, 'k_house'] = urban_predictor.predict(
-400        data.loc[prediction_slc, 'actual_rent_monthly'].values.reshape(-1, 1))
-401
-402    # Rural population
-403    training_slc = (data['domicile_value'] > 10 * data['imputed_rent_monthly']
-404                    ) & (data['domicile_value'] < 1E6) & (data['is_rural'] == 1)
-405    rural_predictor = linear_regression(data.loc[training_slc].dropna(
-406        subset=['domicile_value', 'imputed_rent_monthly']), 'imputed_rent_monthly', 'domicile_value', return_model=True)
-407
-408    prediction_slc = (data['own_rent'] == 'rent') & (
-409        data['is_rural'] == 1) & (data['actual_rent_monthly'] is not None)
-410    data.loc[prediction_slc, 'k_house'] = rural_predictor.predict(
-411        data.loc[prediction_slc, 'actual_rent_monthly'].values.reshape(-1, 1))
-412
-413    # Correct for the households that reported unreasonably low domicile value
-414    prediction_slc = (data['own_rent'] == 'own') & (data['is_rural'] == 0) & (
-415        data['k_house'] <= 10*data['imputed_rent_monthly'])
-416    data.loc[prediction_slc, 'k_house'] = urban_predictor.predict(
-417        data.loc[prediction_slc, 'imputed_rent_monthly'].values.reshape(-1, 1))
-418
-419    prediction_slc = (data['own_rent'] == 'own') & (data['is_rural'] == 1) & (
-420        data['k_house'] <= 10*data['imputed_rent_monthly'])
-421    data.loc[prediction_slc, 'k_house'] = rural_predictor.predict(
-422        data.loc[prediction_slc, 'imputed_rent_monthly'].values.reshape(-1, 1))
-423
-424    data['k_house'] = data['k_house'].clip(lower=0).fillna(0)
-425
-426    return data
-427
-428
-429def calculate_poverty_attributes(data: pd.DataFrame) -> pd.DataFrame:
-430    # Data has four poverty levels:
-431    # (1) $1.90/day = 1345 (ipline190 in dataset)
-432    # (2) $4.00/day = 2890,
-433    # (3) indigence line based on food is 2123 (indline in dataset),
-434    # (4) relative poverty line for food and non-food items is 6443 (povline in dataset)
-435    # Saint Lucia's poverty line is 1.90 * 365 = $689.7 US Dollars per year,
-436    # discounting using the PPP exchange rate of 1.952
-437    # the international poverty line for Saint Lucia is 1.90 * 1.952 * 365 = EC $1, 354 (0.7% in doc have 0.66%)
-438    # US $4 a day PPP is 4 * 1.952 * 365 = EC $2,890 (4.4% in doc have 4%)
-439    # poverty highest in Dennery and Vieux-Fort
-440
-441    # Domestic lines
-442    # !: Do not hardcode these values
-443    # !: Check with Bramka
-444    data['pov_line'] = 6443
-445    data['vul_line'] = 8053.75
-446    data['is_poor'] = data['aeexp'] <= data['pov_line']
-447
-448    # Load PMT data
-449    # ? What is PMT?
-450    # TODO: Merge PMT with data
-451    # !: I don't have this dataset
-452    # pmt = pd.read_stata(inputs + 'SLNET_16April.dta')
-453
-454    # Consumption quintiles and deciles
-455    data = data.rename(columns={'quintile.y': 'quintile',
-456                                'decile.y': 'decile'})
-457
-458    # print('income = {} mil. EC$'.format(round(1E-6*dfout[['aewgt','aeinc']].prod(axis=1).sum(),1)))
-459    # print('       = {} EC$/cap'.format(round(dfout[['aewgt','aeinc']].prod(axis=1).sum()/dfout['pwgt'].sum(),1)))
-460
-461    # Individual income
-462    for _i in ['primary_income_ae', 'cct_ae', 'uct_ae', 'remits_ae', 'other_sources_ae']:
-463        data[_i] = data.groupby('hhid')[_i.replace('_ae', '')].transform(
-464            'sum').multiply(1/data['hhsize_ae'])
-465
-466    # Household consumption
-467    data['imputed_rent_monthly'] = data['imputed_rent_monthly'].fillna(0)
-468    data['housing_service_ae'] = data.groupby(
-469        'hhid')['imputed_rent_monthly'].transform('mean').multiply(12./data['hhsize_ae'])
-470    data['aeexp_house'] = data['hhexp_house'] / data['hhsize_ae']
-471    data['aeexp_food'] = data['hhexp_food'] / data['hhsize_ae']
-472    data['aeexp_other'] = data['aeexp'] - \
-473        data[['aeexp_house', 'aeexp_food']].sum(axis=1)
-474
-475    # sum to households
-476    data['aesoc'] = data['cct_ae'].copy()
-477    data['aeinc'] = data[['primary_income_ae', 'cct_ae', 'uct_ae',
-478                          'remits_ae', 'other_sources_ae', 'housing_service_ae']].sum(axis=1)
-479
-480    data['k_house_ae'] = data['k_house']/data['hhsize_ae']
-481    return data
-482
-483
-484def assign_housing_vulnerability(data: pd.DataFrame) -> pd.DataFrame:
-485    # !: This is quite random!
-486    # TODO: Do not hard code parameters here. Move them to a config file.
-487    data['walls'].fillna('others', inplace=True)
-488    data['v_walls'] = 0.1
-489    data.loc[data['walls'].isin(
-490        ['brick/blocks', 'concrete/concrete blocks']), 'v_walls'] = 0.35
-491    data.loc[data['walls'].isin(['wood & concrete']), 'v_walls'] = 0.5
-492    data.loc[data['walls'].isin(['wood/timber']), 'v_walls'] = 0.6
-493    data.loc[data['walls'].isin(['plywood']), 'v_walls'] = 0.7
-494    data.loc[data['walls'].isin(
-495        ['makeshift', 'others', 'other/dont know']), 'v_walls'] = 0.8
-496    data['roof'].fillna('others', inplace=True)
-497    data['v_roof'] = 0.75
-498    data.loc[data['roof'].isin(
-499        ['sheet metal (galvanize, galvalume)']), 'v_roof'] = 0.5
-500    data['v_init'] = 0.5 * data['v_roof'] + 0.5 * data['v_walls']
-501    return data
-502
-503
-504def subset_columns(data: pd.DataFrame) -> pd.DataFrame:
-505    '''Subset columns of interest.'''
-506    columns_of_interest = ['district',
-507                           'is_rural',
-508                           'hhwgt',
-509                           'hhsize_ae',
-510                           'popwgt',
-511                           'aeinc',
-512                           'aesoc',
-513                           'k_house_ae',
-514                           'own_rent',
-515                           'aeexp',
-516                           'aeexp_house',
-517                           'aeexp_food',
-518                           'aeexp_other',
-519                           'is_poor',
-520                           'v_init',
-521                           'v_walls',
-522                           'v_roof',
-523                           'walls',
-524                           'roof',
-525                           'quintile',
-526                           'decile',
-527                           'primary_income_ae',
-528                           'cct_ae',
-529                           'uct_ae', 'remits_ae',
-530                           'other_sources_ae',
-531                           'housing_service_ae',
-532                           'pov_line',
-533                           'vul_line']
-534    result = data.loc[~data.index.duplicated(
-535        keep='first'), columns_of_interest]
-536    result['aewgt'] = data['aewgt'].groupby(level='hhid').sum()
-537
-538    # Keep characteristics of head of household
-539    household_head_columns = ['sex',
-540                              'age',
-541                              'race',
-542                              'religion',
-543                              'marital_status',
-544                              'cellphone',
-545                              'health_insurance',
-546                              'home_insured']  # ,'bank_account']
-547    result[household_head_columns] = data.loc[data['role']
-548                                              == 'head', household_head_columns]
-549    return result
-550
-551
-552def check_columns(data: pd.DataFrame) -> pd.DataFrame:
-553
-554    # These are the columns of the India case
-555    used_columns = [
-556        # 'hhid',
-557        'aeexp',
-558        'is_poor',
-559        'aeinc',
-560        'aesoc',
-561        'k_house_ae',
-562        'v_init',
-563        # 'delta_tax_safety',
-564        'own_rent',
-565        'aeexp_house',
-566    ]
-567
-568    extra_columns = [
-569        'popwgt',  # used, but seems to be not essential, just for writing
-570    ]
-571
-572    not_used_columns = [
-573        'hhsize',
-574        'hhweight',
-575        'state',
-576        'hhexp',
-577        'inc_safetynet_frac',
-578        'houses_owned',
-579        'percentile',
-580        'decile',
-581        'quintile'
-582    ]
-583
-584    # Check whether the new data has  all columns that we need
-585    missing_columns = []
-586
-587    for column in used_columns:
-588        if column not in data.columns:
-589            missing_columns.append(column)
-590
-591    # Check what columns we have besides the ones we need from used_columns
-592    extra_columns = [
-593        column for column in data.columns if column not in used_columns]
-594    print(f'We have the following extra columns: {extra_columns}')
-595
-596    if len(missing_columns) > 0:
-597        raise ValueError(f'Missing columns: {missing_columns}')
-598
-599    return data
-600
-601
-602def add_missing_columns(data: pd.DataFrame, missing_columns: list) -> pd.DataFrame:
-603    '''Manually add missing columns to the data.'''
-604    for column in missing_columns:
-605        data[column] = 0
-606    return data
-607
-608
-609def merge_districts(data: pd.DataFrame) -> pd.DataFrame:
-610    # !: We merged two districts into one
-611    data['district_original'] = data['district']
-612    data.replace({'district': {'Castries Sub-Urban': 'Castries',
-613                               'Castries City': 'Castries'}}, inplace=True)
-614    return data
-615
-616
-617# Some regression-alike functions
-618# * I did not test them
-619np.random.seed(123)
-620
-621
-622def exponential_regression(data: pd.DataFrame, X_column: str, y_column: str, weights: np.array = None, return_model: bool = False) -> tuple[np.array, float]:
-623    X = data[X_column].values.reshape(-1, 1)
-624    y = data[y_column].values.reshape(-1, 1)
-625    transformer = FunctionTransformer(np.log, validate=True)
-626    y_transformed = transformer.fit_transform(y)
-627
-628    lr = LinearRegression()
-629    lr.fit(X, y_transformed, sample_weight=weights)
-630    y_pred = lr.predict(X)
-631    coef = lr.coef_
-632    r2 = lr.score(X, y_transformed, sample_weight=weights)
-633    if return_model:
-634        return lr
-635    else:
-636        return y_pred, coef, r2
-637
-638
-639def polynomial_regression(data: pd.DataFrame,
-640                          X_column: str,
-641                          y_column: str,
-642                          power: int,
-643                          weights: np.array = None,
-644                          X_new: np.array = None,
-645                          X_start: int = 0,
-646                          X_end: int = 40,
-647                          X_num: int = 100):
-648    # !: Weights are not used in this function
-649    X = data[X_column].squeeze().T
-650    y = data[y_column].squeeze().T
-651    coef = poly.polyfit(X, y, power)
-652
-653    if X_new is None:
-654        X_new = np.linspace(X_start, X_end, num=X_num)
-655
-656    f = poly.polyval(X_new, coef)
-657
-658    return X_new, f
-659
-660
-661def linear_regression(data: pd.DataFrame, X_column: str, y_column: str, weights: np.array = None, return_model: bool = False) -> tuple[np.array, float, float]:
-662    '''Do a linear regression on the data and return the predicted values, the coefficient and the r2 score.'''
-663    X = data[X_column].values.reshape(-1, 1)
-664    y = data[y_column].values.reshape(-1, 1)
-665    lr = LinearRegression()
-666    lr.fit(X, y, sample_weight=weights)
-667    y_pred = lr.predict(X)
-668    coef = lr.coef_
-669    r2 = lr.score(X, y, sample_weight=weights)
-670    if return_model:
-671        return lr
-672    else:
-673        return y_pred, coef, r2
-674
-675# ---------------------------------------------------------------------------- #
-676#                        Run data preparation pipelines                        #
-677# ---------------------------------------------------------------------------- #
-678
-679
-680# prepare_household_survey(country='Saint Lucia')
-681# prepare_asset_damage(country='Saint Lucia',
-682#                      scale='district', return_period=100)
-
- - -
-
- -
- - def - prepare_asset_damage(country: str, scale: str, return_period: int = 100) -> None: - - - -
- -
14def prepare_asset_damage(country: str, scale: str, return_period: int = 100) -> None:
-15    '''Prepare district-level asset damage data and save it into a XLSX file.'''
-16    if country == 'Saint Lucia':
-17        if scale == 'district':
-18            # Load raw data
-19            df = pd.read_excel(
-20                '../../data/raw/asset_damage/Saint Lucia/St Lucia 2015 exposure summary.xlsx', sheet_name='total by parish', skiprows=1)
-21            # Remove redundant columns
-22            df.drop(df.columns[0], axis=1, inplace=True)
-23            # Even though the data is by `parish``, let's call the corresponding column `district``
-24            df.rename(columns={'Unnamed: 1': 'district'}, inplace=True)
-25            # !: Check whether rp is = 100 given the data
-26            df['rp'] = 100
-27            df.rename(
-28                columns={'Combined Total': 'exposed_value'}, inplace=True)
-29
-30            # !: Replace with the real data
-31            # Let's assume that PML is equal to AAL % by district * by the PML for the whole country
-32            # These values are from PML Results 19022016 SaintLucia FinalSummary2.xlsx
-33            total_pml = {10: 351733.75,  # 3,517,337.50
-34                         50: 23523224.51,  # 2,352,322,451.00
-35                         100: 59802419.04,  # 5,980,241,904.00
-36                         250: 147799213.30,  # 14,779,921,330.00
-37                         500: 248310895.20,  # 24,831,089,520.00
-38                         1000: 377593847.00}  # 37,759,384,700.00
-39            aal = pd.read_excel(
-40                '../../data/processed/asset_damage/Saint Lucia/AAL Results 19022016 StLucia FinalSummary2 adjusted.xlsx', sheet_name='AAL St. Lucia Province')
-41            aal.set_index('Name', inplace=True)
-42            aal = aal[['AAL as % of Total AAL']]
-43            aal.columns = ['pml']
-44            aal = aal[aal.index.notnull()]
-45            pml = aal.multiply(total_pml[return_period])
-46            df = pd.merge(df, pml, left_on='district', right_index=True)
-47            df.to_excel(
-48                f'../../data/processed/asset_damage/{country}/{country}.xlsx', index=False)
-49        else:
-50            raise ValueError(
-51                'Only `district` scale is supported for Saint Lucia.')
-52    else:
-53        raise ValueError('Only `Saint Lucia` is supported.')
-
- - -

Prepare district-level asset damage data and save it into a XLSX file.

-
- - -
-
- -
- - def - prepare_household_survey(country: str) -> None: - - - -
- -
118def prepare_household_survey(country: str) -> None:
-119    '''Prepare data for the simulation model.
-120
-121    Parameters
-122    ----------
-123    country : str
-124
-125    Raises
-126    ------
-127    ValueError
-128        If the country is not supported.
-129
-130    '''
-131    # Data preprocessing description:
-132    # 0. Load raw data
-133    # 1. Change `parentid1` to `hhid`
-134    # 2. Add `is_rural` column. 0 if `urban` is URBAN, if `urban` is RURAL then 1.
-135    # 3. Rename `tvalassets` to `kreported`.
-136    # 4. Rename a set of columns.
-137    # 5. Calculate some household attributes. Need to figure out what they mean.
-138    # 6. Add `financial_inst` column which has info on bank or credit union.
-139    # 7. Decode income attributes.
-140    # 8. Calculate some income attributes. Need to figure out what they mean.
-141    # 9. Decode housing attributes.
-142    # 10. Add new housing attributes. Need to figure out what they mean.
-143    # 11. Add new insurance attributes. Need to figure out what they mean.
-144    # 12. Calculate some housing attributes. Need to figure out what they mean.
-145    # 13. Calculate povery attributes. Need to figure out what they mean.
-146    # 14. Assign vulnerability by type of house.
-147    # 15. Subset columns of interest.
-148    # 16. Check which columns do we have and which do we miss.
-149    # 17. Add missing columns.
-150    # 18. Merge districts.
-151    # 19. Save data.
-152
-153    if country != 'Saint Lucia':
-154        raise ValueError('Currently only Saint Lucia is supported.')
-155
-156    print_statistics = True
-157    data = load_data(print_statistics=print_statistics)
-158
-159    # * Note that the sequence of the functions is important
-160    result = (start_pipeline(data)
-161              .pipe(add_is_rural_column, print_statistics=print_statistics)
-162              .pipe(rename_assets_column)
-163              .pipe(rename_other_columns)
-164              .pipe(calculate_household_attributes)
-165              .pipe(get_bank_or_credit_union)
-166              .pipe(decode_demographic_attributes)
-167              .pipe(decode_income_attributes)
-168              .pipe(calculate_income_attributes)
-169              .pipe(decode_housing_attributes)
-170              .pipe(add_housing_attributes)
-171              .pipe(add_insurance_attributes)
-172              .pipe(calculate_housing_attributes)
-173              .pipe(calculate_poverty_attributes)
-174              .pipe(assign_housing_vulnerability)
-175              .pipe(subset_columns)
-176              .pipe(check_columns)
-177              .pipe(add_missing_columns, missing_columns=['delta_tax_safety'])
-178              .pipe(merge_districts)
-179              )
-180
-181    result.to_csv(
-182        f'../../data/processed/household_survey/{country}/{country}.csv ')
-
- - -

Prepare data for the simulation model.

- -

Parameters

- -

country : str

- -

Raises

- -

ValueError - If the country is not supported.

-
- - -
-
- -
- - def - load_data(print_statistics: bool = True) -> pandas.core.frame.DataFrame: - - - -
- -
185def load_data(print_statistics: bool = True) -> pd.DataFrame:
-186    """Load the raw data."""
-187    # Read the raw data
-188    # * This dataset is the combined version of the household and persons files on parentid1
-189    data = pd.read_csv(
-190        '../../data/raw/household_survey/Saint Lucia/SLCHBS2016PersonV12_Housing.csv', low_memory=False)
-191    data.rename(columns={'parentid1': 'hhid'}, inplace=True)
-192
-193    # Set the index to the household id
-194    data.set_index('hhid', inplace=True)
-195
-196    if print_statistics:
-197        print('Number of rows: ', data.shape[0])
-198        print('Number of columns: ', data.shape[1])
-199        print('Number of duplicates based on index: ',
-200              data.index.duplicated().sum())
-201
-202    return data
-
- - -

Load the raw data.

-
- - -
-
- -
- - def - start_pipeline(data: pandas.core.frame.DataFrame): - - - -
- -
205def start_pipeline(data: pd.DataFrame):
-206    """Start the data processing pipeline."""
-207    return data.copy()
-
- - -

Start the data processing pipeline.

-
- - -
-
- -
- - def - add_is_rural_column( data: pandas.core.frame.DataFrame, print_statistics: bool = True) -> pandas.core.frame.DataFrame: - - - -
- -
210def add_is_rural_column(data: pd.DataFrame, print_statistics: bool = True) -> pd.DataFrame:
-211    """Create a new column that indicates whether the household is rural or not."""
-212    data['is_rural'] = 0
-213    data.loc[data['urban'] == 'RURAL', 'is_rural'] = 1
-214    if print_statistics:
-215        print('Number of rural households: ', data['is_rural'].sum())
-216        print('Number of urban households: ',
-217              data.shape[0] - data['is_rural'].sum())
-218    return data
-
- - -

Create a new column that indicates whether the household is rural or not.

-
- - -
-
- -
- - def - rename_assets_column(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame: - - - -
- -
221def rename_assets_column(data: pd.DataFrame) -> pd.DataFrame:
-222    """Rename the assets column to be more descriptive."""
-223    data.rename(columns={'tvalassets': 'kreported'}, inplace=True)
-224    return data
-
- - -

Rename the assets column to be more descriptive.

-
- - -
-
- -
- - def - rename_other_columns(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame: - - - -
- -
227def rename_other_columns(data: pd.DataFrame) -> pd.DataFrame:
-228    '''Rename a set of columns. See function for details.'''
-229    data = data.rename(columns={'DISTRICT_NAME': 'district',
-230                                'persons': 'hhsize',
-231                                'totexp.x': 'hhexp',
-232                                'pcexpae.x': 'aeexp',
-233                                'hincome': 'hhinc',
-234                                'WT.x': 'pwgt',
-235                                'food.x': 'hhexp_food'})
-236    return data
-
- - -

Rename a set of columns. See function for details.

-
- - -
-
- -
- - def - calculate_household_attributes(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame: - - - -
- -
261def calculate_household_attributes(data: pd.DataFrame) -> pd.DataFrame:
-262    lower = 1
-263    fill_na = 1
-264    data['popwgt'] = data.groupby('hhid')['pwgt'].transform('sum')
-265    data['hhwgt'] = data['popwgt'] / data['hhsize']
-266    data['hhsize_ae'] = (data['hhexp'] / data['aeexp']
-267                         ).fillna(fill_na).clip(lower=lower)
-268    data['aewgt'] = data['pwgt']*(data['hhsize_ae'] / data['hhsize'])
-269    return data
-
- - - - -
-
- -
- - def - get_bank_or_credit_union(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame: - - - -
- -
272def get_bank_or_credit_union(data: pd.DataFrame) -> pd.DataFrame:
-273    data['financial_inst'] = 0
-274    data.loc[data['p1_11__3'] == 'yes - bank', 'financial_inst'] = 1
-275    data.loc[data['p1_11__2'] == 'yes - bank', 'financial_inst'] = 1
-276    data.loc[data['p1_11__2'] == 'yes - credit union', 'financial_inst'] = 1
-277    data.loc[data['p1_11__1'] == 'yes - bank', 'financial_inst'] = 1
-278    data.loc[data['p1_11__1'] == 'yes - credit union', 'financial_inst'] = 1
-279    return data
-
- - - - -
-
- -
- - def - decode_demographic_attributes(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame: - - - -
- -
282def decode_demographic_attributes(data: pd.DataFrame) -> pd.DataFrame:
-283    '''Decode the demographic attributes.'''
-284    data = data.rename(columns={'p1_1': 'role',
-285                                'p1_2': 'sex',
-286                                'p1_3': 'age',
-287                                'p1_4': 'race',
-288                                'p1_5': 'religion',
-289                                'p1_6': 'marital_status',
-290                                'p1_7': 'cellphone'})
-291    return data
-
- - -

Decode the demographic attributes.

-
- - -
-
- -
- - def - decode_income_attributes(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame: - - - -
- -
294def decode_income_attributes(data: pd.DataFrame) -> pd.DataFrame:
-295    '''Decode the income-related attributes.'''
-296    data = data.rename(columns={
-297        # 'p1_11':'bank_account',
-298        'p4_1': 'months_worked',
-299        'inc2231002': 'other_entrepreneurial',
-300        'inc2331001': 'remits_intl',
-301        'inc2341001': 'rental_income',
-302        'inc2351001': 'dividends',  # other
-303        'inc2361001': 'interest',  # other
-304        'inc2361002': 'other_investment_income',  # other
-305        'inc2371001': 'pension_public',  # UCT
-306        'inc2371002': 'pension_private_LCA',  # pension private
-307        'inc2371003': 'pension_private_int',  # pension private
-308        'inc2371004': 'social_security',  # UCT
-309        # 'inc2381001':'annuity', # other
-310        'inc2381002': 'public_assistance',  # CCT
-311        'inc2381003': 'child_support',  # other
-312        'inc2391001': 'scholarships',  # other
-313        'inc2391002': 'financial_aid',  # other
-314        'inc2391003': 'alimony',  # other
-315        'inc2391099': 'mystery'
-316    })
-317    return data
-
- - -

Decode the income-related attributes.

-
- - -
-
- -
- - def - calculate_income_attributes(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame: - - - -
- -
320def calculate_income_attributes(data: pd.DataFrame) -> pd.DataFrame:
-321    data['remits_dom'] = 0
-322
-323    # Primary job income
-324    data['primary_income'] = data[['months_worked', 'pincome']].prod(axis=1)
-325
-326    # Secondary income
-327    data['cct'] = data['public_assistance'].copy()
-328    data['uct'] = data[['pension_public', 'social_security']].sum(axis=1)
-329    data['remits'] = data[['remits_intl', 'remits_dom']].sum(axis=1)
-330    data['other_sources'] = data[['dividends', 'interest', 'child_support', 'alimony', 'financial_aid',
-331                                  'scholarships', 'pension_private_LCA', 'pension_private_int', 'other_investment_income', 'mystery']].sum(axis=1)
-332    data['secondary_income'] = data[['other_entrepreneurial', 'cct',
-333                                     'uct', 'remits', 'rental_income', 'other_sources']].sum(axis=1)
-334
-335    # Total income
-336    data['total_income'] = data[[
-337        'primary_income', 'secondary_income']].sum(axis=1)
-338
-339    return data
-
- - - - -
-
- -
- - def - decode_housing_attributes(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame: - - - -
- -
342def decode_housing_attributes(data: pd.DataFrame) -> pd.DataFrame:
-343    '''Decode the housing-related attributes.'''
-344    data = data.rename(columns={'s2': 'own_rent',
-345                                # owner-occupied
-346                                'c1900105': 'mortgage_monthly',
-347                                'c1900104': 'domicile_value',
-348                                'c1900101': 'new_home_purchase_price',
-349                                'c1900103': 'new_home_mortgage_monthly',
-350                                'c1800501': 'rental_income_furnished',
-351                                'c1800502': 'rental_income_unfurnished',
-352                                'c1800503': 'rental_income_business',
-353                                'c0421101': 'imputed_rent_monthly',
-354                                'c1252101': 'insurance_premium',
-355                                # rental
-356                                'c0411100': 'actual_rent_monthly',
-357                                # condition & construction
-358                                's9q1': 'had_shock',
-359                                'h1_2': 'walls',
-360                                'h1_3': 'roof',
-361                                'h1_13': 'yr_house_built'})
-362    return data
-
- - -

Decode the housing-related attributes.

-
- - -
-
- -
- - def - add_housing_attributes(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame: - - - -
- -
365def add_housing_attributes(data: pd.DataFrame) -> pd.DataFrame:
-366    '''Introduce new housing attributes.'''
-367    # ! An assumption
-368    data['own_rent'] = data['own_rent'].replace({'own or rent free': 'own'})
-369    data['home_insured'] = data['insurance_premium'] > 0
-370    return data
-
- - -

Introduce new housing attributes.

-
- - -
-
- -
- - def - add_insurance_attributes(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame: - - - -
- -
373def add_insurance_attributes(data: pd.DataFrame) -> pd.DataFrame:
-374    # ? What does it mean?
-375    # National insurance corporation (unemployment)
-376    data['NIC_enrolled'] = data['p4_18'].isin(['employer', 'self-employed'])
-377    data['NIC_recipient'] = data['p4_17'].isin(['yes, from the nic'])
-378
-379    # Health insurance
-380    data = data.rename(columns={'p2_5': 'health_insurance'})
-381    return data
-
- - - - -
-
- -
- - def - calculate_housing_attributes(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame: - - - -
- -
384def calculate_housing_attributes(data: pd.DataFrame) -> pd.DataFrame:
-385    # Predict domicile value for hh that rent
-386    data['k_house'] = data['domicile_value'].copy().fillna(0)
-387    # total rent per capita per year
-388    data['hhexp_house'] = 12 * data['imputed_rent_monthly'].copy()
-389    data['hhexp_house'].update(12 * data['actual_rent_monthly'])
-390    data['hhexp_house'] = data['hhexp_house'].clip(lower=0).fillna(0)
-391
-392    # Urban population
-393    training_slc = (data['domicile_value'] > 10 * data['imputed_rent_monthly']
-394                    ) & (data['domicile_value'] < 1E6) & (data['is_rural'] == 0)
-395    urban_predictor = linear_regression(data.loc[training_slc].dropna(
-396        subset=['domicile_value', 'imputed_rent_monthly']), 'imputed_rent_monthly', 'domicile_value', return_model=True)
-397
-398    prediction_slc = (data['own_rent'] == 'rent') & (
-399        data['is_rural'] == 0) & (data['actual_rent_monthly'] is not None)
-400    data.loc[prediction_slc, 'k_house'] = urban_predictor.predict(
-401        data.loc[prediction_slc, 'actual_rent_monthly'].values.reshape(-1, 1))
-402
-403    # Rural population
-404    training_slc = (data['domicile_value'] > 10 * data['imputed_rent_monthly']
-405                    ) & (data['domicile_value'] < 1E6) & (data['is_rural'] == 1)
-406    rural_predictor = linear_regression(data.loc[training_slc].dropna(
-407        subset=['domicile_value', 'imputed_rent_monthly']), 'imputed_rent_monthly', 'domicile_value', return_model=True)
-408
-409    prediction_slc = (data['own_rent'] == 'rent') & (
-410        data['is_rural'] == 1) & (data['actual_rent_monthly'] is not None)
-411    data.loc[prediction_slc, 'k_house'] = rural_predictor.predict(
-412        data.loc[prediction_slc, 'actual_rent_monthly'].values.reshape(-1, 1))
-413
-414    # Correct for the households that reported unreasonably low domicile value
-415    prediction_slc = (data['own_rent'] == 'own') & (data['is_rural'] == 0) & (
-416        data['k_house'] <= 10*data['imputed_rent_monthly'])
-417    data.loc[prediction_slc, 'k_house'] = urban_predictor.predict(
-418        data.loc[prediction_slc, 'imputed_rent_monthly'].values.reshape(-1, 1))
-419
-420    prediction_slc = (data['own_rent'] == 'own') & (data['is_rural'] == 1) & (
-421        data['k_house'] <= 10*data['imputed_rent_monthly'])
-422    data.loc[prediction_slc, 'k_house'] = rural_predictor.predict(
-423        data.loc[prediction_slc, 'imputed_rent_monthly'].values.reshape(-1, 1))
-424
-425    data['k_house'] = data['k_house'].clip(lower=0).fillna(0)
-426
-427    return data
-
- - - - -
-
- -
- - def - calculate_poverty_attributes(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame: - - - -
- -
430def calculate_poverty_attributes(data: pd.DataFrame) -> pd.DataFrame:
-431    # Data has four poverty levels:
-432    # (1) $1.90/day = 1345 (ipline190 in dataset)
-433    # (2) $4.00/day = 2890,
-434    # (3) indigence line based on food is 2123 (indline in dataset),
-435    # (4) relative poverty line for food and non-food items is 6443 (povline in dataset)
-436    # Saint Lucia's poverty line is 1.90 * 365 = $689.7 US Dollars per year,
-437    # discounting using the PPP exchange rate of 1.952
-438    # the international poverty line for Saint Lucia is 1.90 * 1.952 * 365 = EC $1, 354 (0.7% in doc have 0.66%)
-439    # US $4 a day PPP is 4 * 1.952 * 365 = EC $2,890 (4.4% in doc have 4%)
-440    # poverty highest in Dennery and Vieux-Fort
-441
-442    # Domestic lines
-443    # !: Do not hardcode these values
-444    # !: Check with Bramka
-445    data['pov_line'] = 6443
-446    data['vul_line'] = 8053.75
-447    data['is_poor'] = data['aeexp'] <= data['pov_line']
-448
-449    # Load PMT data
-450    # ? What is PMT?
-451    # TODO: Merge PMT with data
-452    # !: I don't have this dataset
-453    # pmt = pd.read_stata(inputs + 'SLNET_16April.dta')
-454
-455    # Consumption quintiles and deciles
-456    data = data.rename(columns={'quintile.y': 'quintile',
-457                                'decile.y': 'decile'})
-458
-459    # print('income = {} mil. EC$'.format(round(1E-6*dfout[['aewgt','aeinc']].prod(axis=1).sum(),1)))
-460    # print('       = {} EC$/cap'.format(round(dfout[['aewgt','aeinc']].prod(axis=1).sum()/dfout['pwgt'].sum(),1)))
-461
-462    # Individual income
-463    for _i in ['primary_income_ae', 'cct_ae', 'uct_ae', 'remits_ae', 'other_sources_ae']:
-464        data[_i] = data.groupby('hhid')[_i.replace('_ae', '')].transform(
-465            'sum').multiply(1/data['hhsize_ae'])
-466
-467    # Household consumption
-468    data['imputed_rent_monthly'] = data['imputed_rent_monthly'].fillna(0)
-469    data['housing_service_ae'] = data.groupby(
-470        'hhid')['imputed_rent_monthly'].transform('mean').multiply(12./data['hhsize_ae'])
-471    data['aeexp_house'] = data['hhexp_house'] / data['hhsize_ae']
-472    data['aeexp_food'] = data['hhexp_food'] / data['hhsize_ae']
-473    data['aeexp_other'] = data['aeexp'] - \
-474        data[['aeexp_house', 'aeexp_food']].sum(axis=1)
-475
-476    # sum to households
-477    data['aesoc'] = data['cct_ae'].copy()
-478    data['aeinc'] = data[['primary_income_ae', 'cct_ae', 'uct_ae',
-479                          'remits_ae', 'other_sources_ae', 'housing_service_ae']].sum(axis=1)
-480
-481    data['k_house_ae'] = data['k_house']/data['hhsize_ae']
-482    return data
-
- - - - -
-
- -
- - def - assign_housing_vulnerability(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame: - - - -
- -
485def assign_housing_vulnerability(data: pd.DataFrame) -> pd.DataFrame:
-486    # !: This is quite random!
-487    # TODO: Do not hard code parameters here. Move them to a config file.
-488    data['walls'].fillna('others', inplace=True)
-489    data['v_walls'] = 0.1
-490    data.loc[data['walls'].isin(
-491        ['brick/blocks', 'concrete/concrete blocks']), 'v_walls'] = 0.35
-492    data.loc[data['walls'].isin(['wood & concrete']), 'v_walls'] = 0.5
-493    data.loc[data['walls'].isin(['wood/timber']), 'v_walls'] = 0.6
-494    data.loc[data['walls'].isin(['plywood']), 'v_walls'] = 0.7
-495    data.loc[data['walls'].isin(
-496        ['makeshift', 'others', 'other/dont know']), 'v_walls'] = 0.8
-497    data['roof'].fillna('others', inplace=True)
-498    data['v_roof'] = 0.75
-499    data.loc[data['roof'].isin(
-500        ['sheet metal (galvanize, galvalume)']), 'v_roof'] = 0.5
-501    data['v_init'] = 0.5 * data['v_roof'] + 0.5 * data['v_walls']
-502    return data
-
- - - - -
-
- -
- - def - subset_columns(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame: - - - -
- -
505def subset_columns(data: pd.DataFrame) -> pd.DataFrame:
-506    '''Subset columns of interest.'''
-507    columns_of_interest = ['district',
-508                           'is_rural',
-509                           'hhwgt',
-510                           'hhsize_ae',
-511                           'popwgt',
-512                           'aeinc',
-513                           'aesoc',
-514                           'k_house_ae',
-515                           'own_rent',
-516                           'aeexp',
-517                           'aeexp_house',
-518                           'aeexp_food',
-519                           'aeexp_other',
-520                           'is_poor',
-521                           'v_init',
-522                           'v_walls',
-523                           'v_roof',
-524                           'walls',
-525                           'roof',
-526                           'quintile',
-527                           'decile',
-528                           'primary_income_ae',
-529                           'cct_ae',
-530                           'uct_ae', 'remits_ae',
-531                           'other_sources_ae',
-532                           'housing_service_ae',
-533                           'pov_line',
-534                           'vul_line']
-535    result = data.loc[~data.index.duplicated(
-536        keep='first'), columns_of_interest]
-537    result['aewgt'] = data['aewgt'].groupby(level='hhid').sum()
-538
-539    # Keep characteristics of head of household
-540    household_head_columns = ['sex',
-541                              'age',
-542                              'race',
-543                              'religion',
-544                              'marital_status',
-545                              'cellphone',
-546                              'health_insurance',
-547                              'home_insured']  # ,'bank_account']
-548    result[household_head_columns] = data.loc[data['role']
-549                                              == 'head', household_head_columns]
-550    return result
-
- - -

Subset columns of interest.

-
- - -
-
- -
- - def - check_columns(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame: - - - -
- -
553def check_columns(data: pd.DataFrame) -> pd.DataFrame:
-554
-555    # These are the columns of the India case
-556    used_columns = [
-557        # 'hhid',
-558        'aeexp',
-559        'is_poor',
-560        'aeinc',
-561        'aesoc',
-562        'k_house_ae',
-563        'v_init',
-564        # 'delta_tax_safety',
-565        'own_rent',
-566        'aeexp_house',
-567    ]
-568
-569    extra_columns = [
-570        'popwgt',  # used, but seems to be not essential, just for writing
-571    ]
-572
-573    not_used_columns = [
-574        'hhsize',
-575        'hhweight',
-576        'state',
-577        'hhexp',
-578        'inc_safetynet_frac',
-579        'houses_owned',
-580        'percentile',
-581        'decile',
-582        'quintile'
-583    ]
-584
-585    # Check whether the new data has  all columns that we need
-586    missing_columns = []
-587
-588    for column in used_columns:
-589        if column not in data.columns:
-590            missing_columns.append(column)
-591
-592    # Check what columns we have besides the ones we need from used_columns
-593    extra_columns = [
-594        column for column in data.columns if column not in used_columns]
-595    print(f'We have the following extra columns: {extra_columns}')
-596
-597    if len(missing_columns) > 0:
-598        raise ValueError(f'Missing columns: {missing_columns}')
-599
-600    return data
-
- - - - -
-
- -
- - def - add_missing_columns( data: pandas.core.frame.DataFrame, missing_columns: list) -> pandas.core.frame.DataFrame: - - - -
- -
603def add_missing_columns(data: pd.DataFrame, missing_columns: list) -> pd.DataFrame:
-604    '''Manually add missing columns to the data.'''
-605    for column in missing_columns:
-606        data[column] = 0
-607    return data
-
- - -

Manually add missing columns to the data.

-
- - -
-
- -
- - def - merge_districts(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame: - - - -
- -
610def merge_districts(data: pd.DataFrame) -> pd.DataFrame:
-611    # !: We merged two districts into one
-612    data['district_original'] = data['district']
-613    data.replace({'district': {'Castries Sub-Urban': 'Castries',
-614                               'Castries City': 'Castries'}}, inplace=True)
-615    return data
-
- - - - -
-
- -
- - def - exponential_regression( data: pandas.core.frame.DataFrame, X_column: str, y_column: str, weights: <built-in function array> = None, return_model: bool = False) -> tuple[numpy.array, float]: - - - -
- -
623def exponential_regression(data: pd.DataFrame, X_column: str, y_column: str, weights: np.array = None, return_model: bool = False) -> tuple[np.array, float]:
-624    X = data[X_column].values.reshape(-1, 1)
-625    y = data[y_column].values.reshape(-1, 1)
-626    transformer = FunctionTransformer(np.log, validate=True)
-627    y_transformed = transformer.fit_transform(y)
-628
-629    lr = LinearRegression()
-630    lr.fit(X, y_transformed, sample_weight=weights)
-631    y_pred = lr.predict(X)
-632    coef = lr.coef_
-633    r2 = lr.score(X, y_transformed, sample_weight=weights)
-634    if return_model:
-635        return lr
-636    else:
-637        return y_pred, coef, r2
-
- - - - -
-
- -
- - def - polynomial_regression( data: pandas.core.frame.DataFrame, X_column: str, y_column: str, power: int, weights: <built-in function array> = None, X_new: <built-in function array> = None, X_start: int = 0, X_end: int = 40, X_num: int = 100): - - - -
- -
640def polynomial_regression(data: pd.DataFrame,
-641                          X_column: str,
-642                          y_column: str,
-643                          power: int,
-644                          weights: np.array = None,
-645                          X_new: np.array = None,
-646                          X_start: int = 0,
-647                          X_end: int = 40,
-648                          X_num: int = 100):
-649    # !: Weights are not used in this function
-650    X = data[X_column].squeeze().T
-651    y = data[y_column].squeeze().T
-652    coef = poly.polyfit(X, y, power)
-653
-654    if X_new is None:
-655        X_new = np.linspace(X_start, X_end, num=X_num)
-656
-657    f = poly.polyval(X_new, coef)
-658
-659    return X_new, f
-
- - - - -
-
- -
- - def - linear_regression( data: pandas.core.frame.DataFrame, X_column: str, y_column: str, weights: <built-in function array> = None, return_model: bool = False) -> tuple[numpy.array, float, float]: - - - -
- -
662def linear_regression(data: pd.DataFrame, X_column: str, y_column: str, weights: np.array = None, return_model: bool = False) -> tuple[np.array, float, float]:
-663    '''Do a linear regression on the data and return the predicted values, the coefficient and the r2 score.'''
-664    X = data[X_column].values.reshape(-1, 1)
-665    y = data[y_column].values.reshape(-1, 1)
-666    lr = LinearRegression()
-667    lr.fit(X, y, sample_weight=weights)
-668    y_pred = lr.predict(X)
-669    coef = lr.coef_
-670    r2 = lr.score(X, y, sample_weight=weights)
-671    if return_model:
-672        return lr
-673    else:
-674        return y_pred, coef, r2
-
- - -

Do a linear regression on the data and return the predicted values, the coefficient and the r2 score.

-
- - -
-
- - \ No newline at end of file diff --git a/docs/src/data/read.html b/docs/src/data/read.html deleted file mode 100644 index d5d8961..0000000 --- a/docs/src/data/read.html +++ /dev/null @@ -1,482 +0,0 @@ - - - - - - - src.data.read API documentation - - - - - - - - - -
-
-

-src.data.read

- - - - - - -
 1import pandas as pd
- 2import os
- 3import numpy as np
- 4import json
- 5
- 6
- 7def read_asset_damage(country) -> None:
- 8    '''Read asset damage for all districts from a XLSX file and load it into the memory.'''
- 9    if country == 'Saint Lucia':
-10        all_damage = pd.read_excel(
-11            f"../data/processed/asset_damage/{country}/{country}.xlsx", index_col=None, header=0)
-12    else:
-13        raise ValueError('Only `Saint Lucia` is supported.')
-14
-15    return all_damage
-16
-17
-18def get_asset_damage(all_damage: pd.DataFrame, scale: str, district: str, return_period: int, print_statistics: bool) -> tuple:
-19    '''Get asset damage for a specific district.
-20
-21    Args:
-22        all_damage (pd.DataFrame): Asset damage data for all districts.
-23        scale (str): Scale of the analysis. Only `district` is supported.
-24        district (str): District name.
-25        return_period (int): Return period.
-26        print_statistics (bool): Print the statistics.
-27
-28    Returns:
-29        tuple: Event damage, total asset stock, expected loss fraction.
-30
-31    Raises:
-32        ValueError: If the scale is not `district`.   
-33        ValueError: If the expected loss fraction is greater than 1.
-34    '''
-35    if scale == 'district':
-36        event_damage = all_damage.loc[(all_damage[scale] == district) & (
-37            all_damage['rp'] == return_period), 'pml'].values[0]  # PML
-38        total_asset_stock = all_damage.loc[(all_damage[scale] == district) & (
-39            all_damage['rp'] == return_period), 'exposed_value'].values[0]  # Exposed value
-40
-41    else:
-42        raise ValueError(
-43            'Only `district` scale is supported.')
-44
-45    event_damage = event_damage
-46    total_asset_stock = total_asset_stock
-47    expected_loss_fraction = event_damage / total_asset_stock
-48
-49    if expected_loss_fraction > 1:
-50        raise ValueError(
-51            'Expected loss fraction is greater than 1. Check the data.')
-52
-53    if print_statistics:
-54        print('Event damage = ' + str('{:,}'.format(round(event_damage))))
-55        print('Total asset stock = ' +
-56              str('{:,}'.format(round(total_asset_stock))))
-57        print('Expected loss fraction = ' +
-58              str(np.round(expected_loss_fraction, 3)))
-59
-60    return event_damage, total_asset_stock, expected_loss_fraction
-61
-62
-63def read_household_survey(country: str) -> pd.DataFrame:
-64    '''Reads household survey from a CSV file.
-65
-66    Args:
-67        country (str): Country name.
-68
-69    Returns:
-70        pd.DataFrame: Household survey data.
-71    
-72    Raises:
-73        ValueError: If the country is not `Saint Lucia`.
-74    '''
-75    if country == 'Saint Lucia':
-76        household_survey = pd.read_csv(
-77            f"../data/processed/household_survey/{country}/{country}.csv")
-78    else:
-79        raise ValueError('Only `Saint Lucia` is supported.')
-80
-81    return household_survey
-
- - -
-
- -
- - def - read_asset_damage(country) -> None: - - - -
- -
 8def read_asset_damage(country) -> None:
- 9    '''Read asset damage for all districts from a XLSX file and load it into the memory.'''
-10    if country == 'Saint Lucia':
-11        all_damage = pd.read_excel(
-12            f"../data/processed/asset_damage/{country}/{country}.xlsx", index_col=None, header=0)
-13    else:
-14        raise ValueError('Only `Saint Lucia` is supported.')
-15
-16    return all_damage
-
- - -

Read asset damage for all districts from a XLSX file and load it into the memory.

-
- - -
-
- -
- - def - get_asset_damage( all_damage: pandas.core.frame.DataFrame, scale: str, district: str, return_period: int, print_statistics: bool) -> tuple: - - - -
- -
19def get_asset_damage(all_damage: pd.DataFrame, scale: str, district: str, return_period: int, print_statistics: bool) -> tuple:
-20    '''Get asset damage for a specific district.
-21
-22    Args:
-23        all_damage (pd.DataFrame): Asset damage data for all districts.
-24        scale (str): Scale of the analysis. Only `district` is supported.
-25        district (str): District name.
-26        return_period (int): Return period.
-27        print_statistics (bool): Print the statistics.
-28
-29    Returns:
-30        tuple: Event damage, total asset stock, expected loss fraction.
-31
-32    Raises:
-33        ValueError: If the scale is not `district`.   
-34        ValueError: If the expected loss fraction is greater than 1.
-35    '''
-36    if scale == 'district':
-37        event_damage = all_damage.loc[(all_damage[scale] == district) & (
-38            all_damage['rp'] == return_period), 'pml'].values[0]  # PML
-39        total_asset_stock = all_damage.loc[(all_damage[scale] == district) & (
-40            all_damage['rp'] == return_period), 'exposed_value'].values[0]  # Exposed value
-41
-42    else:
-43        raise ValueError(
-44            'Only `district` scale is supported.')
-45
-46    event_damage = event_damage
-47    total_asset_stock = total_asset_stock
-48    expected_loss_fraction = event_damage / total_asset_stock
-49
-50    if expected_loss_fraction > 1:
-51        raise ValueError(
-52            'Expected loss fraction is greater than 1. Check the data.')
-53
-54    if print_statistics:
-55        print('Event damage = ' + str('{:,}'.format(round(event_damage))))
-56        print('Total asset stock = ' +
-57              str('{:,}'.format(round(total_asset_stock))))
-58        print('Expected loss fraction = ' +
-59              str(np.round(expected_loss_fraction, 3)))
-60
-61    return event_damage, total_asset_stock, expected_loss_fraction
-
- - -

Get asset damage for a specific district.

- -

Args: - all_damage (pd.DataFrame): Asset damage data for all districts. - scale (str): Scale of the analysis. Only district is supported. - district (str): District name. - return_period (int): Return period. - print_statistics (bool): Print the statistics.

- -

Returns: - tuple: Event damage, total asset stock, expected loss fraction.

- -

Raises: - ValueError: If the scale is not district.
- ValueError: If the expected loss fraction is greater than 1.

-
- - -
-
- -
- - def - read_household_survey(country: str) -> pandas.core.frame.DataFrame: - - - -
- -
64def read_household_survey(country: str) -> pd.DataFrame:
-65    '''Reads household survey from a CSV file.
-66
-67    Args:
-68        country (str): Country name.
-69
-70    Returns:
-71        pd.DataFrame: Household survey data.
-72    
-73    Raises:
-74        ValueError: If the country is not `Saint Lucia`.
-75    '''
-76    if country == 'Saint Lucia':
-77        household_survey = pd.read_csv(
-78            f"../data/processed/household_survey/{country}/{country}.csv")
-79    else:
-80        raise ValueError('Only `Saint Lucia` is supported.')
-81
-82    return household_survey
-
- - -

Reads household survey from a CSV file.

- -

Args: - country (str): Country name.

- -

Returns: - pd.DataFrame: Household survey data.

- -

Raises: - ValueError: If the country is not Saint Lucia.

-
- - -
-
- - \ No newline at end of file diff --git a/docs/src/data/visualise.html b/docs/src/data/visualise.html deleted file mode 100644 index a7f4260..0000000 --- a/docs/src/data/visualise.html +++ /dev/null @@ -1,1190 +0,0 @@ - - - - - - - src.data.visualise API documentation - - - - - - - - - -
-
-

-src.data.visualise

- - - - - - -
  1import geopandas as gpd
-  2import matplotlib
-  3import matplotlib.pyplot as plt
-  4import pandas as pd
-  5import numpy as np
-  6from sklearn.preprocessing import MinMaxScaler
-  7import ptitprince as pt
-  8import seaborn as sns
-  9from scipy.stats import spearmanr
- 10from matplotlib.ticker import MaxNLocator
- 11# import contextily as ctx
- 12
- 13
- 14def rainclouds(outcomes: pd.DataFrame, savefigs: bool,  x_columns: list = [], x_titles: list = [], plot_years_in_poverty: bool = False, color_palette: str = 'Set2', sharex: bool = True):
- 15    districts = outcomes['district'].unique().tolist()
- 16    n_districts = len(districts)
- 17    colors = sns.color_palette(color_palette, n_colors=len(districts))
- 18
- 19    if len(x_columns) == 0:
- 20        x_columns = [
- 21            'n_affected_people',
- 22            'n_new_poor_increase_pct',
- 23            'n_new_poor',
- 24            'annual_average_consumption_loss_pct',
- 25            'r',
- 26            'new_poverty_gap',
- 27            # 'one_year_in_poverty',
- 28            # 'two_years_in_poverty',
- 29            # 'three_years_in_poverty',
- 30            # 'four_years_in_poverty',
- 31            # 'five_years_in_poverty',
- 32            # 'six_years_in_poverty',
- 33            # 'seven_years_in_poverty',
- 34            # 'eight_years_in_poverty',
- 35            # 'nine_years_in_poverty',
- 36            # 'ten_years_in_poverty'
- 37        ]
- 38
- 39    if len(x_titles) == 0:
- 40        x_titles = [
- 41            'Affected People',
- 42            'New Poor Increase (%)',
- 43            'New Poor',
- 44            'Wt. Ann. Avg. Consump. Loss p.c. (%)',
- 45            'Socio-Economic Resilience',
- 46            'Poverty Gap',
- 47            # 'One year in poverty',
- 48            # 'Two years in poverty',
- 49            # 'Three years in poverty',
- 50            # 'Four years in poverty',
- 51            # 'Five years in poverty',
- 52            # 'Six years in poverty',
- 53            # 'Seven years in poverty',
- 54            # 'Eight years in poverty',
- 55            # 'Nine years in poverty',
- 56            # 'Ten years in poverty'
- 57        ]
- 58
- 59    is_years_in_poverty = False
- 60
- 61    for x_column, x_title in zip(x_columns, x_titles):
- 62        fig, ax = plt.subplots(ncols=3, nrows=3, figsize=(
- 63            4 * n_districts / 3, 3 * n_districts / 3), sharex=sharex)
- 64
- 65        for district in districts:
- 66            df = outcomes[outcomes['district'] == district].copy()
- 67
- 68            # Calculate an increase in new poor in respect to the total population
- 69            # df = df.assign(one_year_in_poverty = df['years_in_poverty'].apply(lambda x: x[0]))
- 70            # df = df.assign(two_years_in_poverty = df['years_in_poverty'].apply(lambda x: x[1]))
- 71            # df = df.assign(three_years_in_poverty = df['years_in_poverty'].apply(lambda x: x[2]))
- 72            # df = df.assign(four_years_in_poverty = df['years_in_poverty'].apply(lambda x: x[3]))
- 73            # df = df.assign(five_years_in_poverty = df['years_in_poverty'].apply(lambda x: x[4]))
- 74            # df = df.assign(six_years_in_poverty = df['years_in_poverty'].apply(lambda x: x[5]))
- 75            # df = df.assign(seven_years_in_poverty = df['years_in_poverty'].apply(lambda x: x[6]))
- 76            # df = df.assign(eight_years_in_poverty = df['years_in_poverty'].apply(lambda x: x[7]))
- 77            # df = df.assign(nine_years_in_poverty = df['years_in_poverty'].apply(lambda x: x[8]))
- 78            # df = df.assign(ten_years_in_poverty = df['years_in_poverty'].apply(lambda x: x[9]))
- 79
- 80            df[x_column] = df[x_column].astype(float)
- 81
- 82            # Make a half violin plot
- 83            pt.half_violinplot(x=x_column,
- 84                               y='policy',  # hue='scenario',
- 85                               data=df,
- 86                               color=colors[districts.index(district)],
- 87                               bw=.2,
- 88                               cut=0.,
- 89                               scale="area",
- 90                               width=.6,
- 91                               inner=None,
- 92                               ax=ax[districts.index(district) // 3, districts.index(district) % 3])
- 93
- 94            # Add stripplot
- 95            sns.stripplot(x=x_column,
- 96                          y='policy',  # hue='scenario',
- 97                          data=df,
- 98                          color=colors[districts.index(district)],
- 99                          edgecolor='white',
-100                          size=3,
-101                          jitter=1,
-102                          zorder=0,
-103                          orient='h',
-104                          ax=ax[districts.index(district) // 3, districts.index(district) % 3])
-105
-106            # Add boxplot
-107            sns.boxplot(x=x_column,
-108                        y='policy',  # hue='scenario',
-109                        data=df,
-110                        color="black",
-111                        width=.15,
-112                        zorder=10,
-113                        showcaps=True,
-114                        boxprops={'facecolor': 'none', "zorder": 10},
-115                        showfliers=True,
-116                        whiskerprops={'linewidth': 2, "zorder": 10},
-117                        saturation=1,
-118                        orient='h',
-119                        ax=ax[districts.index(district) // 3, districts.index(district) % 3])
-120
-121            if is_years_in_poverty:
-122                title = district + ', E = ' + \
-123                    f'{round(df[x_column].mean())}'
-124            else:
-125                title = district
-126            ax[districts.index(district) // 3,
-127               districts.index(district) % 3].set_title(title)
-128            ax[districts.index(district) // 3,
-129               districts.index(district) % 3].set_ylabel('')
-130            ax[districts.index(district) // 3,
-131               districts.index(district) % 3].set_xlabel(x_title)
-132
-133            # Remove y ticks and labels
-134            ax[districts.index(district) // 3,
-135               districts.index(district) % 3].set_yticklabels([])
-136            ax[districts.index(district) // 3,
-137               districts.index(district) % 3].set_yticks([])
-138
-139            # Do not display floats in the x-axis
-140            ax[districts.index(district) // 3, districts.index(district) %
-141               3].xaxis.set_major_locator(MaxNLocator(integer=True))
-142
-143            # Plot the median
-144            # ax[districts.index(district) // 3, districts.index(district) % 3].axvline(df[x_column].median(), color='black', linestyle='--', linewidth=1)
-145
-146            # Add text close to the boxplot's median
-147            ax[districts.index(district) // 3, districts.index(district) % 3].text(df[x_column].median(), 0.2,
-148                                                                                   f'M={df[x_column].median():.2f}',
-149                                                                                   horizontalalignment='left', size='small', color='black')
-150
-151            # # Add text close to the boxplot's min and max
-152            # ax[districts.index(district) // 3, districts.index(district) % 3].text(df[x_column].min(), 0.3,
-153            #                                                                        f'min={df[x_column].min():.2f}',
-154            #                                                                        horizontalalignment='left', size='small', color='black')
-155            # ax[districts.index(district) // 3, districts.index(district) % 3].text(df[x_column].max(), 0.4,
-156            #                                                                        f'max={df[x_column].max():.2f}',
-157            #                                                                        horizontalalignment='left', size='small', color='black')
-158
-159            initial_poverty_gap = df['initial_poverty_gap'].iloc[0]
-160
-161            # Add initial poverty gap as in the legend to the plot
-162            if x_column == 'new_poverty_gap':
-163                ax[districts.index(district) // 3, districts.index(district) % 3].text(0.025, 0.9,
-164                                                                                       f'Poverty gap before disaster={initial_poverty_gap:.2f}',
-165                                                                                       horizontalalignment='left', size='small', color='black',
-166                                                                                       transform=ax[districts.index(district) // 3, districts.index(district) % 3].transAxes)
-167
-168        # Add a super title
-169        # fig.suptitle(x_title, fontsize=16)
-170        fig.tight_layout()
-171        if savefigs:
-172            plt.savefig(
-173                f'../figures/analysis/{x_column}.png', dpi=500, bbox_inches='tight')
-174
-175
-176def bivariate_choropleth(data, x_name, y_name, x_label, y_label, scale, figsize, return_table):
-177    fig, ax = plt.subplots(figsize=figsize)
-178
-179    # Bin the data
-180    data = bin_data(data, x_name, y_name, scale, print_statistics=False)
-181
-182    # Get colors
-183    all_colors, available_colors = get_colors(data)
-184    cmap = matplotlib.colors.ListedColormap(available_colors)
-185
-186    # Step 1: Draw the map
-187    # border = gpd.read_file(f'../data/processed/boundaries/{city}/city.json')
-188    border = gpd.read_file(
-189        '../data/raw/shapefiles/Saint Lucia/gadm36_LCA_shp/gadm36_LCA_0.shp')
-190    data.plot(ax=ax,
-191              edgecolor='black',
-192              linewidth=.1,
-193              column='Bi_Class',  # variable that is going to be used to color the map
-194              cmap=cmap,  # newly defined bivariate cmap
-195              categorical=True,  # bivariate choropleth has to be colored as categorical map
-196              legend=False)  # we're going to draw the legend ourselves
-197    # add the basemap
-198    # ctx.add_basemap(ax=ax, source=ctx.providers.CartoDB.Positron)
-199    border.plot(ax=ax, facecolor='none',
-200                edgecolor='black', alpha=.5)  # city border
-201    for idx, row in data.iterrows():
-202        ax.annotate(text=row['NAME_1'], xy=row['geometry'].centroid.coords[0],
-203                    ha='center', fontsize=8, color='white')
-204
-205    plt.tight_layout()  # "tighten" two figures map and basemap
-206    plt.axis('off')  # we don't need axis with coordinates
-207    # ax.set_title('Bivariate Choropleth Amsterdam')
-208
-209    # Step 2: draw the legend
-210
-211    # We're drawing a 3x3 "box" as 3 columns
-212    # The xmin and xmax arguments axvspan are defined to create equally sized small boxes
-213
-214    img2 = fig  # refer to the main figure
-215    # add new axes to place the legend there
-216    ax2 = fig.add_axes([0.15, 0.25, 0.1, 0.1])
-217    # and specify its location
-218    alpha = 1  # alpha argument to make it more/less transparent
-219
-220    # Column 1
-221    # All colors to create a complete legend
-222    # all_colors = ['#e8e8e8', '#b0d5df', '#64acbe', '#e4acac', '#ad9ea5', '#627f8c', '#c85a5a', '#985356', '#574249']
-223
-224    ax2.axvspan(xmin=0, xmax=0.33, ymin=0, ymax=0.33,
-225                alpha=alpha, color=all_colors[0])
-226    ax2.axvspan(xmin=0, xmax=0.33, ymin=0.33, ymax=0.66,
-227                alpha=alpha, color=all_colors[1])
-228    ax2.axvspan(xmin=0, xmax=0.33, ymin=0.66, ymax=1,
-229                alpha=alpha, color=all_colors[2])
-230
-231    # Column 2
-232    ax2.axvspan(xmin=0.33, xmax=0.66, ymin=0, ymax=0.33,
-233                alpha=alpha, color=all_colors[3])
-234    ax2.axvspan(xmin=0.33, xmax=0.66, ymin=0.33, ymax=0.66,
-235                alpha=alpha, color=all_colors[4])
-236    ax2.axvspan(xmin=0.33, xmax=0.66, ymin=0.66, ymax=1,
-237                alpha=alpha, color=all_colors[5])
-238
-239    # Column 3
-240    ax2.axvspan(xmin=0.66, xmax=1, ymin=0, ymax=0.33,
-241                alpha=alpha, color=all_colors[6])
-242    ax2.axvspan(xmin=0.66, xmax=1, ymin=0.33, ymax=0.66,
-243                alpha=alpha, color=all_colors[7])
-244    ax2.axvspan(xmin=0.66, xmax=1, ymin=0.66, ymax=1,
-245                alpha=alpha, color=all_colors[8])
-246
-247    # Step 3: annoate the legend
-248    # remove ticks from the big box
-249    ax2.tick_params(axis='both', which='both', length=0)
-250    ax2.axis('off')  # turn off its axis
-251    ax2.annotate("", xy=(0, 1), xytext=(0, 0), arrowprops=dict(
-252        arrowstyle="->", lw=1, color='black'))  # draw arrow for x
-253    ax2.annotate("", xy=(1, 0), xytext=(0, 0), arrowprops=dict(
-254        arrowstyle="->", lw=1, color='black'))  # draw arrow for y
-255    ax2.text(s=x_label, x=0.1, y=-0.25, fontsize=8)  # annotate x axis
-256    ax2.text(s=y_label, x=-0.25, y=0.1, rotation=90,
-257             fontsize=8)  # annotate y axis
-258    # plt.savefig('bivariate_choropleth.png', dpi=300)
-259
-260    if return_table:
-261        return data
-262
-263
-264def nine_quadrants_plot(data, x_name, y_name, scale=True):
-265    _, ax = plt.subplots(figsize=(6, 5))
-266
-267    if scale:
-268        scaler = MinMaxScaler()
-269        # data[x_name] = scaler.fit_transform(data[x_name].values.reshape(-1, 1))
-270        # data[y_name] = scaler.fit_transform(data[y_name].values.reshape(-1, 1))
-271        # Scale data between 0 and 1
-272        data[x_name] = (data[x_name] - data[x_name].min()) / \
-273            (data[x_name].max() - data[x_name].min())
-274        data[y_name] = (data[y_name] - data[y_name].min()) / \
-275            (data[y_name].max() - data[y_name].min())
-276
-277    data.plot.scatter(x_name, y_name, s=20, ax=ax, c='black', zorder=2)
-278
-279    # Iterate over each row and annotate the points
-280    for idx, row in data.iterrows():
-281        ax.annotate(text=row['NAME_1'], xy=(row[x_name], row[y_name]),
-282                    ha='center', fontsize=10, color='black')
-283
-284    # Annotate with Spearman's rho
-285    # rho, p = spearmanr(data[x_name], data[y_name])
-286    # ax.text(0.05, 0.95, f'$\\rho$ = {round(rho, 2)}', transform=ax.transAxes,
-287    #         verticalalignment='top', fontsize=12, bbox=dict(facecolor='white', edgecolor='black', alpha=1))
-288
-289    ax.axvline(0.33, color='black', alpha=.33, lw=1)
-290    ax.axvline(0.66, color='black', alpha=.33, lw=1)
-291    ax.axhline(0.33, color='black', alpha=.33, lw=1)
-292    ax.axhline(0.66, color='black', alpha=.33, lw=1)
-293
-294    alpha = 1
-295
-296    all_colors = {'1A': '#dddddd',
-297                  '1B': '#dd7c8a',
-298                  '1C': '#cc0024',
-299                  '2A': '#7bb3d1',
-300                  '2B': '#8d6c8f',
-301                  '2C': '#8a274a',
-302                  '3A': '#016eae',
-303                  '3B': '#4a4779',
-304                  '3C': '#4b264d'}
-305
-306    # Column 1
-307    c = all_colors['1A']
-308    ax.axvspan(xmin=0, xmax=0.33, ymin=0 + 0.025,
-309               ymax=0.345, alpha=alpha, color=c)
-310
-311    c = all_colors['1B']
-312    ax.axvspan(xmin=0, xmax=0.33, ymin=0.33 + 0.015,
-313               ymax=0.66 - 0.015, alpha=alpha,  color=c)
-314
-315    c = all_colors['1C']
-316    ax.axvspan(xmin=0, xmax=0.33, ymin=0.66 - 0.015,
-317               ymax=1 - 0.05, alpha=alpha, color=c)
-318
-319    # Column 2
-320    c = all_colors['2A']
-321    ax.axvspan(xmin=0.33, xmax=0.66, ymin=0 + 0.025,
-322               ymax=0.345, alpha=alpha,  color=c)
-323
-324    c = all_colors['2B']
-325    ax.axvspan(xmin=0.33, xmax=0.66, ymin=0.345,
-326               ymax=0.645, alpha=alpha,  color=c)
-327
-328    c = all_colors['2C']
-329    ax.axvspan(xmin=0.33, xmax=0.66, ymin=0.649,
-330               ymax=1 - 0.05, alpha=alpha, color=c)
-331
-332    # Column 3
-333    c = all_colors['3A']
-334    ax.axvspan(xmin=0.66, xmax=1, ymin=0.025, ymax=0.345, alpha=alpha, color=c)
-335
-336    c = all_colors['3B']
-337    ax.axvspan(xmin=0.66, xmax=1, ymin=0.345,
-338               ymax=0.645, alpha=alpha,  color=c)
-339
-340    c = all_colors['3C']
-341    ax.axvspan(xmin=0.66, xmax=1, ymin=0.649,
-342               ymax=1 - 0.05, alpha=alpha, color=c)
-343
-344    ax.set_xlim(-.05, 1.05)
-345    ax.set_ylim(-0.05, 1.05)
-346
-347    # Add regression line
-348    # x = data[x_name]
-349    # y = data[y_name]
-350    # m, b = np.polyfit(x, y, 1)
-351    # ax.plot(x, m * x + b, color='black', alpha=0.5, zorder=1)
-352
-353
-354def get_colors(data):
-355
-356    # colors = ['#e8e8e8', # 1A
-357    #           '#b0d5df', # 1B
-358    #           # '#64acbe', # 1C
-359    #           '#e4acac', # 2A
-360    #           '#ad9ea5', # 2B
-361    #           '#627f8c', # 2C
-362    #           '#c85a5a', # 3A
-363    #           '#985356'] # , # 3B
-364    #           # '#574249'] # 3C
-365
-366    all_colors = {'1A': '#e8e8e8',
-367                  '1B': '#b0d5df',
-368                  '1C': '#64acbe',
-369                  '2A': '#e4acac',
-370                  '2B': '#ad9ea5',
-371                  '2C': '#627f8c',
-372                  '3A': '#c85a5a',
-373                  '3B': '#985356',
-374                  '3C': '#574249'}
-375
-376    all_colors = {'1A': '#dddddd',
-377                  '1B': '#dd7c8a',
-378                  '1C': '#cc0024',
-379                  '2A': '#7bb3d1',
-380                  '2B': '#8d6c8f',
-381                  '2C': '#8a274a',
-382                  '3A': '#016eae',
-383                  '3B': '#4a4779',
-384                  '3C': '#4b264d'}
-385
-386    # Set of colors matching the elements of Bi_Class
-387    # We have to exclude those that did not come up in the data
-388    available_classes = data['Bi_Class'].value_counts().sort_index().index
-389    available_colors = [all_colors[i] for i in available_classes]
-390    return list(all_colors.values()), available_colors
-391
-392
-393def bin_data(data, x_name, y_name, scale, print_statistics=True):
-394    if scale:
-395        # Scale the data to be between 0 and 1
-396        # data[x_name] = (data[x_name] - data[x_name].min()) / \
-397        #     (data[x_name].max() - data[x_name].min())
-398        # data[y_name] = (data[y_name] - data[y_name].min()) / \
-399        #     (data[y_name].max() - data[y_name].min())
-400        # Scale the data with MinMaxScaler
-401        scaler = MinMaxScaler()
-402        data[x_name] = scaler.fit_transform(data[x_name].values.reshape(-1, 1))
-403        data[y_name] = scaler.fit_transform(data[y_name].values.reshape(-1, 1))
-404
-405    # Define the bins
-406    bins = [0, 0.33, 0.66, 1]
-407
-408    # Bin the first variable - x
-409    data['Var1_Class'] = pd.cut(data[x_name], bins=bins, include_lowest=True)
-410    data['Var1_Class'] = data['Var1_Class'].astype('str')
-411
-412    # Bin the second variable - y
-413    data['Var2_Class'] = pd.cut(data[y_name], bins=bins, include_lowest=True)
-414    data['Var2_Class'] = data['Var2_Class'].astype('str')
-415
-416    # Code created x bins to 1, 2, 3
-417    x_class_codes = np.arange(1, len(bins))
-418    d = dict(
-419        zip(data['Var1_Class'].value_counts().sort_index().index, x_class_codes))
-420    data['Var1_Class'] = data['Var1_Class'].replace(d)
-421
-422    # Code created y bins to A, B, C
-423    y_class_codes = ['A', 'B', 'C']
-424    d = dict(
-425        zip(data['Var2_Class'].value_counts().sort_index().index, y_class_codes))
-426    data['Var2_Class'] = data['Var2_Class'].replace(d)
-427
-428    # Combine x and y codes to create Bi_Class
-429    data['Bi_Class'] = data['Var1_Class'].astype('str') + data['Var2_Class']
-430
-431    if print_statistics:
-432        print('Number of unique elements in Var1_Class =',
-433              len(data['Var1_Class'].unique()))
-434        print('Number of unique elements in Var2_Class =',
-435              len(data['Var2_Class'].unique()))
-436        print('Number of unique elements in Bi_Class =',
-437              len(data['Bi_Class'].unique()))
-438    return data
-
- - -
-
- -
- - def - rainclouds( outcomes: pandas.core.frame.DataFrame, savefigs: bool, x_columns: list = [], x_titles: list = [], plot_years_in_poverty: bool = False, color_palette: str = 'Set2', sharex: bool = True): - - - -
- -
 15def rainclouds(outcomes: pd.DataFrame, savefigs: bool,  x_columns: list = [], x_titles: list = [], plot_years_in_poverty: bool = False, color_palette: str = 'Set2', sharex: bool = True):
- 16    districts = outcomes['district'].unique().tolist()
- 17    n_districts = len(districts)
- 18    colors = sns.color_palette(color_palette, n_colors=len(districts))
- 19
- 20    if len(x_columns) == 0:
- 21        x_columns = [
- 22            'n_affected_people',
- 23            'n_new_poor_increase_pct',
- 24            'n_new_poor',
- 25            'annual_average_consumption_loss_pct',
- 26            'r',
- 27            'new_poverty_gap',
- 28            # 'one_year_in_poverty',
- 29            # 'two_years_in_poverty',
- 30            # 'three_years_in_poverty',
- 31            # 'four_years_in_poverty',
- 32            # 'five_years_in_poverty',
- 33            # 'six_years_in_poverty',
- 34            # 'seven_years_in_poverty',
- 35            # 'eight_years_in_poverty',
- 36            # 'nine_years_in_poverty',
- 37            # 'ten_years_in_poverty'
- 38        ]
- 39
- 40    if len(x_titles) == 0:
- 41        x_titles = [
- 42            'Affected People',
- 43            'New Poor Increase (%)',
- 44            'New Poor',
- 45            'Wt. Ann. Avg. Consump. Loss p.c. (%)',
- 46            'Socio-Economic Resilience',
- 47            'Poverty Gap',
- 48            # 'One year in poverty',
- 49            # 'Two years in poverty',
- 50            # 'Three years in poverty',
- 51            # 'Four years in poverty',
- 52            # 'Five years in poverty',
- 53            # 'Six years in poverty',
- 54            # 'Seven years in poverty',
- 55            # 'Eight years in poverty',
- 56            # 'Nine years in poverty',
- 57            # 'Ten years in poverty'
- 58        ]
- 59
- 60    is_years_in_poverty = False
- 61
- 62    for x_column, x_title in zip(x_columns, x_titles):
- 63        fig, ax = plt.subplots(ncols=3, nrows=3, figsize=(
- 64            4 * n_districts / 3, 3 * n_districts / 3), sharex=sharex)
- 65
- 66        for district in districts:
- 67            df = outcomes[outcomes['district'] == district].copy()
- 68
- 69            # Calculate an increase in new poor in respect to the total population
- 70            # df = df.assign(one_year_in_poverty = df['years_in_poverty'].apply(lambda x: x[0]))
- 71            # df = df.assign(two_years_in_poverty = df['years_in_poverty'].apply(lambda x: x[1]))
- 72            # df = df.assign(three_years_in_poverty = df['years_in_poverty'].apply(lambda x: x[2]))
- 73            # df = df.assign(four_years_in_poverty = df['years_in_poverty'].apply(lambda x: x[3]))
- 74            # df = df.assign(five_years_in_poverty = df['years_in_poverty'].apply(lambda x: x[4]))
- 75            # df = df.assign(six_years_in_poverty = df['years_in_poverty'].apply(lambda x: x[5]))
- 76            # df = df.assign(seven_years_in_poverty = df['years_in_poverty'].apply(lambda x: x[6]))
- 77            # df = df.assign(eight_years_in_poverty = df['years_in_poverty'].apply(lambda x: x[7]))
- 78            # df = df.assign(nine_years_in_poverty = df['years_in_poverty'].apply(lambda x: x[8]))
- 79            # df = df.assign(ten_years_in_poverty = df['years_in_poverty'].apply(lambda x: x[9]))
- 80
- 81            df[x_column] = df[x_column].astype(float)
- 82
- 83            # Make a half violin plot
- 84            pt.half_violinplot(x=x_column,
- 85                               y='policy',  # hue='scenario',
- 86                               data=df,
- 87                               color=colors[districts.index(district)],
- 88                               bw=.2,
- 89                               cut=0.,
- 90                               scale="area",
- 91                               width=.6,
- 92                               inner=None,
- 93                               ax=ax[districts.index(district) // 3, districts.index(district) % 3])
- 94
- 95            # Add stripplot
- 96            sns.stripplot(x=x_column,
- 97                          y='policy',  # hue='scenario',
- 98                          data=df,
- 99                          color=colors[districts.index(district)],
-100                          edgecolor='white',
-101                          size=3,
-102                          jitter=1,
-103                          zorder=0,
-104                          orient='h',
-105                          ax=ax[districts.index(district) // 3, districts.index(district) % 3])
-106
-107            # Add boxplot
-108            sns.boxplot(x=x_column,
-109                        y='policy',  # hue='scenario',
-110                        data=df,
-111                        color="black",
-112                        width=.15,
-113                        zorder=10,
-114                        showcaps=True,
-115                        boxprops={'facecolor': 'none', "zorder": 10},
-116                        showfliers=True,
-117                        whiskerprops={'linewidth': 2, "zorder": 10},
-118                        saturation=1,
-119                        orient='h',
-120                        ax=ax[districts.index(district) // 3, districts.index(district) % 3])
-121
-122            if is_years_in_poverty:
-123                title = district + ', E = ' + \
-124                    f'{round(df[x_column].mean())}'
-125            else:
-126                title = district
-127            ax[districts.index(district) // 3,
-128               districts.index(district) % 3].set_title(title)
-129            ax[districts.index(district) // 3,
-130               districts.index(district) % 3].set_ylabel('')
-131            ax[districts.index(district) // 3,
-132               districts.index(district) % 3].set_xlabel(x_title)
-133
-134            # Remove y ticks and labels
-135            ax[districts.index(district) // 3,
-136               districts.index(district) % 3].set_yticklabels([])
-137            ax[districts.index(district) // 3,
-138               districts.index(district) % 3].set_yticks([])
-139
-140            # Do not display floats in the x-axis
-141            ax[districts.index(district) // 3, districts.index(district) %
-142               3].xaxis.set_major_locator(MaxNLocator(integer=True))
-143
-144            # Plot the median
-145            # ax[districts.index(district) // 3, districts.index(district) % 3].axvline(df[x_column].median(), color='black', linestyle='--', linewidth=1)
-146
-147            # Add text close to the boxplot's median
-148            ax[districts.index(district) // 3, districts.index(district) % 3].text(df[x_column].median(), 0.2,
-149                                                                                   f'M={df[x_column].median():.2f}',
-150                                                                                   horizontalalignment='left', size='small', color='black')
-151
-152            # # Add text close to the boxplot's min and max
-153            # ax[districts.index(district) // 3, districts.index(district) % 3].text(df[x_column].min(), 0.3,
-154            #                                                                        f'min={df[x_column].min():.2f}',
-155            #                                                                        horizontalalignment='left', size='small', color='black')
-156            # ax[districts.index(district) // 3, districts.index(district) % 3].text(df[x_column].max(), 0.4,
-157            #                                                                        f'max={df[x_column].max():.2f}',
-158            #                                                                        horizontalalignment='left', size='small', color='black')
-159
-160            initial_poverty_gap = df['initial_poverty_gap'].iloc[0]
-161
-162            # Add initial poverty gap as in the legend to the plot
-163            if x_column == 'new_poverty_gap':
-164                ax[districts.index(district) // 3, districts.index(district) % 3].text(0.025, 0.9,
-165                                                                                       f'Poverty gap before disaster={initial_poverty_gap:.2f}',
-166                                                                                       horizontalalignment='left', size='small', color='black',
-167                                                                                       transform=ax[districts.index(district) // 3, districts.index(district) % 3].transAxes)
-168
-169        # Add a super title
-170        # fig.suptitle(x_title, fontsize=16)
-171        fig.tight_layout()
-172        if savefigs:
-173            plt.savefig(
-174                f'../figures/analysis/{x_column}.png', dpi=500, bbox_inches='tight')
-
- - - - -
-
- -
- - def - bivariate_choropleth(data, x_name, y_name, x_label, y_label, scale, figsize, return_table): - - - -
- -
177def bivariate_choropleth(data, x_name, y_name, x_label, y_label, scale, figsize, return_table):
-178    fig, ax = plt.subplots(figsize=figsize)
-179
-180    # Bin the data
-181    data = bin_data(data, x_name, y_name, scale, print_statistics=False)
-182
-183    # Get colors
-184    all_colors, available_colors = get_colors(data)
-185    cmap = matplotlib.colors.ListedColormap(available_colors)
-186
-187    # Step 1: Draw the map
-188    # border = gpd.read_file(f'../data/processed/boundaries/{city}/city.json')
-189    border = gpd.read_file(
-190        '../data/raw/shapefiles/Saint Lucia/gadm36_LCA_shp/gadm36_LCA_0.shp')
-191    data.plot(ax=ax,
-192              edgecolor='black',
-193              linewidth=.1,
-194              column='Bi_Class',  # variable that is going to be used to color the map
-195              cmap=cmap,  # newly defined bivariate cmap
-196              categorical=True,  # bivariate choropleth has to be colored as categorical map
-197              legend=False)  # we're going to draw the legend ourselves
-198    # add the basemap
-199    # ctx.add_basemap(ax=ax, source=ctx.providers.CartoDB.Positron)
-200    border.plot(ax=ax, facecolor='none',
-201                edgecolor='black', alpha=.5)  # city border
-202    for idx, row in data.iterrows():
-203        ax.annotate(text=row['NAME_1'], xy=row['geometry'].centroid.coords[0],
-204                    ha='center', fontsize=8, color='white')
-205
-206    plt.tight_layout()  # "tighten" two figures map and basemap
-207    plt.axis('off')  # we don't need axis with coordinates
-208    # ax.set_title('Bivariate Choropleth Amsterdam')
-209
-210    # Step 2: draw the legend
-211
-212    # We're drawing a 3x3 "box" as 3 columns
-213    # The xmin and xmax arguments axvspan are defined to create equally sized small boxes
-214
-215    img2 = fig  # refer to the main figure
-216    # add new axes to place the legend there
-217    ax2 = fig.add_axes([0.15, 0.25, 0.1, 0.1])
-218    # and specify its location
-219    alpha = 1  # alpha argument to make it more/less transparent
-220
-221    # Column 1
-222    # All colors to create a complete legend
-223    # all_colors = ['#e8e8e8', '#b0d5df', '#64acbe', '#e4acac', '#ad9ea5', '#627f8c', '#c85a5a', '#985356', '#574249']
-224
-225    ax2.axvspan(xmin=0, xmax=0.33, ymin=0, ymax=0.33,
-226                alpha=alpha, color=all_colors[0])
-227    ax2.axvspan(xmin=0, xmax=0.33, ymin=0.33, ymax=0.66,
-228                alpha=alpha, color=all_colors[1])
-229    ax2.axvspan(xmin=0, xmax=0.33, ymin=0.66, ymax=1,
-230                alpha=alpha, color=all_colors[2])
-231
-232    # Column 2
-233    ax2.axvspan(xmin=0.33, xmax=0.66, ymin=0, ymax=0.33,
-234                alpha=alpha, color=all_colors[3])
-235    ax2.axvspan(xmin=0.33, xmax=0.66, ymin=0.33, ymax=0.66,
-236                alpha=alpha, color=all_colors[4])
-237    ax2.axvspan(xmin=0.33, xmax=0.66, ymin=0.66, ymax=1,
-238                alpha=alpha, color=all_colors[5])
-239
-240    # Column 3
-241    ax2.axvspan(xmin=0.66, xmax=1, ymin=0, ymax=0.33,
-242                alpha=alpha, color=all_colors[6])
-243    ax2.axvspan(xmin=0.66, xmax=1, ymin=0.33, ymax=0.66,
-244                alpha=alpha, color=all_colors[7])
-245    ax2.axvspan(xmin=0.66, xmax=1, ymin=0.66, ymax=1,
-246                alpha=alpha, color=all_colors[8])
-247
-248    # Step 3: annoate the legend
-249    # remove ticks from the big box
-250    ax2.tick_params(axis='both', which='both', length=0)
-251    ax2.axis('off')  # turn off its axis
-252    ax2.annotate("", xy=(0, 1), xytext=(0, 0), arrowprops=dict(
-253        arrowstyle="->", lw=1, color='black'))  # draw arrow for x
-254    ax2.annotate("", xy=(1, 0), xytext=(0, 0), arrowprops=dict(
-255        arrowstyle="->", lw=1, color='black'))  # draw arrow for y
-256    ax2.text(s=x_label, x=0.1, y=-0.25, fontsize=8)  # annotate x axis
-257    ax2.text(s=y_label, x=-0.25, y=0.1, rotation=90,
-258             fontsize=8)  # annotate y axis
-259    # plt.savefig('bivariate_choropleth.png', dpi=300)
-260
-261    if return_table:
-262        return data
-
- - - - -
-
- -
- - def - nine_quadrants_plot(data, x_name, y_name, scale=True): - - - -
- -
265def nine_quadrants_plot(data, x_name, y_name, scale=True):
-266    _, ax = plt.subplots(figsize=(6, 5))
-267
-268    if scale:
-269        scaler = MinMaxScaler()
-270        # data[x_name] = scaler.fit_transform(data[x_name].values.reshape(-1, 1))
-271        # data[y_name] = scaler.fit_transform(data[y_name].values.reshape(-1, 1))
-272        # Scale data between 0 and 1
-273        data[x_name] = (data[x_name] - data[x_name].min()) / \
-274            (data[x_name].max() - data[x_name].min())
-275        data[y_name] = (data[y_name] - data[y_name].min()) / \
-276            (data[y_name].max() - data[y_name].min())
-277
-278    data.plot.scatter(x_name, y_name, s=20, ax=ax, c='black', zorder=2)
-279
-280    # Iterate over each row and annotate the points
-281    for idx, row in data.iterrows():
-282        ax.annotate(text=row['NAME_1'], xy=(row[x_name], row[y_name]),
-283                    ha='center', fontsize=10, color='black')
-284
-285    # Annotate with Spearman's rho
-286    # rho, p = spearmanr(data[x_name], data[y_name])
-287    # ax.text(0.05, 0.95, f'$\\rho$ = {round(rho, 2)}', transform=ax.transAxes,
-288    #         verticalalignment='top', fontsize=12, bbox=dict(facecolor='white', edgecolor='black', alpha=1))
-289
-290    ax.axvline(0.33, color='black', alpha=.33, lw=1)
-291    ax.axvline(0.66, color='black', alpha=.33, lw=1)
-292    ax.axhline(0.33, color='black', alpha=.33, lw=1)
-293    ax.axhline(0.66, color='black', alpha=.33, lw=1)
-294
-295    alpha = 1
-296
-297    all_colors = {'1A': '#dddddd',
-298                  '1B': '#dd7c8a',
-299                  '1C': '#cc0024',
-300                  '2A': '#7bb3d1',
-301                  '2B': '#8d6c8f',
-302                  '2C': '#8a274a',
-303                  '3A': '#016eae',
-304                  '3B': '#4a4779',
-305                  '3C': '#4b264d'}
-306
-307    # Column 1
-308    c = all_colors['1A']
-309    ax.axvspan(xmin=0, xmax=0.33, ymin=0 + 0.025,
-310               ymax=0.345, alpha=alpha, color=c)
-311
-312    c = all_colors['1B']
-313    ax.axvspan(xmin=0, xmax=0.33, ymin=0.33 + 0.015,
-314               ymax=0.66 - 0.015, alpha=alpha,  color=c)
-315
-316    c = all_colors['1C']
-317    ax.axvspan(xmin=0, xmax=0.33, ymin=0.66 - 0.015,
-318               ymax=1 - 0.05, alpha=alpha, color=c)
-319
-320    # Column 2
-321    c = all_colors['2A']
-322    ax.axvspan(xmin=0.33, xmax=0.66, ymin=0 + 0.025,
-323               ymax=0.345, alpha=alpha,  color=c)
-324
-325    c = all_colors['2B']
-326    ax.axvspan(xmin=0.33, xmax=0.66, ymin=0.345,
-327               ymax=0.645, alpha=alpha,  color=c)
-328
-329    c = all_colors['2C']
-330    ax.axvspan(xmin=0.33, xmax=0.66, ymin=0.649,
-331               ymax=1 - 0.05, alpha=alpha, color=c)
-332
-333    # Column 3
-334    c = all_colors['3A']
-335    ax.axvspan(xmin=0.66, xmax=1, ymin=0.025, ymax=0.345, alpha=alpha, color=c)
-336
-337    c = all_colors['3B']
-338    ax.axvspan(xmin=0.66, xmax=1, ymin=0.345,
-339               ymax=0.645, alpha=alpha,  color=c)
-340
-341    c = all_colors['3C']
-342    ax.axvspan(xmin=0.66, xmax=1, ymin=0.649,
-343               ymax=1 - 0.05, alpha=alpha, color=c)
-344
-345    ax.set_xlim(-.05, 1.05)
-346    ax.set_ylim(-0.05, 1.05)
-
- - - - -
-
- -
- - def - get_colors(data): - - - -
- -
355def get_colors(data):
-356
-357    # colors = ['#e8e8e8', # 1A
-358    #           '#b0d5df', # 1B
-359    #           # '#64acbe', # 1C
-360    #           '#e4acac', # 2A
-361    #           '#ad9ea5', # 2B
-362    #           '#627f8c', # 2C
-363    #           '#c85a5a', # 3A
-364    #           '#985356'] # , # 3B
-365    #           # '#574249'] # 3C
-366
-367    all_colors = {'1A': '#e8e8e8',
-368                  '1B': '#b0d5df',
-369                  '1C': '#64acbe',
-370                  '2A': '#e4acac',
-371                  '2B': '#ad9ea5',
-372                  '2C': '#627f8c',
-373                  '3A': '#c85a5a',
-374                  '3B': '#985356',
-375                  '3C': '#574249'}
-376
-377    all_colors = {'1A': '#dddddd',
-378                  '1B': '#dd7c8a',
-379                  '1C': '#cc0024',
-380                  '2A': '#7bb3d1',
-381                  '2B': '#8d6c8f',
-382                  '2C': '#8a274a',
-383                  '3A': '#016eae',
-384                  '3B': '#4a4779',
-385                  '3C': '#4b264d'}
-386
-387    # Set of colors matching the elements of Bi_Class
-388    # We have to exclude those that did not come up in the data
-389    available_classes = data['Bi_Class'].value_counts().sort_index().index
-390    available_colors = [all_colors[i] for i in available_classes]
-391    return list(all_colors.values()), available_colors
-
- - - - -
-
- -
- - def - bin_data(data, x_name, y_name, scale, print_statistics=True): - - - -
- -
394def bin_data(data, x_name, y_name, scale, print_statistics=True):
-395    if scale:
-396        # Scale the data to be between 0 and 1
-397        # data[x_name] = (data[x_name] - data[x_name].min()) / \
-398        #     (data[x_name].max() - data[x_name].min())
-399        # data[y_name] = (data[y_name] - data[y_name].min()) / \
-400        #     (data[y_name].max() - data[y_name].min())
-401        # Scale the data with MinMaxScaler
-402        scaler = MinMaxScaler()
-403        data[x_name] = scaler.fit_transform(data[x_name].values.reshape(-1, 1))
-404        data[y_name] = scaler.fit_transform(data[y_name].values.reshape(-1, 1))
-405
-406    # Define the bins
-407    bins = [0, 0.33, 0.66, 1]
-408
-409    # Bin the first variable - x
-410    data['Var1_Class'] = pd.cut(data[x_name], bins=bins, include_lowest=True)
-411    data['Var1_Class'] = data['Var1_Class'].astype('str')
-412
-413    # Bin the second variable - y
-414    data['Var2_Class'] = pd.cut(data[y_name], bins=bins, include_lowest=True)
-415    data['Var2_Class'] = data['Var2_Class'].astype('str')
-416
-417    # Code created x bins to 1, 2, 3
-418    x_class_codes = np.arange(1, len(bins))
-419    d = dict(
-420        zip(data['Var1_Class'].value_counts().sort_index().index, x_class_codes))
-421    data['Var1_Class'] = data['Var1_Class'].replace(d)
-422
-423    # Code created y bins to A, B, C
-424    y_class_codes = ['A', 'B', 'C']
-425    d = dict(
-426        zip(data['Var2_Class'].value_counts().sort_index().index, y_class_codes))
-427    data['Var2_Class'] = data['Var2_Class'].replace(d)
-428
-429    # Combine x and y codes to create Bi_Class
-430    data['Bi_Class'] = data['Var1_Class'].astype('str') + data['Var2_Class']
-431
-432    if print_statistics:
-433        print('Number of unique elements in Var1_Class =',
-434              len(data['Var1_Class'].unique()))
-435        print('Number of unique elements in Var2_Class =',
-436              len(data['Var2_Class'].unique()))
-437        print('Number of unique elements in Bi_Class =',
-438              len(data['Bi_Class'].unique()))
-439    return data
-
- - - - -
-
- - \ No newline at end of file diff --git a/docs/src/data/write.html b/docs/src/data/write.html deleted file mode 100644 index 95bcf59..0000000 --- a/docs/src/data/write.html +++ /dev/null @@ -1,992 +0,0 @@ - - - - - - - src.data.write API documentation - - - - - - - - - -
-
-

-src.data.write

- - - - - - -
  1# Specify which outcomes to store in each run of the simulation model
-  2
-  3import pandas as pd
-  4import numpy as np
-  5
-  6
-  7def add_columns(households: pd.DataFrame, affected_households: pd.DataFrame) -> pd.DataFrame:
-  8    '''Add columns/outcomes of interest from `affected households` to the `households` dataframe.'''
-  9
- 10    # Outcomes of interest from affected households
- 11    outcomes_of_interest: list = [
- 12        'consumption_loss',
- 13        'consumption_loss_NPV',
- 14        'c_t',
- 15        'c_t_unaffected',
- 16        'recovery_rate',
- 17        'weeks_pov']
- 18
- 19    # Merge affected households onto households
- 20    columns = ['hhid'] + outcomes_of_interest
- 21    households = pd.merge(
- 22        households, affected_households[columns], on='hhid', how='left')
- 23    return households
- 24
- 25
- 26def get_outcomes(households, event_damage, total_asset_stock, expected_loss_fraction, average_productivity, n_years) -> dict:
- 27    '''Calculate outcomes of interest from the simulation model.
- 28
- 29    Args:
- 30        households (pd.DataFrame): Households data frame.
- 31        event_damage (float): Event damage.
- 32        total_asset_stock (float): Total asset stock.
- 33        expected_loss_fraction (float): Expected loss fraction.
- 34        average_productivity (float): Average productivity.
- 35        n_years (float): Number of years to consider for calculations (same as for optimization algorithm).
- 36
- 37    Returns:
- 38        dict: Outcomes of interest.
- 39    '''
- 40    # Save some outcomes for verification
- 41    total_population = households['popwgt'].sum()
- 42    total_asset_in_survey = households['total_asset_in_survey'].iloc[0]
- 43
- 44    # Actual outcomes of interest
- 45    affected_households = households[households['is_affected'] == True]
- 46    total_asset_loss = affected_households[[
- 47        'keff', 'v', 'popwgt']].prod(axis=1).sum()
- 48    total_consumption_loss = affected_households[[
- 49        'consumption_loss_NPV', 'popwgt']].prod(axis=1).sum()
- 50    n_affected_people = affected_households['popwgt'].sum()
- 51    annual_average_consumption = (
- 52        households['aeexp'] * households['popwgt']).sum() / households['popwgt'].sum()
- 53    recovery_rate = households['recovery_rate'].mean()
- 54
- 55    # * Poverty line is different across replications
- 56    poverty_line_adjusted = households['poverty_line_adjusted'].values[0]
- 57
- 58    # Get PML, its the same across replications and stored in households
- 59    pml = households['pml'].iloc[0]
- 60
- 61    # Run statistics
- 62    no_affected_households = 0
- 63    zero_consumption_loss = 0
- 64
- 65    # * Some runs give no affected households and we will skip these
- 66    if len(affected_households) == 0:
- 67        no_affected_households += 1
- 68        pass
- 69
- 70    # * Sometimes households are affected but they have no consumption loss
- 71    if affected_households['consumption_loss_NPV'].sum() == 0:
- 72        zero_consumption_loss += 1
- 73        pass
- 74
- 75    # Calculate outcomes of interest
- 76    n_poor_initial, n_new_poor, n_poor_affected, poor_initial, new_poor = find_poor(
- 77        households, poverty_line_adjusted, n_years)
- 78
- 79    years_in_poverty = get_people_by_years_in_poverty(new_poor)
- 80
- 81    initial_poverty_gap, new_poverty_gap = calculate_poverty_gap(
- 82        poor_initial, new_poor, poverty_line_adjusted, n_years)
- 83
- 84    annual_average_consumption_loss, annual_average_consumption_loss_pct = calculate_average_annual_consumption_loss(
- 85        affected_households, n_years)
- 86
- 87    r = calculate_resilience(
- 88        affected_households, pml)
- 89
- 90    return {
- 91        'total_population': total_population,
- 92        'total_asset_loss': total_asset_loss,
- 93        'total_consumption_loss': total_consumption_loss,
- 94        'event_damage': event_damage,
- 95        'total_asset_stock': total_asset_stock,
- 96        'average_productivity': average_productivity,
- 97        'total_asset_in_survey': total_asset_in_survey,
- 98        'expected_loss_fraction': expected_loss_fraction,
- 99        'n_affected_people': n_affected_people,
-100        'annual_average_consumption': annual_average_consumption,
-101        'poverty_line_adjusted': poverty_line_adjusted,
-102        'pml': pml,
-103        'n_poor_initial': n_poor_initial,
-104        'n_poor_affected': n_poor_affected,
-105        'n_new_poor': n_new_poor,
-106        'initial_poverty_gap': initial_poverty_gap,
-107        'new_poverty_gap': new_poverty_gap,
-108        'annual_average_consumption_loss': annual_average_consumption_loss,
-109        'annual_average_consumption_loss_pct': annual_average_consumption_loss_pct,
-110        'r': r,
-111        'recovery_rate': recovery_rate,
-112        'years_in_poverty': years_in_poverty
-113        # 'n_resilience_more_than_1' : n_resilience_more_than_1
-114    }
-115
-116
-117def find_poor(households: pd.DataFrame, poverty_line: float, n_years: int) -> tuple:
-118    '''Get the poor at the beginning of the simulation and the poor at the end of the simulation
-119
-120    Args:
-121        households (pd.DataFrame): Household dataframe
-122        poverty_line (float): Poverty line
-123
-124    Returns:
-125        tuple: Number of poor at the beginning of the simulation, number of new poor at the end of the simulation, and the new poor dataframe
-126    '''
-127    # First, find the poor at the beginning of the simulation
-128    poor_initial = households[households['is_poor'] == True]
-129    n_poor_initial = round(poor_initial['popwgt'].sum())
-130    n_poor_affected = round(
-131        poor_initial[poor_initial['is_affected'] == True]['popwgt'].sum())
-132
-133    # Second, find the new poor at the end of the simulation (`n_years`)
-134    not_poor = households[households['is_poor'] == False]
-135    not_poor_affected = not_poor[not_poor['is_affected'] == True]
-136    x = not_poor_affected['aeexp'] - \
-137        not_poor_affected['consumption_loss_NPV'] / n_years
-138    new_poor = not_poor_affected.loc[x < poverty_line, :]
-139    n_new_poor = round(new_poor['popwgt'].sum())
-140
-141    return n_poor_initial, n_new_poor, n_poor_affected, poor_initial, new_poor
-142
-143
-144def get_people_by_years_in_poverty(new_poor: pd.DataFrame) -> dict:
-145    '''Get the number of people in poverty for each year in poverty.
-146
-147    Args:
-148        new_poor (pd.DataFrame): New poor dataframe
-149
-150    Returns:
-151        dict: Number of people in poverty for each year in poverty
-152    '''
-153    new_poor = new_poor.assign(
-154        years_in_poverty=new_poor['weeks_pov'] // 52)
-155    d = {}
-156    # !: This cannot be higher > n_years
-157    longest_years_in_poverty = 10
-158    for i in range(longest_years_in_poverty):
-159        d[i] = round(new_poor[new_poor['years_in_poverty'] == i]
-160                     ['popwgt'].sum())
-161    d[longest_years_in_poverty] = round(
-162        new_poor[new_poor['years_in_poverty'] >= longest_years_in_poverty]['popwgt'].sum())
-163
-164    return d
-165
-166
-167def calculate_poverty_gap(poor_initial: pd.DataFrame, new_poor: pd.DataFrame, poverty_line: float, n_years: int) -> tuple:
-168    '''Calculate the poverty gap at the beginning and at the end of the simulation.
-169
-170    Args:
-171        poor_initial (pd.DataFrame): Poor at the beginning of the simulation
-172        new_poor (pd.DataFrame): New poor at the end of the simulation
-173        poverty_line (float): Poverty line
-174        n_years (int): Number of years of the optimization algorithm
-175
-176    Returns:
-177        tuple: Poverty gap at the beginning and at the end of the simulation
-178
-179    Raises:
-180        Exception: If the index is duplicated
-181        Exception: If the poverty gap is greater than 1
-182    '''
-183    # First, get the average expenditure of the poor at the beginning of the simulation
-184    average_expenditure_poor_initial = (
-185        poor_initial['aeexp'] * poor_initial['popwgt']).sum() / poor_initial['popwgt'].sum()
-186    initial_poverty_gap = (
-187        poverty_line - average_expenditure_poor_initial) / poverty_line
-188
-189    new_poor['aeexp'] = new_poor['aeexp'] - \
-190        new_poor['consumption_loss_NPV'] / n_years
-191
-192    all_poor = pd.concat([poor_initial, new_poor])
-193
-194    # Now, get the average expenditure of the poor at the end of the simulation
-195    average_expenditure_poor_new = (
-196        all_poor['aeexp'] * all_poor['popwgt']).sum() / all_poor['popwgt'].sum()
-197    new_poverty_gap = (
-198        poverty_line - average_expenditure_poor_new) / poverty_line
-199
-200    # Poverty gap cannot be greater than 1
-201    if new_poverty_gap > 1 or initial_poverty_gap > 1:
-202        raise Exception('Poverty gap is greater than 1')
-203
-204    return initial_poverty_gap, new_poverty_gap
-205
-206
-207def calculate_average_annual_consumption_loss(affected_households: pd.DataFrame, n_years: int) -> tuple:
-208    '''Get the average annual consumption loss and the average annual consumption loss as a percentage of average annual consumption.
-209
-210    Args:
-211        affected_households (pd.DataFrame): Affected households dataframe
-212        n_years (int): Number of years of the optimization algorithm
-213
-214    Returns:
-215        tuple: Average annual consumption loss and average annual consumption loss as a percentage of average annual consumption
-216
-217    Raises:
-218        Exception: If the average annual consumption loss is greater than 1
-219    '''
-220
-221    if len(affected_households) == 0:
-222        return np.nan, np.nan
-223
-224    # Annual consumption loss
-225    annual_consumption_loss = (
-226        affected_households['consumption_loss_NPV'].div(n_years).multiply(affected_households['popwgt'])).sum()
-227    
-228    # Weighted average
-229    annual_average_consumption_loss = annual_consumption_loss / \
-230        affected_households['popwgt'].sum()
-231
-232    # Annual average consumption
-233    annual_average_consumption = (
-234        affected_households['aeexp'] * affected_households['popwgt']).sum() / \
-235        affected_households['popwgt'].sum()
-236
-237    # Annual average consumption loss as a percentage of average annual consumption
-238    annual_average_consumption_loss_pct = annual_average_consumption_loss / \
-239        annual_average_consumption
-240
-241    if annual_average_consumption_loss_pct > 1:
-242        raise Exception(
-243            'Annual average consumption loss is greater than 1')
-244
-245    return annual_average_consumption_loss, annual_average_consumption_loss_pct
-246
-247
-248def calculate_resilience(affected_households: pd.DataFrame, pml: float,
-249                         # n_resilience_more_than_1: int
-250                         ) -> tuple:
-251    '''Calculate the resilience of the affected households.
-252
-253    Args:
-254        affected_households (pd.DataFrame): Affected households dataframe
-255        pml (float): Probable maximum loss
-256
-257    Returns:
-258        tuple: Resilience and number of times resilience is greater than 1
-259
-260    Raises:
-261        Exception: If the total consumption loss is 0
-262    '''
-263    total_consumption_loss = (
-264        affected_households['consumption_loss_NPV'] * affected_households['popwgt']).sum()
-265
-266    if total_consumption_loss == 0:
-267        # raise Exception('Total consumption loss is 0')
-268        r = np.nan
-269    else:
-270        r = pml / total_consumption_loss
-271
-272    # !: Sometimes resilience is greater than 1
-273    # We will set it to 1 then
-274    # if r > 5:
-275    #     r = 1
-276    #     # raise Exception('Resilience is greater than 1')
-277    #     # n_resilience_more_than_1 += 1
-278    #     # continue
-279    return r
-
- - -
-
- -
- - def - add_columns( households: pandas.core.frame.DataFrame, affected_households: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame: - - - -
- -
 8def add_columns(households: pd.DataFrame, affected_households: pd.DataFrame) -> pd.DataFrame:
- 9    '''Add columns/outcomes of interest from `affected households` to the `households` dataframe.'''
-10
-11    # Outcomes of interest from affected households
-12    outcomes_of_interest: list = [
-13        'consumption_loss',
-14        'consumption_loss_NPV',
-15        'c_t',
-16        'c_t_unaffected',
-17        'recovery_rate',
-18        'weeks_pov']
-19
-20    # Merge affected households onto households
-21    columns = ['hhid'] + outcomes_of_interest
-22    households = pd.merge(
-23        households, affected_households[columns], on='hhid', how='left')
-24    return households
-
- - -

Add columns/outcomes of interest from affected households to the households dataframe.

-
- - -
-
- -
- - def - get_outcomes( households, event_damage, total_asset_stock, expected_loss_fraction, average_productivity, n_years) -> dict: - - - -
- -
 27def get_outcomes(households, event_damage, total_asset_stock, expected_loss_fraction, average_productivity, n_years) -> dict:
- 28    '''Calculate outcomes of interest from the simulation model.
- 29
- 30    Args:
- 31        households (pd.DataFrame): Households data frame.
- 32        event_damage (float): Event damage.
- 33        total_asset_stock (float): Total asset stock.
- 34        expected_loss_fraction (float): Expected loss fraction.
- 35        average_productivity (float): Average productivity.
- 36        n_years (float): Number of years to consider for calculations (same as for optimization algorithm).
- 37
- 38    Returns:
- 39        dict: Outcomes of interest.
- 40    '''
- 41    # Save some outcomes for verification
- 42    total_population = households['popwgt'].sum()
- 43    total_asset_in_survey = households['total_asset_in_survey'].iloc[0]
- 44
- 45    # Actual outcomes of interest
- 46    affected_households = households[households['is_affected'] == True]
- 47    total_asset_loss = affected_households[[
- 48        'keff', 'v', 'popwgt']].prod(axis=1).sum()
- 49    total_consumption_loss = affected_households[[
- 50        'consumption_loss_NPV', 'popwgt']].prod(axis=1).sum()
- 51    n_affected_people = affected_households['popwgt'].sum()
- 52    annual_average_consumption = (
- 53        households['aeexp'] * households['popwgt']).sum() / households['popwgt'].sum()
- 54    recovery_rate = households['recovery_rate'].mean()
- 55
- 56    # * Poverty line is different across replications
- 57    poverty_line_adjusted = households['poverty_line_adjusted'].values[0]
- 58
- 59    # Get PML, its the same across replications and stored in households
- 60    pml = households['pml'].iloc[0]
- 61
- 62    # Run statistics
- 63    no_affected_households = 0
- 64    zero_consumption_loss = 0
- 65
- 66    # * Some runs give no affected households and we will skip these
- 67    if len(affected_households) == 0:
- 68        no_affected_households += 1
- 69        pass
- 70
- 71    # * Sometimes households are affected but they have no consumption loss
- 72    if affected_households['consumption_loss_NPV'].sum() == 0:
- 73        zero_consumption_loss += 1
- 74        pass
- 75
- 76    # Calculate outcomes of interest
- 77    n_poor_initial, n_new_poor, n_poor_affected, poor_initial, new_poor = find_poor(
- 78        households, poverty_line_adjusted, n_years)
- 79
- 80    years_in_poverty = get_people_by_years_in_poverty(new_poor)
- 81
- 82    initial_poverty_gap, new_poverty_gap = calculate_poverty_gap(
- 83        poor_initial, new_poor, poverty_line_adjusted, n_years)
- 84
- 85    annual_average_consumption_loss, annual_average_consumption_loss_pct = calculate_average_annual_consumption_loss(
- 86        affected_households, n_years)
- 87
- 88    r = calculate_resilience(
- 89        affected_households, pml)
- 90
- 91    return {
- 92        'total_population': total_population,
- 93        'total_asset_loss': total_asset_loss,
- 94        'total_consumption_loss': total_consumption_loss,
- 95        'event_damage': event_damage,
- 96        'total_asset_stock': total_asset_stock,
- 97        'average_productivity': average_productivity,
- 98        'total_asset_in_survey': total_asset_in_survey,
- 99        'expected_loss_fraction': expected_loss_fraction,
-100        'n_affected_people': n_affected_people,
-101        'annual_average_consumption': annual_average_consumption,
-102        'poverty_line_adjusted': poverty_line_adjusted,
-103        'pml': pml,
-104        'n_poor_initial': n_poor_initial,
-105        'n_poor_affected': n_poor_affected,
-106        'n_new_poor': n_new_poor,
-107        'initial_poverty_gap': initial_poverty_gap,
-108        'new_poverty_gap': new_poverty_gap,
-109        'annual_average_consumption_loss': annual_average_consumption_loss,
-110        'annual_average_consumption_loss_pct': annual_average_consumption_loss_pct,
-111        'r': r,
-112        'recovery_rate': recovery_rate,
-113        'years_in_poverty': years_in_poverty
-114        # 'n_resilience_more_than_1' : n_resilience_more_than_1
-115    }
-
- - -

Calculate outcomes of interest from the simulation model.

- -

Args: - households (pd.DataFrame): Households data frame. - event_damage (float): Event damage. - total_asset_stock (float): Total asset stock. - expected_loss_fraction (float): Expected loss fraction. - average_productivity (float): Average productivity. - n_years (float): Number of years to consider for calculations (same as for optimization algorithm).

- -

Returns: - dict: Outcomes of interest.

-
- - -
-
- -
- - def - find_poor( households: pandas.core.frame.DataFrame, poverty_line: float, n_years: int) -> tuple: - - - -
- -
118def find_poor(households: pd.DataFrame, poverty_line: float, n_years: int) -> tuple:
-119    '''Get the poor at the beginning of the simulation and the poor at the end of the simulation
-120
-121    Args:
-122        households (pd.DataFrame): Household dataframe
-123        poverty_line (float): Poverty line
-124
-125    Returns:
-126        tuple: Number of poor at the beginning of the simulation, number of new poor at the end of the simulation, and the new poor dataframe
-127    '''
-128    # First, find the poor at the beginning of the simulation
-129    poor_initial = households[households['is_poor'] == True]
-130    n_poor_initial = round(poor_initial['popwgt'].sum())
-131    n_poor_affected = round(
-132        poor_initial[poor_initial['is_affected'] == True]['popwgt'].sum())
-133
-134    # Second, find the new poor at the end of the simulation (`n_years`)
-135    not_poor = households[households['is_poor'] == False]
-136    not_poor_affected = not_poor[not_poor['is_affected'] == True]
-137    x = not_poor_affected['aeexp'] - \
-138        not_poor_affected['consumption_loss_NPV'] / n_years
-139    new_poor = not_poor_affected.loc[x < poverty_line, :]
-140    n_new_poor = round(new_poor['popwgt'].sum())
-141
-142    return n_poor_initial, n_new_poor, n_poor_affected, poor_initial, new_poor
-
- - -

Get the poor at the beginning of the simulation and the poor at the end of the simulation

- -

Args: - households (pd.DataFrame): Household dataframe - poverty_line (float): Poverty line

- -

Returns: - tuple: Number of poor at the beginning of the simulation, number of new poor at the end of the simulation, and the new poor dataframe

-
- - -
-
- -
- - def - get_people_by_years_in_poverty(new_poor: pandas.core.frame.DataFrame) -> dict: - - - -
- -
145def get_people_by_years_in_poverty(new_poor: pd.DataFrame) -> dict:
-146    '''Get the number of people in poverty for each year in poverty.
-147
-148    Args:
-149        new_poor (pd.DataFrame): New poor dataframe
-150
-151    Returns:
-152        dict: Number of people in poverty for each year in poverty
-153    '''
-154    new_poor = new_poor.assign(
-155        years_in_poverty=new_poor['weeks_pov'] // 52)
-156    d = {}
-157    # !: This cannot be higher > n_years
-158    longest_years_in_poverty = 10
-159    for i in range(longest_years_in_poverty):
-160        d[i] = round(new_poor[new_poor['years_in_poverty'] == i]
-161                     ['popwgt'].sum())
-162    d[longest_years_in_poverty] = round(
-163        new_poor[new_poor['years_in_poverty'] >= longest_years_in_poverty]['popwgt'].sum())
-164
-165    return d
-
- - -

Get the number of people in poverty for each year in poverty.

- -

Args: - new_poor (pd.DataFrame): New poor dataframe

- -

Returns: - dict: Number of people in poverty for each year in poverty

-
- - -
-
- -
- - def - calculate_poverty_gap( poor_initial: pandas.core.frame.DataFrame, new_poor: pandas.core.frame.DataFrame, poverty_line: float, n_years: int) -> tuple: - - - -
- -
168def calculate_poverty_gap(poor_initial: pd.DataFrame, new_poor: pd.DataFrame, poverty_line: float, n_years: int) -> tuple:
-169    '''Calculate the poverty gap at the beginning and at the end of the simulation.
-170
-171    Args:
-172        poor_initial (pd.DataFrame): Poor at the beginning of the simulation
-173        new_poor (pd.DataFrame): New poor at the end of the simulation
-174        poverty_line (float): Poverty line
-175        n_years (int): Number of years of the optimization algorithm
-176
-177    Returns:
-178        tuple: Poverty gap at the beginning and at the end of the simulation
-179
-180    Raises:
-181        Exception: If the index is duplicated
-182        Exception: If the poverty gap is greater than 1
-183    '''
-184    # First, get the average expenditure of the poor at the beginning of the simulation
-185    average_expenditure_poor_initial = (
-186        poor_initial['aeexp'] * poor_initial['popwgt']).sum() / poor_initial['popwgt'].sum()
-187    initial_poverty_gap = (
-188        poverty_line - average_expenditure_poor_initial) / poverty_line
-189
-190    new_poor['aeexp'] = new_poor['aeexp'] - \
-191        new_poor['consumption_loss_NPV'] / n_years
-192
-193    all_poor = pd.concat([poor_initial, new_poor])
-194
-195    # Now, get the average expenditure of the poor at the end of the simulation
-196    average_expenditure_poor_new = (
-197        all_poor['aeexp'] * all_poor['popwgt']).sum() / all_poor['popwgt'].sum()
-198    new_poverty_gap = (
-199        poverty_line - average_expenditure_poor_new) / poverty_line
-200
-201    # Poverty gap cannot be greater than 1
-202    if new_poverty_gap > 1 or initial_poverty_gap > 1:
-203        raise Exception('Poverty gap is greater than 1')
-204
-205    return initial_poverty_gap, new_poverty_gap
-
- - -

Calculate the poverty gap at the beginning and at the end of the simulation.

- -

Args: - poor_initial (pd.DataFrame): Poor at the beginning of the simulation - new_poor (pd.DataFrame): New poor at the end of the simulation - poverty_line (float): Poverty line - n_years (int): Number of years of the optimization algorithm

- -

Returns: - tuple: Poverty gap at the beginning and at the end of the simulation

- -

Raises: - Exception: If the index is duplicated - Exception: If the poverty gap is greater than 1

-
- - -
-
- -
- - def - calculate_average_annual_consumption_loss(affected_households: pandas.core.frame.DataFrame, n_years: int) -> tuple: - - - -
- -
208def calculate_average_annual_consumption_loss(affected_households: pd.DataFrame, n_years: int) -> tuple:
-209    '''Get the average annual consumption loss and the average annual consumption loss as a percentage of average annual consumption.
-210
-211    Args:
-212        affected_households (pd.DataFrame): Affected households dataframe
-213        n_years (int): Number of years of the optimization algorithm
-214
-215    Returns:
-216        tuple: Average annual consumption loss and average annual consumption loss as a percentage of average annual consumption
-217
-218    Raises:
-219        Exception: If the average annual consumption loss is greater than 1
-220    '''
-221
-222    if len(affected_households) == 0:
-223        return np.nan, np.nan
-224
-225    # Annual consumption loss
-226    annual_consumption_loss = (
-227        affected_households['consumption_loss_NPV'].div(n_years).multiply(affected_households['popwgt'])).sum()
-228    
-229    # Weighted average
-230    annual_average_consumption_loss = annual_consumption_loss / \
-231        affected_households['popwgt'].sum()
-232
-233    # Annual average consumption
-234    annual_average_consumption = (
-235        affected_households['aeexp'] * affected_households['popwgt']).sum() / \
-236        affected_households['popwgt'].sum()
-237
-238    # Annual average consumption loss as a percentage of average annual consumption
-239    annual_average_consumption_loss_pct = annual_average_consumption_loss / \
-240        annual_average_consumption
-241
-242    if annual_average_consumption_loss_pct > 1:
-243        raise Exception(
-244            'Annual average consumption loss is greater than 1')
-245
-246    return annual_average_consumption_loss, annual_average_consumption_loss_pct
-
- - -

Get the average annual consumption loss and the average annual consumption loss as a percentage of average annual consumption.

- -

Args: - affected_households (pd.DataFrame): Affected households dataframe - n_years (int): Number of years of the optimization algorithm

- -

Returns: - tuple: Average annual consumption loss and average annual consumption loss as a percentage of average annual consumption

- -

Raises: - Exception: If the average annual consumption loss is greater than 1

-
- - -
-
- -
- - def - calculate_resilience(affected_households: pandas.core.frame.DataFrame, pml: float) -> tuple: - - - -
- -
249def calculate_resilience(affected_households: pd.DataFrame, pml: float,
-250                         # n_resilience_more_than_1: int
-251                         ) -> tuple:
-252    '''Calculate the resilience of the affected households.
-253
-254    Args:
-255        affected_households (pd.DataFrame): Affected households dataframe
-256        pml (float): Probable maximum loss
-257
-258    Returns:
-259        tuple: Resilience and number of times resilience is greater than 1
-260
-261    Raises:
-262        Exception: If the total consumption loss is 0
-263    '''
-264    total_consumption_loss = (
-265        affected_households['consumption_loss_NPV'] * affected_households['popwgt']).sum()
-266
-267    if total_consumption_loss == 0:
-268        # raise Exception('Total consumption loss is 0')
-269        r = np.nan
-270    else:
-271        r = pml / total_consumption_loss
-272
-273    # !: Sometimes resilience is greater than 1
-274    # We will set it to 1 then
-275    # if r > 5:
-276    #     r = 1
-277    #     # raise Exception('Resilience is greater than 1')
-278    #     # n_resilience_more_than_1 += 1
-279    #     # continue
-280    return r
-
- - -

Calculate the resilience of the affected households.

- -

Args: - affected_households (pd.DataFrame): Affected households dataframe - pml (float): Probable maximum loss

- -

Returns: - tuple: Resilience and number of times resilience is greater than 1

- -

Raises: - Exception: If the total consumption loss is 0

-
- - -
-
- - \ No newline at end of file diff --git a/docs/src/model.html b/docs/src/model.html deleted file mode 100644 index 17d685e..0000000 --- a/docs/src/model.html +++ /dev/null @@ -1,580 +0,0 @@ - - - - - - - src.model API documentation - - - - - - - - - -
-
-

-src.model

- - - - - - -
  1# The model function pipeline, which is called by the ema_workbench in `__main__.py`.
-  2
-  3import pandas as pd
-  4import numpy as np
-  5import random
-  6import matplotlib.pyplot as plt
-  7from src.data.read import *
-  8from src.data.write import *
-  9from src.modules.optimize import *
- 10from src.modules.households import *
- 11
- 12
- 13def initialize_model(country: str, min_households: int) -> tuple:
- 14    '''Initialize the model by reading household survey and asset damage files.
- 15
- 16    Args:
- 17        country (str): Country name.
- 18        min_households (int): Minimum number of households that we need to have in a sample to be representative.
- 19
- 20    Returns:
- 21        tuple: Household survey and asset damage files.
- 22    '''
- 23
- 24    # Read household survey and asset damage files
- 25    household_survey = read_household_survey(country)
- 26    all_damage = read_asset_damage(country)
- 27
- 28    # Duplicate households to have at least `min_households` households
- 29    household_survey = duplicate_households(household_survey, min_households)
- 30
- 31    return household_survey, all_damage
- 32
- 33
- 34def run_model(**kwargs):
- 35    '''Run the model.'''
- 36    # ------------------------- Read the model parameters ------------------------ #
- 37    country = kwargs['country']
- 38    scale = kwargs['scale']
- 39    districts = kwargs['districts']
- 40    min_households = kwargs['min_households']
- 41
- 42    # Read household survey and asset damage files
- 43    household_survey, all_damage = initialize_model(
- 44        country, min_households)
- 45
- 46    # Case study constants
- 47    return_period = kwargs['return_period']
- 48    poverty_line = kwargs['poverty_line']
- 49    indigence_line = kwargs['indigence_line']
- 50    saving_rate = kwargs['saving_rate']
- 51    is_vulnerability_random = kwargs['is_vulnerability_random']
- 52    n_years = kwargs['n_years']  # number of years in optimization algorithm
- 53
- 54    # Model constants
- 55    estimate_savings_params = kwargs['estimate_savings_params']
- 56    set_vulnerability_params = kwargs['set_vulnerability_params']
- 57    calculate_exposure_params = kwargs['calculate_exposure_params']
- 58    determine_affected_params = kwargs['determine_affected_params']
- 59
- 60    # Uncertainties
- 61    poverty_bias = kwargs['poverty_bias']
- 62    consumption_utility = kwargs['consumption_utility']
- 63    discount_rate = kwargs['discount_rate']
- 64    optimization_timestep = kwargs['optimization_timestep']
- 65    income_and_expenditure_growth = kwargs['income_and_expenditure_growth']
- 66
- 67    # Policy levers
- 68    try:
- 69        my_policy = kwargs['my_policy']
- 70    except:
- 71        # If a policy is not provided, use the default policy
- 72        my_policy = 'all+0'
- 73
- 74    add_income_loss = kwargs['add_income_loss']
- 75
- 76    # Outcomes
- 77    # Store outcomes in a dictionary, where the key is a district and value is a dictionary of outcomes
- 78    outcomes = {}
- 79
- 80    # Print statistics for debugging
- 81    print_statistics = kwargs['print_statistics']
- 82
- 83    # Fix random seed for reproducibility
- 84    random_seed = kwargs['random_seed']
- 85    random.seed(random_seed)
- 86    np.random.seed(random_seed)
- 87
- 88    # PIPELINE:
- 89    # 1. Load all damage
- 90    # 2. Load household survey
- 91    # 3. Select district
- 92    # 4. Get event damage, total asset stock, expected loss fraction
- 93    # 5. Calculate average productivity
- 94    # 6. Adjust assets and expenditure
- 95    # 7. Calculate PML
- 96    # 8. Estimate savings
- 97    # 9. Set vulnerability
- 98    # 10. Calculate exposure
- 99    # 11. Determine affected
-100    # 12. Apply individual policy
-101    # 13. Run optimization
-102    # 14. Integrate wellbeing
-103    # 15. Prepare outcomes
-104    # 16. Get outcomes
-105
-106    # ---------------------- Run the model for each district --------------------- #
-107
-108    for district in districts:
-109        # Read household survey and asset damage files for a specific district
-110        event_damage, total_asset_stock, expected_loss_fraction = get_asset_damage(
-111            all_damage, scale, district, return_period, print_statistics)
-112
-113        households = select_district(household_survey, district)
-114
-115        average_productivity = calculate_average_productivity(
-116            households, print_statistics)
-117
-118        # Model the impact of a disaster on households
-119        households = (adjust_assets_and_expenditure(households, total_asset_stock, poverty_line, indigence_line, print_statistics)
-120                      .pipe(calculate_pml, expected_loss_fraction, print_statistics)
-121                      .pipe(estimate_savings, saving_rate, estimate_savings_params)
-122                      .pipe(set_vulnerability, is_vulnerability_random, set_vulnerability_params)
-123                      .pipe(calculate_exposure, poverty_bias, calculate_exposure_params, print_statistics)
-124                      .pipe(determine_affected, determine_affected_params))
-125
-126        # households['aesav'].hist()
-127        # plt.show()
-128
-129        # Apply a policy
-130        households, affected_households = apply_individual_policy(
-131            households, my_policy)
-132
-133        # Calculate the impact and recovery
-134        # cash_transfer = {52: 1000, 208: 5000}
-135        cash_transfer = {}
-136        affected_households = (run_optimization(affected_households, consumption_utility, discount_rate, average_productivity, optimization_timestep, n_years)
-137                               .pipe(integrate_wellbeing, consumption_utility, discount_rate, income_and_expenditure_growth, average_productivity, poverty_line, n_years, add_income_loss, cash_transfer))
-138
-139        # Add columns of affected households to the original households dataframe
-140        households = add_columns(households, affected_households)
-141        # Get outcomes
-142        array_outcomes = np.array(list(get_outcomes(
-143            households, event_damage, total_asset_stock, expected_loss_fraction, average_productivity, n_years).values()))
-144
-145        # * To check whether we have different households affected in different runs
-146        # if district == 'Castries':
-147        #     affected_households.to_csv(f'affected_households_{random_seed}.csv')
-148
-149        outcomes[district] = array_outcomes
-150
-151    return outcomes
-
- - -
-
- -
- - def - initialize_model(country: str, min_households: int) -> tuple: - - - -
- -
14def initialize_model(country: str, min_households: int) -> tuple:
-15    '''Initialize the model by reading household survey and asset damage files.
-16
-17    Args:
-18        country (str): Country name.
-19        min_households (int): Minimum number of households that we need to have in a sample to be representative.
-20
-21    Returns:
-22        tuple: Household survey and asset damage files.
-23    '''
-24
-25    # Read household survey and asset damage files
-26    household_survey = read_household_survey(country)
-27    all_damage = read_asset_damage(country)
-28
-29    # Duplicate households to have at least `min_households` households
-30    household_survey = duplicate_households(household_survey, min_households)
-31
-32    return household_survey, all_damage
-
- - -

Initialize the model by reading household survey and asset damage files.

- -

Args: - country (str): Country name. - min_households (int): Minimum number of households that we need to have in a sample to be representative.

- -

Returns: - tuple: Household survey and asset damage files.

-
- - -
-
- -
- - def - run_model(**kwargs): - - - -
- -
 35def run_model(**kwargs):
- 36    '''Run the model.'''
- 37    # ------------------------- Read the model parameters ------------------------ #
- 38    country = kwargs['country']
- 39    scale = kwargs['scale']
- 40    districts = kwargs['districts']
- 41    min_households = kwargs['min_households']
- 42
- 43    # Read household survey and asset damage files
- 44    household_survey, all_damage = initialize_model(
- 45        country, min_households)
- 46
- 47    # Case study constants
- 48    return_period = kwargs['return_period']
- 49    poverty_line = kwargs['poverty_line']
- 50    indigence_line = kwargs['indigence_line']
- 51    saving_rate = kwargs['saving_rate']
- 52    is_vulnerability_random = kwargs['is_vulnerability_random']
- 53    n_years = kwargs['n_years']  # number of years in optimization algorithm
- 54
- 55    # Model constants
- 56    estimate_savings_params = kwargs['estimate_savings_params']
- 57    set_vulnerability_params = kwargs['set_vulnerability_params']
- 58    calculate_exposure_params = kwargs['calculate_exposure_params']
- 59    determine_affected_params = kwargs['determine_affected_params']
- 60
- 61    # Uncertainties
- 62    poverty_bias = kwargs['poverty_bias']
- 63    consumption_utility = kwargs['consumption_utility']
- 64    discount_rate = kwargs['discount_rate']
- 65    optimization_timestep = kwargs['optimization_timestep']
- 66    income_and_expenditure_growth = kwargs['income_and_expenditure_growth']
- 67
- 68    # Policy levers
- 69    try:
- 70        my_policy = kwargs['my_policy']
- 71    except:
- 72        # If a policy is not provided, use the default policy
- 73        my_policy = 'all+0'
- 74
- 75    add_income_loss = kwargs['add_income_loss']
- 76
- 77    # Outcomes
- 78    # Store outcomes in a dictionary, where the key is a district and value is a dictionary of outcomes
- 79    outcomes = {}
- 80
- 81    # Print statistics for debugging
- 82    print_statistics = kwargs['print_statistics']
- 83
- 84    # Fix random seed for reproducibility
- 85    random_seed = kwargs['random_seed']
- 86    random.seed(random_seed)
- 87    np.random.seed(random_seed)
- 88
- 89    # PIPELINE:
- 90    # 1. Load all damage
- 91    # 2. Load household survey
- 92    # 3. Select district
- 93    # 4. Get event damage, total asset stock, expected loss fraction
- 94    # 5. Calculate average productivity
- 95    # 6. Adjust assets and expenditure
- 96    # 7. Calculate PML
- 97    # 8. Estimate savings
- 98    # 9. Set vulnerability
- 99    # 10. Calculate exposure
-100    # 11. Determine affected
-101    # 12. Apply individual policy
-102    # 13. Run optimization
-103    # 14. Integrate wellbeing
-104    # 15. Prepare outcomes
-105    # 16. Get outcomes
-106
-107    # ---------------------- Run the model for each district --------------------- #
-108
-109    for district in districts:
-110        # Read household survey and asset damage files for a specific district
-111        event_damage, total_asset_stock, expected_loss_fraction = get_asset_damage(
-112            all_damage, scale, district, return_period, print_statistics)
-113
-114        households = select_district(household_survey, district)
-115
-116        average_productivity = calculate_average_productivity(
-117            households, print_statistics)
-118
-119        # Model the impact of a disaster on households
-120        households = (adjust_assets_and_expenditure(households, total_asset_stock, poverty_line, indigence_line, print_statistics)
-121                      .pipe(calculate_pml, expected_loss_fraction, print_statistics)
-122                      .pipe(estimate_savings, saving_rate, estimate_savings_params)
-123                      .pipe(set_vulnerability, is_vulnerability_random, set_vulnerability_params)
-124                      .pipe(calculate_exposure, poverty_bias, calculate_exposure_params, print_statistics)
-125                      .pipe(determine_affected, determine_affected_params))
-126
-127        # households['aesav'].hist()
-128        # plt.show()
-129
-130        # Apply a policy
-131        households, affected_households = apply_individual_policy(
-132            households, my_policy)
-133
-134        # Calculate the impact and recovery
-135        # cash_transfer = {52: 1000, 208: 5000}
-136        cash_transfer = {}
-137        affected_households = (run_optimization(affected_households, consumption_utility, discount_rate, average_productivity, optimization_timestep, n_years)
-138                               .pipe(integrate_wellbeing, consumption_utility, discount_rate, income_and_expenditure_growth, average_productivity, poverty_line, n_years, add_income_loss, cash_transfer))
-139
-140        # Add columns of affected households to the original households dataframe
-141        households = add_columns(households, affected_households)
-142        # Get outcomes
-143        array_outcomes = np.array(list(get_outcomes(
-144            households, event_damage, total_asset_stock, expected_loss_fraction, average_productivity, n_years).values()))
-145
-146        # * To check whether we have different households affected in different runs
-147        # if district == 'Castries':
-148        #     affected_households.to_csv(f'affected_households_{random_seed}.csv')
-149
-150        outcomes[district] = array_outcomes
-151
-152    return outcomes
-
- - -

Run the model.

-
- - -
-
- - \ No newline at end of file diff --git a/docs/src/modules.html b/docs/src/modules.html deleted file mode 100644 index a0050ed..0000000 --- a/docs/src/modules.html +++ /dev/null @@ -1,238 +0,0 @@ - - - - - - - src.modules API documentation - - - - - - - - - -
-
-

-src.modules

- - - - - -
-
- - \ No newline at end of file diff --git a/docs/src/modules/households.html b/docs/src/modules/households.html deleted file mode 100644 index 7e8bbd7..0000000 --- a/docs/src/modules/households.html +++ /dev/null @@ -1,1380 +0,0 @@ - - - - - - - src.modules.households API documentation - - - - - - - - - -
-
-

-src.modules.households

- - - - - - -
  1import pandas as pd
-  2import numpy as np
-  3
-  4
-  5def duplicate_households(household_survey: pd.DataFrame, min_households: int) -> pd.DataFrame:
-  6    '''Duplicates households if the number of households is less than `min_households` threshold.
-  7
-  8    Args:
-  9        household_survey (pd.DataFrame): Household survey data.
- 10        min_households (int): Minimum number of households.
- 11
- 12    Returns:
- 13        pd.DataFrame: Household survey data with duplicated households.
- 14
- 15    Raises:
- 16        ValueError: If the total weights after duplication is not equal to the initial total weights.
- 17    '''
- 18
- 19    if len(household_survey) < min_households:
- 20        print(
- 21            f'Number of households = {len(household_survey)} is less than the threshold = {min_households}')
- 22
- 23        initial_total_weights = household_survey['popwgt'].sum()
- 24
- 25        # Save the original household id
- 26        household_survey['hhid_original'] = household_survey[['hhid']]
- 27
- 28        # Get random ids from the household data to be duplicated
- 29        ids = np.random.choice(
- 30            household_survey.index, min_households - len(household_survey), replace=True)
- 31        n_duplicates = pd.Series(ids).value_counts() + 1
- 32        duplicates = household_survey.loc[ids]
- 33
- 34        # Adjust the weights of the duplicated households
- 35        duplicates['popwgt'] = duplicates['popwgt'] / n_duplicates
- 36
- 37        # Adjust the weights of the original households
- 38        household_survey.loc[ids, 'popwgt'] = household_survey.loc[ids,
- 39                                                                   'popwgt'] / n_duplicates
- 40
- 41        # Combine the original and duplicated households
- 42        household_survey = pd.concat(
- 43            [household_survey, duplicates], ignore_index=True)
- 44
- 45        # Check if the total weights after duplication is equal to the initial total weights
- 46        # TODO: Allow for a small difference
- 47        weights_after_duplication = household_survey['popwgt'].sum()
- 48        if weights_after_duplication != initial_total_weights:
- 49            raise ValueError(
- 50                'Total weights after duplication is not equal to the initial total weights')
- 51
- 52        household_survey.reset_index(drop=True, inplace=True)
- 53        print(
- 54            f'Number of households after duplication: {len(household_survey)}')
- 55    else:
- 56        return household_survey
- 57
- 58
- 59def calculate_average_productivity(households: pd.DataFrame, print_statistics: bool) -> float:
- 60    '''Calculate average productivity as aeinc \ k_house_ae.
- 61
- 62    Args:
- 63        households (pd.DataFrame): Household survey data.
- 64        print_statistics (bool, optional): Whether to print the average productivity. Defaults to False.
- 65
- 66    Returns:
- 67        float: Average productivity.
- 68    '''
- 69    # DEFF: aeinc - some type of income
- 70    average_productivity = households['aeinc'] / households['k_house_ae']
- 71
- 72    # ?: What's happening here?
- 73    # average_productivity = average_productivity.iloc[0]
- 74    average_productivity = np.nanmedian(average_productivity)
- 75    if print_statistics:
- 76        print('Average productivity of capital = ' +
- 77              str(np.round(average_productivity, 3)))
- 78    return average_productivity
- 79
- 80
- 81def adjust_assets_and_expenditure(households: pd.DataFrame, total_asset_stock: float, poverty_line: float, indigence_line: float, print_statistics: bool) -> pd.DataFrame:
- 82    '''Adjust assets and expenditure of household to match data of asset damage file.
- 83
- 84    There can be a mismatch between the data in the household survey and the of the asset damage.
- 85    The latest was created independently.
- 86
- 87    Args:
- 88        households (pd.DataFrame): Household survey data.
- 89        total_asset_stock (float): Total asset stock.
- 90        poverty_line (float): Poverty line.
- 91        indigence_line (float): Indigence line.
- 92        print_statistics (bool, optional): Whether to print the statistics. Defaults to False.
- 93
- 94    Returns:
- 95        pd.DataFrame: Household survey data with adjusted assets and expenditure.
- 96    '''
- 97    # k_house_ae - effective capital stock of the household
- 98    # aeexp - adult equivalent expenditure of a household (total)
- 99    # aeexp_house - data['hhexp_house'] (annual rent) / data['hhsize_ae']
-100    included_variables = ['k_house_ae', 'aeexp', 'aeexp_house']
-101
-102    # Save the initial values
-103    households['k_house_ae_original'] = households['k_house_ae']
-104    households['aeexp_original'] = households['aeexp']
-105    households['aeexp_house_original'] = households['aeexp_house']
-106
-107    # Calculate the total asset in the survey
-108    total_asset_in_survey = households[[
-109        'popwgt', 'k_house_ae']].prod(axis=1).sum()
-110    households['total_asset_in_survey'] = total_asset_in_survey
-111
-112    # Calculate the scaling factor and adjust the variables
-113    scaling_factor = total_asset_stock / total_asset_in_survey
-114    households[included_variables] *= scaling_factor
-115    households['poverty_line_adjusted'] = poverty_line * scaling_factor
-116    households['indigence_line_adjusted'] = indigence_line * scaling_factor
-117
-118    if print_statistics:
-119        print('Total asset in survey =', '{:,}'.format(
-120            round(total_asset_in_survey)))
-121        print('Total asset in asset damage file =',
-122              '{:,}'.format(round(total_asset_stock)))
-123        print('Scaling factor =', round(scaling_factor, 3))
-124
-125    return households
-126
-127
-128def calculate_pml(households: pd.DataFrame, expected_loss_fraction: float, print_statistics: bool) -> pd.DataFrame:
-129    '''Calculate probable maximum loss as a product of population weight, effective capital stock and expected loss fraction.
-130
-131    Args:
-132        households (pd.DataFrame): Household survey data.
-133        expected_loss_fraction (float): Expected loss fraction.
-134        print_statistics (bool, optional): Whether to print the statistics. Defaults to False.
-135
-136    Returns:
-137        pd.DataFrame: Household survey data with probable maximum loss.
-138    '''
-139    # DEF: keff - effective capital stock
-140    # DEF: pml - probable maximum loss
-141    # DEF: popwgt - population weight of each household
-142    households['keff'] = households['k_house_ae'].copy()
-143    pml = households[['popwgt', 'keff']].prod(
-144        axis=1).sum() * expected_loss_fraction
-145    households['pml'] = pml
-146    if print_statistics:
-147        print('Probable maximum loss (total) : ', '{:,}'.format(round(pml)))
-148    return households
-149
-150
-151def select_district(household_survey: pd.DataFrame, district: str) -> pd.DataFrame:
-152    '''Select households for a specific district.'''
-153    return household_survey[household_survey['district'] == district].copy()
-154
-155
-156def estimate_savings(households: pd.DataFrame, saving_rate: float, estimate_savings_params: dict) -> pd.DataFrame:
-157    '''Estimate savings of households.
-158
-159     We assume that savings are a product of expenditure and saving rate with Gaussian noise.
-160
-161    Args:
-162        households (pd.DataFrame): Household survey data for a specific district.
-163        saving_rate (float): Saving rate.
-164        estimate_savings_params (dict): Parameters for estimating savings function.
-165
-166    Returns:
-167        pd.DataFrame: Household survey data with estimated savings.
-168    '''
-169    # * Expenditure & savings information for Saint Lucia https://www.ceicdata.com/en/saint-lucia/lending-saving-and-deposit-rates-annual/lc-savings-rate
-170
-171    # Savings are a product of expenditure and saving rate
-172    x = households.eval(f'aeexp*{saving_rate}')
-173
-174    # Get the mean of the noise with uniform distribution
-175    mean_noise_low = estimate_savings_params['mean_noise_low']  # default 0
-176    mean_noise_high = estimate_savings_params['mean_noise_high']  # default 5
-177
-178    if estimate_savings_params['mean_noise_distribution'] == 'uniform':
-179        loc = np.random.uniform(mean_noise_low, mean_noise_high)
-180    else:
-181        raise ValueError("Only uniform distribution is supported yet.")
-182
-183    # Get the scale
-184    scale = estimate_savings_params['noise_scale']  # default 2.5
-185    size = households.shape[0]
-186    clip_min = estimate_savings_params['savings_clip_min']  # default 0.1
-187    clip_max = estimate_savings_params['savings_clip_max']  # default 1.0
-188
-189    # Calculate savings with normal noise
-190    # !: aesav can go to 0 and above 1 because of the mean noise and loc
-191    # !: See `verification.ipynb` for more details
-192    if estimate_savings_params['noise_distribution'] == 'normal':
-193        households['aesav'] = x * \
-194            np.random.normal(loc, scale, size).round(
-195                2).clip(min=clip_min, max=clip_max)
-196    else:
-197        ValueError("Only normal distribution is supported yet.")
-198
-199    return households
-200
-201
-202def set_vulnerability(households: pd.DataFrame, is_vulnerability_random: bool, set_vulnerability_params: dict) -> pd.DataFrame:
-203    '''Set vulnerability of households.
-204
-205    Vulnerability can be random or based on `v_init` with uniform noise.
-206
-207    Args:
-208        households (pd.DataFrame): Household survey data for a specific district.
-209        is_vulnerability_random (bool): If True, vulnerability is random.
-210
-211    Returns:
-212        pd.DataFrame: Household survey data with assigned vulnerability.
-213
-214    Raises:
-215        ValueError: If the distribution is not supported.
-216    '''
-217
-218    # If vulnerability is random, then draw from the uniform distribution
-219    if is_vulnerability_random:
-220        # default 0.01
-221        low = set_vulnerability_params['vulnerability_random_low']
-222        # default 0.90
-223        high = set_vulnerability_params['vulnerability_random_high']
-224        if set_vulnerability_params['vulnerability_random_distribution'] == 'uniform':
-225            households['v'] = np.random.uniform(low, high, households.shape[0])
-226        else:
-227            raise ValueError("Only uniform distribution is supported yet.")
-228
-229    # If vulnerability is not random, use v_init as a starting point and add some noise
-230    # ?: What is the point of adding the noise to the v_init if we cap it anyhow
-231    else:
-232        # default 0.6
-233        low = set_vulnerability_params['vulnerability_initial_low']
-234        # default 1.4
-235        high = set_vulnerability_params['vulnerability_initial_high']
-236        # v - actual vulnerability
-237        # v_init - initial vulnerability
-238        if set_vulnerability_params['vulnerability_initial_distribution'] == 'uniform':
-239            households['v'] = households['v_init'] * \
-240                np.random.uniform(low, high, households.shape[0])
-241        else:
-242            raise ValueError("Only uniform distribution is supported yet.")
-243
-244        # default 0.95
-245        vulnerability_threshold = set_vulnerability_params['vulnerability_initial_threshold']
-246
-247        # If vulnerability turned out to be (drawn) is above the threshold, set it to the threshold
-248        households.loc[households['v'] >
-249                       vulnerability_threshold, 'v'] = vulnerability_threshold
-250
-251        return households
-252
-253
-254def calculate_exposure(households: pd.DataFrame, poverty_bias: float, calculate_exposure_params: dict, print_statistics: bool) -> pd.DataFrame:
-255    '''Calculate exposure of households.
-256
-257    Exposure is a function of poverty bias, effective capital stock, 
-258    vulnerability and probable maximum loss.
-259
-260    Args:
-261        households (pd.DataFrame): Household survey data for a specific district.
-262        poverty_bias (float): Poverty bias.
-263        calculate_exposure_params (dict): Parameters for calculating exposure function.
-264        print_statistics (bool): If True, print statistics.
-265
-266    Returns:
-267        pd.DataFrame: Household survey data with calculated exposure.
-268    '''
-269    pml = households['pml'].iloc[0]
-270
-271    # Random value for poverty bias
-272    if poverty_bias == 'random':
-273        # default 0.5
-274        low = calculate_exposure_params['poverty_bias_random_low']
-275        # default 1.5
-276        high = calculate_exposure_params['poverty_bias_random_high']
-277        if calculate_exposure_params['poverty_bias_random_distribution'] == 'uniform':
-278            povbias = np.random.uniform(low, high)
-279        else:
-280            raise ValueError("Only uniform distribution is supported yet.")
-281    else:
-282        povbias = poverty_bias
-283
-284    # Set poverty bias to 1 for all households
-285    households['poverty_bias'] = 1
-286
-287    # Set poverty bias to povbias for poor households
-288    households.loc[households['is_poor'] == True, 'poverty_bias'] = povbias
-289
-290    # DEFF: keff - effective capital stock
-291    delimiter = households[['keff', 'v', 'poverty_bias', 'popwgt']].prod(
-292        axis=1).sum()
-293
-294    # ?: fa - fraction affected?
-295    fa0 = pml / delimiter
-296
-297    # Print delimiter and fa0 with commas for thousands
-298    if print_statistics:
-299        print('PML: ', '{:,}'.format(round(pml, 2)))
-300        print('Delimiter: ', '{:,}'.format(round(delimiter, 2)))
-301        print('f0: ', '{:,}'.format(round(fa0, 2)))
-302
-303    households['fa'] = fa0 * households[['poverty_bias']]
-304    households.drop('poverty_bias', axis=1, inplace=True)
-305    return households
-306
-307
-308def determine_affected(households: pd.DataFrame, determine_affected_params: dict) -> tuple:
-309    '''Determines affected households.
-310
-311    We assume that all households have the same probability of being affected, 
-312    but based on `fa` calculated in `calculate_exposure`.
-313
-314    Args:
-315        households (pd.DataFrame): Household survey data for a specific district.
-316        determine_affected_params (dict): Parameters for determining affected households function.
-317
-318    Returns:
-319        tuple: Household survey data with determined affected households and asset loss for each household.
-320
-321    Raises:
-322        ValueError: If total asset is less than PML.
-323        ValueError: If no mask was found.
-324    '''
-325    # Get PML, it is the same for all households
-326    pml = households['pml'].iloc[0]
-327
-328    # Allow for a relatively small error
-329    delta = pml * determine_affected_params['delta_pct']  # default 0.025
-330
-331    # Check if total asset is less than PML
-332    total_asset = households[['keff', 'popwgt']].prod(axis=1).sum()
-333    if total_asset < pml:
-334        raise ValueError(
-335            'Total asset is less than PML.')
-336
-337    low = determine_affected_params['low']  # default 0
-338    high = determine_affected_params['high']  # default 1
-339
-340    # Generate multiple boolean masks at once
-341    num_masks = determine_affected_params['num_masks']  # default 2000
-342    masks = np.random.uniform(
-343        low, high, (num_masks, households.shape[0])) <= households['fa'].values
-344
-345    # Compute total_asset_loss for each mask
-346    asset_losses = (
-347        masks * households[['keff', 'v', 'popwgt']].values.prod(axis=1)).sum(axis=1)
-348
-349    # Find the first mask that yields a total_asset_loss within the desired range
-350    mask_index = np.where((asset_losses >= pml - delta) &
-351                          (asset_losses <= pml + delta))
-352
-353    # Raise an error if no mask was found
-354    if mask_index is None:
-355        raise ValueError(
-356            f'Cannot find affected households in {num_masks} iterations.')
-357    else:
-358        try:
-359            mask_index = mask_index[0][0]
-360        except:
-361            print('mask_index: ', mask_index)
-362
-363    chosen_mask = masks[mask_index]
-364
-365    # Assign the chosen mask to the 'is_affected' column of the DataFrame
-366    households['is_affected'] = chosen_mask
-367
-368    # Save the asset loss for each household
-369    households['asset_loss'] = households.loc[households['is_affected'], [
-370        'keff', 'v', 'popwgt']].prod(axis=1).round(2)
-371    households['asset_loss'] = households['asset_loss'].fillna(0)
-372
-373    return households
-374
-375
-376def apply_individual_policy(households: pd.DataFrame, my_policy: str) -> tuple:
-377    '''Apply a policy to a specific target group.
-378
-379    Args:
-380        households (pd.DataFrame): Household survey data for a specific district.
-381        my_policy (str): Policy to apply. The structure of the policy is `target_group`+`top_up` in a single string. `target_group` can be `all`, `poor`, `poor_near_poor1.25`, `poor_near_poor2.0`, and the `top_up` 0, 10, 30 or 50.
-382
-383    Returns:
-384        tuple: Household survey data with applied policy and affected households.
-385    '''
-386
-387    poverty_line_adjusted = households['poverty_line_adjusted'].iloc[0]
-388
-389    target_group, top_up = my_policy.split('+')
-390    top_up = float(top_up)
-391
-392    # Select a target group
-393    if target_group == 'all':
-394        beneficiaries = households['is_affected'] == True
-395
-396    # * If the target group is poor, the policy won't decrease the number of new poor
-397    elif target_group == 'poor':
-398        beneficiaries = (households['is_affected'] == True) & (
-399            households['is_poor'] == True)
-400
-401    elif target_group == 'poor_near_poor1.25':
-402        poor_affected = (households['is_affected'] == True) & (
-403            households['is_poor'] == True)
-404        near_poor_affected = (households['is_affected'] == True) & (
-405            households['is_poor'] == False) & (households['aeexp'] < 1.25 * poverty_line_adjusted)
-406        beneficiaries = poor_affected | near_poor_affected
-407
-408    elif target_group == 'poor_near_poor2.0':
-409        poor_affected = (households['is_affected'] == True) & (
-410            households['is_poor'] == True)
-411        near_poor_affected = (households['is_affected'] == True) & (
-412            households['is_poor'] == False) & (households['aeexp'] < 2 * poverty_line_adjusted)
-413        beneficiaries = poor_affected | near_poor_affected
-414
-415    # * Here we have to decide to what to add to aeexp or aesav
-416    households.loc[beneficiaries,
-417                   'aesav'] += households.loc[beneficiaries].eval('keff*v') * top_up / 100
-418
-419    # Select columns of interest
-420    columns_of_interest = ['hhid', 'popwgt', 'own_rent', 'quintile', 'aeexp',
-421                           'aeexp_house', 'keff', 'v', 'aesav', 'aesoc', 'delta_tax_safety']
-422    affected_households = households.loc[households['is_affected'],
-423                                         columns_of_interest].copy()
-424    return households, affected_households
-
- - -
-
- -
- - def - duplicate_households( household_survey: pandas.core.frame.DataFrame, min_households: int) -> pandas.core.frame.DataFrame: - - - -
- -
 6def duplicate_households(household_survey: pd.DataFrame, min_households: int) -> pd.DataFrame:
- 7    '''Duplicates households if the number of households is less than `min_households` threshold.
- 8
- 9    Args:
-10        household_survey (pd.DataFrame): Household survey data.
-11        min_households (int): Minimum number of households.
-12
-13    Returns:
-14        pd.DataFrame: Household survey data with duplicated households.
-15
-16    Raises:
-17        ValueError: If the total weights after duplication is not equal to the initial total weights.
-18    '''
-19
-20    if len(household_survey) < min_households:
-21        print(
-22            f'Number of households = {len(household_survey)} is less than the threshold = {min_households}')
-23
-24        initial_total_weights = household_survey['popwgt'].sum()
-25
-26        # Save the original household id
-27        household_survey['hhid_original'] = household_survey[['hhid']]
-28
-29        # Get random ids from the household data to be duplicated
-30        ids = np.random.choice(
-31            household_survey.index, min_households - len(household_survey), replace=True)
-32        n_duplicates = pd.Series(ids).value_counts() + 1
-33        duplicates = household_survey.loc[ids]
-34
-35        # Adjust the weights of the duplicated households
-36        duplicates['popwgt'] = duplicates['popwgt'] / n_duplicates
-37
-38        # Adjust the weights of the original households
-39        household_survey.loc[ids, 'popwgt'] = household_survey.loc[ids,
-40                                                                   'popwgt'] / n_duplicates
-41
-42        # Combine the original and duplicated households
-43        household_survey = pd.concat(
-44            [household_survey, duplicates], ignore_index=True)
-45
-46        # Check if the total weights after duplication is equal to the initial total weights
-47        # TODO: Allow for a small difference
-48        weights_after_duplication = household_survey['popwgt'].sum()
-49        if weights_after_duplication != initial_total_weights:
-50            raise ValueError(
-51                'Total weights after duplication is not equal to the initial total weights')
-52
-53        household_survey.reset_index(drop=True, inplace=True)
-54        print(
-55            f'Number of households after duplication: {len(household_survey)}')
-56    else:
-57        return household_survey
-
- - -

Duplicates households if the number of households is less than min_households threshold.

- -

Args: - household_survey (pd.DataFrame): Household survey data. - min_households (int): Minimum number of households.

- -

Returns: - pd.DataFrame: Household survey data with duplicated households.

- -

Raises: - ValueError: If the total weights after duplication is not equal to the initial total weights.

-
- - -
-
- -
- - def - calculate_average_productivity(households: pandas.core.frame.DataFrame, print_statistics: bool) -> float: - - - -
- -
60def calculate_average_productivity(households: pd.DataFrame, print_statistics: bool) -> float:
-61    '''Calculate average productivity as aeinc \ k_house_ae.
-62
-63    Args:
-64        households (pd.DataFrame): Household survey data.
-65        print_statistics (bool, optional): Whether to print the average productivity. Defaults to False.
-66
-67    Returns:
-68        float: Average productivity.
-69    '''
-70    # DEFF: aeinc - some type of income
-71    average_productivity = households['aeinc'] / households['k_house_ae']
-72
-73    # ?: What's happening here?
-74    # average_productivity = average_productivity.iloc[0]
-75    average_productivity = np.nanmedian(average_productivity)
-76    if print_statistics:
-77        print('Average productivity of capital = ' +
-78              str(np.round(average_productivity, 3)))
-79    return average_productivity
-
- - -

Calculate average productivity as aeinc \ k_house_ae.

- -

Args: - households (pd.DataFrame): Household survey data. - print_statistics (bool, optional): Whether to print the average productivity. Defaults to False.

- -

Returns: - float: Average productivity.

-
- - -
-
- -
- - def - adjust_assets_and_expenditure( households: pandas.core.frame.DataFrame, total_asset_stock: float, poverty_line: float, indigence_line: float, print_statistics: bool) -> pandas.core.frame.DataFrame: - - - -
- -
 82def adjust_assets_and_expenditure(households: pd.DataFrame, total_asset_stock: float, poverty_line: float, indigence_line: float, print_statistics: bool) -> pd.DataFrame:
- 83    '''Adjust assets and expenditure of household to match data of asset damage file.
- 84
- 85    There can be a mismatch between the data in the household survey and the of the asset damage.
- 86    The latest was created independently.
- 87
- 88    Args:
- 89        households (pd.DataFrame): Household survey data.
- 90        total_asset_stock (float): Total asset stock.
- 91        poverty_line (float): Poverty line.
- 92        indigence_line (float): Indigence line.
- 93        print_statistics (bool, optional): Whether to print the statistics. Defaults to False.
- 94
- 95    Returns:
- 96        pd.DataFrame: Household survey data with adjusted assets and expenditure.
- 97    '''
- 98    # k_house_ae - effective capital stock of the household
- 99    # aeexp - adult equivalent expenditure of a household (total)
-100    # aeexp_house - data['hhexp_house'] (annual rent) / data['hhsize_ae']
-101    included_variables = ['k_house_ae', 'aeexp', 'aeexp_house']
-102
-103    # Save the initial values
-104    households['k_house_ae_original'] = households['k_house_ae']
-105    households['aeexp_original'] = households['aeexp']
-106    households['aeexp_house_original'] = households['aeexp_house']
-107
-108    # Calculate the total asset in the survey
-109    total_asset_in_survey = households[[
-110        'popwgt', 'k_house_ae']].prod(axis=1).sum()
-111    households['total_asset_in_survey'] = total_asset_in_survey
-112
-113    # Calculate the scaling factor and adjust the variables
-114    scaling_factor = total_asset_stock / total_asset_in_survey
-115    households[included_variables] *= scaling_factor
-116    households['poverty_line_adjusted'] = poverty_line * scaling_factor
-117    households['indigence_line_adjusted'] = indigence_line * scaling_factor
-118
-119    if print_statistics:
-120        print('Total asset in survey =', '{:,}'.format(
-121            round(total_asset_in_survey)))
-122        print('Total asset in asset damage file =',
-123              '{:,}'.format(round(total_asset_stock)))
-124        print('Scaling factor =', round(scaling_factor, 3))
-125
-126    return households
-
- - -

Adjust assets and expenditure of household to match data of asset damage file.

- -

There can be a mismatch between the data in the household survey and the of the asset damage. -The latest was created independently.

- -

Args: - households (pd.DataFrame): Household survey data. - total_asset_stock (float): Total asset stock. - poverty_line (float): Poverty line. - indigence_line (float): Indigence line. - print_statistics (bool, optional): Whether to print the statistics. Defaults to False.

- -

Returns: - pd.DataFrame: Household survey data with adjusted assets and expenditure.

-
- - -
-
- -
- - def - calculate_pml( households: pandas.core.frame.DataFrame, expected_loss_fraction: float, print_statistics: bool) -> pandas.core.frame.DataFrame: - - - -
- -
129def calculate_pml(households: pd.DataFrame, expected_loss_fraction: float, print_statistics: bool) -> pd.DataFrame:
-130    '''Calculate probable maximum loss as a product of population weight, effective capital stock and expected loss fraction.
-131
-132    Args:
-133        households (pd.DataFrame): Household survey data.
-134        expected_loss_fraction (float): Expected loss fraction.
-135        print_statistics (bool, optional): Whether to print the statistics. Defaults to False.
-136
-137    Returns:
-138        pd.DataFrame: Household survey data with probable maximum loss.
-139    '''
-140    # DEF: keff - effective capital stock
-141    # DEF: pml - probable maximum loss
-142    # DEF: popwgt - population weight of each household
-143    households['keff'] = households['k_house_ae'].copy()
-144    pml = households[['popwgt', 'keff']].prod(
-145        axis=1).sum() * expected_loss_fraction
-146    households['pml'] = pml
-147    if print_statistics:
-148        print('Probable maximum loss (total) : ', '{:,}'.format(round(pml)))
-149    return households
-
- - -

Calculate probable maximum loss as a product of population weight, effective capital stock and expected loss fraction.

- -

Args: - households (pd.DataFrame): Household survey data. - expected_loss_fraction (float): Expected loss fraction. - print_statistics (bool, optional): Whether to print the statistics. Defaults to False.

- -

Returns: - pd.DataFrame: Household survey data with probable maximum loss.

-
- - -
-
- -
- - def - select_district( household_survey: pandas.core.frame.DataFrame, district: str) -> pandas.core.frame.DataFrame: - - - -
- -
152def select_district(household_survey: pd.DataFrame, district: str) -> pd.DataFrame:
-153    '''Select households for a specific district.'''
-154    return household_survey[household_survey['district'] == district].copy()
-
- - -

Select households for a specific district.

-
- - -
-
- -
- - def - estimate_savings( households: pandas.core.frame.DataFrame, saving_rate: float, estimate_savings_params: dict) -> pandas.core.frame.DataFrame: - - - -
- -
157def estimate_savings(households: pd.DataFrame, saving_rate: float, estimate_savings_params: dict) -> pd.DataFrame:
-158    '''Estimate savings of households.
-159
-160     We assume that savings are a product of expenditure and saving rate with Gaussian noise.
-161
-162    Args:
-163        households (pd.DataFrame): Household survey data for a specific district.
-164        saving_rate (float): Saving rate.
-165        estimate_savings_params (dict): Parameters for estimating savings function.
-166
-167    Returns:
-168        pd.DataFrame: Household survey data with estimated savings.
-169    '''
-170    # * Expenditure & savings information for Saint Lucia https://www.ceicdata.com/en/saint-lucia/lending-saving-and-deposit-rates-annual/lc-savings-rate
-171
-172    # Savings are a product of expenditure and saving rate
-173    x = households.eval(f'aeexp*{saving_rate}')
-174
-175    # Get the mean of the noise with uniform distribution
-176    mean_noise_low = estimate_savings_params['mean_noise_low']  # default 0
-177    mean_noise_high = estimate_savings_params['mean_noise_high']  # default 5
-178
-179    if estimate_savings_params['mean_noise_distribution'] == 'uniform':
-180        loc = np.random.uniform(mean_noise_low, mean_noise_high)
-181    else:
-182        raise ValueError("Only uniform distribution is supported yet.")
-183
-184    # Get the scale
-185    scale = estimate_savings_params['noise_scale']  # default 2.5
-186    size = households.shape[0]
-187    clip_min = estimate_savings_params['savings_clip_min']  # default 0.1
-188    clip_max = estimate_savings_params['savings_clip_max']  # default 1.0
-189
-190    # Calculate savings with normal noise
-191    # !: aesav can go to 0 and above 1 because of the mean noise and loc
-192    # !: See `verification.ipynb` for more details
-193    if estimate_savings_params['noise_distribution'] == 'normal':
-194        households['aesav'] = x * \
-195            np.random.normal(loc, scale, size).round(
-196                2).clip(min=clip_min, max=clip_max)
-197    else:
-198        ValueError("Only normal distribution is supported yet.")
-199
-200    return households
-
- - -

Estimate savings of households.

- -

We assume that savings are a product of expenditure and saving rate with Gaussian noise.

- -

Args: - households (pd.DataFrame): Household survey data for a specific district. - saving_rate (float): Saving rate. - estimate_savings_params (dict): Parameters for estimating savings function.

- -

Returns: - pd.DataFrame: Household survey data with estimated savings.

-
- - -
-
- -
- - def - set_vulnerability( households: pandas.core.frame.DataFrame, is_vulnerability_random: bool, set_vulnerability_params: dict) -> pandas.core.frame.DataFrame: - - - -
- -
203def set_vulnerability(households: pd.DataFrame, is_vulnerability_random: bool, set_vulnerability_params: dict) -> pd.DataFrame:
-204    '''Set vulnerability of households.
-205
-206    Vulnerability can be random or based on `v_init` with uniform noise.
-207
-208    Args:
-209        households (pd.DataFrame): Household survey data for a specific district.
-210        is_vulnerability_random (bool): If True, vulnerability is random.
-211
-212    Returns:
-213        pd.DataFrame: Household survey data with assigned vulnerability.
-214
-215    Raises:
-216        ValueError: If the distribution is not supported.
-217    '''
-218
-219    # If vulnerability is random, then draw from the uniform distribution
-220    if is_vulnerability_random:
-221        # default 0.01
-222        low = set_vulnerability_params['vulnerability_random_low']
-223        # default 0.90
-224        high = set_vulnerability_params['vulnerability_random_high']
-225        if set_vulnerability_params['vulnerability_random_distribution'] == 'uniform':
-226            households['v'] = np.random.uniform(low, high, households.shape[0])
-227        else:
-228            raise ValueError("Only uniform distribution is supported yet.")
-229
-230    # If vulnerability is not random, use v_init as a starting point and add some noise
-231    # ?: What is the point of adding the noise to the v_init if we cap it anyhow
-232    else:
-233        # default 0.6
-234        low = set_vulnerability_params['vulnerability_initial_low']
-235        # default 1.4
-236        high = set_vulnerability_params['vulnerability_initial_high']
-237        # v - actual vulnerability
-238        # v_init - initial vulnerability
-239        if set_vulnerability_params['vulnerability_initial_distribution'] == 'uniform':
-240            households['v'] = households['v_init'] * \
-241                np.random.uniform(low, high, households.shape[0])
-242        else:
-243            raise ValueError("Only uniform distribution is supported yet.")
-244
-245        # default 0.95
-246        vulnerability_threshold = set_vulnerability_params['vulnerability_initial_threshold']
-247
-248        # If vulnerability turned out to be (drawn) is above the threshold, set it to the threshold
-249        households.loc[households['v'] >
-250                       vulnerability_threshold, 'v'] = vulnerability_threshold
-251
-252        return households
-
- - -

Set vulnerability of households.

- -

Vulnerability can be random or based on v_init with uniform noise.

- -

Args: - households (pd.DataFrame): Household survey data for a specific district. - is_vulnerability_random (bool): If True, vulnerability is random.

- -

Returns: - pd.DataFrame: Household survey data with assigned vulnerability.

- -

Raises: - ValueError: If the distribution is not supported.

-
- - -
-
- -
- - def - calculate_exposure( households: pandas.core.frame.DataFrame, poverty_bias: float, calculate_exposure_params: dict, print_statistics: bool) -> pandas.core.frame.DataFrame: - - - -
- -
255def calculate_exposure(households: pd.DataFrame, poverty_bias: float, calculate_exposure_params: dict, print_statistics: bool) -> pd.DataFrame:
-256    '''Calculate exposure of households.
-257
-258    Exposure is a function of poverty bias, effective capital stock, 
-259    vulnerability and probable maximum loss.
-260
-261    Args:
-262        households (pd.DataFrame): Household survey data for a specific district.
-263        poverty_bias (float): Poverty bias.
-264        calculate_exposure_params (dict): Parameters for calculating exposure function.
-265        print_statistics (bool): If True, print statistics.
-266
-267    Returns:
-268        pd.DataFrame: Household survey data with calculated exposure.
-269    '''
-270    pml = households['pml'].iloc[0]
-271
-272    # Random value for poverty bias
-273    if poverty_bias == 'random':
-274        # default 0.5
-275        low = calculate_exposure_params['poverty_bias_random_low']
-276        # default 1.5
-277        high = calculate_exposure_params['poverty_bias_random_high']
-278        if calculate_exposure_params['poverty_bias_random_distribution'] == 'uniform':
-279            povbias = np.random.uniform(low, high)
-280        else:
-281            raise ValueError("Only uniform distribution is supported yet.")
-282    else:
-283        povbias = poverty_bias
-284
-285    # Set poverty bias to 1 for all households
-286    households['poverty_bias'] = 1
-287
-288    # Set poverty bias to povbias for poor households
-289    households.loc[households['is_poor'] == True, 'poverty_bias'] = povbias
-290
-291    # DEFF: keff - effective capital stock
-292    delimiter = households[['keff', 'v', 'poverty_bias', 'popwgt']].prod(
-293        axis=1).sum()
-294
-295    # ?: fa - fraction affected?
-296    fa0 = pml / delimiter
-297
-298    # Print delimiter and fa0 with commas for thousands
-299    if print_statistics:
-300        print('PML: ', '{:,}'.format(round(pml, 2)))
-301        print('Delimiter: ', '{:,}'.format(round(delimiter, 2)))
-302        print('f0: ', '{:,}'.format(round(fa0, 2)))
-303
-304    households['fa'] = fa0 * households[['poverty_bias']]
-305    households.drop('poverty_bias', axis=1, inplace=True)
-306    return households
-
- - -

Calculate exposure of households.

- -

Exposure is a function of poverty bias, effective capital stock, -vulnerability and probable maximum loss.

- -

Args: - households (pd.DataFrame): Household survey data for a specific district. - poverty_bias (float): Poverty bias. - calculate_exposure_params (dict): Parameters for calculating exposure function. - print_statistics (bool): If True, print statistics.

- -

Returns: - pd.DataFrame: Household survey data with calculated exposure.

-
- - -
-
- -
- - def - determine_affected( households: pandas.core.frame.DataFrame, determine_affected_params: dict) -> tuple: - - - -
- -
309def determine_affected(households: pd.DataFrame, determine_affected_params: dict) -> tuple:
-310    '''Determines affected households.
-311
-312    We assume that all households have the same probability of being affected, 
-313    but based on `fa` calculated in `calculate_exposure`.
-314
-315    Args:
-316        households (pd.DataFrame): Household survey data for a specific district.
-317        determine_affected_params (dict): Parameters for determining affected households function.
-318
-319    Returns:
-320        tuple: Household survey data with determined affected households and asset loss for each household.
-321
-322    Raises:
-323        ValueError: If total asset is less than PML.
-324        ValueError: If no mask was found.
-325    '''
-326    # Get PML, it is the same for all households
-327    pml = households['pml'].iloc[0]
-328
-329    # Allow for a relatively small error
-330    delta = pml * determine_affected_params['delta_pct']  # default 0.025
-331
-332    # Check if total asset is less than PML
-333    total_asset = households[['keff', 'popwgt']].prod(axis=1).sum()
-334    if total_asset < pml:
-335        raise ValueError(
-336            'Total asset is less than PML.')
-337
-338    low = determine_affected_params['low']  # default 0
-339    high = determine_affected_params['high']  # default 1
-340
-341    # Generate multiple boolean masks at once
-342    num_masks = determine_affected_params['num_masks']  # default 2000
-343    masks = np.random.uniform(
-344        low, high, (num_masks, households.shape[0])) <= households['fa'].values
-345
-346    # Compute total_asset_loss for each mask
-347    asset_losses = (
-348        masks * households[['keff', 'v', 'popwgt']].values.prod(axis=1)).sum(axis=1)
-349
-350    # Find the first mask that yields a total_asset_loss within the desired range
-351    mask_index = np.where((asset_losses >= pml - delta) &
-352                          (asset_losses <= pml + delta))
-353
-354    # Raise an error if no mask was found
-355    if mask_index is None:
-356        raise ValueError(
-357            f'Cannot find affected households in {num_masks} iterations.')
-358    else:
-359        try:
-360            mask_index = mask_index[0][0]
-361        except:
-362            print('mask_index: ', mask_index)
-363
-364    chosen_mask = masks[mask_index]
-365
-366    # Assign the chosen mask to the 'is_affected' column of the DataFrame
-367    households['is_affected'] = chosen_mask
-368
-369    # Save the asset loss for each household
-370    households['asset_loss'] = households.loc[households['is_affected'], [
-371        'keff', 'v', 'popwgt']].prod(axis=1).round(2)
-372    households['asset_loss'] = households['asset_loss'].fillna(0)
-373
-374    return households
-
- - -

Determines affected households.

- -

We assume that all households have the same probability of being affected, -but based on fa calculated in calculate_exposure.

- -

Args: - households (pd.DataFrame): Household survey data for a specific district. - determine_affected_params (dict): Parameters for determining affected households function.

- -

Returns: - tuple: Household survey data with determined affected households and asset loss for each household.

- -

Raises: - ValueError: If total asset is less than PML. - ValueError: If no mask was found.

-
- - -
-
- -
- - def - apply_individual_policy(households: pandas.core.frame.DataFrame, my_policy: str) -> tuple: - - - -
- -
377def apply_individual_policy(households: pd.DataFrame, my_policy: str) -> tuple:
-378    '''Apply a policy to a specific target group.
-379
-380    Args:
-381        households (pd.DataFrame): Household survey data for a specific district.
-382        my_policy (str): Policy to apply. The structure of the policy is `target_group`+`top_up` in a single string. `target_group` can be `all`, `poor`, `poor_near_poor1.25`, `poor_near_poor2.0`, and the `top_up` 0, 10, 30 or 50.
-383
-384    Returns:
-385        tuple: Household survey data with applied policy and affected households.
-386    '''
-387
-388    poverty_line_adjusted = households['poverty_line_adjusted'].iloc[0]
-389
-390    target_group, top_up = my_policy.split('+')
-391    top_up = float(top_up)
-392
-393    # Select a target group
-394    if target_group == 'all':
-395        beneficiaries = households['is_affected'] == True
-396
-397    # * If the target group is poor, the policy won't decrease the number of new poor
-398    elif target_group == 'poor':
-399        beneficiaries = (households['is_affected'] == True) & (
-400            households['is_poor'] == True)
-401
-402    elif target_group == 'poor_near_poor1.25':
-403        poor_affected = (households['is_affected'] == True) & (
-404            households['is_poor'] == True)
-405        near_poor_affected = (households['is_affected'] == True) & (
-406            households['is_poor'] == False) & (households['aeexp'] < 1.25 * poverty_line_adjusted)
-407        beneficiaries = poor_affected | near_poor_affected
-408
-409    elif target_group == 'poor_near_poor2.0':
-410        poor_affected = (households['is_affected'] == True) & (
-411            households['is_poor'] == True)
-412        near_poor_affected = (households['is_affected'] == True) & (
-413            households['is_poor'] == False) & (households['aeexp'] < 2 * poverty_line_adjusted)
-414        beneficiaries = poor_affected | near_poor_affected
-415
-416    # * Here we have to decide to what to add to aeexp or aesav
-417    households.loc[beneficiaries,
-418                   'aesav'] += households.loc[beneficiaries].eval('keff*v') * top_up / 100
-419
-420    # Select columns of interest
-421    columns_of_interest = ['hhid', 'popwgt', 'own_rent', 'quintile', 'aeexp',
-422                           'aeexp_house', 'keff', 'v', 'aesav', 'aesoc', 'delta_tax_safety']
-423    affected_households = households.loc[households['is_affected'],
-424                                         columns_of_interest].copy()
-425    return households, affected_households
-
- - -

Apply a policy to a specific target group.

- -

Args: - households (pd.DataFrame): Household survey data for a specific district. - my_policy (str): Policy to apply. The structure of the policy is target_group+top_up in a single string. target_group can be all, poor, poor_near_poor1.25, poor_near_poor2.0, and the top_up 0, 10, 30 or 50.

- -

Returns: - tuple: Household survey data with applied policy and affected households.

-
- - -
-
- - \ No newline at end of file diff --git a/docs/src/modules/optimize.html b/docs/src/modules/optimize.html deleted file mode 100644 index 34c0c88..0000000 --- a/docs/src/modules/optimize.html +++ /dev/null @@ -1,779 +0,0 @@ - - - - - - - src.modules.optimize API documentation - - - - - - - - - -
-
-

-src.modules.optimize

- - - - - - -
  1import numpy as np
-  2import pandas as pd
-  3import pickle
-  4
-  5
-  6def run_optimization(affected_households: pd.DataFrame, consumption_utility: float, discount_rate: float, average_productivity: float, optimization_timestep: float, n_years: int) -> pd.DataFrame:
-  7    '''This function calculates the recovery rate for each affected household.
-  8
-  9    Args:
- 10        affected_households (pd.DataFrame): A data frame containing the affected households.
- 11        consumption_utility (float): The coefficient of relative risk aversion.
- 12        discount_rate (float): The discount rate.
- 13        average_productivity (float): The average productivity.
- 14        optimization_timestep (float): The timestep for the optimization.
- 15        n_years (int): The number of years in the optimization algorithm.
- 16
- 17    Returns:
- 18        pd.DataFrame: A data frame containing the affected households with the recovery rate.
- 19    '''
- 20
- 21    # Set effective capital stock to zero for renters
- 22    affected_households.loc[affected_households['own_rent']
- 23                            == 'rent', 'keff'] = 0  # V
- 24
- 25    # Prepare a data frame to store optimization results
- 26    optimization_results = pd.DataFrame({'aeexp': -1,
- 27                                         'aeexp_house': -1,
- 28                                         'keff': -1,
- 29                                         'v': -1,
- 30                                         'aesav': -1,
- 31                                         'solution': None,
- 32                                         'bankrupt': None}, index=[0])
- 33
- 34    optimization_results = optimization_results.reset_index(drop=True).set_index(
- 35        ['aeexp',
- 36         'aeexp_house',
- 37         'keff',
- 38         'v',
- 39         'aesav'])
- 40
- 41    # Calculate the recovery rate for each affected household
- 42    affected_households['recovery_rate'] = affected_households['v'].apply(
- 43        lambda x: optimize_recovery_rate(x, optimization_results, consumption_utility, discount_rate, average_productivity, optimization_timestep, n_years))
- 44
- 45    # TODO: Check whether this has any impact on anything
- 46    # optimization_results = optimization_results.sort_index()
- 47
- 48    return affected_households
- 49
- 50
- 51def optimize_recovery_rate(x, optimization_results: pd.DataFrame, consumption_utility: float, discount_rate: float, average_productivity: float, optimization_timestep: float, n_years: int) -> float:
- 52    try:
- 53        # Look for the existing solution
- 54        solution = optimization_results.loc[(
- 55            0, 0, 0, round(x, 3), round(average_productivity, 3)), 'solution']
- 56        return solution
- 57    except:
- 58        # No existing solution found, so we need to optimize
- 59        t_max_linspace = n_years  # years
- 60        nsteps_linspace = 52 * t_max_linspace  # total weeks
- 61        dt = t_max_linspace / nsteps_linspace
- 62
- 63        _lambda = 0
- 64        opt_step = optimization_timestep
- 65        last_dwdlambda = 0
- 66
- 67        while True:
- 68
- 69            dwdlambda = 0
- 70
- 71            for _t in np.linspace(0, t_max_linspace, nsteps_linspace):
- 72
- 73                part1 = average_productivity - \
- 74                    (average_productivity+_lambda)*x*np.e**(-_lambda*_t)
- 75                part1 = part1**(-consumption_utility)
- 76
- 77                part2 = _t * (average_productivity+_lambda) - 1
- 78
- 79                part3 = np.e**(-_t*(discount_rate+_lambda))
- 80
- 81                dwdlambda += part1 * part2 * part3 * dt
- 82
- 83            # !: All these do the same
- 84            if last_dwdlambda < 0 and dwdlambda > 0:
- 85                optimization_results.loc[(0, 0, 0, round(x, 3), round(average_productivity, 3)), [
- 86                    'solution', 'bankrupt']] = [_lambda, False]
- 87                optimization_results = optimization_results.sort_index()
- 88                return _lambda
- 89
- 90            elif last_dwdlambda > 0 and dwdlambda < 0:
- 91                optimization_results.loc[(0, 0, 0, round(x, 3), round(average_productivity, 3)), [
- 92                    'solution', 'bankrupt']] = [_lambda, False]
- 93                optimization_results = optimization_results.sort_index()
- 94                return _lambda
- 95
- 96            # !: That's why assigning more than 10 years does not work, we need to change 10 to `n_years`?
- 97            elif _lambda > 10:
- 98                optimization_results.loc[(0, 0, 0, round(x, 3), round(average_productivity, 3)), [
- 99                    'solution', 'bankrupt']] = [_lambda, False]
-100                optimization_results = optimization_results.sort_index()
-101                return _lambda
-102
-103            else:
-104                last_dwdlambda = dwdlambda
-105            _lambda += opt_step
-106
-107
-108def integrate_wellbeing(affected_households: pd.DataFrame,
-109                        consumption_utility: float,
-110                        discount_rate: float,
-111                        income_and_expenditure_growth: float,
-112                        average_productivity: float,
-113                        poverty_line: float,
-114                        n_years: int,
-115                        add_income_loss: bool,
-116                        cash_transfer: dict = {},
-117                        ) -> pd.DataFrame:
-118
-119    # We need to reset some columns to zero to start the integration
-120    columns = ['consumption_loss', 'consumption_loss_NPV', 'net_consumption_loss',
-121               'net_consumption_loss_NPV', 'c_t', 'w_final', 'weeks_pov', 'w_final2']
-122    affected_households[columns] = [0., 0., 0., 0., 0., 0., 0., 0.]
-123
-124    # Define the number of weeks given the number of years
-125    n_weeks = 52 * n_years
-126    dt = n_years / n_weeks
-127
-128    # * Store consumption recovery in a dict for verification and debugging purposes
-129    # consumption_recovery = {}
-130
-131    # We need to adjust the cash transfer to the timestep of the integration
-132    if cash_transfer != {}:  # If there is a cash transfer
-133        cash_transfer_transformed = {np.linspace(0, n_years, n_weeks)[
-134            t]: cash_transfer[t] for t in list(cash_transfer.keys())}
-135    else:
-136        cash_transfer_transformed = {}
-137
-138    # Calculate the consumption loss for each affected household
-139    for _t in np.linspace(0, n_years, n_weeks):
-140        gfac = (1 + income_and_expenditure_growth)**_t
-141
-142        # TODO: Add an extra condition about to whom the transfer is given
-143        # A "dynamic policy"
-144        if _t in list(cash_transfer_transformed.keys()):
-145            affected_households['aesav'] += cash_transfer_transformed[_t]
-146
-147        # `c_t` is the consumption at time t
-148        # !: It seems that keff remains constant over time
-149        expenditure_growth = gfac * affected_households['aeexp']
-150        exponential_multiplier = np.e**(
-151            -affected_households['recovery_rate']*_t)
-152        savings = gfac * \
-153            affected_households['aesav'] * affected_households['recovery_rate']
-154        asset_damage = gfac * \
-155            affected_households['v'] * \
-156            affected_households[['keff', 'recovery_rate']].prod(axis=1)
-157        
-158        # TODO: Make sure that `delta_tax_safety` is not 0
-159        income_loss = gfac * (1 - affected_households['delta_tax_safety']) * \
-160            average_productivity * \
-161            affected_households['keff'] * affected_households['v']
-162
-163        # Equation is as follows: consumption_loss = expenditure_growth + exponential_multiplier * (savings - asset_damage - income_loss)
-164
-165        if add_income_loss:
-166            affected_households['c_t'] = (expenditure_growth +
-167                                          exponential_multiplier * (savings - asset_damage - income_loss))
-168        else:
-169            affected_households['c_t'] = (expenditure_growth +
-170                                          exponential_multiplier * (savings - asset_damage))
-171
-172        # affected_households['c_t'] = (gfac * affected_households['aeexp']  # expenditure growth
-173
-174        #                             + np.e**(-affected_households['recovery_rate']*_t) # exponential multiplier
-175
-176        #                             * (gfac * affected_households['aesav'] * affected_households['recovery_rate'] # savings
-177        #                                 - gfac * affected_households['v'] * affected_households[['keff', 'recovery_rate']].prod(axis=1))) # asset damage
-178
-179        #                                 # - (1 - affected_households['delta_tax_safety']) # income loss
-180        #                                 #     * average_productivity * affected_households['keff']
-181        #                                 #     * affected_households['v']))
-182
-183        # `c_t_unaffected` is the consumption at time t if the household was not affected by the disaster
-184        affected_households['c_t_unaffected'] = gfac * \
-185            affected_households['aeexp']
-186
-187        # TODO: Add a check to see whether the consumption goes below 0
-188
-189        # Consumption cannot be lower than 0
-190        affected_households.loc[affected_households['c_t'] < 1, 'c_t'] = 1
-191
-192        # TODO: Add a check whether the consumption after hit by disaster should be lower than or equal to consumption before hit by disaster
-193
-194        # consumption after hit by disaster should be lower than or equal to consumption before hit by disaster
-195        affected_households.loc[affected_households['c_t'] > affected_households['c_t_unaffected'],
-196                                'c_t'] = affected_households.loc[affected_households['c_t'] > affected_households['c_t_unaffected'], 'c_t_unaffected']
-197
-198        # total (integrated) consumption loss
-199        affected_households['consumption_loss'] += dt * \
-200            (affected_households['c_t_unaffected'] -
-201                affected_households['c_t'])
-202
-203        affected_households['consumption_loss_NPV'] += dt * \
-204            (affected_households['c_t_unaffected'] -
-205                affected_households['c_t'])*np.e**(-discount_rate*_t)
-206
-207        affected_households['net_consumption_loss'] += dt * \
-208            np.e**(-affected_households['recovery_rate']*_t) * \
-209            affected_households['v']*gfac * \
-210            affected_households['aeexp_house']
-211
-212        affected_households['net_consumption_loss_NPV'] += dt * \
-213            np.e**(-affected_households['recovery_rate']*_t) * affected_households['v']*gfac * \
-214            affected_households['aeexp_house'] * \
-215            np.e**(-discount_rate*_t)
-216
-217        # Increase the number of weeks in poverty
-218        affected_households.loc[affected_households['c_t']
-219                                < poverty_line, 'weeks_pov'] += 1
-220
-221        # Integrated wellbeing
-222        affected_households['w_final'] += dt*(affected_households['c_t'])**(1-consumption_utility) * \
-223            np.e**(-discount_rate*_t)/(1-consumption_utility)
-224
-225        # w_final2 version 02
-226        affected_households['w_final2'] += affected_households['c_t_unaffected']**(1-consumption_utility)/(1-consumption_utility)*dt*(
-227            (1-((affected_households['c_t_unaffected'] - affected_households['c_t'])/affected_households['c_t_unaffected'])*np.e**(-affected_households['recovery_rate']*_t))**(1-consumption_utility)-1)*np.e**(-discount_rate*_t)
-228
-229        # * Use to examine individual consumption recovery
-230        # Save consumption recovery value at the time _t
-231        # consumption_recovery[_t] = affected_households['c_t']
-232
-233    # Save consumption recovery as pickle file
-234    # with open('consumption_recovery.pickle', 'wb') as handle:
-235    #     pickle.dump(consumption_recovery, handle, protocol=pickle.HIGHEST_PROTOCOL)
-236
-237    return affected_households
-
- - -
-
- -
- - def - run_optimization( affected_households: pandas.core.frame.DataFrame, consumption_utility: float, discount_rate: float, average_productivity: float, optimization_timestep: float, n_years: int) -> pandas.core.frame.DataFrame: - - - -
- -
 7def run_optimization(affected_households: pd.DataFrame, consumption_utility: float, discount_rate: float, average_productivity: float, optimization_timestep: float, n_years: int) -> pd.DataFrame:
- 8    '''This function calculates the recovery rate for each affected household.
- 9
-10    Args:
-11        affected_households (pd.DataFrame): A data frame containing the affected households.
-12        consumption_utility (float): The coefficient of relative risk aversion.
-13        discount_rate (float): The discount rate.
-14        average_productivity (float): The average productivity.
-15        optimization_timestep (float): The timestep for the optimization.
-16        n_years (int): The number of years in the optimization algorithm.
-17
-18    Returns:
-19        pd.DataFrame: A data frame containing the affected households with the recovery rate.
-20    '''
-21
-22    # Set effective capital stock to zero for renters
-23    affected_households.loc[affected_households['own_rent']
-24                            == 'rent', 'keff'] = 0  # V
-25
-26    # Prepare a data frame to store optimization results
-27    optimization_results = pd.DataFrame({'aeexp': -1,
-28                                         'aeexp_house': -1,
-29                                         'keff': -1,
-30                                         'v': -1,
-31                                         'aesav': -1,
-32                                         'solution': None,
-33                                         'bankrupt': None}, index=[0])
-34
-35    optimization_results = optimization_results.reset_index(drop=True).set_index(
-36        ['aeexp',
-37         'aeexp_house',
-38         'keff',
-39         'v',
-40         'aesav'])
-41
-42    # Calculate the recovery rate for each affected household
-43    affected_households['recovery_rate'] = affected_households['v'].apply(
-44        lambda x: optimize_recovery_rate(x, optimization_results, consumption_utility, discount_rate, average_productivity, optimization_timestep, n_years))
-45
-46    # TODO: Check whether this has any impact on anything
-47    # optimization_results = optimization_results.sort_index()
-48
-49    return affected_households
-
- - -

This function calculates the recovery rate for each affected household.

- -

Args: - affected_households (pd.DataFrame): A data frame containing the affected households. - consumption_utility (float): The coefficient of relative risk aversion. - discount_rate (float): The discount rate. - average_productivity (float): The average productivity. - optimization_timestep (float): The timestep for the optimization. - n_years (int): The number of years in the optimization algorithm.

- -

Returns: - pd.DataFrame: A data frame containing the affected households with the recovery rate.

-
- - -
-
- -
- - def - optimize_recovery_rate( x, optimization_results: pandas.core.frame.DataFrame, consumption_utility: float, discount_rate: float, average_productivity: float, optimization_timestep: float, n_years: int) -> float: - - - -
- -
 52def optimize_recovery_rate(x, optimization_results: pd.DataFrame, consumption_utility: float, discount_rate: float, average_productivity: float, optimization_timestep: float, n_years: int) -> float:
- 53    try:
- 54        # Look for the existing solution
- 55        solution = optimization_results.loc[(
- 56            0, 0, 0, round(x, 3), round(average_productivity, 3)), 'solution']
- 57        return solution
- 58    except:
- 59        # No existing solution found, so we need to optimize
- 60        t_max_linspace = n_years  # years
- 61        nsteps_linspace = 52 * t_max_linspace  # total weeks
- 62        dt = t_max_linspace / nsteps_linspace
- 63
- 64        _lambda = 0
- 65        opt_step = optimization_timestep
- 66        last_dwdlambda = 0
- 67
- 68        while True:
- 69
- 70            dwdlambda = 0
- 71
- 72            for _t in np.linspace(0, t_max_linspace, nsteps_linspace):
- 73
- 74                part1 = average_productivity - \
- 75                    (average_productivity+_lambda)*x*np.e**(-_lambda*_t)
- 76                part1 = part1**(-consumption_utility)
- 77
- 78                part2 = _t * (average_productivity+_lambda) - 1
- 79
- 80                part3 = np.e**(-_t*(discount_rate+_lambda))
- 81
- 82                dwdlambda += part1 * part2 * part3 * dt
- 83
- 84            # !: All these do the same
- 85            if last_dwdlambda < 0 and dwdlambda > 0:
- 86                optimization_results.loc[(0, 0, 0, round(x, 3), round(average_productivity, 3)), [
- 87                    'solution', 'bankrupt']] = [_lambda, False]
- 88                optimization_results = optimization_results.sort_index()
- 89                return _lambda
- 90
- 91            elif last_dwdlambda > 0 and dwdlambda < 0:
- 92                optimization_results.loc[(0, 0, 0, round(x, 3), round(average_productivity, 3)), [
- 93                    'solution', 'bankrupt']] = [_lambda, False]
- 94                optimization_results = optimization_results.sort_index()
- 95                return _lambda
- 96
- 97            # !: That's why assigning more than 10 years does not work, we need to change 10 to `n_years`?
- 98            elif _lambda > 10:
- 99                optimization_results.loc[(0, 0, 0, round(x, 3), round(average_productivity, 3)), [
-100                    'solution', 'bankrupt']] = [_lambda, False]
-101                optimization_results = optimization_results.sort_index()
-102                return _lambda
-103
-104            else:
-105                last_dwdlambda = dwdlambda
-106            _lambda += opt_step
-
- - - - -
-
- -
- - def - integrate_wellbeing( affected_households: pandas.core.frame.DataFrame, consumption_utility: float, discount_rate: float, income_and_expenditure_growth: float, average_productivity: float, poverty_line: float, n_years: int, add_income_loss: bool, cash_transfer: dict = {}) -> pandas.core.frame.DataFrame: - - - -
- -
109def integrate_wellbeing(affected_households: pd.DataFrame,
-110                        consumption_utility: float,
-111                        discount_rate: float,
-112                        income_and_expenditure_growth: float,
-113                        average_productivity: float,
-114                        poverty_line: float,
-115                        n_years: int,
-116                        add_income_loss: bool,
-117                        cash_transfer: dict = {},
-118                        ) -> pd.DataFrame:
-119
-120    # We need to reset some columns to zero to start the integration
-121    columns = ['consumption_loss', 'consumption_loss_NPV', 'net_consumption_loss',
-122               'net_consumption_loss_NPV', 'c_t', 'w_final', 'weeks_pov', 'w_final2']
-123    affected_households[columns] = [0., 0., 0., 0., 0., 0., 0., 0.]
-124
-125    # Define the number of weeks given the number of years
-126    n_weeks = 52 * n_years
-127    dt = n_years / n_weeks
-128
-129    # * Store consumption recovery in a dict for verification and debugging purposes
-130    # consumption_recovery = {}
-131
-132    # We need to adjust the cash transfer to the timestep of the integration
-133    if cash_transfer != {}:  # If there is a cash transfer
-134        cash_transfer_transformed = {np.linspace(0, n_years, n_weeks)[
-135            t]: cash_transfer[t] for t in list(cash_transfer.keys())}
-136    else:
-137        cash_transfer_transformed = {}
-138
-139    # Calculate the consumption loss for each affected household
-140    for _t in np.linspace(0, n_years, n_weeks):
-141        gfac = (1 + income_and_expenditure_growth)**_t
-142
-143        # TODO: Add an extra condition about to whom the transfer is given
-144        # A "dynamic policy"
-145        if _t in list(cash_transfer_transformed.keys()):
-146            affected_households['aesav'] += cash_transfer_transformed[_t]
-147
-148        # `c_t` is the consumption at time t
-149        # !: It seems that keff remains constant over time
-150        expenditure_growth = gfac * affected_households['aeexp']
-151        exponential_multiplier = np.e**(
-152            -affected_households['recovery_rate']*_t)
-153        savings = gfac * \
-154            affected_households['aesav'] * affected_households['recovery_rate']
-155        asset_damage = gfac * \
-156            affected_households['v'] * \
-157            affected_households[['keff', 'recovery_rate']].prod(axis=1)
-158        
-159        # TODO: Make sure that `delta_tax_safety` is not 0
-160        income_loss = gfac * (1 - affected_households['delta_tax_safety']) * \
-161            average_productivity * \
-162            affected_households['keff'] * affected_households['v']
-163
-164        # Equation is as follows: consumption_loss = expenditure_growth + exponential_multiplier * (savings - asset_damage - income_loss)
-165
-166        if add_income_loss:
-167            affected_households['c_t'] = (expenditure_growth +
-168                                          exponential_multiplier * (savings - asset_damage - income_loss))
-169        else:
-170            affected_households['c_t'] = (expenditure_growth +
-171                                          exponential_multiplier * (savings - asset_damage))
-172
-173        # affected_households['c_t'] = (gfac * affected_households['aeexp']  # expenditure growth
-174
-175        #                             + np.e**(-affected_households['recovery_rate']*_t) # exponential multiplier
-176
-177        #                             * (gfac * affected_households['aesav'] * affected_households['recovery_rate'] # savings
-178        #                                 - gfac * affected_households['v'] * affected_households[['keff', 'recovery_rate']].prod(axis=1))) # asset damage
-179
-180        #                                 # - (1 - affected_households['delta_tax_safety']) # income loss
-181        #                                 #     * average_productivity * affected_households['keff']
-182        #                                 #     * affected_households['v']))
-183
-184        # `c_t_unaffected` is the consumption at time t if the household was not affected by the disaster
-185        affected_households['c_t_unaffected'] = gfac * \
-186            affected_households['aeexp']
-187
-188        # TODO: Add a check to see whether the consumption goes below 0
-189
-190        # Consumption cannot be lower than 0
-191        affected_households.loc[affected_households['c_t'] < 1, 'c_t'] = 1
-192
-193        # TODO: Add a check whether the consumption after hit by disaster should be lower than or equal to consumption before hit by disaster
-194
-195        # consumption after hit by disaster should be lower than or equal to consumption before hit by disaster
-196        affected_households.loc[affected_households['c_t'] > affected_households['c_t_unaffected'],
-197                                'c_t'] = affected_households.loc[affected_households['c_t'] > affected_households['c_t_unaffected'], 'c_t_unaffected']
-198
-199        # total (integrated) consumption loss
-200        affected_households['consumption_loss'] += dt * \
-201            (affected_households['c_t_unaffected'] -
-202                affected_households['c_t'])
-203
-204        affected_households['consumption_loss_NPV'] += dt * \
-205            (affected_households['c_t_unaffected'] -
-206                affected_households['c_t'])*np.e**(-discount_rate*_t)
-207
-208        affected_households['net_consumption_loss'] += dt * \
-209            np.e**(-affected_households['recovery_rate']*_t) * \
-210            affected_households['v']*gfac * \
-211            affected_households['aeexp_house']
-212
-213        affected_households['net_consumption_loss_NPV'] += dt * \
-214            np.e**(-affected_households['recovery_rate']*_t) * affected_households['v']*gfac * \
-215            affected_households['aeexp_house'] * \
-216            np.e**(-discount_rate*_t)
-217
-218        # Increase the number of weeks in poverty
-219        affected_households.loc[affected_households['c_t']
-220                                < poverty_line, 'weeks_pov'] += 1
-221
-222        # Integrated wellbeing
-223        affected_households['w_final'] += dt*(affected_households['c_t'])**(1-consumption_utility) * \
-224            np.e**(-discount_rate*_t)/(1-consumption_utility)
-225
-226        # w_final2 version 02
-227        affected_households['w_final2'] += affected_households['c_t_unaffected']**(1-consumption_utility)/(1-consumption_utility)*dt*(
-228            (1-((affected_households['c_t_unaffected'] - affected_households['c_t'])/affected_households['c_t_unaffected'])*np.e**(-affected_households['recovery_rate']*_t))**(1-consumption_utility)-1)*np.e**(-discount_rate*_t)
-229
-230        # * Use to examine individual consumption recovery
-231        # Save consumption recovery value at the time _t
-232        # consumption_recovery[_t] = affected_households['c_t']
-233
-234    # Save consumption recovery as pickle file
-235    # with open('consumption_recovery.pickle', 'wb') as handle:
-236    #     pickle.dump(consumption_recovery, handle, protocol=pickle.HIGHEST_PROTOCOL)
-237
-238    return affected_households
-
- - - - -
-
- - \ No newline at end of file diff --git a/experiments/config_manager.py b/experiments/config_manager.py deleted file mode 100644 index 3365cce..0000000 --- a/experiments/config_manager.py +++ /dev/null @@ -1,102 +0,0 @@ -import yaml -from pathlib import Path - - -def load_config(country: str, return_period: int, disaster_type: str, is_conflict: bool = False) -> dict: - '''Load configuration for the specified case country. - - Args: - country (str): The country for which to load the configuration. - return_period (int): The return period for the disaster. - disaster_type (str): The type of disaster. - is_conflict (bool): Whether the country is in conflict. - - Returns: - dict: The configuration for the specified case country. - ''' - - config_path = Path(f"../config/{country}.yaml") - - if not config_path.exists(): - raise FileNotFoundError( - f"Config file for {country} not found at {config_path}") - - with open(config_path, "r") as file: - config = yaml.safe_load(file) - - check_config_parameters(config) - - config['constants']['return_period'] = return_period - config['constants']['disaster_type'] = disaster_type - - if is_conflict: - config['constants']['is_conflict'] = True - else: - config['constants']['is_conflict'] = False - - return config - -def check_config_parameters(config: dict) -> None: - '''Check if the configuration parameters are valid. - - Args: - config (dict): The configuration to check. - - Returns: - None - - Raises: - ValueError: If the configuration parameters are not valid. - ''' - return_periods = [10, 50, 100, 250, 500, 1000] - disaster_types = ['hurricane', 'flood'] - - if 'return_period' not in config['constants']: - raise ValueError("Return period not specified in configuration.") - - if 'disaster_type' not in config['constants']: - raise ValueError("Disaster type not specified in configuration.") - - if 'return_period' not in return_periods: - raise ValueError( - f"Return period {config['constants']['return_period']} not in available return periods: {return_periods}") - - if 'disaster_type' not in disaster_types: - raise ValueError( - f"Disaster type {config['constants']['disaster_type']} not in available disaster types: ['hurricane', 'flood']") - - neccessary_parameters = ['country', 'avg_prod', 'inc_exp_growth', 'cons_util', 'disc_rate', 'disaster_type', 'calc_exposure_params', 'identify_aff_params', 'add_inc_loss', 'pov_bias', 'lambda_incr', 'yrs_to_rec', 'rnd_inc_params', 'rnd_sav_params', 'rnd_rent_params', 'rnd_house_vuln_params', 'min_households', 'atol', 'save_households', 'save_consumption_recovery', 'regions', 'levers', 'uncertainties'] - exposure_neccessary_parameters = ['distr', 'high', 'low'] - identify_aff_neccessary_parameters = ['delta_pct', 'distr', 'high', 'low', 'num_masks'] - rnd_inc_neccessary_parameters = ['randomize', 'distr', 'delta'] - rnd_sav_neccessary_parameters = ['randomize', 'distr', 'avg', 'delta'] - rnd_rent_neccessary_parameters = ['randomize', 'distr', 'avg', 'delta'] - rnd_house_vuln_neccessary_parameters = ['randomize', 'distr', 'low', 'high', 'min_thresh', 'max_thresh'] - - for parameter in neccessary_parameters: - if parameter not in config['constants']: - raise ValueError(f"Parameter {parameter} not found in configuration.") - - for parameter in exposure_neccessary_parameters: - if parameter not in config['constants']['calc_exposure_params']: - raise ValueError(f"Parameter {parameter} not found in calc_exposure_params.") - - for parameter in identify_aff_neccessary_parameters: - if parameter not in config['constants']['identify_aff_params']: - raise ValueError(f"Parameter {parameter} not found in identify_aff_params.") - - for parameter in rnd_inc_neccessary_parameters: - if parameter not in config['constants']['rnd_inc_params']: - raise ValueError(f"Parameter {parameter} not found in rnd_inc_params.") - - for parameter in rnd_sav_neccessary_parameters: - if parameter not in config['constants']['rnd_sav_params']: - raise ValueError(f"Parameter {parameter} not found in rnd_sav_params.") - - for parameter in rnd_rent_neccessary_parameters: - if parameter not in config['constants']['rnd_rent_params']: - raise ValueError(f"Parameter {parameter} not found in rnd_rent_params.") - - for parameter in rnd_house_vuln_neccessary_parameters: - if parameter not in config['constants']['rnd_house_vuln_params']: - raise ValueError(f"Parameter {parameter} not found in rnd_house_vuln_params.") \ No newline at end of file diff --git a/experiments/experiment_runner.py b/experiments/experiment_runner.py deleted file mode 100644 index eb7bb03..0000000 --- a/experiments/experiment_runner.py +++ /dev/null @@ -1,44 +0,0 @@ -from pathlib import Path -from ema_workbench import perform_experiments, MultiprocessingEvaluator, save_results, Model - - -def run_experiments(experimental_setup: dict) -> None: - '''Run experiments with the specified setup with the use of EMA Workbench and save the results. - - Args: - experimental_setup (dict): A dictionary containing the setup for the experiments. - - Returns: - None - ''' - country = experimental_setup['country'] - return_period = experimental_setup['return_period'] - model = experimental_setup['model'] - n_scenarios = experimental_setup['n_scenarios'] - n_policies = experimental_setup['n_policies'] - multiprocessing = experimental_setup['multiprocessing'] - n_processes = experimental_setup['n_processes'] - - if multiprocessing: - with MultiprocessingEvaluator(model, n_processes=n_processes) as evaluator: - results = evaluator.perform_experiments( - scenarios=n_scenarios, policies=n_policies) - else: - results = perform_experiments( - models=model, scenarios=n_scenarios, policies=n_policies) - - save_experiment_results(country, return_period, model, - results, n_scenarios, n_policies) - - -def save_experiment_results(country: str, return_period: int, model: Model, results: dict, n_scenarios: int, n_policies: int): - """Saves experiment results to a file, taking into account if there was a conflict.""" - results_path = Path(f'../results/{country}') - results_path.mkdir(parents=True, exist_ok=True) - - is_conflict = getattr(model.constants._data.get( - 'is_conflict'), 'value', False) - - conflict_str = ", conflict=True" if is_conflict else "" - filename = f"return_period={return_period}, scenarios={n_scenarios}, policies={n_policies}{conflict_str}.tar.gz" - save_results(results, results_path / filename) diff --git a/experiments/model_setup.py b/experiments/model_setup.py deleted file mode 100644 index 67b1f3c..0000000 --- a/experiments/model_setup.py +++ /dev/null @@ -1,48 +0,0 @@ -from ema_workbench import Model -from ema_workbench.em_framework.parameters import IntegerParameter, CategoricalParameter, Constant -from ema_workbench.em_framework.outcomes import ArrayOutcome -from unbreakable.model import model - - -def setup_model(config: dict) -> Model: - """ - Set up the EMA Workbench model based on the provided configuration. - - Args: - config (dict): Configuration dictionary loaded from the YAML file. - - Returns: - Model: Configured EMA Workbench model. - """ - my_model = Model(name="model", function=model) - - # Extract and set up uncertainties, constants, and levers from the config - # uncertainties = config.get("uncertainties", {}) - constants = config.get("constants", {}) - levers = config.get("levers", {}) - - # Define seed as an uncertainty for multiple runs, - # By specifying a wider range, we want to ensure that the seed is likely to be different for each run - seed_start = 0 - seed_end = 1000000000 - - # Fix seed to ensure reproducibility - # NOTE: If running multiple instances of the model in parallel, the seed will be the same for all instances - # np.random.seed(42) - - my_model.uncertainties = [IntegerParameter( - "random_seed", seed_start, seed_end)] - - # Constants - my_model.constants = [Constant(key, value) - for key, value in constants.items()] - - # Levers - my_model.levers = [CategoricalParameter( - 'current_policy', [values for _, values in levers.items()])] - - # Outcomes - my_model.outcomes = [ArrayOutcome(region) - for region in constants.get('regions', [])] - - return my_model diff --git a/main.py b/main.py deleted file mode 100644 index 82ce3e6..0000000 --- a/main.py +++ /dev/null @@ -1,36 +0,0 @@ -from experiments.config_manager import load_config -from experiments.model_setup import setup_model -from experiments.experiment_runner import run_experiments -from ema_workbench import ema_logging - -ema_logging.log_to_stderr(ema_logging.INFO) - - -def main(): - try: - country = 'Dominica' - disaster_type = 'hurricane' - return_period = 100 - is_conflict = False - config = load_config(country, return_period, - disaster_type, is_conflict) - model = setup_model(config) - - experimental_setup = { - 'country': country, - 'return_period': return_period, - 'model': model, - 'n_scenarios': 2, - 'n_policies': 0, - 'multiprocessing': False, - 'n_processes': 12 - } - - run_experiments(experimental_setup) - - except Exception as e: - print(f"An error occurred: {e}") - - -if __name__ == "__main__": - main() diff --git a/requirements.txt b/requirements.txt index 309e08c..f82c3d8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,14 +1,291 @@ -ema_workbench==2.4.1 -geopandas==0.12.2 -mapclassify==2.5.0 -matplotlib==3.7.1 -mycolorpy==1.5.1 -numpy==1.24.3 -pandas==1.5.3 -ptitprince==0.2.6 -PyYAML==6.0 -scikit_learn==1.2.2 -scipy==1.10.1 -seaborn==0.11.0 -setuptools==68.0.0 -tqdm==4.65.0 +# This file may be used to create an environment using: +# $ conda create --name --file +# platform: win-64 +anyio=4.4.0=pyhd8ed1ab_0 +argon2-cffi=23.1.0=pyhd8ed1ab_0 +argon2-cffi-bindings=21.2.0=py311he736701_5 +arrow=1.3.0=pyhd8ed1ab_0 +asttokens=2.4.1=pyhd8ed1ab_0 +astunparse=1.6.3=py_0 +async-lru=2.0.4=pyhd8ed1ab_0 +attrs=23.1.0=py311haa95532_0 +babel=2.14.0=pyhd8ed1ab_0 +beautifulsoup4=4.12.3=pyha770c72_0 +blas=1.0=mkl +bleach=6.1.0=pyhd8ed1ab_0 +blosc=1.21.3=h6c2663c_0 +boost-cpp=1.82.0=h59b6b97_2 +bottleneck=1.3.7=py311hd7041d2_0 +branca=0.6.0=py311haa95532_0 +brotli=1.0.9=h2bbff1b_8 +brotli-bin=1.0.9=h2bbff1b_8 +brotli-python=1.0.9=py311hd77b12b_8 +bzip2=1.0.8=h2bbff1b_6 +ca-certificates=2024.8.30=h56e8100_0 +cachecontrol=0.12.11=py311haa95532_1 +cached-property=1.5.2=hd8ed1ab_1 +cached_property=1.5.2=pyha770c72_1 +cairo=1.16.0=haedb8bc_5 +certifi=2024.8.30=py311haa95532_0 +cffi=1.16.0=py311h2bbff1b_1 +cfitsio=3.470=h2bbff1b_7 +charset-normalizer=3.3.2=pyhd3eb1b0_0 +cleo=2.1.0=py311haa95532_0 +click=8.1.7=py311haa95532_0 +click-plugins=1.1.1=pyhd3eb1b0_0 +cligj=0.7.2=pyhd3eb1b0_0 +colorama=0.4.6=py311haa95532_0 +comm=0.2.2=pyhd8ed1ab_0 +contourpy=1.2.0=py311h59b6b97_0 +crashtest=0.4.1=py311haa95532_0 +cryptography=43.0.0=py311h89fc84f_0 +cycler=0.11.0=pyhd3eb1b0_0 +debugpy=1.8.5=py311hda3d55a_1 +decorator=5.1.1=pyhd8ed1ab_0 +defusedxml=0.7.1=pyhd8ed1ab_0 +dill=0.3.8=pypi_0 +distlib=0.3.8=py311haa95532_0 +dulwich=0.21.3=py311h2bbff1b_0 +ema-workbench=2.5.2=pypi_0 +entrypoints=0.4=pyhd8ed1ab_0 +et_xmlfile=1.1.0=py311haa95532_0 +exceptiongroup=1.2.2=pyhd8ed1ab_0 +executing=2.1.0=pyhd8ed1ab_0 +expat=2.6.3=h5da7b33_0 +filelock=3.13.1=py311haa95532_0 +fiona=1.9.5=py311hf62ec03_0 +folium=0.14.0=py311haa95532_0 +fontconfig=2.14.1=hb33846d_3 +fonttools=4.51.0=py311h2bbff1b_0 +fqdn=1.5.1=pyhd8ed1ab_0 +freetype=2.12.1=ha860e81_0 +freexl=2.0.0=hd7a5696_0 +gdal=3.6.2=py311h4e7b5b2_5 +geopandas=0.14.2=py311haa95532_0 +geopandas-base=0.14.2=py311haa95532_0 +geos=3.8.0=h33f27b4_0 +geotiff=1.7.0=h4545760_3 +glib=2.78.4=hd77b12b_0 +glib-tools=2.78.4=hd77b12b_0 +h11=0.14.0=pyhd8ed1ab_0 +h2=4.1.0=pyhd8ed1ab_0 +hdf4=4.2.13=h712560f_2 +hdf5=1.12.1=h51c971a_3 +hpack=4.0.0=pyh9f0ad1d_0 +html5lib=1.1=pyhd3eb1b0_0 +httpcore=1.0.5=pyhd8ed1ab_0 +httpx=0.27.2=pyhd8ed1ab_0 +hyperframe=6.0.1=pyhd8ed1ab_0 +icc_rt=2022.1.0=h6049295_2 +icu=73.1=h6c2663c_0 +idna=3.7=py311haa95532_0 +importlib-metadata=7.0.1=py311haa95532_0 +importlib_metadata=7.0.1=hd3eb1b0_0 +importlib_resources=6.4.5=pyhd8ed1ab_0 +intel-openmp=2023.1.0=h59b6b97_46320 +ipykernel=6.29.5=pyh4bbf305_0 +ipyparallel=8.6.1=py311haa95532_0 +ipython=8.27.0=pyh7428d3b_0 +isoduration=20.11.0=pyhd8ed1ab_0 +jaraco.classes=3.2.1=pyhd3eb1b0_0 +jedi=0.19.1=pyhd8ed1ab_0 +jinja2=3.1.4=py311haa95532_0 +joblib=1.4.2=py311haa95532_0 +jpeg=9e=h827c3e9_3 +json5=0.9.25=pyhd8ed1ab_0 +jsonpointer=3.0.0=py311h1ea47a8_1 +jsonschema=4.19.2=py311haa95532_0 +jsonschema-specifications=2023.7.1=py311haa95532_0 +jsonschema-with-format-nongpl=4.19.2=pyhd8ed1ab_0 +jupyter-lsp=2.2.5=pyhd8ed1ab_0 +jupyter_client=7.4.9=pyhd8ed1ab_0 +jupyter_core=5.7.2=py311h1ea47a8_0 +jupyter_events=0.10.0=pyhd8ed1ab_0 +jupyter_server=2.14.2=pyhd8ed1ab_0 +jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 +jupyterlab=4.2.5=pyhd8ed1ab_0 +jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 +jupyterlab_server=2.27.3=pyhd8ed1ab_0 +kealib=1.5.0=hde4a422_1 +keyring=23.13.1=py311haa95532_0 +kiwisolver=1.4.4=py311hd77b12b_0 +krb5=1.20.1=h5b6d351_0 +lcms2=2.12=h83e58a3_0 +lerc=3.0=hd77b12b_0 +libboost=1.82.0=h3399ecb_2 +libbrotlicommon=1.0.9=h2bbff1b_8 +libbrotlidec=1.0.9=h2bbff1b_8 +libbrotlienc=1.0.9=h2bbff1b_8 +libclang=14.0.6=default_hb5a9fac_1 +libclang13=14.0.6=default_h8e68704_1 +libcurl=8.9.1=h0416ee5_0 +libdeflate=1.17=h2bbff1b_1 +libffi=3.4.4=hd77b12b_1 +libgdal=3.6.2=h0e70117_5 +libglib=2.78.4=ha17d25a_0 +libiconv=1.16=h2bbff1b_3 +libkml=1.3.0=h63940dd_7 +libnetcdf=4.8.1=h6685c40_4 +libpng=1.6.39=h8cc25b3_0 +libpq=12.17=h906ac69_0 +libsodium=1.0.18=h8d14728_1 +libspatialindex=1.9.3=h6c2663c_0 +libspatialite=5.1.0=h25d3e1c_1 +libssh2=1.11.0=h291bd65_0 +libtiff=4.5.1=hd77b12b_0 +libwebp-base=1.3.2=h2bbff1b_0 +libxml2=2.13.1=h24da03e_2 +libzip=1.8.0=h289538f_1 +llvmlite=0.43.0=py311hf2fb9eb_0 +lockfile=0.12.2=py311haa95532_0 +lz4-c=1.9.4=h2bbff1b_1 +mapclassify=2.5.0=py311haa95532_0 +markupsafe=2.1.3=py311h2bbff1b_0 +matplotlib=3.9.2=py311haa95532_0 +matplotlib-base=3.9.2=py311h472561b_0 +matplotlib-inline=0.1.7=pyhd8ed1ab_0 +minizip=4.0.3=hb68bac4_0 +mistune=3.0.2=pyhd8ed1ab_0 +mkl=2023.1.0=h6b88ed4_46358 +mkl-service=2.4.0=py311h2bbff1b_1 +mkl_fft=1.3.10=py311h827c3e9_0 +mkl_random=1.2.7=py311hea22821_0 +more-itertools=10.1.0=py311haa95532_0 +msgpack-python=1.0.3=py311h59b6b97_0 +multiprocess=0.70.16=pypi_0 +nbclient=0.10.0=pyhd8ed1ab_0 +nbconvert=7.16.4=hd8ed1ab_1 +nbconvert-core=7.16.4=pyhd8ed1ab_1 +nbconvert-pandoc=7.16.4=hd8ed1ab_1 +nbformat=5.10.4=pyhd8ed1ab_0 +nest-asyncio=1.6.0=pyhd8ed1ab_0 +networkx=3.3=py311haa95532_0 +notebook=7.2.2=pyhd8ed1ab_0 +notebook-shim=0.2.4=pyhd8ed1ab_0 +numba=0.60.0=py311hea22821_0 +numexpr=2.8.7=py311h1fcbade_0 +numpy=1.26.4=py311hdab7c0b_0 +numpy-base=1.26.4=py311hd01c5d8_0 +openjpeg=2.5.2=hae555c5_0 +openpyxl=3.1.5=py311h827c3e9_0 +openssl=3.3.2=h2466b09_0 +overrides=7.7.0=pyhd8ed1ab_0 +packaging=24.1=py311haa95532_0 +pandas=2.2.2=py311hea22821_0 +pandoc=2.12=haa95532_3 +pandocfilters=1.5.0=pyhd8ed1ab_0 +parso=0.8.4=pyhd8ed1ab_0 +patsy=0.5.6=pypi_0 +pcre2=10.42=h0ff8eda_1 +pdoc=14.4.0=pyhd8ed1ab_0 +pexpect=4.8.0=pyhd3eb1b0_3 +pickleshare=0.7.5=py_1003 +pillow=10.4.0=py311h827c3e9_0 +pip=24.2=py311haa95532_0 +pixman=0.40.0=h2bbff1b_1 +pkginfo=1.10.0=py311haa95532_0 +platformdirs=2.5.2=py311haa95532_0 +platypus-opt=1.3.1=pypi_0 +ply=3.11=py311haa95532_0 +poetry=1.4.0=py311haa95532_0 +poetry-core=1.5.1=py311haa95532_0 +poetry-plugin-export=1.3.0=py311hfacae44_0 +poppler=22.12.0=h0bf3bde_3 +poppler-data=0.4.11=haa95532_1 +proj=9.3.1=ha107b6e_0 +prometheus_client=0.20.0=pyhd8ed1ab_0 +prompt-toolkit=3.0.47=pyha770c72_0 +psutil=6.0.0=py311he736701_1 +ptyprocess=0.7.0=pyhd3eb1b0_2 +pure_eval=0.2.3=pyhd8ed1ab_0 +pybind11-abi=5=hd3eb1b0_0 +pycparser=2.21=pyhd3eb1b0_0 +pygments=2.18.0=pyhd8ed1ab_0 +pyopenssl=24.2.1=py311haa95532_0 +pyparsing=3.1.2=py311haa95532_0 +pyproj=3.6.1=py311ha997c60_0 +pyproject_hooks=1.0.0=py311haa95532_0 +pyqt=5.15.10=py311hd77b12b_0 +pyqt5-sip=12.13.0=py311h2bbff1b_0 +pysocks=1.7.1=py311haa95532_0 +python=3.11.9=he1021f5_0 +python-build=0.10.0=py311haa95532_0 +python-dateutil=2.9.0post0=py311haa95532_2 +python-fastjsonschema=2.20.0=pyhd8ed1ab_0 +python-installer=0.6.0=py311haa95532_0 +python-json-logger=2.0.7=pyhd8ed1ab_0 +python-tzdata=2023.3=pyhd3eb1b0_0 +python_abi=3.11=2_cp311 +pytz=2024.1=py311haa95532_0 +pywin32=306=py311h12c1d0e_2 +pywin32-ctypes=0.2.2=py311haa95532_0 +pywinpty=2.0.13=py311hda3d55a_1 +pyyaml=6.0.2=py311he736701_1 +pyzmq=24.0.1=py311h7b3f143_1 +qhull=2020.2=h59b6b97_2 +qt-main=5.15.2=h19c9488_10 +rapidfuzz=3.5.2=py311h5da7b33_0 +referencing=0.30.2=py311haa95532_0 +requests=2.32.3=py311haa95532_0 +requests-toolbelt=0.9.1=pyhd3eb1b0_0 +rfc3339-validator=0.1.4=pyhd8ed1ab_0 +rfc3986-validator=0.1.1=pyh9f0ad1d_0 +rpds-py=0.10.6=py311h062c2fa_0 +rtree=1.0.1=py311h2eaa2aa_0 +salib=1.5.1=pypi_0 +scikit-learn=1.5.1=py311hea22821_0 +scipy=1.13.1=py311h9f229c6_0 +seaborn=0.13.2=py311haa95532_0 +send2trash=1.8.3=pyh5737063_0 +setuptools=72.1.0=py311haa95532_0 +shapely=2.0.5=py311h82fc408_0 +shellingham=1.5.0=py311haa95532_0 +sip=6.7.12=py311hd77b12b_0 +six=1.16.0=pyhd3eb1b0_1 +sniffio=1.3.1=pyhd8ed1ab_0 +soupsieve=2.5=pyhd8ed1ab_1 +sqlite=3.45.3=h2bbff1b_0 +stack_data=0.6.2=pyhd8ed1ab_0 +statsmodels=0.14.2=pypi_0 +tbb=2021.8.0=h59b6b97_0 +terminado=0.18.1=pyh5737063_0 +threadpoolctl=3.5.0=py311h746a85d_0 +tiledb=2.3.3=hd8964de_3 +tinycss2=1.3.0=pyhd8ed1ab_0 +tk=8.6.14=h0416ee5_0 +tomli=2.0.1=pyhd8ed1ab_0 +tomlkit=0.11.1=py311haa95532_0 +tornado=6.4.1=py311h827c3e9_0 +tqdm=4.66.5=py311h746a85d_0 +traitlets=5.14.3=pyhd8ed1ab_0 +trove-classifiers=2023.10.18=py311haa95532_0 +types-python-dateutil=2.9.0.20240906=pyhd8ed1ab_0 +typing-extensions=4.12.2=hd8ed1ab_0 +typing_extensions=4.12.2=pyha770c72_0 +typing_utils=0.1.0=pyhd8ed1ab_0 +tzdata=2024a=h04d1e81_0 +ucrt=10.0.22621.0=h57928b3_0 +unbreakable=0.3.0=dev_0 +unicodedata2=15.1.0=py311h2bbff1b_0 +uri-template=1.3.0=pyhd8ed1ab_0 +uriparser=0.9.7=h2bbff1b_0 +urllib3=1.26.19=py311haa95532_0 +vc=14.40=h2eaa2aa_0 +vc14_runtime=14.40.33810=hcc2c482_20 +virtualenv=20.16.2=py311haa95532_0 +vs2015_runtime=14.40.33810=h3bf8584_20 +wcwidth=0.2.13=pyhd8ed1ab_0 +webcolors=24.8.0=pyhd8ed1ab_0 +webencodings=0.5.1=py311haa95532_1 +websocket-client=1.8.0=pyhd8ed1ab_0 +wheel=0.43.0=py311haa95532_0 +win_inet_pton=1.1.0=py311haa95532_0 +winpty=0.4.3=4 +xerces-c=3.2.4=hd77b12b_1 +xyzservices=2022.9.0=py311haa95532_1 +xz=5.4.6=h8cc25b3_1 +yaml=0.2.5=h8ffe710_2 +zeromq=4.3.4=h0e60522_1 +zipp=3.17.0=py311haa95532_0 +zlib=1.2.13=h8cc25b3_1 +zstd=1.5.5=hd43e919_2 \ No newline at end of file diff --git a/sensitivity-analysis.ipynb b/sensitivity-analysis.ipynb deleted file mode 100644 index 2c95c12..0000000 --- a/sensitivity-analysis.ipynb +++ /dev/null @@ -1,362 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "import math\n", - "import numpy as np\n", - "import seaborn as sns\n", - "import scipy.stats as stats" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "def generate_households(num_households=1, exp:float = None, v:float = None, fix_seed:bool=True):\n", - " '''Generate dummy households.'''\n", - " if fix_seed:\n", - " np.random.seed(0) # Ensure reproducibility\n", - "\n", - " data = {'exp_house': 0,\n", - " 'consumption_loss': 0,\n", - " 'consumption_loss_npv': 0,\n", - " 'net_consumption_loss': 0,\n", - " 'net_consumption_loss_npv': 0,\n", - " 'c_t': 0,\n", - " 'c_t_unaffected': 0,\n", - " 'wellbeing': 0}\n", - " \n", - " if exp is None:\n", - " # Generate expenditure\n", - " lower, upper = 153, 5474\n", - " mu, sigma = 1099, 1099\n", - " X = stats.truncnorm((lower - mu) / sigma,\n", - " (upper - mu) / sigma, loc=mu, scale=sigma)\n", - " exp = X.rvs(num_households)\n", - " data['exp'] = exp\n", - " else:\n", - " data['exp'] = exp\n", - "\n", - " # Income is a product of expenditure and a random coefficient\n", - " inc_multiplier = 1.48 \n", - " inc_delta = 0.1\n", - " low = inc_multiplier - inc_delta\n", - " high = inc_multiplier + inc_delta\n", - " data['inc'] = data['exp'] * np.random.uniform(low, high)\n", - "\n", - " sav_multiplier = 0.0204\n", - " sav_delta = 0.02\n", - " low = sav_multiplier - sav_delta\n", - " high = sav_multiplier + sav_delta\n", - " data['sav'] = data['inc'] * np.random.uniform(low, high)\n", - "\n", - " # divide by average productivity of capital\n", - " data['keff'] = data['inc'] / 0.35\n", - "\n", - " if v is None:\n", - " data['v'] = np.random.uniform(0.2, 0.8, num_households)\n", - " else:\n", - " data['v'] = v\n", - "\n", - " # Sort column)\n", - " sorted_columns = ['exp', 'inc', 'sav', 'keff', 'exp_house', 'v', 'consumption_loss', 'consumption_loss_npv',\n", - " 'net_consumption_loss', 'net_consumption_loss_npv', 'c_t', 'c_t_unaffected', 'wellbeing']\n", - "\n", - " return pd.DataFrame(data, index=[0])[sorted_columns]" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "def calculate_consumption_recovery(df:pd.DataFrame, parameters:dict, print_statistics:bool=False) -> pd.DataFrame:\n", - " '''Calculate consumption recovery'''\n", - " initial_expenditure = df['exp'].values\n", - " initial_savings = df['sav'].values\n", - " effective_capital = df['keff'].values\n", - "\n", - " recovery_rate = parameters['recovery_rate']\n", - " years_to_recover = parameters['years_to_recover']\n", - " income_and_expenditure_growth = parameters['income_and_expenditure_growth']\n", - " average_productivity = parameters['average_productivity']\n", - " consumption_utility = parameters['consumption_utility']\n", - " discount_rate = parameters['discount_rate']\n", - " \n", - " try:\n", - " vulnerability_increase_factor = parameters['vulnerability_increase_factor']\n", - " vulnerability = parameters['v']\n", - " except:\n", - " vulnerability_increase_factor = 1\n", - " vulnerability = df['v'].values\n", - " \n", - " totaL_weeks = 52 * years_to_recover\n", - " dt = 1 / 52\n", - " consumption = {}\n", - " consumption_unaffected = {}\n", - " wellbeing = {}\n", - " consumption_loss = {}\n", - " consumption_loss_npv = {}\n", - "\n", - " for time in np.linspace(0, years_to_recover, totaL_weeks):\n", - " exponential_multiplier = np.e**(-recovery_rate * time)\n", - " growth_factor = (1 + income_and_expenditure_growth)**time\n", - "\n", - " current_expenditure = growth_factor * initial_expenditure\n", - " current_savings = growth_factor * initial_savings * (1 / vulnerability_increase_factor) # * recovery_rate\n", - " \n", - " asset_loss = growth_factor * effective_capital * vulnerability * vulnerability_increase_factor * recovery_rate \n", - " income_loss = growth_factor * average_productivity * effective_capital * vulnerability * vulnerability_increase_factor # * recovery_rate\n", - " # income_loss = 0\n", - "\n", - " c_t = np.maximum(current_expenditure + exponential_multiplier * (current_savings - asset_loss - income_loss), 0)\n", - " c_t_unaffected = current_expenditure\n", - " c_t = np.minimum(c_t, c_t_unaffected)\n", - " \n", - " consumption[time] = c_t\n", - " consumption_unaffected[time] = c_t_unaffected\n", - " consumption_loss[time] = dt * (c_t_unaffected - c_t)\n", - " consumption_loss_npv[time] = dt * (c_t_unaffected - c_t)*np.e**(-discount_rate * time)\n", - "\n", - " wellbeing[time] = c_t_unaffected**(1 - consumption_utility) / (1 - consumption_utility) * dt \\\n", - " * ((1 - ((c_t_unaffected - c_t) / c_t_unaffected) * np.e**(-recovery_rate * time))**(1 - consumption_utility) - 1) \\\n", - " * np.e**(-discount_rate * time)\n", - "\n", - " total_consumption_loss = sum(consumption_loss.values())\n", - " total_consumption_loss_npv = sum(consumption_loss_npv.values())\n", - "\n", - " if print_statistics:\n", - " print('Total consumption loss:', \"{:,}\".format(round(total_consumption_loss[0])))\n", - " print('Total consumption loss NPV:', \"{:,}\".format(round(total_consumption_loss_npv[0])))\n", - "\n", - " return pd.DataFrame(consumption), pd.DataFrame(consumption_unaffected), pd.DataFrame(consumption_loss), pd.DataFrame(consumption_loss_npv), pd.DataFrame(wellbeing)" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Total consumption loss: 10,221\n", - "Total consumption loss NPV: 9,464\n" - ] - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAEECAYAAAA4Qc+SAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAArEAAAKxAFmbYLUAAAoQklEQVR4nO3deViU9cI38O9s7MMqI8sAIuAyyCKK4pqabSg8B48tetRjJ+p4skyLY8spj8fnPfmcltPr++ipDM20IjNTg1ZLyxV3RUQSFYhFGUR2GJjlfv/AKFMcVGbuYeb7ua65YG5m+Y7X5Zcfv3v5SQRBEEBERL2eVOwARETUM1joRER2goVORGQnWOhERHaChU5EZCdY6EREdsLmCz0lJUXsCEREvYLNF3p1dbXYEYiIegWbL3QiIuoeFjoRkZ1goRMR2QkWOhGRnWChExHZCRY6EZGdsMtCFwQBBZUNuFDfKnYUIiKrsctCb2oz4Her9iLrYJnYUYiIrMYuC13posCYSD98nX9R7ChERFZjl4UOAPcOCcCPVY04X90kdhQiIquw20K/SxMAqQT46hRH6UTkGOy20H3dnTAynNMuROQ47LbQAeC+mACcKK9HRR2PdiEi+2fXhX63JgAAOEonIodg14Ue4OWCoaHe+IqFTkQOwK4LHQDuGxKAQ6WXUd3YJnYUIiKLsvtCvzc6EIIAfFPAUToR2Te7L/RQPzdoAj057UJEds/uCx3oOMlo/7ka1LfoxY5CRGQxDlPoBpOA7aerxI5CRGQxDlHoUSoPRKo88HlepdhRiIgsxiEKXSKRICU2CLuLLqG2uV3sOEREFuEQhQ4AU+MCYTAJvLYLEdkthyn0CH8PRAd5IvsEp12IyD45TKEDQEpcEPafr4G2QSd2FCKiHudQhT4lpuMkoy9OXhA7ChFRj3OoQg/xdUNCqDey81joRGR/HKrQgY5plyOltSivbRE7ChFRj3K4Qp8SEwiJBPico3QisjMOV+gqTxckhfshh4VORHbG4Qod6Jh2OVlRj+JLzWJHISLqMQ5Z6PcNCYBcKsG24xViRyEi6jEOWeg+7k6YMNAfW45VQBAEseMQEfUIhyx0AJiWoEZpTQuO/lQndhQioh7hsIU+aZAKni5yfHq0XOwoREQ9wqKF/sYbbyA6OhoajQYLFiyAIAg4ePAgoqOjERkZiWXLllny7W/IRSHD1LggZJ+oRJvBKFoOIqKeYrFCr66uxsqVK3HkyBGcPHkSR44cQW5uLubPn4+srCwUFhYiOzsb+fn5lopg1rShwWjQGbDjtFa0DEREPcWiI3SDwQCdTge9Xg+9Xg+TyQSDwYDY2FjI5XLMnDkT2dnZloxwQ8PCfBDq64bNR3m0CxH1fhYrdH9/f2RkZCA0NBRBQUGYPHkynJ2dERwc3PkYtVqNigrxylQikWBaQjC+/1GLmqY20XIQEfUEixV6bW0tcnJyUFJSgoqKCuzbtw/NzdeeyCORSK7ZlpmZiaSkJCQlJUGrtex0yLShahhMAs8cJaJez2KF/u233yIyMhK+vr5wdXXFlClT8MMPP1w1Ii8vL0dgYOA1z01PT0dubi5yc3OhUqksFREAEOrnhsR+PjzahYh6PYsVekhICPbt2wedTgej0Yjvv/8ecXFxkMlkyMvLg8FgQFZWFlJSUiwVodumJahxorweZ7WNYkchIrplFiv0pKQkJCcnY+jQoYiNjUVERARSU1OxcuVKzJgxAwMHDkRycjJiYmIsFaHbkmMC4SSXYtMRjtKJqPeSCDZ+7ntSUhJyc3Mt/j4LPzqGPWdrsP/5SVDIHPZ8KyLqxdhcVzyYGIpLTW3YUchj0omod2KhX5HU3xf9/Nyw8VCZ2FGIiG4JC/0KiUSCBxJD8P2PWlyobxU7DhHRTWOh/8r0BDUkEgk2HebOUSLqfVjov6LydMGkQSpsPFQGk8mm9xUTEV2Dhf4bDyWGoKKuFXvPXRI7ChHRTWGh/8YdA/zR19MZH3HnKBH1Miz035DLpLh/WAi+OXURl5vbxY5DRNRtLPTreGB4CPRGAZt55igR9SIs9OsI9XPD+AH+eP9AKXeOElGvwULvwpykMJTWtGBXUbXYUYiIuoWF3oWJg1QI9nbFhv2lYkchIuoWFnoXZFIJZiWFYcePWpRdbhE7DhGRWSz0G3gwMQQKmRQfHPhJ7ChERGax0G/A190JU2MDsfHQT9DpjWLHISK6IRa6GbOTwlDbosfnXHOUiGwcC92M+BBvxAR7YX0ud44SkW1joZshkUgwe1QYTpTVIa+8Tuw4RERdYqF3Q2pcEHzcFFi3t0TsKEREXbqpQm9ra0NlZaWlstgsF4UMs5LC8NmJSlys14kdh4jouswWelpaGhobG1FfX4/BgwfjzjvvxJIlS6yRzabMHhUGqUSC9ftLxI5CRHRdZgu9pKQESqUSn3zyCWbMmIGCggJs3brVCtFsi0rpgpS4IHxw4Ce0tBvEjkNEdA2zhd7W1oZz587hww8/RGpqKiQSiTVy2aRHxoajvlXPqzASkU0yW+hLlixBWloaBg4ciJEjR+L8+fOIjIy0RjabownyxJhIP6zZU8yrMBKRzZEIgnBTzSQIglVH6UlJScjNzbXa+5mzs1CLh9cdwjtzhuMuTV+x4xARdTI7Qp8/fz4aGxvR2tqKxMRE9O3bF2+99ZY1stmkOwb4I8LfHZm7z4sdhYjoKmYLfe/evVAqldi6dStGjhyJsrIyvPnmm9bIZpOkUgkeGdsfB4ov42R5vdhxiIg6mS10nU6H1tZWbNq0Cb///e/h7OxsjVw2bVpCMPzcnfDWrnNiRyEi6mS20OfNmwe1Wg2dTocJEyagtLQUSqXSGtlslotChj+NDccXJy/gfHWT2HGIiADcwk5RADAYDJDL5ZbIcw1b2yn6s/pWPcb8zw4kxwTglelxYschIjI/Qq+rq8PChQsxbNgwDB8+HIsWLUJTE0elXq4KzB4Vhi3HKlBZ1yp2HCIi84U+d+5cBAUFIScnB5999hmCg4Pxxz/+0RrZbN6fxoRDKpHgHR7xQkQ2oFun/i9evBiBgYEICgpCRkYGSku7d23w4uJiTJw4ERqNBjExMWhubsbBgwcRHR2NyMhILFu27LY/gJj8lc54MDEEWQd/Qk1Tm9hxiMjBmS10Hx8fbN68ufP+p59+Cm9v7269+Ny5c7Fs2TIUFBTghx9+gLOzM+bPn4+srCwUFhYiOzsb+fn5txzeFjw2vj8MRgHr9pWIHYWIHJzZQl+7di3WrVuHgIAABAUFYd26dXj33XfNvvCpU6egUCgwbtw4AICvry+0Wi0MBgNiY2Mhl8sxc+ZMZGdn3/6nEJHaxw2p8UFYt68EjTq92HGIyIGZPVQlPDz8lkq3qKgIHh4eSE1NRXl5OaZPn467774bwcHBnY9Rq9X44Ycfbvq1bc3jEyKw5VgF1u8vxfyJjnmdGyISX5eF/te//vWG12x55ZVXbvjCer0eu3fvxvHjx6FSqXDvvfdCoVBc87jrvUdmZiYyMzMBAFqt9obvYwsiVUpMiQnEO7vPY86oMChdrv2cRESW1mWhDxky5LZeWK1WIzExESEhIQCA5ORktLS0oKKiovMx5eXlCAwMvOa56enpSE9PB9BxHHpvsHByFD4/eQHr9pbgyTujxI5DRA6oy0K/3UMTExMTUVVVhdraWnh5eWHXrl3485//jOzsbOTl5UGj0SArKwtr1qy5rfexFZEqJVLjgjpG6aP7wcuVo3Qisi6LLRItl8vx8ssvY/z48YiNjUVUVBSmTp2KlStXYsaMGRg4cCCSk5MRExNjqQhWt+DOKDS1GbB2T7HYUYjIAd3Sqf/WZKun/nfl6Y+PY/upKux+diK83ZzEjkNEDsRiI3RHtWBSFFr0RmTu5iidiKzL7GGLp0+fxuuvv47S0lIYjcbO7Tt27LBosN6qXx93TBsajHf3FuNPY8Ph685ROhFZh9lCf/DBB7Fo0SIsWLAAMpnMGpl6vScnRWHLsQq8+f1Z/G2KRuw4ROQgzBa6i4sLHn74YWtksRuhfm6YOTIU7+0vxdwx4Qj2dhU7EhE5ALNz6JMmTcLSpUtx7NgxFBQUdN7oxp6cFAWFVIJ/f3NG7ChE5CDMjtAPHDgAAFedoi+RSDiHboa/0hmPju+PFd8V4dHx4RgU4Cl2JCKyczxs0YKa2gyY8OpOxKq9sXZuothxiMjO3dKKRXV1dVaI1vt5OMvx1J1R2FGoRe75GrHjEJGd44pFFvbQiFD083PD8i8LYeN/DBFRL2fRFYsIUMikyLhnIE6U1eGLkxfFjkNEdsyiKxZRhykxgRga6o3lX56GTm80/wQioltgsRWL6BcSiQR/T4lGeW0rMrmgNBFZiMVWLKKrxYd4Y1pCMFbtPIfpw0IQ4OUidiQisjNdFvqKFSvw1FNPdblykbkVi+haz947CF/lX8QrXxXi3w/Gix2HiOxMl4Xev39/ALe/chH9oq+nC+ZPjMSrX/+IWaPCkBDqI3YkIrIjXRZ6SkpK5/e/PUzxvffes1wiO/fI2HBkHfwJ/8guwJa/jIZU2vW6rUREN8PsTtEVK1Z0axt1j4tChhenDMaJsjpsPloudhwisiNdjtA3bdqEjz/+GCUlJXjggQc6tzc0NMDHh1MFt+Oe6ACMjeyD5V8W4i5NX65sREQ9ostCHzFiBPz9/XHhwgXMnz+/c7tSqURsbKxVwtkriUSC//7dENzzf3fhX18VYvk0/nsS0e3rcsolLCwMEyZMwJ49ezBgwADU19ejoaEBgYGBkMvNHu1IZoT3ccfjEyKQdbAMR0ovix2HiOyA2Tn0t99+G+PGjcMXX3yBnJwc3HHHHVi9erU1stm9eXdEoJ+fG/62JR96o0nsOETUy5m9fO7gwYNx4MABeHp2XM+7oaEBI0aMQGFhoVUC9ubL53bH7qJqzF5zEH9LHoxHx/cXOw4R9WJmR+ghISGQSn95mFQqRXh4uEVDOZJxUf5IjQvCG9+eQUVdq9hxiKgXM1voSqUSQ4YMwbx58/CXv/wFMTEx8PPzw+LFi7F48WJrZLR7L04dDJlUghe3nOQldonolpndu5mamorU1NTO+0lJSRYN5IhUShe8NFWDxZ/kYcuxCkxLUIsdiYh6IS5BZyMEQcCctQeRV16P7U+Ph0rJi3cR0c0xO+Wybds2xMfHo2/fvlCpVPD394dKpbJGNocikUiwfFoMDEYTXtqaz6kXIrppZgv9mWeewcaNG1FVVQWtVovq6mpotVprZHM4ah83PHffIHx9qoqrGxHRTTNb6GFhYYiIiLBGFgLwh5FhGBHuiyXb8nG5uV3sOETUi5idQz969CgWLVqEsWPHwtnZuXP7kiVLLB4OcJw59F8rudSMe1fswsSBKvznDwnXvR49EdFvmR2hP/XUUxg4cCACAgLg5+fXeSPL6dfHHX+bosGX+Rex+WiF2HGIqJcwe9iiXq/nqf4imDUyFDtOV+Hv2/Ixop8vQv3cxI5ERDbO7Aj9rrvuwvr161FbW4uWlpbOG1mWRCLBv6bHwlkhw9MfH4fRxKNeiOjGzBb6+++/j7///e9ISEhAdHQ0oqOju70sXUtLC8LCwpCRkQEAOHjwIKKjoxEZGYlly5bdXnIHoFK64H+mxeBwaS3e+uGc2HGIyMaZnXIpLi6+5Rf/5z//iZEjR3benz9/PrKysqDRaDBq1ChMmzaNa5aacXd0AB5KDMEb289gbGQfxIV4ix2JiGyU2UJfv379dbfPmTPnhs8rKipCYWEhUlJSkJ+fj8rKShgMhs7FMWbOnIns7GwWeje8NFWDA8WX8UTWUeQ8OQ5ergqxIxGRDTI75XLy5MnO2+HDh7F8+XJ8/vnnZl84IyMDy5cv77xfWVmJ4ODgzvtqtRoVFTyCozvcneVYOXMoqhra8NzmPJ5FSkTXZXaE/uqrr151v6mpCQ899NANn7Nt2zYMGDAAAwYMwL59+wDguiXU1fHVmZmZyMzMBACelXpFdJAXlkzV4MWt+diQW4o5o/qJHYmIbMxNryUnkUhw5syZGz4mNzcXH330ETZt2oSmpibo9Xp4enpeNSIvLy9HYGDgdZ+fnp6O9PR0ALy646/9YWQo9p+vwf/JOY2EUB8MCfYSOxIR2RCzZ4omJiZ2jqSNRiMuXLiAxYsXY+HChd16g3Xr1iE/Px+vvfYahg8fjrVr10Kj0WD06NFYs2YNYmJibvh8RzxT9EYadXpM/d89AIDsJ8fC04Xz6UTUwewI/ZNPPvnlwXI5VCoVFIpbK5GVK1dixowZ0Ol0mD17ttkyp2spXRRYNTMB097ch4yPT+CtWcMglfLSAETUjRF6fn4+IiMj4eLigpycHOTl5SE9Pd1ql9DlCP36Pj5chsWf5OGZuwbgyTujxI5DRDbA7FEus2bNgpOTE/Lz8zuXnJsxY4bFg9GNPTA8BLOTwvDvb89gR2GV2HGIyAaYLXSJRAKpVIrNmzdj0aJFeOGFF1BbW2uNbGTGS1M1GBbqg6c+Oo7iS81ixyEikZktdHd3d7z00ktYv349pk6dCqPRCL1eb41sZIaTXIr/zEqAm5MMj60/jKY2g9iRiEhEZgt906ZN8PHxwbp16xAYGIiKigr89a9/tUY26gaV0gVvzhqG0poWPJV1jBfxInJgXCTaTmw5Vo5FG0/gT2PCsSRFI3YcIhKB2RH6xx9/jKioKKhUKi4SbcPShqqx4M4orN1bjA37S8SOQ0QiMHsc+gsvvIBvvvkG/fv3t0Yeug2LJkeh5FIzlmYXIMTXDRMG8hcvkSMxO0IPDg5GeHi4NbLQbZJIJHhleizi1F544sNjOH2hQexIRGRFZufQH330UZSUlCA5OfmqRaIff/xxi4cDOId+K2qa2pD2n33Q6Y3Y/JfRCPHl8nVEjsDsCF2tVmPs2LFoaGhAdXV1541sl5+HMzY8MgImAZi95gAuNbWJHYmIrKDbR7k0NjZCIpHAw8PD0pmuwhH6rTtVWY+H3s5FWB83ZD2aBCUv5EVk18yO0PPy8hAfH4/ExEQkJCQgISEBeXl51shGtyk6yAur5wzHmaom/HnDEbQZjGJHIiILMlvojz32GN5++20UFhbizJkzeOutt/DYY49ZIxv1gFERfvh/Dw1F7vkaLNp4HAajSexIRGQhZgu9paXlqoWeR4wYgdbWVouGop5175AAvJwWgy9OXsQzm07wbFIiO2X2OPT4+Hg88cQTmDVrFgDggw8+6FzomXqPh0aEQm804aVtpyCTSvDq9DjIeB11IrtittBXr16NVatW4V//+hcAYNy4cVY7ZJF61uxR/WAwCfhHdgHkUgn+Z1osF8cgsiNdHuVSX1+P2tpa9OvX76rtxcXF8PPzg6enpzXy8SgXC3hn13n884vTmDkyFP/83ZAuF+smot6lyzn0J554AmfPnr1m+6lTp/Dkk09aNBRZ1qPj+2PxvQPx4YGf8MKWk5xTJ7ITXRb6sWPHMHny5Gu2T506FUePHrVoKLK8xydE4rn7BiHrYBkWbTwOPY9+Ier1upxD1+l0XT6prY1nHtqDeXdEwN1Zjpe25qOl3YCVMxPgopCJHYuIblGXI/SYmBh88MEH12z/8MMPMXjwYIuGIuuZnRSGfz8Qh50/VuNP6w6hmaseEfVaXe4ULS8vR1paGjw9PREfHw+JRIKjR4+ioaEBW7duhVqttkpA7hS1jq/yL2JB1jFEB3tizR8T4evuJHYkIrpJZq/l8t1336GgoACCIECj0Vx3Xt2SWOjWs7uoGvM2HIHK0wXrHk5EmJ+72JGI6CZwCTq6Sn5FPR5edwgmk4A1cxMRH+ItdiQi6iazp/6TYxkS7IUtj4+Gj7sTHlq9H98WVIkdiYi6iYVO11D7uGHzvNGIU3vjsQ2HsW5vMWz8DzkiAguduuDlpsD6R0YgNS4IS7ML8PynJ9Fu4LHqRLbM7LVcyHE5y2V448F4DAr0xL++KsRZbRPenDUM/kpn808mIqvjCJ1uSCKRYN4dEVj7x0T8eLERqSv34GR5vdixiOg6WOjULRMHqbBl/hi4KmSY/tY+fHy4TOxIRPQbLHTqtkiVB7bMH4NxUf5Y/Ekenvn4BFraeWYpka1godNN8XJV4J05w/C35MHYerwCv1u1F2e1jWLHIiKw0OkWSCQSPDq+PzY+loSGVgNSV+7Fp0fLeWgjkcgsVuhlZWWYMGECNBoNYmNjsWnTJgDAwYMHER0djcjISCxbtsxSb09WMLyfLz5fMBaJ/Xzx9Mcn8GTWMdS36MWOReSwLHbq/4ULF1BVVYX4+HhotVokJCTgxx9/xIQJE7BmzRpoNBqMGjUK7777LoYMGdLl6/DUf9tnMglYv78Ey78shI+bE15/IA5jIvuIHYvI4VhshB4YGIj4+HgAgEqlgq+vLy5dugSDwYDY2FjI5XLMnDkT2dnZlopAViKVSjB3TDhynhwLX3cn/CHzAP47pwA6vVHsaEQOxSpz6IcPH4bJZEJ1dTWCg4M7t6vValRUVFzz+MzMTCQlJSEpKQlardYaEakHRPVVYuv8MfjLhAis3VuMlP/dgyOltWLHInIYFi/0mpoazJkzB6tXr77uTrPrLVCcnp6O3Nxc5ObmQqVSWToi9SAnuRTP3jsIGx8bBYNJwPS39mHpZ6e4cAaRFVi00Nva2pCWlobnn38eo0ePRnBw8FUj8vLycgQGBloyAolkRLgvvnxqHObdEYENuaW4+41d+P5H/rVFZEkWK3RBEDB37lxMmjQJs2fPBgAEBQVBJpMhLy8PBoMBWVlZSElJsVQEEpmLQoZn7x2EbfPHwMddgbnvHsLCj45B29j1erVEdOssdpTLnj17MH78eMTGxnZu27BhA5qbm/HII49Ap9Nh9uzZWLp06Q1fh0e52AeD0YTMPcVY8W0RZFIJFk6Owh9H94NCxlMhiHoKVywiq6qsa8U/vziNz/MuIFLlgX+kRvMQR6IewuERWVWQtytWzUzAh+kjIQHwh8wDePyDIyitaRY7GlGvxxE6iUZvNOG9fSVY8V0RdHojZiWF4clJUfB1dxI7GlGvxEIn0dU2t2PlzrPYsL8UznIp5k2IwJ/GhMPVSSZ2NKJehYVONqPscgte++ZHbDteiQBPF8yfFIkHhqvhLGexE3UHC51szsnyerzydSF2F11CoJcLHp/IYifqDhY62awjpbVY8V0Rdp2pZrETdQMLnWzer4u9r6czHh4TjpkjQ+HpohA7GpFNYaFTr3H0p1r8Z+c5fHu6Ch7OcswYEYKHx4QjyNtV7GhENoGFTr3OueomZO4uxuaj5TCZBKTEBeGRseEYEuwldjQiUbHQqdeqbmzD+v0l2JBbiroWPeJDvDE7KQxTYgPhouA8OzkeFjr1eq3tRmSfqMT63BLkVzTAx02BBxJDMGtkGEJ83cSOR2Q1LHSyG4Ig4HhZHTbkliIn7wL0RhPGRPTB9GFq3BMdwBOVyO6x0MkuXW5uxydHyrDpcDmKtE1QOssxNS4Q04eFICHU+7oLqxD1dix0smuCICCvvB6bjpThs+OVaNAZ0N/fHWnxwZgaF4TwPu5iRyTqMSx0chg6vRHbC6rwyZFy7Dl7CUaTgOggT6TEBWFKTCDn26nXY6GTQ6ppasNXpy4i58QF5BbXQBCA+BBvTIkJxF2avujHkTv1Qix0cnjaRh2+PHkROXmVOFxaC0EAolQemKzpi8mD+2JoiDekUs65k+1joRP9irZRh52FWmwv0GLP2Wro9Cb08XDCnYP6YuIgFUZH+vGSA2SzWOhEXWhtN2LP2Uv4tqAK3xVW4VJTO2RSCeJDvDEuqg/GRfVBnNobcq6LSjaChU7UDSaTgIILDdhVVI3dZy7hcOll6I0ClM5yjI70w9gofySF+yJS5cFDIkk0LHSiW9DSbsCB4svYfeYSdhdVo0jbBADwdXdCYj8fjAj3w8hwXwwO9ISM8+9kJXKxAxD1Rm5OckwcqMLEgSoAgLZBh4Mll3GwuOP29akqAIDSWY5h/XyQEOqD+BBvxKm94eXGOXiyDI7QiSygtrkdh0trcbC4BgeLL+NUZQMMpo7/av37uCM+xBvxoR0FPzjQE05yzsPT7WOhE1mBTm9EwYUGHP+pDsfL6nCivA6lNS0AACe5FIMClBgc4AlNUMdtUIASSh5NQzeJhU4kksvN7ThRXofjP9Wh4EIDCiobUFHX2vnzUF83aAI9MTjQE4MDlYjqq0Sorxvn5KlLLHQiG1Lfou8o9wsNOH2l5Iu0jdAbO/6bOsml6N/HHREqD0SpPBCp8kCUSol+fdy41ipxpyiRLfFyU2BUhB9GRfh1bms3mHD+UhPOaptQVNWEs9VNOKdtwvZTVWg3mgAAMqkEob5uCPNzQz8/d4T5uV25uUPt48qydxAsdCIb1zHH7olBAZ5XbTcYTSirbe0oem0jzmmbUVrTjM9PXkB1Y1vn4yQSIMjLtbPgQ33dEOTtgmBvVwT7uEKldOE0jp1goRP1UnKZFOF93BHexx13afpe9bPmNgN+utyC0ppmlNa0oKSmBT9dbsauM9W4UN8K068mWmVSCQI8Owo+yNsFQd6uCPJ2RbC3KwK8XKBSOsPHzYnXs+kFWOhEdsjdWX5lZ6rnNT/TG02oatChsk6HyrpWVFy5Vda1ouBCA7YXVKG53XjVc+RSCfyVzlApneGvdIHKs+N7lbKj8Dvuu8DPwwkKXgpBNCx0IgejkEmh9nGD2uf6138XBAENOgMqaltR1aCDtlEHbUMbtI1tHd83tuH0hQZUN7Z1zuH/mtJFDj93J/i4O3V8dXOCr3vHzcfdCb5uTvD1+OWr0lnOyyX0EBY6EV1FIpHAy1UBL1cFNEHXjvB/JggC6lv1HUXf0FH2NU3tuNzSjstXvtY2t+N8dTMut7SjrkV/3deRSSXwdJHD88p7eroo4Okq/9X3V27XeYyHsxyuChl/IVwhSqHn5OTgmWeegclkwrPPPov09HQxYhDRbZBIJPB2c4K3mxMG9FWafbzBaEJdqx61ze24/PPtStE3tOrRoNOjvlWPhlYDyi634pSu4cp2A4ymro+ulkgAdyc53J1lcHeWd37v4SzvuO8sh7tTx89+3ubm1PFzVycZXBUyuCh+89VJCieZtNf9orD6cegGgwEajQY7d+6Ep6cnEhIScODAAfj6+l738TwOncixCYKA5nbjlbLvuNVfKfqWdgOa2gxobjOguc3Y8bXdgKafv79yv7nNiKY2A9oN104RdUUiwVUl76yQwvVXxd9xk3bed5ZL4ayQwkkmg5NcCme59JqvzvJfftavjzv6eDj36L+V1UfoBw8eRHR0NIKDgwEAycnJ+PrrrzFjxgxrRyGiXkAikcDjyug62Nv1tl5LbzShpc2IpvaOsm9tN6JVb4Su82ZCq96I1nYjdAYjdO1G6Aymjvv6nx9rgk5vRG1L+y/b2o1oN5rQZui4decXx6vTY3H/8JDb+jy/ZfVCr6ys7CxzAFCr1aioqLB2DCJyQAqZFF5uUotf8VIQBLQbO4q9/Vcl//PXdqMRob49v26t1Qv9ejM8v52nyszMRGZmJgBAq9VaJRcRUU+RSCRwlsusfoau1Q8YDQ4OvmpEXl5ejsDAwKsek56ejtzcXOTm5kKlUlk7IhFRr2T1Qh8xYgTy8/NRUVGBxsZGfPHFF7jnnnusHYOIyO5YfcpFLpfj9ddfx8SJE2EymbB48WL4+fmZfyIREd0QL59LRGQneNEFIiI7wUInIrITLHQiIjth83Poffv2RXh4+C09V6vVOsxhj/ys9omf1X7d6uf19/dHdnb2dX9m84V+Oxxphyo/q33iZ7Vflvi8nHIhIrITdl3ojnRZXn5W+8TPar8s8XntesqFiMiR2PUInYjIkbDQiYjshF0Wek5ODgYOHIioqKjOy/Daq7KyMkyYMAEajQaxsbHYtGmT2JEsqqWlBWFhYcjIyBA7isUVFxdj4sSJ0Gg0iImJQXNzs9iRLOaNN95AdHQ0NBoNFixYcN3LbPdmaWlp8PHxwfTp0zu3/bzYT2RkJJYtW9YzbyTYGb1eL0RFRQnl5eVCQ0ODEBkZKdTU1Igdy2IqKyuFY8eOCYIgCFVVVUJwcLDQ1NQkbigLeuGFF4T7779feOaZZ8SOYnHjx48Xdu3aJQiCINTU1Ah6vV7kRJah1WqF/v37C62trYLBYBBGjx4t7Nu3T+xYPWrHjh3CZ599Jvz+97/v3DZ8+HDhxIkTgl6vF4YPHy6cPHnytt/H7kbov17iTqlUdi5xZ68CAwMRHx8PAFCpVPD19cXly5fFDWUhRUVFKCwsRHJysthRLO7UqVNQKBQYN24cAMDX1xdyuShruluFwWCATqeDXq+HXq+3uxOMJk6cCKXyl4W0KysrYTAYEBsbC7lcjpkzZ3Z5stDNsLtCd+Ql7g4fPgyTyYSQkJ5dp9BWZGRkYPny5WLHsIqioiJ4eHggNTUVCQkJePnll8WOZDH+/v7IyMhAaGgogoKCMHnyZERERIgdy6Is1VN2V+hCN5a4s0c1NTWYM2cOVq9eLXYUi9i2bRsGDBiAAQMGiB3FKvR6PXbv3o1Vq1Zh//792L59O7Zv3y52LIuora1FTk4OSkpKUFFRgX379mHXrl1ix7IoS/WU3RV6d5a4szdtbW1IS0vD888/j9GjR4sdxyJyc3Px0UcfoV+/fsjIyMA777zTczuSbJBarUZiYiJCQkLg7OyM5ORkHD9+XOxYFvHtt98iMjISvr6+cHV1xZQpU+z+EgCW6im7K3RHW+JOEATMnTsXkyZNwuzZs8WOYzHLly9HWVkZSkpK8Nprr+HRRx/FkiVLxI5lMYmJiaiqqkJtbS1MJhN27dqFwYMHix3LIkJCQrBv3z7odDoYjUZ8//33GDhwoNixLCooKAgymQx5eXkwGAzIyspCSkrKbb+u3e1lcbQl7vbu3YuNGzciNjYWW7duBQBs2LABMTEx4gaj2yKXy/Hyyy9j/PjxEAQBd999N6ZOnSp2LItISkpCcnIyhg4dCqlUijvvvBOpqalix+pR99xzD44ePYrm5mao1Wps2bIFK1euxIwZM6DT6TB79uwe+T/LU/+JiOyE3U25EBE5KhY6EZGdYKETEdkJFjoRkZ1goRMR2QkWOjms++67D59++mnn/czMTDz88MMiJiK6PTxskRzW2bNnMXXqVBw7dgzt7e1ITEzEnj17bunCUEajETKZzAIpibqPhU4O7cUXX4RCoUBtbS0iIiJw6NAhnD59GoIgYMWKFRgzZgxyc3Px9NNPo7W1FT4+Pvjggw8QGBiIpUuX4uLFizh79iw0Gg3S0tKwYMECSKVSKBQKHD58WOyPRw6GhU4OrbW1FQkJCXB3d8fEiRMxevRopKWloby8HFOmTMGJEyfQ0NAAd3d3yGQyfPjhhzh06BDeeOMNLF26FNu3b8fOnTvh5OSElJQULFiwAHfddRfq6+vh5eUl9scjB2N3p/4T3QxXV1fcf//96NOnD9577z18/fXX+Mc//gGg4wqW7e3tqK2txaxZs3D+/HkYDAaEhYV1Pv+//uu/4OTkBAAYM2YMnnvuOZw+fRr3338/C52sjjtFyeFJpVJIpVIIgoCcnBwcP34cx48fR3l5OZycnLBkyRJMmTIF+fn5WLduHdra2jqf6+bm1vn9c889h7Vr16KpqQmJiYkOcx1+sh0sdKIrJk+ejFWrVnXeP3HiBACgoaEBarUaAPD+++93+fxz584hLi4OL7zwAgYPHozi4mLLBib6DRY60RVLliyBVqtFTEwMNBpN5wLjGRkZWLhwIcaOHXvViPy3fl7oODY2FqGhoRg1apS1ohMB4E5RIiK7wRE6EZGdYKETEdkJFjoRkZ1goRMR2QkWOhGRnWChExHZCRY6EZGdYKETEdmJ/w+6oPThhdi7WgAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYsAAAEECAYAAADZBhiGAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAArEAAAKxAFmbYLUAAAktElEQVR4nO3deVRU990/8PcsLMqmCKYsSiKDRCZMrCCMpklDYmMCqA8uUUikGmljo03a1IdK+vyU+PRI7Ik1Vk2XkEalDaZ4so3YY1KTJk2EuMUgieQBXCJMBFlkEQZnub8/gIkIODIwc4e579cJh5l7v3f4XI65b77f711kgiAIICIiugm52AUQEZHrY1gQEZFNDAsiIrKJYUFERDYxLIiIyCaGBRER2STpsJg3b57YJRARjQqSDovLly+LXQIR0agg6bAgIqJbw7AgIiKbGBZERGQTw4KIiGwSNSwOHDiA6OhoREVFIT8/v9/6o0ePQq1WQ6VSYdOmTdbl1dXViI+Ph0qlwurVq9F7L8SGhgYkJSUhKioKCxcuhMFgcNq+EBG5M9HCwmQy4dlnn8UHH3yAkydPYsuWLWhqaurTZs2aNSgsLERFRQV0Oh3Ky8sBANnZ2cjNzUVVVRXq6upQXFwMAMjLy8OiRYtQWVmJiIiIAQOIiIiGTinWD+7tNYSFhQEAkpOTcejQIaSnpwMA9Ho9TCYTNBoNACAjIwM6nQ5qtRolJSXYv38/ACAzMxM6nQ6pqanQ6XQ4duyYdfn69euxdu1aEfaORgtBECAIgADAYn3d8/3619etR89yi9CzPXraXvfaYn1t47P6VnNDbTdbO9D6/k8b6NfGxja2Hlgw1O371yzcdP2t1EC2+XkrMfU2vxH9TNHCQq/XW4MCAMLDw1FbW3vT9R999BEaGxsRGBgImUzWb7uWlhYEBAQM+HnkOIIgwGgW0Gk0w2A0o/OaGZ1GMzqu9X3faTTjmskCo7n3S8A1kwXXzBYYe5ZfMwvXrbf0rBdgNFlgFgRYLAJMFgEWQYDZ0v11/evuNrjudU/7nvfXt7fwoERuKuGOQPzjyVkj+pmihcVAz1zqDYCbrb/ZdtdvP9B7AMjPz7cOT9XX1w+taDcmCAJaO01ouNqFhrYuNF69huaOa2jtNKHNYESrwYg2gwmtnUa0GnqWdZpwtcuEDqMZZjuOvEq5DB4KOTwUMngq5fBQyK3fPRRyeCpk1tdKhQzecjkUcpn1Sy7reS2TQS6XQSnv/q6QXb8eUMjl3d9l362X96yXywCZDJBf929IBvQsl0EmA2S4/rWsp333657/IO9dP+BnXf853y3v/X69Af7J9lvWb6uBtun3GbKbrr+VnzNgbTYX2P6cgWsZaKnrcPHy4Os18od20cIiLCysz1/+NTU1SExMvOn6kJAQBAUFoampCYIgQCaTWZcDgL+/v7V3cf3y62VlZSErKwsAoNVqHbV7LsVktqCurQu1zZ3QX+lE7ZVO1PS8vtzWhcarXWi6eg1G80BB3P0Pz9/bA37eSviP8cD4sR6ICBwLP28lfL2VGOuphLeHAmM8FBjjKe/5ruz+3rOsd72nsicQ5HLI5S7+fxwRWYkWFgkJCSgvL0dtbS38/f1x8OBBbNiwwbo+NDQUCoUCZWVliImJQWFhIV599VXIZDJotVoUFxcjNTUVe/fuxRNPPAEASE1NRUFBAdauXYu9e/dK7t5PBqMZFZfaUF3fjqrL7aiqb0f15XZ809gB03V/+SvkMnzP3xth48bgjmAfzLx9PIJ8vTDB1wsTfD0R5OuFIF9PjBvrCT8vJQ/qRASZmM/gfvfdd7Fu3TpYLBZkZ2fjpz/9KZKTk5Gfn4/Q0FCUlpZi1apVMBgMWL58OXJzcwEAlZWVWLZsGa5cuYIHH3wQf/rTnyCXy3H58mUsXrwYtbW1uOuuu1BYWIgxY8YM+vO1Wi1KS0udtLcjy2IRcOZSK05dvIKyiy0oq23B/9W1WYeDfDwViJzoC1WwL6YE+yB8/FiEjR+DsHFjMNHPC0oFL7EholsnaliIbbSFxcWmDvynsgGfVjfgSFUDmjuMAIDQAG/EhgdAEz4OsWEBiLrNF9/z93b5cV8iGj1EG4aiW3OxqQPFp79Fcdm3OF3bAgCYEuSDFE0I7okMQtzt4zHRz1vkKonI3TEsXJDRbMH7X9WhoOQCSs42Qi7rPhXufxeo8cC02xA2bvChNSIiR2BYuBCD0YzXP/sGf/n4LC61GhAZ7ION82KQoglh74GIRMWwcAEWi4CiExex9b3/Q31bFx64cyJ+/+jdmBU5gfMOROQSGBYiO/NtK37z1mmc/OYK7o0KwiuZ8bh70jixyyIi6oNhIRJBEFBQegG/PXAGE3w98afHZ2Cu+nvsSRCRS2JYiKDzmhnrir5A8elvkaoJQd7CWPh5e4hdFhHRoBgWTnal4xqe2H0MZTUt+N//uguPJ05mb4KIXB7DwolaDUakv/IZzjdcRf6P43F/9ESxSyIiuiUMCycxGM34yZ7jOHu5HQWrEpFwR6DYJRER3TKGhZP8v7fLcfxCM/78eByDgohGHd5Nzgne/rwWRSdq8N9zozEn5jaxyyEiGjKGhYNdbOrAb946jfumBuOn904RuxwiIrswLBzsed2XUCrk2Lrkbj4XgohGLYaFA31YUY9/nanHf8+NRrCfl9jlEBHZjWHhIIIg4MX3vsbU23yRnjBZ7HKIiIaFYeEg731Vhy/1rfjlnKlQcPiJiEY5hoWDvPqfc4ia6Iu56u+JXQoR0bAxLBzgzLetOHq+CZmzb+ekNhG5BYaFA/z9swvw9VIi7fthYpdCRDQiGBYjzGS2oLjsW6TEhsDXixfIE5F7YFiMsCPVjWjuMCL17hCxSyEiGjEMixFWXPYtAn08MWvKBLFLISIaMQyLESQIAj74uh5zpk2EUsFfLRG5Dx7RRlBlfTsut3XhB1HBYpdCRDSiGBYj6JPKBgDA7EgOQRGRe2FYjKAj1Q2YFuKPIF/eB4qI3AvDYoQIgoDPzjVxYpuI3BLDYoRcaOxAm8GEuycFiF0KEdGIY1iMkHJ9CwDgrjCGBRG5H4bFCCmvbYWPpwJ3TPARuxQiohHHsBgh5bUtUIcG8MaBROSWGBYjQBAElOtboA7zF7sUIiKHYFiMgMttXbjSYcS0EIYFEbknhsUION/YAQC4nfMVROSmGBYj4ELjVQBAxISxIldCROQYDIsR8E1TB7w95Jjoxyu3icg9iRIWR48ehVqthkqlwqZNmwZsU11djfj4eKhUKqxevRqCIAAAGhoakJSUhKioKCxcuBAGgwEAcODAAdx1112Qy+UoLy932r4A3RfkTQ4cC5mMZ0IRkXsSJSzWrFmDwsJCVFRUQKfTDXhwz87ORm5uLqqqqlBXV4fi4mIAQF5eHhYtWoTKykpEREQgPz8fABAdHY39+/fjvvvuc+q+AMCFpg5MDuR8BRG5L6eHhV6vh8lkgkajgVKpREZGBnQ6XZ82giCgpKQEKSkpAIDMzExrG51Oh+XLl/dbHhUVhTvvvNOJe/Kdbxqvcr6CiNyaKGERFhZmfR8eHo7a2to+bRobGxEYGGgd1rm+TUtLCwICAgbd1tlaDUY0dxgZFkTk1pSO+uC4uDh0dXX1W75r165+y24c6++dnxiozY1thzpPkJ+fbx26qq+vH9K2A7nY1H3a7KRAhgURuS+HhcWJEycGXK7X6/v0BmpqahASEtKnTVBQEJqamiAIAmQyWZ82/v7+1t7FQNvakpWVhaysLACAVqsd0rYDqWvtnmAPCfAe9mcREbkqpw9DhYaGQqFQoKysDCaTCYWFhZg3b16fNjKZDFqt1jqpvXfvXmub1NRUFBQU9FsulvrW7t7TRD+GBRG5L1HOhtq5cyfS09MRHR2N5ORkxMbGAuj+q//48eMAgC1btmDjxo2IjIxEcHCwdbI7JycHRUVFUKlUOHfunLWXcOjQIYSHh6OkpARz5sxBenq6U/alvq0LHgoZxo/1cMrPIyISg0wYaIJAIrRaLUpLS4f1Gb956zT+/fVlfLr+gRGqiojI9fAK7mGqb+tCMK/cJiI3x7AYpssMCyKSAIbFMF3puIbAsZ5il0FE5FAMi2FqunoN43w4uU1E7o1hMQwmswWtBhN7FkTk9hgWw9DSaQQAjGdYEJGbY1gMQ3NHd1iM4zUWROTmGBbD0NxxDQAw3oc9CyJybwyLYWi+2hMW7FkQkZtjWAxDm8EEAPAfw7AgIvfGsBiG9q7usPDzYlgQkXtjWAxDe5cJCrkM3h78NRKRe+NRbhjaDCb4eimH/AAmIqLRZkhh8e233+LIkSMDPslOitq7jPD1ctjzo4iIXIbNI11CQgIOHz6Mq1evIiEhAdOmTUNERAReeeUVZ9Tn0tp7ehZERO7OZs/CaDTCz88PRUVFeOqpp/Dee+/h2LFjzqjN5bV3meHrzbAgIvdnMyzMZjMOHz6MPXv2IDU1FQBgMpkcXthowGEoIpIKm2Gxfft2bN++HUuWLEFsbCzOnj2LpKQkZ9Tm8tq7TOxZEJEk2DzSJSUlWcOhq6sL3t7e2LFjh8MLGw3aDSb4sWdBRBJgs2eRlpaGtrY2tLS0YNq0aXjwwQexYcMGZ9Tm8tq7zBjrybAgIvdnMyzOnz8PPz8/7N+/H+np6fjqq6/w9ttvO6E012cwmjHGk5eqEJH7s3mk6+rqQnV1NV5//XXMnz+fF6Bdx2A0w1upELsMIiKHsxkWGzZsQFpaGqZOnYrExEScPXsWKpXKGbW5NJPZApNFwBhPhgURuT+bA+7Lli3DsmXLrO+nTJmCN99806FFjQYGkwUA4OXBsCAi92ezZ/HNN99gwYIFCA0NRVhYGNLS0vDNN984ozaXZjCaAQDeSs5ZEJH7s3mkW7FiBR577DHo9XrU1tYiIyMDK1ascEJprs0aFuxZEJEE2AyLxsZGPProo9b3S5YsQWNjo0OLGg0Mxu5hKIYFEUmBzbCIiIjAiy++iEuXLuHSpUvYunUrJk+e7IzaXNp3PQsOQxGR+7N5pHvttddw4cIFPPLII3jkkUdw4cIF7N692wmlubYuE4ehiEg6bJ4NNWHCBN7eYwCd13qGoXidBRFJwKBhsWTJkptegPePf/zDIQWNFhyGIiIpGTQs1q5d68w6Rh0Dh6GISEIGDYsf/vCHzqxj1Ok9G8qLPQsikgAe6ezUOww1hj0LIpIAhoWdeFEeEUkJw8JOXSYL5DLAQ8FfIRG5P5unzgYHB/c7K8rf3x8zZszACy+8gClTpjisOFdmNFsYFEQkGTaPdk8++SQ2b96Ms2fP4uzZs8jLy8Njjz2GRx99FCtXrrTrhx49ehRqtRoqlQqbNm0asE11dTXi4+OhUqmwevVqCIIAAGhoaEBSUhKioqKwcOFCGAwGAMDWrVsxbdo0aDQapKWlobW11a7abpXJLDAsiEgybB7t3nvvPWRlZcHX1xe+vr5YtWoV/vnPf2Lx4sW4cuWKXT90zZo1KCwsREVFBXQ6HcrLy/u1yc7ORm5uLqqqqlBXV4fi4mIAQF5eHhYtWoTKykpEREQgPz8fABAXF4fPP/8cZWVlUKvVePHFF+2q7VYZLRYoFXwQFBFJg82w8PHxwR/+8AfU1dWhrq4OO3bsgI+PDywWCxSKoU/u6vV6mEwmaDQaKJVKZGRkQKfT9WkjCAJKSkqQkpICAMjMzLS20el0WL58eb/l999/P7y9vQEAM2bMQG1t7ZBrGwqTWYBSzp4FEUmDzaPdG2+8ga+//hoPP/ww5s6di4qKCuzbtw9GoxGFhYVD/oF6vR5hYWHW9+Hh4f0O7I2NjQgMDLTOlVzfpqWlBQEBAYNuCwC7d+/GQw89NOTahsJktsCDPQsikgibE9wTJ07Erl27BlwXHR096HZxcXHo6urqt3ygz7pxAr13fmKgNje2vfH9Sy+9BABYunTpgHXl5+dbh67q6+sHqd42o0XgMBQRSYbNsDhz5gx+//vf4/z58zCbzdblH3zwwU23O3HixIDLex+i1KumpgYhISF92gQFBaGpqQmCIEAmk/Vp4+/vb+1d3LitTqdDQUEBPvroo0HrysrKQlZWFgBAq9XedB9uxmS2wIPDUEQkETbDYunSpfjlL3+Jn//853bNUdwoNDQUCoUCZWVliImJQWFhIV599dU+bWQyGbRaLYqLi5Gamoq9e/fiiSeeAACkpqaioKAAa9euxd69ezFv3jwA3eG0bt06HD58GL6+vsOu0xaTmT0LIpIOm38ae3t7Y+XKldBoNFCr1dav4di5cyfS09MRHR2N5ORkxMbGAuj+q//48eMAgC1btmDjxo2IjIxEcHCwdbI7JycHRUVFUKlUOHfunLWX8Otf/xqtra1ITU3F9OnTsWbNmmHVaIvRwgluIpIOmTDQBMF11q9fD29vbyxYsABeXl7W5TExMQ4vztG0Wi1KS0vt2vZnfzsB/ZVOvLP2ByNcFRGR67E5DPXZZ58BQJ95AJlMZnPOwt0ZzQKUvCiPiCTCZlh8+OGHzqhj1DFZLFDKOWdBRNIwaFgUFRVhyZIlePnllwdc/9RTTzmsqNGA94YiIikZNCyampoAAJcvX3ZaMaOJ0SxgrCfDgoikYdCwePLJJwEAGzduBACYTCYolTZHrSTDZLZAKfcQuwwiIqew+adxSUkJpk+fjsjISABAWVkZnnnmGYcX5upMFgGeSs5ZEJE02AyLZ555BsXFxQgMDAQAaDQaHD582OGFuTojbyRIRBJi82gnk8n63PgPAOQ8SHYPQ/EKbiKSCJuTEHfeeSfeeecdCIKAmpoa7Ny5E/Hx8c6ozaWZLALvDUVEkmHzaPfyyy+jtLQUSqUSCxYsgCAI2LFjhzNqc2lG9iyISEJs9ix8fHyQl5eHnJwcyGQy+Pn5OaMul8fHqhKRlNg82pWWliI2NhYJCQmYOXMmNBoNjh496ozaXBqv4CYiKbHZs8jKysKePXsQFxcHADh58iQyMzMHfG62lPDeUEQkJTaPduPGjbMGBdD9fOtx48Y5sqZRgY9VJSIpGbRncfDgQQBAbGws0tLSsHTpUshkMhQVFQ3rCXPugs+zICIpuemNBHuNGzcOhw4dAgD4+flZ7xslZbzOgoikZNCweO2115xZx6hisQiwCOAwFBFJxqBhkZ2dfdMNf/e73414MaOF0WIBAA5DEZFkDBoWw33OtjszW7qfRMthKCKSikHD4sc//rEz6xhVerICchnDgoikYdCwmDlzJmQ3ORhK+cI8i9CdFgwLIpKKQcNi//79zqxjVBG6pyzAC7iJSCoGnaGNiIiwfl26dAmffvopIiIi4O/vD4VC4cwaXQ57FkQkNTZv95Gbm4uTJ0+ioqICGRkZ6OjowLJly/DJJ584oz6X1BsWzAoikgqb536+/fbbeOedd+Dj4wMACAsLQ2trq8MLc2W9E9w3m9MhInInNsPCy8sLwHcHxitXrkj+SXkCeoehRC6EiMhJbB71f/azn2Hp0qVoaGjAb3/7W9x7771Yt26dM2pzWQJPnSUiiRl0zqK8vBxqtRorVqxAYmIiDh8+DEEQsG/fPslfsMc5CyKSmkHDIisrC2fPnsX06dMxa9YszJo1C4mJiRg/frwz63NJvCiPiKRm0GGo0tJS1NTUYNOmTRg/fjx2796NuLg4xMTEYNWqVc6s0eVYLOxZEJG03PTUWU9PT2i1WoSHhyM0NBShoaE4ePAgTp8+7az6XBLnLIhIagYNi23btqGkpAR6vR6TJk1CYmIiFi9ejLy8POsZUlLFs6GISGoGDYs///nP8PHxwfz58zFr1iwkJCTwcao9eJ0FEUnNoGFRUVGBK1euoLS0FEeOHMFLL72E5uZmREdHQ6vVYvXq1c6s06Xwdh9EJDU3nbMYN24cHn74YcyaNQulpaUoKSlBQUEB9u3bJ+mwEAQOQxGRtAwaFq+88gpKSkpQUlKC9vZ2JCYmIjExEXv27EF8fLwza3Q53w1DiVsHEZGzDBoWX331FebOnYvc3FxMnjzZmTW5vO8uymNaEJE03PRsKBoYT50lIqkR5Y6AR48ehVqthkqlwqZNmwZsU11djfj4eKhUKqxevdo6T9DQ0ICkpCRERUVh4cKFMBgMAIDt27dDo9Fg+vTpmDt3Lurq6hxWv4VzFkQkMaKExZo1a1BYWIiKigrodDqUl5f3a5OdnY3c3FxUVVWhrq4OxcXFAIC8vDwsWrQIlZWViIiIQH5+PgBg5cqVKCsrw6lTp7BgwQJs3rzZYfWzZ0FEUuP0sNDr9TCZTNBoNFAqlcjIyIBOp+vTRhAElJSUICUlBQCQmZlpbaPT6bB8+fJ+y/39/a3bt7W1OXQ+wTpn4bCfQETkWmw+KW+k6fV6hIWFWd+Hh4fjo48+6tOmsbERgYGB1gN+eHg4amtrAQAtLS0ICAjotxwAXnjhBfzxj3+Er69vv88cSbwoj4ikxmE9i7i4ONx11139vq5evdqv7Y0H3d75iYHa3Nj2+vfr16/HhQsXsGrVKuzYsWPAuvLz86HVaqHValFfXz/k/QI4Z0FE0uOwnsWJEycGXK7X6/v0BmpqahASEtKnTVBQEJqamiAIAmQyWZ82/v7+1t7FQNsCwGOPPYYHHngAzz//fL91WVlZyMrKAgBotVq79s06Z8G0ICKJcPqcRWhoKBQKBcrKymAymVBYWIh58+b1aSOTyaDVaq2T2nv37rW2SU1NRUFBQb/llZWV1u3fffdd3HnnnQ7bB17BTURSI8rZUDt37kR6ejqio6ORnJyM2NhYAN1/9R8/fhwAsGXLFmzcuBGRkZEIDg62Tnbn5OSgqKgIKpUK586ds/YStm7dCrVajenTp+Ott97CSy+95LD6OWdBRFIjEwaaIJAIrVaL0tLSIW9XerYRy/5Sireemo3vT+aTA4nI/YnSsxjteNdZIpIahoUdeFEeEUkNw8IOAu86S0QSw7CwA4ehiEhqGBZ2sIYFf3tEJBE83NnBOgzFu0MRkUQwLOzA230QkdQwLOzAi/KISGoYFnbg7T6ISGoYFnaw8DoLIpIYhoUdensWzAoikgqGhR3YsyAiqWFY2MHCngURSQzDwg68gpuIpIZhMQwMCyKSCoaFHXhRHhFJDcPCDhZLzwuGBRFJBMPCDpyzICKpYVjYgQ8/IiKpYVjYgXMWRCQ1DAs79HQseCNBIpIMhoUdeFEeEUkNw8IOvN0HEUkNw8IOvEU5EUkNw8IOFgtPnSUiaWFY2OG7J+WJWwcRkbMwLOzQezYUexZEJBUMCztYH34kch1ERM7CsLADb/dBRFLDsLAD5yyISGoYFnawCAJkMl7BTUTSwbCwgyBwCIqIpIVhYQdBEDi5TUSSwrCwg4U9CyKSGIaFHXrnLIiIpIJhYQf2LIhIahgWdhAEgTcRJCJJESUsjh49CrVaDZVKhU2bNg3Yprq6GvHx8VCpVFi9erX1qumGhgYkJSUhKioKCxcuhMFg6LPdjh07IJPJ0N7e7rD6LYLAngURSYooYbFmzRoUFhaioqICOp0O5eXl/dpkZ2cjNzcXVVVVqKurQ3FxMQAgLy8PixYtQmVlJSIiIpCfn2/d5vLlyzh48CAmT57s0PoFAbzXBxFJitPDQq/Xw2QyQaPRQKlUIiMjAzqdrk8bQRBQUlKClJQUAEBmZqa1jU6nw/Lly/stB4CcnBw8//zzDr9YjnMWRCQ1ooRFWFiY9X14eDhqa2v7tGlsbERgYKD1oH99m5aWFgQEBPRbXlpaCovFgoSEBIfvA+csiEhqlI764Li4OHR1dfVbvmvXrn7LbuwJ9M5PDNTmxrYymQwWiwU5OTl4/fXXbdaVn59vHbqqr6+32X4gnLMgIqlxWFicOHFiwOV6vb5PT6KmpgYhISF92gQFBaGpqan7SmmZrE8bf39/a++id3lbWxvKy8sxa9Ys62eq1WqcPn0a/v7+fT47KysLWVlZAACtVmvXvlkE3heKiKTF6cNQoaGhUCgUKCsrg8lkQmFhIebNm9enjUwmg1artU5q792719omNTUVBQUFfZYHBATg8uXLOH/+PM6fP4/w8HB8+eWX/YJipFg4DEVEEiPK2VA7d+5Eeno6oqOjkZycjNjYWADdf/UfP34cALBlyxZs3LgRkZGRCA4Otk525+TkoKioCCqVCufOnbP2EpxJEHh7ciKSFpkw0ASBRGi1WpSWlg55u43vlOO9r+pQkvOgA6oiInI9vILbDjx1loikhmFhB95IkIikhmFhB/YsiEhqGBZ2ENizICKJYVjYgY9VJSKpYVjYgXMWRCQ1DruC2509laRCu8EkdhlERE7DsLDDHUE+YpdARORUHIYiIiKbGBZERGQTw4KIiGxiWBARkU0MCyIisolhQURENjEsiIjIJkk/z+K2227DHXfcYde29fX1mDhx4ghX5Jq4r+5LSvvLfb01wcHB0Ol0/ZZLOiyGw94HJ41G3Ff3JaX95b4OD4ehiIjIJoaFncR49rdYuK/uS0r7y30dHg5DERGRTexZEBGRTQwLIiKyiWFhhwMHDiA6OhpRUVHIz88XuxyHuXjxIu6//37ExMRAo9GgqKhI7JIcrqOjAxEREVi3bp3YpTjUuXPnkJSUhJiYGMTGxuLq1atil+Qw27Ztg1qtRkxMDJ5++mm428h7Wloaxo8fj8WLF1uXHT16FGq1GiqVCps2bRqZHyTQkBiNRiEqKkqoqakRWltbBZVKJTQ2NopdlkPo9Xrh888/FwRBEOrq6oSwsDChvb1d3KIc7LnnnhOWLFki/OpXvxK7FIe67777hI8//lgQBEFobGwUjEajyBU5Rn19vTBlyhShs7NTMJlMwuzZs4UjR46IXdaI+uCDD4R3331XWLRokXVZfHy88MUXXwhGo1GIj48XTp8+Peyfw57FEPUmdlhYGPz8/JCcnIxDhw6JXZZDhISEYPr06QCAiRMnIjAwEE1NTeIW5UCVlZWoqKhAcnKy2KU41JdffgkPDw/ce++9AIDAwEAole77HDSTyQSDwQCj0Qij0eh2F+YlJSXBz8/P+l6v18NkMkGj0UCpVCIjI2PAi+yGimExRHq9HmFhYdb34eHhqK2tFbEi5zh+/DgsFgsmTZokdikOs27dOuTl5YldhsNVVlbC19cX8+fPx4wZM7B582axS3KY4OBgrFu3DpMnT0ZoaCjmzJmDyMhIsctyKEcdoxgWQyQMMN4pk8lEqMR5GhsbkZmZib/85S9il+Iw77zzDqZOnYqpU6eKXYrDGY1G/Oc//8GuXbtQUlKC999/H++//77YZTlEc3MzDhw4gPPnz6O2thZHjhzBxx9/LHZZDuWoYxTDYojCwsL6pHRNTQ1CQkJErMixurq6kJaWhpycHMyePVvschymtLQU+/btw+23345169bhlVdeGbmJQRcTHh6OmTNnYtKkSfDy8kJycjJOnToldlkO8a9//QsqlQqBgYEYM2YMUlJS3P6WH446RjEshighIQHl5eWora1FW1sbDh48iLlz54pdlkMIgoAVK1bggQcewPLly8Uux6Hy8vJw8eJFnD9/Hi+++CJ+8pOfYMOGDWKX5RAzZ85EXV0dmpubYbFY8PHHH2PatGlil+UQkyZNwpEjR2AwGGA2m/Hvf/8b0dHRYpflUKGhoVAoFCgrK4PJZEJhYSHmzZs37M9131ktB1Eqldi6dSuSkpJgsViQnZ2NCRMmiF2WQ3z66ad44403oNFo8PbbbwMACgoKEBsbK25hNCxKpRKbN2/GfffdB0EQ8NBDDyE1NVXsshxCq9UiOTkZ3//+9yGXy/Hggw9i/vz5Ypc1oubOnYuTJ0/i6tWrCA8Px1tvvYWdO3ciPT0dBoMBy5cvH5H/Z3m7DyIisonDUEREZBPDgoiIbGJYEBGRTQwLIiKyiWFBREQ2MSyIHOCRRx7Bm2++aX2fn5+PlStXilgR0fDw1FkiB6iqqkJqaio+//xzXLt2DTNnzsQnn3xi103szGYzFAqFA6okunUMCyIH+Z//+R94eHigubkZkZGROHbsGM6cOQNBELB9+3bcc889KC0txbPPPovOzk6MHz8ef//73xESEoLc3FxcunQJVVVViImJQVpaGp5++mnI5XJ4eHjg+PHjYu8eSQzDgshBOjs7MWPGDPj4+CApKQmzZ89GWloaampqkJKSgi+++AKtra3w8fGBQqHA66+/jmPHjmHbtm3Izc3F+++/jw8//BCenp6YN28enn76afzoRz9CS0sLAgICxN49khje7oPIQcaMGYMlS5YgKCgIe/bswaFDh/D8888D6L6T77Vr19Dc3IzHH38cZ8+ehclkQkREhHX7BQsWwNPTEwBwzz33YP369Thz5gyWLFnCsCCn4wQ3kQPJ5XLI5XIIgoADBw7g1KlTOHXqFGpqauDp6YkNGzYgJSUF5eXl2L17N7q6uqzbjh071vp6/fr1+Otf/4r29nbMnDlTEs9QIdfCsCBygjlz5mDXrl3W91988QUAoLW1FeHh4QCAv/3tb4NuX11djbvvvhvPPfccpk2bhnPnzjm2YKIbMCyInGDDhg2or69HbGwsYmJikJ+fD6D76Xy/+MUv8IMf/KBPT+JG27Ztg1qthkajweTJkzFr1ixnlU4EgBPcRER0C9izICIimxgWRERkE8OCiIhsYlgQEZFNDAsiIrKJYUFERDYxLIiIyCaGBRER2fT/AfvWnj2bcUfiAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "df = generate_households(num_households=1, exp=5000, v=0.3, fix_seed=False)\n", - "\n", - "default_parameters = {'recovery_rate': 0.5, \n", - " 'years_to_recover': 10, \n", - " 'income_and_expenditure_growth': 0.02,\n", - " 'average_productivity': 0.35,\n", - " 'consumption_utility': 1.5,\n", - " 'discount_rate': 0.04}\n", - "\n", - "consumption, consumption_unaffected, consumption_loss, consumption_loss_npv, wellbeing = calculate_consumption_recovery(df, default_parameters, print_statistics=True)\n", - "\n", - "ax = consumption_loss.T.plot(legend=False)\n", - "plt.xlabel('Years')\n", - "plt.ylabel('Consumption loss');\n", - "sns.despine()\n", - "\n", - "ax = wellbeing.T.plot(legend=False)\n", - "plt.xlabel('Years')\n", - "plt.ylabel('Wellbeing loss');\n", - "sns.despine()" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(5000, -0.034520709496898866, 6032.746643707037, 9464.387539258825)" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "consumption_utility = 1.5\n", - "discount_rate = 0.04\n", - "weighted_average_expenditure = df['exp'].values[0]\n", - "total_wellbeing_loss = wellbeing.replace([np.inf, -np.inf], np.nan).dropna(axis=1).sum(axis=1).values[0]\n", - "total_asset_damage = df['keff'].multiply(df['v']).values[0]\n", - "total_consumption_loss = consumption_loss.sum(axis=1).values[0]\n", - "total_consumption_loss_npv = consumption_loss_npv.sum(axis=1).values[0]\n", - "weighted_average_expenditure, total_wellbeing_loss, total_asset_damage, total_consumption_loss_npv" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "2.82842712474619e-06" - ] - }, - "execution_count": 45, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "welfare = math.pow(weighted_average_expenditure, -consumption_utility)\n", - "welfare" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "-0.0282842712474619" - ] - }, - "execution_count": 42, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "welfare = (math.pow(weighted_average_expenditure, 1 - consumption_utility)) / (1 - consumption_utility)\n", - "welfare" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1.9943431457505076" - ] - }, - "execution_count": 39, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "welfare = (math.pow((1 / discount_rate) * weighted_average_expenditure, 1 - consumption_utility) - 1) / (1 - consumption_utility)\n", - "welfare" - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "12204.91388831402" - ] - }, - "execution_count": 47, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tot_consum_equiv_loss = - (total_wellbeing_loss / welfare)\n", - "tot_consum_equiv_loss" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(0.6374154290156501, 0.49428834147558226)" - ] - }, - "execution_count": 48, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "total_asset_damage / total_consumption_loss_npv, total_asset_damage / tot_consum_equiv_loss" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "unbreakable", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.18" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/setup.py b/setup.py index 78d9984..e3ec961 100644 --- a/setup.py +++ b/setup.py @@ -1,10 +1,10 @@ from setuptools import find_packages, setup setup( - name='unbreakable', + name="unbreakable", packages=find_packages(), - version='0.3.0', - description='Unbreakable: Building the Resilience of the Poor in the Face of Natural Disasters a Simulation Model', - author='Mikhail Sirenko and Bramka Arga Jafino', - license='CC BY 3.0 IGO', + version="0.4.0", + description="Unbreakable: A Simulation Tool for Estimating Socio-Economic Impacts of Disaster on Households", + author="Mikhail Sirenko and Bramka Arga Jafino", + license="CC BY-SA 4.0", ) diff --git a/unbreakable/__init__.py b/unbreakable/__init__.py index 066d9f5..ae675c2 100644 --- a/unbreakable/__init__.py +++ b/unbreakable/__init__.py @@ -1,3 +1,3 @@ """ .. include:: ../README.md -""" \ No newline at end of file +""" diff --git a/unbreakable/analysis/analyzer.py b/unbreakable/analysis/analyzer.py deleted file mode 100644 index c07cb7e..0000000 --- a/unbreakable/analysis/analyzer.py +++ /dev/null @@ -1,472 +0,0 @@ -import pandas as pd -import numpy as np -import ast -import geopandas as gpd -from tqdm import tqdm -import yaml - - -def prepare_outcomes(results: tuple, add_policies: bool, add_uncertainties: bool) -> pd.DataFrame: - '''Convert outcomes dict in (EMA Workbench format) into a pd.DataFrame. - - Args: - results (tuple): The results of the experiments in the EMA Workbench format. - add_policies (bool): Whether to add policy values. - add_uncertainties (bool): Whether to add uncertainty values. - - Returns: - pd.DataFrame: Outcomes. - ''' - # Read outcome names from a yaml file - with open("../../unbreakable/analysis/outcomes.yaml", "r") as f: - outcome_names = yaml.safe_load(f) - - policy_names = ['current_policy'] - uncertainty_names = [] - - experiments, _ = results - experiments['random_seed'] = experiments['random_seed'].astype(int) - experiments['scenario'] = experiments['scenario'].astype(int) - - if len(experiments['random_seed'].unique()) != experiments['scenario'].max() - experiments['scenario'].min() + 1: - print('Warning! Random seeds are not unique.') - - base_columns = ['scenario', 'policy', 'region', 'random_seed'] - if add_policies: - if add_uncertainties: - columns = base_columns + \ - policy_names + uncertainty_names + outcome_names - else: - columns = base_columns + \ - policy_names + outcome_names - else: - if add_uncertainties: - columns = base_columns + \ - uncertainty_names + outcome_names - else: - columns = base_columns + outcome_names - - scenarios = results[0]['scenario'].values - n_scenarios = results[0]['scenario'].unique().size - - policies = results[0]['policy'].values - n_policies = results[0]['policy'].unique().size - - random_seeds = results[0]['random_seed'].values - n_regions = len(results[1].keys()) - - if add_policies: - policy_values = results[0][policy_names].values - - if add_uncertainties: - uncertainty_values = results[0][uncertainty_names].values - - n_columns = len(columns) - n_rows = n_scenarios * n_policies * n_regions - outcomes = np.zeros((n_rows, n_columns), dtype=object) - - i = 0 # To iterate over rows = scenarios * policies * regions - for region, region_outcomes in results[1].items(): - # To iterate over rows = scenarios * policies (experiments dataframe) - k = 0 - # We reset k every time we change region - for arr in region_outcomes: - # The first 3 rows for scenario, policy and region - outcomes[i, 0] = scenarios[k] - outcomes[i, 1] = policies[k] - outcomes[i, 2] = region - outcomes[i, 3] = random_seeds[k] - - if add_policies: - if add_uncertainties: - # Add policy values - # From 4 to 4 + len(policy_names) policy values - for j, name in enumerate(policy_names): - outcomes[i, 4 + j] = policy_values[k, j] - - # Add uncertainty values - # From 4 + len(policy_names) to 4 + len(policy_names) + len(uncertainty_names) uncertainty values - for j, name in enumerate(uncertainty_names): - outcomes[i, 4 + len(policy_names) + - j] = uncertainty_values[k, j] - - # Add outcomes - # From 4 + len(policy_names) + len(uncertainty_names) to 4 + len(policy_names) + len(uncertainty_names) + len(outcome_names) outcomes - l = 4 + len(policy_names) + len(uncertainty_names) - for v, name in zip(arr, outcome_names): - if name in ['weighted_vuln_quint', 'weighted_vuln_dec', 'years_in_poverty']: - outcomes[i, l] = ast.literal_eval(v) - else: - outcomes[i, l] = v - l += 1 - else: - # Add policy values - # From 4 to 4 + len(policy_names) policy values - for j, name in enumerate(policy_names): - outcomes[i, 4 + j] = policy_values[k, j] - - # Add outcomes - # From 4 + len(policy_names) to 4 + len(policy_names) + len(outcome_names) outcomes - l = 4 + len(policy_names) - for v, name in zip(arr, outcome_names): - if name in ['weighted_vuln_quint', 'weighted_vuln_dec', 'years_in_poverty']: - outcomes[i, l] = ast.literal_eval(v) - else: - outcomes[i, l] = v - l += 1 - else: - if add_uncertainties: - # Add uncertainty values - # From 4 to 4 + len(uncertainty_names) uncertainty values - for j, name in enumerate(uncertainty_names): - outcomes[i, 4 + j] = uncertainty_values[k, j] - - # Add outcomes - # From 4 + len(uncertainty_names) to 4 + len(uncertainty_names) + len(outcome_names) outcomes - l = 4 + len(uncertainty_names) - for v, name in zip(arr, outcome_names): - if name in ['weighted_vuln_quint', 'weighted_vuln_dec', 'years_in_poverty']: - outcomes[i, l] = ast.literal_eval(v) - else: - outcomes[i, l] = v - l += 1 - else: - # Add outcomes - # From 4 to 4 + len(outcome_names) outcomes - l = 4 - for v, name in zip(arr, outcome_names): - if name in ['weighted_vuln_quint', 'weighted_vuln_dec', 'years_in_poverty']: - outcomes[i, l] = ast.literal_eval(v) - else: - outcomes[i, l] = v - l += 1 - k += 1 # increase row index to get next experiment for the current region - i += 1 # increase row index of the outcomes dataframe - outcomes = pd.DataFrame(outcomes, columns=columns) - - # Iterate over the columns and try to convert them to numeric if possible - for col in outcomes.columns: - try: - outcomes[col] = pd.to_numeric(outcomes[col]) - except: - pass - - # Convert pct columns to percentage - outcomes['annual_avg_consum_loss_pct'] = outcomes['annual_avg_consum_loss_pct'] * 100 - outcomes['initial_poverty_gap'] = outcomes['initial_poverty_gap'] * 100 - outcomes['new_poverty_gap_all'] = outcomes['new_poverty_gap_all'] * 100 - outcomes['new_poverty_gap_initial'] = outcomes['new_poverty_gap_initial'] * 100 - outcomes['n_poor_ratio'] = outcomes['n_poor_initial'].div( - outcomes['tot_pop']).round(2) * 100 - - # Calculate the percentage of new poor - outcomes = outcomes.assign(n_new_poor_increase_pp=outcomes['n_new_poor'].div( - outcomes['tot_pop']).multiply(100)) - - # Move years_in_poverty column to the end of the data frame - outcomes = outcomes[[c for c in outcomes if c not in [ - 'years_in_poverty']] + ['years_in_poverty']] - - return outcomes - - -def get_spatial_outcomes(outcomes: pd.DataFrame, country: str, outcomes_of_interest: list = [], aggregation: str = 'median') -> gpd.GeoDataFrame: - '''Connect outcomes with spatial data. - - Args: - outcomes (pd.DataFrame): Outcomes data frame. - country (str, optional): Country name. - outcomes_of_interest (list, optional): List of outcomes of interest. Defaults to []. - aggregation (str, optional): Aggregation method. Defaults to 'median'. - - Returns: - gpd.GeoDataFrame: Spatial outcomes. - ''' - - if aggregation not in ['mean', 'median']: - raise ValueError('Aggregation must be either mean or median') - - if country == 'Saint Lucia': - column = 'NAME_1' - gdf = gpd.read_file( - f'../data/raw/shapefiles/{country}/gadm36_LCA_shp/gadm36_LCA_1.shp') - - gdf['NAME_1'].replace( - {'Soufrière': 'Soufriere', 'Vieux Fort': 'Vieuxfort'}, inplace=True) - - # Merge Anse-la-Raye and Canaries into a single geometry - geometry = gdf[gdf['NAME_1'].isin( - ['Anse-la-Raye', 'Canaries'])].unary_union - - # Add it to the dataframe - gdf.loc[len(gdf)] = [None, None, 'LCA.11_1', 'Anse-La-Raye & Canaries', - None, None, None, None, None, None, geometry] - gdf = gdf[gdf['NAME_1'].isin(outcomes['region'].unique())] - - elif country == 'Dominica': - column = 'NAME' - gdf = gpd.read_file( - '../../data/raw/shapefiles/Dominica/dma_admn_adm1_py_s1_dominode_v2.shp') - - elif country == 'Nigeria': - column = 'shapeName' - gdf = gpd.read_file( - '../../data/raw/shapefiles/Nigeria/geoBoundaries-NGA-ADM1-all/geoBoundaries-NGA-ADM1.shp') - - else: - raise ValueError('Country not supported') - - if len(outcomes_of_interest) == 0: - outcomes_of_interest = [ - 'tot_asset_loss', - 'region_pml', - 'tot_exposed_asset', - 'tot_consum_loss_npv', - 'n_aff_people', - 'n_new_poor', - 'new_poverty_gap_all', - 'annual_avg_consum_loss', - 'annual_avg_consum_loss_pct', - 'n_new_poor_increase_pp', - 'n_poor_ratio', - 'r'] - - # Aggregate outcomes - if aggregation == 'mean': - aggregated = outcomes[['region'] + - outcomes_of_interest].groupby('region').mean() - elif aggregation == 'median': - aggregated = outcomes[['region'] + - outcomes_of_interest].groupby('region').median() - else: - raise ValueError('Aggregation must be either mean or median') - - # Merge with the shapefile - gdf = pd.merge(gdf, aggregated, left_on=column, right_index=True) - gdf.reset_index(inplace=True, drop=True) - return gdf - - -def get_policy_effectiveness_tab(outcomes: pd.DataFrame) -> pd.DataFrame: - '''Get the policy effectiveness table. - - Effectiveness here is how effective the policy is in respect to: - - reducing the number of new poor; - - reducing the average consumption loss. - - Args: - outcomes (pd.DataFrame): Outcomes. - - Returns: - pd.DataFrame: Policy effectiveness table. - ''' - policy_name_mapper = {'all+0': 'None', - 'all+10': '10% to all', - 'all+30': '30% to all', - 'all+50': '50% to all', - 'all+100': '100% to all', - 'poor+0': 'None', - 'poor+10': '10% to poor', - 'poor+30': '30% to poor', - 'poor+50': '50% to poor', - 'poor+100': '100% to poor', - 'poor_near_poor1.25+0': 'None', - 'poor_near_poor1.25+10': '10% to poor and near poor (1.25)', - 'poor_near_poor1.25+30': '30% to poor and near poor (1.25)', - 'poor_near_poor1.25+50': '50% to poor and near poor (1.25)', - 'poor_near_poor1.25+100': '100% to poor and near poor (1.25)', - 'poor_near_poor2.0+0': 'None', - 'poor_near_poor2.0+10': '10% to poor and near poor (2.0)', - 'poor_near_poor2.0+30': '30% to poor and near poor (2.0)', - 'poor_near_poor2.0+50': '50% to poor and near poor (2.0)', - 'poor_near_poor2.0+100': '100% to poor and near poor (2.0)'} - df = outcomes.copy() - df['my_policy'] = df['my_policy'].replace(policy_name_mapper) - df['my_policy'] = pd.Categorical(df['my_policy'], categories=['None', '10% to all', '30% to all', '50% to all', '100% to all', - '10% to poor', '30% to poor', '50% to poor', '100% to poor', - '10% to poor and near poor (1.25)', '30% to poor and near poor (1.25)', '50% to poor and near poor (1.25)', '100% to poor and near poor (1.25)', - '10% to poor and near poor (2.0)', '30% to poor and near poor (2.0)', '50% to poor and near poor (2.0)', '100% to poor and near poor (2.0)'], ordered=True) - df.rename(columns={'my_policy': 'Policy', - 'region': 'Region'}, inplace=True) - df.rename(columns={'annual_average_consumption_loss_pct': 'Annual average consumption loss (%)', - 'n_new_poor': 'Number of new poor'}, - inplace=True) - df['Policy ID'] = df['Policy'].cat.codes - return df - - -def get_weeks_in_poverty_tab(outcomes: pd.DataFrame) -> pd.DataFrame: - '''Get the average across scenarios number of weeks in poverty for each region. - - Args: - outcomes (pd.DataFrame): Outcomes. - - Returns: - pd.DataFrame: Average number of weeks in poverty for each region. - ''' - # Specify the regions - regions = ['Anse-La-Raye & Canaries', 'Castries', 'Choiseul', - 'Dennery', 'Gros Islet', 'Laborie', 'Micoud', 'Soufriere', 'Vieuxfort'] - regions = outcomes['region'].unique() - - # Keep track of the averages - region_average = {} - - # Get the number of scenarios - n_scenarios = outcomes['scenario'].unique().size - - # Get the keys - column_name = 'years_in_poverty' - all_keys = outcomes[column_name][0].keys() - - # Iterate through the regions - for region in regions: - # Subset the outcomes for a specific region - df = outcomes[outcomes['region'] == region] - - # Get the dictionaries from the column - dicts = df[column_name].tolist() - - # Initialize the sums - sums = dict(zip(all_keys, [0] * len(all_keys))) - - # Iterate through the dictionaries and update the sums - for d in dicts: - for key in all_keys: - if key in d: - sums[key] += d[key] - else: - sums[key] += 0 - - # Calculate the average - region_average[region] = { - key: sums[key] / n_scenarios for key in all_keys} - - # Convert the dictionary to a dataframe - result = pd.DataFrame(region_average).T - result.index.name = 'Region' - result.columns = [i for i in range(0, len(all_keys))] - # result.columns = [int(x) if int(x) < len( - # all_keys) else f'>{len(all_keys)}' for x in range(1, len(all_keys) + 1)] - return result - - -def get_average_weighted_vulnerability(outcomes: pd.DataFrame, quintile: bool) -> pd.DataFrame: - '''Get the average weighted vulnerability for each region. - - Args: - outcomes (pd.DataFrame): Outcomes. - quintile (bool): Whether to calculate the average weighted vulnerability by quintile or decile. - - Returns: - pd.DataFrame: Average weighted vulnerability for each region. - ''' - # Specify the regions - regions = ['Anse-La-Raye & Canaries', 'Castries', 'Choiseul', - 'Dennery', 'Gros Islet', 'Laborie', 'Micoud', 'Soufriere', 'Vieuxfort'] - - # Keep track of the averages - region_average = {} - - # Get the number of scenarios - n_scenarios = outcomes['scenario'].unique().size - - if quintile: - column_name = 'weighted_vuln_quint' - all_keys = [1, 2, 3, 4, 5] - else: - column_name = 'weighted_vuln_dec' - all_keys = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - - # Iterate through the regions - for region in regions: - # Subset the outcomes for a specific region - df = outcomes[outcomes['region'] == region] - - # Get the dictionaries from the column - dicts = df[column_name].tolist() - - # Initialize the sums - sums = dict(zip(all_keys, [0] * len(all_keys))) - - # Iterate through the dictionaries and update the sums - for d in dicts: - for key in all_keys: - if key in d: - sums[key] += d[key] - else: - sums[key] += 0 - - # Calculate the average - region_average[region] = { - key: sums[key] / n_scenarios for key in all_keys} - - # Convert the dictionary to a dataframe - result = pd.DataFrame(region_average).T - - # Rename the index and columns - result.index.name = 'region' - if quintile: - result.columns.name = 'Quintile' - else: - result.columns.name = 'Decile' - return result - - -def calculate_resilience(affected_households: pd.DataFrame, tot_wellbeing_loss: float) -> float: - '''Calculate socio-economic resilience of affected households. - - Socio-economic resilience is a ratio of asset loss to consumption loss. - - Args: - affected_households (pd.DataFrame): Affected households. - tot_wellbeing_loss (float): Total wellbeing loss. - - Returns: - float: Socio-economic resilience - ''' - total_consumption_loss = ( - affected_households[['consumption_loss_NPV', 'popwgt']].prod(axis=1)).sum() - - total_asset_damage = ( - affected_households[['keff', 'v', 'popwgt']].prod(axis=1)).sum() - - if total_consumption_loss == 0: - r = np.nan - - else: - r = total_asset_damage / total_consumption_loss - # r = total_asset_damage / tot_wellbeing_loss - - return r - - -def split_policies(outcomes: pd.DataFrame) -> tuple: - # TODO: Make the function more flexible and allow for different top ups and target groups - # Split ASP policies - asp = outcomes[outcomes['current_policy'].str.contains('asp')].copy() - asp[['target_group', 'top_up']] = asp['current_policy'].str.split( - '+', expand=True) - asp['target_group'] = asp['target_group'].str.split(':', expand=True)[1] - - # Make top_up a categorical variable to ensure it is ordered correctly - asp['top_up'] = pd.Categorical(asp['top_up'], categories=['0', '10', '50']) - asp['target_group'] = pd.Categorical(asp['target_group'], categories=[ - 'poor_near_poor2.0', 'all']) - - # Append None policy to ASP - none = outcomes[outcomes['current_policy'] == 'none'].copy() - none['target_group'] = 'none' - none['top_up'] = 'none' - none['current_policy'] = 'none' - asp = pd.concat([asp, none]) - - # Split retrofit policies - retrofit = outcomes[outcomes['current_policy'].str.contains( - 'retrofit')].copy() - retrofit[['target_group', 'houses_pct'] - ] = retrofit['current_policy'].str.split('+', expand=True) - retrofit['target_group'] = retrofit['target_group'].str.split(':', expand=True)[ - 1] - retrofit = pd.concat([retrofit, none]) - return asp, retrofit diff --git a/unbreakable/analysis/calculator.py b/unbreakable/analysis/calculator.py deleted file mode 100644 index 25e3c88..0000000 --- a/unbreakable/analysis/calculator.py +++ /dev/null @@ -1,281 +0,0 @@ -import pandas as pd -import numpy as np -import yaml - - -def calculate_outcomes(households: pd.DataFrame, tot_exposed_asset: float, expected_loss_frac: float, region_pml: float, years_to_recover: int, welfare: float) -> dict: - outcomes = {} - - # Get total population and poverty line - tot_pop = households['wgt'].sum() - pov_line_adjust = households['poverty_line_adjusted'].values[0] - - # Subset affected households - aff_households = households[households['is_affected'] == True] - - # Write already precomputed outcomes - outcomes['return_period'] = households['return_period'].iloc[0] - outcomes['tot_pop'] = tot_pop - outcomes['tot_households'] = households.shape[0] - outcomes['n_aff_people'] = aff_households['wgt'].sum() - outcomes['n_aff_households'] = aff_households.shape[0] - - try: - outcomes['n_retrofitted'] = households[households['retrofitted'] - == True]['wgt'].sum() - outcomes['n_retrofitted_hh'] = households[households['retrofitted'] - == True].shape[0] - outcomes['n_aff_retrofitted'] = aff_households[aff_households['retrofitted'] - == True]['wgt'].sum() - outcomes['n_aff_retrofitted_hh'] = aff_households[aff_households['retrofitted'] == True].shape[0] - - except: - outcomes['n_retrofitted_ppl'] = 0 - outcomes['n_retrofitted_hh'] = 0 - outcomes['n_aff_retrofitted_ppl'] = 0 - outcomes['n_aff_retrofitted_hh'] = 0 - - outcomes['tot_asset_surv'] = households['tot_asset_surv'].iloc[0] - outcomes['tot_exposed_asset'] = tot_exposed_asset - outcomes['tot_asset_loss'] = aff_households[[ - 'keff', 'v', 'wgt']].prod(axis=1).sum() - outcomes['expected_loss_frac'] = expected_loss_frac - outcomes['region_pml'] = region_pml - outcomes['annual_avg_consum'] = weighted_mean(households, 'exp', 'wgt') - outcomes['pov_line_adjust'] = households['poverty_line_adjusted'].iloc[0] - outcomes['mean_recovery_rate'] = aff_households['recovery_rate'].mean() - outcomes['tot_consum_loss_npv'] = weighted_sum( - aff_households, 'consumption_loss_npv', 'wgt') - - # Calculate model outcomes - n_poor_initial, n_new_poor, n_poor_affected, poor_initial, new_poor = find_poor( - households, pov_line_adjust, years_to_recover) - - years_in_poverty = get_people_by_years_in_poverty(new_poor) - - initial_poverty_gap, new_poverty_gap_initial, new_poverty_gap_all = calculate_poverty_gap( - poor_initial, new_poor, pov_line_adjust, years_to_recover) - - annual_average_consumption_loss, annual_average_consumption_loss_pct = calculate_average_annual_consumption_loss( - aff_households, years_to_recover) - - tot_consum_equiv_loss = - aff_households['wellbeing'].div(welfare).multiply( - aff_households['wgt']).sum() - - r = calculate_resilience(aff_households, tot_consum_equiv_loss) - - outcomes['n_poor_initial'] = n_poor_initial - outcomes['n_poor_affected'] = n_poor_affected - outcomes['n_new_poor'] = n_new_poor - outcomes['initial_poverty_gap'] = initial_poverty_gap - outcomes['new_poverty_gap_initial'] = new_poverty_gap_initial - outcomes['new_poverty_gap_all'] = new_poverty_gap_all - outcomes['annual_avg_consum_loss'] = annual_average_consumption_loss - outcomes['annual_avg_consum_loss_pct'] = annual_average_consumption_loss_pct - outcomes['r'] = r - outcomes['years_in_poverty'] = years_in_poverty - - # Save outcome names in a yaml file to pick up in preprocessing - with open('analysis/outcomes.yaml', 'w') as f: - yaml.dump(list(outcomes.keys()), f) - - return outcomes - - -def find_poor(households: pd.DataFrame, pov_line: float, years_to_recover: int) -> tuple: - '''Get the poor at the beginning of the simulation and the poor at the end of the simulation - - Args: - households (pd.DataFrame): Households. - pov_line (float): Poverty line. - years_to_recover (int): Number of years cut-off parameter when calculating consumption loss. - - Returns: - tuple: Number of poor at the beginning of the simulation, number of new poor at the end of the simulation, and the new poor dataframe - ''' - # First, find the poor at the beginning of the simulation - poor_initial = households[households['is_poor'] == True] - n_poor_initial = round(poor_initial['wgt'].sum()) - n_poor_affected = round( - poor_initial[poor_initial['is_affected'] == True]['wgt'].sum()) - - # Second, find the new poor at the end of the simulation (`years_to_recover`) - not_poor = households[households['is_poor'] == False] - not_poor_affected = not_poor[not_poor['is_affected'] == True] - x = not_poor_affected['exp'] - \ - not_poor_affected['consumption_loss_npv'] / years_to_recover - new_poor = not_poor_affected.loc[x < pov_line, :] - new_poor = new_poor.assign(is_poor=True) - n_new_poor = round(new_poor['wgt'].sum()) - - return n_poor_initial, n_new_poor, n_poor_affected, poor_initial, new_poor - - -def get_people_by_years_in_poverty(affected_households: pd.DataFrame) -> dict: - '''Get the number of people in poverty for each year in poverty. - - Args: - affected_households (pd.DataFrame): Affected households - - Returns: - dict: Number of people in poverty for each year in poverty - ''' - affected_households = affected_households.assign( - years_in_poverty=affected_households['weeks_in_poverty'] // 52) - d = {} - longest_years_in_poverty = 10 - for i in range(longest_years_in_poverty + 1): - d[i] = round(affected_households[affected_households['years_in_poverty'] == i] - ['wgt'].sum()) - return d - - -def calculate_poverty_gap(poor_initial: pd.DataFrame, new_poor: pd.DataFrame, poverty_line: float, years_to_recover: int) -> tuple: - '''Calculate the poverty gap at the beginning and at the end of the simulation. - - Args: - poor_initial (pd.DataFrame): Poor at the beginning of the simulation - new_poor (pd.DataFrame): New poor at the end of the simulation - poverty_line (float): Poverty line - years_to_recover (int): Number of years cut-off parameter when calculating consumption loss. Default is 10. - - Returns: - tuple: Poverty gap at the beginning and at the end of the simulation - - Raises: - Exception: If the index is duplicated - Exception: If the poverty gap is greater than 1 - ''' - average_expenditure_poor_initial = ( - poor_initial['exp'] * poor_initial['wgt']).sum() / poor_initial['wgt'].sum() - - # assert poverty_line > average_expenditure_poor_initial, 'Poverty line cannot be less than average expenditure of the poor' - - initial_poverty_gap = ( - poverty_line - average_expenditure_poor_initial) / poverty_line - - # Combine the poor at the beginning of the simulation and the new poor at the end of the simulation - all_poor = pd.concat([poor_initial, new_poor]) - - # Expenditure of both were affected by the disaster - all_poor = all_poor.assign( - exp=all_poor['exp'] - all_poor['consumption_loss_npv'] / years_to_recover) - - # Now, get the average expenditure of the poor at the end of the simulation - average_expenditure_poor_all = ( - all_poor['exp'] * all_poor['wgt']).sum() / all_poor['wgt'].sum() - - # Calculate the poverty gap at the end of the simulation - new_poverty_gap_all = ( - poverty_line - average_expenditure_poor_all) / poverty_line - - # However, we also want to know the poverty gap for old poor - poor_initial = poor_initial.assign( - exp=poor_initial['exp'] - poor_initial['consumption_loss_npv'] / years_to_recover) - - average_expenditure_poor_initial = ( - poor_initial['exp'] * poor_initial['wgt']).sum() / poor_initial['wgt'].sum() - - new_poverty_gap_initial = ( - poverty_line - average_expenditure_poor_initial) / poverty_line - - # Poverty gap cannot be greater than 1 - if initial_poverty_gap > 1 or new_poverty_gap_initial > 1 or new_poverty_gap_all > 1: - raise Exception('Poverty gap cannot be greater than 1') - - return initial_poverty_gap, new_poverty_gap_initial, new_poverty_gap_all - - -def calculate_average_annual_consumption_loss(affected_households: pd.DataFrame, years_to_recover: int) -> tuple: - '''Get the average annual consumption loss and the average annual consumption loss as a percentage of average annual consumption. - - Args: - affected_households (pd.DataFrame): Affected households. - years_to_recover (int): Number of years cut-off parameter when calculating consumption loss. Default is 10. - - Returns: - tuple: Average annual consumption loss and average annual consumption loss as a percentage of average annual consumption - - Raises: - Exception: If the average annual consumption loss is greater than 1 - ''' - - if len(affected_households) == 0: - return np.nan, np.nan - - # Annual consumption loss - annual_consumption_loss = ( - affected_households['consumption_loss_npv'].div(years_to_recover).multiply(affected_households['wgt'])).sum() - - # Weighted average - annual_average_consumption_loss = annual_consumption_loss / \ - affected_households['wgt'].sum() - - annual_average_consumption_loss_pct = (affected_households['consumption_loss_npv'] - .div(years_to_recover) - .div(affected_households['exp']) - .multiply(affected_households['wgt']).sum())\ - / affected_households['wgt'].sum() - - if annual_average_consumption_loss_pct > 1: - raise Exception( - 'Annual average consumption loss pct is greater than 1') - - return annual_average_consumption_loss, annual_average_consumption_loss_pct - - -def calculate_resilience(affected_households: pd.DataFrame, tot_consum_equiv_loss: float) -> float: - '''Calculate socio-economic resilience of affected households. - - Socio-economic resilience is a ratio of asset loss to consumption loss. - - Args: - affected_households (pd.DataFrame): Affected households. - tot_consum_equiv_loss (float): Total consumption equivalent loss. - - Returns: - float: Socio-economic resilience - ''' - # TODO: Test resilience values, it should not go above, e.g., 10 - # total_consumption_loss = ( - # affected_households[['consumption_loss_NPV', 'wgt']].prod(axis=1)).sum() - - total_asset_damage = ( - affected_households[['keff', 'v', 'wgt']].prod(axis=1)).sum() - - # if total_consumption_loss == 0: - # r = np.nan - - # else: - # r = total_asset_damage / total_consumption_loss - r = total_asset_damage / tot_consum_equiv_loss - - return r - - -def weighted_sum(df: pd.DataFrame, col: str, wgt: str) -> float: - '''Calculate the weighted sum of a column in a dataframe. - - Args: - df (pd.DataFrame): Dataframe. - col (str): Column name. - wgt (str): Weight column name. - - Returns: - float: Weighted sum of a column in a dataframe. - ''' - return (df[col] * df[wgt]).sum() - - -def weighted_mean(df: pd.DataFrame, col: str, wgt: str) -> float: - '''Calculate the weighted mean of a column in a dataframe. - - Args: - df (pd.DataFrame): Dataframe. - col (str): Column name. - wgt (str): Weight column name. - - Returns: - float: Weighted mean of a column in a dataframe. - ''' - return weighted_sum(df, col, wgt) / df[wgt].sum() diff --git a/unbreakable/analysis/distributional_metrics.py b/unbreakable/analysis/distributional_metrics.py new file mode 100644 index 0000000..9e15a0d --- /dev/null +++ b/unbreakable/analysis/distributional_metrics.py @@ -0,0 +1,168 @@ +import pandas as pd +import numpy as np +from typing import Dict, List, Any +from functools import partial +from unbreakable.analysis.economic_metrics import ( + calculate_average_annual_consumption_loss, +) +from unbreakable.analysis.resilience_metrics import calculate_socioeconomic_resilience + + +def calculate_distributional_impacts( + households: pd.DataFrame, + max_years: int, + socioeconomic_attributes: List[str], + baseline_avg_annual_consumption_loss_pct: float, + baseline_resilience: Dict[str, float], +) -> Dict[str, float]: + """ + Calculate distributional impacts across different socioeconomic groups. + + This function analyzes the impact of disasters on various socioeconomic groups + by calculating metrics such as consumption loss and resilience for each group. + + Args: + households (pd.DataFrame): DataFrame containing household data. + max_years (int): Maximum number of years for calculating annualized consumption loss. + socioeconomic_attributes (List[str]): List of column names representing socioeconomic attributes. + baseline_avg_annual_consumption_loss_pct (float): Baseline average annual consumption loss percentage. + baseline_resilience (Dict[str, float]): Baseline resilience metrics. + + Returns: + Dict[str, float]: A dictionary containing calculated impact metrics for each socioeconomic group. + """ + outcomes = {} + # Filter for affected households + affected_households = households[households["ever_affected"]] + + # Iterate through each socioeconomic attribute + for column in socioeconomic_attributes: + # Get unique, non-null values for the current attribute + group_values = households[column].dropna().unique() + + # Calculate impacts for each group within the current attribute + for group_value in group_values: + # Filter affected households for the current group + group_households = affected_households[ + affected_households[column] == group_value + ] + + if group_households.empty: + # Handle empty groups by passing empty DataFrame and default values + group_outcomes = calculate_group_outcomes( + column, + group_value, + pd.DataFrame(), + affected_households, + 0.0, + 0.0, + {"consumption_based": 0.0, "wellbeing_based": 0.0}, + baseline_avg_annual_consumption_loss_pct, + baseline_resilience, + ) + else: + # Calculate metrics for non-empty groups + avg_consumption_loss, avg_consumption_loss_pct = ( + calculate_average_annual_consumption_loss( + group_households, max_years + ) + ) + resilience = calculate_socioeconomic_resilience(group_households) + + group_outcomes = calculate_group_outcomes( + column, + group_value, + group_households, + affected_households, + avg_consumption_loss, + avg_consumption_loss_pct, + resilience, + baseline_avg_annual_consumption_loss_pct, + baseline_resilience, + ) + + outcomes.update(group_outcomes) + + return outcomes + + +def calculate_group_outcomes( + column: str, + group_value: Any, + group_households: pd.DataFrame, + affected_households: pd.DataFrame, + average_consumption_loss: float, + average_consumption_loss_pct: float, + resilience: Dict[str, float], + baseline_avg_annual_consumption_loss_pct: float, + baseline_resilience: Dict[str, float], +) -> Dict[str, float]: + """ + Calculate impact outcomes for a specific socioeconomic group. + + This function computes various impact metrics for a given socioeconomic group, + including consumption loss, reconstruction rates, and resilience measures. + + Args: + column (str): Name of the socioeconomic attribute. + group_value (Any): The specific value of the socioeconomic attribute for this group. + group_households (pd.DataFrame): DataFrame containing data for households in this group. + affected_households (pd.DataFrame): DataFrame containing data for all affected households. + average_consumption_loss (float): Average annual consumption loss for this group. + average_consumption_loss_pct (float): Average consumption loss percentage for this group. + resilience (Dict[str, float]): Resilience metrics for this group. + baseline_avg_annual_consumption_loss_pct (float): Baseline average annual consumption loss percentage. + baseline_resilience (Dict[str, float]): Baseline resilience metrics. + + Returns: + Dict[str, float]: A dictionary containing calculated impact metrics for the specific group. + """ + if group_households.empty: + return { + # f"annual_average_consumption_loss_{column}_{group_value}": None, + f"annual_average_consumption_loss_pct_{column}_{group_value}": None, + f"average_consumption_loss_pct_difference_{column}_{group_value}": None, + # f"average_reconstruction_rate_{column}_{group_value}": None, + f"average_reconstruction_rate_difference_{column}_{group_value}": None, + # f"r_consumption_based_{column}_{group_value}": None, + f"r_consumption_based_difference_{column}_{group_value}": None, + # f"r_wellbeing_based_{column}_{group_value}": None, + f"r_wellbeing_based_difference_{column}_{group_value}": None, + } + + return { + # f"annual_average_consumption_loss_{column}_{group_value}": average_consumption_loss, + f"annual_average_consumption_loss_pct_{column}_{group_value}": average_consumption_loss_pct, + f"average_consumption_loss_pct_difference_{column}_{group_value}": ( + (average_consumption_loss_pct - baseline_avg_annual_consumption_loss_pct) + / baseline_avg_annual_consumption_loss_pct + if baseline_avg_annual_consumption_loss_pct != 0 + else 0.0 + ), + f"average_reconstruction_rate_{column}_{group_value}": group_households[ + "reconstruction_rate" + ].mean(), + f"average_reconstruction_rate_difference_{column}_{group_value}": ( + ( + group_households["reconstruction_rate"].mean() + - affected_households["reconstruction_rate"].mean() + ) + / affected_households["reconstruction_rate"].mean() + if affected_households["reconstruction_rate"].mean() != 0 + else 0.0 + ), + f"r_consumption_based_{column}_{group_value}": resilience["consumption_based"], + f"r_consumption_based_difference_{column}_{group_value}": ( + (resilience["consumption_based"] - baseline_resilience["consumption_based"]) + / baseline_resilience["consumption_based"] + if baseline_resilience["consumption_based"] != 0 + else 0.0 + ), + f"r_wellbeing_based_{column}_{group_value}": resilience["wellbeing_based"], + f"r_wellbeing_based_difference_{column}_{group_value}": ( + (resilience["wellbeing_based"] - baseline_resilience["wellbeing_based"]) + / baseline_resilience["wellbeing_based"] + if baseline_resilience["wellbeing_based"] != 0 + else 0.0 + ), + } diff --git a/unbreakable/analysis/economic_metrics.py b/unbreakable/analysis/economic_metrics.py new file mode 100644 index 0000000..8650b82 --- /dev/null +++ b/unbreakable/analysis/economic_metrics.py @@ -0,0 +1,56 @@ +import pandas as pd +from typing import Tuple + + +def calculate_average_annual_consumption_loss( + affected_households: pd.DataFrame, max_years: int +) -> Tuple[float, float]: + """ + Calculate the average annual consumption loss and its percentage of average annual consumption. + + Args: + affected_households (pd.DataFrame): Affected households data. Must include columns: + - consumption_loss_npv: Net present value of consumption loss + - household_weight: Household weight + - exp: Annual consumption (expenditure) + max_years (int): Number of years cut-off parameter for calculating consumption loss. + + Returns: + Tuple[float, float]: + - Average annual consumption loss + - Average annual consumption loss as a percentage of average annual consumption + + Raises: + ValueError: If the average annual consumption loss percentage is greater than 100% + ValueError: If the DataFrame is empty + """ + if affected_households.empty: + raise ValueError("The affected_households DataFrame is empty.") + + # Calculate annual consumption loss + annual_consumption_loss = ( + affected_households["consumption_loss_npv"] + .div(max_years) + .mul(affected_households["household_weight"]) + .sum() + ) + + # Calculate weighted average annual consumption loss + total_weight = affected_households["household_weight"].sum() + annual_average_consumption_loss = annual_consumption_loss / total_weight + + # Calculate percentage of average annual consumption loss + annual_average_consumption_loss_pct = ( + affected_households["consumption_loss_npv"] + .div(max_years) + .div(affected_households["exp"]) + .mul(affected_households["household_weight"]) + .sum() + ) / total_weight + + if annual_average_consumption_loss_pct > 1: + raise ValueError( + "Annual average consumption loss percentage is greater than 100%" + ) + + return annual_average_consumption_loss, annual_average_consumption_loss_pct diff --git a/unbreakable/analysis/metric_calculator.py b/unbreakable/analysis/metric_calculator.py new file mode 100644 index 0000000..a325ee7 --- /dev/null +++ b/unbreakable/analysis/metric_calculator.py @@ -0,0 +1,106 @@ +import pandas as pd +from typing import Dict, Any +import json +import numpy as np + +from unbreakable.analysis.poverty_metrics import ( + analyze_poor_population, + analyze_poverty_duration, + calculate_poverty_gaps, +) +from unbreakable.analysis.resilience_metrics import calculate_socioeconomic_resilience +from unbreakable.analysis.economic_metrics import ( + calculate_average_annual_consumption_loss, +) +from unbreakable.analysis.distributional_metrics import ( + calculate_distributional_impacts, +) + + +def calculate_metrics( + households: pd.DataFrame, max_years: int, analysis_params: Dict[str, Any] +) -> Dict[str, float]: + """ + Calculate various metrics across affected households. + + Args: + households (pd.DataFrame): DataFrame containing household data. + max_years (int): Number of years for calculating annualized consumption loss. + analysis_params (Dict[str, Any]): Dictionary containing analysis parameters. + + Returns: + Dict[str, float]: A dictionary containing calculated metrics. + """ + affected_households = households[households["ever_affected"]].copy() + + # Calculate years to recover + affected_households["years_to_recover"] = np.round( + np.log(1 / 0.05) / affected_households["reconstruction_rate"] + ) + + avg_years_to_recover = affected_households["years_to_recover"].mean() + avg_dwelling_vulnerability = affected_households["v"].mean() + + # Calculate poverty metrics + ( + initial_poor_count, + new_poor_count, + affected_poor_count, + initial_poor_df, + new_poor_df, + ) = analyze_poor_population(households, max_years) + + poverty_duration = analyze_poverty_duration(affected_households, max_years) + + initial_poverty_gap, updated_initial_poverty_gap, overall_poverty_gap = ( + calculate_poverty_gaps(initial_poor_df, new_poor_df, max_years) + ) + + # Calculate resilience metrics + resilience = calculate_socioeconomic_resilience(affected_households) + + # Calculate economic metrics + avg_annual_consumption_loss, avg_annual_consumption_loss_pct = ( + calculate_average_annual_consumption_loss(affected_households, max_years) + ) + + # Compile results + results = { + "households_count": len(households), + "affected_households_count": len(affected_households), + "people_count": households["household_weight"].sum(), + "affected_people_count": affected_households["household_weight"].sum(), + "initial_poor_count": initial_poor_count, + "new_poor_count": new_poor_count, + "affected_poor_count": affected_poor_count, + "initial_poverty_gap": initial_poverty_gap, + "updated_initial_poverty_gap": updated_initial_poverty_gap, + "overall_poverty_gap": overall_poverty_gap, + "resilience_consumption_based": resilience["consumption_based"], + "resilience_wellbeing_based": resilience["wellbeing_based"], + "annual_average_consumption_loss": avg_annual_consumption_loss, + "annual_average_consumption_loss_pct": avg_annual_consumption_loss_pct, + "average_years_to_recover": avg_years_to_recover, + "average_dwelling_vulnerability": avg_dwelling_vulnerability, + **{ + f"poverty_duration_{year}": count + for year, count in poverty_duration.items() + }, + } + + # Calculate distributional impacts if required + if analysis_params.get("distributional_impacts", False): + distributional_outcomes = calculate_distributional_impacts( + households, + max_years, + analysis_params.get("socioeconomic_attributes", []), + avg_annual_consumption_loss_pct, + resilience, + ) + results.update(distributional_outcomes) + + # Save results keys in a json file + with open("experiments/outcome_names_ordered.json", "w") as f: + json.dump(list(results.keys()), f) + + return results diff --git a/unbreakable/analysis/outcomes.yaml b/unbreakable/analysis/outcomes.yaml deleted file mode 100644 index 6604855..0000000 --- a/unbreakable/analysis/outcomes.yaml +++ /dev/null @@ -1,28 +0,0 @@ -- return_period -- tot_pop -- tot_households -- n_aff_people -- n_aff_households -- n_retrofitted_ppl -- n_retrofitted_hh -- n_aff_retrofitted_ppl -- n_aff_retrofitted_hh -- tot_asset_surv -- tot_exposed_asset -- tot_asset_loss -- expected_loss_frac -- region_pml -- annual_avg_consum -- pov_line_adjust -- mean_recovery_rate -- tot_consum_loss_npv -- n_poor_initial -- n_poor_affected -- n_new_poor -- initial_poverty_gap -- new_poverty_gap_initial -- new_poverty_gap_all -- annual_avg_consum_loss -- annual_avg_consum_loss_pct -- r -- years_in_poverty diff --git a/unbreakable/analysis/poverty_metrics.py b/unbreakable/analysis/poverty_metrics.py new file mode 100644 index 0000000..df5445a --- /dev/null +++ b/unbreakable/analysis/poverty_metrics.py @@ -0,0 +1,193 @@ +import pandas as pd +from typing import Dict + + +def analyze_poor_population( + households: pd.DataFrame, max_years: int +) -> tuple[int, int, int, pd.DataFrame, pd.DataFrame]: + """ + Analyze and categorize poor population based on initial state and after-disaster effects. + + This function identifies the initially poor population, the affected poor population, + and the newly poor population after considering disaster effects over a specified recovery period. + + Args: + households (pd.DataFrame): DataFrame containing household data. + max_years (int): Number of years for calculating annualized consumption loss. + + Returns: + tuple[int, int, int, pd.DataFrame, pd.DataFrame]: A tuple containing: + - initial_poor_count: Number of initially poor households. + - new_poor_count: Number of newly poor households after disaster effects. + - affected_poor_count: Number of initially poor households affected by the disaster. + - initial_poor_df: DataFrame of initially poor households. + - new_poor_df: DataFrame of newly poor households. + + Note: + The function assumes the presence of specific columns in the input DataFrame: + 'poverty_line', 'is_poor', 'household_weight', 'ever_affected', 'exp', 'consumption_loss_npv'. + """ + poverty_line = households["poverty_line"].iloc[0] + + # Identify initially poor households + initial_poor_df = households[households["is_poor"]] + initial_poor_count = round(initial_poor_df["household_weight"].sum()) + + # Identify affected poor households + affected_poor_df = initial_poor_df[initial_poor_df["ever_affected"]] + affected_poor_count = round(affected_poor_df["household_weight"].sum()) + + # Identify newly poor households + initially_not_poor_df = households[~households["is_poor"]] + affected_not_poor_df = initially_not_poor_df[initially_not_poor_df["ever_affected"]] + + post_disaster_expenditure = ( + affected_not_poor_df["exp"] + - affected_not_poor_df["consumption_loss_npv"] / max_years + ) + + # ! The poverty line is yearly and the expenditure is monthly + new_poor_df = affected_not_poor_df[ + post_disaster_expenditure < (poverty_line / 12) + ].copy() + new_poor_df["is_poor"] = True + new_poor_count = round(new_poor_df["household_weight"].sum()) + + return ( + initial_poor_count, + new_poor_count, + affected_poor_count, + initial_poor_df, + new_poor_df, + ) + + +def analyze_poverty_duration( + households: pd.DataFrame, max_years: int +) -> Dict[int, int]: + """ + Analyze the duration of poverty for affected households. + + This function calculates the number of people experiencing poverty for different + durations, up to a specified maximum number of years. + + Args: + households (pd.DataFrame): DataFrame containing affected household data. + Must include 'weeks_in_poverty' and 'wgt' (weight) columns. + max_years (int, optional): Maximum number of years to consider. Defaults to 10. + + Returns: + Dict[int, int]: A dictionary where keys are years in poverty (0 to max_years), + and values are the number of people experiencing poverty for that duration. + + Note: + The function assumes that 'weeks_in_poverty' and 'household_weight' columns exist in the input DataFrame. + """ + # Calculate years in poverty from weeks + households = households.copy() + households["years_in_poverty"] = households["weeks_in_poverty"] // 52 + + # Initialize dictionary with zeros for all year counts + poverty_duration_counts = {year: 0 for year in range(max_years + 1)} + + # Group by years in poverty and sum weights + grouped_data = ( + households.groupby("years_in_poverty")["household_weight"] + .sum() + .round() + .astype(int) + ) + + # Update dictionary with actual counts, capped at max_years + poverty_duration_counts.update(grouped_data[grouped_data.index <= max_years]) + + return poverty_duration_counts + + +# TODO: Review how the poverty gaps are calculated + + +def calculate_poverty_gaps( + initial_poor: pd.DataFrame, new_poor: pd.DataFrame, max_years: int = 10 +) -> tuple[float, float, float]: + """ + Calculate the poverty gaps at the beginning and end of the simulation. + This function computes three poverty gaps: + 1. Initial poverty gap + 2. Updated poverty gap for initially poor population + 3. Overall poverty gap including newly poor population + + Args: + initial_poor (pd.DataFrame): DataFrame of initially poor population. + new_poor (pd.DataFrame): DataFrame of newly poor population. + max_years (int): Number of years for calculating annualized consumption loss. Defaults to 10. + + Returns: + tuple[float, float, float]: A tuple containing: + - initial_poverty_gap: Poverty gap at the beginning of the simulation. + - updated_initial_poverty_gap: Updated poverty gap for initially poor population. + - overall_poverty_gap: Poverty gap including both initial and newly poor populations. + + Raises: + ValueError: If any calculated poverty gap is greater than 1. + """ + + def calculate_average_expenditure(df: pd.DataFrame) -> float: + if df.empty: + return 0 + return (df["exp"] * df["household_weight"]).sum() / df["household_weight"].sum() + + def calculate_poverty_gap(average_expenditure: float, poverty_line: float) -> float: + if average_expenditure >= poverty_line: + return 0 + return (poverty_line - average_expenditure) / poverty_line + + # Handle case when initial_poor is empty + if initial_poor.empty: + return 0, 0, 0 if new_poor.empty else 1 + + poverty_line = initial_poor["poverty_line"].iloc[0] + initial_poor = initial_poor.copy() + new_poor = new_poor.copy() + + initial_avg_expenditure = calculate_average_expenditure(initial_poor) + initial_poverty_gap = calculate_poverty_gap(initial_avg_expenditure, poverty_line) + + # Handle case when new_poor is empty + if new_poor.empty: + updated_initial_avg_expenditure = calculate_average_expenditure( + initial_poor.assign( + exp=lambda x: x["exp"] - x["consumption_loss_npv"] / max_years + ) + ) + updated_initial_poverty_gap = calculate_poverty_gap( + updated_initial_avg_expenditure, poverty_line + ) + return ( + initial_poverty_gap, + updated_initial_poverty_gap, + updated_initial_poverty_gap, + ) + + all_poor = pd.concat([initial_poor, new_poor]) + all_poor["exp"] -= all_poor["consumption_loss_npv"] / max_years + overall_avg_expenditure = calculate_average_expenditure(all_poor) + overall_poverty_gap = calculate_poverty_gap(overall_avg_expenditure, poverty_line) + + initial_poor["exp"] -= initial_poor["consumption_loss_npv"] / max_years + updated_initial_avg_expenditure = calculate_average_expenditure(initial_poor) + updated_initial_poverty_gap = calculate_poverty_gap( + updated_initial_avg_expenditure, poverty_line + ) + + if any( + gap > 1 + for gap in [ + initial_poverty_gap, + updated_initial_poverty_gap, + overall_poverty_gap, + ] + ): + raise ValueError("Poverty gap cannot be greater than 1") + + return initial_poverty_gap, updated_initial_poverty_gap, overall_poverty_gap diff --git a/unbreakable/analysis/resilience_metrics.py b/unbreakable/analysis/resilience_metrics.py new file mode 100644 index 0000000..7a04818 --- /dev/null +++ b/unbreakable/analysis/resilience_metrics.py @@ -0,0 +1,69 @@ +import pandas as pd +from typing import Dict + + +def calculate_socioeconomic_resilience( + affected_households: pd.DataFrame, +) -> Dict[str, float]: + """Calculate socio-economic resilience of affected households. + + Socio-economic resilience is calculated using two methods: + 1. Consumption-based = Asset damage / consumption loss + 2. Wellbeing-based = Asset damage / consumption equivalent loss + + Args: + affected_households (pd.DataFrame): Affected households. + + Returns: + Dict[str, float]: Dictionary containing: + - consumption_based: Resilience based on consumption loss + - equivalent_based: Resilience based on consumption equivalent loss + """ + total_asset_damage = ( + affected_households[["keff", "v", "household_weight"]].prod(axis=1) + ).sum() + + total_consumption_loss = ( + affected_households[["consumption_loss_npv", "household_weight"]].prod(axis=1) + ).sum() + + total_consumption_equivalent_loss = calculate_consumption_equivalent_loss( + affected_households + ) + + if total_consumption_loss == 0 or total_consumption_equivalent_loss == 0: + return { + "consumption_based": 0, + "wellbeing_based": 0, + } + + else: + return { + "consumption_based": total_asset_damage / total_consumption_loss, + "wellbeing_based": total_asset_damage / total_consumption_equivalent_loss, + } + + +def calculate_consumption_equivalent_loss(affected_households: pd.DataFrame) -> float: + """ + Calculate the total consumption equivalent loss for affected households. + + This function computes the sum of weighted wellbeing losses relative to welfare + across all affected households. + + Args: + affected_households (pd.DataFrame): DataFrame containing affected households data. + + Returns: + float: The total consumption equivalent loss, always returned as a positive number. + + Note: + The function assumes that 'wellbeing_loss' is typically a negative value, + hence the negative sign in the calculation to return a positive loss. + """ + total_consumption_equivalent_loss = -( + (affected_households["wellbeing_loss"] / affected_households["welfare"]) + * affected_households["household_weight"] + ).sum() + + return total_consumption_equivalent_loss diff --git a/unbreakable/analysis/verifier.py b/unbreakable/analysis/verifier.py deleted file mode 100644 index a6b7ebd..0000000 --- a/unbreakable/analysis/verifier.py +++ /dev/null @@ -1,139 +0,0 @@ -import os -import pandas as pd -from tqdm import tqdm - - -def filter_and_save_consumption_data(country: str = 'Nigeria', return_period: int = 100, run_subset: bool = False, n_runs: int = 1, include_regions_of_interest: bool = False, regions_of_interest: list = None, save_results: bool = False): - ''' - Filter and save the consumption recovery data for the specified country. - - Args: - country (str): The country for which to load the data. - return_period (int): The return period of the disaster. - run_subset (bool): If True, only the first n_runs runs are included. If False, all runs are included. - n_runs (int): The number of runs to include if run_subset is True. - include_regions_of_interest (bool): If True, only data from regions are included. If False, data from all regions are included. - regions_of_interest (list, optional): A list of regions of interest. Only used if include_regions_of_interest is True. - save_results (bool): If True, the results are saved to a CSV file. - - Returns: - dict: A dictionary with keys 'Conflict' and 'No Conflict', each containing a dictionary with 'region' and 'data'. - - Examples: - # Load only 1 run - run_subset = True - n_runs = 1 - - # Load only data from Oyo and Taraba - include_regions_of_interest = True - regions_of_interest = ['Oyo', 'Taraba'] - - # Run the function - results = filter_and_save_consumption_data(run_subset=run_subset, n_runs=n_runs, include_regions_of_interest=include_regions_of_interest, regions_of_interest=regions_of_interest, save_results=True) - ''' - # Initialize the results dictionary - results = {} - - # False - No Conflict, True - Conflict - run_types = [False, True] - - # Loop through the two run types - for c in run_types: - # Set the path to the experiment data - path = os.path.abspath( - f'../../experiments/{country}/consumption_recovery/return_period={return_period}/conflict={c}/') - - # Get the list of folders in the path - folders = [f for f in os.listdir( - path) if os.path.isdir(os.path.join(path, f))] - - # Limit the number of runs if run_subset is True - if run_subset: - folders = folders[:n_runs] - else: - n_runs = len(folders) - - # Initialize the dictionary to store the data for all regions - all_regions_data = {} - - # Loop through the folders - for folder in tqdm(folders, desc=f"Processing {'Conflict' if c else 'No Conflict'} Runs"): - # Get the list of files in the folder - folder_path = os.path.join(path, folder) - - # Limit the files to the regions of interest if include_regions_of_interest is True - if include_regions_of_interest: - files = [f for f in os.listdir(folder_path) if f.split('.')[ - 0] in regions_of_interest] - else: - files = os.listdir(folder_path) - - # Check if region should be included based on the include_conflict_regions_only flag and conflict_regions list - for file in files: - # Get the region name from the file name - region = file.split('.')[0] - - # Load the data from the file - file_path = os.path.join(folder_path, file) - data = pd.read_pickle(file_path) - - # t is the time index - t = list(data.keys()) - - # Get the consumption recovery data for each region - all_region_hh = [data[i]['c_t'].rename( - i) for i in t if not data[i].empty] - - # Concatenate the data for all households in the region - all_regions_data[region] = pd.concat(all_region_hh, axis=1) - - # Store the results in the dictionary - results['Conflict' if c else 'No Conflict'] = all_regions_data - - # Save the results to a CSV file - if save_results: - results_path = os.path.abspath( - f'../../experiments/{country}/consumption_recovery/') - if not os.path.exists(results_path): - os.makedirs(results_path) - for run_type, regions_data in results.items(): - for region, data in regions_data.items(): - data.to_csv(f'{results_path}/{run_type}_{region}_{n_runs}.csv') - - return results - - -def load_consumption_data(country: str = 'Nigeria') -> list: - '''Load the prepared consumption recovery data.''' - # List the files in the folder - folder = f'../../experiments/{country}/consumption_recovery/' - files = os.listdir(folder) - - # Get the regional and mean files - regional_files = [f for f in files if 'mean' not in f] - - # Ignore files if these are folders - regional_files = [f for f in regional_files if '.' in f] - - # Load the data from the regional files - # Differentiate between conflict and no conflict - conflict_regional_data = {} - no_conflict_regional_data = {} - - for file in regional_files: - # Get the region name from the file name - region = file.split('_')[1] - # Get the conflict status from the file name - conflict_status = 'No Conflict' if 'No Conflict' in file else 'Conflict' - # Load the data from the file - data = pd.read_csv(folder + file, index_col=0) - # Store the data in the appropriate dictionary - if conflict_status == 'Conflict': - conflict_regional_data[region] = data - else: - no_conflict_regional_data[region] = data - - return conflict_regional_data, no_conflict_regional_data - - -filter_and_save_consumption_data(save_results=True) diff --git a/unbreakable/analysis/visualizer.py b/unbreakable/analysis/visualizer.py deleted file mode 100644 index 548d4cf..0000000 --- a/unbreakable/analysis/visualizer.py +++ /dev/null @@ -1,543 +0,0 @@ -import geopandas as gpd -import matplotlib -import matplotlib.pyplot as plt -import pandas as pd -import numpy as np -from sklearn.preprocessing import MinMaxScaler -import ptitprince as pt -import seaborn as sns -from scipy.stats import spearmanr -from matplotlib.ticker import MaxNLocator -import mapclassify as mc -from mycolorpy import colorlist as mcp -# import contextily as ctx - - -def raincloud_plot(outcomes: pd.DataFrame, savefig: bool, color_palette: str = 'Set2', sharex: bool = True): - '''Visualize the outcomes using a raincloud plot. - - Args: - outcomes (pd.DataFrame): The outcomes dataframe. - savefig (bool): Whether to save the figure or not. - color_palette (str, optional): The color palette to use. Defaults to 'Set2'. - sharex (bool, optional): Whether to share the x-axis or not. Defaults to True. - - Returns: - None - ''' - - regions = outcomes['region'].unique().tolist() - n_regions = len(regions) - colors = sns.color_palette(color_palette, n_colors=len(regions)) - - x_columns = [ - 'n_aff_people', - 'n_new_poor_increase_pp', - 'n_new_poor', - 'annual_avg_consum_loss_pct', - 'r', - 'new_poverty_gap_initial', - 'new_poverty_gap_all', - ] - - x_titles = [ - 'Affected People', - 'New Poor Increase (p.p.)', - 'New Poor', - f'Wt. Ann. Avg. Consump. Loss p.c. (%)', - 'Socio-Economic Resilience', - 'New Poverty Gap Initial Poor', - 'New Poverty Gap All Poor'] - - for x_column, x_title in zip(x_columns, x_titles): - fig, ax = plt.subplots(ncols=3, nrows=4, figsize=( - 4 * n_regions / 3, 3 * n_regions / 3), sharex=sharex) - - for region in regions: - # Select the region - df = outcomes[outcomes['region'] == region].copy() - - # Convert to float - df[x_column] = df[x_column].astype(float) - - # Make a half violin plot - pt.half_violinplot(x=x_column, - y='policy', - data=df, - color=colors[regions.index(region)], - bw=.2, - cut=0., - scale="area", - width=.6, - inner=None, - ax=ax[regions.index(region) // 3, regions.index(region) % 3]) - - # Add stripplot - sns.stripplot(x=x_column, - y='policy', - data=df, - color=colors[regions.index(region)], - edgecolor='white', - size=3, - jitter=1, - zorder=0, - orient='h', - ax=ax[regions.index(region) // 3, regions.index(region) % 3]) - - # Add boxplot - sns.boxplot(x=x_column, - y='policy', - data=df, - color="black", - width=.15, - zorder=10, - showcaps=True, - boxprops={'facecolor': 'none', "zorder": 10}, - showfliers=True, - whiskerprops={'linewidth': 2, "zorder": 10}, - saturation=1, - orient='h', - ax=ax[regions.index(region) // 3, regions.index(region) % 3]) - - # Set title - title = region - ax[regions.index(region) // 3, - regions.index(region) % 3].set_title(title) - ax[regions.index(region) // 3, - regions.index(region) % 3].set_ylabel('') - ax[regions.index(region) // 3, - regions.index(region) % 3].set_xlabel(x_title) - - # Remove y ticks and labels - ax[regions.index(region) // 3, - regions.index(region) % 3].set_yticklabels([]) - ax[regions.index(region) // 3, - regions.index(region) % 3].set_yticks([]) - - # Do not display floats in the x-axis - ax[regions.index(region) // 3, regions.index(region) % - 3].xaxis.set_major_locator(MaxNLocator(integer=True)) - - # Add text close to the boxplot's median - ax[regions.index(region) // 3, regions.index(region) % 3].text(df[x_column].median(), 0.2, - f'M={df[x_column].median():.2f}', - horizontalalignment='left', size='small', color='black') - # Remove 2 last subplots - ax[3, 1].set_visible(False) - ax[3, 2].set_visible(False) - fig.tight_layout() - if savefig: - plt.savefig( - f'../reports/figures/analysis/{x_column}.png', dpi=500, bbox_inches='tight') - plt.savefig( - f'../reports/figures/analysis/{x_column}.pgf', bbox_inches='tight') - - -def bivariate_choropleth(data: gpd.GeoDataFrame, x_name: str, y_name: str, x_label: str, y_label: str, scheme: str, figsize: tuple, return_table: bool) -> None: - '''Create a bivariate choropleth map. - - Args: - data (gpd.GeoDataFrame): Outcomes data frame. - x_name (str): The name of the first variable. - y_name (str): The name of the second variable. - x_label (str): The label of the first variable. - y_label (str): The label of the second variable. - scheme (str): The scheme to use for binning the data. - figsize (tuple): The size of the figure. - return_table (bool): Whether to return the data frame or not. - - Returns: - None - ''' - - fig, ax = plt.subplots(figsize=figsize) - - # TODO: Allow for 5 classes - # Bin the data - data = bin_data(data, x_name, y_name, scheme, print_statistics=False) - - # Get colors - all_colors, available_colors = get_colors(data) - cmap = matplotlib.colors.ListedColormap(available_colors) - - # Step 1: Draw the map - # border = gpd.read_file(f'../data/processed/boundaries/{city}/city.json') - border = gpd.read_file( - '../data/raw/shapefiles/Saint Lucia/gadm36_LCA_shp/gadm36_LCA_0.shp') - data.plot(ax=ax, - edgecolor='black', - linewidth=.1, - column='Bi_Class', # variable that is going to be used to color the map - cmap=cmap, # newly defined bivariate cmap - categorical=True, # bivariate choropleth has to be colored as categorical map - legend=False) # we're going to draw the legend ourselves - # add the basemap - # ctx.add_basemap(ax=ax, source=ctx.providers.CartoDB.Positron) - border.plot(ax=ax, facecolor='none', - edgecolor='black', alpha=.5) # city border - for idx, row in data.iterrows(): - ax.annotate(text=row['NAME_1'], xy=row['geometry'].centroid.coords[0], - ha='center', fontsize=8, color='white') - - plt.tight_layout() # "tighten" two figures map and basemap - plt.axis('off') # we don't need axis with coordinates - # ax.set_title('Bivariate Choropleth Amsterdam') - - # Step 2: draw the legend - - # We're drawing a 3x3 "box" as 3 columns - # The xmin and xmax arguments axvspan are defined to create equally sized small boxes - - img2 = fig # refer to the main figure - # add new axes to place the legend there - ax2 = fig.add_axes([0.15, 0.25, 0.1, 0.1]) - # and specify its location - alpha = 1 # alpha argument to make it more/less transparent - - # Column 1 - # All colors to create a complete legend - # all_colors = ['#e8e8e8', '#b0d5df', '#64acbe', '#e4acac', '#ad9ea5', '#627f8c', '#c85a5a', '#985356', '#574249'] - - ax2.axvspan(xmin=0, xmax=0.33, ymin=0, ymax=0.33, - alpha=alpha, color=all_colors[0]) - ax2.axvspan(xmin=0, xmax=0.33, ymin=0.33, ymax=0.66, - alpha=alpha, color=all_colors[1]) - ax2.axvspan(xmin=0, xmax=0.33, ymin=0.66, ymax=1, - alpha=alpha, color=all_colors[2]) - - # Column 2 - ax2.axvspan(xmin=0.33, xmax=0.66, ymin=0, ymax=0.33, - alpha=alpha, color=all_colors[3]) - ax2.axvspan(xmin=0.33, xmax=0.66, ymin=0.33, ymax=0.66, - alpha=alpha, color=all_colors[4]) - ax2.axvspan(xmin=0.33, xmax=0.66, ymin=0.66, ymax=1, - alpha=alpha, color=all_colors[5]) - - # Column 3 - ax2.axvspan(xmin=0.66, xmax=1, ymin=0, ymax=0.33, - alpha=alpha, color=all_colors[6]) - ax2.axvspan(xmin=0.66, xmax=1, ymin=0.33, ymax=0.66, - alpha=alpha, color=all_colors[7]) - ax2.axvspan(xmin=0.66, xmax=1, ymin=0.66, ymax=1, - alpha=alpha, color=all_colors[8]) - - # Step 3: annoate the legend - # remove ticks from the big box - ax2.tick_params(axis='both', which='both', length=0) - ax2.axis('off') # turn off its axis - ax2.annotate("", xy=(0, 1), xytext=(0, 0), arrowprops=dict( - arrowstyle="->", lw=1, color='black')) # draw arrow for x - ax2.annotate("", xy=(1, 0), xytext=(0, 0), arrowprops=dict( - arrowstyle="->", lw=1, color='black')) # draw arrow for y - ax2.text(s=x_label, x=0.1, y=-0.25, fontsize=8) # annotate x axis - ax2.text(s=y_label, x=-0.25, y=0.1, rotation=90, - fontsize=8) # annotate y axis - # plt.savefig('bivariate_choropleth.png', dpi=300) - - if return_table: - return data - - -def nine_quadrants_plot(data: pd.DataFrame, x_name: str, y_name: str, scale: bool = True) -> None: - '''Create a nine quadrants plot. - - Args: - data (pd.DataFrame): Outcomes data frame. - x_name (str): The name of the first variable. - y_name (str): The name of the second variable. - scale (bool, optional): Whether to scale the data or not. Defaults to True. - - Returns: - None - ''' - _, ax = plt.subplots(figsize=(6, 5)) - - if scale: - scaler = MinMaxScaler() - data[x_name] = scaler.fit_transform(data[x_name].values.reshape(-1, 1)) - data[y_name] = scaler.fit_transform(data[y_name].values.reshape(-1, 1)) - - data.plot.scatter(x_name, y_name, s=20, ax=ax, c='black', zorder=2) - - # Iterate over each row and annotate the points - for idx, row in data.iterrows(): - ax.annotate(text=row['NAME_1'], xy=(row[x_name], row[y_name]), - ha='center', fontsize=10, color='black') - - # Annotate with Spearman's rho - # rho, p = spearmanr(data[x_name], data[y_name]) - # ax.text(0.05, 0.95, f'$\\rho$ = {round(rho, 2)}', transform=ax.transAxes, - # verticalalignment='top', fontsize=12, bbox=dict(facecolor='white', edgecolor='black', alpha=1)) - - ax.axvline(0.33, color='black', alpha=.33, lw=1) - ax.axvline(0.66, color='black', alpha=.33, lw=1) - ax.axhline(0.33, color='black', alpha=.33, lw=1) - ax.axhline(0.66, color='black', alpha=.33, lw=1) - - alpha = 1 - - all_colors = {'1A': '#dddddd', - '1B': '#dd7c8a', - '1C': '#cc0024', - '2A': '#7bb3d1', - '2B': '#8d6c8f', - '2C': '#8a274a', - '3A': '#016eae', - '3B': '#4a4779', - '3C': '#4b264d'} - - # Column 1 - c = all_colors['1A'] - ax.axvspan(xmin=0, xmax=0.33, ymin=0 + 0.025, - ymax=0.345, alpha=alpha, color=c) - - c = all_colors['1B'] - ax.axvspan(xmin=0, xmax=0.33, ymin=0.33 + 0.015, - ymax=0.66 - 0.015, alpha=alpha, color=c) - - c = all_colors['1C'] - ax.axvspan(xmin=0, xmax=0.33, ymin=0.66 - 0.015, - ymax=1 - 0.05, alpha=alpha, color=c) - - # Column 2 - c = all_colors['2A'] - ax.axvspan(xmin=0.33, xmax=0.66, ymin=0 + 0.025, - ymax=0.345, alpha=alpha, color=c) - - c = all_colors['2B'] - ax.axvspan(xmin=0.33, xmax=0.66, ymin=0.345, - ymax=0.645, alpha=alpha, color=c) - - c = all_colors['2C'] - ax.axvspan(xmin=0.33, xmax=0.66, ymin=0.649, - ymax=1 - 0.05, alpha=alpha, color=c) - - # Column 3 - c = all_colors['3A'] - ax.axvspan(xmin=0.66, xmax=1, ymin=0.025, ymax=0.345, alpha=alpha, color=c) - - c = all_colors['3B'] - ax.axvspan(xmin=0.66, xmax=1, ymin=0.345, - ymax=0.645, alpha=alpha, color=c) - - c = all_colors['3C'] - ax.axvspan(xmin=0.66, xmax=1, ymin=0.649, - ymax=1 - 0.05, alpha=alpha, color=c) - - ax.set_xlim(-.05, 1.05) - ax.set_ylim(-0.05, 1.05) - - # Add regression line - # x = data[x_name] - # y = data[y_name] - # m, b = np.polyfit(x, y, 1) - # ax.plot(x, m * x + b, color='black', alpha=0.5, zorder=1) - - -def get_colors(data: pd.DataFrame) -> list: - '''Get colors for the bivariate choropleth map.''' - - # colors = ['#e8e8e8', # 1A - # '#b0d5df', # 1B - # # '#64acbe', # 1C - # '#e4acac', # 2A - # '#ad9ea5', # 2B - # '#627f8c', # 2C - # '#c85a5a', # 3A - # '#985356'] # , # 3B - # # '#574249'] # 3C - - all_colors = {'1A': '#e8e8e8', - '1B': '#b0d5df', - '1C': '#64acbe', - '2A': '#e4acac', - '2B': '#ad9ea5', - '2C': '#627f8c', - '3A': '#c85a5a', - '3B': '#985356', - '3C': '#574249'} - - all_colors = {'1A': '#dddddd', - '1B': '#dd7c8a', - '1C': '#cc0024', - '2A': '#7bb3d1', - '2B': '#8d6c8f', - '2C': '#8a274a', - '3A': '#016eae', - '3B': '#4a4779', - '3C': '#4b264d'} - - # Set of colors matching the elements of Bi_Class - # We have to exclude those that did not come up in the data - available_classes = data['Bi_Class'].value_counts().sort_index().index - available_colors = [all_colors[i] for i in available_classes] - return list(all_colors.values()), available_colors - - -def bin_data(data: gpd.GeoDataFrame, x_name: str, y_name: str, scheme: str = 'fisher_jenks', print_statistics: bool = True) -> gpd.GeoDataFrame: - '''Bin the data for the bivariate choropleth map. - - Args: - data (gpd.GeoDataFrame): Outcomes data frame. - x_name (str): The name of the first variable. - y_name (str): The name of the second variable. - scheme (str): The scheme to use for binning the data. - print_statistics (bool, optional): Whether to print statistics or not. Defaults to True. - - Returns: - data (gpd.GeoDataFrame): The outcomes data frame with the binned data. - ''' - if scheme == 'fisher_jenks': - x_classifier = mc.FisherJenks(data[x_name], k=3) - # x_bin_edges = x_classifier.bins - x_bin_labels = x_classifier.yb - - y_classifier = mc.FisherJenks(data[y_name], k=3) - # y_bin_edges = y_classifier.bins - y_bin_labels = y_classifier.yb - - # Bin the first variable - x - data['Var1_Class'] = x_bin_labels - data['Var1_Class'] = data['Var1_Class'].astype('str') - - # Bin the second variable - y - data['Var2_Class'] = y_bin_labels - data['Var2_Class'] = data['Var2_Class'].astype('str') - - # Code created x bins to 1, 2, 3 - d = {'0': '1', '1': '2', '2': '3'} - data['Var1_Class'] = data['Var1_Class'].replace(d) - - # Code created y bins to A, B, C - d = {'0': 'A', '1': 'B', '2': 'C'} - data['Var2_Class'] = data['Var2_Class'].replace(d) - - # Combine x and y codes to create Bi_Class - data['Bi_Class'] = data['Var1_Class'].astype('str') + data['Var2_Class'] - - if print_statistics: - print('Number of unique elements in Var1_Class =', - len(data['Var1_Class'].unique())) - print('Number of unique elements in Var2_Class =', - len(data['Var2_Class'].unique())) - print('Number of unique elements in Bi_Class =', - len(data['Bi_Class'].unique())) - return data - - -def annotated_hist(outcomes: pd.DataFrame, annotate: bool) -> None: - '''Create an annotated histogram of the annual average consumption loss. - - Args: - outcomes (pd.DataFrame): Outcomes data frame. - annotate (bool): Whether to annotate the plot or not. - - Returns: - None - ''' - sns.histplot(outcomes['annual_avg_consum_loss_pct'],) - plt.xlabel('Annual Average Consumption Loss PC (%)') - plt.ylabel('Run count') - - plt.axvline(outcomes['annual_avg_consum_loss_pct'].min( - ), color='red', linestyle='dashed', linewidth=1) - plt.axvline(outcomes['annual_avg_consum_loss_pct'].max( - ), color='red', linestyle='dashed', linewidth=1) - plt.axvline(outcomes['annual_avg_consum_loss_pct'].median( - ), color='black', linestyle='dashed', linewidth=1) - - if annotate: - plt.annotate(f"{outcomes['annual_avg_consum_loss_pct'].min():.2f}%", - xy=(outcomes['annual_avg_consum_loss_pct'].min(), 0), - xytext=( - outcomes['annual_avg_consum_loss_pct'].min() - 5, 100), - arrowprops=dict(facecolor='black', shrink=0.05), - horizontalalignment='right', verticalalignment='top') - plt.annotate(f"{outcomes['annual_avg_consum_loss_pct'].max():.2f}%", - xy=(outcomes['annual_avg_consum_loss_pct'].max(), 0), - xytext=( - outcomes['annual_avg_consum_loss_pct'].max() + 5, 100), - arrowprops=dict(facecolor='black', shrink=0.05), - horizontalalignment='left', verticalalignment='top') - plt.annotate(f"{outcomes['annual_avg_consum_loss_pct'].median():.2f}%", - xy=(outcomes['annual_avg_consum_loss_pct'].median(), 0), - xytext=( - outcomes['annual_avg_consum_loss_pct'].median() + 5, 100), - arrowprops=dict(facecolor='black', shrink=0.05), - horizontalalignment='left', verticalalignment='top') - sns.despine() - plt.tight_layout() - - -def coloured_density_plots(outcomes: pd.DataFrame, scheme: str, k: int, cmap: str = "OrRd", legend: bool = True) -> None: - '''Make colored density plots for each region. Color here matches the color of the choropleth map. - - Args: - outcomes (pd.DataFrame): Outcomes data frame. - scheme (str, optional): The scheme to use for binning the data. - k (int, optional): The number of bins. - cmap (str, optional): The name of the colormap to use. Defaults to "OrRd". - - Returns: - None - ''' - # Choropleth map uses median values to classify the regions, we're going to do the same - median_outcomes = outcomes.groupby('region').median(numeric_only=True)[ - ['annual_avg_consum_loss_pct']] - - # The map used equalinterval scheme, but it would be beneficial to allow for other schemes - if scheme == 'equal_intervals': - classifier = mc.EqualInterval(median_outcomes.values, k=k) - elif scheme == 'fisher_jenks': - classifier = mc.FisherJenks(median_outcomes.values, k=k) - else: - raise ValueError( - 'Invalid scheme. Please use `equal_intervals` or `fisher_jenks`') - - # Get the bin edges and labels - bin_edges = classifier.bins - bin_labels = classifier.yb - - # Map the region to the bin label - region_to_label_mapper = dict(zip(median_outcomes.index, bin_labels)) - - # Map the bin label to a color - colors = mcp.gen_color(cmap=cmap, n=k) - label_color_mapper = dict(zip(np.arange(0, k), colors)) - - regions = outcomes['region'].unique().tolist() - fig, ax = plt.subplots() - - # Get regions with min and max values - descr = outcomes.iloc[:, 2:-1].groupby('region').describe()[ - ['annual_avg_consum_loss_pct']] - min_distr = descr['annual_avg_consum_loss_pct']['50%'].idxmin() - max_distr = descr['annual_avg_consum_loss_pct']['50%'].idxmax() - - # Make the density plots - for region in regions: - df = outcomes[outcomes['region'] == region] - region_label = region_to_label_mapper[region] - label_color = label_color_mapper[region_label] - color = label_color - - # Make the line thicker for regions with min and max values - if region in [min_distr, max_distr]: - linewidth = 5 - else: - linewidth = 1 - sns.kdeplot(data=df, x='annual_avg_consum_loss_pct', - ax=ax, color=color, linewidth=linewidth, alpha=1) - - ax.set_xlabel('Annual Average Consumption Loss PC (%)') - ax.set_ylabel('Run density') - ax.spines['right'].set_visible(False) - ax.spines['top'].set_visible(False) - ax.spines['left'].set_visible(False) - ax.spines['bottom'].set_visible(False) - ax.set_facecolor('lightgray') - - if legend: - # Move legend outside the plot - ax.legend(regions, title='Region', frameon=False) - ax.get_legend().set_bbox_to_anchor((1, 1)) diff --git a/unbreakable/data/generator.py b/unbreakable/data/generator.py deleted file mode 100644 index ca2206c..0000000 --- a/unbreakable/data/generator.py +++ /dev/null @@ -1,82 +0,0 @@ -import numpy as np -import pandas as pd -import numpy as np -import seaborn as sns -import scipy.stats as stats - - -def generate_households(num_households=1, conflict_intensity: str = 'None', fix_seed=True): - '''Generate dummy households.''' - if fix_seed: - np.random.seed(0) # Ensure reproducibility - - data = {'exp_house': 0, - 'consumption_loss': 0, - 'consumption_loss_npv': 0, - 'net_consumption_loss': 0, - 'net_consumption_loss_npv': 0, - 'c_t': 0, - 'c_t_unaffected': 0, - 'wellbeing': 0} - - if conflict_intensity != 'None': - d = {'Very low': {'mean': 1522.72, 'std': 980.51, 'min': 154.25, 'max': 5473.81}, - 'Low': {'mean': 1333.83, 'std': 799.99, 'min': 226.35, 'max': 5439.8}, - 'Medium': {'mean': 982.08, 'std': 666.34, 'min': 175.05, 'max': 5317.89}, - 'High': {'mean': 1064.61, 'std': 809.55, 'min': 156.39, 'max': 5439.94}, - 'Very high': {'mean': 637.02, 'std': 474.87, 'min': 152.8, 'max': 5172.65}} - - lower, upper = d[conflict_intensity]['min'], d[conflict_intensity]['max'] - mu, sigma = d[conflict_intensity]['mean'], d[conflict_intensity]['std'] - X = stats.truncnorm((lower - mu) / sigma, - (upper - mu) / sigma, loc=mu, scale=sigma) - exp = X.rvs(num_households) - else: - # Let's take q=0.25 and q=0.75 as the lower and upper bounds - lower, upper = 153, 5474 - mu, sigma = 1099, 1099 - X = stats.truncnorm((lower - mu) / sigma, - (upper - mu) / sigma, loc=mu, scale=sigma) - exp = X.rvs(num_households) - - data['exp'] = exp - # Income is a product of expenditure and a random coefficient - inc_multiplier = 1.48 # for Nigeria - inc_delta = 0.1 - low = inc_multiplier - inc_delta - high = inc_multiplier + inc_delta - data['inc'] = data['exp'] * np.random.uniform(low, high) - - sav_multiplier = 0.0204 # for Nigeria - sav_delta = 0.02 - low = sav_multiplier - sav_delta - high = sav_multiplier + sav_delta - data['sav'] = data['inc'] * np.random.uniform(low, high) - - # divide by average productivity, 0.35 for Nigeria - data['keff'] = data['inc'] / 0.35 - - mean_vulnerability = {'Very low': 0.43, - 'Low': 0.46, - 'Medium': 0.66, - 'High': 0.63, - 'Very high': 0.65} - - if conflict_intensity != 'None': - data['v'] = mean_vulnerability[conflict_intensity] - else: - data['v'] = np.random.uniform(0.2, 0.8, num_households) - - # Sort columns - sorted_columns = ['exp', 'inc', 'sav', 'keff', 'exp_house', 'v', 'consumption_loss', 'consumption_loss_npv', - 'net_consumption_loss', 'net_consumption_loss_npv', 'c_t', 'c_t_unaffected', 'wellbeing'] - - return pd.DataFrame(data)[sorted_columns] - - -def generate_risk_and_damage(): - pass - - -def generate_conflict(): - pass diff --git a/unbreakable/data/randomizer.py b/unbreakable/data/randomizer.py deleted file mode 100644 index 17c0bc7..0000000 --- a/unbreakable/data/randomizer.py +++ /dev/null @@ -1,522 +0,0 @@ -import numpy as np -import pandas as pd - - -def randomize(households: pd.DataFrame, risk_and_damage: pd.DataFrame, - params: dict, random_seed: int, print_statistics: bool = False) -> pd.DataFrame: - ''' - Randomize household data, resample it and match it with risk data. - - Args: - households: Households. - params: Dictionary with parameters for randomization. - random_seed: Random seed. - print_statistics: Whether to print statistics. - - Returns: - households: Randomized and resampled households. - ''' - # Ensure reproducibility - if random_seed is not None: - np.random.seed(random_seed) - households['random_seed'] = random_seed - - # Save country and return period - households['country'] = params['country'] - households['return_period'] = params['return_period'] - - # Extra necessary parameters - rnd_inc_params = params['rnd_inc_params'] - rnd_sav_params = params['rnd_sav_params'] - rnd_rent_params = params['rnd_rent_params'] - avg_prod = params['avg_prod'] - rnd_house_vuln_params = params['rnd_house_vuln_params'] - min_households = params['min_households'] - atol = params['atol'] - - # Randomize household data - households = rnd_income(households, rnd_inc_params) - households = rnd_savings(households, rnd_sav_params) - households = rnd_rent(households, rnd_rent_params) - households = calc_dwelling_value(households, avg_prod) - households = rnd_house_vuln(households, rnd_house_vuln_params) - - # Resample households to be more representative - households = resample_households(households, min_households, random_seed) - - # Match household survey assets with risk and asset damage data - households = match_survey_with_risk_data( - households, risk_and_damage, atol, print_statistics) - - return households - - -# ---------------------------------------------------------------------------- # -# Randomize household survey data # -# ---------------------------------------------------------------------------- # - - -def rnd_inc_mult(size: int, **params) -> np.ndarray: - # NOTE: `normal` is to showcase the flexibility of the function, - # we cannot use it for income generation as it can produce negative values - '''Randomize income multiplier based on the specified parameters.''' - distr = params.get('distr') - if distr == 'uniform': - low = params.get('inc_mult') - params.get('delta') - high = params.get('inc_mult') + params.get('delta') - if low < 0: - raise ValueError("Low income cannot be negative.") - return np.random.uniform(low, high, size) - elif distr == 'normal': - loc = params.get('loc') - scale = params.get('scale') - return np.random.normal(loc, scale, size) - else: - raise ValueError( - f"Distribution '{distr}' is not supported yet.") - - -def rnd_income(households: pd.DataFrame, rnd_income_params: dict) -> pd.DataFrame: - '''Randomize household income.''' - if rnd_income_params['randomize']: - households = households.copy() - size = households.shape[0] - - # Apply income generation for regions or country as applicable - if households['rgn_inc_mult'].notna().any(): - for region in households['region'].unique(): - mask = households['region'] == region - rnd_income_params['inc_mult'] = households.loc[mask, - 'rgn_inc_mult'].iloc[0] - size = mask.sum() - inc_mult_rnd = rnd_inc_mult(size, **rnd_income_params) - - # Estimate income as a product of expenditure and income multiplier - households.loc[mask, 'inc'] = households.loc[mask, - 'exp'] * inc_mult_rnd - elif households['ctry_inc_mult'].notna().any(): - rnd_income_params['inc_mult'] = households['ctry_inc_mult'].iloc[0] - inc_mult_rnd = rnd_inc_mult(size, **rnd_income_params) - # Estimate income as a product of expenditure and income multiplier - households['inc'] = households['exp'] * inc_mult_rnd - else: - raise ValueError("No income multiplier found.") - - assert not households['inc'].isna().any(), "Income cannot be NaN" - assert not (households['inc'] < 0).any(), "Income cannot be negative" - assert not (households['inc'] == 0).any(), "Income cannot be 0" - return households - - else: - return households - - -def rnd_sav_mult(size: int, **params): - """Randomize savings multiplier based on the specified distribution.""" - # NOTE: `normal` is to showcase the flexibility of the function, - # we cannot use it for income generation as it can produce negative values - distr = params.get('distr') - if distr == 'uniform': - low = params.get('low') - high = params.get('high') - return np.random.uniform(low, high, size) - elif distr == 'normal': - loc = params.get('loc') - scale = params.get('scale') - return np.random.normal(loc, scale, size) - else: - raise ValueError(f"Distribution '{distr}' is not supported yet.") - - -def rnd_savings(households: pd.DataFrame, rnd_savings_params: dict) -> pd.DataFrame: - '''Randomize household savings.''' - if rnd_savings_params['randomize']: - # Get function parameters - distr = rnd_savings_params['distr'] - size = households.shape[0] - - # Ensure that the distribution is supported - if distr == 'uniform': - low = rnd_savings_params.get( - 'avg') - rnd_savings_params.get('delta') - high = rnd_savings_params.get( - 'avg') + rnd_savings_params.get('delta') - if low < 0: - raise ValueError("Low savings cannot be negative.") - rnd_savings_params.update({'low': low, 'high': high}) - - else: - raise ValueError(f"Distribution '{distr}' is not supported yet.") - - # Randomize savings multiplier using the distribution-specific function - sav_mult_rnd = rnd_sav_mult(size, **rnd_savings_params) - - # Estimate savings as a product of income and savings multiplier - households['sav'] = households['inc'] * sav_mult_rnd - - assert not households['sav'].isna().any(), "Savings cannot be NaN" - assert not (households['sav'] < 0).any(), "Savings cannot be negative" - assert not (households['sav'] == 0).any(), "Savings cannot be 0" - - return households - else: - return households - - -def rnd_rent_mult(size: int, **params): - """Randomize rent multiplier based on the specified distribution.""" - # NOTE: `normal` is to showcase the flexibility of the function, - # we cannot use it for income generation as it can produce negative values - distr = params.get('distr') - if distr == 'uniform': - low = params.get('low') - high = params.get('high') - return np.random.uniform(low, high, size) - elif distr == 'normal': - loc = params.get('loc') - scale = params.get('scale') - return np.random.normal(loc, scale, size) - else: - raise ValueError(f"Distribution '{distr}' is not supported yet.") - - -def rnd_rent(households: pd.DataFrame, rnd_rent_params: dict) -> pd.DataFrame: - '''Randomize household rent.''' - if rnd_rent_params['randomize']: - # Get function parameters - distr = rnd_rent_params['distr'] - size = households.shape[0] - - # Ensure that the distribution is supported - if distr == 'uniform': - low = rnd_rent_params.get('avg') - rnd_rent_params.get('delta') - high = rnd_rent_params.get('avg') + rnd_rent_params.get('delta') - if low < 0: - raise ValueError("Low rent cannot be negative.") - rnd_rent_params.update({'low': low, 'high': high}) - - else: - raise ValueError(f"Distribution '{distr}' is not supported yet.") - - # Generate savings using the distribution-specific function - rent_mult_rnd = rnd_rent_mult(size, **rnd_rent_params) - - # Assign rent as a product of exp and rent multiplier to each of the rows - households['exp_house'] = households['exp'].mul(rent_mult_rnd) - - assert not households['exp_house'].isna().any(), "Rent cannot be NaN" - assert not (households['exp_house'] < - 0).any(), "Rent cannot be negative" - assert not (households['exp_house'] == 0).any(), "Rent cannot be 0" - - # Remove rent for the households that own - households.loc[households['own_rent'] == 'own', 'exp_house'] = 0 - - return households - else: - return households - - -def calc_dwelling_value(households: pd.DataFrame, avg_prod: float) -> pd.DataFrame: - '''Calculate dwelling value based on the average productivity.''' - # Get the dwelling value for the households that own - households.loc[households['own_rent'] == 'own', - 'k_house'] = households['inc'] / avg_prod - - # Set the dwelling value to 0 for the households that rent - households.loc[households['own_rent'] == 'rent', - 'k_house'] = 0 - - assert not households['k_house'].isna( - ).any(), "Dwelling value cannot be NaN" - assert not (households['k_house'] < 0).any( - ), "Dwelling value cannot be negative" - - return households - - -def rnd_house_vuln(households: pd.DataFrame, rnd_house_vuln_params: dict) -> pd.DataFrame: - ''' - Randomize house vulnerability. - - Args: - households: Households - Required columns: 'v_init' (initial vulnerability) - rnd_house_vuln_params: Dictionary with parameters for randomization. - - Returns: - households: Households with randomized vulnerability. - - Raises: - ValueError: If the distribution is not supported. - ''' - if rnd_house_vuln_params['randomize']: - distr = rnd_house_vuln_params['distr'] - if distr == 'uniform': - # Unpack parameters - low = rnd_house_vuln_params['low'] # default 0.8 - high = rnd_house_vuln_params['high'] # default 1.0 - max_thresh = rnd_house_vuln_params['max_thresh'] # default 0.9 - min_thresh = rnd_house_vuln_params['min_thresh'] # default 0.2 - - # Multiply initial vulnerability by a random value - households['v'] = households['v_init'] * \ - np.random.uniform(low, high, households.shape[0]) - - # Limit vulnerability to a threshold, since under extreme values, recovery rate skyrockets - households.loc[households['v'] > max_thresh, 'v'] = max_thresh - households.loc[households['v'] < min_thresh, 'v'] = min_thresh - else: - raise ValueError("Only uniform distribution is supported yet.") - return households - else: - return households - -# ---------------------------------------------------------------------------- # -# Duplicate households-related # -# ---------------------------------------------------------------------------- # - - -def resample_households(households: pd.DataFrame, min_households: int, random_seed: int) -> pd.DataFrame: - '''Resample country households to be more representative in `identify_affected` function. - - Args: - households (pd.DataFrame): Households. - min_households (int): Minimum number of households for the country sample to be representative. - random_seed (int): Random seed for reproducibility. - - Returns: - pd.DataFrame: Resampled households.f - ''' - sample = pd.DataFrame() - households['id_orig'] = households['id'] - for rgn in households['region'].unique(): - rgn_households = households[households['region'] == rgn] - # TODO: Remove this condition when the data is fixed - if rgn != 'Borno': - rgn_households = resample_region( - rgn_households, min_households, random_seed) - sample = pd.concat( - [sample, rgn_households]) - sample['id'] = range(1, len(sample) + 1) - sample.reset_index(drop=True, inplace=True) - return sample - - -def resample_region(households: pd.DataFrame, min_households: int, random_seed: int) -> pd.DataFrame: - '''Weighted resampling with adjustment for household representation within a given region. - - Args: - households (pd.DataFrame): Households of a specific region. - min_households (int): Minimum number of households for the region sample to be representative. - random_seed (int): Random seed for reproducibility. - - Returns: - pd.DataFrame: Resampled households of a specific region. - - Raises: - ValueError: If the total weights after resampling is not equal to the initial total weights. - ''' - - if len(households) < min_households: - # Save the initial total weights - initial_total_weights = households['wgt'].sum() - - # Save the original household id - households = households.assign( - id_orig=households['id']) - - # Sample households with replacement - delta = min_households - len(households) - - # To avoid sampling one household - if delta == 1: - delta = 2 - - # ?: Check if fixing np random seed is affecting pandas random sampling - if random_seed is not None: - sample = households.sample( - n=delta, replace=True, random_state=random_seed) - else: - sample = households.sample( - n=delta, replace=True) - - # Keep how many duplicates by index - duplicates = sample.index.value_counts() - - # Combine the original and the sampled households - duplicated_households = pd.concat( - [households, sample], axis=0, sort=False) - - # Iterate over the duplicated households and update the weights - for household_id in duplicates.index: - # Get original weight - original_weight = households.loc[household_id, 'wgt'] - - # Count how many rows are there (could be one as well) - n_duplicates = duplicates[household_id] - - # Update the weight - duplicated_households.loc[household_id, - 'wgt'] = original_weight / (n_duplicates + 1) - - # Get the new weight - weights_after_duplication = duplicated_households.loc[household_id, 'wgt'].sum( - ) - - # Check if it is close to the original weight - if not np.isclose(weights_after_duplication, original_weight, atol=1e-6): - raise ValueError( - 'Total weights after duplication is not equal to the initial total weights') - - if not np.isclose(duplicated_households['wgt'].sum(), initial_total_weights, atol=1e-6): - raise ValueError( - 'Total weights after duplication is not equal to the initial total weights') - - return duplicated_households.reset_index(drop=True) - else: - return households - -# ---------------------------------------------------------------------------- # -# Matching household survey assets with risk and asset damage data # -# ---------------------------------------------------------------------------- # - - -def match_survey_with_risk_data(households: pd.DataFrame, risk_and_damage: pd.DataFrame, atol: int, print_statistics: bool = False) -> pd.DataFrame: - # Initialize list to store matched households - matched = [] - - # Iterate over unique regions - for region in households['region'].unique(): - # Filter households by region - region_households = households[households['region'] == region].copy() - - # Compute survey assets - region_households['survey_assets'] = region_households[[ - 'k_house', 'wgt']].prod(axis=1) - survey_assets = region_households['survey_assets'].sum() - - # Get total exposed asset from disaster risk assessment for the given region - disaster_assessment = risk_and_damage[risk_and_damage['region'] - == region].iloc[0] - exposed_assets = disaster_assessment['total_exposed_stock'] - - # Optionally print statistics - if print_statistics: - print_statistics_for_region( - region, survey_assets, exposed_assets, region_households) - - # Match households with disaster risk assessment data - df = match_assets( - region_households, exposed_assets, atol=atol) - - # Recalculate survey assets - df['survey_assets'] = df[['k_house', 'wgt']].prod(axis=1) - - # Assert that the assets match after matching - assert round(exposed_assets) == round( - df['survey_assets'].sum()), "Mismatch in assets after matching" - - matched.append(df) - - # Concatenate matched households and return - return pd.concat(matched) - - -def print_statistics_for_region(region: str, survey_assets: float, exposed_assets: float, households: pd.DataFrame): - print('Region:', region) - print('Household survey assets:', '{:,}'.format(round(survey_assets))) - print('Disaster risk assessment assets:', - '{:,}'.format(round(exposed_assets))) - comparison_ratio = survey_assets / \ - exposed_assets if survey_assets > exposed_assets else exposed_assets / survey_assets - print('Comparison:', '{:.2f} times'.format(comparison_ratio), 'bigger') - print('Median expenditure:', '{:,}'.format(households['exp'].median())) - print('Poverty line:', '{:,}'.format(households['povline'].values[0])) - print('----------------------------------------\n') - - -def check_asset_match(households: pd.DataFrame, tot_exposed_asset: float, atol: float) -> bool: - '''Check if the total asset in the survey matches the total exposed asset. - - Args: - households (pd.DataFrame): Households data. - tot_exposed_asset (float): Total exposed asset stock from the damage data. - atol (float): Absolute tolerance for the comparison. - - Returns: - bool: True if the assets match within the specified tolerance, False otherwise. - ''' - tot_asset_surv = households[['k_house', 'wgt']].prod(axis=1).sum() - return np.isclose(tot_exposed_asset, tot_asset_surv, atol=atol) - - -def adjust_assets(households: pd.DataFrame, tot_exposed_asset: float) -> pd.DataFrame: - '''Adjusts the assets of the households to match the total exposed asset. - - Args: - households (pd.DataFrame): Households data. - tot_exposed_asset (float): Total exposed asset to match. - - Returns: - pd.DataFrame: Adjusted households data. - ''' - tot_asset_surv = households[['k_house', 'wgt']].prod(axis=1).sum() - scaling_factor = tot_exposed_asset / tot_asset_surv - households['tot_asset_surv'] = tot_asset_surv - households['k_house'] *= scaling_factor - - return households - - -def adjust_expenditure(households: pd.DataFrame, scaling_factor: float) -> pd.DataFrame: - '''Adjusts the expenditure of the households based on the scaling factor. - - Args: - households (pd.DataFrame): Households data. - scaling_factor (float): Scaling factor for adjustment. - - Returns: - pd.DataFrame: Households data with adjusted expenditure. - ''' - households['exp'] *= scaling_factor - households['exp_house'] *= scaling_factor - - return households - - -def adjust_poverty_line(households: pd.DataFrame, scaling_factor: float) -> pd.DataFrame: - '''Adjusts the poverty line of the households based on the scaling factor. - - Args: - households (pd.DataFrame): Households data. - scaling_factor (float): Scaling factor for adjustment. - - Returns: - pd.DataFrame: Households data with adjusted poverty line. - ''' - poverty_line = households['poverty_line'].iloc[0] - households['poverty_line_adjusted'] = poverty_line * scaling_factor - - return households - - -def match_assets(households: pd.DataFrame, tot_exposed_asset: float, atol: float) -> pd.DataFrame: - '''Matches and possibly adjusts assets, poverty line and expenditure of households to the asset damage data. - - Args: - households (pd.DataFrame): Households data. - tot_exposed_asset (float): Total exposed asset from the damage data. - atol (float): Absolute tolerance for the comparison. - - Returns: - pd.DataFrame: Households with potentially adjusted assets, expenditure, and poverty line. - ''' - if not check_asset_match(households, tot_exposed_asset, atol): - tot_asset_surv = households[['k_house', 'wgt']].prod(axis=1).sum() - scaling_factor = tot_exposed_asset / tot_asset_surv - households = adjust_assets(households, tot_exposed_asset) - households = adjust_expenditure(households, scaling_factor) - households = adjust_poverty_line(households, scaling_factor) - - return households diff --git a/unbreakable/data/reader.py b/unbreakable/data/reader.py deleted file mode 100644 index e3e8741..0000000 --- a/unbreakable/data/reader.py +++ /dev/null @@ -1,58 +0,0 @@ -import pandas as pd -import logging -from pathlib import Path - -# Configure logging -logging.basicConfig(level=logging.ERROR, - format='%(asctime)s - %(levelname)s - %(message)s') - - -def read_data_file(file_path: Path, file_type: str = 'csv', **kwargs) -> pd.DataFrame: - ''' - Generic function to read a data file. - - Args: - file_path (Path): Path object to the file. - file_type (str): Type of the file ('xlsx' or 'csv'). - **kwargs: Additional keyword arguments for pandas read functions. - - Returns: - pd.DataFrame: Data from the file. - - Raises: - FileNotFoundError: If the file does not exist. - pd.errors.EmptyDataError: If the file is empty. - ''' - try: - if file_type == 'xlsx': - return pd.read_excel(file_path, **kwargs) - elif file_type == 'csv': - return pd.read_csv(file_path, **kwargs) - except Exception as e: - logging.error(f"Error reading data from {file_path}: {e}") - raise - - -def read_data(country: str, is_conflict: bool = False, base_path: str = "../data/processed") -> tuple: - ''' - Load all data for a given country. - - Args: - country (str): Country name. - is_conflict (bool): Whether to read conflict data. - base_path (str): Base path to the data directories. - - Returns: - tuple: DataFrames of household, risk and damage, and optionally conflict data. - ''' - paths = { - 'household': (Path(base_path) / "household_survey" / f"{country}.csv", 'csv'), - 'risk_and_damage': (Path(base_path) / "disaster_risk" / f"{country}.xlsx", 'xlsx'), - 'conflict': (Path(base_path) / "conflict" / f"{country}.xlsx", 'xlsx') - } - - households = read_data_file(*paths['household']) - risk_and_damage = read_data_file(*paths['risk_and_damage']) - conflict = read_data_file(*paths['conflict']) if is_conflict else None - - return households, risk_and_damage, conflict diff --git a/unbreakable/data/saver.py b/unbreakable/data/saver.py deleted file mode 100644 index 76181ee..0000000 --- a/unbreakable/data/saver.py +++ /dev/null @@ -1,19 +0,0 @@ -from pathlib import Path -import pandas as pd - - -def save_households(households: pd.DataFrame, params: dict, random_seed: int): - '''Save region households data to a CSV file. - - Args: - households (pd.DataFrame): Households data. - params (dict): A dictionary of parameters. - random_seed (int): Random seed. - - Returns: - None - ''' - output_dir = Path(f'../results/{params["country"]}/households/') - output_dir.mkdir(parents=True, exist_ok=True) - file_path = output_dir / f'{params["region"]}_{random_seed}.csv' - households.to_csv(file_path) diff --git a/unbreakable/example.py b/unbreakable/example.py new file mode 100644 index 0000000..f0f64ca --- /dev/null +++ b/unbreakable/example.py @@ -0,0 +1,46 @@ +from unbreakable.experiments.config_handler import load_config, update_config +from unbreakable.experiments.model_setup import setup_model +from unbreakable.experiments.experiment_runner import run_experiments + +from ema_workbench import ema_logging + +ema_logging.log_to_stderr(ema_logging.INFO) + + +def main(): + try: + country = "Example" + disaster_spec = [ + {"type": "flood", "event_time": 0, "return_period": None}, + # {"type": "flood", "event_time": 0, "return_period": 50}, + # {"type": "earthquake", "event_time": 0, "return_period": 100}, + ] + + if len(disaster_spec) == 1: + return_period = disaster_spec[0]["return_period"] + else: + return_period = None + + config = load_config(country) + config = update_config(config, disaster_spec) + model = setup_model(config) + + experimental_setup = { + "country": country, + "disaster_spec": disaster_spec, + "model": model, + "return_period": return_period, + "n_scenarios": 1000, # number of replications + "n_policies": 0, + "multiprocessing": False, # use multiprocessing + "n_processes": 16, # number of replications to run in parallel + } + + run_experiments(experimental_setup) + + except Exception as e: + print(f"An error occurred: {e}") + + +if __name__ == "__main__": + main() diff --git a/experiments/__init__.py b/unbreakable/experiments/__init__.py similarity index 100% rename from experiments/__init__.py rename to unbreakable/experiments/__init__.py diff --git a/unbreakable/experiments/config_handler.py b/unbreakable/experiments/config_handler.py new file mode 100644 index 0000000..822ce2d --- /dev/null +++ b/unbreakable/experiments/config_handler.py @@ -0,0 +1,146 @@ +import yaml +from pathlib import Path +from typing import Dict, Any, Union, List, Set + + +def load_config(country: str) -> Dict[str, Any]: + """ + Load and validate configuration settings for the analysis. + + Args: + country (str): Country name. + + Returns: + Dict[str, Any]: Validated configuration settings. + """ + config_path = Path(f"../config/{country}.yaml") + if not config_path.exists(): + raise FileNotFoundError(f"Config file for {country} not found at {config_path}") + + with open(config_path, "r") as file: + config = yaml.safe_load(file) + + validate_config(config) + return config + + +def validate_config(config: Dict[str, Any]) -> None: + """Validate the configuration parameters.""" + required_params = { + "constants": { + "country": None, + "spatial_units": None, + "economic_params": { + "average_productivity", + "income_and_expenditure_growth", + "consumption_utility", + "discount_rate", + }, + "recovery_params": { + "use_precomputed_reconstruction_rates", + "lambda_increment", + "max_years", + }, + "disaster_params": { + "impact_data_type": None, + "disaster_impact_params": { + "add_income_loss", + "poverty_bias_factor", + "distribution", + "max_bias", + "min_bias", + }, + "determine_affected_params": { + "loss_margin_pct", + "max_random_threshold", + "min_random_threshold", + "num_simulations", + }, + }, + "income_params": {"estimate", "randomize", "distribution", "delta"}, + "savings_params": { + "estimate", + "randomize", + "cap_with_max_savings_rate", + "distribution", + "delta", + "max_savings_rate", + }, + "rent_params": { + "estimate", + "randomize", + "distribution", + "pct_of_income", + "delta", + }, + "dwelling_vulnerability_params": { + "randomize", + "distribution", + "low", + "high", + "min_threshold", + "max_threshold", + }, + "min_households": None, + "atol": None, + "analysis_params": { + "save_households", + "save_consumption_recovery", + "distributional_impacts", + }, + } + } + + for key, sub_params in required_params.items(): + if key not in config: + raise ValueError(f"Top-level key '{key}' not found in configuration.") + + if sub_params: + validate_sub_params(config[key], sub_params, key) + + +def validate_sub_params( + config_section: Dict[str, Any], + required_params: Dict[str, Union[None, List, Set]], + parent_key: str, +) -> None: + """Validate sub-parameters of a configuration section.""" + for sub_key, expected_values in required_params.items(): + if sub_key not in config_section: + raise ValueError(f"Sub-parameter '{sub_key}' not found in '{parent_key}'.") + + if isinstance(expected_values, (list, set)): + validate_value( + config_section[sub_key], expected_values, f"{parent_key}.{sub_key}" + ) + + +def validate_value( + value: Any, expected_values: Union[List, Set], param_path: str +) -> None: + """Validate a single configuration value.""" + if isinstance(expected_values, set): + missing_keys = expected_values - set(value.keys()) + if missing_keys: + raise ValueError(f"Missing keys {missing_keys} in {param_path}.") + elif value not in expected_values: + raise ValueError( + f"Value '{value}' for {param_path} not in valid list {expected_values}." + ) + + +def update_config(config, disaster_spec): + """Update the configuration settings with the disaster specification.""" + config["constants"].update( + { + "disaster_spec": disaster_spec, + } + ) + + # Event time cannot be greater than years to recover + for event in disaster_spec: + if event["event_time"] > config["constants"]["recovery_params"]["max_years"]: + raise ValueError( + f"Event time {event['event_time']} is greater than years to recover {config['constants']['years_to_recover']}" + ) + return config diff --git a/unbreakable/experiments/experiment_results_formatter.py b/unbreakable/experiments/experiment_results_formatter.py new file mode 100644 index 0000000..93d55d0 --- /dev/null +++ b/unbreakable/experiments/experiment_results_formatter.py @@ -0,0 +1,124 @@ +import pandas as pd +import numpy as np +import json +import ast +from typing import Tuple, List, Dict, Any + + +def format_experiment_results( + results: Tuple[pd.DataFrame, Dict[str, np.ndarray]], + include_policies: bool = True, + include_uncertainties: bool = True, +) -> pd.DataFrame: + """ + Process experiment results from EMA Workbench format into a structured DataFrame. + + Args: + results (Tuple[pd.DataFrame, Dict[str, np.ndarray]]): EMA Workbench experiment results. + include_policies (bool): Whether to include policy values in the output. + include_uncertainties (bool): Whether to include uncertainty values in the output. + + Returns: + pd.DataFrame: Processed results as a structured DataFrame. + """ + experiments, outcome_data = results + outcome_names = load_outcome_names() + + base_columns = ["scenario", "policy", "spatial_unit", "random_seed"] + policy_names = ["current_policy"] + uncertainty_names = [] # Add uncertainty names if needed + + columns = build_column_list( + base_columns, + policy_names, + uncertainty_names, + outcome_names, + include_policies, + include_uncertainties, + ) + + processed_data = [] + for spatial_unit, spatial_unit_outcomes in outcome_data.items(): + spatial_unit_data = process_spatial_unit_data( + experiments, + spatial_unit_outcomes, + spatial_unit, + policy_names, + uncertainty_names, + outcome_names, + include_policies, + include_uncertainties, + ) + processed_data.extend(spatial_unit_data) + + results_df = pd.DataFrame(processed_data, columns=columns) + return results_df + + +def load_outcome_names() -> List[str]: + """Load outcome names from JSON file.""" + with open("../../unbreakable/experiments/outcome_names_ordered.json", "r") as f: + return json.load(f) + + +def build_column_list( + base_columns: List[str], + policy_names: List[str], + uncertainty_names: List[str], + outcome_names: List[str], + include_policies: bool, + include_uncertainties: bool, +) -> List[str]: + """Build the list of columns for the output DataFrame.""" + columns = base_columns.copy() + if include_policies: + columns.extend(policy_names) + if include_uncertainties: + columns.extend(uncertainty_names) + columns.extend(outcome_names) + return columns + + +def process_spatial_unit_data( + experiments: pd.DataFrame, + spatial_unit_outcomes: np.ndarray, + spatial_unit: str, + policy_names: List[str], + uncertainty_names: List[str], + outcome_names: List[str], + include_policies: bool, + include_uncertainties: bool, +) -> List[List[Any]]: + """Process data for a single spatial unit.""" + spatial_unit_data = [] + for idx, outcome_array in enumerate(spatial_unit_outcomes): + row = [ + experiments["scenario"].iloc[idx], + experiments["policy"].iloc[idx], + spatial_unit, + experiments["random_seed"].iloc[idx], + ] + + if include_policies: + row.extend(experiments[policy_names].iloc[idx].tolist()) + + if include_uncertainties: + row.extend(experiments[uncertainty_names].iloc[idx].tolist()) + + row.extend(process_outcome_values(outcome_array, outcome_names)) + spatial_unit_data.append(row) + + return spatial_unit_data + + +def process_outcome_values( + outcome_array: np.ndarray, outcome_names: List[str] +) -> List[Any]: + """Process individual outcome values.""" + processed_values = [] + for value, name in zip(outcome_array, outcome_names): + if name in ["years_in_poverty"]: + processed_values.append(ast.literal_eval(value)) + else: + processed_values.append(value) + return processed_values diff --git a/unbreakable/experiments/experiment_runner.py b/unbreakable/experiments/experiment_runner.py new file mode 100644 index 0000000..8a37364 --- /dev/null +++ b/unbreakable/experiments/experiment_runner.py @@ -0,0 +1,47 @@ +from pathlib import Path +from typing import Dict, Any +from ema_workbench import perform_experiments, MultiprocessingEvaluator, save_results + + +def run_experiments(experimental_setup: Dict[str, Any]) -> None: + """ + Run experiments with the specified setup using EMA Workbench and save the results. + + Args: + experimental_setup (Dict[str, Any]): A dictionary containing the setup for the experiments. + """ + country = experimental_setup["country"] + disaster_spec = experimental_setup["disaster_spec"] + model = experimental_setup["model"] + return_period = experimental_setup["return_period"] + n_scenarios = experimental_setup["n_scenarios"] + n_policies = experimental_setup["n_policies"] + multiprocessing = experimental_setup["multiprocessing"] + n_processes = experimental_setup["n_processes"] + + if multiprocessing: + with MultiprocessingEvaluator(model, n_processes=n_processes) as evaluator: + results = evaluator.perform_experiments( + scenarios=n_scenarios, policies=n_policies + ) + else: + results = perform_experiments( + models=model, scenarios=n_scenarios, policies=n_policies + ) + + # If disaster spec has only one disaster, extract the disaster type + if len(disaster_spec) == 1: + disaster_type = disaster_spec[0]["type"] + + # Else, make a combined disaster type + else: + disaster_type = "" + for i in range(len(disaster_spec)): + disaster_type += disaster_spec[i]["type"] + if i != len(disaster_spec) - 1: + disaster_type += "_and_" + + results_path = Path(f"../results/{country}") + results_path.mkdir(parents=True, exist_ok=True) + filename = f"disaster_type={disaster_type}_return_period={return_period}_scenarios={n_scenarios}_policies={n_policies}.tar.gz" + save_results(results, results_path / filename) diff --git a/unbreakable/experiments/model_setup.py b/unbreakable/experiments/model_setup.py new file mode 100644 index 0000000..105755f --- /dev/null +++ b/unbreakable/experiments/model_setup.py @@ -0,0 +1,39 @@ +from typing import Dict, Any +from ema_workbench import Model +from ema_workbench.em_framework.parameters import ( + IntegerParameter, + CategoricalParameter, + Constant, +) +from ema_workbench.em_framework.outcomes import ArrayOutcome +from unbreakable.model import model + + +def setup_model(config: Dict[str, Any]) -> Model: + """ + Set up the EMA Workbench model based on the provided configuration. + + Args: + config (Dict[str, Any]): Configuration dictionary loaded from the YAML file. + + Returns: + Model: Configured EMA Workbench model. + """ + my_model = Model(name="model", function=model) + + constants = config.get("constants", {}) + levers = config.get("levers", {}) + + # Define seed as an uncertainty for multiple runs, + # By specifying a wider range, we want to ensure that the seed is likely to be different for each run + my_model.uncertainties = [IntegerParameter("random_seed", 0, 1_000_000_000)] + my_model.constants = [Constant(key, value) for key, value in constants.items()] + my_model.levers = [CategoricalParameter("current_policy", list(levers.values()))] + + # Outcomes are stored in array and calculated for each region + my_model.outcomes = [ + ArrayOutcome(spatial_unit) + for spatial_unit in constants.get("spatial_units", []) + ] + + return my_model diff --git a/unbreakable/experiments/outcome_names_ordered.json b/unbreakable/experiments/outcome_names_ordered.json new file mode 100644 index 0000000..df94ee5 --- /dev/null +++ b/unbreakable/experiments/outcome_names_ordered.json @@ -0,0 +1 @@ +["affected_households_count", "people_count", "affected_people_count", "initial_poor_count", "new_poor_count", "affected_poor_count", "initial_poverty_gap", "updated_initial_poverty_gap", "overall_poverty_gap", "resilience_consumption_based", "resilience_wellbeing_based", "annual_average_consumption_loss", "annual_average_consumption_loss_pct", "average_years_to_recover", "poverty_duration_0", "poverty_duration_1", "poverty_duration_2", "poverty_duration_3", "poverty_duration_4", "poverty_duration_5", "poverty_duration_6", "poverty_duration_7", "poverty_duration_8", "poverty_duration_9", "poverty_duration_10", "annual_average_consumption_loss_pct_female_headed_False", "average_consumption_loss_pct_difference_female_headed_False", "average_reconstruction_rate_female_headed_False", "average_reconstruction_rate_difference_female_headed_False", "r_consumption_based_female_headed_False", "r_consumption_based_difference_female_headed_False", "r_wellbeing_based_female_headed_False", "r_wellbeing_based_difference_female_headed_False", "annual_average_consumption_loss_pct_female_headed_True", "average_consumption_loss_pct_difference_female_headed_True", "average_reconstruction_rate_female_headed_True", "average_reconstruction_rate_difference_female_headed_True", "r_consumption_based_female_headed_True", "r_consumption_based_difference_female_headed_True", "r_wellbeing_based_female_headed_True", "r_wellbeing_based_difference_female_headed_True", "annual_average_consumption_loss_pct_urban_Urban", "average_consumption_loss_pct_difference_urban_Urban", "average_reconstruction_rate_urban_Urban", "average_reconstruction_rate_difference_urban_Urban", "r_consumption_based_urban_Urban", "r_consumption_based_difference_urban_Urban", "r_wellbeing_based_urban_Urban", "r_wellbeing_based_difference_urban_Urban", "annual_average_consumption_loss_pct_urban_Rural", "average_consumption_loss_pct_difference_urban_Rural", "average_reconstruction_rate_urban_Rural", "average_reconstruction_rate_difference_urban_Rural", "r_consumption_based_urban_Rural", "r_consumption_based_difference_urban_Rural", "r_wellbeing_based_urban_Rural", "r_wellbeing_based_difference_urban_Rural", "annual_average_consumption_loss_pct_educat4_highest_Primary (complete or incomplete)", "average_consumption_loss_pct_difference_educat4_highest_Primary (complete or incomplete)", "average_reconstruction_rate_educat4_highest_Primary (complete or incomplete)", "average_reconstruction_rate_difference_educat4_highest_Primary (complete or incomplete)", "r_consumption_based_educat4_highest_Primary (complete or incomplete)", "r_consumption_based_difference_educat4_highest_Primary (complete or incomplete)", "r_wellbeing_based_educat4_highest_Primary (complete or incomplete)", "r_wellbeing_based_difference_educat4_highest_Primary (complete or incomplete)", "annual_average_consumption_loss_pct_educat4_highest_Secondary (complete or incomplete)", "average_consumption_loss_pct_difference_educat4_highest_Secondary (complete or incomplete)", "average_reconstruction_rate_educat4_highest_Secondary (complete or incomplete)", "average_reconstruction_rate_difference_educat4_highest_Secondary (complete or incomplete)", "r_consumption_based_educat4_highest_Secondary (complete or incomplete)", "r_consumption_based_difference_educat4_highest_Secondary (complete or incomplete)", "r_wellbeing_based_educat4_highest_Secondary (complete or incomplete)", "r_wellbeing_based_difference_educat4_highest_Secondary (complete or incomplete)", "annual_average_consumption_loss_pct_educat4_highest_Tertiary (complete or incomplete)", "average_consumption_loss_pct_difference_educat4_highest_Tertiary (complete or incomplete)", "average_reconstruction_rate_educat4_highest_Tertiary (complete or incomplete)", "average_reconstruction_rate_difference_educat4_highest_Tertiary (complete or incomplete)", "r_consumption_based_educat4_highest_Tertiary (complete or incomplete)", "r_consumption_based_difference_educat4_highest_Tertiary (complete or incomplete)", "r_wellbeing_based_educat4_highest_Tertiary (complete or incomplete)", "r_wellbeing_based_difference_educat4_highest_Tertiary (complete or incomplete)", "annual_average_consumption_loss_pct_educat4_highest_No education", "average_consumption_loss_pct_difference_educat4_highest_No education", "average_reconstruction_rate_educat4_highest_No education", "average_reconstruction_rate_difference_educat4_highest_No education", "r_consumption_based_educat4_highest_No education", "r_consumption_based_difference_educat4_highest_No education", "r_wellbeing_based_educat4_highest_No education", "r_wellbeing_based_difference_educat4_highest_No education", "annual_average_consumption_loss_pct_employed_fraction_0.5", "average_consumption_loss_pct_difference_employed_fraction_0.5", "average_reconstruction_rate_employed_fraction_0.5", "average_reconstruction_rate_difference_employed_fraction_0.5", "r_consumption_based_employed_fraction_0.5", "r_consumption_based_difference_employed_fraction_0.5", "r_wellbeing_based_employed_fraction_0.5", "r_wellbeing_based_difference_employed_fraction_0.5", "annual_average_consumption_loss_pct_employed_fraction_0.25", "average_consumption_loss_pct_difference_employed_fraction_0.25", "average_reconstruction_rate_employed_fraction_0.25", "average_reconstruction_rate_difference_employed_fraction_0.25", "r_consumption_based_employed_fraction_0.25", "r_consumption_based_difference_employed_fraction_0.25", "r_wellbeing_based_employed_fraction_0.25", "r_wellbeing_based_difference_employed_fraction_0.25", "annual_average_consumption_loss_pct_employed_fraction_0.2", "average_consumption_loss_pct_difference_employed_fraction_0.2", "average_reconstruction_rate_employed_fraction_0.2", "average_reconstruction_rate_difference_employed_fraction_0.2", "r_consumption_based_employed_fraction_0.2", "r_consumption_based_difference_employed_fraction_0.2", "r_wellbeing_based_employed_fraction_0.2", "r_wellbeing_based_difference_employed_fraction_0.2", "annual_average_consumption_loss_pct_employed_fraction_0.1666666666666666", "average_consumption_loss_pct_difference_employed_fraction_0.1666666666666666", "average_reconstruction_rate_employed_fraction_0.1666666666666666", "average_reconstruction_rate_difference_employed_fraction_0.1666666666666666", "r_consumption_based_employed_fraction_0.1666666666666666", "r_consumption_based_difference_employed_fraction_0.1666666666666666", "r_wellbeing_based_employed_fraction_0.1666666666666666", "r_wellbeing_based_difference_employed_fraction_0.1666666666666666", "annual_average_consumption_loss_pct_employed_fraction_0.6666666666666666", "average_consumption_loss_pct_difference_employed_fraction_0.6666666666666666", "average_reconstruction_rate_employed_fraction_0.6666666666666666", "average_reconstruction_rate_difference_employed_fraction_0.6666666666666666", "r_consumption_based_employed_fraction_0.6666666666666666", "r_consumption_based_difference_employed_fraction_0.6666666666666666", "r_wellbeing_based_employed_fraction_0.6666666666666666", "r_wellbeing_based_difference_employed_fraction_0.6666666666666666", "annual_average_consumption_loss_pct_employed_fraction_0.4", "average_consumption_loss_pct_difference_employed_fraction_0.4", "average_reconstruction_rate_employed_fraction_0.4", "average_reconstruction_rate_difference_employed_fraction_0.4", "r_consumption_based_employed_fraction_0.4", "r_consumption_based_difference_employed_fraction_0.4", "r_wellbeing_based_employed_fraction_0.4", "r_wellbeing_based_difference_employed_fraction_0.4", "annual_average_consumption_loss_pct_employed_fraction_0.3333333333333333", "average_consumption_loss_pct_difference_employed_fraction_0.3333333333333333", "average_reconstruction_rate_employed_fraction_0.3333333333333333", "average_reconstruction_rate_difference_employed_fraction_0.3333333333333333", "r_consumption_based_employed_fraction_0.3333333333333333", "r_consumption_based_difference_employed_fraction_0.3333333333333333", "r_wellbeing_based_employed_fraction_0.3333333333333333", "r_wellbeing_based_difference_employed_fraction_0.3333333333333333", "annual_average_consumption_loss_pct_employed_fraction_0.1428571428571428", "average_consumption_loss_pct_difference_employed_fraction_0.1428571428571428", "average_reconstruction_rate_employed_fraction_0.1428571428571428", "average_reconstruction_rate_difference_employed_fraction_0.1428571428571428", "r_consumption_based_employed_fraction_0.1428571428571428", "r_consumption_based_difference_employed_fraction_0.1428571428571428", "r_wellbeing_based_employed_fraction_0.1428571428571428", "r_wellbeing_based_difference_employed_fraction_0.1428571428571428", "annual_average_consumption_loss_pct_employed_fraction_0.0", "average_consumption_loss_pct_difference_employed_fraction_0.0", "average_reconstruction_rate_employed_fraction_0.0", "average_reconstruction_rate_difference_employed_fraction_0.0", "r_consumption_based_employed_fraction_0.0", "r_consumption_based_difference_employed_fraction_0.0", "r_wellbeing_based_employed_fraction_0.0", "r_wellbeing_based_difference_employed_fraction_0.0", "annual_average_consumption_loss_pct_employed_fraction_0.2857142857142857", "average_consumption_loss_pct_difference_employed_fraction_0.2857142857142857", "average_reconstruction_rate_employed_fraction_0.2857142857142857", "average_reconstruction_rate_difference_employed_fraction_0.2857142857142857", "r_consumption_based_employed_fraction_0.2857142857142857", "r_consumption_based_difference_employed_fraction_0.2857142857142857", "r_wellbeing_based_employed_fraction_0.2857142857142857", "r_wellbeing_based_difference_employed_fraction_0.2857142857142857", "annual_average_consumption_loss_pct_employed_fraction_0.2222222222222222", "average_consumption_loss_pct_difference_employed_fraction_0.2222222222222222", "average_reconstruction_rate_employed_fraction_0.2222222222222222", "average_reconstruction_rate_difference_employed_fraction_0.2222222222222222", "r_consumption_based_employed_fraction_0.2222222222222222", "r_consumption_based_difference_employed_fraction_0.2222222222222222", "r_wellbeing_based_employed_fraction_0.2222222222222222", "r_wellbeing_based_difference_employed_fraction_0.2222222222222222", "annual_average_consumption_loss_pct_employed_fraction_0.125", "average_consumption_loss_pct_difference_employed_fraction_0.125", "average_reconstruction_rate_employed_fraction_0.125", "average_reconstruction_rate_difference_employed_fraction_0.125", "r_consumption_based_employed_fraction_0.125", "r_consumption_based_difference_employed_fraction_0.125", "r_wellbeing_based_employed_fraction_0.125", "r_wellbeing_based_difference_employed_fraction_0.125", "annual_average_consumption_loss_pct_employed_fraction_0.1818181818181818", "average_consumption_loss_pct_difference_employed_fraction_0.1818181818181818", "average_reconstruction_rate_employed_fraction_0.1818181818181818", "average_reconstruction_rate_difference_employed_fraction_0.1818181818181818", "r_consumption_based_employed_fraction_0.1818181818181818", "r_consumption_based_difference_employed_fraction_0.1818181818181818", "r_wellbeing_based_employed_fraction_0.1818181818181818", "r_wellbeing_based_difference_employed_fraction_0.1818181818181818", "annual_average_consumption_loss_pct_employed_fraction_0.2727272727272727", "average_consumption_loss_pct_difference_employed_fraction_0.2727272727272727", "average_reconstruction_rate_employed_fraction_0.2727272727272727", "average_reconstruction_rate_difference_employed_fraction_0.2727272727272727", "r_consumption_based_employed_fraction_0.2727272727272727", "r_consumption_based_difference_employed_fraction_0.2727272727272727", "r_wellbeing_based_employed_fraction_0.2727272727272727", "r_wellbeing_based_difference_employed_fraction_0.2727272727272727", "annual_average_consumption_loss_pct_employed_fraction_0.3636363636363636", "average_consumption_loss_pct_difference_employed_fraction_0.3636363636363636", "average_reconstruction_rate_employed_fraction_0.3636363636363636", "average_reconstruction_rate_difference_employed_fraction_0.3636363636363636", "r_consumption_based_employed_fraction_0.3636363636363636", "r_consumption_based_difference_employed_fraction_0.3636363636363636", "r_wellbeing_based_employed_fraction_0.3636363636363636", "r_wellbeing_based_difference_employed_fraction_0.3636363636363636", "annual_average_consumption_loss_pct_employed_fraction_0.375", "average_consumption_loss_pct_difference_employed_fraction_0.375", "average_reconstruction_rate_employed_fraction_0.375", "average_reconstruction_rate_difference_employed_fraction_0.375", "r_consumption_based_employed_fraction_0.375", "r_consumption_based_difference_employed_fraction_0.375", "r_wellbeing_based_employed_fraction_0.375", "r_wellbeing_based_difference_employed_fraction_0.375", "annual_average_consumption_loss_pct_employed_fraction_0.3", "average_consumption_loss_pct_difference_employed_fraction_0.3", "average_reconstruction_rate_employed_fraction_0.3", "average_reconstruction_rate_difference_employed_fraction_0.3", "r_consumption_based_employed_fraction_0.3", "r_consumption_based_difference_employed_fraction_0.3", "r_wellbeing_based_employed_fraction_0.3", "r_wellbeing_based_difference_employed_fraction_0.3", "annual_average_consumption_loss_pct_employed_fraction_0.0909090909090909", "average_consumption_loss_pct_difference_employed_fraction_0.0909090909090909", "average_reconstruction_rate_employed_fraction_0.0909090909090909", "average_reconstruction_rate_difference_employed_fraction_0.0909090909090909", "r_consumption_based_employed_fraction_0.0909090909090909", "r_consumption_based_difference_employed_fraction_0.0909090909090909", "r_wellbeing_based_employed_fraction_0.0909090909090909", "r_wellbeing_based_difference_employed_fraction_0.0909090909090909", "annual_average_consumption_loss_pct_employed_fraction_0.4285714285714285", "average_consumption_loss_pct_difference_employed_fraction_0.4285714285714285", "average_reconstruction_rate_employed_fraction_0.4285714285714285", "average_reconstruction_rate_difference_employed_fraction_0.4285714285714285", "r_consumption_based_employed_fraction_0.4285714285714285", "r_consumption_based_difference_employed_fraction_0.4285714285714285", "r_wellbeing_based_employed_fraction_0.4285714285714285", "r_wellbeing_based_difference_employed_fraction_0.4285714285714285", "annual_average_consumption_loss_pct_employed_fraction_0.5714285714285714", "average_consumption_loss_pct_difference_employed_fraction_0.5714285714285714", "average_reconstruction_rate_employed_fraction_0.5714285714285714", "average_reconstruction_rate_difference_employed_fraction_0.5714285714285714", "r_consumption_based_employed_fraction_0.5714285714285714", "r_consumption_based_difference_employed_fraction_0.5714285714285714", "r_wellbeing_based_employed_fraction_0.5714285714285714", "r_wellbeing_based_difference_employed_fraction_0.5714285714285714", "annual_average_consumption_loss_pct_employed_fraction_0.1333333333333333", "average_consumption_loss_pct_difference_employed_fraction_0.1333333333333333", "average_reconstruction_rate_employed_fraction_0.1333333333333333", "average_reconstruction_rate_difference_employed_fraction_0.1333333333333333", "r_consumption_based_employed_fraction_0.1333333333333333", "r_consumption_based_difference_employed_fraction_0.1333333333333333", "r_wellbeing_based_employed_fraction_0.1333333333333333", "r_wellbeing_based_difference_employed_fraction_0.1333333333333333", "annual_average_consumption_loss_pct_employed_fraction_0.75", "average_consumption_loss_pct_difference_employed_fraction_0.75", "average_reconstruction_rate_employed_fraction_0.75", "average_reconstruction_rate_difference_employed_fraction_0.75", "r_consumption_based_employed_fraction_0.75", "r_consumption_based_difference_employed_fraction_0.75", "r_wellbeing_based_employed_fraction_0.75", "r_wellbeing_based_difference_employed_fraction_0.75", "annual_average_consumption_loss_pct_employed_fraction_0.6", "average_consumption_loss_pct_difference_employed_fraction_0.6", "average_reconstruction_rate_employed_fraction_0.6", "average_reconstruction_rate_difference_employed_fraction_0.6", "r_consumption_based_employed_fraction_0.6", "r_consumption_based_difference_employed_fraction_0.6", "r_wellbeing_based_employed_fraction_0.6", "r_wellbeing_based_difference_employed_fraction_0.6", "annual_average_consumption_loss_pct_employed_fraction_0.4166666666666667", "average_consumption_loss_pct_difference_employed_fraction_0.4166666666666667", "average_reconstruction_rate_employed_fraction_0.4166666666666667", "average_reconstruction_rate_difference_employed_fraction_0.4166666666666667", "r_consumption_based_employed_fraction_0.4166666666666667", "r_consumption_based_difference_employed_fraction_0.4166666666666667", "r_wellbeing_based_employed_fraction_0.4166666666666667", "r_wellbeing_based_difference_employed_fraction_0.4166666666666667", "annual_average_consumption_loss_pct_employed_fraction_0.8", "average_consumption_loss_pct_difference_employed_fraction_0.8", "average_reconstruction_rate_employed_fraction_0.8", "average_reconstruction_rate_difference_employed_fraction_0.8", "r_consumption_based_employed_fraction_0.8", "r_consumption_based_difference_employed_fraction_0.8", "r_wellbeing_based_employed_fraction_0.8", "r_wellbeing_based_difference_employed_fraction_0.8", "annual_average_consumption_loss_pct_employed_fraction_0.2307692307692307", "average_consumption_loss_pct_difference_employed_fraction_0.2307692307692307", "average_reconstruction_rate_employed_fraction_0.2307692307692307", "average_reconstruction_rate_difference_employed_fraction_0.2307692307692307", "r_consumption_based_employed_fraction_0.2307692307692307", "r_consumption_based_difference_employed_fraction_0.2307692307692307", "r_wellbeing_based_employed_fraction_0.2307692307692307", "r_wellbeing_based_difference_employed_fraction_0.2307692307692307", "annual_average_consumption_loss_pct_employed_fraction_1.0", "average_consumption_loss_pct_difference_employed_fraction_1.0", "average_reconstruction_rate_employed_fraction_1.0", "average_reconstruction_rate_difference_employed_fraction_1.0", "r_consumption_based_employed_fraction_1.0", "r_consumption_based_difference_employed_fraction_1.0", "r_wellbeing_based_employed_fraction_1.0", "r_wellbeing_based_difference_employed_fraction_1.0", "annual_average_consumption_loss_pct_employed_fraction_0.1", "average_consumption_loss_pct_difference_employed_fraction_0.1", "average_reconstruction_rate_employed_fraction_0.1", "average_reconstruction_rate_difference_employed_fraction_0.1", "r_consumption_based_employed_fraction_0.1", "r_consumption_based_difference_employed_fraction_0.1", "r_wellbeing_based_employed_fraction_0.1", "r_wellbeing_based_difference_employed_fraction_0.1", "annual_average_consumption_loss_pct_employed_fraction_0.4444444444444444", "average_consumption_loss_pct_difference_employed_fraction_0.4444444444444444", "average_reconstruction_rate_employed_fraction_0.4444444444444444", "average_reconstruction_rate_difference_employed_fraction_0.4444444444444444", "r_consumption_based_employed_fraction_0.4444444444444444", "r_consumption_based_difference_employed_fraction_0.4444444444444444", "r_wellbeing_based_employed_fraction_0.4444444444444444", "r_wellbeing_based_difference_employed_fraction_0.4444444444444444", "annual_average_consumption_loss_pct_employed_fraction_0.7142857142857143", "average_consumption_loss_pct_difference_employed_fraction_0.7142857142857143", "average_reconstruction_rate_employed_fraction_0.7142857142857143", "average_reconstruction_rate_difference_employed_fraction_0.7142857142857143", "r_consumption_based_employed_fraction_0.7142857142857143", "r_consumption_based_difference_employed_fraction_0.7142857142857143", "r_wellbeing_based_employed_fraction_0.7142857142857143", "r_wellbeing_based_difference_employed_fraction_0.7142857142857143", "annual_average_consumption_loss_pct_employed_fraction_0.2142857142857142", "average_consumption_loss_pct_difference_employed_fraction_0.2142857142857142", "average_reconstruction_rate_employed_fraction_0.2142857142857142", "average_reconstruction_rate_difference_employed_fraction_0.2142857142857142", "r_consumption_based_employed_fraction_0.2142857142857142", "r_consumption_based_difference_employed_fraction_0.2142857142857142", "r_wellbeing_based_employed_fraction_0.2142857142857142", "r_wellbeing_based_difference_employed_fraction_0.2142857142857142", "annual_average_consumption_loss_pct_employed_fraction_0.0833333333333333", "average_consumption_loss_pct_difference_employed_fraction_0.0833333333333333", "average_reconstruction_rate_employed_fraction_0.0833333333333333", "average_reconstruction_rate_difference_employed_fraction_0.0833333333333333", "r_consumption_based_employed_fraction_0.0833333333333333", "r_consumption_based_difference_employed_fraction_0.0833333333333333", "r_wellbeing_based_employed_fraction_0.0833333333333333", "r_wellbeing_based_difference_employed_fraction_0.0833333333333333", "annual_average_consumption_loss_pct_employed_fraction_0.2666666666666666", "average_consumption_loss_pct_difference_employed_fraction_0.2666666666666666", "average_reconstruction_rate_employed_fraction_0.2666666666666666", "average_reconstruction_rate_difference_employed_fraction_0.2666666666666666", "r_consumption_based_employed_fraction_0.2666666666666666", "r_consumption_based_difference_employed_fraction_0.2666666666666666", "r_wellbeing_based_employed_fraction_0.2666666666666666", "r_wellbeing_based_difference_employed_fraction_0.2666666666666666", "annual_average_consumption_loss_pct_employed_fraction_0.0714285714285714", "average_consumption_loss_pct_difference_employed_fraction_0.0714285714285714", "average_reconstruction_rate_employed_fraction_0.0714285714285714", "average_reconstruction_rate_difference_employed_fraction_0.0714285714285714", "r_consumption_based_employed_fraction_0.0714285714285714", "r_consumption_based_difference_employed_fraction_0.0714285714285714", "r_wellbeing_based_employed_fraction_0.0714285714285714", "r_wellbeing_based_difference_employed_fraction_0.0714285714285714", "annual_average_consumption_loss_pct_imp_wat_rec_True", "average_consumption_loss_pct_difference_imp_wat_rec_True", "average_reconstruction_rate_imp_wat_rec_True", "average_reconstruction_rate_difference_imp_wat_rec_True", "r_consumption_based_imp_wat_rec_True", "r_consumption_based_difference_imp_wat_rec_True", "r_wellbeing_based_imp_wat_rec_True", "r_wellbeing_based_difference_imp_wat_rec_True", "annual_average_consumption_loss_pct_imp_wat_rec_False", "average_consumption_loss_pct_difference_imp_wat_rec_False", "average_reconstruction_rate_imp_wat_rec_False", "average_reconstruction_rate_difference_imp_wat_rec_False", "r_consumption_based_imp_wat_rec_False", "r_consumption_based_difference_imp_wat_rec_False", "r_wellbeing_based_imp_wat_rec_False", "r_wellbeing_based_difference_imp_wat_rec_False", "annual_average_consumption_loss_pct_imp_san_rec_True", "average_consumption_loss_pct_difference_imp_san_rec_True", "average_reconstruction_rate_imp_san_rec_True", "average_reconstruction_rate_difference_imp_san_rec_True", "r_consumption_based_imp_san_rec_True", "r_consumption_based_difference_imp_san_rec_True", "r_wellbeing_based_imp_san_rec_True", "r_wellbeing_based_difference_imp_san_rec_True", "annual_average_consumption_loss_pct_imp_san_rec_False", "average_consumption_loss_pct_difference_imp_san_rec_False", "average_reconstruction_rate_imp_san_rec_False", "average_reconstruction_rate_difference_imp_san_rec_False", "r_consumption_based_imp_san_rec_False", "r_consumption_based_difference_imp_san_rec_False", "r_wellbeing_based_imp_san_rec_False", "r_wellbeing_based_difference_imp_san_rec_False", "annual_average_consumption_loss_pct_hsize_ex_5_True", "average_consumption_loss_pct_difference_hsize_ex_5_True", "average_reconstruction_rate_hsize_ex_5_True", "average_reconstruction_rate_difference_hsize_ex_5_True", "r_consumption_based_hsize_ex_5_True", "r_consumption_based_difference_hsize_ex_5_True", "r_wellbeing_based_hsize_ex_5_True", "r_wellbeing_based_difference_hsize_ex_5_True", "annual_average_consumption_loss_pct_hsize_ex_5_False", "average_consumption_loss_pct_difference_hsize_ex_5_False", "average_reconstruction_rate_hsize_ex_5_False", "average_reconstruction_rate_difference_hsize_ex_5_False", "r_consumption_based_hsize_ex_5_False", "r_consumption_based_difference_hsize_ex_5_False", "r_wellbeing_based_hsize_ex_5_False", "r_wellbeing_based_difference_hsize_ex_5_False", "annual_average_consumption_loss_pct_household_has_disability_False", "average_consumption_loss_pct_difference_household_has_disability_False", "average_reconstruction_rate_household_has_disability_False", "average_reconstruction_rate_difference_household_has_disability_False", "r_consumption_based_household_has_disability_False", "r_consumption_based_difference_household_has_disability_False", "r_wellbeing_based_household_has_disability_False", "r_wellbeing_based_difference_household_has_disability_False", "annual_average_consumption_loss_pct_household_has_disability_True", "average_consumption_loss_pct_difference_household_has_disability_True", "average_reconstruction_rate_household_has_disability_True", "average_reconstruction_rate_difference_household_has_disability_True", "r_consumption_based_household_has_disability_True", "r_consumption_based_difference_household_has_disability_True", "r_wellbeing_based_household_has_disability_True", "r_wellbeing_based_difference_household_has_disability_True", "annual_average_consumption_loss_pct_is_single_parent_False", "average_consumption_loss_pct_difference_is_single_parent_False", "average_reconstruction_rate_is_single_parent_False", "average_reconstruction_rate_difference_is_single_parent_False", "r_consumption_based_is_single_parent_False", "r_consumption_based_difference_is_single_parent_False", "r_wellbeing_based_is_single_parent_False", "r_wellbeing_based_difference_is_single_parent_False", "annual_average_consumption_loss_pct_is_single_parent_True", "average_consumption_loss_pct_difference_is_single_parent_True", "average_reconstruction_rate_is_single_parent_True", "average_reconstruction_rate_difference_is_single_parent_True", "r_consumption_based_is_single_parent_True", "r_consumption_based_difference_is_single_parent_True", "r_wellbeing_based_is_single_parent_True", "r_wellbeing_based_difference_is_single_parent_True", "annual_average_consumption_loss_pct_dependency_ratio_High", "average_consumption_loss_pct_difference_dependency_ratio_High", "average_reconstruction_rate_dependency_ratio_High", "average_reconstruction_rate_difference_dependency_ratio_High", "r_consumption_based_dependency_ratio_High", "r_consumption_based_difference_dependency_ratio_High", "r_wellbeing_based_dependency_ratio_High", "r_wellbeing_based_difference_dependency_ratio_High", "annual_average_consumption_loss_pct_dependency_ratio_Low", "average_consumption_loss_pct_difference_dependency_ratio_Low", "average_reconstruction_rate_dependency_ratio_Low", "average_reconstruction_rate_difference_dependency_ratio_Low", "r_consumption_based_dependency_ratio_Low", "r_consumption_based_difference_dependency_ratio_Low", "r_wellbeing_based_dependency_ratio_Low", "r_wellbeing_based_difference_dependency_ratio_Low"] \ No newline at end of file diff --git a/unbreakable/main.py b/unbreakable/main.py new file mode 100644 index 0000000..d07666e --- /dev/null +++ b/unbreakable/main.py @@ -0,0 +1,46 @@ +from unbreakable.experiments.config_handler import load_config, update_config +from unbreakable.experiments.model_setup import setup_model +from unbreakable.experiments.experiment_runner import run_experiments + +from ema_workbench import ema_logging + +ema_logging.log_to_stderr(ema_logging.INFO) + + +def main(): + try: + country = "Bangladesh" + disaster_spec = [ + {"type": "flood", "event_time": 0, "return_period": None}, + # {"type": "flood", "event_time": 0, "return_period": 50}, + # {"type": "earthquake", "event_time": 0, "return_period": 100}, + ] + + if len(disaster_spec) == 1: + return_period = disaster_spec[0]["return_period"] + else: + return_period = None + + config = load_config(country) + config = update_config(config, disaster_spec) + model = setup_model(config) + + experimental_setup = { + "country": country, + "disaster_spec": disaster_spec, + "model": model, + "return_period": return_period, + "n_scenarios": 2, + "n_policies": 0, + "multiprocessing": False, + "n_processes": 16, + } + + run_experiments(experimental_setup) + + except Exception as e: + print(f"An error occurred: {e}") + + +if __name__ == "__main__": + main() diff --git a/unbreakable/model.py b/unbreakable/model.py index 015c64f..7eb25bc 100644 --- a/unbreakable/model.py +++ b/unbreakable/model.py @@ -1,57 +1,218 @@ import numpy as np -from ema_workbench import * -from unbreakable.data.saver import * -from unbreakable.data.reader import * -from unbreakable.data.randomizer import * -from unbreakable.analysis.calculator import * -from unbreakable.modules.disaster import * -from unbreakable.modules.households import * -from unbreakable.modules.policy import * -from unbreakable.modules.recovery import * +import pandas as pd +from typing import Dict, Any, Optional + +from unbreakable.utils.data_loader import load_data, load_reconstruction_rates +from unbreakable.utils.household_data_preprocessor import prepare_household_data +from unbreakable.utils.data_randomizer import randomize_dwelling_vulnerability +from unbreakable.modules.dwelling_vulnerability import calculate_dwelling_vulnerability +from unbreakable.modules.disaster_impact import ( + calculate_compound_impact, + calculate_years_until_next_event, + distribute_disaster_impact, + determine_affected_households, + split_households_by_affected_percentage, +) +from unbreakable.modules.household_recovery import ( + calculate_household_reconstruction_rates, +) +from unbreakable.modules.socioeconomic_impact import estimate_socioeconomic_impact +from unbreakable.analysis.metric_calculator import calculate_metrics def model(**params) -> dict: - '''Simulation model. + random_seed = params["random_seed"] + + # ------------------------- 1: Load and prepare data ------------------------- # + params["current_policy"] = params.get("current_policy", "none") + households, disaster_impacts = load_data(params) + reconstruction_rates = load_reconstruction_rates(params) + households = prepare_household_data( + households, disaster_impacts, params, random_seed + ) + + # ------- 2: If compound events/multiple events update disaster impacts ------ # + disaster_impacts = calculate_compound_impact( + params["disaster_spec"], disaster_impacts + ) + years_until_next_event = calculate_years_until_next_event(disaster_impacts, params) + + # ----------------- 3: Simulate disaster in each spatial unit ---------------- # + outcomes = {} + for spatial_unit in params["spatial_units"]: + previous_disaster_type = None + spatial_unit_households = households[ + households["spatial_unit"] == spatial_unit + ].copy() + + # In case of multiple events keep track of cumulative impact + spatial_unit_households["cumulative_asset_impact_ratio"] = 0 + spatial_unit_households["ever_affected"] = False + + # -------------------- 4: Iterate over each disaster event ------------------- # + for event_time, current_impact in disaster_impacts.items(): + spatial_unit_households = simulate_disaster( + spatial_unit_households, + current_impact[current_impact["spatial_unit"] == spatial_unit], + previous_disaster_type, + params, + reconstruction_rates, + random_seed, + ) + + # Store the disaster type for the next event + previous_disaster_type = current_impact[ + current_impact["spatial_unit"] == spatial_unit + ]["disaster_type"].values[0] + + # ----------------------- 5. Apply policy interventions ---------------------- # + # Note that adaptive social protection policies can be applied here + # But retrofitting policies should be applied before the disaster event + + # --------------- 6. Estimate consumption and well-being losses -------------- # + spatial_unit_households = estimate_socioeconomic_impact( + spatial_unit_households, + params, + years_until_next_event[event_time], + current_impact["disaster_type"].values[0], + ( + current_impact["rp"].iloc[0] + if "rp" in current_impact.columns and not current_impact.empty + else None + ), + random_seed, + ) + + # Update cumulative impact + spatial_unit_households[ + "cumulative_asset_impact_ratio" + ] += spatial_unit_households["asset_impact_ratio"] + spatial_unit_households["ever_affected"] |= spatial_unit_households[ + "is_affected" + ] + # Reset affected status for next event + spatial_unit_households["is_affected"] = False + + # ---------------- 7. Calculate outcomes for each spatial unit --------------- # + outcomes[spatial_unit] = np.array( + list( + calculate_metrics( + spatial_unit_households, + params["recovery_params"]["max_years"], + params["analysis_params"], + ).values() + ) + ) + + return outcomes + + +def simulate_disaster( + households: pd.DataFrame, + disaster_impact: Dict[str, Any], + previous_disaster_type: str, + params: Dict[str, Any], + reconstruction_rates: Optional[pd.DataFrame] = None, + random_seed: int = None, +) -> pd.DataFrame: + """Simulate disaster impact and recovery for a single event. + + This function simulates the impact of a disaster on households and estimates subsequent + recovery. It handles different types of disasters and can use either percentage of + population affected or Probable Maximum Loss (PML) to determine the disaster's impact. Args: - params (dict): A dictionary of parameters. For a complete list of parameters, see, e.g., `config/Nigeria.yaml`. + households (pd.DataFrame): DataFrame containing household data. + disaster_impact (Dict[str, Any]): Dictionary containing disaster impact information. + Must include 'disaster_type' and either 'pct_population_affected' or 'pml'. + previous_disaster_type (str): The type of the previous disaster, used to determine + if dwelling vulnerability should be randomized. + params (Dict[str, Any]): Dictionary containing various simulation parameters. + Must include 'dwelling_vulnerability_params', 'disaster_params', 'economic_params', + and 'recovery_params'. + precomputed_rates (Optional[pd.DataFrame], optional): Precomputed reconstruction rates. + If None, rates will be calculated. Defaults to None. + random_seed (int, optional): Seed for random number generation to ensure + reproducibility. Defaults to None. Returns: - dict: A dictionary of outcomes. The key is a district and value is a list of outcomes. - ''' - random_seed = params['random_seed'] + pd.DataFrame: Updated household data after simulating disaster impact and initial recovery. - households, risk_and_damage, conflict = read_data( - params['country'], params['is_conflict']) + Raises: + KeyError: If required keys are missing in the input dictionaries. + ValueError: If neither 'pct_population_affected' nor 'pml' is provided in disaster_impact. - households = randomize( - households, risk_and_damage, params, random_seed) + Note: + - The function modifies the input households DataFrame in-place. + - The function assumes the existence of several helper functions like + calculate_dwelling_vulnerability, randomize_dwelling_vulnerability, etc. + - The disaster impact is distributed either based on percentage of population + affected or PML, depending on which is provided in the disaster_impact dict. + """ + # Extract disaster impact information + disaster_type = disaster_impact["disaster_type"].values[0] - # ! What is this? - welfare = calculate_welfare(households, params['cons_util']) + # Two options are possible for the impact data type: + # 'assets', then we have pml or 'population' then we have pct_population_affected + pml = disaster_impact.get("pml", pd.Series([None])).iloc[0] + pct_population_affected = disaster_impact.get( + "pct_population_affected", pd.Series([None]) + ).iloc[0] - # Store outcomes in a dict, where key is a region and value is a list of outcomes - outcomes = {} + # If the disaster type has changed, randomize the dwelling vulnerability + if previous_disaster_type is None or previous_disaster_type != disaster_type: + params["dwelling_vulnerability_params"]["randomize"] = True + else: + params["dwelling_vulnerability_params"]["randomize"] = False + + # 1: Calculate dwelling vulnerability given the disaster type and randomize if needed + households = households.pipe(calculate_dwelling_vulnerability, disaster_type).pipe( + randomize_dwelling_vulnerability, + params["dwelling_vulnerability_params"], + random_seed, + ) - for region in params['regions']: - region_households = households[households['region'] == region].copy( + # 2.1: If impact data type is population, + # distribute disaster impact based on percentage of population affected + if pct_population_affected is not None: + unaffected, affected = split_households_by_affected_percentage( + households, pct_population_affected ) - total_exposed_stock, expected_loss_fraction, region_pml = get_region_damage( - risk_and_damage, region, params['return_period']) + affected = distribute_disaster_impact( + affected, + params["disaster_params"]["disaster_impact_params"], + params["dwelling_vulnerability_params"], + pml, + pct_population_affected, + random_seed, + ) - region_households = (region_households - .pipe(calculate_exposure, region_pml, params['pov_bias'], params['calc_exposure_params']) - .pipe(identify_affected, region_pml, params['identify_aff_params'], random_seed=random_seed) - .pipe(apply_policy, params['country'], params.get('current_policy', 'none'), params['disaster_type'], random_seed=random_seed) - .pipe(calculate_recovery_rate, params['avg_prod'], params['cons_util'], params['disc_rate'], params['lambda_incr'], params['yrs_to_rec'], params['is_conflict'], conflict) - .pipe(calculate_wellbeing, params['avg_prod'], params['cons_util'], params['disc_rate'], params['inc_exp_growth'], params['yrs_to_rec'], params['add_inc_loss'], params['save_consumption_recovery'], params['is_conflict'])) + households = pd.concat([unaffected, affected]) - if params['save_households']: - save_households( - params['country'], region, region_households, random_seed) + # 2.2: If impact data type is assets, distribute disaster impact based on PML + else: + households = households.pipe( + distribute_disaster_impact, + params["disaster_params"]["disaster_impact_params"], + params["dwelling_vulnerability_params"], + pml, + pct_population_affected, + random_seed, + ).pipe( + determine_affected_households, + pml, + params["disaster_params"]["determine_affected_params"], + random_seed, + ) - outcomes[region] = np.array(list(calculate_outcomes( - region_households, total_exposed_stock, expected_loss_fraction, region_pml, params['yrs_to_rec'], welfare).values())) + # 3: Calculate/reuse precomputed household reconstruction rates + households = calculate_household_reconstruction_rates( + households, + params["economic_params"], + params["recovery_params"], + params["recovery_params"]["use_precomputed_reconstruction_rates"], + reconstruction_rates, + ) - return outcomes + return households diff --git a/unbreakable/modules/disaster.py b/unbreakable/modules/disaster.py deleted file mode 100644 index 9e82915..0000000 --- a/unbreakable/modules/disaster.py +++ /dev/null @@ -1,35 +0,0 @@ -import pandas as pd - - -def get_region_damage(all_damage: pd.DataFrame, region: str, return_period: int) -> tuple[float, float, float]: - ''' - Extracts total exposed stock, loss fraction and PML for a given region and return period. - - Args: - all_damage (pd.DataFrame): DataFrame containing damage data. - region (str): The region to filter the data. - return_period (int): The return period to filter the data. - - Returns: - tuple[float, float]: A tuple containing the total exposed stock, loss fraction and PML. - ''' - - # If the data has `rp` column, use it to filter the data - if 'rp' in all_damage.columns: - filtered_data = all_damage.loc[ - (all_damage['region'] == region) & ( - all_damage['rp'] == return_period), - ['total_exposed_stock', 'loss_fraction', 'pml'] - ] - # If the doesn't have `rp` column use only the `region` column to filter the data - else: - filtered_data = all_damage.loc[ - all_damage['region'] == region, - ['total_exposed_stock', 'loss_fraction', 'pml'] - ] - - if filtered_data.empty: - raise ValueError( - "No data found for the specified region and/or return period.") - - return tuple(filtered_data.values[0]) diff --git a/unbreakable/modules/disaster_impact.py b/unbreakable/modules/disaster_impact.py new file mode 100644 index 0000000..a750c07 --- /dev/null +++ b/unbreakable/modules/disaster_impact.py @@ -0,0 +1,339 @@ +import pandas as pd +import numpy as np +from collections import defaultdict +from typing import Dict, Union, Tuple + + +def split_households_by_affected_percentage( + households: pd.DataFrame, affected_percentage: float +) -> Tuple[pd.DataFrame, pd.DataFrame]: + """ + Split the households DataFrame into affected and unaffected based on the given percentage. + + Args: + households (pd.DataFrame): Original households DataFrame. + affected_percentage (float): Percentage of population affected (0 to 1). + + Returns: + Tuple[pd.DataFrame, pd.DataFrame]: Unaffected households, Affected households + """ + + # Calculate the new weights + households["unaffected_weight"] = households["household_weight"] * ( + 1 - affected_percentage + ) + households["affected_weight"] = households["household_weight"] * affected_percentage + + # Create the unaffected DataFrame + unaffected = households.copy() + unaffected["household_weight"] = unaffected["unaffected_weight"] + + # Create the affected DataFrame + affected = households.copy() + affected["household_weight"] = affected["affected_weight"] + + # Drop the temporary columns + unaffected = unaffected.drop(["unaffected_weight", "affected_weight"], axis=1) + affected = affected.drop(["unaffected_weight", "affected_weight"], axis=1) + + # Add a column to indicate affected status + affected["is_affected"] = True + unaffected["is_affected"] = False + + return unaffected, affected + + +def distribute_disaster_impact( + households: pd.DataFrame, + disaster_impact_params: Dict[str, Union[str, float, int]], + dwelling_vulnerability_params: Dict[str, Union[float, int]], + pml: float = None, + pct_population_affected: float = None, + random_seed: int = None, +) -> pd.DataFrame: + """ + Distribute disaster impact among households based on either PML or affected percentage. + + Args: + households (pd.DataFrame): DataFrame containing household data. + disaster_impact_params (Dict[str, Union[str, float, int]]): Parameters for disaster impact. + dwelling_vulnerability_params (Dict[str, Union[float, int]]): Parameters for dwelling vulnerability. + pml (float, optional): Probable Maximum Loss. Defaults to None. + pct_population_affected (float, optional): Percentage of affected population. Defaults to None. + random_seed (int, optional): Random seed for reproducibility. Defaults to None. + Returns: + pd.DataFrame: Updated households DataFrame with distributed impact. + + Raises: + ValueError: If neither PML nor pct_population_affected is provided, or if an unsupported distribution is specified. + """ + if pml is None and pct_population_affected is None: + raise ValueError("Either PML or pct_population_affected must be provided.") + + np.random.seed(random_seed) + + if pct_population_affected is not None: + # Define how vulnerability can change + # Decrease by 0-80% + min_change = 0.2 + max_change = 1.0 + + households["vulnerability_change_factor"] = np.random.uniform( + min_change, max_change, size=len(households) + ) + + # Save original v + households["v_orig"] = households["v"].copy() + + # Disaster increases vulnerability + households["v"] *= households["vulnerability_change_factor"] + + # Ensure that the vulnerability is within the specified thresholds + max_threshold = dwelling_vulnerability_params.get("max_threshold", 0.9) + min_threshold = dwelling_vulnerability_params.get("min_threshold", 0.2) + households["v"] = np.clip(households["v"], min_threshold, max_threshold) + + # No need to calculate asset impact ratio + households["asset_impact_ratio"] = None + + else: + # Use the original approach with PML + poverty_bias_factor = disaster_impact_params.get("poverty_bias_factor", 1.0) + + if poverty_bias_factor == "random": + if disaster_impact_params.get("distribution", "uniform") == "uniform": + min_bias = disaster_impact_params.get("min_bias", 0.5) + max_bias = disaster_impact_params.get("max_bias", 1.5) + poverty_bias_factor = np.random.uniform(min_bias, max_bias) + else: + raise ValueError("Only uniform distribution is supported.") + + households["poverty_bias_factor"] = np.where( + households["is_poor"], poverty_bias_factor, 1.0 + ) + + total_weighted_vulnerability = ( + households[["keff", "v", "poverty_bias_factor", "household_weight"]] + .prod(axis=1) + .sum() + ) + + households["asset_impact_ratio"] = ( + pml / total_weighted_vulnerability + ) * households["poverty_bias_factor"] + + return households + + +def determine_affected_households( + households: pd.DataFrame, + pml: float, + params: Dict[str, Union[float, int]], + random_seed: int, +) -> pd.DataFrame: + """ + Determine which households are affected by a disaster. + + Args: + households (pd.DataFrame): DataFrame containing household data. + pml (float): Probable Maximum Loss. + params (Dict[str, Union[float, int]]): Parameters for determination. + random_seed (int, optional): Random seed for reproducibility. Defaults to None. + + Returns: + pd.DataFrame: Updated households DataFrame with affected status and asset loss. + + Raises: + ValueError: If total asset stock is less than PML or if no suitable mask is found. + """ + np.random.seed(random_seed) + + acceptable_loss_margin = pml * params.get("acceptable_loss_margin ", 0.025) + total_asset_value = (households["keff"] * households["household_weight"]).sum() + + if total_asset_value < pml: + raise ValueError("Total asset stock is less than PML.") + + min_random_threshold = params.get("min_random_threshold", 0) + max_random_threshold = params.get("max_random_threshold", 1) + num_simulations = params.get("num_simulations", 10000) + + impact_simulations = ( + np.random.uniform( + min_random_threshold, + max_random_threshold, + (num_simulations, households.shape[0]), + ) + <= households["asset_impact_ratio"].values + ) + + simulated_losses = ( + impact_simulations + * households[["keff", "v", "household_weight"]].values.prod(axis=1) + ).sum(axis=1) + + valid_simulations = (simulated_losses >= pml - acceptable_loss_margin) & ( + simulated_losses <= pml + acceptable_loss_margin + ) + + if not np.any(valid_simulations): + raise ValueError( + f"Cannot find affected households in {num_simulations} simulations." + ) + + chosen_simulation = impact_simulations[np.argmax(valid_simulations)] + + households["is_affected"] = chosen_simulation + households["asset_loss"] = np.where( + households["is_affected"], + households[["keff", "v", "household_weight"]].prod(axis=1), + 0, + ) + + total_asset_loss = households["asset_loss"].sum() + if not ( + pml - acceptable_loss_margin <= total_asset_loss <= pml + acceptable_loss_margin + ): + raise ValueError( + f"Total asset loss ({total_asset_loss}) is not within the acceptable range." + ) + + return households + + +def calculate_compound_impact(disaster_spec, disaster_impacts): + """ + Calculate the compound impact of multiple disasters. + + Args: + disaster_spec (list): List of dictionaries containing disaster specifications. + disaster_impacts (pd.DataFrame): DataFrame containing disaster risk data. + + Returns: + dict: Dictionary containing compound disaster impact. + """ + # If disaster_spec len is 1 there are no coinciding disasters, return the disaster_risk as is + if len(disaster_spec) == 1: + # Disaster impacts have data on multiple return periods + # Filter the disaster impacts for the return period in disaster_spec + rp = disaster_spec[0].get("return_period") + filtered_impacts = disaster_impacts if rp is None else disaster_impacts[disaster_impacts["rp"] == rp] + return {disaster_spec[0]["event_time"]: filtered_impacts} + + # Group disasters by event_time + event_time_dict = defaultdict(list) + for disaster in disaster_spec: + event_time_dict[disaster["event_time"]].append(disaster) + + # Filter coinciding events + coinciding = { + time: disasters + for time, disasters in event_time_dict.items() + if len(disasters) > 1 + } + + # Filter individual events + individual = { + time: disasters + for time, disasters in event_time_dict.items() + if len(disasters) == 1 + } + + # Iterate over coinciding disasters and calculate compound impact as a sum of PMLs + compound_risk = {} + for time, events in coinciding.items(): + disaster_types = set(event["type"] for event in events) + return_periods = [event["return_period"] for event in events] + compound_type = "+".join(sorted(disaster_types)) + compound_return_period = "+".join(sorted(return_periods)) + + # Filter relevant risks once + relevant_risks = disaster_impacts[ + (disaster_impacts["disaster_type"].isin(disaster_types)) + & (disaster_impacts["rp"].isin(return_periods)) + ] + + # Group by spatial_unit and calculate compound impact + compound_impact = ( + relevant_risks.groupby("spatial_unit") + .agg( + { + "pml": "sum", + "loss_fraction": "sum", + "residential": "first", + "non_residential": "first", + "total_exposed_stock": "first", + } + ) + .reset_index() + ) + + # Ensure that loss_fraction is in [0, 1] + compound_impact["loss_fraction"] = compound_impact["loss_fraction"].clip(0, 1) + + # Ensure that PML is not greater than total exposed stock + compound_impact["pml"] = compound_impact[["pml", "total_exposed_stock"]].min( + axis=1 + ) + + # Name compound disaster + compound_impact["disaster_type"] = compound_type + compound_impact["rp"] = compound_return_period + + # Reorder columns + sorted_columns = [ + "disaster_type", + "spatial_unit", + "residential", + "non_residential", + "total_exposed_stock", + "rp", + "pml", + "loss_fraction", + ] + compound_risk[time] = compound_impact[sorted_columns] + + individual_risk = {} + for time, events in individual.items(): + for event in events: + disaster_type = event["type"] + return_period = event["return_period"] + + current_risk = disaster_impacts[ + (disaster_impacts["disaster_type"] == disaster_type) + & (disaster_impacts["rp"] == return_period) + ].copy() + + individual_risk[time] = current_risk + + # Combine individual and compound risk dicts + combined_risk = {**individual_risk, **compound_risk} + + # Sort combined risk by event time (its keys) + combined_risk = dict(sorted(combined_risk.items())) + + return combined_risk + + +def calculate_years_until_next_event(disaster_impacts, params): + """Calculate the time until the next event.""" + # Initialize a new dictionary to store the time until the next event + time_until_next_event = {} + sorted_times = sorted(disaster_impacts.keys()) + + # If there is only one event, return max_years + if len(disaster_impacts) == 1: + return {sorted_times[0]: params["recovery_params"]["max_years"]} + + # Iterate through the sorted keys and calculate the difference + for i in range(len(sorted_times) - 1): + current_time = sorted_times[i] + next_time = sorted_times[i + 1] + time_until_next_event[current_time] = next_time - current_time + + # Handle the last event, which has no next event + max_years = params["recovery_params"]["max_years"] + time_until_next_event[sorted_times[-1]] = ( + max_years - time_until_next_event[sorted_times[-2]] + ) + return time_until_next_event diff --git a/unbreakable/modules/dwelling_vulnerability.py b/unbreakable/modules/dwelling_vulnerability.py new file mode 100644 index 0000000..ed0700b --- /dev/null +++ b/unbreakable/modules/dwelling_vulnerability.py @@ -0,0 +1,147 @@ +import pandas as pd +from typing import Dict, Literal + +ROOF_SCORES: Dict[str, float] = { + "Concrete": 0.2, + "Finished – Concrete": 0.2, + "Finished – Metal": 0.4, + "Finished – Tile": 0.4, # TODO: Confirm this value + "Tile": 0.5, + "Shingle (asphalt)": 0.5, + "Shingle (other)": 0.5, + "Finished – Asbestos": 0.6, + "Shingle (wood)": 0.6, + "Finished – Wood": 0.6, # TODO: Confirm this value + "Sheet metal (galvanize, galvalume)": 0.65, + "Makeshift/thatched": 0.8, + "Natural – Thatch/palm leaf": 0.8, + "Other": 0.8, +} + +WALL_SCORES: Dict[str, float] = { + "Concrete/Concrete blocks": 0.2, + "Concrete/Concrete Blocks": 0.2, + "Finished – Cement blocks": 0.3, + "Brick/Blocks": 0.35, + "Wood & Concrete": 0.4, + "Finished – Stone with lime/cement": 0.45, + "Finished – GRC/Gypsum/Asbestos": 0.5, + "Wood/Timber": 0.6, + "Finished – Wood planks/shingles": 0.6, # TODO: Confirm this value + "Natural – Other": 0.6, + "Plywood": 0.7, + "Rudimentary – Plywood": 0.7, + "Rudimentary – Other": 0.7, # TODO: Confirm this value + "Rudimentary – Uncovered adobe": 0.75, # TODO: Confirm this value + "Natural – Cane/palm/trunks": 0.75, # TODO: Confirm this value + "Makeshift": 0.8, + "Makeshift": 0.8, + "Other": 0.8, +} + +FLOOR_SCORES: Dict[str, float] = { + "Finished – Cement/red bricks": 0.2, + "Finished – Parquet or polished wood": 0.4, + "Rudimentary – Wood planks": 0.5, + "Natural – Earth/sand": 0.7, + "Other": 0.6, +} + +DISASTER_MULTIPLIERS = { + "hurricane": {"roof": 0.6, "walls": 0.3, "floor": 0.1}, + "earthquake": {"roof": 0.2, "walls": 0.6, "floor": 0.2}, + "flood": {"roof": 0.2, "walls": 0.4, "floor": 0.4}, +} + + +def calculate_dwelling_vulnerability( + households: pd.DataFrame, disaster_type: str +) -> pd.DataFrame: + """ + Calculate dwelling vulnerability based on roof and wall types for a given disaster type. + If floor data is available, it will be included in the calculation. + + Args: + households (pd.DataFrame): Households DataFrame with 'walls' and 'roof' columns. 'floor' column is optional. + disaster_type (str): Type of disaster ('hurricane', 'earthquake', or 'flood'). + + Returns: + pd.DataFrame: DataFrame with added vulnerability columns. + + Raises: + ValueError: If an unsupported disaster type is provided or if there are missing scores for wall or roof types. + """ + # ! ASSUMPTION + # If material type is not found in the scores, it is assumed to be 'Other' + # Note that 'Other' is the most vulnerable material type + + # Calculate vulnerability scores for walls and roofs + households["v_walls"] = ( + households["walls"].map(WALL_SCORES).fillna(WALL_SCORES["Other"]) + ) + households["v_roof"] = ( + households["roof"].map(ROOF_SCORES).fillna(ROOF_SCORES["Other"]) + ) + + # Check if floor data is available + floor_data_available = "floor" in households.columns + + if floor_data_available: + households["v_floor"] = ( + households["floor"].map(FLOOR_SCORES).fillna(FLOOR_SCORES["Other"]) + ) + + # Check for any missing scores + missing_wall_types = households[households["v_walls"].isnull()]["walls"].unique() + missing_roof_types = households[households["v_roof"].isnull()]["roof"].unique() + + missing_types_message = ( + f"Missing scores for wall types: {missing_wall_types} " + f"and roof types: {missing_roof_types}" + ) + + if floor_data_available: + missing_floor_types = households[households["v_floor"].isnull()][ + "floor" + ].unique() + missing_types_message += f" and floor types: {missing_floor_types}" + + if ( + missing_wall_types.size > 0 + or missing_roof_types.size > 0 + or (floor_data_available and missing_floor_types.size > 0) + ): + raise ValueError(missing_types_message) + + # Get multipliers for the given disaster type + try: + if "+" in disaster_type: + disaster_types = disaster_type.split("+") + multipliers = { + key: max( + DISASTER_MULTIPLIERS[disaster_type][key] + for disaster_type in disaster_types + ) + for key in ["walls", "roof", "floor"] + } + else: + multipliers = DISASTER_MULTIPLIERS[disaster_type] + except KeyError: + raise ValueError(f"Disaster type '{disaster_type}' not supported") + + # Calculate initial vulnerability + if floor_data_available: + households["v_init"] = ( + households["v_walls"] * multipliers["walls"] + + households["v_roof"] * multipliers["roof"] + + households["v_floor"] * multipliers["floor"] + ) + else: + # Adjust the calculation if floor data is not available + total_weight = multipliers["walls"] + multipliers["roof"] + households["v_init"] = ( + households["v_walls"] * multipliers["walls"] + + households["v_roof"] * multipliers["roof"] + ) / total_weight + + return households diff --git a/unbreakable/modules/household_recovery.py b/unbreakable/modules/household_recovery.py new file mode 100644 index 0000000..b581dbc --- /dev/null +++ b/unbreakable/modules/household_recovery.py @@ -0,0 +1,217 @@ +import pandas as pd +import numpy as np +from typing import Dict, Optional + + +def calculate_household_reconstruction_rates( + households: pd.DataFrame, + economic_params: Dict[str, float], + recovery_params: Dict[str, float], + use_precomputed_reconstruction_rates: bool = False, + reconstruction_rates: Optional[pd.DataFrame] = None, +) -> pd.DataFrame: + """ + Calculate reconstruction rates for affected households. + + Args: + households (pd.DataFrame): DataFrame containing household data. + economic_params (Dict[str, float]): Economic parameters for reconstruction calculation. + recovery_params (Dict[str, float]): Recovery parameters for reconstruction calculation. + use_precomputed_reconstruction_rates (bool): Whether to use precomputed reconstruction rates. + reconstruction_rates (Optional[pd.DataFrame]): Precomputed reconstruction rates data for 'population' impact data type. + + Returns: + pd.DataFrame: Updated DataFrame with reconstruction rates for affected households. + + Raises: + ValueError: If reconstruction rates are invalid or if precomputed rates are missing for 'population' type. + """ + if use_precomputed_reconstruction_rates: + if reconstruction_rates is None: + raise ValueError( + "Precomputed rates data must be provided for 'population' impact data type." + ) + + households["reconstruction_rate"] = 0.0 + + # Identify affected households + affected_mask = households["is_affected"] + + # NOTE Precomputed rates are calculated for rounded vulnerability values + households.loc[affected_mask, "v_rounded"] = households.loc[ + affected_mask, "v" + ].round(2) + + # Merge precomputed rates only for affected households + affected_households = households.loc[affected_mask].merge( + reconstruction_rates, + left_on="v_rounded", + right_on="v", + how="left", + suffixes=("", "_precomputed"), + ) + + # Check for missing precomputed rates + missing_rates = affected_households["reconstruction_rate_precomputed"].isnull() + if missing_rates.any(): + missing_v = affected_households.loc[missing_rates, "v_rounded"].unique() + raise ValueError( + f"Precomputed reconstruction rates not found for vulnerability values: {missing_v}" + ) + + # Update reconstruction rates for affected households + households.loc[affected_mask, "reconstruction_rate"] = affected_households[ + "reconstruction_rate_precomputed" + ].values + + # Clean up temporary columns + households = households.drop( + ["v_rounded", "v_precomputed", "reconstruction_rate_precomputed"], + axis=1, + errors="ignore", + ) + + return households + + else: + # Original calculation for PML-based approach + affected_mask = households["is_affected"] + households.loc[affected_mask, "reconstruction_rate"] = 0.0 + households.loc[affected_mask, "reconstruction_rate"] = households.loc[ + affected_mask + ].apply( + lambda row: find_optimal_reconstruction_rate( + row["v"], economic_params, recovery_params + ), + axis=1, + ) + + # Validate reconstruction rates + validate_reconstruction_rates( + households.loc[households["is_affected"], "reconstruction_rate"], + recovery_params["max_years"], + ) + + return households + + +def find_optimal_reconstruction_rate( + dwelling_vulnerability: float, + economic_params: Dict[str, float], + recovery_params: Dict[str, float], +) -> float: + """ + Find the optimal reconstruction rate for a household given its dwelling vulnerability. + + Args: + dwelling_vulnerability (float): Dwelling vulnerability score of the household. + economic_params (Dict[str, float]): Economic parameters for reconstruction calculation. + recovery_params (Dict[str, float]): Recovery parameters for reconstruction calculation. + + Returns: + float: Optimal reconstruction rate. + + Notes: + This function uses a numerical optimization approach to find the optimal + reconstruction rate that maximizes utility over time. + """ + max_years = recovery_params["max_years"] + lambda_increment = recovery_params["lambda_increment"] + average_productivity = economic_params["average_productivity"] + consumption_utility = economic_params["consumption_utility"] + discount_rate = economic_params["discount_rate"] + total_weeks = 52 * recovery_params["max_years"] + dt = 1 / 52 + lambda_value = 0 + last_derivative_lambda = 0 + + while True: + derivative_lambda = 0 + for time in np.linspace(0, max_years, total_weeks): + factor = average_productivity + lambda_value + marginal_utility_term = ( + average_productivity + - factor * dwelling_vulnerability * np.exp(-lambda_value * time) + ) ** (-consumption_utility) + time_productivity_adjustment = time * factor - 1 + discount_factor = np.exp(-time * (discount_rate + lambda_value)) + derivative_lambda += ( + marginal_utility_term + * time_productivity_adjustment + * discount_factor + * dt + ) + if ( + (last_derivative_lambda < 0 and derivative_lambda > 0) + or (last_derivative_lambda > 0 and derivative_lambda < 0) + or lambda_value > max_years + ): + return lambda_value + last_derivative_lambda = derivative_lambda + lambda_value += lambda_increment + + +def validate_reconstruction_rates(rates: pd.Series, max_years: int) -> None: + """ + Validate the calculated reconstruction rates. + + Args: + rates (pd.Series): Series of reconstruction rates. + max_years (int): Maximum allowed years for reconstruction. + + Raises: + ValueError: If any reconstruction rate is invalid (0 or equal to max_years). + """ + if rates.eq(max_years).any(): + raise ValueError("Reconstruction rate not found for some households") + if rates.eq(0).any(): + raise ValueError("Reconstruction rate is 0 for some households") + if rates.isna().any(): + raise ValueError("Reconstruction rate is missing for some households") + + +def precompute_reconstruction_rates( + economic_params, recovery_params, dwelling_vulnerabilities +): + """Precompute optimal reconstruction rates for a range of dwelling vulnerabilities. + Args: + economic_params (Dict[str, float]): Economic parameters for reconstruction calculation. + recovery_params (Dict[str, float]): Recovery parameters for reconstruction calculation. + dwelling_vulnerabilities (np.ndarray): Array of dwelling vulnerabilities. + Returns: + None + """ + optimal_rates = [ + find_optimal_reconstruction_rate(v, economic_params, recovery_params) + for v in dwelling_vulnerabilities + ] + optimal_rates_df = pd.DataFrame( + { + "v": dwelling_vulnerabilities, + "reconstruction_rate": optimal_rates, + } + ) + + # Round vulnerabilities to 2 decimal places to ensure 0.01 step + optimal_rates_df["v"] = optimal_rates_df["v"].round(2) + + optimal_rates_df.to_csv( + "../../data/generated/optimal_reconstruction_rates.csv", index=False + ) + + +if __name__ == "__main__": + # NOTE These are dummy parameters for the sake of the example + economic_params = { + "average_productivity": 0.25636, + "consumption_utility": 1.5, + "discount_rate": 0.04, + } + recovery_params = {"max_years": 10, "lambda_increment": 0.01} + + # Generate vulnerabilities with exact 0.01 step + dwelling_vulnerabilities = np.round(np.arange(0.2, 0.91, 0.01), 2) + + precompute_reconstruction_rates( + economic_params, recovery_params, dwelling_vulnerabilities + ) diff --git a/unbreakable/modules/households.py b/unbreakable/modules/households.py deleted file mode 100644 index 1a10b20..0000000 --- a/unbreakable/modules/households.py +++ /dev/null @@ -1,148 +0,0 @@ -import pandas as pd -import numpy as np - - -def calculate_exposure(households: pd.DataFrame, region_pml: float, pov_bias: float, calc_exposure_params: dict) -> pd.DataFrame: - '''Calculate how much each of the households is exposed to the disaster. - - Households can be either equally exposed to the disaster or the exposure can be re-distributed between poor and non-poor households with the use of `poverty_bias`. - - Args: - households (pd.DataFrame): Households. - region_pml (float): Region PML. - pov_bias (float): Poverty bias. - calc_exposure_params (dict): Parameters for calculating exposure. - - Returns: - pd.DataFrame: Households with a new `fa` column representing the impact of the disaster. - - Raises: - ValueError: If only uniform distribution is supported yet. - ''' - - # Random value for poverty bias - if pov_bias == 'random': - if calc_exposure_params['distr'] == 'uniform': - # default 0.5 - low = calc_exposure_params['low'] - # default 1.5 - high = calc_exposure_params['high'] - poverty_bias = np.random.uniform(low, high) - else: - raise ValueError("Only uniform distribution is supported yet.") - else: - poverty_bias = pov_bias - - # Set poverty bias to 1 for all households - households['pov_bias'] = 1 - - # Set poverty bias to povbias for poor households - households.loc[households['is_poor'] == True, 'pov_bias'] = poverty_bias - - # Keff is the effective capital stock of the household - # Physical assets such as land, housing, and durable goods - # NOTE: Currently, only the dwelling value k_house is considered - households['keff'] = households['k_house'].copy() - - # How much each household is affected by the disaster - normalization_factor = households[['keff', 'v', 'pov_bias', 'wgt']].prod( - axis=1).sum() - - # Distribute the impact of the disaster given region's PML across households - households['fa'] = (region_pml / normalization_factor) * \ - households['pov_bias'] # `Poverty bias` allows to re-distribute impact between poor and non-poor households - - return households - - -def identify_affected(households: pd.DataFrame, region_pml: float, ident_affected_params: dict, random_seed: int) -> pd.DataFrame: - '''Determine affected households. - - We assume that all households have the same chance of being affected, - but based on `fa` value calculated in `calculate_exposure`. - - Args: - households (pd.DataFrame): Households. - district_pml (float): Region PML. - ident_affected_params (dict): Parameters for determining affected households function. - - Returns: - pd.DataFrame: Households with `is_affected` and `asset_loss` columns. - - Raises: - ValueError: If no mask was found. - ''' - # BUG: For whatever reason fixing random seed in the model.py doesn't work here - if random_seed is not None: - np.random.seed(random_seed) - - # Allow for a relatively small error between the total asset loss and the PML - delta = region_pml * ident_affected_params['delta_pct'] # default 0.025 - - # Check if total asset is less than PML - tot_asset_stock = households[['keff', 'wgt']].prod(axis=1).sum() - if tot_asset_stock < region_pml: - raise ValueError( - 'Total asset stock is less than PML.') - - low = ident_affected_params['low'] # default 0 - high = ident_affected_params['high'] # default 1 - - # Generate multiple boolean masks at once - num_masks = ident_affected_params['num_masks'] # default 10,000 - masks = np.random.uniform( - low, high, (num_masks, households.shape[0])) <= households['fa'].values - - # Compute total_asset_loss for each mask - asset_losses = ( - masks * households[['keff', 'v', 'wgt']].values.prod(axis=1)).sum(axis=1) - - # Find the first mask that yields a total_asset_loss within the desired range - mask_index = np.where((asset_losses >= region_pml - delta) & - (asset_losses <= region_pml + delta)) - - # Raise an error if no mask was found - if mask_index is None: - raise ValueError( - f'Cannot find affected households in {num_masks} iterations.') - else: - try: - # Select the first mask that satisfies the condition - mask_index = mask_index[0][0] - except: - print('mask_index: ', mask_index) - - chosen_mask = masks[mask_index] - - # Raise an error if no mask was found - if len(chosen_mask) == 0: - raise ValueError( - f'Cannot find affected households in {num_masks} iterations.') - - # Assign the chosen mask to the 'is_affected' column of the DataFrame - households['is_affected'] = chosen_mask - - # Save the asset loss for each household - households['asset_loss'] = households.loc[households['is_affected'], [ - 'keff', 'v', 'wgt']].prod(axis=1) - households['asset_loss'] = households['asset_loss'].fillna(0) - - # Check whether the total asset loss is within the desired range - tot_asset_loss = households['asset_loss'].sum() - if (tot_asset_loss < region_pml - delta) or (tot_asset_loss > region_pml + delta): - raise ValueError( - f'Total asset loss ({tot_asset_loss}) is not within the desired range.') - - # num_affected = households['is_affected'].sum() - # print(f'Number of affected households: {num_affected}') - # print(households[households['is_affected']].index) - - return households - - -def calculate_welfare(households: pd.DataFrame, consumption_utility: float) -> float: - '''Calculate the welfare of all households in a country based on their expenditures and a given consumption utility.''' - weighted_average_expenditure = np.sum(households['exp'] * households['wgt']) / np.sum( - households['wgt']) - welfare = weighted_average_expenditure ** (-consumption_utility) - return welfare diff --git a/unbreakable/modules/policy.py b/unbreakable/modules/policy.py deleted file mode 100644 index ed4254f..0000000 --- a/unbreakable/modules/policy.py +++ /dev/null @@ -1,331 +0,0 @@ -import pandas as pd -import numpy as np - - -def cash_transfer(households: pd.DataFrame, current_policy: str) -> pd.DataFrame: - ''' - Apply cash transfer to a specific target group. - - This function applies a cash transfer policy to a specific target group of households. The policy is specified in the format "+", where can be "all", "poor", "poor_near_poor1.25", or "poor_near_poor2.0", and is a percentage value indicating the amount to be added to the 'sav' column of the households. - - Args: - households (pd.DataFrame): Households. - Required columns: 'is_affected', 'is_poor', 'exp', 'poverty_line_adjusted', 'keff', 'v', 'sav' - policy (str): Policy to apply. Format: "+". Example: "poor+100". - - Returns: - pd.DataFrame: Households with applied policy. - ''' - try: - target_group, top_up = current_policy.split('+') - top_up = float(top_up) - except ValueError: - raise ValueError( - "policy should be in the format '+'") - - # Get the adjusted poverty line - poverty_line_adjusted = households['poverty_line_adjusted'].iloc[0] - - # Filter affected households - affected_households = households.query('is_affected') - - # Determine beneficiaries based on target group - if target_group == 'all': - beneficiaries = affected_households - - elif target_group == 'poor': - beneficiaries = affected_households.query('is_poor') - - # If there are no poor households, return the original DataFrame - if len(beneficiaries) == 0: - return households - - # TODO: Split into separate policies poor and near_poor - elif target_group in ['poor_near_poor1.25', 'poor_near_poor2.0']: - multiplier = 1.25 if target_group == 'poor_near_poor1.25' else 2.0 - # Define conditions for poor and near poor households - poor_condition = affected_households['is_poor'] == True - near_poor_condition = (~affected_households['is_poor']) & ( - affected_households['exp'] < multiplier * poverty_line_adjusted) - - # Combine conditions to identify beneficiaries - beneficiary_condition = poor_condition | near_poor_condition - - # If there are no beneficiaries, return the original DataFrame - if not beneficiary_condition.any(): - return households - - # Select beneficiaries based on the combined condition - beneficiaries = affected_households.loc[beneficiary_condition] - else: - raise ValueError(f"Unknown target group: {target_group}") - - # Apply top-up - households.loc[beneficiaries.index, 'sav'] += ( - beneficiaries.eval('keff*v') * top_up / 100 - ) - - return households - - -def retrofitting(country: str, households: pd.DataFrame, current_policy: str, disaster_type: str, random_seed: int) -> pd.DataFrame: - ''' - Apply retrofitting to a specific target group. - - This function applies a retrofitting policy to a specific target group of households. The policy is specified in the format "+", where can be "all", "poor_40", and is a percentage value indicating the proportion of houses to be retrofitted. - - Args: - country (str): Country name. - households (pd.DataFrame): Households. - Required columns: 'roof', 'walls', 'is_poor', 'exp' - policy (str): Policy to apply. Format: "+". Example: "poor_40+100". - disaster_type (str): Type of disaster. Example: "hurricane". - random_seed (int): Random seed for reproducibility. - - Returns: - pd.DataFrame: Households with applied policy. - - Raises: - ValueError: If the policy format is incorrect or the households DataFrame does not contain the required columns. - ''' - if random_seed is not None: - # Set random seed for reproducibility - np.random.seed(random_seed) - - try: - target_group, houses_pct = current_policy.split('+') - houses_pct = int(houses_pct) - except ValueError: - raise ValueError( - "my_policy should be in the format '+'") - - # Check whether the households DataFrame contains the required columns - if not {'roof', 'walls', 'is_poor', 'exp'}.issubset(households.columns): - raise ValueError( - "Households DataFrame must contain 'roof', 'walls', 'is_poor', and 'exp' columns") - - # Each country has different retrofitting policies - if country == 'Dominica': - # Define which houses are vulnerable (material vulnerability score > 0.5) - v_roof_types = [ - 'Shingle (wood)', 'Shingle (asphalt)', 'Shingle (other)', 'Other'] - v_walls_types = ['Wood/Timber', 'Plywood', - 'Makeshift', "Other/Don't know", 'Other'] - robust_roof = 'Concrete' - robust_walls = 'Concrete/Concrete blocks' - - # Find the vulnerable houses where both roof and walls are vulnerable - vulnerable_houses = households[households['walls'].isin( - v_walls_types) | households['roof'].isin(v_roof_types)] - - # Select only the ones that own - vulnerable_houses = vulnerable_houses[vulnerable_houses['own_rent'] == 'own'] - - if len(vulnerable_houses) == 0: - return households - - # Save old roof and walls materials - households['roof_old'] = households['roof'] - households['walls_old'] = households['walls'] - - # Apply the policy to a percentage of the vulnerable houses - if houses_pct != 100: - if random_seed is not None: - # ?: Check if fixing the np random seed affects the sampling - vulnerable_houses = vulnerable_houses.sample( - frac=houses_pct/100, random_state=random_seed) - else: - vulnerable_houses = vulnerable_houses.sample( - frac=houses_pct/100) - - # Search for poor households if the target group is not 'all' - if target_group != 'all': - # Get pct of poor households - pct_poor = int(target_group.split('_')[1]) / 100 - - # Find the poor vulnerable houses - poor_houses = vulnerable_houses.query('is_poor') - - # Find pct_poor (e.g., 40%) of the poorest expenditure-wise - poor_houses = poor_houses.nsmallest( - int(len(poor_houses) * pct_poor), 'exp', keep='all') - - if len(poor_houses) == 0: - return households - - # Keep only the poor houses - vulnerable_houses = vulnerable_houses.loc[poor_houses. index] - - # Apply retrofitting to the vulnerable houses - households['retrofitted'] = False - - # Retrofit roofs - # current_roofs = households.loc[vulnerable_houses.index, 'roof'] - # current_walls = households.loc[vulnerable_houses.index, 'walls'] - - households.loc[vulnerable_houses.index, 'roof'] = households.loc[vulnerable_houses.index, 'roof'].apply( - lambda x: robust_roof if x in v_roof_types else x - ) - # Retrofit walls - households.loc[vulnerable_houses.index, 'walls'] = households.loc[vulnerable_houses.index, 'walls'].apply( - lambda x: robust_walls if x in v_walls_types else x - ) - - # retrofitted_roofs = households.loc[vulnerable_houses.index, 'roof'] - # retrofitted_walls = households.loc[vulnerable_houses.index, 'walls'] - - # Print how many roofs and walls were retrofitted - # print( - # f"Retrofitting {len(vulnerable_houses)} houses: {len(vulnerable_houses[retrofitted_roofs != current_roofs])} roofs and {len(vulnerable_houses[retrofitted_walls != current_walls])} walls") - - households.loc[vulnerable_houses.index, 'retrofitted'] = True - - # Calculate the new vulnerability score - households = recalculate_house_vulnerability( - country, households, disaster_type) - - # NOTE: After retrofitting we do not randomize the vulnerability score - return households - - else: - raise ValueError(f"Country '{country}' not yet supported") - - -def recalculate_house_vulnerability(country: str, households: pd.DataFrame, disaster_type: str) -> pd.DataFrame: - '''Recalculate vulnerability of a house based on its new retrofitted roof and walls material. - - Args: - country (str): Country name. - households (pd.DataFrame): Households. - Required columns: 'roof', 'walls' - disaster_type (str): Type of disaster. Example: "hurricane". - - Returns: - pd.DataFrame: Households with recalculated vulnerability scores. - - Raises: - ValueError: If the country is not supported. - ValueError: If the disaster type is not supported. - ''' - # Each country has different roof and wall materials and their respective vulnerability scores - if country == 'Dominica': - # Define vulnerability scores in dictionaries for easy mapping - v_roof_scores = { - 'Concrete': 0.2, - 'Sheet metal (galvanize, galvalume)': 0.4, - 'Shingle (wood)': 0.6, - 'Shingle (asphalt)': 0.6, - 'Shingle (other)': 0.6, - 'Other': 0.75, - } - - v_walls_scores = { - 'Brick/Blocks': 0.2, - 'Concrete/Concrete Blocks': 0.2, - 'Concrete/Concrete blocks': 0.2, - 'Wood & Concrete': 0.4, - 'Wood/Timber': 0.6, - 'Plywood': 0.7, - 'Makeshift': 0.8, - "Other/Don't know": 0.8, - "Other/Don't Know": 0.8, - 'Other': 0.8, - } - - elif country == 'Nigeria': - v_roof_scores = { - 'Finished – Concrete': 0.2, - 'Finished – Asbestos': 0.25, - 'Finished – Metal tile': 0.35, - 'Finished – Tile': 0.5, - 'Other – Specific': 0.75, - 'Rudimentary – Other': 0.75, - 'Other': 0.75, - 'Natural – Thatch/palm leaf': 0.9 - } - - v_walls_scores = { - 'Finished – Cement blocks': 0.2, - 'Finished – Stone with lime/cement': 0.4, - 'Finished – Woven Bamboo': 0.6, - 'Rudimentary – Bamboo with mud': 0.8, - 'Other': 0.8, - } - - else: - raise ValueError(f"Country '{country}' not yet supported") - - # Save current vulnerability score - # current_v = households['v'].copy() - # current_v_roof = households['v_roof'].copy() - # current_v_walls = households['v_walls'].copy() - - # Calculate the vulnerability scores for the roof and walls - households['v_roof'] = households['roof'].map(v_roof_scores) - households['v_walls'] = households['walls'].map(v_walls_scores) - - # Count how many v values changed - # print( - # f'Changed {len(households[households["v_roof"] != current_v_roof])} roofs') - # print( - # f'Changed {len(households[households["v_walls"] != current_v_walls])} walls') - - # Calculate the new vulnerability score - if disaster_type == 'hurricane': - v_roof_multiplier = 0.6 - v_walls_multiplier = 0.4 - elif disaster_type == 'earthquake': - v_roof_multiplier = 0.3 - v_walls_multiplier = 0.7 - elif disaster_type == 'flood': - v_roof_multiplier = 0.2 - v_walls_multiplier = 0.8 - else: - raise ValueError(f"Disaster type '{disaster_type}' not yet supported") - - # NOTE: Since it is for a retrofitting policy, - # we immediately assign the new values to `v` and not `v_init` column - households['v'] = v_roof_multiplier * \ - households['v_roof'] + v_walls_multiplier * households['v_walls'] - - # Assertions to check values are within expected range - assert households[['v_roof', 'v_walls', 'v']].apply( - lambda x: (x >= 0).all() and (x <= 1).all()).all() - assert households['v'].isna().sum() == 0 - - return households - - -def apply_policy(households: pd.DataFrame, country: str, current_policy: str, disaster_type: str, random_seed: int) -> pd.DataFrame: - ''' - Apply a specific policy to a set of households. - - This function applies a specific policy to a set of households, based on their economic status and the impact of external factors. The policy is specified in the format ":", where can be "asp" (cash transfer) or "retrofit" (housing retrofitting), and is a string containing the details of the policy. - - Args: - country (str): Country name. - households (pd.DataFrame): Households. - Required columns: 'is_affected', 'is_poor', 'exp', 'povline_adjusted', 'keff', 'v', 'sav', 'roof', 'walls' - policy (str): Policy to apply. Format: ":". Example: "asp:poor+100". - disaster_type (str): Type of disaster. Example: "hurricane". - random_seed (int): Random seed for reproducibility. - - Returns: - pd.DataFrame: Households with applied policy. - - Raises: - ValueError: If the policy type is unknown. - ''' - # Identify the type of policy provided - policy_type = current_policy.split(':')[0] - - # Apply the policy based on its type - if policy_type == 'asp': - return cash_transfer(households, current_policy.split(':')[1]) - elif policy_type == 'retrofit': - return retrofitting(country, households, current_policy.split(':')[1], disaster_type, random_seed) - elif policy_type == 'none': - return households - else: - raise ValueError( - f"Unknown policy type: {policy_type}, please use 'asp', 'retrofit' or 'none'") diff --git a/unbreakable/data/__init__.py b/unbreakable/modules/policy_interventions.py similarity index 100% rename from unbreakable/data/__init__.py rename to unbreakable/modules/policy_interventions.py diff --git a/unbreakable/modules/recovery.py b/unbreakable/modules/recovery.py deleted file mode 100644 index ae6b5b1..0000000 --- a/unbreakable/modules/recovery.py +++ /dev/null @@ -1,213 +0,0 @@ -import numpy as np -import pandas as pd -import pickle -import os - - -def calculate_recovery_rate(households: pd.DataFrame, average_productivity: float, consumption_utility: float, discount_rate: float, lambda_increment: float, years_to_recover: int, is_conflict: bool, conflict: pd.DataFrame = None) -> pd.DataFrame: - # Assign initial value to recovery_rate - households['recovery_rate'] = 0 - - # Subset households that are affected by the disaster - affected_households = households[households['is_affected'] == True].copy() - - # If there is a conflict, adjust the average productivity - if is_conflict: - region_conflict_intensity = conflict[conflict['region'] - == households['region'].values[0]]['conflict_intensity'].values[0] - - adjusted_average_productivity = {'Very high': 0.225, - 'High': 0.25, - 'Medium': 0.275, - 'Low': 0.3, - 'Very low': 0.325, - 'None': 0.35} - average_productivity = adjusted_average_productivity[region_conflict_intensity] - - # Search for the recovery rate for each affected household - affected_households['recovery_rate'] = affected_households['v'].apply( - lambda x: find_recovery_rate(x, average_productivity, consumption_utility, discount_rate, lambda_increment, years_to_recover)) - - assert (affected_households['recovery_rate'] == years_to_recover).any( - ) == False, 'Recovery rate was not found for one of the households' - assert (affected_households['recovery_rate'] > 1).any( - ) == False, 'Recovery rate is greater than 1 for one of the households' - assert (affected_households['recovery_rate'] == 0).any( - ) == False, 'Recovery rate is 0 for one of the households' - - households.loc[affected_households.index, - 'recovery_rate'] = affected_households['recovery_rate'] - - return households - - -def find_recovery_rate(v: float, average_productivity: float, consumption_utility: float, discount_rate: float, lambda_increment: float, years_to_recover: int) -> float: - totaL_weeks = 52 * years_to_recover - dt = 1 / 52 - - lambda_value = 0 - last_derivative_lambda = 0 - - while True: - derivative_lambda = 0 - for time in np.linspace(0, years_to_recover, totaL_weeks): - factor = average_productivity + lambda_value - part1 = (average_productivity - factor * v * - np.exp(-lambda_value * time)) ** (-consumption_utility) - part2 = time * factor - 1 - part3 = np.exp(-time * (discount_rate + lambda_value)) - derivative_lambda += part1 * part2 * part3 * dt - - if (last_derivative_lambda < 0 and derivative_lambda > 0) or (last_derivative_lambda > 0 and derivative_lambda < 0) or lambda_value > years_to_recover: - return lambda_value - - last_derivative_lambda = derivative_lambda - lambda_value += lambda_increment - - -def calculate_wellbeing(households: pd.DataFrame, average_productivity: float, consumption_utility: float, discount_rate: float, income_and_expenditure_growth: float, years_to_recover: int, add_income_loss: bool, save_consumption_recovery: bool, is_conflict: bool = False, conflict: pd.DataFrame = None) -> pd.DataFrame: - - # Get the adjusted poverty line for the region - poverty_line_adjusted = households['poverty_line_adjusted'].values[0] - - # Add new columns with initial values - new_columns = ['consumption_loss', 'consumption_loss_npv', 'net_consumption_loss', - 'net_consumption_loss_npv', 'c_t', 'c_t_unaffected', 'weeks_in_poverty', 'wellbeing'] - households[new_columns] = 0 - - # Subset households that are affected by the disaster - affected_households = households[households['is_affected'] == True].copy() - - # Define the number of weeks given the number of years - totaL_weeks = 52 * years_to_recover - dt = 1 / 52 - - consumption_recovery = {} - - if is_conflict: - region_conflict_class = households['conflict_intensity'].values[0] - marco_multiplier = {'Very high': 0.05, - 'High': 0.02997, - 'Medium': 0.0232, - 'Low': 0.01595, - 'Very low': 0.00725, - 'None': 0.0} - vulnerability_increase_factor = 1 + \ - marco_multiplier[region_conflict_class] - else: - vulnerability_increase_factor = 1 - - # Integrate consumption loss and well-being - for time in np.linspace(0, years_to_recover, totaL_weeks): - exponential_multiplier = np.e**( - -affected_households['recovery_rate'] * time) - - growth_factor = (1 + income_and_expenditure_growth)**time - - expenditure = growth_factor * affected_households['exp'] - - savings = growth_factor * \ - affected_households['sav'] * (1 / vulnerability_increase_factor) - - asset_loss = growth_factor * \ - affected_households['v'] * affected_households['keff'] * \ - affected_households['recovery_rate'] * \ - vulnerability_increase_factor - - income_loss = growth_factor * average_productivity * \ - affected_households['keff'] * \ - affected_households['v'] * vulnerability_increase_factor - - # asset_loss = growth_factor * affected_households['v'] * \ - # (affected_households['exp_house'] + - # affected_households[['keff', 'recovery_rate']].prod(axis=1)) - - if add_income_loss == False: - affected_households['c_t'] = (expenditure + - exponential_multiplier * (savings - asset_loss)) - else: - affected_households['c_t'] = (expenditure + - exponential_multiplier * (savings - asset_loss - income_loss)) - - affected_households['c_t_unaffected'] = expenditure - - # Avoid negative consumption - if (affected_households['c_t'] < 0).any(): - affected_households.loc[affected_households['c_t'] < 0, 'c_t'] = 0 - - # Make sure that consumption does not exceed the unaffected consumption - if (affected_households['c_t'] > affected_households['c_t_unaffected']).any(): - affected_households.loc[affected_households['c_t'] > affected_households['c_t_unaffected'], - 'c_t'] = affected_households.loc[affected_households['c_t'] > affected_households['c_t_unaffected'], 'c_t_unaffected'] - - # Calculate consumption loss - affected_households['consumption_loss'] += dt * \ - (affected_households['c_t_unaffected'] - - affected_households['c_t']) - - affected_households['consumption_loss_npv'] += dt * \ - (affected_households['c_t_unaffected'] - - affected_households['c_t'])*np.e**(-discount_rate*time) - - # BUG: That's wrong, if exp_house = 0 then then net_consumption_loss is 0 - affected_households['net_consumption_loss'] += dt * \ - np.e**(-affected_households['recovery_rate']*time) * \ - affected_households['v'] * growth_factor * \ - affected_households['exp_house'] - - # BUG: That's wrong, if exp_house = 0 then then net_consumption_loss_npv is 0 - affected_households['net_consumption_loss_npv'] += dt * \ - np.e**(-affected_households['recovery_rate']*time) * affected_households['v'] * growth_factor * \ - affected_households['exp_house'] * \ - np.e**(-discount_rate*time) - - # Increase the number of weeks in poverty - affected_households.loc[affected_households['c_t'] - < poverty_line_adjusted, 'weeks_in_poverty'] += 1 - - # Calculate wellbeing - affected_households['wellbeing'] += affected_households['c_t_unaffected']**(1 - consumption_utility)\ - / (1 - consumption_utility) * dt \ - * ((1 - ((affected_households['c_t_unaffected'] - affected_households['c_t']) / affected_households['c_t_unaffected']) - * np.e**(-affected_households['recovery_rate'] * time))**(1 - consumption_utility) - 1)\ - * np.e**(-discount_rate * time) - - # Store the consumption recovery for each time step - if save_consumption_recovery: - consumption_recovery[time] = affected_households.loc[:, [ - 'wgt', 'is_poor', 'recovery_rate', 'c_t_unaffected', 'c_t']].set_index('wgt') - - # Save the content of the columns for affected_households into households data frame - households.loc[affected_households.index, - new_columns] = affected_households[new_columns] - - # Save consumption recovery as a pickle file - if save_consumption_recovery: - country = households['country'].values[0] - region = households['region'].values[0] - return_period = households['return_period'].values[0] - try: - random_seed = households['random_seed'].values[0] - except: - random_seed = None - - save_consumption_recovery_to_file(consumption_recovery, - country, region, return_period, is_conflict, random_seed) - - return households - - -def save_consumption_recovery_to_file(consumption_recovery: dict, country: str, region: str, return_period: str, is_conflict: bool, random_seed: int): - if is_conflict: - folder = f'../experiments/{country}/consumption_recovery/return_period={return_period}/conflict={is_conflict}/{random_seed}' - else: - folder = f'../experiments/{country}/consumption_recovery/return_period={return_period}/conflict={is_conflict}/{random_seed}' - - # Create a folder if it does not exist - if not os.path.exists(folder): - os.makedirs(folder) - - # Save consumption recovery as pickle file - with open(folder + f'/{region}.pickle', 'wb') as handle: - pickle.dump(consumption_recovery, handle, - protocol=pickle.HIGHEST_PROTOCOL) diff --git a/unbreakable/modules/socioeconomic_impact.py b/unbreakable/modules/socioeconomic_impact.py new file mode 100644 index 0000000..0d6aa74 --- /dev/null +++ b/unbreakable/modules/socioeconomic_impact.py @@ -0,0 +1,399 @@ +import pandas as pd +import numpy as np +import os +import pickle +from typing import Dict, List + + +def estimate_socioeconomic_impact( + households: pd.DataFrame, + params: dict, + years_until_next_event: int, + disaster_type: str, + return_period: str = None, + random_seed: int = None, +) -> pd.DataFrame: + """ + Estimate the socioeconomic impact of a disaster on households. + + Args: + households (pd.DataFrame): DataFrame containing household data. + params (dict): Dictionary containing economic, disaster impact, and analysis parameters. + years_until_next_event (int): Number of years until the next disaster event. + disaster_type (str): Type of disaster. + return_period (str): Return period of the disaster. + random_seed (int): Random seed used in the simulation. Note that nothing is stochastic in this function. + + Returns: + pd.DataFrame: Updated household data with estimated socioeconomic impact. + """ + # TODO: Review how the socioeconomic impact is estimated in case of consecutive events + + # Extract parameters + economic_params = params["economic_params"] + analysis_params = params["analysis_params"] + disaster_impact_params = params["disaster_params"]["disaster_impact_params"] + + # Set up constants + weeks_in_year = 52 + dt = 1 / weeks_in_year + + # Use this columns to store cumulative losses across multiple events + columns_to_update: List[str] = [ + "consumption_loss", + "consumption_loss_npv", + "net_consumption_loss", + "net_consumption_loss_npv", + "weeks_in_poverty", + "wellbeing_loss", + ] + + # These columns must be reset to zero for each event + columns_to_reset: List[str] = ["c_t", "c_t_unaffected"] + + households = households.copy() + households[columns_to_update] = households.get(columns_to_update, 0.0) + households[columns_to_reset] = 0.0 + + # Filter affected households + affected_households = households[households["is_affected"] == True].copy() + + if affected_households.empty: + return households + + # Dictionary to store consumption recovery data + consumption_recovery = {} + + for t in np.linspace( + 0, years_until_next_event, int(years_until_next_event * weeks_in_year) + ): + update_affected_households( + affected_households, t, economic_params, disaster_impact_params, dt + ) + + if analysis_params["save_consumption_recovery"]: + store_consumption_recovery(consumption_recovery, affected_households, t) + + # Update main dataframe + households.loc[affected_households.index, columns_to_update + columns_to_reset] = ( + affected_households[columns_to_update + columns_to_reset] + ) + + # Save consumption recovery data if required + if analysis_params["save_consumption_recovery"]: + save_consumption_recovery( + consumption_recovery, + params["country"], + households["spatial_unit"].values[0], + disaster_type, + return_period, + random_seed, + ) + + return households + + +def update_affected_households( + affected_households: pd.DataFrame, + t: float, + economic_params: dict, + disaster_impact_params: dict, + dt: float, +): + """ + Update the affected households' data for a given time step. + + Args: + affected_households (pd.DataFrame): DataFrame of affected households. + t (float): Current time step. + economic_params (dict): Dictionary of economic parameters. + disaster_impact_params (dict): Dictionary of disaster impact parameters. + dt (float): Time step size. + """ + exponential_multiplier = np.exp(-affected_households["reconstruction_rate"] * t) + growth_factor = (1 + economic_params["income_and_expenditure_growth"]) ** t + + expenditure = growth_factor * affected_households["exp"] + savings = growth_factor * affected_households["sav"] + asset_loss = ( + growth_factor + * affected_households["v"] + * affected_households["keff"] + * affected_households["reconstruction_rate"] + ) + income_loss = ( + growth_factor + * economic_params["average_productivity"] + * affected_households["keff"] + * affected_households["v"] + ) + + if disaster_impact_params["add_income_loss"]: + affected_households["c_t"] = expenditure + exponential_multiplier * ( + savings - asset_loss - income_loss + ) + else: + affected_households["c_t"] = expenditure + exponential_multiplier * ( + savings - asset_loss + ) + + affected_households["c_t_unaffected"] = expenditure + + # Ensure c_t is at least 1 + # TODO Review this clipping, maybe it should be 0 + affected_households["c_t"] = ( + affected_households[["c_t", "c_t_unaffected"]].min(axis=1).clip(lower=0) + ) + + update_losses(affected_households, t, economic_params, dt) + + +def update_losses( + affected_households: pd.DataFrame, t: float, economic_params: dict, dt: float +): + """ + Update the losses for affected households. + + Args: + affected_households (pd.DataFrame): DataFrame of affected households. + t (float): Current time step. + economic_params (dict): Dictionary of economic parameters. + dt (float): Time step size. + """ + # ! If c_t was larger than c_t_unaffected, + # the consumption_loss will be 0 + # TODO Fix this + + consumption_loss = dt * ( + affected_households["c_t_unaffected"] - affected_households["c_t"] + ) + + consumption_loss_npv = consumption_loss * np.exp( + -economic_params["discount_rate"] * t + ) + + affected_households["consumption_loss"] += consumption_loss + affected_households["consumption_loss_npv"] += consumption_loss_npv + + net_consumption_loss = ( + dt + * np.exp(-affected_households["reconstruction_rate"] * t) + * affected_households["v"] + * (1 + economic_params["income_and_expenditure_growth"]) ** t + * affected_households["rent"] + ) + net_consumption_loss_npv = net_consumption_loss * np.exp( + -economic_params["discount_rate"] * t + ) + + affected_households["net_consumption_loss"] += net_consumption_loss + affected_households["net_consumption_loss_npv"] += net_consumption_loss_npv + + # ! Poverty line is yearly and c_t is weekly + affected_households.loc[ + affected_households["c_t"] < (affected_households["poverty_line"] / 52), + "weeks_in_poverty", + ] += 1 + + update_wellbeing(affected_households, t, economic_params, dt) + + +def update_wellbeing( + affected_households: pd.DataFrame, t: float, economic_params: dict, dt: float +): + """ + Update the wellbeing loss for affected households. + + Args: + affected_households (pd.DataFrame): DataFrame of affected households. + t (float): Current time step. + economic_params (dict): Dictionary of economic parameters. + dt (float): Time step size. + """ + unaffected_utility = ( + affected_households["c_t_unaffected"] + ** (1 - economic_params["consumption_utility"]) + ) / (1 - economic_params["consumption_utility"]) + + adjusted_wellbeing = ( + ( + 1 + - ( + (affected_households["c_t_unaffected"] - affected_households["c_t"]) + / affected_households["c_t_unaffected"] + ) + * np.exp(-affected_households["reconstruction_rate"] * t) + ) + ** (1 - economic_params["consumption_utility"]) + ) - 1 + + wellbeing_loss = ( + unaffected_utility + * dt + * adjusted_wellbeing + * np.exp(-economic_params["discount_rate"] * t) + ) + + # If t = 0, and wellbeing_loss is inf or nan, turn it into 0 + if t == 0: + wellbeing_loss = wellbeing_loss.replace([np.inf, -np.inf], 0).fillna(0) + + affected_households["wellbeing_loss"] += wellbeing_loss + + +def store_consumption_recovery( + consumption_recovery: Dict, affected_households: pd.DataFrame, t: float +): + """ + Store consumption recovery data for a given time step. + + Args: + consumption_recovery (Dict): Dictionary to store consumption recovery data. + affected_households (pd.DataFrame): DataFrame of affected households. + t (float): Current time step. + """ + consumption_recovery[t] = affected_households[ + [ + "household_id", + "household_weight", + "is_poor", + "reconstruction_rate", + "c_t_unaffected", + "c_t", + ] + ].set_index("household_id") + + +def save_consumption_recovery( + consumption_recovery: Dict, + country: str, + spatial_unit: str, + disaster_type: str, + return_period: int = None, + random_seed: int = None, +): + """ + Save consumption recovery to a file. + + Args: + consumption_recovery (Dict): Dictionary containing consumption recovery data. + country (str): Country name. + spatial_unit (str): Spatial unit identifier. + disaster_type (str): Type of disaster. + return_period (int): Return period of the disaster. + random_seed (int): Random seed used in the simulation. + """ + folder = f"../results/{country}/consumption_recovery/" + os.makedirs(folder, exist_ok=True) + + with open( + f"{folder}/{spatial_unit}_{disaster_type}_rp={return_period}_{random_seed}.pickle", + "wb", + ) as handle: + pickle.dump(consumption_recovery, handle, protocol=pickle.HIGHEST_PROTOCOL) + + +# def update_wellbeing( +# affected_households: pd.DataFrame, t: float, economic_params: dict, dt: float +# ): +# """ +# Update the wellbeing loss for affected households with added diagnostic checks. + +# Args: +# affected_households (pd.DataFrame): DataFrame of affected households. +# t (float): Current time step. +# economic_params (dict): Dictionary of economic parameters. +# dt (float): Time step size. +# """ +# # Check 1: Print input parameters +# print(f"Time step: {t}, dt: {dt}") +# print(f"Economic params: {economic_params}") + +# # Check 2: Verify c_t_unaffected is positive +# if (affected_households["c_t_unaffected"] <= 0).any(): +# print("Warning: c_t_unaffected contains non-positive values") +# print(affected_households[affected_households["c_t_unaffected"] <= 0]) + +# unaffected_utility = ( +# affected_households["c_t_unaffected"] +# ** (1 - economic_params["consumption_utility"]) +# ) / (1 - economic_params["consumption_utility"]) + +# # Check 3: Verify unaffected_utility calculation +# if np.isinf(unaffected_utility).any() or np.isnan(unaffected_utility).any(): +# print("Warning: unaffected_utility contains inf or nan values") +# print( +# affected_households[ +# np.isinf(unaffected_utility) | np.isnan(unaffected_utility) +# ] +# ) + +# relative_consumption_change = ( +# affected_households["c_t_unaffected"] - affected_households["c_t"] +# ) / affected_households["c_t_unaffected"] + +# # Check 4: Verify relative consumption change +# if (relative_consumption_change >= 1).any() or ( +# relative_consumption_change < 0 +# ).any(): +# print("Warning: relative consumption change is >= 1 or < 0") +# print( +# affected_households[ +# (relative_consumption_change >= 1) | (relative_consumption_change < 0) +# ] +# ) + +# reconstruction_term = np.exp(-affected_households["reconstruction_rate"] * t) + +# # Check 5: Verify reconstruction term +# if np.isinf(reconstruction_term).any() or np.isnan(reconstruction_term).any(): +# print("Warning: reconstruction term contains inf or nan values") +# print( +# affected_households[ +# np.isinf(reconstruction_term) | np.isnan(reconstruction_term) +# ] +# ) + +# adjusted_wellbeing = ( +# (1 - relative_consumption_change * reconstruction_term) +# ** (1 - economic_params["consumption_utility"]) +# ) - 1 + +# # Check 6: Verify adjusted_wellbeing calculation +# if np.isinf(adjusted_wellbeing).any() or np.isnan(adjusted_wellbeing).any(): +# print("Warning: adjusted_wellbeing contains inf or nan values") +# print( +# affected_households[ +# np.isinf(adjusted_wellbeing) | np.isnan(adjusted_wellbeing) +# ] +# ) + +# discount_term = np.exp(-economic_params["discount_rate"] * t) + +# wellbeing_loss = unaffected_utility * dt * adjusted_wellbeing * discount_term + +# # Check 7: Verify final wellbeing_loss calculation +# if np.isinf(wellbeing_loss).any() or np.isnan(wellbeing_loss).any(): +# print("Warning: wellbeing_loss contains inf or nan values") +# print(affected_households[np.isinf(wellbeing_loss) | np.isnan(wellbeing_loss)]) + +# # If t = 0, and wellbeing_loss is inf or nan, turn it into 0 +# if t == 0: +# wellbeing_loss = wellbeing_loss.replace([np.inf, -np.inf], 0).fillna(0) + +# affected_households["wellbeing_loss"] += wellbeing_loss + +# # Check 8: Verify final wellbeing_loss in DataFrame +# if ( +# np.isinf(affected_households["wellbeing_loss"]).any() +# or np.isnan(affected_households["wellbeing_loss"]).any() +# ): +# print("Warning: Final wellbeing_loss contains inf or nan values") +# print( +# affected_households[ +# np.isinf(affected_households["wellbeing_loss"]) +# | np.isnan(affected_households["wellbeing_loss"]) +# ] +# ) + +# return affected_households diff --git a/unbreakable/utils/__init__.py b/unbreakable/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/unbreakable/utils/data_estimator.py b/unbreakable/utils/data_estimator.py new file mode 100644 index 0000000..e1f3422 --- /dev/null +++ b/unbreakable/utils/data_estimator.py @@ -0,0 +1,173 @@ +import pandas as pd +import numpy as np +from typing import Optional + + +def estimate_effective_capital_stock( + households: pd.DataFrame, params: dict +) -> pd.DataFrame: + """ + Estimate effective capital stock for homeowners. + + Args: + households (pd.DataFrame): DataFrame containing household data. + params (dict): Dictionary of parameters for estimation. + + Returns: + pd.DataFrame: DataFrame with estimated capital stock. + + Raises: + ValueError: If 'inc' or 'owns_house' columns are not present in the DataFrame. + """ + if "inc" not in households.columns or "owns_house" not in households.columns: + raise ValueError( + "Both 'inc' and 'owns_house' columns must be present to estimate capital stock." + ) + + households = households.copy() + households.loc[households["owns_house"] == True, "k_house"] = ( + households["inc"] / params["economic_params"]["average_productivity"] + ) + + households.loc[households["owns_house"] == False, "k_house"] = 0 + + # NOTE + # Keff is the effective capital stock of the household + # Physical assets such as land, homes, and durable goods used to generate income + # For now we assume that keff is equal to the dwelling value k_house + households["keff"] = households["k_house"] + + # TODO Estimate effective capital stock for renters in a more realistic way + # Estimate effective capital stock for renters based on savings rate + savings_rate = (households["inc"] - households["exp"]) / households["inc"] + + households.loc[households["owns_house"] == False, "keff"] = ( + households["inc"] + * savings_rate + / params["economic_params"]["average_productivity"] + ) + + return households + + +def estimate_welfare(households: pd.DataFrame, params: dict) -> pd.DataFrame: + """ + Estimate welfare based on consumption utility function. + + Args: + households (pd.DataFrame): DataFrame containing household data. + params (dict): Dictionary of parameters for estimation. + + Returns: + pd.DataFrame: DataFrame with estimated welfare. + + Raises: + ValueError: If 'exp' column is not present in the DataFrame. + """ + if "exp" not in households.columns: + raise ValueError("'exp' column must be present to estimate welfare.") + + households = households.copy() + + # TODO Review the equation since it contradicts with Walsh & Hallegatte (2020) + weighted_average_expenditure = np.sum( + households["exp"] * households["household_weight"] + ) / np.sum(households["household_weight"]) + welfare = weighted_average_expenditure ** ( + -params["economic_params"]["consumption_utility"] + ) + households["welfare"] = welfare + return households + + +def estimate_rent(households: pd.DataFrame, params: dict) -> pd.DataFrame: + """ + Estimate household rent as percentage of income. + + Args: + households (pd.DataFrame): DataFrame containing household data. + params (dict): Dictionary of parameters for estimation. + + Returns: + pd.DataFrame: DataFrame with estimated rent. + + Raises: + ValueError: If 'inc' column is not present in the DataFrame. + """ + if "inc" not in households.columns: + raise ValueError("'inc' column must be present to estimate rent.") + + households = households.copy() + pct_of_income = params.get("pct_of_income", 0.3) + households["rent"] = households["inc"] * pct_of_income + return households + + +def estimate_savings(households: pd.DataFrame, params: dict) -> pd.DataFrame: + """ + Estimate household savings based on income and expenditure. + + Args: + households (pd.DataFrame): DataFrame containing household data. + params (dict): Dictionary of parameters for estimation. + + Returns: + pd.DataFrame: DataFrame with estimated savings. + + Raises: + ValueError: If 'inc' or 'exp' columns are not present in the DataFrame. + """ + if "inc" not in households.columns or "exp" not in households.columns: + raise ValueError( + "Both 'inc' and 'exp' columns must be present to estimate savings." + ) + + households = households.copy() + if params.get("cap_with_max_savings_rate", False): + max_savings_rate = params.get("max_savings_rate", 0.05) + households["sav"] = households["inc"] * max_savings_rate + + else: + households["sav"] = households["inc"] - households["exp"] + return households + + +def estimate_income(households: pd.DataFrame, params: dict) -> pd.DataFrame: + """ + Estimate household incomes based on expenditure and income-to-expenditure ratios. + + Args: + households (pd.DataFrame): DataFrame containing household data. + params (dict): Dictionary of parameters for estimation. + + Returns: + pd.DataFrame: DataFrame with estimated incomes. + + Raises: + ValueError: If no income-to-expenditure ratio is found or provided. + """ + households = households.copy() + + # If we previously inferred region-specific ratios, use them + if "region_inc_exp_ratio" in households.columns: + for region in households["region"].unique(): + mask = households["region"] == region + region_ratio = households.loc[mask, "region_inc_exp_ratio"].iloc[0] + households.loc[mask, "inc"] = households.loc[mask, "exp"] * region_ratio + + # If we manage to infer only country-wise ratio, use it + elif "country_inc_exp_ratio" in households.columns: + country_ratio = households["country_inc_exp_ratio"].iloc[0] + households["inc"] = households["exp"] * country_ratio + + # If we don't have either, then use the ratio provided in config + elif params.get("inc_exp_ratio"): + inc_exp_ratio = params["inc_exp_ratio"] + households["inc"] = households["exp"] * inc_exp_ratio + + else: + raise ValueError( + "No income-to-expenditure ratio found. Please provide region_inc_exp_ratio, country_inc_exp_ratio, or inc_exp_ratio in params." + ) + + return households diff --git a/unbreakable/utils/data_generator.py b/unbreakable/utils/data_generator.py new file mode 100644 index 0000000..05c0d67 --- /dev/null +++ b/unbreakable/utils/data_generator.py @@ -0,0 +1,260 @@ +import numpy as np +import pandas as pd +from typing import Dict, Literal + +# TODO: Generate example population impact data + +ROOF_SCORES: Dict[str, float] = { + "Concrete": 0.2, + "Finished – Concrete": 0.2, + "Finished – Metal": 0.4, + "Tile": 0.5, + "Shingle (asphalt)": 0.5, + "Shingle (other)": 0.5, + "Finished – Asbestos": 0.6, + "Shingle (wood)": 0.6, + "Sheet metal (galvanize, galvalume)": 0.65, + "Makeshift/thatched": 0.8, + "Natural – Thatch/palm leaf": 0.8, + "Other": 0.8, +} + +WALL_SCORES: Dict[str, float] = { + "Concrete/Concrete blocks": 0.2, + "Concrete/Concrete Blocks": 0.2, + "Finished – Cement blocks": 0.3, + "Brick/Blocks": 0.35, + "Wood & Concrete": 0.4, + "Finished – Stone with lime/cement": 0.45, + "Finished – GRC/Gypsum/Asbestos": 0.5, + "Wood/Timber": 0.6, + "Natural – Other": 0.6, + "Plywood": 0.7, + "Rudimentary – Plywood": 0.7, + "Makeshift": 0.8, + "Other": 0.8, +} + +FLOOR_SCORES: Dict[str, float] = { + "Finished – Cement/red bricks": 0.2, + "Finished – Parquet or polished wood": 0.4, + "Rudimentary – Wood planks": 0.5, + "Natural – Earth/sand": 0.7, + "Other": 0.6, +} + + +def generate_households( + num_households: int, num_spatial_units: int, seed: int = 0 +) -> pd.DataFrame: + """ + Generate dummy households with various economic and demographic attributes based on income. + + Args: + num_households (int): Number of households to generate. + num_spatial_units (int): Number of spatial units where households are located. + seed (int): Random seed for reproducibility. + + Returns: + pd.DataFrame: DataFrame containing household data. + """ + np.random.seed(seed) + + # Constants + income_to_expenditure_ratio = 1.2 + housing_expenditure_ratio = 0.3 + effective_capital_stock_factor = 1 / 0.35 + home_ownership_rate = 0.7 + min_savings_rate = 0.05 + + # Generate base income data + income = np.random.normal(2000, 500, num_households) + income = np.clip(income, 1000, 3000) + + # Generate additional columns based on income + female_headed = np.random.rand(num_households) < ( + 0.3 - (income - 1000) / 2000 * 0.2 + ) + urban = np.random.rand(num_households) < ((income - 1000) / 2000 * 0.6 + 0.2) + + # Determine literacy levels based on income + literacy_thresholds = np.percentile(income, [33, 66]) + literacy = np.select( + [ + income <= literacy_thresholds[0], + (income > literacy_thresholds[0]) & (income <= literacy_thresholds[1]), + income > literacy_thresholds[1], + ], + ["Low", "Medium", "High"], + default="Medium", + ) + + owns_home = np.random.rand(num_households) < ( + (income - 1000) / 2000 * 0.5 + home_ownership_rate - 0.25 + ) + + # Assign spatial units + spatial_units = [f"region_{i}" for i in range(num_spatial_units)] + assigned_spatial_units = np.random.choice(spatial_units, num_households) + + data = { + "inc": income, + "owns_home": owns_home, + "keff": income * effective_capital_stock_factor, + "spatial_unit": assigned_spatial_units, + "female_headed": female_headed, + "urban": urban, + "literacy": literacy, + } + + data["roof"] = [select_material(inc, ROOF_SCORES) for inc in income] + data["walls"] = [select_material(inc, WALL_SCORES) for inc in income] + data["floor"] = [select_material(inc, FLOOR_SCORES) for inc in income] + + # Calculate housing expenditure + data["exp_house"] = np.where( + data["owns_home"], 0, income * housing_expenditure_ratio + ) + + # Calculate total expenditure ensuring minimum savings + max_expenditure = income * (1 - min_savings_rate) + data["exp"] = np.minimum( + income / income_to_expenditure_ratio, max_expenditure - data["exp_house"] + ) + + # Calculate savings + data["sav"] = income - data["exp"] - data["exp_house"] + + # Assign each household a unique ID and weight + data["household_id"] = range(1, num_households + 1) + data["household_weight"] = np.random.uniform(1, 100, num_households) + + # Define poverty line and poor status + poverty_line = np.percentile(data["inc"], 20) + data["poverty_line"] = poverty_line + data["is_poor"] = data["inc"] < poverty_line + + # Sort columns + sorted_columns = [ + "spatial_unit", + "household_id", + "household_weight", + "inc", + "exp", + "sav", + "owns_home", + "exp_house", + "keff", + "roof", + "walls", + "floor", + "poverty_line", + "is_poor", + "female_headed", + "urban", + "literacy", + ] + + # Assert conditions + assert ( + data["inc"] >= data["exp"] + data["exp_house"] + ).all(), "Income should be greater than expenditure" + assert (data["sav"] >= 0).all(), "Savings should be positive" + assert (data["exp"] >= 0).all(), "Expenditure should be positive" + assert (data["exp_house"] >= 0).all(), "Housing expenditure should be positive" + + return pd.DataFrame(data)[sorted_columns] + + +def select_material(income: float, material_scores: Dict[str, float]) -> str: + """ + Select a material based on income, favoring lower vulnerability scores for higher incomes. + + Args: + income (float): Household income + material_scores (Dict[str, float]): Dictionary of materials and their vulnerability scores + + Returns: + str: Selected material + """ + materials = list(material_scores.keys()) + scores = np.array(list(material_scores.values())) + + # Invert and normalize scores to use as probabilities + inv_scores = 1 - scores / scores.max() + probabilities = inv_scores / inv_scores.sum() + + # Adjust probabilities based on income + income_factor = min(income / 3000, 1) # Normalize income, cap at 3000 + adjusted_probs = probabilities * (1 + income_factor) + adjusted_probs /= adjusted_probs.sum() + + return np.random.choice(materials, p=adjusted_probs) + + +def generate_disaster_risk(disaster_type: str, num_spatial_units: int): + """Generate dummy disaster data for a given disaster type and number of spatial units.""" + np.random.seed(42) # For reproducibility + + spatial_units = [f"region_{i}" for i in range(num_spatial_units)] + return_periods = [10, 50, 100, 250] # Common return periods + + data = [] + + for rp in return_periods: + rp_factor = rp / 250 # Normalize return period + + for spatial_unit in spatial_units: + residential = np.random.uniform(100_000_000, 250_000_000) + non_residential = np.random.uniform(50_000_000, 100_000_000) + total = residential + non_residential + + # Adjust PML and loss fraction based on disaster type and return period + if disaster_type == "flood": + base_loss = 0.05 + max_loss = 0.3 + elif disaster_type == "hurricane": + base_loss = 0.1 + max_loss = 0.4 + elif disaster_type == "earthquake": + base_loss = 0.15 + max_loss = 0.5 + else: + raise ValueError(f"Invalid disaster type: {disaster_type}") + + # Calculate loss fraction ensuring it increases with return period + loss_fraction = base_loss + (max_loss - base_loss) * rp_factor + # Add some randomness + loss_fraction += np.random.uniform(-0.05, 0.05) + loss_fraction = max( + base_loss, min(max_loss, loss_fraction) + ) # Ensure within bounds + + pml = total * loss_fraction + + data.append( + { + "disaster_type": disaster_type, + "spatial_unit": spatial_unit, + "residential": round(residential, 2), + "non_residential": round(non_residential, 2), + "total_exposed_stock": round(total, 2), + "rp": rp, + "pml": round(pml, 2), + "loss_fraction": round(loss_fraction, 3), + } + ) + + return pd.DataFrame(data) + + +if __name__ == "__main__": + # Generate dummy disaster risk and household survey data + disaster_types = ["flood", "hurricane", "earthquake"] + for disaster in disaster_types: + df = generate_disaster_risk(disaster, num_spatial_units=64) + df.to_csv( + f"../../data/processed/asset_impacts/Example/{disaster}.csv", index=False + ) + households = generate_households(100, num_spatial_units=64) + households.to_csv("../../data/processed/household_survey/Example.csv", index=False) diff --git a/unbreakable/utils/data_loader.py b/unbreakable/utils/data_loader.py new file mode 100644 index 0000000..edce610 --- /dev/null +++ b/unbreakable/utils/data_loader.py @@ -0,0 +1,74 @@ +import pandas as pd +from typing import List +from typing import Dict, Optional, Any + + +def load_data(params) -> tuple[pd.DataFrame, pd.DataFrame]: + """ + Load households and disaster impact data for a given country and disaster specifications. + + Args: + params (Dict[str, Any]): Parameters dictionary containing country, disaster_params, and recovery_params + + Returns: + tuple[pd.DataFrame, pd.DataFrame]: DataFrames of household and disaster impact data. + """ + country = params["country"] + impact_data_type = params["disaster_params"]["impact_data_type"] + disaster_spec = params["disaster_spec"] + + households = pd.read_csv(f"../data/processed/household_survey/{country}.csv") + + unique_disasters = set(disaster["type"] for disaster in disaster_spec) + + impact_data = [] + for disaster in unique_disasters: + if impact_data_type == "assets": + df = pd.read_csv( + f"../data/processed/asset_impacts/{country}/{disaster}.csv" + ) + elif impact_data_type == "population": + df = pd.read_csv( + f"../data/processed/population_impacts/{country}/{disaster}.csv" + ) + else: + raise ValueError( + f"Invalid impact_data_type: {impact_data_type}. Must be 'assets' or 'population'." + ) + impact_data.append(df) + + disaster_impacts = ( + pd.concat(impact_data, ignore_index=True) + if len(impact_data) > 1 + else impact_data[0] + ) + + return households, disaster_impacts + + +def load_reconstruction_rates(params: Dict[str, Any]) -> Optional[pd.DataFrame]: + """ + Load precomputed optimal reconstruction rates from a file. + + Args: + params (Dict[str, Any]): Parameters dictionary containing recovery_params. + + Returns: + Optional[pd.DataFrame]: Dataframe of reconstruction rates if file exists and should be used, None otherwise. + """ + + if not params["recovery_params"]["use_precomputed_reconstruction_rates"]: + return None + + try: + return pd.read_csv( + f"../data/generated/{params['country']}/optimal_reconstruction_rates.csv" + ) + except FileNotFoundError: + raise FileNotFoundError( + f"Reconstruction rates file not found for {params['country']}" + ) + except Exception as e: + raise RuntimeError( + f"Error loading reconstruction rates for {params['country']}: {str(e)}" + ) diff --git a/unbreakable/utils/data_matcher.py b/unbreakable/utils/data_matcher.py new file mode 100644 index 0000000..32633b1 --- /dev/null +++ b/unbreakable/utils/data_matcher.py @@ -0,0 +1,101 @@ +import pandas as pd +import numpy as np + + +def align_household_assets_with_exposure_data( + households: pd.DataFrame, exposure_data: pd.DataFrame, atol: float +) -> pd.DataFrame: + """ + Aligns household assets with exposure data and scales household economic indicators + for each spatial unit. + + This function performs the following steps for each unique spatial unit: + 1. Matches household data with corresponding exposure data. + 2. Aligns the total household assets with the exposed assets from the exposure data. + 3. If there's a mismatch (within the specified tolerance), it scales the household + economic indicators to match the exposure data. + + Args: + households (pd.DataFrame): Household survey data containing asset information + and other economic indicators. + exposure_data (pd.DataFrame): Exposure data containing information about total + exposed assets for each spatial unit. + atol (float): Absolute tolerance used for matching assets. If the difference + between household assets and exposed assets is within this tolerance, + no scaling is performed. + + Returns: + pd.DataFrame: A DataFrame containing the aligned and potentially scaled + household data. If scaling was performed, original values are preserved + in columns with '_orig' suffix. + + Note: + - The function assumes that both 'households' and 'exposure_data' DataFrames + have a 'spatial_unit' column for matching. + - The 'exposure_data' DataFrame should have a 'total_exposed_stock' column + representing the total exposed assets for each spatial unit. + - If scaling is performed, it affects the following columns in the household data: + 'exp', 'inc', 'sav', 'rent', 'k_house', and 'poverty_line'. + """ + aligned_households = [] + for spatial_unit in households["spatial_unit"].unique(): + unit_households = households[households["spatial_unit"] == spatial_unit].copy() + exposed_assets = exposure_data.loc[ + exposure_data["spatial_unit"] == spatial_unit, "total_exposed_stock" + ].iloc[0] + aligned_df = align_assets(unit_households, exposed_assets, atol) + aligned_households.append(aligned_df) + return pd.concat(aligned_households) + + +def align_assets( + households: pd.DataFrame, exposed_assets: float, atol: float +) -> pd.DataFrame: + """ + Align household assets with exposed assets from disaster risk data. + + Args: + households (pd.DataFrame): Household data for a specific spatial unit. + exposed_assets (float): Total exposed assets for the spatial unit. + atol (float): Absolute tolerance for asset matching. + + Returns: + pd.DataFrame: Households with aligned assets and adjusted values. + """ + survey_assets = (households["k_house"] * households["household_weight"]).sum() + + if not np.isclose(exposed_assets, survey_assets, atol=atol): + scaling_factor = exposed_assets / survey_assets + households = scale_household_data(households, scaling_factor) + + survey_assets_aligned = ( + households["k_house"] * households["household_weight"] + ).sum() + + assert round(exposed_assets) == round( + survey_assets_aligned + ), "Asset mismatch after alignment" + + return households + + +def scale_household_data( + households: pd.DataFrame, scaling_factor: float +) -> pd.DataFrame: + """ + Scale household data based on the calculated scaling factor. + + Args: + households (pd.DataFrame): Household data to be scaled. + scaling_factor (float): Factor to scale the data by. + + Returns: + pd.DataFrame: Scaled household data. + """ + households["poverty_line_orig"] = households["poverty_line"].iloc[0] + households["k_house_orig"] = households["k_house"] + + for column in ["exp", "inc", "sav", "rent", "k_house", "poverty_line"]: + households[column] *= scaling_factor + + return households diff --git a/unbreakable/utils/data_randomizer.py b/unbreakable/utils/data_randomizer.py new file mode 100644 index 0000000..15bb60a --- /dev/null +++ b/unbreakable/utils/data_randomizer.py @@ -0,0 +1,198 @@ +import pandas as pd +import numpy as np +from typing import Optional, Literal + + +def randomize_rent( + households: pd.DataFrame, params: dict, random_seed: int +) -> pd.DataFrame: + """ + Randomize household rent based on estimated rent and provided parameters. + + Args: + households (pd.DataFrame): DataFrame containing household data with existing rent. + params (dict): Dictionary of parameters for randomization. + + Returns: + pd.DataFrame: DataFrame with randomized rent. + + Raises: + ValueError: If 'rent' column is not present in the DataFrame. + """ + np.random.seed(random_seed) + if "rent" not in households.columns: + raise ValueError("'rent' column not found. Please estimate rent first.") + + households = households.copy() + delta = params.get("delta", 0.05) + distribution = params.get("distribution", "uniform") + + if distribution == "uniform": + multiplier = 1 + np.random.uniform(-delta, delta, len(households)) + else: + raise ValueError( + f"Distribution '{distribution}' is not supported. Currently, only 'uniform' is available." + ) + + households["rent"] = households["rent"] * multiplier + return households + + +def randomize_savings( + households: pd.DataFrame, params: dict, random_seed: int +) -> pd.DataFrame: + """ + Randomize household savings based on estimated savings and provided parameters. + + Args: + households (pd.DataFrame): DataFrame containing household data with existing savings. + params (dict): Dictionary of parameters for randomization. + random_seed (int): Random seed for reproducibility. + + Returns: + pd.DataFrame: DataFrame with randomized savings. + + Raises: + ValueError: If 'sav' or 'inc' columns are not present in the DataFrame. + """ + if "sav" not in households.columns or "inc" not in households.columns: + raise ValueError( + "Both 'sav' and 'inc' columns must be present to randomize savings." + ) + np.random.seed(random_seed) + + households = households.copy() + saving_rate = households["sav"] / households["inc"] + delta = params.get("delta", 0.1) + distribution = params.get("distribution", "uniform") + + if distribution == "uniform": + multiplier = 1 + np.random.uniform(-delta, delta, len(households)) + else: + raise ValueError( + f"Distribution '{distribution}' is not supported. Currently, only 'uniform' is available." + ) + + households["sav"] = households["inc"] * saving_rate * multiplier + + max_savings_rate = params.get("max_savings_rate", 0.2) + households["sav"] = np.minimum( + households["sav"], households["inc"] * max_savings_rate + ) + + return households + + +def randomize_income( + households: pd.DataFrame, params: dict, random_seed: int +) -> pd.DataFrame: + """ + Randomize household incomes based on estimated incomes and provided parameters. + + Args: + households (pd.DataFrame): DataFrame containing household data with estimated incomes. + params (dict): Dictionary of parameters for randomization. + random_seed (int): Random seed for reproducibility. + + Returns: + pd.DataFrame: DataFrame with randomized incomes. + + Raises: + ValueError: If 'inc' column is not present in the DataFrame. + """ + np.random.seed(random_seed) + if "inc" not in households.columns: + raise ValueError("'inc' column not found. Please estimate incomes first.") + + households = households.copy() + randomized_ratio = randomize_ratio( + households["inc"] / households["exp"], + size=len(households), + distribution=params.get("distribution", "uniform"), + delta=params.get("delta", 0.1), + ) + households["inc"] = households["exp"] * randomized_ratio + return households + + +def randomize_ratio( + base_ratio: pd.Series, size: int, distribution: str = "uniform", delta: float = 0.1 +) -> np.ndarray: + """ + Generate randomized income-to-expenditure ratios. + + This function creates an array of randomized ratios based on a base ratio and specified distribution. + + Args: + base_ratio (pd.Series): The base ratios to randomize. + size (int): Number of ratios to generate. + distribution (str): Type of distribution to use (default: 'uniform'). + delta (float): Range of variation around the base_ratio (default: 0.1). + + Returns: + np.ndarray: Array of randomized ratios. + + Raises: + ValueError: If an unsupported distribution is specified. + """ + if distribution == "uniform": + low = np.maximum(base_ratio - delta, 1.01) # Ensure ratio doesn't go below 1.01 + high = base_ratio + delta + return np.random.uniform(low, high, size) + else: + raise ValueError( + f"Distribution '{distribution}' is not supported. Currently, only 'uniform' is available." + ) + + +def randomize_dwelling_vulnerability( + households: pd.DataFrame, params: dict, random_seed: int +) -> pd.DataFrame: + """ + Randomize dwelling vulnerability. + + Args: + households (pd.DataFrame): Households DataFrame with 'v_init' column (initial vulnerability). + params (dict): Dict of parameters for randomization. + random_seed (int): Random seed for reproducibility. + + Returns: + pd.DataFrame: Households with randomized vulnerability ('v' column added). + + Raises: + ValueError: If the distribution is not supported or if required parameters are missing. + """ + if not params.get("randomize", False): + if "v" not in households.columns: + households["v"] = households["v_init"] + return households + + np.random.seed(random_seed) + + distribution = params.get("distribution", "uniform") + + if distribution != "uniform": + raise ValueError( + f"Distribution '{distribution}' is not supported. Only 'uniform' is currently supported." + ) + + # Extract parameters with default values + low = params.get("low", 0.9) + high = params.get("high", 1.1) + max_threshold = params.get("max_threshold", 0.9) + min_threshold = params.get("min_threshold", 0.2) + + # Validate parameters + if not (0 < min_threshold < max_threshold < 1): + raise ValueError( + f"Invalid 'min_thresh' and 'max_thresh' values: {min_threshold}, {max_threshold}. Must be 0 < min_thresh < max_thresh < 1." + ) + + # Generate random values and calculate new vulnerability + random_factors = np.random.uniform(low, high, households.shape[0]) + households["v"] = households["v_init"] * random_factors + + # Apply thresholds using numpy for efficiency + households["v"] = np.clip(households["v"], min_threshold, max_threshold) + + return households diff --git a/unbreakable/utils/data_resampler.py b/unbreakable/utils/data_resampler.py new file mode 100644 index 0000000..ceccebf --- /dev/null +++ b/unbreakable/utils/data_resampler.py @@ -0,0 +1,74 @@ +import pandas as pd +import numpy as np + + +def resample_households_by_spatial_unit( + households: pd.DataFrame, min_households: int, random_seed: int = None +) -> pd.DataFrame: + """Resample country households to be more representative. + + Args: + households (pd.DataFrame): Households data. + min_households (int): Minimum number of households for representative sample. + random_seed (int, optional): Random seed for reproducibility. Defaults to None. + + Returns: + pd.DataFrame: Resampled households. + """ + households = households.copy() + households["household_id_orig"] = households["household_id"] + households["household_weight_orig"] = households["household_weight"] + + resampled = ( + households.groupby("spatial_unit") + .apply( + lambda x: upsample_spatial_unit_households(x, min_households, random_seed) + ) + .reset_index(drop=True) + ) + + resampled["household_id"] = range(1, len(resampled) + 1) + return resampled + + +def upsample_spatial_unit_households( + households: pd.DataFrame, min_households: int, random_seed: int = None +) -> pd.DataFrame: + """Weighted resampling with adjustment for household representation within a spatial unit. + + Args: + households (pd.DataFrame): Households of a specific spatial unit. + min_households (int): Minimum number of households for representative sample. + random_seed (int, optional): Random seed for reproducibility. Defaults to None. + + Returns: + pd.DataFrame: Resampled households of a specific spatial unit. + + Raises: + ValueError: If total weights after resampling is not equal to initial total weights. + """ + np.random.seed(random_seed) + if len(households) >= min_households: + return households + + initial_total_weights = households["household_weight"].sum() + delta = max(min_households - len(households), 2) # Ensure at least 2 samples + + sample = households.sample(n=delta, replace=True, random_state=random_seed) + duplicated_households = pd.concat([households, sample], ignore_index=True) + + duplication_counts = duplicated_households.groupby("household_id").size() + duplicated_households["household_weight"] /= duplication_counts[ + duplicated_households["household_id"] + ].values + + if not np.isclose( + duplicated_households["household_weight"].sum(), + initial_total_weights, + atol=1e-6, + ): + raise ValueError( + "Total weights after duplication is not equal to the initial total weights" + ) + + return duplicated_households diff --git a/unbreakable/utils/data_validator.py b/unbreakable/utils/data_validator.py new file mode 100644 index 0000000..4587a03 --- /dev/null +++ b/unbreakable/utils/data_validator.py @@ -0,0 +1,97 @@ +import pandas as pd +import numpy as np +from typing import Optional + + +def validate_rent( + rent: pd.Series, income: pd.Series, expenditure: pd.Series +) -> Optional[ValueError]: + """ + Validate the generated rent. + + This function checks if the generated rent values are valid: + - Not NaN + - Positive + - Less than income + - Less than expenditure + + Args: + rent (pd.Series): Series of generated rent values. + income (pd.Series): Series of income values. + expenditure (pd.Series): Series of expenditure values. + + Returns: + None if validation passes. + + Raises: + ValueError: If any validation check fails. + """ + if rent.isna().any(): + raise ValueError("Rent cannot be NaN") + if (rent <= 0).any(): + raise ValueError("Rent must be positive") + if (rent >= income).any(): + raise ValueError("Rent must be less than income") + if (rent >= expenditure).any(): + raise ValueError("Rent must be less than expenditure") + return None + + +def validate_income(income: pd.Series, expenditure: pd.Series) -> Optional[ValueError]: + """ + Validate the generated income. + + This function checks if the generated income values are valid: + - Not NaN + - Positive + - Greater than corresponding expenditure + + Args: + income (pd.Series): Series of generated income values. + expenditure (pd.Series): Series of corresponding expenditure values. + + Returns: + None if validation passes. + + Raises: + ValueError: If any validation check fails. + """ + if income.isna().any(): + raise ValueError("Income cannot be NaN") + if (income <= 0).any(): + raise ValueError("Income must be positive") + if (income <= expenditure).any(): + raise ValueError("Income must be greater than expenditure") + return None + + +def validate_savings( + savings: pd.Series, income: pd.Series, expenditure: pd.Series +) -> Optional[ValueError]: + """ + Validate the generated savings. + + This function checks if the generated savings values are valid: + - Not NaN + - Not negative + - Not greater than income + - Consistent with income - expenditure + + Args: + savings (pd.Series): Series of generated savings values. + income (pd.Series): Series of income values. + expenditure (pd.Series): Series of expenditure values. + + Returns: + None if validation passes. + + Raises: + ValueError: If any validation check fails. + """ + if savings.isna().any(): + raise ValueError("Savings cannot be NaN") + if (savings < 0).any(): + raise ValueError("Savings cannot be negative") + if (savings > income).any(): + raise ValueError("Savings cannot be greater than income") + return None diff --git a/unbreakable/utils/household_data_preprocessor.py b/unbreakable/utils/household_data_preprocessor.py new file mode 100644 index 0000000..cb9451b --- /dev/null +++ b/unbreakable/utils/household_data_preprocessor.py @@ -0,0 +1,177 @@ +import pandas as pd +import numpy as np +from typing import Optional +from unbreakable.utils.data_validator import * +from unbreakable.utils.data_estimator import * +from unbreakable.utils.data_randomizer import * +from unbreakable.utils.data_resampler import * +from unbreakable.utils.data_matcher import * + + +def prepare_household_data( + households: pd.DataFrame, + disaster_impacts: pd.DataFrame, + params: dict, + random_seed: int, +) -> pd.DataFrame: + """ + Prepare household data by updating, estimating and/or randomizing them based on provided parameters. + + Args: + households (pd.DataFrame): DataFrame containing household data. + disaster_impacts (pd.DataFrame): DataFrame containing disaster impacts data. + params (dict): Dictionary of parameters for randomization. + random_seed (int): Random seed for reproducibility. + + Returns: + pd.DataFrame: DataFrame with updated household data. + """ + np.random.seed(random_seed) + households = get_income(households, params["income_params"], random_seed) + households = get_savings(households, params["savings_params"], random_seed) + households = get_rent(households, params["rent_params"], random_seed) + + # Resample households to ensure minimum number of households for representative sample + households = resample_households_by_spatial_unit( + households, params["min_households"], random_seed + ) + + # * This must be done after resampling and before matching + households = estimate_effective_capital_stock(households, params) + + if params["disaster_params"]["impact_data_type"] == "assets": + # There could be a mismatch between the assets in the household data and the exposure data + households = align_household_assets_with_exposure_data( + households, disaster_impacts, params["atol"] + ) + + # Estimate welfare based on consumption utility + households = estimate_welfare(households, params) + + return households + + +def get_rent(households: pd.DataFrame, params: dict, random_seed: int) -> pd.DataFrame: + """ + Estimate and/or randomize household rent based on provided parameters. + + This function serves as a wrapper to call the estimate_rent and randomize_rent + functions based on the provided parameters. + + Args: + households (pd.DataFrame): DataFrame containing household data. + params (dict): Dictionary of parameters for estimation and randomization. + random_seed (int): Random seed for reproducibility. + + Returns: + pd.DataFrame: DataFrame with estimated and/or randomized rent. + + Raises: + ValueError: If invalid combination of estimate and randomize parameters are provided. + """ + estimate = params.get("estimate", False) + randomize = params.get("randomize", False) + + if estimate and not randomize: + households = estimate_rent(households, params) + elif randomize and not estimate: + if "rent" not in households.columns: + raise ValueError( + "'rent' column not found. Cannot randomize without existing rent estimates." + ) + households = randomize_rent(households, params, random_seed) + elif estimate and randomize: + households = estimate_rent(households, params) + households = randomize_rent(households, params, random_seed) + else: + # If neither estimate nor randomize is True, return the original households + return households + + validate_rent(households["rent"], households["inc"], households["exp"]) + return households + + +def get_savings( + households: pd.DataFrame, params: dict, random_seed: int +) -> pd.DataFrame: + """ + Estimate and/or randomize household savings based on provided parameters. + + This function serves as a wrapper to call the estimate_savings and randomize_savings + functions based on the provided parameters. + + Args: + households (pd.DataFrame): DataFrame containing household data. + params (dict): Dictionary of parameters for estimation and randomization. + random_seed (int): Random seed for reproducibility. + + Returns: + pd.DataFrame: DataFrame with estimated and/or randomized savings. + + Raises: + ValueError: If invalid combination of estimate and randomize parameters are provided. + """ + estimate = params.get("estimate", False) + randomize = params.get("randomize", False) + + if estimate and not randomize: + households = estimate_savings(households, params) + elif randomize and not estimate: + if "sav" not in households.columns: + raise ValueError( + "'sav' column not found. Cannot randomize without existing savings estimates." + ) + households = randomize_savings(households, params, random_seed) + elif estimate and randomize: + households = estimate_savings(households, params) + households = randomize_savings(households, params, random_seed) + else: + # If neither estimate nor randomize is True, return the original households + return households + + validate_savings(households["sav"], households["inc"], households["exp"]) + return households + + +def get_income( + households: pd.DataFrame, params: dict, random_seed: int +) -> pd.DataFrame: + """ + Estimate and/or randomize household incomes based on provided parameters. + + This function serves as a wrapper to call the estimate_income and randomize_income + functions based on the provided parameters. + + Args: + households (pd.DataFrame): DataFrame containing household data. + params (dict): Dictionary of parameters for estimation and randomization. + random_seed (int): Random seed for reproducibility. + + Returns: + pd.DataFrame: DataFrame with estimated and/or randomized incomes. + + Raises: + ValueError: If neither estimate nor randomize parameters are provided. + """ + estimate = params.get("estimate", False) + randomize = params.get("randomize", False) + + if estimate and not randomize: + households = estimate_income(households, params) + + elif randomize and not estimate: + if "inc" not in households.columns: + raise ValueError( + "'inc' column not found. Cannot randomize without existing income estimates." + ) + households = randomize_income(households, params, random_seed) + + elif estimate and randomize: + households = estimate_income(households, params) + households = randomize_income(households, params, random_seed) + else: + # If neither estimate nor randomize is True, return the original households + return households + + validate_income(households["inc"], households["exp"]) + return households