<jupyter_start><jupyter_text>Tabular Data`xskillscore` can be used on tabular data such as that stored in a `pandas.DataFrame`.It can be used most effectively when evaluating predictions over different fields.<jupyter_code>import numpy as np
import pandas as pd
import xskillscore as xs
from sklearn.datasets import load_boston
from sklearn.metrics import mean_squared_error
np.random.seed(seed=42)<jupyter_output><empty_output><jupyter_text>Boston house prices dataset A small example is to take a dataset and evaluate the model according to a field (column).Load the Boston house prices dataset:<jupyter_code>data = load_boston()
df = pd.DataFrame(data.data, columns=data.feature_names)
df['y'] = pd.Series(data.target)
df<jupyter_output><empty_output><jupyter_text>Create a dummy prediction column by adding noise to `y`:<jupyter_code>noise = np.random.uniform(-1, 1, size=len(df['y']))
df['yhat'] = (df['y'] + (df['y'] * noise)).clip(lower=df["y"].min())<jupyter_output><empty_output><jupyter_text>Evaluate the model over the field `RAD` using `pandas.groupby.apply` with `mean_squared_error` from `scikit-learn`:<jupyter_code>df.groupby('RAD').apply(lambda x: mean_squared_error(x["y"], x["yhat"]))<jupyter_output><empty_output><jupyter_text>You could also do the following using `xskillscore`.First, structure the `pandas.DataFrame` to keep the core fields when converting to an `xarray` object:<jupyter_code>min_df = df.reset_index().set_index(["index", "RAD"])[["y", "yhat"]]
min_df<jupyter_output><empty_output><jupyter_text>Convert it to an `xarray.Dataset` using `pandas.DataFrame.to_xarray`. Note: This will create an array of `index` by `RAD` and pad the values that do not exist with `nan`.<jupyter_code>ds = min_df.to_xarray()
ds<jupyter_output><empty_output><jupyter_text>You call now apply any metric from `xskillscore` using the accessor method. The input for the `dim` argument is `index` as we want to reduce this dimension and apply the metric over `RAD`. In addition, there are `nan`'s in the `xarray.Dataset` so you should use `skipna=True`:<jupyter_code>out = ds.xs.mse('y', 'yhat', dim="index", skipna=True)
out<jupyter_output><empty_output><jupyter_text>It makes sense to return the data in tabular form hence you can call `xarray.DataArray.to_series` to convert it to a `pandas.Series`:<jupyter_code>out.to_series()<jupyter_output><empty_output><jupyter_text>Evaluating predictions over many columns `xskillscore` is built upon `xarray.apply_ufunc` which offers speed-up by vectorizing operations. As a result `xskillscore` can be faster than `pandas.groupby.apply`. This is espicially true if there are many samples in the dataset and if the predictions have to be evaluated over many fields.For this exercise we will create fake data for which the predictions have to be evaluated over three fields:<jupyter_code>stores = np.arange(100)
skus = np.arange(100)
dates = pd.date_range("1/1/2020", "1/10/2020", freq="D")

rows = []
for _, date in enumerate(dates):
    for _, store in enumerate(stores):
        for _, sku in enumerate(skus):
            rows.append(
                dict(
                    {
                        "DATE": date,
                        "STORE": store,
                        "SKU": sku,
                        "y": np.random.randint(9) + 1,
                    }
                )
            )
df = pd.DataFrame(rows)

noise = np.random.uniform(-1, 1, size=len(df['y']))
df['yhat'] = (df['y'] + (df['y'] * noise)).clip(lower=df["y"].min())
df<jupyter_output><empty_output><jupyter_text>Time the `pandas.groupby.apply` method:<jupyter_code>%%time
df.groupby(['STORE', 'SKU']).apply(lambda x: mean_squared_error(x["y"], x["yhat"]))<jupyter_output>CPU times: user 2.57 s, sys: 10.3 ms, total: 2.58 s
Wall time: 2.58 s<jupyter_text>Time it using `xskillscore`:<jupyter_code>%%time
df.set_index(["DATE", "STORE", "SKU"]).to_xarray().xs.mse(
    "y", "yhat", dim="DATE"
).to_series()<jupyter_output>CPU times: user 21.8 ms, sys: 4.02 ms, total: 25.8 ms
Wall time: 24.4 ms
{'fraction_non_alphanumeric': 0.13076923076923078, 'fraction_numerical': 0.012655086848635236, 'mean_word_length': 4.717730496453901, 'pattern_counts': {'":': 4, '<': 43, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '442829', 'license': 'Apache-2.0', 'n_tokens_mistral': 1422, 'n_tokens_neox': 1360, 'n_words': 385, 'path': 'docs/source/tabular-data.ipynb', 'repo_name': 'aaronspring/xskillscore', 'size': '4030'}