डेटा फेरबदल पंक्तियों


437

मेरे पास निम्नलिखित डेटाफ़्रेम है:

    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 के साथ पंक्तियों के बाद 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
...

इसे कैसे प्राप्त किया जा सकता है?

जवाबों:


828

पंडों के साथ ऐसा करने का मुहावरेदार तरीका .sampleआपके डेटाफ्रेम की विधि का उपयोग प्रतिस्थापन के बिना सभी पंक्तियों का नमूना करना है:

df.sample(frac=1)

fracकीवर्ड तर्क निर्दिष्ट पंक्तियों के अंश बेतरतीब नमूने में वापस जाने के लिए है, तो frac=1इसका मतलब है सभी पंक्तियों को वापस (यादृच्छिक क्रम में)।


नोट: यदि आप अपने डेटाफ़्रेम को इन-प्लेस में फेरबदल करना चाहते हैं और सूचकांक को रीसेट करना चाहते हैं, तो आप कर सकते हैं

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

यहां, निर्दिष्ट करने drop=Trueसे .reset_indexपुराने इंडेक्स प्रविष्टियों वाले कॉलम बनाने से रोकता है।

फॉलो-अप नोट: यद्यपि यह नहीं लग सकता है कि उपरोक्त ऑपरेशन इन-प्लेस है , अजगर / पांडा पर्याप्त स्मार्ट है जो कि फेरबदल की गई वस्तु के लिए दूसरा मॉलॉक न करें। यही है, भले ही संदर्भ वस्तु बदल गई है (जिसके द्वारा मेरा मतलब id(df_old)समान नहीं है id(df_new)), अंतर्निहित सी वस्तु अभी भी समान है। यह दिखाने के लिए कि यह वास्तव में मामला है, आप एक साधारण मेमोरी प्रोफाइलर चला सकते हैं:

$ 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()हैं तो आप अभी भी उसी अंतर्निहित वस्तु को संदर्भित कर रहे हैं।
क्रिश

2
ठीक है, मैं इसे एक मेमोरी प्रोफाइल के साथ चलाऊंगा जब मेरे पास समय होगा। धन्यवाद
क्रिस

5
नहीं, यह DataFrame की नकल नहीं करता है, बस इस लाइन को देखें: github.com/pandas-dev/pandas/blob/v0.23.0/pandas/core/…
minhle_r7

2
@ m-dz मैंने इस पर एक मेमोरी प्रोफाइलर चलाया। अद्यतन उत्तर में "अनुवर्ती नोट" देखें।
क्रिश २

225

आप बस इसके लिए sklearn का उपयोग कर सकते हैं

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

11
यह अच्छा है, लेकिन आपको फेरबदल के बाद अपने अनुक्रमित को रीसेट करने की आवश्यकता हो सकती है: df.reset_index (inplace = True, drop = True)
cemsazara

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

टीएल; डीआर : 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 सेकंड

डेटा ढांचा

df = sklearn.utils.shuffle(df)

0.3183923360193148 सेकेंड। 3x तेज

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)सबसे धीमा है, लेकिन नई मेमोरी को आवंटित नहीं करता है।
लो tolmencre

2
डेटा के साथ अक्ष को फेरबदल करने के संदर्भ में, ऐसा लगता है कि यह भी ऐसा ही कर सकता है। और हाँ, ऐसा लगता है कि ऊपर समान कोड का उपयोग करते हुए, df.sample(frac=1)लगभग 20% अधिक तेज है sklearn.utils.shuffle(df)। या आप sklearn.utils.shuffle(ndarray)अलग परिणाम प्राप्त करने के लिए कर सकते हैं ।
हक्कू

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), अंतर्निहित वस्तु की नकल नहीं की गई है। दूसरे शब्दों में, ऑपरेशन प्रभावी रूप से मेमोरी में है (हालांकि माना जाता है कि यह स्पष्ट नहीं है)।
क्रिस

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 के समान क्रम का उत्पादन करेगा। संक्षेप में, सावधानी के साथ उपयोग करें!
जाब्लास्को

@ जाब्लास्को यह गलत है, मूल डीएफ बिल्कुल नहीं बदला गया है। का प्रलेखन np.random.permutation: "... यदि x एक सरणी है, तो एक प्रतिलिपि बनाएँ और तत्वों को यादृच्छिक रूप से फेरबदल करें"। का दस्तावेज़ीकरण DataFrame.reindex: "एक नई वस्तु तब तक उत्पन्न होती है जब तक कि नया सूचकांक वर्तमान के बराबर और कॉपी = गलत न हो"। तो जवाब पूरी तरह से सुरक्षित है (हालांकि एक प्रतिलिपि का उत्पादन)।
एंड्रियास शोगेनहुमर

3
@ AndreasSchörgenhumer, इसे इंगित करने के लिए धन्यवाद, आप आंशिक रूप से सही हैं! मुझे पता था कि मैंने इसकी कोशिश की थी, इसलिए मैंने कुछ परीक्षण किया। के दस्तावेज़ों के बावजूद np.random.permutation says, और सुन्न के संस्करणों के आधार पर, आपको मेरे द्वारा वर्णित प्रभाव या आपके द्वारा उल्लेखित प्रभाव मिलता है। Numpy> 1.15.0 के साथ, एक डेटाफ्रेम बनाकर और एक प्लेन np.random.permutation(df.index)करते हुए, मूल df परिवर्तन में सूचकांक। वही सुन्न == 1.14.6 के लिए सही नहीं है। इसलिए, पहले से कहीं ज्यादा, मैं अपनी चेतावनी दोहराता हूं: अप्रत्याशित साइड इफेक्ट्स और संस्करण निर्भरता के कारण चीजों को करने का तरीका खतरनाक है।
जाब्लास्को

@ जाब्लास्को आप सही हैं, विवरण के लिए धन्यवाद। मैं १.१४ की संख्या में चल रहा था, इसलिए सब कुछ ठीक काम कर रहा था। 1.15 की संख्या के साथ कहीं-कहीं बग दिखाई देता है। इस बग के प्रकाश में, आपकी चेतावनी वर्तमान में सही है। हालाँकि, जैसा कि यह एक बग है और दस्तावेज़ीकरण अन्य व्यवहार को बताता है, मैं अभी भी अपने पिछले बयान से चिपका हुआ हूं कि उत्तर सुरक्षित है (यह देखते हुए कि प्रलेखन वास्तविक व्यवहार को दर्शाता है, जिसे हमें सामान्य रूप से भरोसा करने में सक्षम होना चाहिए)।
एंड्रियास शोगेनहुमर

ईमानदार होने के लिए @ AndreasSchörgenhumer, बिल्कुल यकीन नहीं है कि यह एक बग या एक विशेषता है। प्रलेखन एक सरणी की एक प्रति की गारंटी देता है, न कि एक Indexप्रकार की ... किसी भी मामले में, मैं अपनी सिफारिशों / चेतावनियों को वास्तविक व्यवहार पर आधारित करता हूं, डॉक्स पर नहीं: पी
जाब्लास्को

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

उपरोक्त कोड में आपको मेरी जगह डेटा फ्रेम डालें।


मैं इस पद्धति को पसंद करता हूं क्योंकि इसका मतलब है कि फेरबदल को दोहराया जा सकता है अगर मुझे अपने एल्गोरिथ्म आउटपुट को बिल्कुल ठीक करने की आवश्यकता है, यादृच्छिक चर को एक चर में संग्रहीत करके।

0

यहाँ एक और तरीका है:

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.