Câu hỏi Pandas: resample timeseries với groupby


Với DataFrame gấu trúc bên dưới:

In [115]: times = pd.to_datetime(pd.Series(['2014-08-25 21:00:00','2014-08-25 21:04:00',
                                            '2014-08-25 22:07:00','2014-08-25 22:09:00']))
          locations = ['HK', 'LDN', 'LDN', 'LDN']
          event = ['foo', 'bar', 'baz', 'qux']
          df = pd.DataFrame({'Location': locations,
                             'Event': event}, index=times)
          df
Out[115]:
                               Event Location
          2014-08-25 21:00:00  foo   HK
          2014-08-25 21:04:00  bar   LDN
          2014-08-25 22:07:00  baz   LDN
          2014-08-25 22:09:00  qux   LDN

Tôi muốn resample dữ liệu để tổng hợp nó theo giờ bằng cách đếm trong khi nhóm theo vị trí để tạo ra một khung dữ liệu trông như thế này:

Out[115]:
                               HK    LDN
          2014-08-25 21:00:00  1     1
          2014-08-25 22:00:00  0     2

Tôi đã thử các kết hợp khác nhau của resample () và groupby () nhưng không có may mắn. Làm thế nào tôi sẽ đi về điều này?


20
2017-08-14 14:04


gốc


Đối với những người đến câu hỏi này trong năm 2017+, pd.TimeGrouper không được chấp nhận. Xem câu trả lời này cho cú pháp mới nhất. - Ted Petrou


Các câu trả lời:


Trong bài đăng gốc của tôi, tôi đã đề xuất sử dụng pd.TimeGrouper. Ngày nay, sử dụng pd.Grouper thay vì pd.TimeGrouper. Cú pháp phần lớn là giống nhau, nhưng TimeGrouper  hiện không được chấp nhận ủng hộ pd.Grouper.

Hơn nữa, trong khi pd.TimeGrouper chỉ có thể nhóm theo DatetimeIndex, pd.Grouper có thể nhóm theo ngày giờ cột mà bạn có thể chỉ định thông qua key tham số.


Bạn có thể sử dụng pd.Grouper để nhóm DatetimeIndex'ed DataFrame theo giờ:

grouper = df.groupby([pd.Grouper('1H'), 'Location'])

sử dụng count để đếm số lượng sự kiện trong mỗi nhóm:

grouper['Event'].count()
#                      Location
# 2014-08-25 21:00:00  HK          1
#                      LDN         1
# 2014-08-25 22:00:00  LDN         2
# Name: Event, dtype: int64

sử dụng unstack để di chuyển Location mức chỉ mục đến một cấp độ cột:

grouper['Event'].count().unstack()
# Out[49]: 
# Location             HK  LDN
# 2014-08-25 21:00:00   1    1
# 2014-08-25 22:00:00 NaN    2

và sau đó sử dụng fillna để thay đổi NaN thành số không.


Để tất cả chúng cùng nhau,

grouper = df.groupby([pd.Grouper('1H'), 'Location'])
result = grouper['Event'].count().unstack('Location').fillna(0)

sản lượng

Location             HK  LDN
2014-08-25 21:00:00   1    1
2014-08-25 22:00:00   0    2

26
2017-08-14 14:10





Câu trả lời của Pandas 0.21: TimeGrouper sẽ không được dùng nữa

Có hai tùy chọn để thực hiện việc này. Họ thực sự có thể đưa ra các kết quả khác nhau dựa trên dữ liệu của bạn. Nhóm tùy chọn đầu tiên theo Vị trí và trong nhóm Vị trí theo giờ. Nhóm tùy chọn thứ hai theo Vị trí và giờ cùng một lúc.

lựa chọn 1: Sử dụng groupby + resample

grouped = df.groupby('Location').resample('H')['Event'].count()

Lựa chọn 2: Nhóm cả vị trí và Ngày giờ cùng với groupby(pd.Grouper)

grouped = df.groupby(['Location', pd.Grouper(freq='H')])['Event'].count()

Cả hai đều sẽ dẫn đến những điều sau đây:

Location                     
HK        2014-08-25 21:00:00    1
LDN       2014-08-25 21:00:00    1
          2014-08-25 22:00:00    2
Name: Event, dtype: int64

Và sau đó định hình lại:

grouped.unstack('Location', fill_value=0)

Sẽ đầu ra

Location             HK  LDN
2014-08-25 21:00:00   1    1
2014-08-25 22:00:00   0    2

21
2017-08-27 22:34



Xin lỗi, tôi biết đây là một câu hỏi cũ. Làm thế nào bạn sẽ làm điều này cho một nhóm nhiều cột bây giờ mà TimeGrouper là nhận được phản đối? Ngoài ra, có thể chỉ định ngày bắt đầu và ngày kết thúc ngoài các khoảng thời gian không? - Pylander
@Pylander TimeGrouper không làm gì mà Grouper không thể làm được. Chỉ cần sử dụng một danh sách như được thực hiện với tùy chọn 2. Bạn chỉ có thể chỉ định ngày tháng theo các khoảng thời gian đều đặn với các bí danh offset ngày. Nếu bạn có ngày không thường xuyên, bạn sẽ phải thực hiện một số tiền xử lý và chỉ cần gắn nhãn cho mỗi nhóm mà nó thuộc về và sau đó sử dụng groupby với các nhóm đó. - Ted Petrou
Điều đó có ý nghĩa. Vì vậy, chỉ cần làm rõ vào những ngày không thường xuyên. Tôi có phạm vi ngày mong muốn là 2004-01-01-12 / 31/2018 với khoảng thời gian 30 ngày. Không có đảm bảo rằng sẽ có giá trị cho mỗi khóa nhóm cho mỗi khoảng thời gian. Đây có phải là vấn đề "không thường xuyên" hay tôi sẽ được đặt theo phương pháp này? - Pylander
Khoảng thời gian 30 ngày là các ngày thông thường. Nếu một số khóa nhóm của bạn có các ngày khác nhau thì mỗi tùy chọn trong câu trả lời này sẽ cho bạn kết quả khác nhau. Nó sẽ phụ thuộc vào kết quả bạn mong muốn. Nếu bạn vẫn còn bối rối chỉ cần đi trước và tạo ra một câu hỏi mới. - Ted Petrou
Cảm ơn vì những lời khuyên. Tôi đã kết thúc việc tạo ra một câu hỏi mới: stackoverflow.com/questions/46611626/… - Pylander


Nhiều cột nhóm theo

untubu là tại chỗ với câu trả lời của mình nhưng tôi muốn thêm vào những gì bạn có thể làm nếu bạn có một cột thứ ba, nói Cost và muốn tổng hợp nó như trên. Đó là thông qua kết hợp câu trả lời của unutbu và cái này tôi đã tìm ra cách để làm điều này và nghĩ rằng tôi sẽ chia sẻ cho người dùng trong tương lai.

Tạo DataFrame với Cost colunm.

In[1]: 
      import pandas as pd

      times = pd.to_datetime(pd.Series(['2014-08-25 21:00:00',
                  '2014-08-25 21:04:00','2014-08-25 22:07:00','2014-08-25 22:09:00']))

      locations = ['HK', 'LDN', 'LDN', 'LDN']
      event = ['foo', 'bar', 'baz', 'qux']
      cost = [20, 24, 34, 52] # add in cost colunm

      df = pd.DataFrame({'Location': locations, 'Event': event, 'Cost': cost}, index=times)
      df

Out[1]:
                               Event Location Cost
          2014-08-25 21:00:00  foo   HK       20
          2014-08-25 21:04:00  bar   LDN      24
          2014-08-25 22:07:00  baz   LDN      34
          2014-08-25 22:09:00  qux   LDN      52

Bây giờ chúng tôi nhóm bằng cách sử dụng agg để chỉ định từng phương pháp tổng hợp cột, tức là số lượng, trung bình, tổng, v.v ...

In[2]:    
      df = df.groupby([pd.TimeGrouper('1H'), 'Location']).agg({'Event': np.sum,
                                                               'Cost': np.mean})

Out[2]:
                               Location    Event     Cost
          2014-08-25 21:00:00  HK          1         20
                               LDN         1         24
          2014-08-25 22:00:00  LDN         2         43

Sau đó, trận chung kết unstack với điền NaN với số không và hiển thị dưới dạng int bởi vì nó đẹp.

In[3]: 
      df.df.unstack().fillna(0).astype(int)

Out[3]:

                                Cost      Event
                    Location    HK  LDN   HK   LDN
         2014-08-25 21:00:00    20  24    1    1
         2014-08-25 22:00:00    0   43    0    2

6
2018-04-15 10:19