it-roy-ru.com

Перемешать строки 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, чтобы все Types были смешаны. Возможный результат может быть:

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

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

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

215
JNevens

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

df.sample(frac=1)

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

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

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

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

460
Kris

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

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

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

47
joris

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)

питонбенчмаркинг

23
haku

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

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

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

9
NotANumber

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

df_shuffled = df.reindex(np.random.permutation(df.index))
3
Ido Cohn

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

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

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

0
Abhilash Reddy Yammanuru

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

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

0
soulmachine

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

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

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

0
Sundeep Pidugu