def rsquared_adj(r, nobs, df_res, has_constant=True):
    """
    Compute the adjusted R^2, coefficient of determination. 

    Args:
        r (float): rsquared value
        nobs (int): number of observations the model was fit on
        df_res (int): degrees of freedom of the residuals (nobs - number of model params)
        has_constant (bool): whether the fitted model included a constant (intercept)
    
    Returns:
        float: adjusted coefficient of determination
    """

    if has_constant:
        return 1.0 - (nobs - 1) / df_res * (1.0 - r)
    else:
        return 1.0 - nobs / df_res * (1.0 - r)