【发布时间】:2021-07-13 16:30:00
【问题描述】:
我有一个简单的 DataFrame,其中包含心率(和相关列),由唯一且单调递增的日期时间值索引,以一分钟的间隔采样(在移除传感器的地方有一些中断)。这是一个示例:
print(data)
End Time HR Min HR Max HR
Start Time
2020-10-14 18:27:00 2020-10-14 18:27:59 87.0 84.0 89.0
2020-10-14 18:28:00 2020-10-14 18:28:59 89.0 85.0 94.0
2020-10-14 18:29:00 2020-10-14 18:29:59 87.0 84.0 90.0
2020-10-14 18:30:00 2020-10-14 18:30:59 91.0 87.0 96.0
2020-10-14 18:31:00 2020-10-14 18:31:59 95.0 91.0 100.0
... ... ... ... ...
2021-07-08 22:26:00 2021-07-08 22:26:59 73.0 70.0 76.0
2021-07-08 22:27:00 2021-07-08 22:27:59 76.0 74.0 79.0
2021-07-08 22:28:00 2021-07-08 22:28:59 71.0 70.0 74.0
2021-07-08 22:29:00 2021-07-08 22:29:59 71.0 69.0 74.0
2021-07-08 22:30:00 2021-07-08 22:30:59 74.0 72.0 78.0
[373234 rows x 4 columns]
我想检测“峰值”,即心率超过阈值 5 分钟或更长时间。所以,需要明确的是,当一个峰值持续 10 分钟时,它仍然是一个峰值,而不是两个。
当然,我可以按阈值过滤:
maybe_peaks = data[data['HR']>= threshold])]
print(maybe_peaks)
End Time HR Min HR Max HR
Start Time
2020-10-16 12:14:00 2020-10-16 12:14:59 104.0 95.0 108.0
2020-10-16 12:15:00 2020-10-16 12:15:59 111.0 106.0 115.0
2020-10-16 12:16:00 2020-10-16 12:16:59 132.0 105.0 157.0
2020-10-16 12:17:00 2020-10-16 12:17:59 126.0 106.0 159.0
2020-10-16 12:18:00 2020-10-16 12:18:59 109.0 108.0 111.0
... ... ... ... ...
2021-07-04 12:58:00 2021-07-04 12:58:59 103.0 97.0 116.0
2021-07-06 13:38:00 2021-07-06 13:38:59 106.0 103.0 108.0
2021-07-06 13:39:00 2021-07-06 13:39:59 104.0 102.0 109.0
2021-07-06 17:02:00 2021-07-06 17:02:59 121.0 98.0 135.0
2021-07-07 19:58:00 2021-07-07 19:58:59 110.0 105.0 116.0
[12940 rows x 4 columns]
但是问题就变成了:如何进一步过滤掉超过阈值的时间短于 5 分钟的行。
当然,我可以做这种 C 风格的逐行循环,但我觉得这既不是最有效也不是最优雅的方式。
最终,我想在 x 轴上构建一个日历日,以及这些峰值事件沿 y 的频率/计数的图。
任何提示/方向将不胜感激。
这里有一些示例数据可以提供帮助:
from pandas import Timestamp
test_dat = [[Timestamp('2021-06-25 12:00:00'), Timestamp('2021-06-25 12:00:59'), 99.0, 95.0, 105.0], [Timestamp('2021-06-25 12:01:00'), Timestamp('2021-06-25 12:01:59'), 96.0, 91.0, 102.0], [Timestamp('2021-06-25 12:02:00'), Timestamp('2021-06-25 12:02:59'), 100.0, 96.0, 105.0], [Timestamp('2021-06-25 12:03:00'), Timestamp('2021-06-25 12:03:59'), 96.0, 91.0, 100.0], [Timestamp('2021-06-25 12:04:00'), Timestamp('2021-06-25 12:04:59'), 93.0, 88.0, 102.0], [Timestamp('2021-06-25 12:05:00'), Timestamp('2021-06-25 12:05:59'), 105.0, 99.0, 110.0], [Timestamp('2021-06-25 12:06:00'), Timestamp('2021-06-25 12:06:59'), 102.0, 97.0, 109.0], [Timestamp('2021-06-25 12:07:00'), Timestamp('2021-06-25 12:07:59'), 96.0, 87.0, 102.0], [Timestamp('2021-06-25 12:08:00'), Timestamp('2021-06-25 12:08:59'), 96.0, 93.0, 101.0], [Timestamp('2021-06-25 12:09:00'), Timestamp('2021-06-25 12:09:59'), 96.0, 90.0, 106.0], [Timestamp('2021-06-25 12:10:00'), Timestamp('2021-06-25 12:10:59'), 100.0, 95.0, 110.0], [Timestamp('2021-06-25 12:11:00'), Timestamp('2021-06-25 12:11:59'), 100.0, 95.0, 113.0], [Timestamp('2021-06-25 12:12:00'), Timestamp('2021-06-25 12:12:59'), 98.0, 91.0, 103.0], [Timestamp('2021-06-25 12:13:00'), Timestamp('2021-06-25 12:13:59'), 101.0, 97.0, 108.0], [Timestamp('2021-06-25 12:14:00'), Timestamp('2021-06-25 12:14:59'), 98.0, 91.0, 102.0], [Timestamp('2021-06-25 12:15:00'), Timestamp('2021-06-25 12:15:59'), 100.0, 93.0, 110.0], [Timestamp('2021-06-25 12:16:00'), Timestamp('2021-06-25 12:16:59'), 96.0, 89.0, 104.0], [Timestamp('2021-06-25 12:17:00'), Timestamp('2021-06-25 12:17:59'), 98.0, 95.0, 104.0], [Timestamp('2021-06-25 12:18:00'), Timestamp('2021-06-25 12:18:59'), 95.0, 93.0, 99.0], [Timestamp('2021-06-25 12:19:00'), Timestamp('2021-06-25 12:19:59'), 94.0, 84.0, 104.0], [Timestamp('2021-06-25 12:20:00'), Timestamp('2021-06-25 12:20:59'), 94.0, 90.0, 99.0], [Timestamp('2021-06-25 12:21:00'), Timestamp('2021-06-25 12:21:59'), 98.0, 95.0, 100.0], [Timestamp('2021-06-25 12:22:00'), Timestamp('2021-06-25 12:22:59'), 98.0, 97.0, 102.0], [Timestamp('2021-06-25 12:23:00'), Timestamp('2021-06-25 12:23:59'), 98.0, 96.0, 102.0], [Timestamp('2021-06-25 12:24:00'), Timestamp('2021-06-25 12:24:59'), 98.0, 96.0, 100.0], [Timestamp('2021-06-25 12:25:00'), Timestamp('2021-06-25 12:25:59'), 96.0, 95.0, 100.0], [Timestamp('2021-06-25 12:26:00'), Timestamp('2021-06-25 12:26:59'), 102.0, 98.0, 105.0], [Timestamp('2021-06-25 12:27:00'), Timestamp('2021-06-25 12:27:59'), 97.0, 92.0, 103.0], [Timestamp('2021-06-25 12:28:00'), Timestamp('2021-06-25 12:28:59'), 92.0, 87.0, 99.0], [Timestamp('2021-06-25 12:29:00'), Timestamp('2021-06-25 12:29:59'), 96.0, 94.0, 99.0], [Timestamp('2021-06-25 12:30:00'), Timestamp('2021-06-25 12:30:59'), 97.0, 93.0, 100.0], [Timestamp('2021-06-25 12:31:00'), Timestamp('2021-06-25 12:31:59'), 101.0, 97.0, 103.0], [Timestamp('2021-06-25 12:32:00'), Timestamp('2021-06-25 12:32:59'), 99.0, 95.0, 103.0], [Timestamp('2021-06-25 12:33:00'), Timestamp('2021-06-25 12:33:59'), 101.0, 93.0, 105.0], [Timestamp('2021-06-25 12:34:00'), Timestamp('2021-06-25 12:34:59'), 98.0, 96.0, 101.0], [Timestamp('2021-06-25 12:35:00'), Timestamp('2021-06-25 12:35:59'), 100.0, 93.0, 105.0], [Timestamp('2021-06-25 12:36:00'), Timestamp('2021-06-25 12:36:59'), 103.0, 101.0, 108.0], [Timestamp('2021-06-25 12:37:00'), Timestamp('2021-06-25 12:37:59'), 105.0, 101.0, 111.0], [Timestamp('2021-06-25 12:38:00'), Timestamp('2021-06-25 12:38:59'), 106.0, 103.0, 114.0], [Timestamp('2021-06-25 12:39:00'), Timestamp('2021-06-25 12:39:59'), 107.0, 104.0, 109.0], [Timestamp('2021-06-25 12:40:00'), Timestamp('2021-06-25 12:40:59'), 101.0, 95.0, 109.0], [Timestamp('2021-06-25 12:41:00'), Timestamp('2021-06-25 12:41:59'), 99.0, 96.0, 103.0], [Timestamp('2021-06-25 12:42:00'), Timestamp('2021-06-25 12:42:59'), 99.0, 96.0, 105.0], [Timestamp('2021-06-25 12:43:00'), Timestamp('2021-06-25 12:43:59'), 96.0, 95.0, 98.0], [Timestamp('2021-06-25 12:44:00'), Timestamp('2021-06-25 12:44:59'), 96.0, 94.0, 99.0], [Timestamp('2021-06-25 12:45:00'), Timestamp('2021-06-25 12:45:59'), 102.0, 96.0, 110.0], [Timestamp('2021-06-25 12:46:00'), Timestamp('2021-06-25 12:46:59'), 105.0, 102.0, 109.0], [Timestamp('2021-06-25 12:47:00'), Timestamp('2021-06-25 12:47:59'), 104.0, 100.0, 108.0], [Timestamp('2021-06-25 12:48:00'), Timestamp('2021-06-25 12:48:59'), 100.0, 98.0, 103.0], [Timestamp('2021-06-25 12:49:00'), Timestamp('2021-06-25 12:49:59'), 103.0, 99.0, 110.0], [Timestamp('2021-06-25 12:50:00'), Timestamp('2021-06-25 12:50:59'), 106.0, 99.0, 111.0], [Timestamp('2021-06-25 12:51:00'), Timestamp('2021-06-25 12:51:59'), 100.0, 95.0, 104.0], [Timestamp('2021-06-25 12:52:00'), Timestamp('2021-06-25 12:52:59'), 108.0, 102.0, 113.0], [Timestamp('2021-06-25 12:53:00'), Timestamp('2021-06-25 12:53:59'), 113.0, 106.0, 116.0], [Timestamp('2021-06-25 12:54:00'), Timestamp('2021-06-25 12:54:59'), 109.0, 105.0, 113.0], [Timestamp('2021-06-25 12:55:00'), Timestamp('2021-06-25 12:55:59'), 103.0, 101.0, 110.0], [Timestamp('2021-06-25 12:56:00'), Timestamp('2021-06-25 12:56:59'), 104.0, 94.0, 109.0], [Timestamp('2021-06-25 12:57:00'), Timestamp('2021-06-25 12:57:59'), 93.0, 82.0, 107.0], [Timestamp('2021-06-25 12:58:00'), Timestamp('2021-06-25 12:58:59'), 99.0, 94.0, 104.0], [Timestamp('2021-06-25 12:59:00'), Timestamp('2021-06-25 12:59:59'), 98.0, 92.0, 103.0], [Timestamp('2021-06-25 13:00:00'), Timestamp('2021-06-25 13:00:59'), 98.0, 95.0, 102.0]]
df = pd.DataFrame(test_dat, columns=['Start Time', 'End Time', 'HR', 'Min HR', 'Max HR']).set_index('Start Time')
编辑:没关系,但我使用的阈值是 103 BPM。 (这是从统计量计算出来的,而不是一个幻数。)
【问题讨论】:
-
您想如何处理移除传感器的中断?计算峰值时是否需要考虑缺失的区间?
-
@ShubhamSharma 我认为这不是问题。我想在高峰期可能会取下或戴上传感器。但在这种情况下,如果峰值已经 5 分钟长,则将被计算在内。如果不是,则不应计算它——与中断无关。
-
如果
heart rate > threshold超过5 min,我们应该把它分成5 分钟的间隔吗?例如,假设 HR 保持在阈值以上 12 分钟,那么在这种情况下,我们应该计算 1 条连续记录还是 2 条5 min连续记录? -
@ShubhamSharma 好问题!我将编辑我的问题以专门解决它。简短的回答:超过 5 分钟仍然是一个高峰。因此,峰值被定义为心率超过阈值 5 分钟或更长时间。所以,超过 5 分钟仍然是同一个峰值。
标签: python-3.x pandas dataframe datetime