Подтвердить что ты не робот

Перетасовка/перестановка DataFrame в pandas

Какой простой и эффективный способ перетасовать файл данных в pandas, по строкам или по столбцам? То есть как написать функцию shuffle(df, n, axis=0), которая принимает фрейм данных, количество тасований n, а ось (axis=0 - это строки, axis=1 - столбцы) и возвращает копию кадра данных, который был перетасован n раз.

Изменить: ключ должен сделать это, не уничтожая ярлыки строки/столбца в кадре данных. Если вы просто перетасовываете 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)
4b9b3361

Ответ 1

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

Ответ 2

Используйте функцию 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

Ответ 3

Сэмплирование рандомизируется, поэтому просто выберите весь кадр данных.

df.sample(frac=1)

Ответ 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() для reset столбца индекса, если это необходимо:

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

Ответ 5

В документах используйте 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

Ответ 6

Я прибегал к адаптации @root ответа немного и напрямую используя исходные значения. Конечно, это означает, что вы теряете способность делать фантазийную индексацию, но она отлично работает для просто перетасовки данных.

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

Ответ 7

Это может быть более полезно, если вы хотите, чтобы ваш индекс перетасовывался.

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

Он выбирает новый df с помощью нового индекса, затем reset их.

Ответ 8

Простым решением в pandas является использование метода 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, а не серию, иначе возвращаемая серия будет выравниваться с исходным DataFrame, не меняя вещь:

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

Ответ 9

Вот работа, которую я нашел, если вы хотите только перетасовать подмножество DataFrame:

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

Ответ 10

Я знаю, что вопрос относится к pandas df, но в случае, когда тасовка происходит по строке (порядок столбцов изменен, порядок строк неизменен), тогда имена столбцов больше не имеют значения, и было бы интересно использовать np.array, тогда np.apply_along_axis() будет тем, что вы ищете.

Если это приемлемо, это было бы полезно, обратите внимание, что легко переключить ось, по которой данные перетасовываются.

Если кадр данных panda имеет имя df, возможно, вы можете:

  • получить значения фрейма данных с помощью values = df.values,
  • создайте np.array из values
  • примените приведенный ниже метод, чтобы перетасовать np.array по строке или столбцу
  • воссоздайте новый (перетасованный) pandas 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]]

Ответ 11

Если вы хотите перетасовать только один столбец (не индекс) кадра данных со многими столбцами:

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