Coefficients of polynomial :math:`h(x)`, which has been fitted to
    the deterministic dynamics of Langevin model

    .. math::
        \dot{x}(t) = h(x(t)) + \mathcal{N}(0,R)

    as described by [1].

    For short time-series this method is highly dependent on the parameters.

    .. rubric:: References

    |  [1] Friedrich et al. (2000): Physics Letters A 271, p. 217-222
    |  *Extracting model equations from experimental data*

    :param x: the time series to calculate the feature of
    :type x: numpy.ndarray
    :param param: contains dictionaries {"m": x, "r": y, "coeff": z} with x being positive integer, the order of polynom to fit for estimating fixed points of
                    dynamics, y positive float, the number of quantils to use for averaging and finally z, a positive integer corresponding to the returned
                    coefficient
    :type param: list
    :return: the different feature values
    :return type: pandas.Series

def friedrich_coefficients(x, param):
    """
    Coefficients of polynomial :math:`h(x)`, which has been fitted to
    the deterministic dynamics of Langevin model

    .. math::
        \dot{x}(t) = h(x(t)) + \mathcal{N}(0,R)

    as described by [1].

    For short time-series this method is highly dependent on the parameters.

    .. rubric:: References

    |  [1] Friedrich et al. (2000): Physics Letters A 271, p. 217-222
    |  *Extracting model equations from experimental data*

    :param x: the time series to calculate the feature of
    :type x: numpy.ndarray
    :param param: contains dictionaries {"m": x, "r": y, "coeff": z} with x being positive integer, the order of polynom to fit for estimating fixed points of
                    dynamics, y positive float, the number of quantils to use for averaging and finally z, a positive integer corresponding to the returned
                    coefficient
    :type param: list
    :return: the different feature values
    :return type: pandas.Series
    """
    calculated = {}  # calculated is dictionary storing the calculated coefficients {m: {r: friedrich_coefficients}}
    res = {}  # res is a dictionary containg the results {"m_10__r_2__coeff_3": 15.43}

    for parameter_combination in param:
        m = parameter_combination['m']
        r = parameter_combination['r']
        coeff = parameter_combination["coeff"]

        assert coeff >= 0, "Coefficients must be positive or zero. Found {}".format(coeff)

        # calculate the current friedrich coefficients if they do not exist yet
        if m not in calculated:
            calculated[m] = {r: _estimate_friedrich_coefficients(x, m, r)}
        else:
            if r not in calculated[m]:
                calculated[m] = {r: _estimate_friedrich_coefficients(x, m, r)}

        try:
            res["m_{}__r_{}__coeff_{}".format(m, r, coeff)] = calculated[m][r][coeff]
        except IndexError:
            res["m_{}__r_{}__coeff_{}".format(m, r, coeff)] = np.NaN
    return [(key, value) for key, value in res.items()]