2017-01-30 42 views
15

Mam dataframe, który wygląda tak:Różnica czasu w ramach grupy przez obiekty w Pythonie Pand

from to   datetime    other 
------------------------------------------------- 
11  1  2016-11-06 22:00:00   - 
11  1  2016-11-06 20:00:00   - 
11  1  2016-11-06 15:45:00   - 
11  12 2016-11-06 15:00:00   - 
11  1  2016-11-06 12:00:00   - 
11  18 2016-11-05 10:00:00   - 
11  12 2016-11-05 10:00:00   - 
12  1  2016-10-05 10:00:59   - 
12  3  2016-09-06 10:00:34   - 

Chcę GroupBy „z”, a następnie „do” kolumn, a następnie posortować „datetime” w porządku malejącym porządek, a następnie ostatecznie obliczyć różnicę czasu w obrębie tych pogrupowanych między obiektami między bieżącym a następnym razem. Na przykład w tym przypadku chciałbym mieć dataframe jak następuje:

from to  timediff in minutes           others 
11  1   120 
11  1   255 
11  1   225 
11  1   0 (preferrably subtract this date from the epoch) 
11  12   300 
11  12   0 
11  18   0 
12  1   25 
12  3   0 

nie mogę uzyskać moja głowa wokół to zastanawianie się !! Czy jest na to wyjście? Każda pomoc będzie bardzo ceniona !! Dziękuję bardzo z góry!

+0

[Czy ten post help] (http://stackoverflow.com/q/2788871/6912791)? To prosty sposób porównywania obiektów DateTime. Nie jestem zaznajomiony z ramkami danych, ale jeśli dobrze pamiętam, możesz przechodzić przez pewne kolumny. –

Odpowiedz

12
df.assign(
    timediff=df.sort_values(
     'datetime', ascending=False 
    ).groupby(['from', 'to']).datetime.diff(-1).dt.seconds.div(60).fillna(0)) 

enter image description here

15

myślę, że trzeba:

groupby z applysort_values z diff, konwersja Timedelta do minut seconds i podziału podłogi 60

fillna i sort_index, usunąć poziom 2 w indeksie

df = df.groupby(['from','to']).datetime 
     .apply(lambda x: x.sort_values().diff().dt.seconds // 60) 
     .fillna(0) 
     .sort_index() 
     .reset_index(level=2, drop=True) 
     .reset_index(name='timediff in minutes') 

print (df) 

    from to timediff in minutes 
0 11 1     120.0 
1 11 1     255.0 
2 11 1     225.0 
3 11 1     0.0 
4 11 12     300.0 
5 11 12     0.0 
6 11 18     0.0 
7 12 3     0.0 
8 12 3     0.0 

df = df.join(df.groupby(['from','to']) 
       .datetime 
       .apply(lambda x: x.sort_values().diff().dt.seconds // 60) 
       .fillna(0) 
       .reset_index(level=[0,1], drop=True) 
       .rename('timediff in minutes')) 
print (df) 
    from to   datetime other timediff in minutes 
0 11 1 2016-11-06 22:00:00  -    120.0 
1 11 1 2016-11-06 20:00:00  -    255.0 
2 11 1 2016-11-06 15:45:00  -    225.0 
3 11 12 2016-11-06 15:00:00  -    300.0 
4 11 1 2016-11-06 12:00:00  -     0.0 
5 11 18 2016-11-05 10:00:00  -     0.0 
6 11 12 2016-11-05 10:00:00  -     0.0 
7 12 3 2016-10-05 10:00:59  -     0.0 
8 12 3 2016-09-06 10:00:34  -     0.0 
+0

Dziękuję bardzo! Działa to, ale chciałem również, aby pozostała kolumna pozostała taka jaka jest! – Gingerbread

+0

Ok, dodam do tego rozwiązanie. – jezrael

11

Prawie jak wyżej, ale bez apply:

result = df.sort_values(['from','to','datetime'])\ 
      .groupby(['from','to'])['datetime']\ 
      .diff().dt.seconds.fillna(0) 
+0

Znalazłem przy użyciu metody .apply() jak w odpowiedzi na słowo jezrael tylko nieznacznie szybciej niż bezpośrednio wywołując .diff() (np.% Timeit na 1000 wierszy, 100 pętli, najlepiej z 3: 10.9ms/loop with apply i 11.1ms/loop bez podania) – Quetzalcoatl