2013-07-17 9 views
10

Mam dataframe pandy takiego:Pandy dataframe: Sprawdź, czy dane są monotonicznie maleje

Balance  Jan  Feb  Mar  Apr 
0 9.724135 0.389376 0.464451 0.229964 0.691504 
1 1.114782 0.838406 0.679096 0.185135 0.143883 
2 7.613946 0.960876 0.220274 0.788265 0.606402 
3 0.144517 0.800086 0.287874 0.223539 0.206002 
4 1.332838 0.430812 0.939402 0.045262 0.388466 

chciałbym grupa wierszy, których autorem jest zastanawianie się, czy wartości od stycznia aż do Apr są monotonicznie maleje (jak w wierszach indeksowanych 1 i 3) lub nie, a następnie sumują salda dla każdej grupy, tzn. na koniec chciałbym otrzymać dwie liczby (1,259299 dla malejącej serii czasowej i 18,670919 dla pozostałych).

Wydaje mi się, że gdybym mógł dodać kolumnę "maleje", to znaczy, że mógłbym robić sumy przy użyciu grupowego pandy, ale w jaki sposób utworzyć tę kolumnę?

Dzięki Anne

+0

Czy myślałeś o kolumnie booleans za każdy miesiąc? Masz przejście od malejącego do rosnącego w różnych wierszach. – TomAugspurger

+0

Ahh nevermind. Masz na myśli zmniejszenie z miesiąca na miesiąc. Po drugiej stronie kolumn. – TomAugspurger

Odpowiedz

9

Można użyć jednej z funkcji is_monotonic z algos:

In [10]: months = ['Jan', 'Feb', 'Mar', 'Apr'] 

In [11]: df.loc[:, months].apply(lambda x: pd.algos.is_monotonic_float64(-x)[0], 
             axis=1) 
Out[11]: 
0 False 
1  True 
2 False 
3  True 
4 False 
dtype: bool 

The is_monotonic sprawdza, czy tablica to malejącą stąd -x.values.

(Wydaje znacznie szybciej niż rozwiązania Toma, nawet przy użyciu małych DataFrame warunkiem.)

+2

@TomAugspurger Myślę, że słowo, którego szukasz, jest "pandastyczne" ... \ * ahem \ *. –

+0

Dzięki Andy, działa to pięknie. Mam głupie pytanie - próbowałem znaleźć dokumentację dotyczącą funkcji is_monotonic i nie mogę znaleźć żadnego online. Czy masz link? – Anne

+0

Kolejne pytanie - nie mogę po prostu napisać '-x' zamiast' -x.values' w 'df.loc [:, months] .apply (lambda x: pd.algos.is_monotonic_float64 (-x.wartości) [0], oś = 1) '? Próbowałem i * wydawało się, że działa. – Anne

5
months = ['Jan', 'Feb', 'Mar', 'Apr'] 

Transpozycja tak, że możemy użyć metody diff (który nie bierze argument oś). Wypełniamy pierwszy wiersz (styczeń) wartością 0. W przeciwnym razie jest to NaN.

In [77]: df[months].T.diff().fillna(0) <= 0 
Out[77]: 
     0  1  2  3  4 
Jan True True True True True 
Feb False True True True False 
Mar True True False True True 
Apr False True True True False 

Aby sprawdzić, czy maleje monotonicznie, użyj metody .all(). Domyślnie przechodzi to przez oś 0, wiersze (miesiące).

In [78]: is_decreasing = (df[months].T.diff().fillna(0) <= 0).all() 

In [79]: is_decreasing 
Out[79]: 
0 False 
1  True 
2 False 
3  True 
4 False 
dtype: bool 

In [80]: df['is_decreasing'] = is_decreasing 

In [81]: df 
Out[81]: 
    Balance  Jan  Feb  Mar  Apr is_decreasing 
0 9.724135 0.389376 0.464451 0.229964 0.691504   False 
1 1.114782 0.838406 0.679096 0.185135 0.143883   True 
2 7.613946 0.960876 0.220274 0.788265 0.606402   False 
3 0.144517 0.800086 0.287874 0.223539 0.206002   True 
4 1.332838 0.430812 0.939402 0.045262 0.388466   False 

A jak pan sugeruje, możemy GroupBy is_decreasing oraz sumy:

In [83]: df.groupby('is_decreasing')['Balance'].sum() 
Out[83]: 
is_decreasing 
False   18.670919 
True    1.259299 
Name: Balance, dtype: float64 

Nadszedł takich czasach, kiedy kocham pandy.

0

Pandy 0,19 dodał publiczną Series.is_monotonic API (jak wspomniano, moduł algos jest nieudokumentowane i nie gwarantuje trzymać). .

Istnieją również is_monotonic_increasing i is_monotonic_decreasing. Wszystkie 3 są nieostre (tj. is_monotonic_decreasing sprawdzają, czy sekwencja maleje odpowiednio lub), ale można je połączyć z is_unqiue, jeśli potrzebujesz ścisłości.

my_df = pd.DataFrame({'A':[1,2,3],'B':[1,1,1],'C':[3,2,1]}) 
my_df 
Out[32]: 
    A B C 
0 1 1 3 
1 2 1 2 
2 3 1 1 

my_df.apply(lambda x: x.is_monotonic) 
Out[33]: 
A  True 
B  True 
C False 
dtype: bool