Pandas - Interleave / Zip two DataFrames by row

Here's an extension of @Bharath's answer that can be applied to DataFrames with user-defined indexes without losing them, using pd.MultiIndex.

Define Dataframes with the full set of column/ index labels and names:

df1 = pd.DataFrame([['a','b','c'], ['d','e','f']], index=['one', 'two'], columns=['col_a', 'col_b','col_c'])  
df1.columns.name = 'cols'
df1.index.name = 'rows'
df2 = pd.DataFrame([['A','B','C'], ['D','E','F']], index=['one', 'two'], columns=['col_a', 'col_b','col_c'])
df2.columns.name = 'cols'
df2.index.name = 'rows'

Add DataFrame ID to MultiIndex:

df1.index = pd.MultiIndex.from_product([[1], df1.index], names=["df_id", df1.index.name])
df2.index = pd.MultiIndex.from_product([[2], df2.index], names=["df_id", df2.index.name])

Then use @Bharath's concat() and sort_index():

data = pd.concat([df1, df2], axis=0, sort=True)
data.sort_index(axis=0, level=data.index.names[::-1], inplace=True)

Output:

cols       col_a col_b col_c
df_id rows                  
1     one      a     b     c
2     one      A     B     C
1     two      d     e     f
2     two      D     E     F


You can sort the index after concatenating and then reset the index i.e

import pandas as pd

df1 = pd.DataFrame([['a','b','c'], ['d','e','f']])  
df2 = pd.DataFrame([['A','B','C'], ['D','E','F']])

concat_df = pd.concat([df1,df2]).sort_index().reset_index(drop=True)

Output :

   0  1  2
0  a  b  c
1  A  B  C
2  d  e  f
3  D  E  F

EDIT (OmerB) : Incase of keeping the order regardless of the index value then.

import pandas as pd
df1 = pd.DataFrame([['a','b','c'], ['d','e','f']]).reset_index()  
df2 = pd.DataFrame([['A','B','C'], ['D','E','F']]).reset_index()

concat_df = pd.concat([df1,df2]).sort_index().set_index('index')

Use toolz.interleave

In [1024]: from toolz import interleave

In [1025]: pd.DataFrame(interleave([df1.values, df2.values]))
Out[1025]:
   0  1  2
0  a  b  c
1  A  B  C
2  d  e  f
3  D  E  F