Meerdere items filteren in een Python Panda-dataframe met meerdere indexen

Ik heb de volgende tabel:

Opmerking: zowel NSRCODE als PBL_AWI zijn indexen

Opmerking: de kolom % van het gebied zou zijn ingevuld, maar heb dit nog niet gedaan.

NSRCODE  PBL_AWI          Area           % Of Area
CM       BONS             44705.492941
         BTNN            253854.591990
         FONG             41625.590370
         FONS             16814.159680
         Lake             57124.819333
         River             1603.906642
         SONS            583958.444751
         STNN             45603.837177
         clearcut        106139.013930
         disturbed       127719.865675
         lowland         118795.578059
         upland         2701289.270193
LBH      BFNN            289207.169650
         BONS           9140084.716743
         BTNI             33713.160390
         BTNN          19748004.789040
         FONG           1687122.469691
         FONS           5169959.591270
         FTNI            317251.976160
         FTNN           6536472.869395
         Lake            258046.508310
         River            44262.807900
         SONS           4379097.677405
         burn regen      744773.210860
         clearcut         54066.756790
         disturbed       597561.471686
         lowland       12591619.141842
         upland        23843453.638117

Hoe filter ik een item uit de “PBL_AWI”-index?
Ik wil bijvoorbeeld [‘Lake’, ‘River’, ‘Upland’]

. behouden


Antwoord 1, autoriteit 100%

Je kunt get_level_valuesgebruiken in combinatie met Boolean slicing.

In [50]:
print df[np.in1d(df.index.get_level_values(1), ['Lake', 'River', 'Upland'])]
                          Area
NSRCODE PBL_AWI               
CM      Lake      57124.819333
        River      1603.906642
LBH     Lake     258046.508310
        River     44262.807900

Hetzelfde idee kan op veel verschillende manieren worden uitgedrukt, zoals df[df.index.get_level_values('PBL_AWI').isin(['Lake', 'River', 'Upland'])]

Houd er rekening mee dat u 'Upland'in uw gegevens heeft in plaats van 'Upland'


Antwoord 2, autoriteit 42%

Een andere (misschien schonere) manier zou deze kunnen zijn:

print(df[df.index.isin(['Lake', 'River', 'Upland'], level=1)])

De parameter levelspecificeert het indexnummer (beginnend met 0) of indexnaam (hier: level='PBL_AWI')


Antwoord 3, autoriteit 7%

Ook (van hier):

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

… te gebruiken als

df.filter_by({'PBL_AWI' : ['Lake', 'River', 'Upland']})

(niet getest met panelen en elementen met een hogere dimensie, maar ik verwacht wel dat het werkt)


Antwoord 4, autoriteit 4%

df.filter(regex=…,axis=…)is nog beknopter, omdat het werkt op zowel index=0 als kolom=1 as. U hoeft zich geen zorgen te maken over niveaus en u kunt lui zijn met regex. Compleet voorbeeld voor filter op index:

df.filter(regex='Lake|River|Upland',axis=0)

voer hier de afbeeldingsbeschrijving in

als je het transponeert en probeert te filteren op kolommen (standaard as=1), werkt het ook:

df.T.filter(regex='Lake|River|Upland')

voer hier de afbeeldingsbeschrijving in

Nu kun je met regex ook gemakkelijk hoofdletters oplossen met Upland:

upland = re.compile('Upland', re.IGNORECASE)
df.filter(regex=upland ,axis=0)

voer hier de afbeeldingsbeschrijving in

Dit is het commando om bovenstaande invoertabel te lezen:

df = pd.read_csv(io.StringIO(inpute_table), sep="\s{2,}").set_index(['NSRCODE', 'PBL_AWI'])


Antwoord 5, autoriteit 2%

Een eenvoudigere aanpak met behulp van .loczou zijn

df.loc[(slice(None),['Lake', 'River', 'Upland'])]

slice(None)betekent geen filtering op de index op het eerste niveau. We kunnen de index op het tweede niveau filteren met behulp van een lijst met waarden ['Lake', 'River', 'Upland']


Antwoord 6

Dit is een antwoord op een kleine variant van de gestelde vraag die iemand anders misschien wat tijd kan besparen. Als u op zoek bent naar een wildcard-type overeenkomst met een label waarvan u de exacte waarde niet weet, kunt u zoiets als dit gebruiken:

q_labels = [ label for label in df.index.levels[1] if label.startswith('Q') ]
new_df = df[ df.index.isin(q_labels, level=1) ]

Other episodes