Перемешать строки DataFrame

У меня есть следующий DataFrame:

    Col1  Col2  Col3  Type
0      1     2     3     1
1      4     5     6     1
...
20     7     8     9     2
21    10    11    12     2
...
45    13    14    15     3
46    16    17    18     3
...

DataFrame считывается из CSV файла. Все строки с Type 1 находятся сверху, за ними следуют строки с Type 2, за которыми следуют строки с Type 3 и т.д.

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

    Col1  Col2  Col3  Type
0      7     8     9     2
1     13    14    15     3
...
20     1     2     3     1
21    10    11    12     2
...
45     4     5     6     1
46    16    17    18     3
...

Как мне этого добиться?

Ответ 1

Идиоматический способ сделать это с пандами - это использовать метод .sample вашего фрейма данных, т.е.

df.sample(frac=1)

Ключевой аргумент frac определяет долю строк, возвращаемых в случайной выборке, поэтому frac=1 означает возвращение всех строк (в случайном порядке).


Примечание: Если вы хотите переместить ваш фрейм данных на месте и сбросить индекс, вы можете сделать, например,

df = df.sample(frac=1).reset_index(drop=True)

Здесь указание drop=True не позволяет .reset_index создавать столбец, содержащий старые записи индекса.

Последующее замечание: Несмотря на то, что приведенная выше операция может выглядеть неэффективно, Python/pandas достаточно умен, чтобы не выполнять другой malloc для перемешанного объекта. То есть, даже если эталонный объект изменился (я имею в виду id(df_old) не совпадает с id(df_new)), базовый объект C остается тем же. Чтобы показать, что это действительно так, вы можете запустить простой профилировщик памяти:

$ python3 -m memory_profiler .\test.py
Filename: .\test.py

Line #    Mem usage    Increment   Line Contents
================================================
     5     68.5 MiB     68.5 MiB   @profile
     6                             def shuffle():
     7    847.8 MiB    779.3 MiB       df = pd.DataFrame(np.random.randn(100, 1000000))
     8    847.9 MiB      0.1 MiB       df = df.sample(frac=1).reset_index(drop=True)

Ответ 2

Вы можете просто использовать sklearn для этого

from sklearn.utils import shuffle
df = shuffle(df)

Ответ 3

Вы можете перемешать строки фрейма данных путем индексирования с перетасованным индексом. Для этого вы можете использовать np.random.permutation (но np.random.choice также возможность):

In [12]: df = pd.read_csv(StringIO(s), sep="\s+")

In [13]: df
Out[13]: 
    Col1  Col2  Col3  Type
0      1     2     3     1
1      4     5     6     1
20     7     8     9     2
21    10    11    12     2
45    13    14    15     3
46    16    17    18     3

In [14]: df.iloc[np.random.permutation(len(df))]
Out[14]: 
    Col1  Col2  Col3  Type
46    16    17    18     3
45    13    14    15     3
20     7     8     9     2
0      1     2     3     1
1      4     5     6     1
21    10    11    12     2

Если вы хотите сохранить индекс с номерами 1, 2,.., n, как в вашем примере, вы можете просто reset индекс: df_shuffled.reset_index(drop=True)

Ответ 4

TL; DR: np.random.shuffle(ndarray) может сделать эту работу.
Итак, в вашем случае

np.random.shuffle(DataFrame.values)

DataFrame, под капотом, использует NumPy ndarray в качестве владельца данных. (Вы можете проверить из исходного кода DataFrame)

Поэтому, если вы используете np.random.shuffle(), он будет перетасовывать массив вдоль первой оси многомерного массива. Но индекс DataFrame остается не перетасованным.

Хотя есть некоторые моменты, которые следует учитывать.

  • функция не возвращает ничего. Если вы хотите сохранить копию исходного объекта, вы должны сделать это, прежде чем перейти к функции.
  • sklearn.utils.shuffle(), как предложил пользователь tj89, может назначать random_state вместе с другой опцией для управления выводом. Вы можете хотеть это для цели разработки.
  • sklearn.utils.shuffle() быстрее. Но будет перемешивать информацию об оси (индекс, столбец) DataFrame вместе с ndarray он содержит.

Результат теста

между sklearn.utils.shuffle() и np.random.shuffle().

ndarray

nd = sklearn.utils.shuffle(nd)

0,10793248389381915 сек. В 8 раз быстрее

np.random.shuffle(nd)

0,8897626010002568 с

DataFrame

df = sklearn.utils.shuffle(df)

0,3183923360193148 сек. В 3 раза быстрее

np.random.shuffle(df.values)

0,9357550159329548 сек

Вывод: если информация оси (индекс, столбец) может быть перетасована вместе с ndarray, используйте sklearn.utils.shuffle(). В противном случае используйте np.random.shuffle()

используемый код

import timeit
setup = '''
import numpy as np
import pandas as pd
import sklearn
nd = np.random.random((1000, 100))
df = pd.DataFrame(nd)
'''

timeit.timeit('nd = sklearn.utils.shuffle(nd)', setup=setup, number=1000)
timeit.timeit('np.random.shuffle(nd)', setup=setup, number=1000)
timeit.timeit('df = sklearn.utils.shuffle(df)', setup=setup, number=1000)
timeit.timeit('np.random.shuffle(df.values)', setup=setup, number=1000)

Ответ 5

(У меня недостаточно репутации, чтобы комментировать это в верхнем посте, поэтому я надеюсь, что кто-то другой может сделать это для меня.) Была высказана обеспокоенность, что первый метод:

df.sample(frac=1)

сделал глубокую копию или просто изменил фрейм данных. Я запустил следующий код:

print(hex(id(df)))
print(hex(id(df.sample(frac=1))))
print(hex(id(df.sample(frac=1).reset_index(drop=True))))

и мои результаты были:

0x1f8a784d400
0x1f8b9d65e10
0x1f8b9d65b70

Это означает, что метод не возвращает тот же объект, как было предложено в последнем комментарии. Таким образом, этот метод действительно делает случайную копию.

Ответ 6

AFAIK самое простое решение:

df_shuffled = df.reindex(np.random.permutation(df.index))

Ответ 7

перетасуйте кадр данных pandas, взяв образец массива в этом случае индекса и рандомизируйте его порядок, а затем установите массив в качестве индекса кадра данных. Теперь отсортируйте фрейм данных по индексу. Вот твой перетасованный кадр данных

import random
df = pd.DataFrame({"a":[1,2,3,4],"b":[5,6,7,8]})
index = [i for i in range(df.shape[0])]
random.shuffle(index)
df.set_index([index]).sort_index()

выход

    a   b
0   2   6
1   1   5
2   3   7
3   4   8

Вставьте свой фрейм данных вместо моего в приведенном выше коде.

Ответ 8

Простейший способ сделать это приведенный ниже код. (Python)

from sklearn.utils import shuffle
dataFrame = shuffle(dataFrame)

Это будет перетаскивать все столбцы, и вы будете иметь хорошее сочетание всех, так что все Type смешаны

Ответ 9

Что также полезно, если вы используете его для Machine_learning и хотите всегда разделять одни и те же данные, вы можете использовать:

df.sample(n=len(df), random_state=42)

это гарантирует, что ваш случайный выбор всегда будет воспроизводимым

Ответ 10

Вот еще один способ:

df['rnd'] = np.random.rand(len(df)) df = df.sort_values(by='rnd', inplace=True).drop('rnd', axis=1)