janitor/utils.py
def _computations_pivot_wider(
    df: pd.DataFrame,
    index: Optional[Union[List, str]] = None,
    names_from: Optional[Union[List, str]] = None,
    values_from: Optional[Union[List, str]] = None,
    names_sort: Optional[bool] = False,
    flatten_levels: Optional[bool] = True,
    values_from_first: Optional[bool] = True,
    names_prefix: Optional[str] = None,
    names_sep: Optional[str] = "_",
    fill_value: Optional[Union[int, float, str]] = None,
) -> pd.DataFrame:
    """
    This is the main workhorse of the `pivot_wider` function.
    If `values_from` is a list, then every item in `values_from`
    will be added to the front of each output column. This option
    can be turned off with the `values_from_first` argument, in
    which case, the `names_from` variables (or `names_prefix`, if
    present) start each column.
    The `unstack` method is used here, and not `pivot`; multiple
    labels in the `index` or `names_from` are supported in the
    `pivot` function for Pandas 1.1 and above. Also, the
    `pivot_table` function is not used, because it is quite slow,
    compared to the `pivot` function and `unstack`.
    The columns are sorted in the order of appearance from the
    source data. This only occurs if `flatten_levels` is True.
    """

    # TODO : include an aggfunc argument
    if values_from is None:
        if index:
            values_from = [
                col for col in df.columns if col not in (index + names_from)
            ]
        else:
            values_from = [col for col in df.columns if col not in names_from]

    dtypes = None
    before = None
    # ensure `names_sort` is in combination with `flatten_levels`
    if all((names_sort is False, flatten_levels)):
        # dtypes only needed for names_from
        # since that is what will become the new column names
        dtypes = {
            column_name: CategoricalDtype(
                categories=column.unique(), ordered=True
            )
            for column_name, column in df.filter(names_from).items()
        }
        if index is not None:
            before = df.filter(index)
            if before.duplicated().any():
                before = before.drop_duplicates()

        df = df.astype(dtypes)

    if index is None:  # use existing index
        df = df.set_index(names_from, append=True)
    else:
        df = df.set_index(index + names_from)

    if not df.index.is_unique:
        raise ValueError(
            """
            There are non-unique values in your combination
            of `index` and `names_from`. Kindly provide a
            unique identifier for each row.
            """
        )

    df = df.loc[:, values_from]
    df = df.unstack(names_from, fill_value=fill_value)  # noqa: PD010
    if flatten_levels:
        if isinstance(values_from, list):
            df.columns = df.columns.set_names(level=0, names="values_from")
            if not values_from_first:
                df = df.reorder_levels(names_from + ["values_from"], axis=1)
        if df.columns.nlevels > 1:
            df.columns = [names_sep.join(entry) for entry in df]
        if names_prefix:
            df = df.add_prefix(names_prefix)
        df.columns = list(
            df.columns
        )  # blanket approach that covers categories

        if index:
            # this way we avoid having to convert index
            # from category to original dtype
            # while still maintaining order of appearance
            if names_sort is False:
                df = before.merge(
                    df, how="left", left_on=index, right_index=True
                ).reset_index(drop=True)
            else:
                df = df.reset_index()
        else:
            # remove default index, since it is irrelevant
            df = df.reset_index().iloc[:, 1:]

        return df

    return df

    This is the main workhorse of the `pivot_wider` function.
    If `values_from` is a list, then every item in `values_from`
    will be added to the front of each output column. This option
    can be turned off with the `values_from_first` argument, in
    which case, the `names_from` variables (or `names_prefix`, if
    present) start each column.
    The `unstack` method is used here, and not `pivot`; multiple
    labels in the `index` or `names_from` are supported in the
    `pivot` function for Pandas 1.1 and above. Also, the
    `pivot_table` function is not used, because it is quite slow,
    compared to the `pivot` function and `unstack`.
    The columns are sorted in the order of appearance from the
    source data. This only occurs if `flatten_levels` is True.
    
This is the main workhorse of the `pivot_wider` function.
If `values_from` is a list, then every item in `values_from`
will be added to the front of each output column.
This is the main workhorse of the ` pivot_wider ` function . If ` values_from ` is a list then every item in ` values_from ` will be added to the front of each output column .
def _computations_pivot_wider(
    df: pd.DataFrame,
    index: Optional[Union[List, str]] = None,
    names_from: Optional[Union[List, str]] = None,
    values_from: Optional[Union[List, str]] = None,
    names_sort: Optional[bool] = False,
    flatten_levels: Optional[bool] = True,
    values_from_first: Optional[bool] = True,
    names_prefix: Optional[str] = None,
    names_sep: Optional[str] = "_",
    fill_value: Optional[Union[int, float, str]] = None,
) -> pd.DataFrame:
    if values_from is None:
        if index:
            values_from = [
                col for col in df.columns if col not in (index + names_from)
            ]
        else:
            values_from = [col for col in df.columns if col not in names_from]
    dtypes = None
    before = None
    if all((names_sort is False, flatten_levels)):
        dtypes = {
            column_name: CategoricalDtype(
                categories=column.unique(), ordered=True
            )
            for column_name, column in df.filter(names_from).items()
        }
        if index is not None:
            before = df.filter(index)
            if before.duplicated().any():
                before = before.drop_duplicates()
        df = df.astype(dtypes)
    if index is None:  
        df = df.set_index(names_from, append=True)
    else:
        df = df.set_index(index + names_from)
    if not df.index.is_unique:
        raise ValueError(
            """
            There are non-unique values in your combination
            of `index` and `names_from`. Kindly provide a
            unique identifier for each row.
            """
        )
    df = df.loc[:, values_from]
    df = df.unstack(names_from, fill_value=fill_value)  
    if flatten_levels:
        if isinstance(values_from, list):
            df.columns = df.columns.set_names(level=0, names="values_from")
            if not values_from_first:
                df = df.reorder_levels(names_from + ["values_from"], axis=1)
        if df.columns.nlevels > 1:
            df.columns = [names_sep.join(entry) for entry in df]
        if names_prefix:
            df = df.add_prefix(names_prefix)
        df.columns = list(
            df.columns
        )  
        if index:
            if names_sort is False:
                df = before.merge(
                    df, how="left", left_on=index, right_index=True
                ).reset_index(drop=True)
            else:
                df = df.reset_index()
        else:
            df = df.reset_index().iloc[:, 1:]
        return df
    return df
def _computations_pivot_wider ( df : pd . DataFrame , index : Optional [ Union [ List , str ] ] = None , names_from : Optional [ Union [ List , str ] ] = None , values_from : Optional [ Union [ List , str ] ] = None , names_sort : Optional [ bool ] = False , flatten_levels : Optional [ bool ] = True , values_from_first : Optional [ bool ] = True , names_prefix : Optional [ str ] = None , names_sep : Optional [ str ] = "_" , fill_value : Optional [ Union [ int , float , str ] ] = None , ) -> pd . DataFrame : if values_from is None : if index : values_from = [ col for col in df . columns if col not in ( index + names_from ) ] else : values_from = [ col for col in df . columns if col not in names_from ] dtypes = None before = None if all ( ( names_sort is False , flatten_levels ) ) : dtypes = { column_name : CategoricalDtype ( categories = column . unique ( ) , ordered = True ) for column_name , column in df . filter ( names_from ) . items ( ) } if index is not None : before = df . filter ( index ) if before . duplicated ( ) . any ( ) : before = before . drop_duplicates ( ) df = df . astype ( dtypes ) if index is None : df = df . set_index ( names_from , append = True ) else : df = df . set_index ( index + names_from ) if not df . index . is_unique : raise ValueError ( """
            There are non-unique values in your combination
            of `index` and `names_from`. Kindly provide a
            unique identifier for each row.
            """ ) df = df . loc [ : , values_from ] df = df . unstack ( names_from , fill_value = fill_value ) if flatten_levels : if isinstance ( values_from , list ) : df . columns = df . columns . set_names ( level = 0 , names = "values_from" ) if not values_from_first : df = df . reorder_levels ( names_from + [ "values_from" ] , axis = 1 ) if df . columns . nlevels > 1 : df . columns = [ names_sep . join ( entry ) for entry in df ] if names_prefix : df = df . add_prefix ( names_prefix ) df . columns = list ( df . columns ) if index : if names_sort is False : df = before . merge ( df , how = "left" , left_on = index , right_index = True ) . reset_index ( drop = True ) else : df = df . reset_index ( ) else : df = df . reset_index ( ) . iloc [ : , 1 : ] return df return df
This is the main workhorse of the `pivot_wider` function.
This is the main workhorse of the ` pivot_wider ` function .
"""
    This is the main workhorse of the `pivot_wider` function.
    If `values_from` is a list, then every item in `values_from`
    will be added to the front of each output column. This option
    can be turned off with the `values_from_first` argument, in
    which case, the `names_from` variables (or `names_prefix`, if
    present) start each column.
    The `unstack` method is used here, and not `pivot`; multiple
    labels in the `index` or `names_from` are supported in the
    `pivot` function for Pandas 1.1 and above. Also, the
    `pivot_table` function is not used, because it is quite slow,
    compared to the `pivot` function and `unstack`.
    The columns are sorted in the order of appearance from the
    source data. This only occurs if `flatten_levels` is True.
    """ # TODO : include an aggfunc argument # ensure `names_sort` is in combination with `flatten_levels` # dtypes only needed for names_from # since that is what will become the new column names # use existing index # noqa: PD010 # blanket approach that covers categories # this way we avoid having to convert index # from category to original dtype # while still maintaining order of appearance # remove default index, since it is irrelevant
df
pd.DataFrame
index
Optional[Union[List, str]]
names_from
Optional[Union[List, str]]
values_from
Optional[Union[List, str]]
names_sort
Optional[bool]
flatten_levels
Optional[bool]
values_from_first
Optional[bool]
names_prefix
Optional[str]
names_sep
Optional[str]
fill_value
Optional[Union[int, float, str]]