2015-11-18 29 views
7

mam ten dataframe df:pandy - GroupBy i filtrowania dla kolejnych wartości

U,Datetime 
01,2015-01-01 20:00:00 
01,2015-02-01 20:05:00 
01,2015-04-01 21:00:00 
01,2015-05-01 22:00:00 
01,2015-07-01 22:05:00 
02,2015-08-01 20:00:00 
02,2015-09-01 21:00:00 
02,2014-01-01 23:00:00 
02,2014-02-01 22:05:00 
02,2015-01-01 20:00:00 
02,2014-03-01 21:00:00 
03,2015-10-01 20:00:00 
03,2015-11-01 21:00:00 
03,2015-12-01 23:00:00 
03,2015-01-01 22:05:00 
03,2015-02-01 20:00:00 
03,2015-05-01 21:00:00 
03,2014-01-01 20:00:00 
03,2014-02-01 21:00:00 

wykonany przez U i Datetime obiektu. Chciałbym filtrować wartości U z co najmniej trzema kolejnymi zdarzeniami w miesiącach/roku. Do tej pory mam pogrupowane według U, year i month jak:

m = df.groupby(['U',df.index.year,df.index.month]).size() 

uzyskania:

U   
1 2015 1  1 
     2  1 
     4  1 
     5  1 
     7  1 
2 2014 1  1 
     2  1 
     3  1 
    2015 1  1 
     8  1 
     9  1 
3 2014 1  1 
     2  1 
    2015 1  1 
     2  1 
     5  1 
     10 1 
     11 1 
     12 1 

Trzecia kolumna jest związana z występującymi w różnych miesiącach/rok. W tym przypadku tylko wartości U02 i 03 zawierają co najmniej trzy kolejne wartości w miesiącach/roku. Teraz nie mogę się zorientować, w jaki sposób mogę wybrać tych użytkowników i na przykład je umieścić na liście lub po prostu zachować je w oryginalnej ramce danych df i odrzucić pozostałe. Próbowałem też:

g = m.groupby(level=[0,1]).diff() 

Ale nie mogę uzyskać żadnych przydatnych informacji.

+0

Trudne .... I zaczął robić pewne postępy przez 'u = m.unstack ('U')'. Sztuczka polega na tym, że miesiące i lata nie mogą zawierać luk. '((u == u.shift (-1)) & (u == u.shift (-2))). any()' powie wtedy, które wartości miały trzy kolejne miesiące. – Alexander

Odpowiedz

1

W końcu mogę wymyślić rozwiązanie :).

, aby dać ci pojęcie, jak działa funkcja niestandardowa, po prostu odejmuje wartość miesiąca od poprzedniej wartości, wynik powinien być oczywiście one, a to powinno się zdarzyć dwa razy, na przykład, jeśli masz listę numery [5 , 6 , 7], więc 7 - 6 = 1 i 6 - 5 = 1, 1 tutaj pojawił się dwa razy więc warunek został spełniony

In [80]: 
df.reset_index(inplace=True) 

In [281]: 
df['month'] = df.Datetime.dt.month 
df['year'] = df.Datetime.dt.year 
df 
Out[281]: 
      Datetime U month year 
0 2015-01-01 20:00:00 1 1  2015 
1 2015-02-01 20:05:00 1 2  2015 
2 2015-04-01 21:00:00 1 4  2015 
3 2015-05-01 22:00:00 1 5  2015 
4 2015-07-01 22:05:00 1 7  2015 
5 2015-08-01 20:00:00 2 8  2015 
6 2015-09-01 21:00:00 2 9  2015 
7 2014-01-01 23:00:00 2 1  2014 
8 2014-02-01 22:05:00 2 2  2014 
9 2015-01-01 20:00:00 2 1  2015 
10 2014-03-01 21:00:00 2 3  2014 
11 2015-10-01 20:00:00 3 10  2015 
12 2015-11-01 21:00:00 3 11  2015 
13 2015-12-01 23:00:00 3 12  2015 
14 2015-01-01 22:05:00 3 1  2015 
15 2015-02-01 20:00:00 3 2  2015 
16 2015-05-01 21:00:00 3 5  2015 
17 2014-01-01 20:00:00 3 1  2014 
18 2014-02-01 21:00:00 3 2  2014 

In [284]: 
g = df.groupby([df['U'] , df.year]) 

In [86]: 
res = g.filter(lambda x : is_at_least_three_consec(x['month'].diff().values.tolist())) 
res 
Out[86]: 
     Datetime   U month year 
7 2014-01-01 23:00:00 2 1  2014 
8 2014-02-01 22:05:00 2 2  2014 
10 2014-03-01 21:00:00 2 3  2014 
11 2015-10-01 20:00:00 3 10  2015 
12 2015-11-01 21:00:00 3 11  2015 
13 2015-12-01 23:00:00 3 12  2015 
14 2015-01-01 22:05:00 3 1  2015 
15 2015-02-01 20:00:00 3 2  2015 
16 2015-05-01 21:00:00 3 5  2015 

jeśli chcesz zobaczyć wynik funkcji niestandardowej

In [84]: 
res = g['month'].agg(lambda x : is_at_least_three_consec(x.diff().values.tolist())) 
res 
Out[84]: 
U year 
1 2015 False 
2 2014  True 
    2015 False 
3 2014 False 
    2015  True 
Name: month, dtype: bool 

ten sposób funkcja zwyczaj realizowany

In [53]:  
def is_at_least_three_consec(month_diff): 
    consec_count = 0 
    #print(month_diff) 
    for index , val in enumerate(month_diff): 
     if index != 0 and val == 1: 
       consec_count += 1 
       if consec_count == 2: 
        return True 
     else: 
      consec_count = 0 
​ 
    return False