<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def waic(data, pointwise=False, scale="deviance"):
 """Calculate the widely available information criterion. Also calculates the WAIC's standard error and the effective number of parameters of the samples in trace from model. Read more theory here - in a paper by some of the leading authorities on model selection dx.doi.org/10.1111/1467-9868.00353 Parameters data : obj Any object that can be converted to an az.InferenceData object Refer to documentation of az.convert_to_dataset for details pointwise: bool if True the pointwise predictive accuracy will be returned. Default False scale : str Output scale for loo. Available options are: - `deviance` : (default) -2 * (log-score) - `log` : 1 * log-score - `negative_log` : -1 * (log-score) Returns ------- DataFrame with the following columns: waic: widely available information criterion waic_se: standard error of waic p_waic: effective number parameters var_warn: 1 if posterior variance of the log predictive densities exceeds 0.4 waic_i: and array of the pointwise predictive accuracy, only if pointwise True waic_scale: scale of the waic results """

    inference_data = convert_to_inference_data(data)
    for group in ("sample_stats",):
        if not hasattr(inference_data, group):
            raise TypeError(
                "Must be able to extract a {group} group from data!".format(group=group)
            )
    if "log_likelihood" not in inference_data.sample_stats:
        raise TypeError("Data must include log_likelihood in sample_stats")
    log_likelihood = inference_data.sample_stats.log_likelihood

    if scale.lower() == "deviance":
        scale_value = -2
    elif scale.lower() == "log":
        scale_value = 1
    elif scale.lower() == "negative_log":
        scale_value = -1
    else:
        raise TypeError('Valid scale values are "deviance", "log", "negative_log"')

    n_samples = log_likelihood.chain.size * log_likelihood.draw.size
    new_shape = (n_samples,) + log_likelihood.shape[2:]
    log_likelihood = log_likelihood.values.reshape(*new_shape)

    lppd_i = _logsumexp(log_likelihood, axis=0, b_inv=log_likelihood.shape[0])

    vars_lpd = np.var(log_likelihood, axis=0)
    warn_mg = 0
    if np.any(vars_lpd > 0.4):
        warnings.warn(
            """For one or more samples the posterior variance of the log predictive
        densities exceeds 0.4. This could be indication of WAIC starting to fail see
        http://arxiv.org/abs/1507.04544 for details
        """
        )
        warn_mg = 1

    waic_i = scale_value * (lppd_i - vars_lpd)
    waic_se = (len(waic_i) * np.var(waic_i)) ** 0.5
    waic_sum = np.sum(waic_i)
    p_waic = np.sum(vars_lpd)

    if pointwise:
        if np.equal(waic_sum, waic_i).all():  # pylint: disable=no-member
            warnings.warn(
                """The point-wise WAIC is the same with the sum WAIC, please double check
            the Observed RV in your model to make sure it returns element-wise logp.
            """
            )
        return pd.Series(
            data=[waic_sum, waic_se, p_waic, warn_mg, waic_i, scale],
            index=["waic", "waic_se", "p_waic", "warning", "waic_i", "waic_scale"],
        )
    else:
        return pd.Series(
            data=[waic_sum, waic_se, p_waic, warn_mg, scale],
            index=["waic", "waic_se", "p_waic", "warning", "waic_scale"],
        )