2014-04-10 9 views
9

this answer से प्रेरित और this question के आसान उत्तर की कमी के कारण मैंने खुद को मल्टीइंडेक्स स्तर द्वारा फ़िल्टर करने के लिए जीवन को आसान बनाने के लिए एक छोटी वाक्य रचनात्मक चीनी लिखने में पाया।स्लाइस पांडा मल्टीइंडेक्स स्तर या सबलेवल द्वारा डेटाफ्रेम

def _filter_series(x, level_name, filter_by): 
    """ 
    Filter a pd.Series or pd.DataFrame x by `filter_by` on the MultiIndex level 
    `level_name` 

    Uses `pd.Index.get_level_values()` in the background. `filter_by` is either 
    a string or an iterable. 
    """ 
    if isinstance(x, pd.Series) or isinstance(x, pd.DataFrame): 
     if type(filter_by) is str: 
      filter_by = [filter_by] 

     index = x.index.get_level_values(level_name).isin(filter_by) 
     return x[index] 
    else: 
     print "Not a pandas object" 

लेकिन अगर मैं पांडा विकास दल जानते हैं (और मैं शुरू कर रहा हूँ, धीरे धीरे!) वहाँ पहले से ही यह करने के लिए एक अच्छा तरीका है, और मैं बस नहीं जानता कि यह अभी तक है!

क्या मैं सही हूँ?

उत्तर

1

आपके पास filter विधि है जो इस तरह की चीजें कर सकती है। उदाहरण है कि linked तो सवाल में पूछा गया था के साथ उदाहरण के लिए:

In [188]: df.filter(like='0630', axis=0) 
Out[188]: 
         sales  cogs net_pft 
STK_ID RPT_Date         
876 20060630 857483000 729541000 67157200 
     20070630 1146245000 1050808000 113468500 
     20080630 1932470000 1777010000 133756300 
2254 20070630 501221000 289167000 118012200 

फिल्टर विधि पल (आगामी 0.14 में) पर refactored है, और एक level कीवर्ड जोड़ दिया जाएगा (क्योंकि अब आप एक समस्या है, तो हो सकता है सूचकांक के विभिन्न स्तरों में एक ही लेबल दिखाई देते हैं)।

3

इस मास्टर में नई बहु-सूचकांक स्लाइसर का उपयोग कर बहुत आसान है/0.14 (जल्द ही रिहा), here

देख रहे बनाने के लिए इस syntatically आसान (इसकी मुश्किल नहीं करने के लिए), here देखना एक खुला मुद्दा है इस तरह जैसे कुछ: df.loc[{ 'third' : ['C1','C3'] }] मुझे लगता है कि उचित है

यहाँ कैसे आप यह कर सकते है (की आवश्यकता है मास्टर/0.14):

In [2]: def mklbl(prefix,n): 
    ...:  return ["%s%s" % (prefix,i) for i in range(n)] 
    ...: 


In [11]: index = MultiIndex.from_product([mklbl('A',4), 
mklbl('B',2), 
mklbl('C',4), 
mklbl('D',2)],names=['first','second','third','fourth']) 

In [12]: columns = ['value'] 

In [13]: df = DataFrame(np.arange(len(index)*len(columns)).reshape((len(index),len(columns))),index=index,columns=columns).sortlevel() 

In [14]: df 
Out[14]: 
          value 
first second third fourth  
A0 B0  C0 D0   0 
        D1   1 
      C1 D0   2 
        D1   3 
      C2 D0   4 
        D1   5 
      C3 D0   6 
        D1   7 
     B1  C0 D0   8 
        D1   9 
      C1 D0   10 
        D1   11 
      C2 D0   12 
        D1   13 
      C3 D0   14 
        D1   15 
A1 B0  C0 D0   16 
        D1   17 
      C1 D0   18 
        D1   19 
      C2 D0   20 
        D1   21 
      C3 D0   22 
        D1   23 
     B1  C0 D0   24 
        D1   25 
      C1 D0   26 
        D1   27 
      C2 D0   28 
        D1   29 
      C3 D0   30 
        D1   31 
A2 B0  C0 D0   32 
        D1   33 
      C1 D0   34 
        D1   35 
      C2 D0   36 
        D1   37 
      C3 D0   38 
        D1   39 
     B1  C0 D0   40 
        D1   41 
      C1 D0   42 
        D1   43 
      C2 D0   44 
        D1   45 
      C3 D0   46 
        D1   47 
A3 B0  C0 D0   48 
        D1   49 
      C1 D0   50 
        D1   51 
      C2 D0   52 
        D1   53 
      C3 D0   54 
        D1   55 
     B1  C0 D0   56 
        D1   57 
      C1 D0   58 
        D1   59 
          ... 

[64 rows x 1 columns] 

le के सभी भर में एक इंडेक्सर बनाएं VELS, सभी प्रविष्टियों का चयन

In [15]: indexer = [slice(None)]*len(df.index.names) 

स्तर के बारे में हम केवल परवाह प्रविष्टियों हम परवाह किया है के बारे में

In [16]: indexer[df.index.names.index('third')] = ['C1','C3'] 

यह चयन करें (अपने महत्वपूर्ण है कि यह एक टपल है!)

In [18]: df.loc[tuple(indexer),:] 
Out[18]: 
          value 
first second third fourth  
A0 B0  C1 D0   2 
        D1   3 
      C3 D0   6 
        D1   7 
     B1  C1 D0   10 
        D1   11 
      C3 D0   14 
        D1   15 
A1 B0  C1 D0   18 
        D1   19 
      C3 D0   22 
        D1   23 
     B1  C1 D0   26 
        D1   27 
      C3 D0   30 
        D1   31 
A2 B0  C1 D0   34 
        D1   35 
      C3 D0   38 
        D1   39 
     B1  C1 D0   42 
        D1   43 
      C3 D0   46 
        D1   47 
A3 B0  C1 D0   50 
        D1   51 
      C3 D0   54 
        D1   55 
     B1  C1 D0   58 
        D1   59 
      C3 D0   62 
        D1   63 

[32 rows x 1 columns] 
+0

स्पष्टता के लिए, मैन्युअल रूप से इस dataframe wou पर यह कर ld 'df.loc की तरह दिखें [pd.IndexSlice [:,:, [' C1 ',' C3 '],:],:] 'या' df.loc (axis = 0) [:,:, [' C1 ',' सी 3 '],:] – joris

+0

क्या मल्टीइंडेक्स से दिनांक सीमा का चयन करने का कोई तरीका है? मेरे पास 'df.loc है [:, pd.IndexSlice [:,:,:,:, 'value']] 'जहां पहला': 'एक तिथि होगी और मैं कई तिथियों से टुकड़ा करना चाहता हूं न कि सिर्फ एक दिन – toasteez

4

मैंने वास्तव में जोरीस के जवाब को उखाड़ फेंक दिया ... लेकिन दुर्भाग्यवश वह उल्लेख करता है कि वह 0.14 में नहीं हुआ है और न ही 0.17 में हो रहा है। तो पल के लिए मुझे एक त्वरित और गंदे समाधान (स्पष्ट रूप से जेफ के एक से प्राप्त) का सुझाव देने दें:

def filter_by(df, constraints): 
    """Filter MultiIndex by sublevels.""" 
    indexer = [constraints[name] if name in constraints else slice(None) 
       for name in df.index.names] 
    return df.loc[tuple(indexer)] if len(df.shape) == 1 else df.loc[tuple(indexer),] 

pd.Series.filter_by = filter_by 
pd.DataFrame.filter_by = filter_by 

...

df.filter_by({'level_name' : value}) 

जहां value वास्तव में एक भी मान हो सकता है के रूप में प्रयोग की जाने वाली, लेकिन यह भी एक सूची, एक टुकड़ा ...

(पैनलों और उच्च आयाम तत्वों के साथ अपरीक्षित, लेकिन मैं इसे काम करने की उम्मीद करते हैं)

संबंधित मुद्दे