def pivot_table(df, index=None, columns=None, values=None, aggfunc='mean'):
    "\n    Create a spreadsheet-style pivot table as a DataFrame. Target ``columns``\n    must have category dtype to infer result's ``columns``.\n    ``index``, ``columns``, and ``aggfunc`` must be all scalar.\n    ``values`` can be scalar or list-like.\n\n    Parameters\n    ----------\n    df : DataFrame\n    index : scalar\n        column to be index\n    columns : scalar\n        column to be columns\n    values : scalar or list(scalar)\n        column(s) to aggregate\n    aggfunc : {'mean', 'sum', 'count', 'first', 'last'}, default 'mean'\n\n    Returns\n    -------\n    table : DataFrame\n\n    See Also\n    --------\n    pandas.DataFrame.pivot_table\n    "
    if ((not is_scalar(index)) or (index is None)):
        raise ValueError("'index' must be the name of an existing column")
    if ((not is_scalar(columns)) or (columns is None)):
        raise ValueError("'columns' must be the name of an existing column")
    if (not methods.is_categorical_dtype(df[columns])):
        raise ValueError("'columns' must be category dtype")
    if (not has_known_categories(df[columns])):
        raise ValueError("'columns' must have known categories. Please use `df[columns].cat.as_known()` beforehand to ensure known categories")
    if (not ((is_list_like(values) and all([is_scalar(v) for v in values])) or is_scalar(values))):
        raise ValueError("'values' must refer to an existing column or columns")
    available_aggfuncs = ['mean', 'sum', 'count', 'first', 'last']
    if ((not is_scalar(aggfunc)) or (aggfunc not in available_aggfuncs)):
        raise ValueError(('aggfunc must be either ' + ', '.join((f"'{x}'" for x in available_aggfuncs))))
    columns_contents = pd.CategoricalIndex(df[columns].cat.categories, name=columns)
    if is_scalar(values):
        new_columns = columns_contents
    else:
        new_columns = pd.MultiIndex.from_product((sorted(values), columns_contents), names=[None, columns])
    if (aggfunc in ['first', 'last']):
        if is_scalar(values):
            meta = pd.DataFrame(columns=new_columns, dtype=df[values].dtype, index=pd.Index(df._meta[index]))
        else:
            meta = pd.DataFrame(columns=new_columns, index=pd.Index(df._meta[index]))
            for value_col in values:
                meta[value_col] = meta[value_col].astype(df[values].dtypes[value_col])
    else:
        meta = pd.DataFrame(columns=new_columns, dtype=np.float64, index=pd.Index(df._meta[index]))
    kwargs = {'index': index, 'columns': columns, 'values': values}
    if (aggfunc in ['sum', 'mean']):
        pv_sum = apply_concat_apply([df], chunk=methods.pivot_sum, aggregate=methods.pivot_agg, meta=meta, token='pivot_table_sum', chunk_kwargs=kwargs)
    if (aggfunc in ['count', 'mean']):
        pv_count = apply_concat_apply([df], chunk=methods.pivot_count, aggregate=methods.pivot_agg, meta=meta, token='pivot_table_count', chunk_kwargs=kwargs)
    if (aggfunc == 'sum'):
        return pv_sum
    elif (aggfunc == 'count'):
        return pv_count
    elif (aggfunc == 'mean'):
        return (pv_sum / pv_count)
    elif (aggfunc == 'first'):
        return apply_concat_apply([df], chunk=methods.pivot_first, aggregate=methods.pivot_agg_first, meta=meta, token='pivot_table_first', chunk_kwargs=kwargs)
    elif (aggfunc == 'last'):
        return apply_concat_apply([df], chunk=methods.pivot_last, aggregate=methods.pivot_agg_last, meta=meta, token='pivot_table_last', chunk_kwargs=kwargs)
    else:
        raise ValueError
Create a spreadsheet-style pivot table as a DataFrame. Target ``columns``
must have category dtype to infer result's ``columns``.
``index``, ``columns``, and ``aggfunc`` must be all scalar.
``values`` can be scalar or list-like.

Parameters
----------
df : DataFrame
index : scalar
    column to be index
columns : scalar
    column to be columns
values : scalar or list(scalar)
    column(s) to aggregate
aggfunc : {'mean', 'sum', 'count', 'first', 'last'}, default 'mean'

Returns
-------
table : DataFrame

See Also
--------
pandas.DataFrame.pivot_table
def pivot_table(df, index=None, columns=None, values=None, aggfunc='mean'):
    "\n    Create a spreadsheet-style pivot table as a DataFrame. Target ``columns``\n    must have category dtype to infer result's ``columns``.\n    ``index``, ``columns``, and ``aggfunc`` must be all scalar.\n    ``values`` can be scalar or list-like.\n\n    Parameters\n    ----------\n    df : DataFrame\n    index : scalar\n        column to be index\n    columns : scalar\n        column to be columns\n    values : scalar or list(scalar)\n        column(s) to aggregate\n    aggfunc : {'mean', 'sum', 'count', 'first', 'last'}, default 'mean'\n\n    Returns\n    -------\n    table : DataFrame\n\n    See Also\n    --------\n    pandas.DataFrame.pivot_table\n    "
    if ((not is_scalar(index)) or (index is None)):
        raise ValueError("'index' must be the name of an existing column")
    if ((not is_scalar(columns)) or (columns is None)):
        raise ValueError("'columns' must be the name of an existing column")
    if (not methods.is_categorical_dtype(df[columns])):
        raise ValueError("'columns' must be category dtype")
    if (not has_known_categories(df[columns])):
        raise ValueError("'columns' must have known categories. Please use `df[columns].cat.as_known()` beforehand to ensure known categories")
    if (not ((is_list_like(values) and all([is_scalar(v) for v in values])) or is_scalar(values))):
        raise ValueError("'values' must refer to an existing column or columns")
    available_aggfuncs = ['mean', 'sum', 'count', 'first', 'last']
    if ((not is_scalar(aggfunc)) or (aggfunc not in available_aggfuncs)):
        raise ValueError(('aggfunc must be either ' + ', '.join((f"'{x}'" for x in available_aggfuncs))))
    columns_contents = pd.CategoricalIndex(df[columns].cat.categories, name=columns)
    if is_scalar(values):
        new_columns = columns_contents
    else:
        new_columns = pd.MultiIndex.from_product((sorted(values), columns_contents), names=[None, columns])
    if (aggfunc in ['first', 'last']):
        if is_scalar(values):
            meta = pd.DataFrame(columns=new_columns, dtype=df[values].dtype, index=pd.Index(df._meta[index]))
        else:
            meta = pd.DataFrame(columns=new_columns, index=pd.Index(df._meta[index]))
            for value_col in values:
                meta[value_col] = meta[value_col].astype(df[values].dtypes[value_col])
    else:
        meta = pd.DataFrame(columns=new_columns, dtype=np.float64, index=pd.Index(df._meta[index]))
    kwargs = {'index': index, 'columns': columns, 'values': values}
    if (aggfunc in ['sum', 'mean']):
        pv_sum = apply_concat_apply([df], chunk=methods.pivot_sum, aggregate=methods.pivot_agg, meta=meta, token='pivot_table_sum', chunk_kwargs=kwargs)
    if (aggfunc in ['count', 'mean']):
        pv_count = apply_concat_apply([df], chunk=methods.pivot_count, aggregate=methods.pivot_agg, meta=meta, token='pivot_table_count', chunk_kwargs=kwargs)
    if (aggfunc == 'sum'):
        return pv_sum
    elif (aggfunc == 'count'):
        return pv_count
    elif (aggfunc == 'mean'):
        return (pv_sum / pv_count)
    elif (aggfunc == 'first'):
        return apply_concat_apply([df], chunk=methods.pivot_first, aggregate=methods.pivot_agg_first, meta=meta, token='pivot_table_first', chunk_kwargs=kwargs)
    elif (aggfunc == 'last'):
        return apply_concat_apply([df], chunk=methods.pivot_last, aggregate=methods.pivot_agg_last, meta=meta, token='pivot_table_last', chunk_kwargs=kwargs)
    else:
        raise ValueError