landuse / tests /test_app.py
danyoung's picture
Added app
6d95c4c
import unittest
import pandas as pd
import json
import app.app as app
import app.constants as constants
import app.utils as utils
import app.Prescriptor as Prescriptor
class TestUtilFunctions(unittest.TestCase):
def setUp(self):
self.df = pd.read_csv(constants.DATA_FILE_PATH, index_col=constants.INDEX_COLS)
def test_add_nonland(self):
"""
Simple vanilla test case for add_nonland().
"""
data = [0, 0.01, 0.01, 0.2, 0.4, 0.02, 0.03, 0.01, 0.01, 0.05, 0.01, 0.1]
series = pd.Series(dict(zip(constants.LAND_USE_COLS, data)))
full = utils.add_nonland(series)
self.assertAlmostEqual(full["nonland"], 1 - sum(data), delta=constants.SLIDER_PRECISION)
def test_add_nonland_sum_over_one(self):
"""
Makes sure if the columns sum to >1, we get 0 for nonland
"""
data = [1 for _ in range(len(constants.LAND_USE_COLS))]
series = pd.Series(dict(zip(constants.LAND_USE_COLS, data)))
full = utils.add_nonland(series)
self.assertAlmostEqual(full["nonland"], 0, delta=constants.SLIDER_PRECISION)
def test_create_check_options_length(self):
values = ["a", "b", "c"]
options = utils.create_check_options(values)
self.assertEqual(len(options), len(values))
def test_create_check_options_values(self):
"""
Checks if the values in the options are correct
"""
values = ["a", "b", "c"]
options = utils.create_check_options(values)
for i in range(len(options)):
self.assertEqual(options[i]["value"], values[i])
def test_compute_percent_change(self):
"""
Tests compute percent change on standard example.
"""
context_data = [0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.12]
presc_data = [0.10, 0.06, 0.11, 0.05, 0.12, 0.04, 0.13, 0.03, 0.08]
context = pd.Series(dict(zip(constants.LAND_USE_COLS, context_data)))
presc = pd.Series(dict(zip(constants.RECO_COLS, presc_data)))
percent_change = utils.compute_percent_change(context, presc)
self.assertAlmostEqual(percent_change, 0.14, delta=constants.SLIDER_PRECISION)
def test_compute_percent_change_no_change(self):
"""
Tests compute percent change when nothing changes.
"""
context_data = [0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.12]
presc_data = context_data[0:6] + context_data [8:11]
context = pd.Series(dict(zip(constants.LAND_USE_COLS, context_data)))
presc = pd.Series(dict(zip(constants.RECO_COLS, presc_data)))
percent_change = utils.compute_percent_change(context, presc)
self.assertAlmostEqual(percent_change, 0, delta=constants.SLIDER_PRECISION)
def test_compute_percent_change_all_nonreco(self):
"""
Tests compute change when there is only urban/primf/primn.
"""
context_data = [0, 0, 0, 0, 0, 0, 0.33, 0.33, 0, 0, 0, 0.34]
presc_data = context_data[0:6] + context_data [8:11]
context = pd.Series(dict(zip(constants.LAND_USE_COLS, context_data)))
presc = pd.Series(dict(zip(constants.RECO_COLS, presc_data)))
percent_change = utils.compute_percent_change(context, presc)
self.assertEqual(percent_change, 0)
def test_compute_percent_change_not_sum_to_one(self):
"""
Tests compute percent change on a context with some nonland.
"""
context_data = [0.01 for _ in range(len(constants.LAND_USE_COLS))]
presc_data = [0.02, 0.00, 0.02, 0.00, 0.02, 0.00, 0.02, 0.00, 0.01]
context = pd.Series(dict(zip(constants.LAND_USE_COLS, context_data)))
presc = pd.Series(dict(zip(constants.RECO_COLS, presc_data)))
percent_change = utils.compute_percent_change(context, presc)
self.assertAlmostEqual(percent_change, 0.333333, delta=constants.SLIDER_PRECISION)
class TestEncoder(unittest.TestCase):
"""
Since the encoded values are somewhat arbitrary based off what the prescriptor
is trained on, we have to test based off what is in the fields file.
"""
def setUp(self):
self.df = pd.read_csv(constants.DATA_FILE_PATH, index_col=constants.INDEX_COLS)
self.encoder = None
self.fields = None
with open(constants.FIELDS_PATH, "r") as f:
self.fields = json.load(f)
self.encoder = utils.Encoder(self.fields)
def test_easy_case(self):
"""
Tests encoding a simple case.
"""
row = self.df.iloc[[0]]
row = row[constants.CONTEXT_COLUMNS]
pred = self.encoder.encode_as_df(row)
for col in constants.CONTEXT_COLUMNS:
range = self.fields[col]["range"]
# Min-max scale formula
true = (row[col].values[0] - range[0]) / (range[1] - range[0])
self.assertAlmostEqual(pred[col].values[0], true, delta=constants.SLIDER_PRECISION)
def test_non_field_cols(self):
"""
Test that non-field columns are not encoded and excluded from final dataframe.
"""
row = self.df.iloc[[0]]
row = row[constants.CONTEXT_COLUMNS]
row["test"] = 999
enc = self.encoder.encode_as_df(row)
# Make sure we didn't add the test column
self.assertEqual(sorted(list(enc.columns)), sorted(constants.CONTEXT_COLUMNS))
# Make sure we're still encoding
true = (row["primf"].values[0] - self.fields["primf"]["range"][0]) / (self.fields["primf"]["range"][1] - self.fields["primf"]["range"][0])
self.assertAlmostEqual(enc["primf"].values[0], true, delta=constants.SLIDER_PRECISION)
def test_multiple_input(self):
"""
Tests we can pass in a multi-row dataframe and get proper encodings.
This isn't strictly necessary for our current use case, but it's good to test.
"""
rows = self.df.iloc[0:2]
rows = rows[constants.CONTEXT_COLUMNS]
enc = self.encoder.encode_as_df(rows)
for col in constants.CONTEXT_COLUMNS:
minmax = self.fields[col]["range"]
for i in range(len(rows)):
val = rows.iloc[i][col]
true = (val - minmax[0]) / (minmax[1] - minmax[0])
self.assertAlmostEqual(enc.iloc[i][col], true, delta=constants.SLIDER_PRECISION)
class TestPrescriptor(unittest.TestCase):
def setUp(self):
self.df = pd.read_csv(constants.DATA_FILE_PATH, index_col=constants.INDEX_COLS)
pareto_df = pd.read_csv(constants.PARETO_CSV_PATH)
self.prescriptor_id_list = list(pareto_df["id"])
def test_load_all_prescriptors(self):
"""
Checks if all the prescriptors are loadable
"""
for presc_id in self.prescriptor_id_list:
presc = Prescriptor.Prescriptor(presc_id)
self.assertNotEqual(presc, None)
def test_prescribe_shape(self):
"""
Tests if the prescribe function outputs something in the right shape
"""
presc = Prescriptor.Prescriptor(self.prescriptor_id_list[0])
for i in range(1, 10):
sample_context_df = self.df.iloc[0:i][constants.CONTEXT_COLUMNS]
prescription = presc.run_prescriptor(sample_context_df)
self.assertEqual(set(prescription.columns), set(constants.RECO_COLS))
self.assertEqual(len(prescription), i)
def test_scale(self):
"""
Tests if prescriptor properly scales land use back to what it should be.
"""
presc = Prescriptor.Prescriptor(self.prescriptor_id_list[0])
sample_context_df = self.df.iloc[0:100][constants.CONTEXT_COLUMNS]
old_total = sample_context_df[constants.RECO_COLS].sum(axis=1).reset_index(drop=True)
prescription = presc.run_prescriptor(sample_context_df)
new_total = prescription.sum(axis=1)
self.assertEqual(old_total.equals(new_total), True)