Pandas 在列级别按日期时间分组

Pandas group by datetime within column level

我有一个由以下人员创建的数据框:

df = pd.DataFrame({})
df['Date']  = pd.to_datetime(np.arange(0,12), unit='h', origin='2018-08-01  06:00:00')
df['ship'] = [1,1,2,2,2,3,3,3,3,3,3,3] # ship ID number
dt_trip = 4 # maximum duration of each trip to be classified as the same trip


                  Date  ship
0  2018-08-01 06:00:00     1
1  2018-08-01 07:00:00     1
2  2018-08-01 08:00:00     2
3  2018-08-01 09:00:00     2
4  2018-08-01 10:00:00     2
5  2018-08-01 11:00:00     3
6  2018-08-01 12:00:00     3
7  2018-08-01 13:00:00     3
8  2018-08-01 14:00:00     3
9  2018-08-01 15:00:00     3
10 2018-08-01 16:00:00     3
11 2018-08-01 17:00:00     3

我试图获得一个新的列来显示每艘船的航次。每次行程定义为相对于行程开始的 4 小时间隔。当新的船号位于下一行时,新的行程将自动开始(无论之前的日期时间如何)。从之前的 post 我得到了旅行的解决方案。

origin = df["Date"][0].hour
df["Trip"] = df.apply(lambda x: ((x["Date"].hour - origin) // dt_trip) + 1, axis=1)
df["Trip"] = df.groupby(['Trip','ship']).ngroup() +1 # trip starts at: 1

此解决方案在 ship-column 更改其行时进行新的行程。我想要的唯一更改是将原点更改为新行程开始时的日期时间。所以索引 4 应该有 Trip = 2,因为船是相同的并且行程开始之间的时间差(索引 = 2)。现在它查看第一个给定的日期时间。

所需的解决方案如下所示:

                  Date  ship  Trip  Trip_desired
0  2018-08-01 06:00:00     1     1  1
1  2018-08-01 07:00:00     1     1  1
2  2018-08-01 08:00:00     2     2  2
3  2018-08-01 09:00:00     2     2  2
4  2018-08-01 10:00:00     2     3  2
5  2018-08-01 11:00:00     3     4  3
6  2018-08-01 12:00:00     3     4  3
7  2018-08-01 13:00:00     3     4  3
8  2018-08-01 14:00:00     3     5  3
9  2018-08-01 15:00:00     3     5  4
10 2018-08-01 16:00:00     3     5  4
11 2018-08-01 17:00:00     3     5  4

我会做:

total_time = df['Date'] - df.groupby('ship')['Date'].transform('min')
trips = total_time.dt.total_seconds().fillna(0)//(dt_trip*3600)

df['trip'] = df.groupby(['ship', trips]).ngroup()+1

输出:

                  Date  ship  trip
0  2018-08-01 06:00:00     1     1
1  2018-08-01 07:00:00     1     1
2  2018-08-01 08:00:00     2     2
3  2018-08-01 09:00:00     2     2
4  2018-08-01 10:00:00     2     2
5  2018-08-01 11:00:00     3     3
6  2018-08-01 12:00:00     3     3
7  2018-08-01 13:00:00     3     3
8  2018-08-01 14:00:00     3     3
9  2018-08-01 15:00:00     3     4
10 2018-08-01 16:00:00     3     4
11 2018-08-01 17:00:00     3     4