DataFrame 행 섞기


438

다음과 같은 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 파일에서 읽습니다. Type1이 있는 모든 행 은 맨 위에 있고 Type2가있는 행, Type3이 있는 행 등이 있습니다.

모든 행 Type이 혼합 되도록 DataFrame 행의 순서를 섞고 싶습니다 . 가능한 결과는 다음과 같습니다.

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

어떻게하면 되나요?

답변:


830

Pandas로 이것을 수행하는 관용적 방법은 .sample데이터 프레임 의 방법 을 사용하여 교체없이 모든 행을 샘플링하는 것입니다.

df.sample(frac=1)

frac있도록 키워드 인수 지정 행의 분수는, 랜덤 샘플 반환 frac=1수단은 (임의의 순서로)의 모든 행을 반환한다.


참고 : 데이터 프레임을 제자리에 섞고 인덱스를 재설정하려면 다음과 같이하십시오.

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

여기서 지정 drop=True하면 .reset_index이전 색인 항목이 포함 된 열이 작성되지 않습니다.

후속 조치 : 위의 작업이 제자리에 있는 것처럼 보이지 않을 수 있습니다. 파이썬 / 팬더는 셔플 된 객체에 대해 다른 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)

6
그렇습니다. 이것은 내가 첫 번째 주석에서 보여주고 싶은 것입니다. 필요한 메모리를 두 번 할당해야합니다.
m-dz

2
@ m-dz 내가 틀렸다면 나를 수정하십시오. 그렇지 않으면 .copy()여전히 동일한 기본 객체를 참조하고 있습니다.
Kris

2
시간이 있으면 메모리 프로파일 러로 실행하겠습니다. 감사합니다
Kris

5
아니요, DataFrame을 복사하지 않습니다. github.com/pandas-dev/pandas/blob/v0.23.0/pandas/core/…
minhle_r7

2
@ m-dz 메모리 프로파일 러를 실행했습니다. 업데이트 된 답변의 "추적 사항"을 참조하십시오.
Kris

225

당신은 이것을 위해 sklearn을 사용할 수 있습니다

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

11
이것은 좋지만 셔플 후 인덱스를 재설정해야 할 수도 있습니다. df.reset_index (inplace = True, drop = True)
cemsazara 2016 년

55

셔플 된 인덱스로 인덱싱하여 데이터 프레임의 행을 셔플 할 수 있습니다. 이를 위해 다음을 사용할 수 있습니다 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)


40

TL; DR : np.random.shuffle(ndarray)작업을 수행 할 수 있습니다.
따라서 귀하의 경우

np.random.shuffle(DataFrame.values)

DataFrame후드 아래에서 NumPy ndarray를 데이터 홀더로 사용합니다. ( DataFrame 소스 코드 에서 확인할 수 있습니다 )

따라서를 사용하면 np.random.shuffle()다차원 배열의 첫 번째 축을 따라 배열을 섞습니다. 그러나 DataFrame유골의 색인 은 뒤섞이지 않았다.

그러나 고려해야 할 몇 가지 사항이 있습니다.

  • 함수는 none을 반환합니다. 원래 객체의 사본을 유지하려면 함수에 전달하기 전에 수행해야합니다.
  • sklearn.utils.shuffle()tj89 사용자가 제안한대로 random_state출력을 제어하는 ​​다른 옵션과 함께 지정할 수 있습니다 . 당신은 그것을 개발 목적으로 원할 수 있습니다.
  • sklearn.utils.shuffle()가 더 빠르다. 그러나의 축 정보 (인덱스, 열) 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)


3
하지 않습니다 df = df.sample(frac=1)으로 똑같은 일을 df = sklearn.utils.shuffle(df)? 내 측정에 따르면 df = df.sample(frac=1)더 빠르며 정확히 동일한 동작을 수행하는 것 같습니다. 또한 새로운 메모리를 할당합니다. np.random.shuffle(df.values)가장 느리지 만 새 메모리를 할당하지는 않습니다.
lo tolmencre 2018

2
축을 데이터와 함께 섞는 것과 관련하여 동일한 작업을 수행하는 것처럼 보입니다. 그리고 예, 위의 동일한 코드를 사용하는 df.sample(frac=1)것보다 약 20 % 빠릅니다 sklearn.utils.shuffle(df). 또는 sklearn.utils.shuffle(ndarray)다른 결과를 얻기 위해 할 수 있습니다.
haku

12

(최고의 게시물에 이것을 언급 할만 큼 평판이 충분하지 않으므로 다른 사람이 나를 위해 그렇게 할 수 있기를 바랍니다.) 첫 번째 방법은 다음과 같은 우려가 제기되었습니다.

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

이는 마지막 주석에서 제안한 것과 같이 메소드가 동일한 오브젝트를 리턴 하지 않음 을 의미합니다 . 따라서이 방법은 실제로 뒤섞인 사본을 만듭니다.


2
원래 답변의 후속 메모 를 살펴보십시오 . 참조가 변경되었지만 (다른 id)에도 기본 개체가 복사 되지 않음을 알 수 있습니다. 다시 말해, 작업은 메모리 내에서 효과적으로 이루어집니다 (물론 분명하지는 않습니다).
Kris

7

유용한 정보, Machine_learning에 사용하고 항상 동일한 데이터를 분리하려는 경우 다음을 사용할 수 있습니다.

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

이것은 무작위 선택을 항상 복제 가능하게 유지합니다.


5

AFAIK 가장 간단한 해결책은 다음과 같습니다.

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

3
이렇게하면 원본 df의 색인이 변경되고 df_shuffled에 저장되는 사본이 생성됩니다. 그러나 더 걱정스러운 것은 인덱스에 의존하지 않는 것, 예를 들어`df_shuffled.iterrows () '는 df와 정확히 같은 순서를 생성 할 것입니다. 요약하면주의해서 사용하십시오!
Jblasco

@Jblasco 이것은 정확하지 않습니다. 원본 df는 전혀 변경 되지 않았습니다 . 의 문서 np.random.permutation"... x가 배열 인 경우 만들 사본을 무작위 요소를 셔플". 문서 DataFrame.reindex: " 새 색인이 현재 색인과 같지 않고 copy = False가 아니면 새 객체 가 생성됩니다." 따라서 대답은 완벽하게 안전합니다 (사본을 생성하더라도).
Andreas Schörgenhumer

3
@ AndreasSchörgenhumer, 이것을 지적 해 주셔서 감사합니다. 부분적으로 옳습니다! 나는 그것을 시도했다는 것을 알았으므로 테스트를했습니다. 의 문서 np.random.permutation says와 numpy의 버전에 따라, 내가 설명한 효과 또는 언급 한 효과를 얻습니다. numpy> 1.15.0을 사용하면 데이터 프레임을 만들고 일반을 수행 np.random.permutation(df.index)하면 원래 df의 인덱스가 변경됩니다. numpy == 1.14.6의 경우에도 마찬가지입니다. 따라서 그 어느 때보다도 경고를 반복합니다. 예기치 않은 부작용과 버전 종속성으로 인해 작업 방식이 위험합니다.
Jblasco

@Jblasco 당신이 옳습니다. 자세한 내용에 감사드립니다. 나는 numpy 1.14를 실행하고 있었으므로 모든 것이 잘 작동했습니다. numpy 1.15에서는 어딘가에 버그 가있는 것 같습니다 . 이 버그에 비추어 귀하의 경고는 현재 정확한 것입니다. 그러나 버그 이기 때문에 문서에 다른 동작이 명시 되어 있기 때문에 나는 대답이 안전하다는 이전의 진술을 고수합니다 (문서가 일반적으로 의존 해야하는 실제 동작을 반영하기 때문에).
Andreas Schörgenhumer

@ AndreasSchörgenhumer, 버그인지 또는 기능인지 확실하지 않은 경우 정직합니다. 문서는 Index타입이 아닌 배열의 복사본을 보장합니다 ... 어쨌든, 나는 권장 사항 / 경고를 docs가 아닌 실제 행동에 기반합니다 : p
Jblasco

2

이 경우 인덱스 로 샘플 배열을 가져와 팬더 데이터 프레임을 섞고 순서를 랜덤 화 한 다음 배열을 데이터 프레임 인덱스로 설정하십시오. 이제 인덱스에 따라 데이터 프레임을 정렬하십시오. 셔플 된 데이터 프레임으로갑니다.

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

위의 코드에서 내 자리에 데이터 프레임을 삽입하십시오.


무작위 색인을 변수에 저장하여 알고리즘 출력을 정확하게 재현 해야하는 경우 셔플을 반복 할 수 있음을 의미 하므로이 방법을 선호합니다.
rayzinnz

0

다른 방법은 다음과 같습니다.

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.