From 9e27a3f85e971e759e24a972b0d6578ff8c09198 Mon Sep 17 00:00:00 2001 From: YONG WOOK KIM Date: Wed, 22 May 2024 14:13:59 -0500 Subject: [PATCH] Rename Social Vulnerability to Social Vulnerability Score (#572) * Rename Social Vulnerability to Social Vulnerability Score * readd old files * update requirements * updated copyright * fixed wrong caption * renamded output name * renamded output name in the code * fixed typo in result name * revert back to previous result name * Changed copyright year * modified copyright year --- CHANGELOG.md | 5 + docs/source/modules.rst | 7 + environment.yml | 1 + .../socialvulnerability.py | 158 +---------------- .../socialvulnerabilityscore/__init__.py | 8 + .../socialvulnerabilityscore.py | 163 ++++++++++++++++++ requirements.imports | 1 + requirements.min | 1 + requirements.txt | 1 + setup.py | 1 + .../test_socialvulnerabilityscore.py | 34 ++++ 11 files changed, 230 insertions(+), 150 deletions(-) create mode 100644 pyincore/analyses/socialvulnerabilityscore/__init__.py create mode 100644 pyincore/analyses/socialvulnerabilityscore/socialvulnerabilityscore.py create mode 100644 tests/pyincore/analyses/socialvulnerabilityscore/test_socialvulnerabilityscore.py diff --git a/CHANGELOG.md b/CHANGELOG.md index e8f9fc781..79dd5c0d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - Permission error in clearing cache process [#563](https://github.com/IN-CORE/pyincore/issues/563) +## [Unreleased] + +### Changed +- Rename Social Vulnerability Analysis to Social Vulnerability Index Analysis [#556](https://github.com/IN-CORE/pyincore/issues/556) + ## [1.18.1] - 2024-04-30 ### Changed diff --git a/docs/source/modules.rst b/docs/source/modules.rst index 1d031c821..a6e52691c 100644 --- a/docs/source/modules.rst +++ b/docs/source/modules.rst @@ -306,6 +306,13 @@ analyses/socialvulnerability ============================ .. autoclass:: socialvulnerability.socialvulnerability.SocialVulnerability :members: +.. deprecated:: 1.19.0 + This class will be deprecated soon. Use :class:`socialvulnerabilityscore.SocialVulnerabilityScore` instead. + +analyses/socialvulnerabilityscore +============================ +.. autoclass:: socialvulnerabilityscore.socialvulnerabilityscore.SocialVulnerabilityScore + :members: analyses/tornadoepndamage ========================= diff --git a/environment.yml b/environment.yml index be15b6336..dcacabdc1 100644 --- a/environment.yml +++ b/environment.yml @@ -20,3 +20,4 @@ dependencies: - rtree>=1.1.0 - scipy>=1.11.3 - shapely>=2.0.2 + - deprecated>=1.2.14 diff --git a/pyincore/analyses/socialvulnerability/socialvulnerability.py b/pyincore/analyses/socialvulnerability/socialvulnerability.py index 3c890d416..86d86d05a 100644 --- a/pyincore/analyses/socialvulnerability/socialvulnerability.py +++ b/pyincore/analyses/socialvulnerability/socialvulnerability.py @@ -4,160 +4,18 @@ # terms of the Mozilla Public License v2.0 which accompanies this distribution, # and is available at https://www.mozilla.org/en-US/MPL/2.0/ -import pandas as pd -from pyincore import BaseAnalysis +from deprecated.sphinx import deprecated +from pyincore.analyses.socialvulnerabilityscore import SocialVulnerabilityScore -class SocialVulnerability(BaseAnalysis): - """This analysis computes a social vulnerability score for per associated zone in census data. - - The computation extracts zoning and a social vulnerability score obtained by computing demographic features of - interest against national average values. - - The output of the computation is a dataset CSV format. - - Contributors - | Science: Elaina Sutley, Amin Enderami - | Implementation: Amin Enderami, Santiago Núñez-Corrales, and NCSA IN-CORE Dev Team - - Related publications - - Args: - incore_client (IncoreClient): Service authentication. - - """ +@deprecated(version='1.19.0', reason="This class will be deprecated soon. Use SocialVulnerabilityScore instead.") +class SocialVulnerability(): def __init__(self, incore_client): - super(SocialVulnerability, self).__init__(incore_client) - - def run(self): - """Execute the social vulnerability analysis using known parameters.""" - df_navs = pd.DataFrame(self.get_input_dataset('national_vulnerability_feature_averages').get_csv_reader()) - - df_dem = pd.DataFrame(self.get_input_dataset('social_vulnerability_demographic_factors').get_csv_reader()) - - # Make sure data types match - df_dem["factor_white_nonHispanic"] = df_dem["factor_white_nonHispanic"].astype(float) - df_dem["factor_owner_occupied"] = df_dem["factor_owner_occupied"].astype(float) - df_dem["factor_earning_higher_than_national_poverty_rate"] =\ - df_dem["factor_earning_higher_than_national_poverty_rate"].astype(float) - df_dem["factor_over_25_with_high_school_diploma_or_higher"] =\ - df_dem["factor_over_25_with_high_school_diploma_or_higher"].astype(float) - df_dem["factor_without_disability_age_18_to_65"] =\ - df_dem["factor_without_disability_age_18_to_65"].astype(float) - - self.social_vulnerability_model(df_navs, df_dem) - - def social_vulnerability_model(self, df_navs, df_dem): - """ - - Args: - df_navs (pd.DataFrame): dataframe containing the national average values for vulnerability factors - df_dem (pd.DataFrame): dataframe containing demographic factors required for the vulnerability score - - Returns: - - """ - - # Compute the social vulnerability index - df_sv = self.compute_svs(df_dem, df_navs) - - # Save into a CSV file - result_name = self.get_parameter("result_name") - self.set_result_csv_data("sv_result", df_sv, - name=result_name, - source="dataframe") - - @staticmethod - def compute_svs(df, df_navs): - """ Computation of the social vulnerability score and corresponding zoning + self._delegate = SocialVulnerabilityScore(incore_client) - Args: - df (pd.DataFrame): dataframe for the census geographic unit of interest - df_navs (pd.DataFrame): dataframe containing national average values - - Returns: - pd.DataFrame: Social vulnerability score and corresponding zoning data + def __getattr__(self, name): """ - navs = df_navs['average'].astype(float).array - - df['R1'] = df['factor_white_nonHispanic'] / navs[0] - df['R2'] = df['factor_owner_occupied'] / navs[1] - df['R3'] = df['factor_earning_higher_than_national_poverty_rate'] / navs[2] - df['R4'] = df['factor_over_25_with_high_school_diploma_or_higher'] / navs[3] - df['R5'] = df['factor_without_disability_age_18_to_65'] / navs[4] - df['SVS'] = df.apply(lambda row: (row['R1'] + row['R2'] + row['R3'] + row['R4'] + row['R5']) / 5, axis=1) - - maximum_nav = 1/navs - std = abs(1 - (sum(maximum_nav) / len(maximum_nav))) / 3 - - lb_2 = 1 - 1.5*std - lb_1 = 1 - 0.5*std - ub_1 = 1 + 0.5*std - ub_2 = 1 + 1.5*std - - zones = [] - - for svs in df['SVS'].tolist(): - if svs < lb_2: - new_zone = 'High Vulnerable (zone5)' - elif svs < lb_1: - new_zone = 'Medium to High Vulnerable (zone4)' - elif svs < ub_1: - new_zone = 'Medium Vulnerable (zone3)' - elif svs < ub_2: - new_zone = 'Medium to Low Vulnerable (zone2)' - elif svs > ub_2: - new_zone = 'Low Vulnerable (zone1)' - else: - new_zone = 'No Data' - zones.append(new_zone) - - df['zone'] = zones - df = df.sort_values(by="GEO_ID") - - return df - - def get_spec(self): - """Get specifications of the housing serial recovery model. - - Returns: - obj: A JSON object of specifications of the social vulnerability model. - + Delegate attribute access to the SocialVulnerabilityScore instance. """ - return { - 'name': 'social-vulnerability', - 'description': 'Social vulnerability score model', - 'input_parameters': [ - { - 'id': 'result_name', - 'required': True, - 'description': 'Result CSV dataset name', - 'type': str - }, - ], - 'input_datasets': [ - { - 'id': 'national_vulnerability_feature_averages', - 'required': True, - 'description': 'A csv file with national vulnerability feature averages', - 'type': ['incore:socialVulnerabilityFeatureAverages'] - }, - { - 'id': 'social_vulnerability_demographic_factors', - 'required': True, - 'description': 'A csv file with social vulnerability demographic factors for a given geographic ' - 'type', - 'type': ['incore:socialVulnerabilityDemFactors'] - } - ], - 'output_datasets': [ - { - 'id': 'sv_result', - 'parent_type': 'social_vulnerability_score', - 'description': 'A csv file with zones containing demographic factors' - 'qualified by a social vulnerability score', - 'type': 'incore:socialVulnerabilityScore' - } - ] - } + return getattr(self._delegate, name) diff --git a/pyincore/analyses/socialvulnerabilityscore/__init__.py b/pyincore/analyses/socialvulnerabilityscore/__init__.py new file mode 100644 index 000000000..c4b8e13bb --- /dev/null +++ b/pyincore/analyses/socialvulnerabilityscore/__init__.py @@ -0,0 +1,8 @@ +# Copyright (c) 2021 University of Illinois and others. All rights reserved. +# +# This program and the accompanying materials are made available under the +# terms of the Mozilla Public License v2.0 which accompanies this distribution, +# and is available at https://www.mozilla.org/en-US/MPL/2.0/ + + +from pyincore.analyses.socialvulnerabilityscore.socialvulnerabilityscore import SocialVulnerabilityScore diff --git a/pyincore/analyses/socialvulnerabilityscore/socialvulnerabilityscore.py b/pyincore/analyses/socialvulnerabilityscore/socialvulnerabilityscore.py new file mode 100644 index 000000000..f76e3f7ce --- /dev/null +++ b/pyincore/analyses/socialvulnerabilityscore/socialvulnerabilityscore.py @@ -0,0 +1,163 @@ +# Copyright (c) 2021 University of Illinois and others. All rights reserved. +# +# This program and the accompanying materials are made available under the +# terms of the Mozilla Public License v2.0 which accompanies this distribution, +# and is available at https://www.mozilla.org/en-US/MPL/2.0/ + +import pandas as pd +from pyincore import BaseAnalysis + + +class SocialVulnerabilityScore(BaseAnalysis): + """This analysis computes a social vulnerability score for per associated zone in census data. + + The computation extracts zoning and a social vulnerability score obtained by computing demographic features of + interest against national average values. + + The output of the computation is a dataset CSV format. + + Contributors + | Science: Elaina Sutley, Amin Enderami + | Implementation: Amin Enderami, Santiago Núñez-Corrales, and NCSA IN-CORE Dev Team + + Related publications + + Args: + incore_client (IncoreClient): Service authentication. + + """ + + def __init__(self, incore_client): + super(SocialVulnerabilityScore, self).__init__(incore_client) + + def run(self): + """Execute the social vulnerability score analysis using known parameters.""" + df_navs = pd.DataFrame(self.get_input_dataset('national_vulnerability_feature_averages').get_csv_reader()) + + df_dem = pd.DataFrame(self.get_input_dataset('social_vulnerability_demographic_factors').get_csv_reader()) + + # Make sure data types match + df_dem["factor_white_nonHispanic"] = df_dem["factor_white_nonHispanic"].astype(float) + df_dem["factor_owner_occupied"] = df_dem["factor_owner_occupied"].astype(float) + df_dem["factor_earning_higher_than_national_poverty_rate"] =\ + df_dem["factor_earning_higher_than_national_poverty_rate"].astype(float) + df_dem["factor_over_25_with_high_school_diploma_or_higher"] =\ + df_dem["factor_over_25_with_high_school_diploma_or_higher"].astype(float) + df_dem["factor_without_disability_age_18_to_65"] =\ + df_dem["factor_without_disability_age_18_to_65"].astype(float) + + self.social_vulnerability_score_model(df_navs, df_dem) + + def social_vulnerability_score_model(self, df_navs, df_dem): + """ + + Args: + df_navs (pd.DataFrame): dataframe containing the national average values for vulnerability factors + df_dem (pd.DataFrame): dataframe containing demographic factors required for the vulnerability score + + Returns: + + """ + + # Compute the social vulnerability score index + df_sv = self.compute_svs(df_dem, df_navs) + + # Save into a CSV file + result_name = self.get_parameter("result_name") + self.set_result_csv_data("sv_result", df_sv, + name=result_name, + source="dataframe") + + @staticmethod + def compute_svs(df, df_navs): + """ Computation of the social vulnerability score and corresponding zoning + + Args: + df (pd.DataFrame): dataframe for the census geographic unit of interest + df_navs (pd.DataFrame): dataframe containing national average values + + Returns: + pd.DataFrame: Social vulnerability score and corresponding zoning data + """ + navs = df_navs['average'].astype(float).array + + df['R1'] = df['factor_white_nonHispanic'] / navs[0] + df['R2'] = df['factor_owner_occupied'] / navs[1] + df['R3'] = df['factor_earning_higher_than_national_poverty_rate'] / navs[2] + df['R4'] = df['factor_over_25_with_high_school_diploma_or_higher'] / navs[3] + df['R5'] = df['factor_without_disability_age_18_to_65'] / navs[4] + df['SVS'] = df.apply(lambda row: (row['R1'] + row['R2'] + row['R3'] + row['R4'] + row['R5']) / 5, axis=1) + + maximum_nav = 1/navs + std = abs(1 - (sum(maximum_nav) / len(maximum_nav))) / 3 + + lb_2 = 1 - 1.5*std + lb_1 = 1 - 0.5*std + ub_1 = 1 + 0.5*std + ub_2 = 1 + 1.5*std + + zones = [] + + for svs in df['SVS'].tolist(): + if svs < lb_2: + new_zone = 'High Vulnerable (zone5)' + elif svs < lb_1: + new_zone = 'Medium to High Vulnerable (zone4)' + elif svs < ub_1: + new_zone = 'Medium Vulnerable (zone3)' + elif svs < ub_2: + new_zone = 'Medium to Low Vulnerable (zone2)' + elif svs > ub_2: + new_zone = 'Low Vulnerable (zone1)' + else: + new_zone = 'No Data' + zones.append(new_zone) + + df['zone'] = zones + df = df.sort_values(by="GEO_ID") + + return df + + def get_spec(self): + """Get specifications of the housing serial recovery model. + + Returns: + obj: A JSON object of specifications of the social vulnerability score model. + + """ + return { + 'name': 'social-vulnerability-score', + 'description': 'Social vulnerability score model', + 'input_parameters': [ + { + 'id': 'result_name', + 'required': True, + 'description': 'Result CSV dataset name', + 'type': str + }, + ], + 'input_datasets': [ + { + 'id': 'national_vulnerability_feature_averages', + 'required': True, + 'description': 'A csv file with national vulnerability feature averages', + 'type': ['incore:socialVulnerabilityFeatureAverages'] + }, + { + 'id': 'social_vulnerability_demographic_factors', + 'required': True, + 'description': 'A csv file with social vulnerability score demographic factors for a given geographic ' + 'type', + 'type': ['incore:socialVulnerabilityDemFactors'] + } + ], + 'output_datasets': [ + { + 'id': 'sv_result', + 'parent_type': 'social_vulnerability_score', + 'description': 'A csv file with zones containing demographic factors' + 'qualified by a social vulnerability score', + 'type': 'incore:socialVulnerabilityScore' + } + ] + } diff --git a/requirements.imports b/requirements.imports index 99829a026..bad57f2f9 100644 --- a/requirements.imports +++ b/requirements.imports @@ -15,3 +15,4 @@ shapely pycodestyle pytest python-jose +Deprecated diff --git a/requirements.min b/requirements.min index a5a7e0be9..e6e22d39a 100644 --- a/requirements.min +++ b/requirements.min @@ -16,3 +16,4 @@ requests>=2.31.0 rtree>=1.1.0 scipy>=1.11.3 shapely>=2.0.2 +Deprecated>=1.2.14 diff --git a/requirements.txt b/requirements.txt index 67803f1a7..986a33f58 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,3 +15,4 @@ requests>=2.31.0 rtree>=1.1.0 scipy>=1.11.3 shapely>=2.0.2 +Deprecated>=1.2.14 diff --git a/setup.py b/setup.py index 197f307cd..3ea2d73df 100644 --- a/setup.py +++ b/setup.py @@ -67,6 +67,7 @@ 'rtree>=1.1.0', 'scipy>=1.11.3', 'shapely>=2.0.2', + 'Deprecated>=1.2.14' ], extras_require={ diff --git a/tests/pyincore/analyses/socialvulnerabilityscore/test_socialvulnerabilityscore.py b/tests/pyincore/analyses/socialvulnerabilityscore/test_socialvulnerabilityscore.py new file mode 100644 index 000000000..77a731c8d --- /dev/null +++ b/tests/pyincore/analyses/socialvulnerabilityscore/test_socialvulnerabilityscore.py @@ -0,0 +1,34 @@ +# This program and the accompanying materials are made available under the +# terms of the Mozilla Public License v2.0 which accompanies this distribution, +# and is available at https://www.mozilla.org/en-US/MPL/2.0/ + + +from pyincore import IncoreClient +from pyincore.analyses.socialvulnerabilityscore import SocialVulnerabilityScore +import pyincore.globals as pyglobals + + +def run_with_base_class(): + census_geo_level = "tract" + + # For a full example, datasets should be obtained using the Census API in pyincore_data + national_vulnerability_feature_averages = "6241d9c653302c512d67ef26" + # social_vulnerability_demographic_factors = "6241e58653302c512d67fb38" + social_vulnerability_demographic_factors = "62b4d2f7be53de4a4737e52d" # calculated from censusutil + + client = IncoreClient(pyglobals.INCORE_API_DEV_URL) + social_vulnerability_score = SocialVulnerabilityScore(client) + + social_vulnerability_score.set_parameter("result_name", "social_vulnerabilty_score") + + social_vulnerability_score.load_remote_input_dataset("national_vulnerability_feature_averages", + national_vulnerability_feature_averages) + social_vulnerability_score.load_remote_input_dataset("social_vulnerability_demographic_factors", + social_vulnerability_demographic_factors) + + # Run pipeline damage analysis + result = social_vulnerability_score.run_analysis() + + +if __name__ == "__main__": + run_with_base_class()