Files
OpenBB/openbb_terminal/econometrics/regression_view.py
James Maslek 4495d4d2f5 Refactoring econometrics for SDK usability (#3379)
* Econometrics enhancements

* Docsring

* norm show chart when true

* isort + lint

* Make coint sdk friendly

* mypy?

* Why you miss this locally pylint?

* Clean up granger command

* Tests

* #3323

* Fix up dwat function

* Fix rounding error in test--hopefully

* Update bgod and bpag

* testing mypy

* small commit to help rebase?

* Update Panel OLS stuff. Need some more examples and to fix mypy

* add docstring example

* update controller complete and duplicate printing

Co-authored-by: Jeroen Bouma <jer.bouma@gmail.com>
2022-11-15 09:46:29 -05:00

217 lines
6.0 KiB
Python

"""Regression View"""
__docformat__ = "numpy"
import logging
import os
from typing import List, Optional
import pandas as pd
from matplotlib import pyplot as plt
import statsmodels
from openbb_terminal.config_plot import PLOT_DPI
from openbb_terminal.config_terminal import theme
from openbb_terminal.decorators import log_start_end
from openbb_terminal.econometrics import regression_model
from openbb_terminal.helper_funcs import export_data, plot_autoscale, print_rich_table
from openbb_terminal.rich_config import console
logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def display_panel(
Y: pd.DataFrame,
X: pd.DataFrame,
regression_type: str = "OLS",
entity_effects: bool = False,
time_effects: bool = False,
export: str = "",
):
"""Based on the regression type, this function decides what regression to run.
Parameters
----------
data : dict
A dictionary containing the datasets.
regression_variables : list
The regressions variables entered where the first variable is
the dependent variable.
each column/dataset combination.
regression_type: str
The type of regression you wish to execute. Choose from:
OLS, POLS, RE, BOLS, FE
entity_effects: bool
Whether to apply Fixed Effects on entities.
time_effects: bool
Whether to apply Fixed Effects on time.
export : str
Format to export data
Returns
-------
The dataset used, the dependent variable, the independent variable and
the regression model.
"""
model = regression_model.get_regressions_results(
Y,
X,
regression_type,
entity_effects,
time_effects,
)
if regression_type != "OLS":
console.print(model)
if export:
results_as_html = model.summary.tables[1].as_html()
df = pd.read_html(results_as_html, header=0, index_col=0)[0]
dependent = Y.columns[0]
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
f"{dependent}_{regression_type}_regression",
df,
)
return model
@log_start_end(log=logger)
def display_dwat(
model: statsmodels.regression.linear_model.RegressionResultsWrapper,
dependent_variable: pd.Series,
plot: bool = True,
export: str = "",
external_axes: Optional[List[plt.axes]] = None,
):
"""Show Durbin-Watson autocorrelation tests
Parameters
----------
model : OLS Model
A fit statsmodels OLS model.
dependent_variable : pd.Series
The dependent variable for plotting
plot : bool
Whether to plot the residuals
export : str
Format to export data
external_axes: Optional[List[plt.axes]]
External axes to plot on
"""
autocorr = regression_model.get_dwat(model)
if 1.5 < autocorr < 2.5:
console.print(
f"The result {autocorr} is within the range 1.5 and 2.5 which therefore indicates "
f"autocorrelation not to be problematic."
)
else:
console.print(
f"The result {autocorr} is outside the range 1.5 and 2.5 and could "
f"be problematic. Please consider lags of the dependent or independent variable."
)
if plot:
if external_axes is None:
_, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
else:
ax = external_axes[0]
ax.scatter(dependent_variable, model.resid)
ax.axhline(y=0, color="r", linestyle="-")
ax.set_ylabel("Residual")
ax.set_xlabel(dependent_variable.name.capitalize())
ax.set_title("Plot of Residuals")
theme.style_primary_axis(ax)
if external_axes is None:
theme.visualize_output()
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
f"{dependent_variable.name}_dwat",
autocorr,
)
@log_start_end(log=logger)
def display_bgod(
model: statsmodels.regression.linear_model.RegressionResultsWrapper,
lags: int = 3,
export: str = "",
):
"""Show Breusch-Godfrey autocorrelation test
Parameters
----------
model : OLS Model
OLS model that has been fit.
lags : int
The amount of lags included.
export : str
Format to export data
"""
df = regression_model.get_bgod(model, lags)
print_rich_table(
df,
headers=list(["Breusch-Godfrey"]),
show_index=True,
title=f"Breusch-Godfrey autocorrelation test [Lags: {lags}]",
)
p_value = df.loc["p-value"][0]
if p_value > 0.05:
console.print(
f"{round(p_value, 2)} indicates the autocorrelation. Consider re-estimating with "
"clustered standard errors and applying the Random Effects or Fixed Effects model."
)
else:
console.print(
f"The result {round(p_value, 2)} indicates no existence of autocorrelation."
)
export_data(export, os.path.dirname(os.path.abspath(__file__)), "results_bgod", df)
console.print()
@log_start_end(log=logger)
def display_bpag(
model: statsmodels.regression.linear_model.RegressionResultsWrapper,
export: str = "",
):
"""Show Breusch-Pagan heteroscedasticity test
Parameters
----------
model : OLS Model
OLS model that has been fit.
export : str
Format to export data
"""
df = regression_model.get_bpag(model)
print_rich_table(
df,
headers=list(["Breusch-Pagan"]),
show_index=True,
title="Breusch-Pagan heteroscedasticity test",
)
p_value = df.loc["p-value"][0]
if p_value > 0.05:
console.print(
f"{round(p_value, 2)} indicates heteroscedasticity. Consider taking the log "
f"or a rate for the dependent variable."
)
else:
console.print(
f"The result {round(p_value, 2)} indicates no existence of heteroscedasticity."
)
export_data(export, os.path.dirname(os.path.abspath(__file__)), "results_bpag", df)
console.print()