2015-12-08 37 views
9

muszę filtrować ramki danych z dict, zbudowany z kluczem jest nazwa kolumny, a wartość jest wartością, że chcę, aby filtrować:Filtrowanie dataframe pandy korzystając z wartości dict

filter_v = {'A':1, 'B':0, 'C':'This is right'} 
# this would be the normal approach 
df[(df['A'] == 1) & (df['B'] ==0)& (df['C'] == 'This is right')] 

ale chcę zrobić coś na liniach

for column, value in filter_v.items(): 
    df[df[column] == value] 

ale to będzie filtrować ramki danych kilka razy, jedną wartość w czasie, a nie zastosowanie wszystkich filtrów jednocześnie. Czy istnieje sposób, aby to zrobić programowo?

EDIT: Przykład:

df1 = pd.DataFrame({'A':[1,0,1,1, np.nan], 'B':[1,1,1,0,1], 'C':['right','right','wrong','right', 'right'],'D':[1,2,2,3,4]}) 
filter_v = {'A':1, 'B':0, 'C':'right'} 
df1.loc[df1[filter_v.keys()].isin(filter_v.values()).all(axis=1), :] 

daje

A B C D 
0 1 1 right 1 
1 0 1 right 2 
3 1 0 right 3 

ale oczekiwany wynik był

A B C D 
3 1 0 right 3 

tylko ostatnia powinna być zaznaczona.

+0

Jakie jest pożądane wyjście? –

+0

Ramka danych zawierająca tylko wartości odpowiadające wszystkim warunkom jednocześnie. – Ivan

Odpowiedz

18

IIUC, powinieneś być w stanie zrobić coś takiego:

>>> df1.loc[(df1[list(filter_v)] == pd.Series(filter_v)).all(axis=1)] 
    A B  C D 
3 1 0 right 3 

to działa przez tworząc serię do porównania z:

>>> pd.Series(filter_v) 
A  1 
B  0 
C right 
dtype: object 

Wybór odpowiedniej części df1:

>>> df1[list(filter_v)] 
    A  C B 
0 1 right 1 
1 0 right 1 
2 1 wrong 1 
3 1 right 0 
4 NaN right 1 

Znalezienie gdzie pasuje:

>>> df1[list(filter_v)] == pd.Series(filter_v) 
     A  B  C 
0 True False True 
1 False False True 
2 True False False 
3 True True True 
4 False False True 

Znalezienie gdzie wszystko mecz:

>>> (df1[list(filter_v)] == pd.Series(filter_v)).all(axis=1) 
0 False 
1 False 
2 False 
3  True 
4 False 
dtype: bool 

I wreszcie za pomocą tego indeksu do df1:

>>> df1.loc[(df1[list(filter_v)] == pd.Series(filter_v)).all(axis=1)] 
    A B  C D 
3 1 0 right 3 
+0

Ładne rozwiązanie i niesamowite wyjaśnienie. – Ivan

+0

@ DSM jak sprawdzić, czy kolumny 'df' z' dict.keys' zawierają 'str' z' dict.values' ?? –

1

Oto sposób, aby to zrobić:

df.loc[df[filter_v.keys()].isin(filter_v.values()).all(axis=1), :] 

UPDATE:

Z wartości są takie same w całej kolumny można wtedy zrobić coś takiego:

# Create your filtering function: 

def filter_dict(df, dic): 
    return df[df[dic.keys()].apply(
      lambda x: x.equals(pd.Series(dic.values(), index=x.index, name=x.name)), asix=1)] 

# Use it on your DataFrame: 

filter_dict(df1, filter_v) 

Która wydajność:

A B  C D 
3 1 0 right 3    

Jeśli jest coś, czego nie często można iść tak daleko, aby załatać DataFrame dla łatwego dostępu do tego filtra:

pd.DataFrame.filter_dict_ = filter_dict 

a następnie użyć tego filtru tak:

df1.filter_dict_(filter_v) 

Która przyniosłoby taki sam wynik.

ALE, to nie jest sposób, aby to zrobić, prawo. Używałbym podejścia DSM.

+0

Dzięki, ale wygląda na to, że dotyczy to tylko ostatniej pary kluczy w dyktafonie. – Ivan

+0

Nie jestem pewien, czy rozumiem, co mówisz ... To podejście jest prostym filtrem wszystkich kolumn, które są zakodowane jako klucze w słowniku 'filter', a następnie filtrują wszystkie wartości w wierszach, aby dopasować wartości w słowniku. Być może możesz zilustrować problem powtarzalnym przykładem? – Primer

+0

Zobacz aktualizację, która rozwiązuje ten problem. – Primer

1

Oto kolejny sposób:

filterSeries = pd.Series(np.ones(df.shape[0],dtype=bool)) 
for column, value in filter_v.items(): 
    filterSeries = ((df[column] == value) & filterSeries) 

Daje:

>>> df[filterSeries] 
    A B  C D 
3 1 0 right 3