# Path: econtools/metrics/api.py
# def reg(df: pd.DataFrame,
#         y_name: str, x_name: Union[str, List[str]],
#         fe_name: Optional[str]=None, a_name: Optional[str]=None,
#         nosingles: bool=True,
#         vce_type: Optional[str]=None, cluster: Optional[str]=None,
#         shac: Optional[dict]=None,
#         addcons: Optional[bool]=None, nocons: bool=False,
#         awt_name: Optional[str]=None,
#         save_mem: bool=False,
#         check_colinear: bool=False,
#         ) -> Results:
#     """OLS Regression.
# 
#     Args:
#         df (DataFrame): Data with any relevant variables.
#         y_name (str): Column name in ``df`` of the dependent variable.
#         x_name (str or list): Column name(s) in ``df`` of the independent
#                 variables/regressors
# 
#     Keyword Args:
#         vce_type (str): Type of estimator to use for variance-covariance matrix
#             of estimated coefficients. Default is standard OLS. Possible
#             choices are:
#                 - 'robust' or 'hc1'
#                 - 'hc2'
#                 - 'hc3'
#                 - 'cluster' (requires kwarg ``cluster``)
#                 - 'shac' (requires kwarg ``shac``)
#         cluster (str): Column name in ``df`` used to cluster standard errors.
#         shac (dict): Arguments to pass to spatial HAC estimator.
#             Requires:
#                 - **x** (*str*): Column name in ``df`` to serve as longitude.
#                 - **y** (*str*): Column name in ``df`` to serve as latitude.
#                 - **kern** (*str*): Kernel to use in estimation. May be
#                   triangle (``tria``) or uniform (``unif``).
#                 - **band** (float): Bandwidth for kernel.
#         fe_name (str) - Column name in ``df`` that defines groups for within
#             transformation (demeaning).
#         a_name (str) - Deprecated. See ``fe_name``.
#         awt_name (str): Column name in ``df`` to use for analytic weights in
#             regression.
#         addcons (bool): Defaults to False. Add a constant to independent
#             variables. Has no effect if ``a_name`` is passed.
#         nocons (bool): Defaults to False. Flag so estimators know that
#             independent variables ``df`` do not include a constant. Only
#             affects degrees of freedom.
#         nosingles (bool): Defaults to True. Drop observations that are obsorbed
#             by the within transformation. Has no effect if ``a_name=None``.
#         save_mem (bool): Defaults to False. If True, the returned
#             :py:class:`~econtools.metrics.core.Results` object will not save
#             large objects, specifically ``yhat``, ``sample``, and ``resid``.
#         check_colinear (bool): Default False. Checks rank of regressor matrix,
#             X. If X is rank deficient, an error is raised that prints the
#             colinear columns.
# 
#     Returns:
#         A :py:class:`~econtools.metrics.core.Results` object
#     """
# 
#     fe_name = _a_name_deprecation_handling(a_name, fe_name)
# 
#     RegWorker = Regression(
#         df, y_name, x_name,
#         fe_name=fe_name, nosingles=nosingles, addcons=addcons, nocons=nocons,
#         vce_type=vce_type, cluster=cluster, shac=shac,
#         awt_name=awt_name,
#         save_mem=save_mem,
#         check_colinear=check_colinear,
#     )
# 
#     results = RegWorker.main()
#     return results


from math import factorial
from typing import Union, Optional, Tuple, Callable, cast
from econtools.metrics import reg
import numpy as np
import pandas as pd
    import matplotlib.pyplot as plt
        for xi_idx, x_i in enumerate(x):
            y_no_i = np.delete(y, xi_idx)
            x_no_i = np.delete(x, xi_idx)
            y_hat = ghat_of_x(y_no_i, x_no_i, x_i, h, degree, kernel)
            resid2 = (y[xi_idx] - y_hat) ** 2
            this_CV_h += resid2
        CV_h[h_idx] = this_CV_h
    return h_set, CV_h

def _set_hset_for_cv(x, kernel):
    hs = silverman(x, kernel)
    h_set = np.linspace(.2 * hs, 2 * hs, num=50)
    return h_set


def ghat_of_x(y, x, x0, h, degree, kernel):
    K = kernel_func(x - x0, h, kernel)
    if _sparse_data(K, degree):
        return np.nan

    X = _make_X(x, x0, degree)
    x_name = ['cons'] + ['x{}'.format(i) for i in range(1, degree + 1)]
    df = pd.DataFrame(
        np.hstack((
            y.reshape(-1, 1),
            X,
            K.reshape(-1, 1)
        )),
        columns=['y'] + x_name + ['k']
    )

# Path: econtools/metrics/api.py
# def reg(df: pd.DataFrame,
#         y_name: str, x_name: Union[str, List[str]],
#         fe_name: Optional[str]=None, a_name: Optional[str]=None,
#         nosingles: bool=True,
#         vce_type: Optional[str]=None, cluster: Optional[str]=None,
#         shac: Optional[dict]=None,
#         addcons: Optional[bool]=None, nocons: bool=False,
#         awt_name: Optional[str]=None,
#         save_mem: bool=False,
#         check_colinear: bool=False,
#         ) -> Results:
#     """OLS Regression.
# 
#     Args:
#         df (DataFrame): Data with any relevant variables.
#         y_name (str): Column name in ``df`` of the dependent variable.
#         x_name (str or list): Column name(s) in ``df`` of the independent
#                 variables/regressors
# 
#     Keyword Args:
#         vce_type (str): Type of estimator to use for variance-covariance matrix
#             of estimated coefficients. Default is standard OLS. Possible
#             choices are:
#                 - 'robust' or 'hc1'
#                 - 'hc2'
#                 - 'hc3'
#                 - 'cluster' (requires kwarg ``cluster``)
#                 - 'shac' (requires kwarg ``shac``)
#         cluster (str): Column name in ``df`` used to cluster standard errors.
#         shac (dict): Arguments to pass to spatial HAC estimator.
#             Requires:
#                 - **x** (*str*): Column name in ``df`` to serve as longitude.
#                 - **y** (*str*): Column name in ``df`` to serve as latitude.
#                 - **kern** (*str*): Kernel to use in estimation. May be
#                   triangle (``tria``) or uniform (``unif``).
#                 - **band** (float): Bandwidth for kernel.
#         fe_name (str) - Column name in ``df`` that defines groups for within
#             transformation (demeaning).
#         a_name (str) - Deprecated. See ``fe_name``.
#         awt_name (str): Column name in ``df`` to use for analytic weights in
#             regression.
#         addcons (bool): Defaults to False. Add a constant to independent
#             variables. Has no effect if ``a_name`` is passed.
#         nocons (bool): Defaults to False. Flag so estimators know that
#             independent variables ``df`` do not include a constant. Only
#             affects degrees of freedom.
#         nosingles (bool): Defaults to True. Drop observations that are obsorbed
#             by the within transformation. Has no effect if ``a_name=None``.
#         save_mem (bool): Defaults to False. If True, the returned
#             :py:class:`~econtools.metrics.core.Results` object will not save
#             large objects, specifically ``yhat``, ``sample``, and ``resid``.
#         check_colinear (bool): Default False. Checks rank of regressor matrix,
#             X. If X is rank deficient, an error is raised that prints the
#             colinear columns.
# 
#     Returns:
#         A :py:class:`~econtools.metrics.core.Results` object
#     """
# 
#     fe_name = _a_name_deprecation_handling(a_name, fe_name)
# 
#     RegWorker = Regression(
#         df, y_name, x_name,
#         fe_name=fe_name, nosingles=nosingles, addcons=addcons, nocons=nocons,
#         vce_type=vce_type, cluster=cluster, shac=shac,
#         awt_name=awt_name,
#         save_mem=save_mem,
#         check_colinear=check_colinear,
#     )
# 
#     results = RegWorker.main()
#     return results


# Path: econtools/metrics/locallinear.py
from math import factorial
from typing import Union, Optional, Tuple, Callable, cast
from econtools.metrics import reg
import numpy as np
import pandas as pd
    import matplotlib.pyplot as plt

        for xi_idx, x_i in enumerate(x):
            y_no_i = np.delete(y, xi_idx)
            x_no_i = np.delete(x, xi_idx)
            y_hat = ghat_of_x(y_no_i, x_no_i, x_i, h, degree, kernel)
            resid2 = (y[xi_idx] - y_hat) ** 2
            this_CV_h += resid2
        CV_h[h_idx] = this_CV_h
    return h_set, CV_h

def _set_hset_for_cv(x, kernel):
    hs = silverman(x, kernel)
    h_set = np.linspace(.2 * hs, 2 * hs, num=50)
    return h_set


def ghat_of_x(y, x, x0, h, degree, kernel):
    K = kernel_func(x - x0, h, kernel)
    if _sparse_data(K, degree):
        return np.nan

    X = _make_X(x, x0, degree)
    x_name = ['cons'] + ['x{}'.format(i) for i in range(1, degree + 1)]
    df = pd.DataFrame(
        np.hstack((
            y.reshape(-1, 1),
            X,
            K.reshape(-1, 1)
        )),
        columns=['y'] + x_name + ['k']
    )

    res = reg(df, 'y', x_name, awt_name='k')