Search code examples
pythondataframeconcatenationalphabeticalcolumnsorting

how to not let columns sorted by alphabetical order after concatenate dataframes with different number of columns in python


I across this problem when using python for a double-level header. and found the same problem from other forum as states below:

When concatenating DataFrames and the header is douple-level, the column names get alphanumerically sorted if there are any differences between them. If they're identical across DataFrames, they don't get sorted.

This sort is undocumented and unwanted. Certainly the default behavior should be no-sort. For example:

I have two dataframe

# df1:              C   A   B         # df2:         C   A   B   D
                    1   2   3                        1   2   3   4
                0   4   5   6                    0   5   6   7   8
                1   7   8   9                    1   9  10  11  12

if I print "Cols sorted", concat([df1,df2], sort = False)

# Cols sorted           A   B   C    D
                        2   3   1    4
                    0   5   6   4  NaN
                    1   8   9   7  NaN

But I want to keep it as the original order like:

# Cols wanted:          C   A   B    D
                        1   2   3    4
                    0   4   5   6  NaN
                    1   7   8   9  NaN

since df1 is placed in the first place when I concatenate them. When I use df1.append(df2), I have the same problem.

Also I am organizing a DataFrame with 60+ columns. So I can just create a new list of column names in right order and just simply do df = df[list of column name in original order]


Solution

  • Interesting problem... However, I think I found a work around the sort=False failing on multiindex column dataframe concatenations.

    Let's first concat the dataframe column indexes together by converting them a dataframe and using pd.concat. Then we use that index of that result to reindex the column axis of the pd.concat dataframes to get the original column order back.

    Setup:

    df = pd.DataFrame({'A':np.random.choice(list('ABC'),10) , 'B':np.random.randint(0,5,10),'C':np.random.random(10)})   
    df1 = df.set_index(['A','B'], append=True)['C'].unstack([1,2])
    
    df = pd.DataFrame({'A':np.random.choice(list('DEF'),10) , 'B':np.random.randint(0,5,10),'C':np.random.random(10)})
    df2 = df.set_index(['A','B'], append=True)['C'].unstack([1,2])
    
    print(df1)
    A         B                   C         B         A                  C         B
    B         1         4         2         0         0         4        4         2
    0  0.657680       NaN       NaN       NaN       NaN       NaN      NaN       NaN
    1  0.518157       NaN       NaN       NaN       NaN       NaN      NaN       NaN
    2       NaN  0.776922       NaN       NaN       NaN       NaN      NaN       NaN
    3       NaN       NaN  0.063375       NaN       NaN       NaN      NaN       NaN
    4  0.328447       NaN       NaN       NaN       NaN       NaN      NaN       NaN
    5       NaN       NaN       NaN  0.598312       NaN       NaN      NaN       NaN
    6       NaN       NaN       NaN       NaN  0.918801       NaN      NaN       NaN
    7       NaN       NaN       NaN       NaN       NaN  0.045484      NaN       NaN
    8       NaN       NaN       NaN       NaN       NaN       NaN  0.71723       NaN
    9       NaN       NaN       NaN       NaN       NaN       NaN      NaN  0.246769
    
    print(df2)
    A         D                   E         D                   F                  E
    B         1         0         0         3         2         3        2         4
    0  0.396883       NaN       NaN       NaN       NaN       NaN      NaN       NaN
    1       NaN  0.789478       NaN       NaN       NaN       NaN      NaN       NaN
    2       NaN       NaN  0.076724       NaN       NaN       NaN      NaN       NaN
    3       NaN       NaN       NaN  0.424836       NaN       NaN      NaN       NaN
    4       NaN       NaN       NaN       NaN  0.970031       NaN      NaN       NaN
    5       NaN       NaN       NaN       NaN       NaN  0.119261      NaN       NaN
    6  0.781708       NaN       NaN       NaN       NaN       NaN      NaN       NaN
    7       NaN       NaN       NaN       NaN       NaN       NaN  0.57147       NaN
    8       NaN       NaN       NaN       NaN       NaN       NaN      NaN  0.407157
    9       NaN       NaN       NaN       NaN  0.932431       NaN      NaN       NaN
    

    First, let's try pd.concat([df1,df2], sort=False), print head(2):

    A   A       B                     C       D               E       F    
    B   0   4   0         1   2   4   2   4   0   1   2   3   0   4   2   3
    0 NaN NaN NaN  0.657680 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
    1 NaN NaN NaN  0.518157 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
    

    Nope, that didn't work.

    So, lets concat column indexes from both dataframes first.

    orig_cols = pd.concat([df1.columns.to_frame(), df2.columns.to_frame()]).index
    pd.concat([df1,df2]).reindex(orig_cols, axis=1)
    

    Now let's look at output of head(2):

    A         B       C   B   A       C   B   D       E   D       F       E
    B         1   4   2   0   0   4   4   2   1   0   0   3   2   3   2   4
    0  0.657680 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
    1  0.518157 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
    

    It worked.