Concat aleatoriamente marcos de datos por fila

¿Cómo puedo combinar, unir o concatear aleatoriamente marcos de datos de pandas por fila? Supongamos que tengo cuatro marcos de datos algo como esto (con muchas más filas):

df1 = pd.DataFrame({'col1':["1_1", "1_1"], 'col2':["1_2", "1_2"], 'col3':["1_3", "1_3"]}) df2 = pd.DataFrame({'col1':["2_1", "2_1"], 'col2':["2_2", "2_2"], 'col3':["2_3", "2_3"]}) df3 = pd.DataFrame({'col1':["3_1", "3_1"], 'col2':["3_2", "3_2"], 'col3':["3_3", "3_3"]}) df4 = pd.DataFrame({'col1':["4_1", "4_1"], 'col2':["4_2", "4_2"], 'col3':["4_3", "4_3"]}) 

¿Cómo puedo unir estos cuatro marcos de datos de forma aleatoria y generar algo como esto (se fusionan aleatoriamente fila por fila):

  col1 col2 col3 col1 col2 col3 col1 col2 col3 col1 col2 col3 0 1_1 1_2 1_3 4_1 4_2 4_3 2_1 2_2 2_3 3_1 3_2 3_3 1 2_1 2_2 2_3 1_1 1_2 1_3 3_1 3_2 3_3 4_1 4_2 4_3 

Estaba pensando que podría hacer algo como esto:

 my_list = [df1,df2,df3,df4] my_list = random.sample(my_list, len(my_list)) df = pd.DataFrame({'empty' : []}) for row in df: new_df = pd.concat(my_list, axis=1) print new_df 

Arriba for statement no funcionará por más de la primera fila, cada fila después (tengo más) será igual, es decir, solo se barajará una vez:

  col1 col2 col3 col1 col2 col3 col1 col2 col3 col1 col2 col3 0 4_1 4_2 4_3 1_1 1_2 1_3 2_1 2_2 2_3 3_1 3_2 3_3 1 4_1 4_2 4_3 1_1 1_2 1_3 2_1 2_2 2_3 3_1 3_2 3_3 

ACTUALIZACIÓN: una solución mucho mejor de @Divakar:

 df1 = pd.DataFrame({'col1':["1_1", "1_1"], 'col2':["1_2", "1_2"], 'col3':["1_3", "1_3"], 'col4':["1_4", "1_4"]}) df2 = pd.DataFrame({'col1':["2_1", "2_1"], 'col2':["2_2", "2_2"], 'col3':["2_3", "2_3"], 'col4':["2_4", "2_4"]}) df3 = pd.DataFrame({'col1':["3_1", "3_1"], 'col2':["3_2", "3_2"], 'col3':["3_3", "3_3"], 'col4':["3_4", "3_4"]}) df4 = pd.DataFrame({'col1':["4_1", "4_1"], 'col2':["4_2", "4_2"], 'col3':["4_3", "4_3"], 'col4':["4_4", "4_4"]}) dfs = [df1, df2, df3, df4] n = len(dfs) nrows = dfs[0].shape[0] ncols = dfs[0].shape[1] A = pd.concat(dfs, axis=1).values.reshape(nrows,-1,ncols) sidx = np.random.rand(nrows,n).argsort(1) out_arr = A[np.arange(nrows)[:,None],sidx,:].reshape(nrows,-1) df = pd.DataFrame(out_arr) 

Salida:

 In [203]: df Out[203]: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 3_1 3_2 3_3 3_4 1_1 1_2 1_3 1_4 4_1 4_2 4_3 4_4 2_1 2_2 2_3 2_4 1 4_1 4_2 4_3 4_4 2_1 2_2 2_3 2_4 3_1 3_2 3_3 3_4 1_1 1_2 1_3 1_4 

Explicación: (c) Divakar

Solución basada en NumPy

¡Tengamos una solución vectorizada basada en NumPy y esperamos que sea rápida!

1) Cambiemos una matriz de valores concatenados en una matriz 3D “cortando” cada fila en grupos de ncols correspondientes al número de columnas en cada uno de los marcos de datos de entrada –

 A = pd.concat(dfs, axis=1).values.reshape(nrows,-1,ncols) 

2) A continuación, intentamos que np.aragsort nos brinde índices únicos aleatorios que van de 0 a N-1 , donde N es el número de marcos de datos de entrada:

 sidx = np.random.rand(nrows,n).argsort(1) 

3) El truco final es la elegante indexación de NumPy junto con algunas transmisiones para indexar en A con sidx para darnos la matriz de salida:

 out_arr = A[np.arange(nrows)[:,None],sidx,:].reshape(nrows,-1) 

4) Si es necesario, convertir a dataframe –

 df = pd.DataFrame(out_arr) 

Respuesta VIEJA:

IIUC puedes hacerlo de esta manera:

 dfs = [df1, df2, df3, df4] n = len(dfs) ncols = dfs[0].shape[1] v = pd.concat(dfs, axis=1).values a = np.arange(n * ncols).reshape(n, df1.shape[1]) df = pd.DataFrame(np.asarray([v[i, a[random.sample(range(n), n)].reshape(n * ncols,)] for i in dfs[0].index])) 

Salida

 In [150]: df Out[150]: 0 1 2 3 4 5 6 7 8 9 10 11 0 1_1 1_2 1_3 3_1 3_2 3_3 4_1 4_2 4_3 2_1 2_2 2_3 1 2_1 2_2 2_3 1_1 1_2 1_3 3_1 3_2 3_3 4_1 4_2 4_3 

Explicación:

 In [151]: v Out[151]: array([['1_1', '1_2', '1_3', '2_1', '2_2', '2_3', '3_1', '3_2', '3_3', '4_1', '4_2', '4_3'], ['1_1', '1_2', '1_3', '2_1', '2_2', '2_3', '3_1', '3_2', '3_3', '4_1', '4_2', '4_3']], dtype=object) In [152]: a Out[152]: array([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11]]) 

Tal vez algo como esto?

 import random import numpy as np dfs = [df1, df2, df3, df4] n = np.sum(len(df.columns) for df in dfs) pd.concat(dfs, axis=1).iloc[:, random.sample(range(n), n)] Out[130]: col1 col3 col1 col2 col1 col1 col2 col2 col3 col3 col3 col2 0 4_1 4_3 1_1 4_2 2_1 3_1 1_2 3_2 1_3 3_3 2_3 2_2 

O, si solo se barajan los df, puedes hacer:

 dfs = [df1, df2, df3, df4] random.shuffle(dfs) pd.concat(dfs, axis=1) Out[133]: col1 col2 col3 col1 col2 col3 col1 col2 col3 col1 col2 col3 0 4_1 4_2 4_3 2_1 2_2 2_3 1_1 1_2 1_3 3_1 3_2 3_3