2016-06-17 29 views
6

Mam pandas DataFrame z kolumną boolowską, posortowaną według innej kolumny i potrzebuję obliczyć odwrotną sumę skumulowaną, czyli liczbę prawdziwych wartości z bieżącego rzędu na dół.Odwrócona skumulowana suma kolumny w pandach.DataFrame

Przykład

In [13]: df = pd.DataFrame({'A': [True] * 3 + [False] * 5, 'B': np.random.rand(8) }) 

In [15]: df = df.sort_values('B') 

In [16]: df 
Out[16]: 
     A   B 
6 False 0.037710 
2 True 0.315414 
4 False 0.332480 
7 False 0.445505 
3 False 0.580156 
1 True 0.741551 
5 False 0.796944 
0 True 0.817563 

Potrzebuję czegoś, co da mi nową kolumnę z wartościami

3 
3 
2 
2 
2 
2 
1 
1 

Oznacza to, że za każdym rzędzie powinna ona zawierać ilość prawdziwych wartości w tym wierszu i wierszy poniżej .

Próbowałem różnych metod przy użyciu .iloc[::-1], ale wynik nie jest pożądany.

Pomyśl, brakuje mi oczywistej rzeczy. Zaczynałem używać Pand tylko wczoraj.

Odpowiedz

10

tyłu kolumna A mieć cumSum, a następnie do tyłu ponownie:

df['C'] = df.ix[::-1, 'A'].cumsum()[::-1] 

import pandas as pd 
df = pd.DataFrame(
    {'A': [False, True, False, False, False, True, False, True], 
    'B': [0.03771, 0.315414, 0.33248, 0.445505, 0.580156, 0.741551, 0.796944, 0.817563],}, 
    index=[6, 2, 4, 7, 3, 1, 5, 0]) 
df['C'] = df.ix[::-1, 'A'].cumsum()[::-1] 
print(df) 

wydajności

 A   B C 
6 False 0.037710 3 
2 True 0.315414 3 
4 False 0.332480 2 
7 False 0.445505 2 
3 False 0.580156 2 
1 True 0.741551 2 
5 False 0.796944 1 
0 True 0.817563 1 

Alternatywnie, można policzyć True s w kolumnie A i subtrac t (przesunięty) suma:

Ale to znacznie wolniej. Korzystanie IPython przeprowadzić benchmark:

In [116]: df = pd.DataFrame({'A':np.random.randint(2, size=10**5).astype(bool)}) 

In [117]: %timeit df['A'].sum()-df['A'].shift(1).fillna(0).cumsum() 
10 loops, best of 3: 19.8 ms per loop 

In [118]: %timeit df.ix[::-1, 'A'].cumsum()[::-1] 
1000 loops, best of 3: 701 µs per loop 
0

To działa, ale jest powolna ... jak @unutbu odpowiedź. Wartość True równa się 1. Fails on False lub inna wartość.

df[2] = df.groupby('A').cumcount(ascending=False)+1 
df[1] = np.where(df['A']==True,df[2],None) 
df[1] = df[1].fillna(method='bfill').fillna(0) 
del df[2] 

     A   B 1 
# 3 False 0.277557 3.0 
# 7 False 0.400751 3.0 
# 6 False 0.431587 3.0 
# 5 False 0.481006 3.0 
# 1 True 0.534364 3.0 
# 2 True 0.556378 2.0 
# 0 True 0.863192 1.0 
# 4 False 0.916247 0.0