Перемешивание строк фрейма данных


у меня есть следующий фрейм данных:

    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
...

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

Я хотел бы перетасовать строки фрейма данных, так что все 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
...

как видно из результата, порядок строк перемешивается, но столбцы остаются прежними. Я не знаю если я объясняю это ясно. Дай мне знать, если я этого не сделаю.

как я могу добиться этого?

7 165

7 ответов:

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

df.sample(frac=1)

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

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

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

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

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

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

вы можете перемешать строки фрейма данных путем индексирования с перемешанным индексом. Для этого вы можете, например, использовать np.random.permutationnp.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 как и в вашем примере, вы можете просто сбросить индекс:df_shuffled.reset_index(drop=True)

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

np.random.shuffle(DataFrame.values)

исходя из моего понимания, DataFrame, под капотом, использует NumPy ndarray в качестве держателя данных. Вы можете проверить от исходный код фрейма данных. Так что если вы используете np.random.shuffle(), он будет перетасовывать массив вдоль первой оси многомерного массива. Но колонны-мудрый остается тем же самым.

некоторые ограничения следующие.

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

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

между 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 сек. 3x быстрее

np.random.shuffle(df.values)', setup=setup, number=1000)

0.9357550159329548 сек

вывод:sklearn.utils.shuffle(), если это возможно.

используется код

setup = '''
import numpy as np
import pandas as pd
from sklearn.utils import shuffle
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)

pythonбенчмаркинг

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

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

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

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

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

перетасуйте фрейм данных 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

вставьте фрейм данных в место моего в вышеуказанном коде .