Pandas - 可连接的长度 pd.Intervals
Pandas - length of connectable pd.Intervals
我们从一个区间轴开始,它被分成长度为 5 的区间。(0,5], (5, 10], ...
有一个时间戳列,其中有一些 >= 0 的时间戳。通过使用 pd.cut() 可以确定与时间戳对应的区间 bin。 (例如“时间戳”= 3.0 -> “time_bin”=(0,5])。
如果有没有对应时间戳的时间bin,则不会出现在interval列中。因此,“time_bin”列中可能存在间隔间隙,例如 (5,10)、(15,20)。(即缺少间隔 (10,15] // 请注意时间戳列已排序)
目标是获取一列“connected_interval”,表示当前行区间是否与上一个行区间相连; connected 意味着没有间隔间隙,即 (0,5], (5,10], (10, 15] 将被分配相同的整数 ID) 和列“conn_interv_length”表示每个最大可能的连接interval 区间的长度。区间 (0,5], (5,10], (10, 15] 的长度为 15.
初始数据框有列“group_id”、“时间戳”、“time_bin”。应计算列“connected_interval”和“conn_interv_len”。
注意:欢迎任何获取填充连接间隔长度的解决方案。
df = pd.DataFrame({"group_id":['A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B'],\
"timestamp": [0.0, 3.0, 9.0, 24.2, 30.2, 0.0, 136.51, 222.0, 237.0, 252.0],\
"time_bin": [pd.Interval(0, 5, closed='left'), pd.Interval(0, 5, closed='left'), pd.Interval(5, 10, closed='left'), pd.Interval(20, 25, closed='left'), pd.Interval(30, 35, closed='left'), pd.Interval(0, 5, closed='left'), pd.Interval(135, 140, closed='left'), pd.Interval(220, 225, closed='left'), pd.Interval(235, 240, closed='left'), pd.Interval(250, 255, closed='left')],\
"connected_interval":[0, 0, 0, 1, 2, 0, 1, 2, 3, 4],\
"conn_interv_len":[10, 10, 10, 5, 5, 5, 5, 5, 5, 5],\
})
具有预期输出列的输入:
group_id timestamp time_bin connected_interval conn_interv_len
0 A 0.00 [0, 5) 0 10
1 A 3.00 [0, 5) 0 10
2 A 9.00 [5, 10) 0 10
3 A 24.20 [20, 25) 1 5
4 A 30.20 [30, 35) 2 5
5 B 0.00 [0, 5) 0 5
6 B 136.51 [135, 140) 1 5
7 B 222.00 [220, 225) 2 5
8 B 237.00 [235, 240) 3 5
9 B 252.00 [250, 255) 4 5
IIUC,您可以对间隔进行排序,删除重复项,提取 left/right 边界,基于连续 left/right 的 match/mismatch 创建组,然后再次合并输出到原文:
df2 = (df[['group_id', 'time_bin']]
# extract bounds and sort intervals
.assign(left=df['time_bin'].array.left,
right=df['time_bin'].array.right)
.sort_values(by=['group_id', 'left', 'right'])
# ensure no duplicates
.drop_duplicates(['group_id', 'time_bin'])
# compute connected intervals and connected length
.assign(connected_interval=lambda d:
d.groupby('group_id', group_keys=False)
.apply(lambda g: g['left'].ne(g['right'].shift())
.cumsum().sub(1)),
conn_interv_len=lambda d:
(g := d.groupby(['group_id', 'connected_interval']))['right'].transform('max')
-g['left'].transform('min')
)
.drop(columns=['left', 'right'])
)
# merge to restore missing dropped duplicated rows
out = df.merge(df2)
输出:
group_id timestamp time_bin connected_interval conn_interv_len
0 A 0.00 [0, 5) 0 10
1 A 3.00 [0, 5) 0 10
2 A 9.00 [5, 10) 0 10
3 A 24.20 [20, 25) 1 5
4 A 30.20 [30, 35) 2 5
5 B 0.00 [0, 5) 0 5
6 B 136.51 [135, 140) 1 5
7 B 222.00 [220, 225) 2 5
8 B 237.00 [235, 240) 3 5
9 B 252.00 [250, 255) 4 5
我们从一个区间轴开始,它被分成长度为 5 的区间。(0,5], (5, 10], ... 有一个时间戳列,其中有一些 >= 0 的时间戳。通过使用 pd.cut() 可以确定与时间戳对应的区间 bin。 (例如“时间戳”= 3.0 -> “time_bin”=(0,5])。
如果有没有对应时间戳的时间bin,则不会出现在interval列中。因此,“time_bin”列中可能存在间隔间隙,例如 (5,10)、(15,20)。(即缺少间隔 (10,15] // 请注意时间戳列已排序)
目标是获取一列“connected_interval”,表示当前行区间是否与上一个行区间相连; connected 意味着没有间隔间隙,即 (0,5], (5,10], (10, 15] 将被分配相同的整数 ID) 和列“conn_interv_length”表示每个最大可能的连接interval 区间的长度。区间 (0,5], (5,10], (10, 15] 的长度为 15.
初始数据框有列“group_id”、“时间戳”、“time_bin”。应计算列“connected_interval”和“conn_interv_len”。
注意:欢迎任何获取填充连接间隔长度的解决方案。
df = pd.DataFrame({"group_id":['A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B'],\
"timestamp": [0.0, 3.0, 9.0, 24.2, 30.2, 0.0, 136.51, 222.0, 237.0, 252.0],\
"time_bin": [pd.Interval(0, 5, closed='left'), pd.Interval(0, 5, closed='left'), pd.Interval(5, 10, closed='left'), pd.Interval(20, 25, closed='left'), pd.Interval(30, 35, closed='left'), pd.Interval(0, 5, closed='left'), pd.Interval(135, 140, closed='left'), pd.Interval(220, 225, closed='left'), pd.Interval(235, 240, closed='left'), pd.Interval(250, 255, closed='left')],\
"connected_interval":[0, 0, 0, 1, 2, 0, 1, 2, 3, 4],\
"conn_interv_len":[10, 10, 10, 5, 5, 5, 5, 5, 5, 5],\
})
具有预期输出列的输入:
group_id timestamp time_bin connected_interval conn_interv_len
0 A 0.00 [0, 5) 0 10
1 A 3.00 [0, 5) 0 10
2 A 9.00 [5, 10) 0 10
3 A 24.20 [20, 25) 1 5
4 A 30.20 [30, 35) 2 5
5 B 0.00 [0, 5) 0 5
6 B 136.51 [135, 140) 1 5
7 B 222.00 [220, 225) 2 5
8 B 237.00 [235, 240) 3 5
9 B 252.00 [250, 255) 4 5
IIUC,您可以对间隔进行排序,删除重复项,提取 left/right 边界,基于连续 left/right 的 match/mismatch 创建组,然后再次合并输出到原文:
df2 = (df[['group_id', 'time_bin']]
# extract bounds and sort intervals
.assign(left=df['time_bin'].array.left,
right=df['time_bin'].array.right)
.sort_values(by=['group_id', 'left', 'right'])
# ensure no duplicates
.drop_duplicates(['group_id', 'time_bin'])
# compute connected intervals and connected length
.assign(connected_interval=lambda d:
d.groupby('group_id', group_keys=False)
.apply(lambda g: g['left'].ne(g['right'].shift())
.cumsum().sub(1)),
conn_interv_len=lambda d:
(g := d.groupby(['group_id', 'connected_interval']))['right'].transform('max')
-g['left'].transform('min')
)
.drop(columns=['left', 'right'])
)
# merge to restore missing dropped duplicated rows
out = df.merge(df2)
输出:
group_id timestamp time_bin connected_interval conn_interv_len
0 A 0.00 [0, 5) 0 10
1 A 3.00 [0, 5) 0 10
2 A 9.00 [5, 10) 0 10
3 A 24.20 [20, 25) 1 5
4 A 30.20 [30, 35) 2 5
5 B 0.00 [0, 5) 0 5
6 B 136.51 [135, 140) 1 5
7 B 222.00 [220, 225) 2 5
8 B 237.00 [235, 240) 3 5
9 B 252.00 [250, 255) 4 5