Skip to content

Commit

Permalink
style: reformat
Browse files Browse the repository at this point in the history
  • Loading branch information
Clarmy committed Feb 26, 2024
1 parent d1856ac commit 5257b76
Show file tree
Hide file tree
Showing 16 changed files with 111 additions and 109 deletions.
15 changes: 2 additions & 13 deletions cyeva/core/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
calc_threshold_mae,
calc_multiclass_accuracy_ratio,
calc_multiclass_hanssen_kuipers_score,
calc_multiclass_heidke_skill_score
calc_multiclass_heidke_skill_score,
)


Expand All @@ -36,7 +36,6 @@ class Comparison:
def __init__(
self, observation: Union[np.ndarray, list], forecast: Union[np.ndarray, list]
):

if isinstance(observation, Quantity):
observation = observation.magnitude
if isinstance(forecast, Quantity):
Expand Down Expand Up @@ -216,7 +215,6 @@ def calc_multiclass_accuracy_ratio(
*args,
**kwargs
) -> float:

if observation is None:
observation = self.observation
if forecast is None:
Expand All @@ -232,14 +230,13 @@ def calc_multiclass_hanssen_kuipers_score(
*args,
**kwargs
) -> float:

if observation is None:
observation = self.observation
if forecast is None:
forecast = self.forecast

return calc_multiclass_hanssen_kuipers_score(observation, forecast)

@result_round_digit(4)
def calc_multiclass_heidke_skill_score(
self,
Expand All @@ -248,7 +245,6 @@ def calc_multiclass_heidke_skill_score(
*args,
**kwargs
) -> float:

if observation is None:
observation = self.observation
if forecast is None:
Expand Down Expand Up @@ -295,7 +291,6 @@ def calc_threshold_accuracy_ratio(
*args,
**kwargs
) -> float:

if observation is None:
observation = self.observation
if forecast is None:
Expand All @@ -316,7 +311,6 @@ def calc_threshold_hit_ratio(
*args,
**kwargs
) -> float:

if observation is None:
observation = self.observation
if forecast is None:
Expand All @@ -337,7 +331,6 @@ def calc_threshold_miss_ratio(
*args,
**kwargs
) -> float:

if observation is None:
observation = self.observation
if forecast is None:
Expand All @@ -358,7 +351,6 @@ def calc_threshold_false_alarm_ratio(
*args,
**kwargs
) -> float:

if observation is None:
observation = self.observation
if forecast is None:
Expand All @@ -379,7 +371,6 @@ def calc_threshold_bias_score(
*args,
**kwargs
) -> float:

if observation is None:
observation = self.observation
if forecast is None:
Expand All @@ -400,7 +391,6 @@ def calc_threshold_ts(
*args,
**kwargs
) -> float:

if observation is None:
observation = self.observation
if forecast is None:
Expand All @@ -421,7 +411,6 @@ def calc_threshold_mae(
*args,
**kwargs
) -> float:

if observation is None:
observation = self.observation
if forecast is None:
Expand Down
8 changes: 6 additions & 2 deletions cyeva/core/precip.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,12 @@ def __init__(
self.kind = kind
self.unit = unit
self.lev = lev
self.observation = (self.observation * UNITS.parse_expression(unit)).to("mm").magnitude
self.forecast = (self.forecast * UNITS.parse_expression(unit)).to("mm").magnitude
self.observation = (
(self.observation * UNITS.parse_expression(unit)).to("mm").magnitude
)
self.forecast = (
(self.forecast * UNITS.parse_expression(unit)).to("mm").magnitude
)
self.df = pd.DataFrame(
{
"observation": self.observation,
Expand Down
80 changes: 45 additions & 35 deletions cyeva/core/statistic.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def calc_binary_quadrant_values(

return hits, misses, false_alarms, correct_rejects, total


@assert_length
@drop_nan
def calc_multiclass_confusion_matrix(
Expand Down Expand Up @@ -80,11 +81,17 @@ class K n(F_K,O_1) n(F_K,O_2) n(F_K,O_K)
cates = np.unique(np.concatenate([np.unique(observation), np.unique(forecast)]))
confusion_matrix_list = []
for obs_cate_, fcst_cate_ in product(cates, cates):
count_cate_ = Counter((observation==obs_cate_) & (forecast==fcst_cate_))[True]
count_cate_ = Counter((observation == obs_cate_) & (forecast == fcst_cate_))[
True
]
confusion_matrix_list.append([obs_cate_, fcst_cate_, count_cate_])

confusion_matrix = pd.DataFrame(np.array(confusion_matrix_list), columns=['observation','forecast', 'count'])
confusion_matrix = confusion_matrix.pivot_table('count', index='forecast',columns='observation',aggfunc='sum').astype(int)
confusion_matrix = pd.DataFrame(
np.array(confusion_matrix_list), columns=["observation", "forecast", "count"]
)
confusion_matrix = confusion_matrix.pivot_table(
"count", index="forecast", columns="observation", aggfunc="sum"
).astype(int)

assert len(observation) == np.sum(confusion_matrix.values)

Expand All @@ -104,98 +111,101 @@ def calc_multiclass_accuracy_ratio(
Args:
observation (Union[list, np.ndarray]): Multiclass observation data array
that consist of class labels.
forecast (Union[list, np.ndarray]): Multiclass forecast data array
forecast (Union[list, np.ndarray]): Multiclass forecast data array
that consist of class labels.
Returns:
float: The accuracy(%) of multiclass forecast. Perfect score 100.
"""

confusion_matrix = calc_multiclass_confusion_matrix(
observation, forecast
)
confusion_matrix = calc_multiclass_confusion_matrix(observation, forecast)
# compute the sum of hits of all categories
all_hits = np.sum(confusion_matrix.values.diagonal())
total = len(observation)

return (all_hits / total) * 100
return (all_hits / total) * 100


@assert_length
@fix_zero_division
@drop_nan
def calc_multiclass_heidke_skill_score(
observation: Union[list, np.ndarray], forecast: Union[list, np.ndarray]
) -> float:
"""calculate the Heidke Skill Score (HSS), which measures the
fraction of correct forecasts after eliminating those forecasts
which would be correct due purely to random chance.
"""calculate the Heidke Skill Score (HSS), which measures the
fraction of correct forecasts after eliminating those forecasts
which would be correct due purely to random chance.
HSS = \frac {\frac {1} {Total} \sum\limits_{i=1}^{K} n(F_i,O_i) -
\frac {1} {Total^2} \sum\limits_{i=1}^{K} N(F_i)N(O_i) }
HSS = \frac {\frac {1} {Total} \sum\limits_{i=1}^{K} n(F_i,O_i) -
\frac {1} {Total^2} \sum\limits_{i=1}^{K} N(F_i)N(O_i) }
{1 - \frac {1} {Total^2} \sum\limits_{i=1}^{K} N(F_i)*N(O_i)}
Args:
observation (Union[list, np.ndarray]): Multiclass observation data array
that consist of class labels.
forecast (Union[list, np.ndarray]): Multiclass forecast data array
forecast (Union[list, np.ndarray]): Multiclass forecast data array
that consist of class labels.
Returns:
float: HSS score. Perfect score 1.
"""

confusion_matrix = calc_multiclass_confusion_matrix(
observation, forecast
)
confusion_matrix = calc_multiclass_confusion_matrix(observation, forecast)
total = len(observation)

# compute HSS score
acc_ = np.sum(confusion_matrix.values.diagonal()) / total
reference_acc_ = np.sum(confusion_matrix.sum(axis=0).values * confusion_matrix.sum(axis=1).values) / (total**2)
acc_ = np.sum(confusion_matrix.values.diagonal()) / total
reference_acc_ = np.sum(
confusion_matrix.sum(axis=0).values * confusion_matrix.sum(axis=1).values
) / (total**2)
perfect_acc_ = 1
hss_score_ = ( acc_ - reference_acc_ ) / (perfect_acc_ - reference_acc_)
hss_score_ = (acc_ - reference_acc_) / (perfect_acc_ - reference_acc_)

return hss_score_


@assert_length
@fix_zero_division
@drop_nan
def calc_multiclass_hanssen_kuipers_score(
observation: Union[list, np.ndarray], forecast: Union[list, np.ndarray]
) -> float:
"""calculate the Hanssen and Kuipers Score (HSS), which is
similar to the Heidke skill score (above), except that in
the denominator the fraction of correct forecasts due to
"""calculate the Hanssen and Kuipers Score (HSS), which is
similar to the Heidke skill score (above), except that in
the denominator the fraction of correct forecasts due to
random chance is for an unbiased forecast.
HK = \frac {\frac {1} {Total} \sum\limits_{i=1}^{K} n(F_i,O_i) -
\frac {1} {Total^2} \sum\limits_{i=1}^{K} N(F_i)N(O_i) }
HK = \frac {\frac {1} {Total} \sum\limits_{i=1}^{K} n(F_i,O_i) -
\frac {1} {Total^2} \sum\limits_{i=1}^{K} N(F_i)N(O_i) }
{1 - \frac {1} {Total^2} \sum\limits_{i=1}^{K} N(O_i)^2}
Args:
observation (Union[list, np.ndarray]): Multiclass observation data array
that consist of class labels.
forecast (Union[list, np.ndarray]): Multiclass forecast data array
forecast (Union[list, np.ndarray]): Multiclass forecast data array
that consist of class labels.
Returns:
float: HK score. Perfect score 1.
"""

confusion_matrix = calc_multiclass_confusion_matrix(
observation, forecast
)
confusion_matrix = calc_multiclass_confusion_matrix(observation, forecast)
total = len(observation)

# compute HK score
acc_ = np.sum(confusion_matrix.values.diagonal()) / total
reference_acc_ = np.sum(confusion_matrix.sum(axis=0).values * confusion_matrix.sum(axis=1).values) / (total**2)
acc_ = np.sum(confusion_matrix.values.diagonal()) / total
reference_acc_ = np.sum(
confusion_matrix.sum(axis=0).values * confusion_matrix.sum(axis=1).values
) / (total**2)
perfect_acc_ = 1
unbias_reference_acc_ = np.sum(confusion_matrix.sum(axis=0).values**2) / (total**2)
hk_score_ = ( acc_ - reference_acc_ ) / (perfect_acc_ - unbias_reference_acc_)

unbias_reference_acc_ = np.sum(confusion_matrix.sum(axis=0).values ** 2) / (
total**2
)
hk_score_ = (acc_ - reference_acc_) / (perfect_acc_ - unbias_reference_acc_)

return hk_score_


@assert_length
@fix_zero_division
@drop_nan
Expand Down
8 changes: 6 additions & 2 deletions cyeva/core/temp.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@ def __init__(
super().__init__(observation, forecast)
self.kind = kind
self.lev = lev
self.observation = (self.observation * UNITS.parse_expression(unit)).to("degC").magnitude
self.forecast = (self.forecast * UNITS.parse_expression(unit)).to("degC").magnitude
self.observation = (
(self.observation * UNITS.parse_expression(unit)).to("degC").magnitude
)
self.forecast = (
(self.forecast * UNITS.parse_expression(unit)).to("degC").magnitude
)
self.df = pd.DataFrame(
{
"observation": self.observation,
Expand Down
1 change: 0 additions & 1 deletion cyeva/core/weather_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ def gather_all_factors(self):
}
)


df = pd.DataFrame(result)

return df
Expand Down
1 change: 0 additions & 1 deletion cyeva/utils/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ def convert_to_ndarray(func):

@wraps(func)
def wrapper(observation, forecast, *args, **kwargs):

if not isinstance(observation, np.ndarray) and not isinstance(
observation, Number
):
Expand Down
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,4 @@
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ["_static"]

master_doc = 'index'
master_doc = "index"
4 changes: 3 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ def get_version(rel_path):
url="https://github.com/caiyunapp/cyeva",
include_package_data=True,
package_data={"": ["*.csv", "*.config", "*.nl", "*.json"]},
packages=setuptools.find_packages(exclude=["*.tests", "*.tests.*", "tests.*", "tests"]),
packages=setuptools.find_packages(
exclude=["*.tests", "*.tests.*", "tests.*", "tests"]
),
install_requires=required,
classifiers=[
"Development Status :: 4 - Beta",
Expand Down
2 changes: 1 addition & 1 deletion tests/functions/case/weather_code/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .accuracy_ratio import ACCURACY_RATE_CASE
from .hk import HK_CASE
from .hss import HSS_CASE
from .hss import HSS_CASE
11 changes: 7 additions & 4 deletions tests/functions/case/weather_code/accuracy_ratio.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
ACCURACY_RATE_CASE = [
{"obs": [1, 2, 3, 4, 5], "fct": [1, 2, 3, 4, 5], "result": 100},
{"obs": ['A', 'B', 'C', 'D', 'E'], "fct": ['A', 'B', 'C', 'D', 'E'], "result": 100},
{"obs": [1]*5 + [2]*5 + [3]*5 + [4]*5 + [5]*5, "fct": [1, 2, 3, 4, 5]*5, "result": 20}

]
{"obs": ["A", "B", "C", "D", "E"], "fct": ["A", "B", "C", "D", "E"], "result": 100},
{
"obs": [1] * 5 + [2] * 5 + [3] * 5 + [4] * 5 + [5] * 5,
"fct": [1, 2, 3, 4, 5] * 5,
"result": 20,
},
]
8 changes: 6 additions & 2 deletions tests/functions/case/weather_code/hk.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
HK_CASE = [
{"obs": [1, 2, 3, 4, 5], "fct": [1, 2, 3, 4, 5], "result": 1},
{"obs": [1]*5 + [2]*5 + [3]*5 + [4]*5 + [5]*5, "fct": [1, 2, 3, 4, 5]*5, "result": 0}
]
{
"obs": [1] * 5 + [2] * 5 + [3] * 5 + [4] * 5 + [5] * 5,
"fct": [1, 2, 3, 4, 5] * 5,
"result": 0,
},
]
8 changes: 6 additions & 2 deletions tests/functions/case/weather_code/hss.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
HSS_CASE = [
{"obs": [1, 2, 3, 4, 5], "fct": [1, 2, 3, 4, 5], "result": 1},
{"obs": [1]*5 + [2]*5 + [3]*5 + [4]*5 + [5]*5, "fct": [1, 2, 3, 4, 5]*5, "result": 0}
]
{
"obs": [1] * 5 + [2] * 5 + [3] * 5 + [4] * 5 + [5] * 5,
"fct": [1, 2, 3, 4, 5] * 5,
"result": 0,
},
]
1 change: 0 additions & 1 deletion tests/functions/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@


def test_comparison():

for case in RMSE_CASE:
obs = case["obs"]
fcst = case["fct"]
Expand Down
Loading

0 comments on commit 5257b76

Please sign in to comment.