DataFrame satırlarını karıştır


438

Aşağıdaki DataFrame var:

    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 bir csv dosyasından okunur. Type1 olan tüm satırlar üstte, ardından Type2'li satırlar , ardından Type3'lü satırlar vb. Gelir .

Tüm Typekarışık 's böylece DataFrame satır satır sırasını karıştırmak istiyorum. Olası bir sonuç şunlar olabilir:

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

Bunu nasıl başarabilirim?

Yanıtlar:


830

Bunu Pandalar ile .sampleyapmanın en iddialı yolu, veri satırınızın yöntemini tüm satırları değiştirmeden örneklemek için kullanmaktır :

df.sample(frac=1)

fracBöylece anahtar bağımsız değişken belirtir satır fraksiyonu, rastgele seçilmiş bir grupta geri frac=1aracı (rasgele sırayla) tüm satırları döndürür.


Not: Veri çerçevenizi yerinde karıştırmak ve dizini sıfırlamak isterseniz, örn.

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

Burada belirtmek , eski dizin girişlerini içeren bir sütun oluşturmayı drop=Trueengeller .reset_index.

Takip notu: Yukarıdaki işlem yerinde gibi görünmese de , python / pandalar karıştırılan nesne için başka bir malloc yapmayacak kadar akıllıdır. Yani, referans nesnesi değişmiş olsa da (yani demek istediğim id(df_old)ile aynı değildir id(df_new)), temeldeki C nesnesi hala aynıdır. Bunun gerçekten böyle olduğunu göstermek için, basit bir bellek profili oluşturabilirsiniz:

$ 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
Evet, ilk yorumumda tam olarak göstermek istediğim şey, gerekli hafızayı iki kez atamanız gerekiyor, bu da yerinde yapmaktan çok uzak.
m-dz

2
@ m-dz Yanılıyorsam düzelt ama yapmazsan .copy()hala aynı temel nesneyi referans alıyorsun.
Kris

2
Tamam, zamanım olduğunda bir bellek profiler ile çalıştıracağım. Teşekkürler
Kris

5
hayır, DataFrame'i kopyalamaz, sadece şu satıra bakın: github.com/pandas-dev/pandas/blob/v0.23.0/pandas/core/…
minhle_r7

2
@ m-dz Üzerinde bir bellek profili oluşturdum. Güncel cevapta "takip notu" na bakınız.
Kris

225

Bunun için sadece sklearn kullanabilirsiniz

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

11
Bu güzel, ancak karıştırmadan sonra dizinlerinizi sıfırlamanız gerekebilir: df.reset_index (inplace = True, drop = True)
cemsazara

55

Karıştırılmış bir dizinle dizin oluşturarak bir veri çerçevesinin satırlarını karıştırabilirsiniz. Bunun için örneğin kullanabilirsiniz np.random.permutation(ancak np.random.choiceaynı zamanda bir olasılıktır):

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

Örneğinizde olduğu gibi 1, 2, .., n numaralı numarayı saklamak istiyorsanız, dizini sıfırlayabilirsiniz: df_shuffled.reset_index(drop=True)


40

TL; DR : np.random.shuffle(ndarray)işi yapabilir.
Yani, senin durumunda

np.random.shuffle(DataFrame.values)

DataFrame, kaputun altında, veri tutucu olarak NumPy ndarray kullanır. ( DataFrame kaynak kodundan kontrol edebilirsiniz )

Yani, kullanırsanız np.random.shuffle(), diziyi çok boyutlu bir dizinin ilk ekseni boyunca karıştırır. Ancak DataFramekalıntıların endeksi karışık.

Yine de dikkate alınması gereken bazı noktalar vardır.

  • işlevi hiçbiri döndürmez. Orijinal nesnenin bir kopyasını saklamak istediğinizde, işleve geçmeden önce bunu yapmanız gerekir.
  • sklearn.utils.shuffle(), kullanıcı tj89'un önerdiği gibi, random_stateçıkışı kontrol etmek için başka bir seçenekle birlikte atayabilir . Bunu geliştirme amacıyla isteyebilirsiniz.
  • sklearn.utils.shuffle()daha hızlı. Ancak içerdiği eksen bilgisini (indeks, sütun) DataFramebirlikte ndarrayÇIKARACAKTIR.

Karşılaştırma sonucu

arasında sklearn.utils.shuffle()ve np.random.shuffle().

ndarray

nd = sklearn.utils.shuffle(nd)

0.10793248389381915 sn. 8 kat daha hızlı

np.random.shuffle(nd)

0.8897626010002568 saniye

Veri çerçevesi

df = sklearn.utils.shuffle(df)

0.3183923360193148 sn. 3 kat daha hızlı

np.random.shuffle(df.values)

0.9357550159329548 saniye

Sonuç: ndarray ile karıştırılması gereken eksen bilgisinin (indeks, sütun) uygun olması durumunda, kullanın sklearn.utils.shuffle(). Aksi takdirde,np.random.shuffle()

kullanılan kod

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)Tam olarak aynı şeyi yapmıyor mu df = sklearn.utils.shuffle(df)? Ölçümlerime göre df = df.sample(frac=1)daha hızlı ve aynı eylemi gerçekleştiriyor gibi görünüyor. İkisi de yeni bellek ayırıyor. np.random.shuffle(df.values)en yavaş olanıdır, ancak yeni bellek ayırmaz.
lo tolmencre

2
Ekseni verilerle birlikte karıştırmak açısından, aynı şeyi yapabileceği anlaşılıyor. Ve evet, yukarıdaki aynı kodu kullanarak df.sample(frac=1)yaklaşık% 20 daha hızlı görünüyor sklearn.utils.shuffle(df). Ya da sklearn.utils.shuffle(ndarray)farklı bir sonuç elde etmek için yapabilirsiniz .
haku

12

(Bunu üst yazıya yorumlamak için yeterli itibarım yok, bu yüzden umarım başka biri bunu benim için yapabilir.) İlk yöntemin ortaya çıkardığı bir endişe vardı:

df.sample(frac=1)

derin bir kopya yaptı ya da sadece veri çerçevesini değiştirdi. Aşağıdaki kodu koştum:

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

ve sonuçlarım:

0x1f8a784d400
0x1f8b9d65e10
0x1f8b9d65b70

hangi yöntemin demektir değil son açıklamada dile getirildiği gibi, aynı nesneyi dönüyor. Yani bu yöntem gerçekten karışık bir kopya yapıyor .


2
Lütfen orijinal cevabın Takip notuna bakınız . Eğer referanslar (farklı değişmiş olsa bile o var göreceksiniz ids), alttaki nesne olduğunu değil kopyalandı. Başka bir deyişle, operasyon etkili bir şekilde hafızadadır (kuşkusuz açık olmasa da).
Kris

7

Ayrıca yararlıdır, Machine_learning için kullanıyorsanız ve her zaman aynı verileri ayırmak istiyorsanız, şunları kullanabilirsiniz:

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

Bu, rastgele seçiminizi her zaman kopyalanabilir tutmanızı sağlar


5

AFAIK en basit çözüm:

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

3
Lütfen bunun orijinal df'deki indeksleri değiştirdiğini ve df_shuffled'a kaydettiğiniz bir kopyasını ürettiğini unutmayın. Ancak, daha endişe verici olan, endekse bağlı olmayan herhangi bir şey, örneğin `df_shuffled.iterrows () 'df ile tam olarak aynı düzeni üretecektir. Özetle, dikkatli kullanın!
Jblasco

@Jblasco Bu yanlış, orijinal df hiç değişmiyor. Dokümantasyon np.random.permutation: "..., x bir dizi ise, yapmak kopyasını ve rastgele unsurları karıştırmak". Dokümantasyon DataFrame.reindex: " Yeni indeks mevcut olana eşdeğer değilse ve copy = False" değilse yeni bir nesne üretilir. Bu yüzden cevap mükemmel bir şekilde güvenlidir (bir kopya üretse de).
Andreas Schörgenhumer

3
@ AndreasSchörgenhumer, bunu belirttiğin için teşekkürler, kısmen haklısın! Denediğimi biliyordum, bu yüzden biraz test yaptım. Neyin belgelendirilmesine rağmen np.random.permutation saysve numpy sürümlerine bağlı olarak, tarif ettiğim etkiyi veya bahsettiğiniz etkiyi elde edersiniz. Numpy> 1.15.0 ile veri çerçevesi oluşturma ve düzleştirme np.random.permutation(df.index), orijinal df'deki indeksler değişir. Aynı durum numpy == 1.14.6 için geçerli değildir. Yani, her zamankinden daha fazla, uyarımı tekrarlıyorum: bu tür şeyleri yapmak, öngörülemeyen yan etkiler ve sürüm bağımlılıkları nedeniyle tehlikelidir.
Jblasco

@Jblasco Haklısın, detaylar için teşekkür ederim. Ben 1.14 numpy koşuyordu, bu yüzden her şey iyi çalıştı. Numpy 1.15 ile bir yerde bir hata var gibi görünüyor . Bu hatanın ışığında, uyarılarınız şu anda gerçekten doğrudur. Ancak, bir hata olduğu ve dokümantasyonun diğer davranışları belirttiği için, cevabın güvenli olduğuna dair önceki ifademe bağlı kalıyorum (dokümantasyonun normalde güvenebilmemiz gereken gerçek davranışı yansıttığı göz önüne alındığında).
Andreas Schörgenhumer

@ AndreasSchörgenhumer, dürüst olmak gerekirse, bir hata veya özellik olup olmadığından emin değilim. Belgeler, bir dizinin bir kopyasını değil, bir Indextür kopyasını garanti eder ... Her durumda, önerilerimi / uyarılarımı dokümanlar üzerinde değil, gerçek davranışa
dayandırırım

2

Bu durum dizininde örnek bir dizi alarak panda veri çerçevesini karıştırın ve sırasını rastgele sıralayın ve ardından diziyi veri çerçevesinin bir dizini olarak ayarlayın. Şimdi veri çerçevesini dizine göre sıralayın. Karıştırılmış veri çerçeveniz burada

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()

çıktı

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

Yukarıdaki çerçevede benim yerine veri çerçevesi yerleştirin.


Bu yöntemi, rasgele dizini bir değişkene depolayarak algoritma çıktımı tam olarak yeniden üretmem gerekirse tekrarlayabileceği için bu yöntemi tercih ederim.
rayzinnz

0

İşte başka bir yol:

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.