पंडों में पंक्तियों का चयन करें MultiIndex DataFrame


146

डेटाफ़्रेम की पंक्तियों का चयन / फ़िल्टर करने के लिए सबसे सामान्य पांडा तरीके क्या हैं जिनका सूचकांक एक मल्टीएंडेक्स है ?

  • एकल मूल्य / लेबल के आधार पर स्लाइसिंग
  • एक या अधिक स्तरों से कई लेबल पर आधारित स्लाइसिंग
  • बूलियन स्थितियों और अभिव्यक्तियों पर फ़िल्टरिंग
  • कौन से तरीके किन परिस्थितियों में लागू होते हैं

सादगी के लिए मान्यताओं:

  1. इनपुट डेटाफ्रेम में डुप्लिकेट इंडेक्स कीज़ नहीं होती हैं
  2. नीचे दिए गए इनपुट डेटाफ्रेम में केवल दो स्तर हैं। (अधिकांश समाधान यहाँ N स्तर के लिए सामान्यीकृत दिखाए गए हैं)

उदाहरण इनपुट:

mux = pd.MultiIndex.from_arrays([
    list('aaaabbbbbccddddd'),
    list('tuvwtuvwtuvwtuvw')
], names=['one', 'two'])

df = pd.DataFrame({'col': np.arange(len(mux))}, mux)

         col
one two     
a   t      0
    u      1
    v      2
    w      3
b   t      4
    u      5
    v      6
    w      7
    t      8
c   u      9
    v     10
d   w     11
    t     12
    u     13
    v     14
    w     15

प्रश्न 1: किसी एक आइटम का चयन करना

मैं "स्तर" "एक" वाली पंक्तियों का चयन कैसे करूं?

         col
one two     
a   t      0
    u      1
    v      2
    w      3

इसके अतिरिक्त, मैं आउटपुट में "एक" स्तर कैसे गिरा सकता हूं?

     col
two     
t      0
u      1
v      2
w      3

प्रश्न 1 बी
मैं सभी पंक्तियों को मूल्य "टी" के साथ "स्तर" दो पर कैसे काटूं ?

         col
one two     
a   t      0
b   t      4
    t      8
d   t     12

प्रश्न 2: एक स्तर में कई मानों का चयन करना

मैं आइटम "बी" और "डी" के स्तर "एक" के अनुरूप पंक्तियों का चयन कैसे कर सकता हूं?

         col
one two     
b   t      4
    u      5
    v      6
    w      7
    t      8
d   w     11
    t     12
    u     13
    v     14
    w     15

प्रश्न 2b
मुझे "t" और "w" स्तर "दो" के अनुरूप सभी मान कैसे मिलेंगे?

         col
one two     
a   t      0
    w      3
b   t      4
    w      7
    t      8
d   w     11
    t     12
    w     15

प्रश्न 3: एकल क्रॉस सेक्शन को जोड़ना (x, y)

मैं एक क्रॉस सेक्शन को कैसे प्राप्त कर सकता हूं, अर्थात, इंडेक्स के लिए एक विशिष्ट मान रखने वाली एकल पंक्ति df? विशेष रूप से, मैं ('c', 'u')द्वारा दिए गए क्रॉस सेक्शन को कैसे पुनः प्राप्त करूं

         col
one two     
c   u      9

प्रश्न 4: मल्टीपल क्रॉस सेक्शन को स्लाइस करना [(a, b), (c, d), ...]

मैं करने के लिए इसी दो पंक्तियों का चयन कैसे करूं ('c', 'u'), और ('a', 'w')?

         col
one two     
c   u      9
a   w      3

प्रश्न 5: प्रति स्तर पर कटा हुआ एक आइटम

मैं "स्तर" एक "एक" या "t" स्तर "दो" में संगत सभी पंक्तियों को कैसे प्राप्त कर सकता हूं?

         col
one two     
a   t      0
    u      1
    v      2
    w      3
b   t      4
    t      8
d   t     12

प्रश्न 6: मनमाना टुकड़ा करना

मैं विशिष्ट क्रॉस सेक्शन का टुकड़ा कैसे कर सकता हूं? "ए" और "बी" के लिए, मैं उप-स्तरों "यू" और "वी" के साथ सभी पंक्तियों का चयन करना चाहूंगा, और "डी" के लिए, मैं उप-स्तर "डब्ल्यू" के साथ पंक्तियों का चयन करना चाहूंगा।

         col
one two     
a   u      1
    v      2
b   u      5
    v      6
d   w     11
    w     15

प्रश्न 7 संख्यात्मक स्तर से मिलकर एक अद्वितीय सेटअप का उपयोग करेगा:

np.random.seed(0)
mux2 = pd.MultiIndex.from_arrays([
    list('aaaabbbbbccddddd'),
    np.random.choice(10, size=16)
], names=['one', 'two'])

df2 = pd.DataFrame({'col': np.arange(len(mux2))}, mux2)

         col
one two     
a   5      0
    0      1
    3      2
    3      3
b   7      4
    9      5
    3      6
    5      7
    2      8
c   4      9
    7     10
d   6     11
    8     12
    8     13
    1     14
    6     15

प्रश्न 7: मल्टीएंडेक्स के व्यक्तिगत स्तरों पर संख्यात्मक असमानता द्वारा फ़िल्टरिंग

मुझे उन सभी पंक्तियों को कैसे प्राप्त करना चाहिए जहां स्तर "दो" में मान 5 से अधिक हैं?

         col
one two     
b   7      4
    9      5
c   7     10
d   6     11
    8     12
    8     13
    6     15

नोट: यह पोस्ट मल्टीएंडेक्स बनाने के तरीके, उन पर असाइनमेंट ऑपरेशन या किसी अन्य प्रदर्शन से संबंधित चर्चा कैसे करें (ये अन्य समय के लिए अलग विषय हैं) के माध्यम से नहीं जाएंगे।

जवाबों:


166

मल्टीआंडेक्स / एडवांस्ड इंडेक्सिंग

नोट
इस पोस्ट को निम्न तरीके से संरचित किया जाएगा:

  1. ओपी में पूछे गए सवालों को एक-एक करके संबोधित किया जाएगा
  2. प्रत्येक प्रश्न के लिए, इस समस्या को हल करने और अपेक्षित परिणाम प्राप्त करने के लिए लागू एक या एक से अधिक तरीकों का प्रदर्शन किया जाएगा।

नोट एस (बहुत कुछ इस तरह) पाठकों के लिए अतिरिक्त कार्यक्षमता, कार्यान्वयन विवरण और विषय के लिए अन्य जानकारी सरसरी जानकारी के साथ शामिल किया जाएगा। ये नोट्स डॉक्स को परिमार्जन और विभिन्न अस्पष्ट विशेषताओं को उजागर करने के माध्यम से संकलित किए गए हैं, और मेरे अपने (संयुक्त रूप से सीमित) अनुभव से।

सभी कोड नमूनों ने पांडा v0.23.4, python3.7 पर बनाया और परीक्षण किया है । यदि कुछ स्पष्ट नहीं है, या तथ्यात्मक रूप से गलत है, या यदि आपको अपने उपयोग के मामले में कोई समाधान नहीं मिला है, तो कृपया एक संपादन का सुझाव देने के लिए स्वतंत्र महसूस करें, टिप्पणियों में स्पष्टीकरण का अनुरोध करें, या एक नया प्रश्न खोलें, .... जैसा कि लागू हो ।

यहां कुछ सामान्य मुहावरों का परिचय दिया गया है (इसलिए फोर आइडियम्स के रूप में संदर्भित) हम बार-बार आएंगे

  1. DataFrame.loc- लेबल द्वारा चयन के लिए एक सामान्य समाधान (+ pd.IndexSliceअधिक जटिल अनुप्रयोगों के लिए स्लाइस शामिल)

  2. DataFrame.xs - एक श्रृंखला / DataFrame से एक विशेष क्रॉस सेक्शन निकालें।

  3. DataFrame.query- स्लाइसिंग और / या फ़िल्टरिंग ऑपरेशन को गतिशील रूप से निर्दिष्ट करें (अर्थात, एक अभिव्यक्ति के रूप में जिसका मूल्यांकन गतिशील रूप से किया जाता है। दूसरों की तुलना में कुछ परिदृश्यों पर अधिक लागू होता है। इसके अलावा डॉक्स के इस अनुभाग को मल्टीआईंडेक्स पर क्वेरी करने के लिए देखें।

  4. एक मुखौटा के साथ बूलियन अनुक्रमण का उपयोग करके उत्पन्न MultiIndex.get_level_values(अक्सर के साथ संयोजन के रूप में Index.isin, खासकर जब कई मूल्यों के साथ फ़िल्टरिंग)। यह भी कुछ परिस्थितियों में काफी उपयोगी है।

एक बेहतर समझ हासिल करने के लिए चार मुहावरों के संदर्भ में विभिन्न स्लाइसिंग और फ़िल्टरिंग समस्याओं पर ध्यान देना फायदेमंद होगा जो किसी दिए गए स्थिति पर लागू हो सकते हैं। यह समझना बहुत महत्वपूर्ण है कि सभी मुहावरे हर परिस्थिति में (यदि बिल्कुल भी) समान रूप से अच्छे से काम करेंगे। अगर किसी मुहावरे को नीचे दी गई समस्या के संभावित समाधान के रूप में सूचीबद्ध नहीं किया गया है, तो इसका मतलब है कि मुहावरे को उस समस्या पर प्रभावी रूप से लागू नहीं किया जा सकता है।


प्रश्न 1

मैं "स्तर" "एक" वाली पंक्तियों का चयन कैसे करूं?

         col
one two     
a   t      0
    u      1
    v      2
    w      3

आप locअधिकांश स्थितियों के लिए एक सामान्य उद्देश्य समाधान के रूप में उपयोग कर सकते हैं :

df.loc[['a']]

इस बिंदु पर, यदि आप प्राप्त करते हैं

TypeError: Expected tuple, got str

इसका मतलब है कि आप पांडा के पुराने संस्करण का उपयोग कर रहे हैं। उन्नयन पर विचार करें! अन्यथा, उपयोग करें df.loc[('a', slice(None)), :]

वैकल्पिक रूप से, आप xsयहां उपयोग कर सकते हैं , क्योंकि हम एक एकल क्रॉस सेक्शन निकाल रहे हैं। ध्यान दें levelsऔर axisतर्क (उचित चूक यहां मान ली जा सकती है)।

df.xs('a', level=0, axis=0, drop_level=False)
# df.xs('a', drop_level=False)

यहां, परिणाम में "स्तर" को छोड़ने के स्तर drop_level=Falseको रोकने के लिए तर्क की आवश्यकता है xs(जिस स्तर पर हम फिसल गए थे)।

फिर भी एक और विकल्प यहाँ उपयोग कर रहा है query:

df.query("one == 'a'")

यदि इंडेक्स में कोई नाम नहीं है, तो आपको अपनी क्वेरी स्ट्रिंग को बदलने की आवश्यकता होगी "ilevel_0 == 'a'"

अंत में, का उपयोग कर get_level_values:

df[df.index.get_level_values('one') == 'a']
# If your levels are unnamed, or if you need to select by position (not label),
# df[df.index.get_level_values(0) == 'a']

इसके अतिरिक्त, मैं आउटपुट में "एक" स्तर कैसे गिरा सकता हूं?

     col
two     
t      0
u      1
v      2
w      3

इसे आसानी से इस्तेमाल किया जा सकता है

df.loc['a'] # Notice the single string argument instead the list.

या,

df.xs('a', level=0, axis=0, drop_level=True)
# df.xs('a')

ध्यान दें कि हम drop_levelतर्क को छोड़ सकते हैं (इसे Trueडिफ़ॉल्ट रूप से माना जाता है )।

नोट
आप देख सकते हैं कि फ़िल्टर किए गए DataFrame में अभी भी सभी स्तर हो सकते हैं, भले ही वे DataFrame को प्रिंट करते समय नहीं दिखाते हों। उदाहरण के लिए,

v = df.loc[['a']]
print(v)
         col
one two     
a   t      0
    u      1
    v      2
    w      3

print(v.index)
MultiIndex(levels=[['a', 'b', 'c', 'd'], ['t', 'u', 'v', 'w']],
           labels=[[0, 0, 0, 0], [0, 1, 2, 3]],
           names=['one', 'two'])

आप इन स्तरों से छुटकारा पा सकते हैं MultiIndex.remove_unused_levels:

v.index = v.index.remove_unused_levels()

print(v.index)
MultiIndex(levels=[['a'], ['t', 'u', 'v', 'w']],
           labels=[[0, 0, 0, 0], [0, 1, 2, 3]],
           names=['one', 'two'])

प्रश्न 1 बी

मैं मूल्य "t" के साथ सभी पंक्तियों को "दो" स्तर पर कैसे काटूं?

         col
one two     
a   t      0
b   t      4
    t      8
d   t     12

सहज रूप से, आप कुछ शामिल करना चाहते हैं slice():

df.loc[(slice(None), 't'), :]

इट जस्ट वर्क्स! ™ लेकिन यह क्लंकी है। हम pd.IndexSliceयहां एपीआई का उपयोग करके अधिक प्राकृतिक स्लाइसिंग सिंटैक्स की सुविधा प्रदान कर सकते हैं।

idx = pd.IndexSlice
df.loc[idx[:, 't'], :]

यह बहुत, बहुत क्लीनर है।

नोट कॉलम के पार
अनुगामी टुकड़ा क्यों :आवश्यक है? इसका कारण यह है, locदोनों अक्षों ( axis=0या axis=1) के साथ चयन और स्लाइस करने के लिए इस्तेमाल किया जा सकता है । स्पष्ट रूप से यह स्पष्ट किए बिना कि धुरी को किस अक्ष पर किया जाना है, ऑपरेशन अस्पष्ट हो जाता है। स्लाइसिंग पर प्रलेखन में बड़ा लाल बॉक्स देखें ।

यदि आप अस्पष्टता के किसी भी शेड को दूर करना चाहते हैं, तो locएक axis पैरामीटर को स्वीकार करता है :

df.loc(axis=0)[pd.IndexSlice[:, 't']]

axisपैरामीटर के बिना (यानी, बस कर df.loc[pd.IndexSlice[:, 't']]), स्लाइसिंग को कॉलम पर माना जाता है, और KeyErrorइस परिस्थिति में उठाया जाएगा।

यह स्लाइसर में प्रलेखित है । इस पोस्ट के उद्देश्य के लिए, हालांकि, हम स्पष्ट रूप से सभी कुल्हाड़ियों को निर्दिष्ट करेंगे।

के साथ xs, यह है

df.xs('t', axis=0, level=1, drop_level=False)

के साथ query, यह है

df.query("two == 't'")
# Or, if the first level has no name, 
# df.query("ilevel_1 == 't'") 

और अंत में get_level_values, आप कर सकते हैं

df[df.index.get_level_values('two') == 't']
# Or, to perform selection by position/integer,
# df[df.index.get_level_values(1) == 't']

सभी एक ही प्रभाव के लिए।


प्रश्न 2

मैं आइटम "बी" और "डी" के स्तर "एक" के अनुरूप पंक्तियों का चयन कैसे कर सकता हूं?

         col
one two     
b   t      4
    u      5
    v      6
    w      7
    t      8
d   w     11
    t     12
    u     13
    v     14
    w     15

लोक का उपयोग करते हुए, यह एक सूची निर्दिष्ट करके इसी तरह से किया जाता है।

df.loc[['b', 'd']]

"बी" और "डी" के चयन की उपरोक्त समस्या को हल करने के लिए, आप भी उपयोग कर सकते हैं query:

items = ['b', 'd']
df.query("one in @items")
# df.query("one == @items", parser='pandas')
# df.query("one in ['b', 'd']")
# df.query("one == ['b', 'd']", parser='pandas')

नोट
हाँ, डिफ़ॉल्ट पार्सर है 'pandas', लेकिन इस वाक्यविन्यास को उजागर करना महत्वपूर्ण है पारंपरिक रूप से अजगर नहीं है। पांडस पार्सर अभिव्यक्ति से थोड़ा अलग पार्स पेड़ उत्पन्न करता है। यह निर्दिष्ट करने के लिए कुछ कार्यों को अधिक सहज बनाने के लिए किया जाता है। अधिक जानकारी के लिए, कृपया pd.eval () का उपयोग करके पांडा में डायनामिक अभिव्यक्ति मूल्यांकन पर मेरी पोस्ट पढ़ें ।

और, get_level_values+ के साथ Index.isin:

df[df.index.get_level_values("one").isin(['b', 'd'])]

प्रश्न 2 बी

मुझे "t" और "w" स्तर "दो" के अनुरूप सभी मान कैसे प्राप्त होंगे?

         col
one two     
a   t      0
    w      3
b   t      4
    w      7
    t      8
d   w     11
    t     12
    w     15

इसके साथ loc, यह केवल संयोजन के साथ संभव है pd.IndexSlice

df.loc[pd.IndexSlice[:, ['t', 'w']], :] 

पहले पेट :में pd.IndexSlice[:, ['t', 'w']]साधन प्रथम स्तर के पार काट करने के लिए। जैसे-जैसे स्तर की गहराई बढ़ती जा रही है, आपको और अधिक स्लाइस निर्दिष्ट करने की आवश्यकता होगी, एक स्तर के पार स्लाइस किया जा रहा है। हालांकि, आपको कटा हुआ होने के अलावा और अधिक स्तरों को निर्दिष्ट करने की आवश्यकता नहीं होगी ।

के साथ query, यह है

items = ['t', 'w']
df.query("two in @items")
# df.query("two == @items", parser='pandas') 
# df.query("two in ['t', 'w']")
# df.query("two == ['t', 'w']", parser='pandas')

साथ get_level_valuesऔर Index.isin(ऊपर के समान):

df[df.index.get_level_values('two').isin(['t', 'w'])]

प्रश्न 3

मैं एक क्रॉस सेक्शन को कैसे प्राप्त कर सकता हूं, अर्थात, इंडेक्स के लिए एक विशिष्ट मान रखने वाली एकल पंक्ति df? विशेष रूप से, मैं ('c', 'u')द्वारा दिए गए क्रॉस सेक्शन को कैसे पुनः प्राप्त करूं

         col
one two     
c   u      9

locचाबियों का एक समूह निर्दिष्ट करके उपयोग करें :

df.loc[('c', 'u'), :]

या,

df.loc[pd.IndexSlice[('c', 'u')]]

नोट
इस बिंदु पर, आप PerformanceWarningइस तरह दिख सकते हैं:

PerformanceWarning: indexing past lexsort depth may impact performance.

इसका मतलब यह है कि आपका सूचकांक क्रमबद्ध नहीं है। पैंडा इष्टतम खोज और पुनर्प्राप्ति के लिए अनुक्रमित होने पर (इस मामले में, शाब्दिक रूप से, हम स्ट्रिंग मान के साथ काम कर रहे हैं) पर निर्भर करता है। एक त्वरित फिक्स अग्रिम में उपयोग करके अपने डेटाफ़्रेम को सॉर्ट करना होगा DataFrame.sort_index। यह विशेष रूप से एक प्रदर्शन के दृष्टिकोण से वांछनीय है, अगर आप मिलकर ऐसे कई प्रश्न करते हैं:

df_sort = df.sort_index()
df_sort.loc[('c', 'u')]

आप यह MultiIndex.is_lexsorted()जांचने के लिए भी उपयोग कर सकते हैं कि सूचकांक अनुक्रमित है या नहीं। यह फ़ंक्शन रिटर्न Trueया Falseतदनुसार। आप इस फ़ंक्शन को यह निर्धारित करने के लिए कॉल कर सकते हैं कि अतिरिक्त सॉर्टिंग चरण की आवश्यकता है या नहीं।

इसके साथ xs, यह फिर से पहले तर्क के रूप में एकल टपल को पारित कर रहा है, अन्य सभी तर्कों के साथ उनके उचित चूक के लिए सेट किया गया है:

df.xs(('c', 'u'))

के साथ query, चीजें थोड़ी भद्दी हो जाती हैं:

df.query("one == 'c' and two == 'u'")

अब आप देख सकते हैं कि इसे सामान्य बनाना अपेक्षाकृत कठिन है। लेकिन फिर भी इस विशेष समस्या के लिए ठीक है।

कई स्तरों पर फैले एक्सेस के साथ, get_level_valuesअभी भी उपयोग किया जा सकता है, लेकिन अनुशंसित नहीं है:

m1 = (df.index.get_level_values('one') == 'c')
m2 = (df.index.get_level_values('two') == 'u')
df[m1 & m2]

प्रश्न 4

मैं करने के लिए इसी दो पंक्तियों का चयन कैसे करूं ('c', 'u'), और ('a', 'w')?

         col
one two     
c   u      9
a   w      3

इसके साथ loc, यह अभी भी उतना ही सरल है:

df.loc[[('c', 'u'), ('a', 'w')]]
# df.loc[pd.IndexSlice[[('c', 'u'), ('a', 'w')]]]

इसके साथ query, आपको अपने क्रॉस सेक्शन और स्तरों पर पुनरावृति करके गतिशील रूप से एक क्वेरी स्ट्रिंग उत्पन्न करने की आवश्यकता होगी:

cses = [('c', 'u'), ('a', 'w')]
levels = ['one', 'two']
# This is a useful check to make in advance.
assert all(len(levels) == len(cs) for cs in cses) 

query = '(' + ') or ('.join([
    ' and '.join([f"({l} == {repr(c)})" for l, c in zip(levels, cs)]) 
    for cs in cses
]) + ')'

print(query)
# ((one == 'c') and (two == 'u')) or ((one == 'a') and (two == 'w'))

df.query(query)

100% मत करो! लेकिन यह संभव है।


प्रश्न 5

मैं "स्तर" एक "एक" या "t" स्तर "दो" में संगत सभी पंक्तियों को कैसे प्राप्त कर सकता हूं?

         col
one two     
a   t      0
    u      1
    v      2
    w      3
b   t      4
    t      8
d   t     12

यह वास्तव में locशुद्धता सुनिश्चित करते हुए और अभी भी कोड स्पष्टता बनाए रखने के साथ करना बहुत मुश्किल है । df.loc[pd.IndexSlice['a', 't']]यह गलत है, इसकी व्याख्या की जाती है df.loc[pd.IndexSlice[('a', 't')]](जैसे, क्रॉस सेक्शन का चयन करना)। आप pd.concatप्रत्येक लेबल को अलग से संभालने के साथ एक समाधान के बारे में सोच सकते हैं :

pd.concat([
    df.loc[['a'],:], df.loc[pd.IndexSlice[:, 't'],:]
])

         col
one two     
a   t      0
    u      1
    v      2
    w      3
    t      0   # Does this look right to you? No, it isn't!
b   t      4
    t      8
d   t     12

लेकिन आप देखेंगे कि एक पंक्ति दोहराई गई है। ऐसा इसलिए है क्योंकि उस पंक्ति ने दोनों स्लाइसिंग शर्तों को संतुष्ट किया है, और इसलिए दो बार दिखाई दिया। आपको इसके बजाय करने की आवश्यकता होगी

v = pd.concat([
        df.loc[['a'],:], df.loc[pd.IndexSlice[:, 't'],:]
])
v[~v.index.duplicated()]

लेकिन अगर आपके डेटाफ़्रेम में अंतर्निहित डुप्लिकेट इंडेक्स (जो आप चाहते हैं) शामिल हैं, तो यह उन्हें बनाए नहीं रखेगा। अत्यधिक सावधानी के साथ उपयोग करें

इसके साथ query, यह मूर्खतापूर्ण सरल है:

df.query("one == 'a' or two == 't'")

इसके साथ get_level_values, यह अभी भी सरल है, लेकिन उतना सुरुचिपूर्ण नहीं है:

m1 = (df.index.get_level_values('one') == 'a')
m2 = (df.index.get_level_values('two') == 't')
df[m1 | m2] 

प्रश्न 6

मैं विशिष्ट क्रॉस सेक्शन का टुकड़ा कैसे कर सकता हूं? "ए" और "बी" के लिए, मैं उप-स्तरों "यू" और "वी" के साथ सभी पंक्तियों का चयन करना चाहूंगा, और "डी" के लिए, मैं उप-स्तर "डब्ल्यू" के साथ पंक्तियों का चयन करना चाहूंगा।

         col
one two     
a   u      1
    v      2
b   u      5
    v      6
d   w     11
    w     15

यह एक विशेष मामला है जिसे मैंने चार मुहावरों की प्रयोज्यता को समझने में मदद करने के लिए जोड़ा है - यह एक ऐसा मामला है जहां उनमें से कोई भी प्रभावी ढंग से काम नहीं करेगा, क्योंकि स्लाइसिंग बहुत विशिष्ट है, और किसी भी वास्तविक पैटर्न का पालन नहीं करता है।

आमतौर पर, इस तरह की समस्याओं को कम करने के लिए कुंजी की सूची को स्पष्ट रूप से पारित करने की आवश्यकता होगी loc। ऐसा करने का एक तरीका यह है:

keys = [('a', 'u'), ('a', 'v'), ('b', 'u'), ('b', 'v'), ('d', 'w')]
df.loc[keys, :]

यदि आप कुछ टाइपिंग को सहेजना चाहते हैं, तो आप यह पहचानेंगे कि "a", "b" और इसके उपशीर्षों को स्लाइस करने का एक पैटर्न है, इसलिए हम स्लाइसिंग कार्य को दो भागों में विभाजित कर सकते हैं और concatपरिणाम:

pd.concat([
     df.loc[(('a', 'b'), ('u', 'v')), :], 
     df.loc[('d', 'w'), :]
   ], axis=0)

"ए" और "बी" के लिए स्लाइसिंग विनिर्देश थोड़ा साफ है (('a', 'b'), ('u', 'v'))क्योंकि समान उप-स्तरों को अनुक्रमित किया जा रहा है जो प्रत्येक स्तर के लिए समान हैं।


प्रश्न 7

मुझे उन सभी पंक्तियों को कैसे प्राप्त करना चाहिए जहां स्तर "दो" में मान 5 से अधिक हैं?

         col
one two     
b   7      4
    9      5
c   7     10
d   6     11
    8     12
    8     13
    6     15

यह प्रयोग करके किया जा सकता है query,

df2.query("two > 5")

और get_level_values

df2[df2.index.get_level_values('two') > 5]

नोट
इस उदाहरण के समान, हम इन निर्माणों का उपयोग करके किसी भी मनमानी स्थिति के आधार पर फ़िल्टर कर सकते हैं। सामान्य तौर पर, यह है कि याद करने के लिए उपयोगी है locऔर xsलेबल आधारित अनुक्रमण के लिए विशेष रूप से कर रहे हैं, जबकि queryऔर get_level_valuesछानने के लिए सामान्य सशर्त मास्क के निर्माण के लिए सहायक होते हैं।


बोनस प्रश्न

क्या होगा यदि मुझे एक MultiIndex कॉलम को स्लाइस करने की आवश्यकता है ?

दरअसल, यहां ज्यादातर समाधान छोटे बदलावों के साथ ही कॉलम पर भी लागू होते हैं। विचार करें:

np.random.seed(0)
mux3 = pd.MultiIndex.from_product([
        list('ABCD'), list('efgh')
], names=['one','two'])

df3 = pd.DataFrame(np.random.choice(10, (3, len(mux))), columns=mux3)
print(df3)

one  A           B           C           D         
two  e  f  g  h  e  f  g  h  e  f  g  h  e  f  g  h
0    5  0  3  3  7  9  3  5  2  4  7  6  8  8  1  6
1    7  7  8  1  5  9  8  9  4  3  0  3  5  0  2  3
2    8  1  3  3  3  7  0  1  9  9  0  4  7  3  2  7

ये निम्नलिखित बदलाव हैं, जिन्हें आपको स्तंभों के साथ काम करने के लिए चार मुहावरों के लिए करना होगा।

  1. के साथ टुकड़ा करने के लिए loc, का उपयोग करें

    df3.loc[:, ....] # Notice how we slice across the index with `:`. 

    या,

    df3.loc[:, pd.IndexSlice[...]]
  2. xsउपयुक्त के रूप में उपयोग करने के लिए , बस एक तर्क पास करें axis=1

  3. आप सीधे उपयोग करके कॉलम स्तर मानों तक पहुँच सकते हैं df.columns.get_level_values। फिर आपको कुछ ऐसा करने की आवश्यकता होगी

    df.loc[:, {condition}] 

    जहां {condition}कुछ स्थिति का उपयोग करके बनाया गया है columns.get_level_values

  4. उपयोग करने के लिए query, आपका एकमात्र विकल्प अनुक्रमणिका, सूचकांक पर क्वेरी और फिर से प्रस्ताव करना है:

    df3.T.query(...).T

    अनुशंसित नहीं, अन्य 3 विकल्पों में से एक का उपयोग करें।


6

हाल ही में मैं एक उपयोग के मामले में आया था, जहां मेरे पास 3-स्तरीय मल्टी-इंडेक्स डेटाफ्रेम था, जिसमें मैं ऊपर दिए गए किसी भी समाधान को नहीं बना सका, जिसके परिणाम मैं देख रहा था। यह काफी संभव है कि उपरोक्त समाधान मेरे उपयोग के मामले के लिए निश्चित रूप से काम करते हैं, और मैंने कई प्रयास किए, हालांकि मैं उन्हें उस समय के साथ काम करने में असमर्थ था जो मैंने उपलब्ध था।

मैं विशेषज्ञ से बहुत दूर हूं, लेकिन मैं एक समाधान में डूबा हुआ हूं जो ऊपर दिए गए व्यापक उत्तरों में सूचीबद्ध नहीं था। मैं कोई गारंटी नहीं देता कि समाधान किसी भी तरह से इष्टतम हैं।

यह प्रश्न # 6 से थोड़ा अलग परिणाम प्राप्त करने का एक अलग तरीका है। (और साथ ही अन्य प्रश्नों की संभावना)

विशेष रूप से मैं देख रहा था:

  1. सूचकांक के एक स्तर से दो + मान चुनने का एक तरीका और सूचकांक के एक और स्तर से एक एकल मान है, और
  2. डेटाफ़्रेम आउटपुट में पिछले ऑपरेशन से सूचकांक मूल्यों को छोड़ने का एक तरीका है।

गियर्स में एक बंदर रिंच (हालांकि पूरी तरह से तय करने योग्य):

  1. सूचकांक अनाम थे।

नीचे खिलौना डेटाफ़्रेम पर:

    index = pd.MultiIndex.from_product([['a','b'],
                               ['stock1','stock2','stock3'],
                               ['price','volume','velocity']])

    df = pd.DataFrame([1,2,3,4,5,6,7,8,9,
                      10,11,12,13,14,15,16,17,18], 
                       index)

                        0
    a stock1 price      1
             volume     2
             velocity   3
      stock2 price      4
             volume     5
             velocity   6
      stock3 price      7
             volume     8
             velocity   9
    b stock1 price     10
             volume    11
             velocity  12
      stock2 price     13
             volume    14
             velocity  15
      stock3 price     16
             volume    17
             velocity  18

नीचे दिए गए कार्यों का उपयोग करना, निश्चित रूप से:

    df.xs(('stock1', 'velocity'), level=(1,2))

        0
    a   3
    b  12

लेकिन मैं एक अलग परिणाम चाहता था, इसलिए उस परिणाम को प्राप्त करने की मेरी विधि थी:

   df.iloc[df.index.isin(['stock1'], level=1) & 
           df.index.isin(['velocity'], level=2)] 

                        0
    a stock1 velocity   3
    b stock1 velocity  12

और अगर मुझे एक स्तर से दो + मान चाहिए और दूसरे स्तर से एक एकल (या 2+) मूल्य:

    df.iloc[df.index.isin(['stock1','stock3'], level=1) & 
            df.index.isin(['velocity'], level=2)] 

                        0
    a stock1 velocity   3
      stock3 velocity   9
    b stock1 velocity  12
      stock3 velocity  18

उपरोक्त विधि शायद थोड़ी क्लूनी है, हालांकि मैंने पाया कि यह मेरी जरूरतों को पूरा करता है और एक बोनस के रूप में मेरे लिए समझना और पढ़ना आसान था।


2
अच्छा, levelतर्क के बारे में पता नहीं था Index.isin!
cs95
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.