Mezclar filas del marco de datos
Tengo el siguiente marco de datos:
Col1 Col2 Col3 Type
0 1 2 3 1
1 4 5 6 1
...
20 7 8 9 2
21 10 11 12 2
...
45 13 14 15 3
46 16 17 18 3
...
El DataFrame se lee desde un archivo CSV. Todas las filas que tienen Type
1 están en la parte superior, seguidas por las filas con Type
2, seguidas por las filas conType
3, etc.
Me gustaría mezclar el orden de las filas del DataFrame para que todas Type
estén mezcladas. Un posible resultado podría ser:
Col1 Col2 Col3 Type
0 7 8 9 2
1 13 14 15 3
...
20 1 2 3 1
21 10 11 12 2
...
45 4 5 6 1
46 16 17 18 3
...
¿Cómo puedo conseguir esto?
La forma idiomática de hacer esto con Pandas es usar el .sample
método de su marco de datos para muestrear todas las filas sin reemplazo:
df.sample(frac=1)
El frac
argumento de la palabra clave especifica la fracción de filas que se devolverán en la muestra aleatoria, por lo que frac=1
significa devolver todas las filas (en orden aleatorio).
Nota: Si desea mezclar su marco de datos en el lugar y restablecer el índice, puede hacerlo, por ejemplo
df = df.sample(frac=1).reset_index(drop=True)
Aquí, especificar drop=True
impide .reset_index
crear una columna que contenga las entradas de índice antiguas.
Nota de seguimiento: aunque puede que no parezca que la operación anterior está implementada , python/pandas es lo suficientemente inteligente como para no realizar otro malloc para el objeto barajado. Es decir, aunque el objeto de referencia haya cambiado (con lo que quiero decir que id(df_old)
no es el mismo que id(df_new)
), el objeto C subyacente sigue siendo el mismo. Para demostrar que este es realmente el caso, puede ejecutar un generador de perfiles de memoria simple:
$ python3 -m memory_profiler .\test.py
Filename: .\test.py
Line # Mem usage Increment Line Contents
================================================
5 68.5 MiB 68.5 MiB @profile
6 def shuffle():
7 847.8 MiB 779.3 MiB df = pd.DataFrame(np.random.randn(100, 1000000))
8 847.9 MiB 0.1 MiB df = df.sample(frac=1).reset_index(drop=True)
Simplemente puedes usar sklearn
para esto
from sklearn.utils import shuffle
df = shuffle(df)
Puede mezclar las filas de un marco de datos indexando con un índice aleatorio. Para ello, puede utilizar, por ejemplo np.random.permutation
(pero np.random.choice
también es una posibilidad):
In [12]: df = pd.read_csv(StringIO(s), sep="\s+")
In [13]: df
Out[13]:
Col1 Col2 Col3 Type
0 1 2 3 1
1 4 5 6 1
20 7 8 9 2
21 10 11 12 2
45 13 14 15 3
46 16 17 18 3
In [14]: df.iloc[np.random.permutation(len(df))]
Out[14]:
Col1 Col2 Col3 Type
46 16 17 18 3
45 13 14 15 3
20 7 8 9 2
0 1 2 3 1
1 4 5 6 1
21 10 11 12 2
Si desea mantener el índice numerado de 1, 2, .., n como en su ejemplo, simplemente puede restablecer el índice:df_shuffled.reset_index(drop=True)
(No tengo suficiente reputación para comentar esto en la publicación principal, así que espero que alguien más pueda hacerlo por mí). Se planteó la preocupación de que el primer método:
df.sample(frac=1)
Hace una copia profunda o simplemente cambia el marco de datos. Ejecuté el siguiente código:
print(hex(id(df)))
print(hex(id(df.sample(frac=1))))
print(hex(id(df.sample(frac=1).reset_index(drop=True))))
y mis resultados fueron:
0x1f8a784d400
0x1f8b9d65e10
0x1f8b9d65b70
lo que significa que el método no devuelve el mismo objeto, como se sugirió en el último comentario. Así que este método efectivamente hace una copia mezclada .