Перетасовка/перестановка 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)
Ответы
Ответ 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)