python numpy pandas

python - barajar/permutar un DataFrame en pandas



numpy (11)

¿Cuál es una forma simple y eficiente de mezclar un marco de datos en pandas, filas o columnas? Es decir, cómo escribir una función shuffle(df, n, axis=0) que toma un dataframe, un número de shuffles n , y un eje ( axis=0 is rows, axis=1 is columns) y devuelve una copia del dataframe eso ha sido barajado n veces.

Editar : la clave es hacer esto sin destruir las etiquetas de fila / columna del marco de datos. Si simplemente baraja df.index pierde toda esa información. Quiero que el df resultante sea el mismo que el original, excepto con el orden de las filas o el orden de las columnas diferentes.

Edit2 : Mi pregunta no estaba clara. Cuando digo barajar las filas, me refiero a mezclar cada fila de forma independiente. Por lo tanto, si tiene dos columnas b , quiero que cada fila se baraje por sí sola, de modo que no tenga las mismas asociaciones entre b que si reordena cada fila como un todo. Algo como:

for 1...n: for each col in df: shuffle column return new_df

Pero, con suerte, es más eficiente que el bucle ingenuo. Esto no funciona para mi:

def shuffle(df, n, axis=0): shuffled_df = df.copy() for k in range(n): shuffled_df.apply(np.random.shuffle(shuffled_df.values),axis=axis) return shuffled_df df = pandas.DataFrame({''A'':range(10), ''B'':range(10)}) shuffle(df, 5)


Del docs use sample() :

In [79]: s = pd.Series([0,1,2,3,4,5]) # When no arguments are passed, returns 1 row. In [80]: s.sample() Out[80]: 0 0 dtype: int64 # One may specify either a number of rows: In [81]: s.sample(n=3) Out[81]: 5 5 2 2 4 4 dtype: int64 # Or a fraction of the rows: In [82]: s.sample(frac=0.5) Out[82]: 5 5 4 4 1 1 dtype: int64


El muestreo se aleatoriza, de modo que solo muestree todo el marco de datos.

df.sample(frac=1)


Este es un trabajo que encontré si solo quieres barajar un subconjunto del DataFrame:

shuffle_to_index = 20 df = pd.concat([df.iloc[np.random.permutation(range(shuffle_to_index))], df.iloc[shuffle_to_index:]])


Esto podría ser más útil cuando desee que su índice se mezcle.

def shuffle(df): index = list(df.index) random.shuffle(index) df = df.ix[index] df.reset_index() return df

Selecciona nuevo df usando un nuevo índice, luego reinícialo.


Puede usar sklearn.utils.shuffle() ( requires sklearn 0.16.1 o superior para admitir tramas de datos Pandas):

# Generate data import pandas as pd df = pd.DataFrame({''A'':range(5), ''B'':range(5)}) print(''df: {0}''.format(df)) # Shuffle Pandas data frame import sklearn.utils df = sklearn.utils.shuffle(df) print(''/n/ndf: {0}''.format(df))

productos:

df: A B 0 0 0 1 1 1 2 2 2 3 3 3 4 4 4 df: A B 1 1 1 0 0 0 3 3 3 4 4 4 2 2 2

Luego puede usar df.reset_index() para restablecer la columna de índice, si es necesario:

df = df.reset_index(drop=True) print(''/n/ndf: {0}''.format(df)

productos:

df: A B 0 1 1 1 0 0 2 4 4 3 2 2 4 3 3


Recurrí a adaptar ligeramente la respuesta de @root y usar los valores brutos directamente. Por supuesto, esto significa que usted pierde la capacidad de hacer una indexación elegante, pero funciona perfectamente solo para mezclar los datos.

In [1]: import numpy In [2]: import pandas In [3]: df = pandas.DataFrame({"A": range(10), "B": range(10)}) In [4]: %timeit df.apply(numpy.random.shuffle, axis=0) 1000 loops, best of 3: 406 µs per loop In [5]: %%timeit ...: for view in numpy.rollaxis(df.values, 1): ...: numpy.random.shuffle(view) ...: 10000 loops, best of 3: 22.8 µs per loop In [6]: %timeit df.apply(numpy.random.shuffle, axis=1) 1000 loops, best of 3: 746 µs per loop In [7]: %%timeit for view in numpy.rollaxis(df.values, 0): numpy.random.shuffle(view) ...: 10000 loops, best of 3: 23.4 µs per loop

Tenga en cuenta que numpy.rollaxis trae el eje especificado a la primera dimensión y luego nos permite iterar sobre las matrices con las dimensiones restantes, es decir, si queremos barajar a lo largo de la primera dimensión (columnas), tenemos que rodar la segunda dimensión al frente , de modo que apliquemos la mezcla a vistas sobre la primera dimensión.

In [8]: numpy.rollaxis(df, 0).shape Out[8]: (10, 2) # we can iterate over 10 arrays with shape (2,) (rows) In [9]: numpy.rollaxis(df, 1).shape Out[9]: (2, 10) # we can iterate over 2 arrays with shape (10,) (columns)

Su función final utiliza un truco para alinear el resultado con la expectativa de aplicar una función a un eje:

def shuffle(df, n=1, axis=0): df = df.copy() axis = int(not axis) # pandas.DataFrame is always 2D for _ in range(n): for view in numpy.rollaxis(df.values, axis): numpy.random.shuffle(view) return df


Sé que la pregunta es para pandas df, pero en el caso de que la mezcla se produzca por filas (el orden de las columnas cambió, el orden de las filas no se modificó), los nombres de las columnas ya no importan y podría ser interesante usar un np.array en np.array lugar, np.apply_along_axis() será lo que estás buscando.

Si eso es aceptable, sería útil, tenga en cuenta que es fácil cambiar el eje a lo largo del cual se barajan los datos.

Si el marco de datos de panda se llama df , tal vez puedas:

  1. obtener los valores del marco de datos con values = df.values ,
  2. crear un np.array partir de los values
  3. aplique el método que se muestra a continuación para barajar el np.array por fila o columna
  4. recrear un nuevo pandas df (barajado) del np.array arrastrado

Matriz original

a = np.array([[10, 11, 12], [20, 21, 22], [30, 31, 32],[40, 41, 42]]) print(a) [[10 11 12] [20 21 22] [30 31 32] [40 41 42]]

Mantener el orden de las filas, mezclar las columnas dentro de cada fila

print(np.apply_along_axis(np.random.permutation, 1, a)) [[11 12 10] [22 21 20] [31 30 32] [40 41 42]]

Mantenga el orden de las columnas, mezcle filas dentro de cada columna

print(np.apply_along_axis(np.random.permutation, 0, a)) [[40 41 32] [20 31 42] [10 11 12] [30 21 22]]

La matriz original no ha cambiado

print(a) [[10 11 12] [20 21 22] [30 31 32] [40 41 42]]


Si desea barajar solo una columna (no el índice) de un marco de datos con muchas columnas:

df [''column_name''] = numpy.random.permutation (df.column_name)


Una solución simple en pandas es usar el método de sample forma independiente en cada columna. Use apply para iterar sobre cada columna:

df = pd.DataFrame({''a'':[1,2,3,4,5,6], ''b'':[1,2,3,4,5,6]}) df a b 0 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 6 6 df.apply(lambda x: x.sample(frac=1).values) a b 0 4 2 1 1 6 2 6 5 3 5 3 4 2 4 5 3 1

Debe usar .value para que devuelva una matriz numpy y no una serie, de lo contrario la serie devuelta se alineará con el DataFrame original sin cambiar nada:

df.apply(lambda x: x.sample(frac=1)) a b 0 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 6 6


Utilice la función randomperperformance de random.permuation :

In [1]: df = pd.DataFrame({''A'':range(10), ''B'':range(10)}) In [2]: df Out[2]: A B 0 0 0 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 6 6 6 7 7 7 8 8 8 9 9 9 In [3]: df.reindex(np.random.permutation(df.index)) Out[3]: A B 0 0 0 5 5 5 6 6 6 3 3 3 8 8 8 7 7 7 9 9 9 1 1 1 2 2 2 4 4 4


In [16]: def shuffle(df, n=1, axis=0): ...: df = df.copy() ...: for _ in range(n): ...: df.apply(np.random.shuffle, axis=axis) ...: return df ...: In [17]: df = pd.DataFrame({''A'':range(10), ''B'':range(10)}) In [18]: shuffle(df) In [19]: df Out[19]: A B 0 8 5 1 1 7 2 7 3 3 6 2 4 3 4 5 0 1 6 9 0 7 4 6 8 2 8 9 5 9