Was ist eine einfache und effiziente Möglichkeit, einen Datenrahmen in Pandas nach Zeilen oder Spalten zu mischen? Dh wie man eine Funktion schreibt shuffle(df, n, axis=0)
, die einen Datenrahmen, eine Anzahl von Mischvorgängen n
und eine Achse ( axis=0
ist Zeilen, axis=1
ist Spalten) verwendet und eine Kopie des Datenrahmens zurückgibt, der n
mal gemischt wurde.
Bearbeiten : Mit dieser Taste können Sie die Zeilen- / Spaltenbeschriftungen des Datenrahmens nicht zerstören. Wenn Sie nur mischen df.index
, gehen all diese Informationen verloren. Ich möchte, dass das Ergebnis df
mit dem Original identisch ist, außer dass die Reihenfolge der Zeilen oder Spalten unterschiedlich ist.
Edit2 : Meine Frage war unklar. Wenn ich "Zeilen mischen" sage, meine ich "mischen" jede Zeile einzeln. Wenn Sie also zwei Spalten haben a
und b
, möchte ich, dass jede Zeile für sich gemischt wird, damit Sie nicht die gleichen Assoziationen zwischen a
und haben, b
wie Sie es tun, wenn Sie nur jede Zeile als Ganzes neu anordnen. Etwas wie:
for 1...n:
for each col in df: shuffle column
return new_df
Aber hoffentlich effizienter als naives Looping. Das funktioniert bei mir nicht:
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)
Antworten:
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
quelle
1,5
zusammen und4,8
zusammen haben (aber auch nicht nur eine Spaltenmischung, die Sie auf zwei Auswahlmöglichkeiten beschränkt)df.apply(np.random.permutation)
würde als Lösungdf.reindex(np.random.permutation(df.index))
funktionieren und sah ordentlicher aus, aber tatsächlich verhalten sie sich anders. Letzteres behält die Zuordnung zwischen Spalten derselben Zeile bei, Ersteres nicht. Mein Missverständnis natürlich, aber hoffentlich wird es andere Menschen vor dem gleichen Fehler bewahren.import numpy as np
Verwenden Sie die
random.permuation
Funktion von numpy :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
quelle
df.iloc[np.random.permutation(np.arange(len(df)))]
wenn es Dupes und so gibt (und kann für mi schneller sein).df.reindex(np.random.permutation(df.index))
durchdf.set_index(np.random.permutation(df.index))
den gewünschten Effekt zu erzielen.set_index
wie Emanuel brauchte ich auchdf.sort_index(inplace=True)
Die Abtastung erfolgt nach dem Zufallsprinzip. Abtasten Sie also einfach den gesamten Datenrahmen.
df.sample(frac=1)
quelle
df['column'] = df['column'].sample(frac=1).reset_index(drop=True)
Sie können Folgendes verwenden
sklearn.utils.shuffle()
( erfordert sklearn 0.16.1 oder höher, um Pandas-Datenrahmen zu unterstützen):# 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))
Ausgänge:
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
Anschließend können Sie die
df.reset_index()
Indexspalte bei Bedarf zurücksetzen:df = df.reset_index(drop=True) print('\n\ndf: {0}'.format(df)
Ausgänge:
df: A B 0 1 1 1 0 0 2 4 4 3 2 2 4 3 3
quelle
df.sample(frac=1)
Ihrer Information , ist geringfügig schneller (76,9 vs 78,9 ms für 400k Zeilen).Verwenden Sie aus den Dokumenten
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
quelle
Eine einfache Lösung bei Pandas besteht darin, die
sample
Methode unabhängig für jede Spalte anzuwenden . Verwenden Sieapply
diese Option, um über jede Spalte zu iterieren: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
Sie müssen verwenden,
.value
damit Sie ein numpy-Array und keine Serie zurückgeben. Andernfalls wird die zurückgegebene Serie am ursprünglichen DataFrame ausgerichtet und ändert nichts: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
quelle
Ich habe darauf zurückgegriffen, die Antwort von @root leicht anzupassen und die Rohwerte direkt zu verwenden. Dies bedeutet natürlich, dass Sie nicht mehr in der Lage sind, ausgefallene Indizierungen durchzuführen, aber es funktioniert perfekt, wenn Sie nur die Daten mischen.
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
Beachten Sie, dass
numpy.rollaxis
die angegebene Achse auf die erste Dimension gebracht wird, und lassen Sie uns dann über Arrays mit den verbleibenden Dimensionen iterieren. Wenn wir also entlang der ersten Dimension (Spalten) mischen möchten, müssen wir die zweite Dimension nach vorne rollen, damit Wir wenden das Mischen auf Ansichten über die erste Dimension an.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)
Ihre endgültige Funktion verwendet dann einen Trick, um das Ergebnis mit der Erwartung in Einklang zu bringen, eine Funktion auf eine Achse anzuwenden:
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
quelle
Dies kann nützlicher sein, wenn Sie möchten, dass Ihr Index gemischt wird.
def shuffle(df): index = list(df.index) random.shuffle(index) df = df.ix[index] df.reset_index() return df
Es wählt neue df mit neuem Index aus und setzt sie dann zurück.
quelle
Ich weiß, dass die Frage für ein
pandas
df ist, aber wenn das Mischen nach Zeilen erfolgt (Spaltenreihenfolge geändert, Zeilenreihenfolge unverändert), spielen die Spaltennamen keine Rolle mehr und es könnte interessant sein,np.array
stattdessen ein zu verwendennp.apply_along_axis()
werden Sie es sein sind auf der Suche nach.Wenn dies akzeptabel ist, ist dies hilfreich. Beachten Sie, dass es einfach ist, die Achse zu wechseln, entlang der die Daten gemischt werden.
Wenn Ihr Panda-Datenrahmen benannt ist
df
, können Sie möglicherweise:values = df.values
,np.array
vonvalues
np.array
Zeilen oder Spalten zu mischennp.array
Ursprüngliches Array
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]]
Behalten Sie die Zeilenreihenfolge bei und mischen Sie die Spalten in jeder Zeile
print(np.apply_along_axis(np.random.permutation, 1, a)) [[11 12 10] [22 21 20] [31 30 32] [40 41 42]]
Halten Sie die Spaltenreihenfolge und mischen Sie die Zeilen in jeder Spalte
print(np.apply_along_axis(np.random.permutation, 0, a)) [[40 41 32] [20 31 42] [10 11 12] [30 21 22]]
Das ursprüngliche Array bleibt unverändert
print(a) [[10 11 12] [20 21 22] [30 31 32] [40 41 42]]
quelle
Hier ist eine Problemumgehung, die ich gefunden habe, wenn Sie nur eine Teilmenge des DataFrame mischen möchten:
shuffle_to_index = 20 df = pd.concat([df.iloc[np.random.permutation(range(shuffle_to_index))], df.iloc[shuffle_to_index:]])
quelle