перетасовка / перестановка фрейма данных в панд
какой простой и эффективный способ перетасовать фрейм данных в панд, по строкам или по столбцам? Т. е. как написать функцию shuffle(df, n, axis=0) это занимает фрейм данных, ряд перетасовок n, и ось (axis=0 это строки axis=1 is columns) и возвращает копию кадра данных, который был перетасован n раза.
Edit: ключ должен сделать это, не разрушая метки строк / столбцов фрейма данных. Если вы просто перемешать df.index что теряет все, что информация. Я хочу, чтобы в результате df быть таким же, как оригинал, за исключением того, что порядок строк или порядок столбцов отличается.
Edit2: мой вопрос был неясен. Когда я говорю перетасовать строки, я имею в виду перетасовать каждую строку независимо. Так что если у вас есть два столбца a и b, Я хочу, чтобы каждая строка перетасовывалась сама по себе, чтобы у вас не было одинаковых ассоциаций между a и b как вы делаете, если вы просто переупорядочить каждую строку в целом. Что-то например:
for 1...n:
for each col in df: shuffle column
return new_df
но, надеюсь, более эффективным, чем наивный цикл. Это не работает для меня:
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)
11 ответов:
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
использовать библиотеки numpy это
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
можно использовать
sklearn.utils.shuffle()(требует sklearn 0.16.1 или выше для поддержки фреймов данных 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))выходы:
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затем вы можете использовать
df.reset_index()чтобы сбросить столбец индекса, если нужно быть:df = df.reset_index(drop=True) print('\n\ndf: {0}'.format(df)выходы:
df: A B 0 1 1 1 0 0 2 4 4 3 2 2 4 3 3
из документов используйте
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
я прибегнул к адаптации @root 's ответ немного и с использованием необработанных значений непосредственно. Конечно, это означает, что вы теряете возможность делать причудливую индексацию, но она отлично работает для простого перетасовки данных.
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отметим, что
numpy.rollaxisприводит указанную ось к первому измерению, а затем давайте переберем массивы с оставшимися измерениями, т. е. если мы хотим перетасовать первое измерение (столбцы), нам нужно свернуть второе измерение на фронт, чтобы мы применяем перетасовку к представлениям над первым измерением.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)ваша конечная функция затем использует трюк, чтобы привести результат в соответствие с ожиданием применения функции к оси:
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
Это может быть более полезно, когда вы хотите, чтобы ваш индекс перетасовали.
def shuffle(df): index = list(df.index) random.shuffle(index) df = df.ix[index] df.reset_index() return dfон выбирает новый df с помощью нового индекса, а затем сбросить их.
Если вы хотите перетасовать только один столбец (не Индекс) фрейма данных с большим количеством столбцов:
df ['column_name'] = numpy.случайность.перестановка(ДФ.column_name)
простое решение в панд является использование
sampleметод независимо от каждого столбца. Используйтеapplyдля итерации по каждому столбцу: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вы должны использовать
.valueтак что вы возвращаете массив numpy, а не серию, иначе возвращенная серия будет выровнена по исходному фрейму данных, не меняя ничего: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
вот работа, которую я нашел, если вы хотите только перетасовать подмножество фрейма данных:
shuffle_to_index = 20 df = pd.concat([df.iloc[np.random.permutation(range(shuffle_to_index))], df.iloc[shuffle_to_index:]])
Я знаю, что вопрос для
pandasdf но в случае, если перетасовка происходит по строке (порядок столбцов изменен, порядок строк не изменился), то имена столбцов больше не имеют значения, и было бы интересно использоватьnp.array, а затемnp.apply_along_axis()будет то, что вы ищете.если это приемлемо, то это было бы полезно, обратите внимание, что легко переключить ось, вдоль которой данные перемешиваются.
если вы panda фрейм данных называется
df, может быть, вы может:
- получить значения фрейма данных с
values = df.values,- создать
np.arrayСvalues- примените метод, показанный ниже, чтобы перетасовать
np.arrayпо строке или столбцу- воссоздать новую (перетасованную) панду df из перетасованной
np.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]]сохранить порядок строк, перемешать столбцы в каждой строке
print(np.apply_along_axis(np.random.permutation, 1, a)) [[11 12 10] [22 21 20] [31 30 32] [40 41 42]]держите порядок Колумб, перемешайте строки внутри каждого колонка
print(np.apply_along_axis(np.random.permutation, 0, a)) [[40 41 32] [20 31 42] [10 11 12] [30 21 22]]исходный массив не изменился
print(a) [[10 11 12] [20 21 22] [30 31 32] [40 41 42]]
Comments