def pivot_table(self, values: Optional[Union[(Name, List[Name])]]=None, index: Optional[List[Name]]=None, columns: Optional[Name]=None, aggfunc: Union[(str, Dict[(Name, str)])]='mean', fill_value: Optional[Any]=None) -> 'DataFrame':
    '\n        Create a spreadsheet-style pivot table as a DataFrame. The levels in\n        the pivot table will be stored in MultiIndex objects (hierarchical\n        indexes) on the index and columns of the result DataFrame.\n\n        Parameters\n        ----------\n        values : column to aggregate.\n            They should be either a list less than three or a string.\n        index : column (string) or list of columns\n            If an array is passed, it must be the same length as the data.\n            The list should contain string.\n        columns : column\n            Columns used in the pivot operation. Only one column is supported and\n            it should be a string.\n        aggfunc : function (string), dict, default mean\n            If dict is passed, the key is column to aggregate and value\n            is function or list of functions.\n        fill_value : scalar, default None\n            Value to replace missing values with.\n\n        Returns\n        -------\n        table : DataFrame\n\n        Examples\n        --------\n        >>> df = ps.DataFrame({"A": ["foo", "foo", "foo", "foo", "foo",\n        ...                          "bar", "bar", "bar", "bar"],\n        ...                    "B": ["one", "one", "one", "two", "two",\n        ...                          "one", "one", "two", "two"],\n        ...                    "C": ["small", "large", "large", "small",\n        ...                          "small", "large", "small", "small",\n        ...                          "large"],\n        ...                    "D": [1, 2, 2, 3, 3, 4, 5, 6, 7],\n        ...                    "E": [2, 4, 5, 5, 6, 6, 8, 9, 9]},\n        ...                   columns=[\'A\', \'B\', \'C\', \'D\', \'E\'])\n        >>> df\n             A    B      C  D  E\n        0  foo  one  small  1  2\n        1  foo  one  large  2  4\n        2  foo  one  large  2  5\n        3  foo  two  small  3  5\n        4  foo  two  small  3  6\n        5  bar  one  large  4  6\n        6  bar  one  small  5  8\n        7  bar  two  small  6  9\n        8  bar  two  large  7  9\n\n        This first example aggregates values by taking the sum.\n\n        >>> table = df.pivot_table(values=\'D\', index=[\'A\', \'B\'],\n        ...                        columns=\'C\', aggfunc=\'sum\')\n        >>> table.sort_index()  # doctest: +NORMALIZE_WHITESPACE\n        C        large  small\n        A   B\n        bar one    4.0      5\n            two    7.0      6\n        foo one    4.0      1\n            two    NaN      6\n\n        We can also fill missing values using the `fill_value` parameter.\n\n        >>> table = df.pivot_table(values=\'D\', index=[\'A\', \'B\'],\n        ...                        columns=\'C\', aggfunc=\'sum\', fill_value=0)\n        >>> table.sort_index()  # doctest: +NORMALIZE_WHITESPACE\n        C        large  small\n        A   B\n        bar one      4      5\n            two      7      6\n        foo one      4      1\n            two      0      6\n\n        We can also calculate multiple types of aggregations for any given\n        value column.\n\n        >>> table = df.pivot_table(values=[\'D\'], index =[\'C\'],\n        ...                        columns="A", aggfunc={\'D\': \'mean\'})\n        >>> table.sort_index()  # doctest: +NORMALIZE_WHITESPACE\n                 D\n        A      bar       foo\n        C\n        large  5.5  2.000000\n        small  5.5  2.333333\n\n        The next example aggregates on multiple values.\n\n        >>> table = df.pivot_table(index=[\'C\'], columns="A", values=[\'D\', \'E\'],\n        ...                         aggfunc={\'D\': \'mean\', \'E\': \'sum\'})\n        >>> table.sort_index() # doctest: +NORMALIZE_WHITESPACE\n                 D             E\n        A      bar       foo bar foo\n        C\n        large  5.5  2.000000  15   9\n        small  5.5  2.333333  17  13\n        '
    if (not is_name_like_value(columns)):
        raise TypeError('columns should be one column name.')
    if ((not is_name_like_value(values)) and (not (isinstance(values, list) and all((is_name_like_value(v) for v in values))))):
        raise TypeError('values should be one column or list of columns.')
    if ((not isinstance(aggfunc, str)) and ((not isinstance(aggfunc, dict)) or (not all(((is_name_like_value(key) and isinstance(value, str)) for (key, value) in aggfunc.items()))))):
        raise TypeError('aggfunc must be a dict mapping from column name to aggregate functions (string).')
    if (isinstance(aggfunc, dict) and (index is None)):
        raise NotImplementedError("pivot_table doesn't support aggfunc as dict and without index.")
    if (isinstance(values, list) and (index is None)):
        raise NotImplementedError("values can't be a list without index.")
    if (columns not in self.columns):
        raise ValueError('Wrong columns {}.'.format(name_like_string(columns)))
    if (not is_name_like_tuple(columns)):
        columns = (columns,)
    if isinstance(values, list):
        values = [(col if is_name_like_tuple(col) else (col,)) for col in values]
        if (not all((isinstance(self._internal.spark_type_for(col), NumericType) for col in values))):
            raise TypeError('values should be a numeric type.')
    else:
        values = (values if is_name_like_tuple(values) else (values,))
        if (not isinstance(self._internal.spark_type_for(values), NumericType)):
            raise TypeError('values should be a numeric type.')
    if isinstance(aggfunc, str):
        if isinstance(values, list):
            agg_cols = [F.expr('{1}(`{0}`) as `{0}`'.format(self._internal.spark_column_name_for(value), aggfunc)) for value in values]
        else:
            agg_cols = [F.expr('{1}(`{0}`) as `{0}`'.format(self._internal.spark_column_name_for(values), aggfunc))]
    elif isinstance(aggfunc, dict):
        aggfunc = {(key if is_name_like_tuple(key) else (key,)): value for (key, value) in aggfunc.items()}
        agg_cols = [F.expr('{1}(`{0}`) as `{0}`'.format(self._internal.spark_column_name_for(key), value)) for (key, value) in aggfunc.items()]
        agg_columns = [key for (key, _) in aggfunc.items()]
        if (set(agg_columns) != set(values)):
            raise ValueError('Columns in aggfunc must be the same as values.')
    sdf = self._internal.resolved_copy.spark_frame
    if (index is None):
        sdf = sdf.groupBy().pivot(pivot_col=self._internal.spark_column_name_for(columns)).agg(*agg_cols)
    elif isinstance(index, list):
        index = [(label if is_name_like_tuple(label) else (label,)) for label in index]
        sdf = sdf.groupBy([self._internal.spark_column_name_for(label) for label in index]).pivot(pivot_col=self._internal.spark_column_name_for(columns)).agg(*agg_cols)
    else:
        raise TypeError('index should be a None or a list of columns.')
    if ((fill_value is not None) and isinstance(fill_value, (int, float))):
        sdf = sdf.fillna(fill_value)
    psdf: DataFrame
    if (index is not None):
        index_columns = [self._internal.spark_column_name_for(label) for label in index]
        index_fields = [self._internal.field_for(label) for label in index]
        if isinstance(values, list):
            data_columns = [column for column in sdf.columns if (column not in index_columns)]
            if (len(values) > 1):
                data_columns.sort(key=(lambda x: x.split('_', 1)[1]))
                sdf = sdf.select((index_columns + data_columns))
                column_name_to_index = dict(zip(self._internal.data_spark_column_names, self._internal.column_labels))
                column_labels = [tuple((list(column_name_to_index[name.split('_')[1]]) + [name.split('_')[0]])) for name in data_columns]
                column_label_names = (([cast(Optional[Name], None)] * column_labels_level(values)) + [columns])
                internal = InternalFrame(spark_frame=sdf, index_spark_columns=[scol_for(sdf, col) for col in index_columns], index_names=index, index_fields=index_fields, column_labels=column_labels, data_spark_columns=[scol_for(sdf, col) for col in data_columns], column_label_names=column_label_names)
                psdf = DataFrame(internal)
            else:
                column_labels = [tuple((list(values[0]) + [column])) for column in data_columns]
                column_label_names = (([cast(Optional[Name], None)] * len(values[0])) + [columns])
                internal = InternalFrame(spark_frame=sdf, index_spark_columns=[scol_for(sdf, col) for col in index_columns], index_names=index, index_fields=index_fields, column_labels=column_labels, data_spark_columns=[scol_for(sdf, col) for col in data_columns], column_label_names=column_label_names)
                psdf = DataFrame(internal)
        else:
            internal = InternalFrame(spark_frame=sdf, index_spark_columns=[scol_for(sdf, col) for col in index_columns], index_names=index, index_fields=index_fields, column_label_names=[columns])
            psdf = DataFrame(internal)
    else:
        if isinstance(values, list):
            index_values = values[(- 1)]
        else:
            index_values = values
        index_map: Dict[(str, Optional[Label])] = {}
        for (i, index_value) in enumerate(index_values):
            colname = SPARK_INDEX_NAME_FORMAT(i)
            sdf = sdf.withColumn(colname, SF.lit(index_value))
            index_map[colname] = None
        internal = InternalFrame(spark_frame=sdf, index_spark_columns=[scol_for(sdf, col) for col in index_map.keys()], index_names=list(index_map.values()), column_label_names=[columns])
        psdf = DataFrame(internal)
    psdf_columns = psdf.columns
    if isinstance(psdf_columns, pd.MultiIndex):
        psdf.columns = psdf_columns.set_levels(psdf_columns.levels[(- 1)].astype(spark_type_to_pandas_dtype(self._psser_for(columns).spark.data_type)), level=(- 1))
    else:
        psdf.columns = psdf_columns.astype(spark_type_to_pandas_dtype(self._psser_for(columns).spark.data_type))
    return psdf
Create a spreadsheet-style pivot table as a DataFrame. The levels in
the pivot table will be stored in MultiIndex objects (hierarchical
indexes) on the index and columns of the result DataFrame.

Parameters
----------
values : column to aggregate.
    They should be either a list less than three or a string.
index : column (string) or list of columns
    If an array is passed, it must be the same length as the data.
    The list should contain string.
columns : column
    Columns used in the pivot operation. Only one column is supported and
    it should be a string.
aggfunc : function (string), dict, default mean
    If dict is passed, the key is column to aggregate and value
    is function or list of functions.
fill_value : scalar, default None
    Value to replace missing values with.

Returns
-------
table : DataFrame

Examples
--------
>>> df = ps.DataFrame({"A": ["foo", "foo", "foo", "foo", "foo",
...                          "bar", "bar", "bar", "bar"],
...                    "B": ["one", "one", "one", "two", "two",
...                          "one", "one", "two", "two"],
...                    "C": ["small", "large", "large", "small",
...                          "small", "large", "small", "small",
...                          "large"],
...                    "D": [1, 2, 2, 3, 3, 4, 5, 6, 7],
...                    "E": [2, 4, 5, 5, 6, 6, 8, 9, 9]},
...                   columns=['A', 'B', 'C', 'D', 'E'])
>>> df
     A    B      C  D  E
0  foo  one  small  1  2
1  foo  one  large  2  4
2  foo  one  large  2  5
3  foo  two  small  3  5
4  foo  two  small  3  6
5  bar  one  large  4  6
6  bar  one  small  5  8
7  bar  two  small  6  9
8  bar  two  large  7  9

This first example aggregates values by taking the sum.

>>> table = df.pivot_table(values='D', index=['A', 'B'],
...                        columns='C', aggfunc='sum')
>>> table.sort_index()  # doctest: +NORMALIZE_WHITESPACE
C        large  small
A   B
bar one    4.0      5
    two    7.0      6
foo one    4.0      1
    two    NaN      6

We can also fill missing values using the `fill_value` parameter.

>>> table = df.pivot_table(values='D', index=['A', 'B'],
...                        columns='C', aggfunc='sum', fill_value=0)
>>> table.sort_index()  # doctest: +NORMALIZE_WHITESPACE
C        large  small
A   B
bar one      4      5
    two      7      6
foo one      4      1
    two      0      6

We can also calculate multiple types of aggregations for any given
value column.

>>> table = df.pivot_table(values=['D'], index =['C'],
...                        columns="A", aggfunc={'D': 'mean'})
>>> table.sort_index()  # doctest: +NORMALIZE_WHITESPACE
         D
A      bar       foo
C
large  5.5  2.000000
small  5.5  2.333333

The next example aggregates on multiple values.

>>> table = df.pivot_table(index=['C'], columns="A", values=['D', 'E'],
...                         aggfunc={'D': 'mean', 'E': 'sum'})
>>> table.sort_index() # doctest: +NORMALIZE_WHITESPACE
         D             E
A      bar       foo bar foo
C
large  5.5  2.000000  15   9
small  5.5  2.333333  17  13
def pivot_table(self, values: Optional[Union[(Name, List[Name])]]=None, index: Optional[List[Name]]=None, columns: Optional[Name]=None, aggfunc: Union[(str, Dict[(Name, str)])]='mean', fill_value: Optional[Any]=None) -> 'DataFrame':
    '\n        Create a spreadsheet-style pivot table as a DataFrame. The levels in\n        the pivot table will be stored in MultiIndex objects (hierarchical\n        indexes) on the index and columns of the result DataFrame.\n\n        Parameters\n        ----------\n        values : column to aggregate.\n            They should be either a list less than three or a string.\n        index : column (string) or list of columns\n            If an array is passed, it must be the same length as the data.\n            The list should contain string.\n        columns : column\n            Columns used in the pivot operation. Only one column is supported and\n            it should be a string.\n        aggfunc : function (string), dict, default mean\n            If dict is passed, the key is column to aggregate and value\n            is function or list of functions.\n        fill_value : scalar, default None\n            Value to replace missing values with.\n\n        Returns\n        -------\n        table : DataFrame\n\n        Examples\n        --------\n        >>> df = ps.DataFrame({"A": ["foo", "foo", "foo", "foo", "foo",\n        ...                          "bar", "bar", "bar", "bar"],\n        ...                    "B": ["one", "one", "one", "two", "two",\n        ...                          "one", "one", "two", "two"],\n        ...                    "C": ["small", "large", "large", "small",\n        ...                          "small", "large", "small", "small",\n        ...                          "large"],\n        ...                    "D": [1, 2, 2, 3, 3, 4, 5, 6, 7],\n        ...                    "E": [2, 4, 5, 5, 6, 6, 8, 9, 9]},\n        ...                   columns=[\'A\', \'B\', \'C\', \'D\', \'E\'])\n        >>> df\n             A    B      C  D  E\n        0  foo  one  small  1  2\n        1  foo  one  large  2  4\n        2  foo  one  large  2  5\n        3  foo  two  small  3  5\n        4  foo  two  small  3  6\n        5  bar  one  large  4  6\n        6  bar  one  small  5  8\n        7  bar  two  small  6  9\n        8  bar  two  large  7  9\n\n        This first example aggregates values by taking the sum.\n\n        >>> table = df.pivot_table(values=\'D\', index=[\'A\', \'B\'],\n        ...                        columns=\'C\', aggfunc=\'sum\')\n        >>> table.sort_index()  # doctest: +NORMALIZE_WHITESPACE\n        C        large  small\n        A   B\n        bar one    4.0      5\n            two    7.0      6\n        foo one    4.0      1\n            two    NaN      6\n\n        We can also fill missing values using the `fill_value` parameter.\n\n        >>> table = df.pivot_table(values=\'D\', index=[\'A\', \'B\'],\n        ...                        columns=\'C\', aggfunc=\'sum\', fill_value=0)\n        >>> table.sort_index()  # doctest: +NORMALIZE_WHITESPACE\n        C        large  small\n        A   B\n        bar one      4      5\n            two      7      6\n        foo one      4      1\n            two      0      6\n\n        We can also calculate multiple types of aggregations for any given\n        value column.\n\n        >>> table = df.pivot_table(values=[\'D\'], index =[\'C\'],\n        ...                        columns="A", aggfunc={\'D\': \'mean\'})\n        >>> table.sort_index()  # doctest: +NORMALIZE_WHITESPACE\n                 D\n        A      bar       foo\n        C\n        large  5.5  2.000000\n        small  5.5  2.333333\n\n        The next example aggregates on multiple values.\n\n        >>> table = df.pivot_table(index=[\'C\'], columns="A", values=[\'D\', \'E\'],\n        ...                         aggfunc={\'D\': \'mean\', \'E\': \'sum\'})\n        >>> table.sort_index() # doctest: +NORMALIZE_WHITESPACE\n                 D             E\n        A      bar       foo bar foo\n        C\n        large  5.5  2.000000  15   9\n        small  5.5  2.333333  17  13\n        '
    if (not is_name_like_value(columns)):
        raise TypeError('columns should be one column name.')
    if ((not is_name_like_value(values)) and (not (isinstance(values, list) and all((is_name_like_value(v) for v in values))))):
        raise TypeError('values should be one column or list of columns.')
    if ((not isinstance(aggfunc, str)) and ((not isinstance(aggfunc, dict)) or (not all(((is_name_like_value(key) and isinstance(value, str)) for (key, value) in aggfunc.items()))))):
        raise TypeError('aggfunc must be a dict mapping from column name to aggregate functions (string).')
    if (isinstance(aggfunc, dict) and (index is None)):
        raise NotImplementedError("pivot_table doesn't support aggfunc as dict and without index.")
    if (isinstance(values, list) and (index is None)):
        raise NotImplementedError("values can't be a list without index.")
    if (columns not in self.columns):
        raise ValueError('Wrong columns {}.'.format(name_like_string(columns)))
    if (not is_name_like_tuple(columns)):
        columns = (columns,)
    if isinstance(values, list):
        values = [(col if is_name_like_tuple(col) else (col,)) for col in values]
        if (not all((isinstance(self._internal.spark_type_for(col), NumericType) for col in values))):
            raise TypeError('values should be a numeric type.')
    else:
        values = (values if is_name_like_tuple(values) else (values,))
        if (not isinstance(self._internal.spark_type_for(values), NumericType)):
            raise TypeError('values should be a numeric type.')
    if isinstance(aggfunc, str):
        if isinstance(values, list):
            agg_cols = [F.expr('{1}(`{0}`) as `{0}`'.format(self._internal.spark_column_name_for(value), aggfunc)) for value in values]
        else:
            agg_cols = [F.expr('{1}(`{0}`) as `{0}`'.format(self._internal.spark_column_name_for(values), aggfunc))]
    elif isinstance(aggfunc, dict):
        aggfunc = {(key if is_name_like_tuple(key) else (key,)): value for (key, value) in aggfunc.items()}
        agg_cols = [F.expr('{1}(`{0}`) as `{0}`'.format(self._internal.spark_column_name_for(key), value)) for (key, value) in aggfunc.items()]
        agg_columns = [key for (key, _) in aggfunc.items()]
        if (set(agg_columns) != set(values)):
            raise ValueError('Columns in aggfunc must be the same as values.')
    sdf = self._internal.resolved_copy.spark_frame
    if (index is None):
        sdf = sdf.groupBy().pivot(pivot_col=self._internal.spark_column_name_for(columns)).agg(*agg_cols)
    elif isinstance(index, list):
        index = [(label if is_name_like_tuple(label) else (label,)) for label in index]
        sdf = sdf.groupBy([self._internal.spark_column_name_for(label) for label in index]).pivot(pivot_col=self._internal.spark_column_name_for(columns)).agg(*agg_cols)
    else:
        raise TypeError('index should be a None or a list of columns.')
    if ((fill_value is not None) and isinstance(fill_value, (int, float))):
        sdf = sdf.fillna(fill_value)
    psdf: DataFrame
    if (index is not None):
        index_columns = [self._internal.spark_column_name_for(label) for label in index]
        index_fields = [self._internal.field_for(label) for label in index]
        if isinstance(values, list):
            data_columns = [column for column in sdf.columns if (column not in index_columns)]
            if (len(values) > 1):
                data_columns.sort(key=(lambda x: x.split('_', 1)[1]))
                sdf = sdf.select((index_columns + data_columns))
                column_name_to_index = dict(zip(self._internal.data_spark_column_names, self._internal.column_labels))
                column_labels = [tuple((list(column_name_to_index[name.split('_')[1]]) + [name.split('_')[0]])) for name in data_columns]
                column_label_names = (([cast(Optional[Name], None)] * column_labels_level(values)) + [columns])
                internal = InternalFrame(spark_frame=sdf, index_spark_columns=[scol_for(sdf, col) for col in index_columns], index_names=index, index_fields=index_fields, column_labels=column_labels, data_spark_columns=[scol_for(sdf, col) for col in data_columns], column_label_names=column_label_names)
                psdf = DataFrame(internal)
            else:
                column_labels = [tuple((list(values[0]) + [column])) for column in data_columns]
                column_label_names = (([cast(Optional[Name], None)] * len(values[0])) + [columns])
                internal = InternalFrame(spark_frame=sdf, index_spark_columns=[scol_for(sdf, col) for col in index_columns], index_names=index, index_fields=index_fields, column_labels=column_labels, data_spark_columns=[scol_for(sdf, col) for col in data_columns], column_label_names=column_label_names)
                psdf = DataFrame(internal)
        else:
            internal = InternalFrame(spark_frame=sdf, index_spark_columns=[scol_for(sdf, col) for col in index_columns], index_names=index, index_fields=index_fields, column_label_names=[columns])
            psdf = DataFrame(internal)
    else:
        if isinstance(values, list):
            index_values = values[(- 1)]
        else:
            index_values = values
        index_map: Dict[(str, Optional[Label])] = {}
        for (i, index_value) in enumerate(index_values):
            colname = SPARK_INDEX_NAME_FORMAT(i)
            sdf = sdf.withColumn(colname, SF.lit(index_value))
            index_map[colname] = None
        internal = InternalFrame(spark_frame=sdf, index_spark_columns=[scol_for(sdf, col) for col in index_map.keys()], index_names=list(index_map.values()), column_label_names=[columns])
        psdf = DataFrame(internal)
    psdf_columns = psdf.columns
    if isinstance(psdf_columns, pd.MultiIndex):
        psdf.columns = psdf_columns.set_levels(psdf_columns.levels[(- 1)].astype(spark_type_to_pandas_dtype(self._psser_for(columns).spark.data_type)), level=(- 1))
    else:
        psdf.columns = psdf_columns.astype(spark_type_to_pandas_dtype(self._psser_for(columns).spark.data_type))
    return psdf