Skip to content

Commit

Permalink
fix basevals and core cge bug
Browse files Browse the repository at this point in the history
  • Loading branch information
Rashmil-1999 committed Oct 30, 2024
2 parents ad44f2f + a51ce64 commit 9f7e9b2
Show file tree
Hide file tree
Showing 15 changed files with 272 additions and 16 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/conda.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
shell: bash -l {0}

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

- name: get release info
id: release_info
Expand All @@ -40,7 +40,7 @@ jobs:
fi
- name: Cache conda
uses: actions/cache@v2
uses: actions/cache@v4
env:
# Increase this value to reset cache if environment.yml has not changed
CACHE_NUMBER: 0
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/doc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:

steps:
# checkout source code
- uses: actions/checkout@v2
- uses: actions/checkout@v4

# calculate some variables that are used later
- name: version information
Expand Down Expand Up @@ -84,4 +84,4 @@ jobs:
username: ${{ secrets.HUB_USERNAME }}
password: ${{ secrets.HUB_PASSWORD }}
tags: "${{ env.TAGS }}"
buildargs: BRANCH,VERSION,BUILDNUMBER,GITSHA1
buildargs: BRANCH,VERSION,BUILDNUMBER,GITSHA1
6 changes: 3 additions & 3 deletions .github/workflows/pypi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

- name: get release info
id: release_info
Expand Down Expand Up @@ -50,7 +50,7 @@ jobs:
pip install -r requirements.txt
- name: Cache pip
uses: actions/cache@v2
uses: actions/cache@v4
with:
# This path is specific to Ubuntu
path: ~/.cache/pip
Expand All @@ -66,7 +66,7 @@ jobs:
- name: Publish distribution to PyPI
if: github.event_name == 'release'
uses: pypa/gh-action-pypi-publish@master
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ env.TOKEN }}
repository_url: ${{ env.REPO_URL }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/pytests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ jobs:
name: Python ${{ matrix.vars.python-version }} Test
steps:
- name: Checkout source code
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Cache conda
uses: actions/cache@v2
uses: actions/cache@v4
env:
# Increase this value to reset cache if environment.yml has not changed
CACHE_NUMBER: 0
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/requirements.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

# check all requirements
- name: requirements check
Expand Down
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,22 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).


## [Unreleased]
## [1.20.0] - 2024-10-24

### Fixed
- Fixed Sphinx autodoc skipping class methods with custom decorators. [#518](https://github.com/IN-CORE/pyincore/issues/518)
- Pyomo version fixed to fix indp solver failure [#585](https://github.com/IN-CORE/pyincore/issues/585)
- Uploaded raster files doesn't respect the order [#614](https://github.com/IN-CORE/pyincore/issues/614)
- Fixed the pypi publish of the package [#621](https://github.com/IN-CORE/pyincore/issues/621)

### Changed
- Support Interdependent recovery of residential buildings and households [#606](https://github.com/IN-CORE/pyincore/pull/606)
- Remove unused insecure IN-CORE client [#581](https://github.com/IN-CORE/pyincore/issues/581)
- Update GH actions to use the latest version [#623](https://github.com/IN-CORE/pyincore/issues/623)

### Added
- Apply Black formatter [#589](https://github.com/IN-CORE/pyincore/issues/589)
- Equity Metric Analysis [#608](https://github.com/IN-CORE/pyincore/issues/608)
- Internal client connecting to the IN-CORE services [#609](https://github.com/IN-CORE/pyincore/issues/609)
- MlEnabledCgeJoplin analysis with documentation [#588](https://github.com/IN-CORE/pyincore/issues/588)

Expand Down
4 changes: 2 additions & 2 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@
author = ""

# The short X.Y version
version = "1.19"
version = "1.20"
# The full version, including alpha/beta/rc tags
release = "1.19.0"
release = "1.20.0"

# -- General configuration ---------------------------------------------------

Expand Down
7 changes: 7 additions & 0 deletions docs/source/modules.rst
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ analyses/epnfunctionality
.. autoclass:: epnfunctionality.epnfunctionality.EpnFunctionalityUtil
:members:

analyses/equitymetric
=========================
.. autoclass:: equitymetric.equitymetric.EquityMetric
:members:
.. autoclass:: equitymetric.equitymetric.EquityMetricUtil
:members:

analyses/example
================
.. autoclass:: example.exampleanalysis.ExampleAnalysis
Expand Down
8 changes: 8 additions & 0 deletions pyincore/analyses/equitymetric/__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.
#
# 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.equitymetric.equitymetric import EquityMetric
from pyincore.analyses.equitymetric.equitymetricutil import EquityMetricUtil
140 changes: 140 additions & 0 deletions pyincore/analyses/equitymetric/equitymetric.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# 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 numpy as np
from pyincore import BaseAnalysis
from pyincore.analyses.equitymetric.equitymetricutil import EquityMetricUtil


class EquityMetric(BaseAnalysis):
"""Computes equity metric.
Args:
incore_client: Service client with authentication info
"""

def __init__(self, incore_client):
super(EquityMetric, self).__init__(incore_client)

def run(self):
"""Execute equity metric analysis"""

division_decision_column = self.get_parameter("division_decision_column")
scarce_resource_df = self.get_input_dataset(
"scarce_resource"
).get_dataframe_from_csv()
hua_df = self.get_input_dataset(
"housing_unit_allocation"
).get_dataframe_from_csv()
if division_decision_column == "SVI" and "SVI" not in hua_df.columns:
hua_df = EquityMetricUtil.prepare_svi_as_division_decision(hua_df)

merged_df = hua_df.merge(
scarce_resource_df, how="inner", left_on="guid", right_on="guid"
)

equity_metric = self.equity_metric(merged_df, division_decision_column)

self.set_result_csv_data(
"equity_metric",
equity_metric,
name=self.get_parameter("result_name") + "_equity_metric",
)

return True

def equity_metric(self, merged_df, division_decision_column):
"""
Compute equity metric
Args:
merged_df: Merging housing unit allocation and scarce resource to create dataframes
division_decision_column: column name of the division decision variable e.g. SVI
Returns:
equity_metric: equity metric values that consist of Theil’s T Value, Between Zone Inequality, Within Zone Inequality
"""
# Calculation of households in each group
total_1 = merged_df[merged_df[division_decision_column] > 0].shape[
0
] # socially vulnerable populations
total_2 = merged_df[merged_df[division_decision_column] < 1].shape[
0
] # non socially vulnerable populations
total_households = (
total_1 + total_2
) # for non-vacant households (i.e., non-vacant are not included)

# Metric Computation
scarce_resource = merged_df["scarce_resource"]
yi = scarce_resource / np.sum(scarce_resource)
Yg_1 = np.sum(yi[merged_df[division_decision_column] > 0])
Yg_2 = np.sum(yi[merged_df[division_decision_column] < 1])
TheilT = np.sum(yi * np.log(yi * total_households))
bzi = np.sum(yi[merged_df[division_decision_column] > 0]) * np.log(
np.average(yi[merged_df[division_decision_column] > 0]) / np.average(yi)
) + np.sum(yi[merged_df[division_decision_column] < 1]) * np.log(
np.average(yi[merged_df[division_decision_column] < 1]) / np.average(yi)
)
wzi = Yg_1 * np.sum(
yi[merged_df[division_decision_column] > 0]
/ Yg_1
* np.log((yi[merged_df[division_decision_column] > 0] / Yg_1 * total_1))
) + Yg_2 * np.sum(
yi[merged_df[division_decision_column] < 1]
/ Yg_2
* np.log((yi[merged_df[division_decision_column] < 1] / Yg_2 * total_2))
)

return [{"Theils T": TheilT, "BZI": bzi, "WZI": wzi}]

def get_spec(self):
"""Get specifications of the Equity Metric analysis.
Returns:
obj: A JSON object of specifications of the Equity Metric analysis.
"""
return {
"name": "equity-metric",
"description": "Equity metric analysis",
"input_parameters": [
{
"id": "result_name",
"required": True,
"description": "result dataset name",
"type": str,
},
{
"id": "division_decision_column",
"required": True,
"description": "Division decision. "
"Binary variable associated with each household used to group it into two groups "
"(e.g. low income vs non low income, minority vs non-minority, "
"social vulnerability)",
"type": str,
},
],
"input_datasets": [
{
"id": "housing_unit_allocation",
"required": True,
"description": "A csv file with the merged dataset of the inputs, aka Probabilistic"
"House Unit Allocation",
"type": ["incore:housingUnitAllocation"],
},
{
"id": "scarce_resource",
"required": True,
"description": "Scarce resource dataset e.g. probability of service, return time, etc",
"type": ["incore:scarceResource"],
},
],
"output_datasets": [
{
"id": "equity_metric",
"description": "CSV file of equity metric, including Theil’s T Value, Between Zone Inequality, Within Zone Inequality",
"type": "incore:equityMetric",
}
],
}
57 changes: 57 additions & 0 deletions pyincore/analyses/equitymetric/equitymetricutil.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# 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


class EquityMetricUtil:
@staticmethod
def prepare_svi_as_division_decision(hua_df):
"""
socially vulnerability as division decision variable which is a binary variable associated with each household
used to group it into two groups
Args:
hua_df:
Returns:
"""
# Add variable to indicate if high socially vulnerability for metric's computation
median_income = hua_df["randincome"].median()

condition1 = hua_df["randincome"] <= median_income
condition2 = hua_df["ownershp"] == 2
condition3 = hua_df["race"] != 1
condition4 = hua_df["hispan"] != 0

hua_df["SVI"] = condition1 & condition2 & condition3 & condition4
hua_df["SVI"] = (hua_df["SVI"]).astype(int)

return hua_df

@staticmethod
def prepare_return_time_as_scarce_resource(return_df):
return_sequence = return_df.iloc[:, 4:94]
# add return time to the scarce resource dataset
time_to_return = EquityMetricUtil._time_to_return(return_sequence)
return_df["Return Time"] = pd.to_numeric(time_to_return)
return_df["scarce_resource"] = 91 - return_df["Return Time"]

return return_df

@staticmethod
def _time_to_return(return_sequence):
# now create a for loop to determine the time for each row
time_to_return = []
for i in range(0, return_sequence.shape[0]):
if max(return_sequence.iloc[i]) == 4:
column_index = (return_sequence == 4).idxmax(axis=1)[i]
else:
# assuming for 5 that it is never recovered, so we set it to max time interval of 90
column_index = 90
time_to_return.append(column_index)

return time_to_return
2 changes: 1 addition & 1 deletion pyincore/globals.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import os
import shutil

PACKAGE_VERSION = "1.19.0"
PACKAGE_VERSION = "1.20.0"

INCORE_API_PROD_URL = "https://incore.ncsa.illinois.edu"
INCORE_API_DEV_URL = "https://incore-dev.ncsa.illinois.edu"
Expand Down
10 changes: 9 additions & 1 deletion pyincore/utils/datasetutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def _apply_retrofit_value(row):
)
else None
)
_ = (
type = (
row["config_mappingEntryKey"]["type"]
if (
"config_mappingEntryKey" in row.index
Expand All @@ -164,6 +164,14 @@ def _apply_retrofit_value(row):

if target_column and expression:
if target_column in row.index:
# Don't delete this line. Retrofit value is calculated based on the expression and will be
# used in the later eval
retrofit_value = ( # noqa: F841
float(row["retrofit_value"])
if type == "number"
else row["retrofit_value"]
)

# Dangerous! Be careful with the expression
row[target_column] = eval(f"row[target_column]{expression}")
else:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from setuptools import setup, find_packages

# version number of pyincore
version = "1.19.0"
version = "1.20.0"

with open("README.rst", encoding="utf-8") as f:
readme = f.read()
Expand Down
Loading

0 comments on commit 9f7e9b2

Please sign in to comment.