<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def unite(df, colname, *args, **kwargs):
 """ Does the inverse of `separate`, joining columns together by a specified separator. Any columns that are not strings will be converted to strings. Args: df (pandas.DataFrame):
 DataFrame passed in through the pipe. colname (str):
 the name of the new joined column. *args: list of columns to be joined, which can be strings, symbolic, or integer positions. Kwargs: sep (str):
 the string separator to join the columns with. remove (bool):
 Boolean indicating whether or not to remove the original columns. na_action (str):
 can be one of `'maintain'` (the default), '`ignore'`, or `'as_string'`. The default will make the new column row a `NaN` value if any of the original column cells at that row contained `NaN`. '`ignore'` will treat any `NaN` value as an empty string during joining. `'as_string'` will convert any `NaN` value to the string `'nan'` prior to joining. """


    to_unite = list([a for a in flatten(args)])
    sep = kwargs.get('sep', '_')
    remove = kwargs.get('remove', True)
    # possible na_action values
    # ignore: empty string
    # maintain: keep as np.nan (default)
    # as_string: becomes string 'nan'
    na_action = kwargs.get('na_action', 'maintain')

    # print(to_unite, sep, remove, na_action)

    if na_action == 'maintain':
        df[colname] = df[to_unite].apply(lambda x: np.nan if any(x.isnull())
        else sep.join(x.map(str)), axis=1)
    elif na_action == 'ignore':
        df[colname] = df[to_unite].apply(lambda x: sep.join(x[~x.isnull()].map(str)),
                                         axis=1)
    elif na_action == 'as_string':
        df[colname] = df[to_unite].astype(str).apply(lambda x: sep.join(x), axis=1)

    if remove:
        df.drop(to_unite, axis=1, inplace=True)

    return df