Melts the specified columns in your DataFrame into two key:value columns.

    Args:
        key (str): Name of identifier column.
        values (str): Name of column that will contain values for the key.
        *args (str, int, symbolic): Columns to "melt" into the new key and
            value columns. If no args are specified, all columns are melted
            into they key and value columns.

    Kwargs:
        add_id (bool): Boolean value indicating whether to add a `"_ID"`
            column that will preserve information about the original rows
            (useful for being able to re-widen the data later).

    Example:
        diamonds >> gather('variable', 'value', ['price', 'depth','x','y','z']) >> head(5)

           carat      cut color clarity  table variable  value
        0   0.23    Ideal     E     SI2   55.0    price  326.0
        1   0.21  Premium     E     SI1   61.0    price  326.0
        2   0.23     Good     E     VS1   65.0    price  327.0
        3   0.29  Premium     I     VS2   58.0    price  334.0
        4   0.31     Good     J     SI2   58.0    price  335.0

def gather(df, key, values, *args, **kwargs):
    """
    Melts the specified columns in your DataFrame into two key:value columns.

    Args:
        key (str): Name of identifier column.
        values (str): Name of column that will contain values for the key.
        *args (str, int, symbolic): Columns to "melt" into the new key and
            value columns. If no args are specified, all columns are melted
            into they key and value columns.

    Kwargs:
        add_id (bool): Boolean value indicating whether to add a `"_ID"`
            column that will preserve information about the original rows
            (useful for being able to re-widen the data later).

    Example:
        diamonds >> gather('variable', 'value', ['price', 'depth','x','y','z']) >> head(5)

           carat      cut color clarity  table variable  value
        0   0.23    Ideal     E     SI2   55.0    price  326.0
        1   0.21  Premium     E     SI1   61.0    price  326.0
        2   0.23     Good     E     VS1   65.0    price  327.0
        3   0.29  Premium     I     VS2   58.0    price  334.0
        4   0.31     Good     J     SI2   58.0    price  335.0
    """

    if len(args) == 0:
        args = df.columns.tolist()
    else:
        args = [a for a in flatten(args)]

    if kwargs.get('add_id', False):
        df = df.assign(_ID=np.arange(df.shape[0]))

    columns = df.columns.tolist()
    id_vars = [col for col in columns if col not in args]
    return pd.melt(df, id_vars, list(args), key, values)