Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename Social Vulnerability to Social Vulnerability Score #572

Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).


## [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
Expand Down
7 changes: 7 additions & 0 deletions docs/source/modules.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
=========================
Expand Down
1 change: 1 addition & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ dependencies:
- rtree>=1.1.0
- scipy>=1.11.3
- shapely>=2.0.2
- deprecated>=1.2.14
160 changes: 8 additions & 152 deletions pyincore/analyses/socialvulnerability/socialvulnerability.py
Original file line number Diff line number Diff line change
@@ -1,163 +1,19 @@
# Copyright (c) 2021 University of Illinois and others. All rights reserved.
#
ywkim312 marked this conversation as resolved.
Show resolved Hide resolved
# 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
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)
8 changes: 8 additions & 0 deletions pyincore/analyses/socialvulnerabilityscore/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (c) 2024 University of Illinois and others. All rights reserved.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should match the original copyright year, 2021

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have already updated. Maybe you're using the old one? Can you pull one more time?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh my bad, changed it.

#
# 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
163 changes: 163 additions & 0 deletions pyincore/analyses/socialvulnerabilityscore/socialvulnerabilityscore.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# Copyright (c) 2024 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'
}
]
}
1 change: 1 addition & 0 deletions requirements.imports
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ shapely
pycodestyle
pytest
python-jose
Deprecated
1 change: 1 addition & 0 deletions requirements.min
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ requests>=2.31.0
rtree>=1.1.0
scipy>=1.11.3
shapely>=2.0.2
Deprecated>=1.2.14
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ requests>=2.31.0
rtree>=1.1.0
scipy>=1.11.3
shapely>=2.0.2
Deprecated>=1.2.14
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
'rtree>=1.1.0',
'scipy>=1.11.3',
'shapely>=2.0.2',
'Deprecated>=1.2.14'
],

extras_require={
Expand Down
Loading
Loading