我正在尝试分析数据框中的一些数据,并确定数据中何时出现空闲时间(显示为平点)。 这些平点是当 disp 值从 > 520 到 ~ 225 时出现的。我想创建一个新列来充当这些时间的标签。
这是我的一些数据的一小段浓缩摘录。 完整数据集大约有 270,000 行,并且可能很嘈杂。 空闲期的开始是第 150 行,空闲期的结束是第 157 行。
disp temp
148 528.253551 0.908375
149 537.832220 0.944138
150 225.073475 0.890493
151 225.247861 0.892878
152 225.487333 0.895262
153 225.515279 0.926256
154 225.515003 0.909567
155 225.518680 0.901222
156 225.537893 0.927448
157 225.068878 0.865460
158 540.460613 0.873804
159 531.048884 0.865460
我想生成的输出是
disp temp state
148 528.253551 0.908375 None
149 537.832220 0.944138 None
150 225.073475 0.890493 idl_strt
151 225.247861 0.892878 idle
152 225.487333 0.895262 idle
153 225.515279 0.926256 idle
154 225.515003 0.909567 idle
155 225.518680 0.901222 idle
156 225.537893 0.927448 idle
157 225.068878 0.865460 idl_ends
158 540.460613 0.873804 None
159 531.048884 0.865460 None
有矢量化的方法来做到这一点吗? 通过 pd.apply 方法调用的函数可以查看之前的行而不首先创建额外的移位列吗?
我已经能够使用以下代码使用“idl_start”和“idl_ends”填充状态列的正确行
def _idlefinder(self, row):
"""Logic for finding idles start and end"""
if (row["disp"] + 250.0) < row["nextdisp"]: # find large drops in disp value
return "idle_strt"
elif row["disp"] + 250 < row["lastdisp"]: # find large increases in disp value
return "idle_end"
df["lastdisp"] = df["disp"].shift(1)
df["nextdisp"] = df["disp"].shift(-1)
df["status"] = df.apply(_idlefinder, axis=1) # label idle_start and idle_end
df.drop(columns=["nextdisp", "lastdisp"], inplace=True)
但这既不优雅也不完整的解决方案。 我要问的关键部分是如何填充“idl_strt”和“idl_ends”之间的行,因为数据的其余部分(带有噪音读数的上升和暂停)也必须被识别和标记。 我的偏好是不要逐行浏览数据,因为我使用的是数据框。
该程序的早期版本确实在列表中逐行解析这些数据,但变得有点冗长并且需要调整或修改。
您有多种方法可以矢量地实现这一目标。下面是一个示例,它根据接近 225 的值(容差为 ±2)识别平坦区域,并在上一个/下一个值 >520 时突出显示开始/结束。它使用
shift
和 numpy.select
:
def idle_finder(col, flat_value=225, flat_tol=2, high_thresh=520):
m1 = col.gt(high_thresh)
m2 = col.sub(flat_value).abs().lt(flat_tol)
return pd.Series(np.select([m1.shift()&m2, m1.shift(-1)&m2, m2],
['idl_strt', 'idl_ends', 'idle'],
''),
index=col.index
).replace('', None)
df['status'] = idle_finder(df['disp'])
输出:
disp temp status
148 528.253551 0.908375 None
149 537.832220 0.944138 None
150 225.073475 0.890493 idl_strt
151 225.247861 0.892878 idle
152 225.487333 0.895262 idle
153 225.515279 0.926256 idle
154 225.515003 0.909567 idle
155 225.518680 0.901222 idle
156 225.537893 0.927448 idle
157 225.068878 0.865460 idl_ends
158 540.460613 0.873804 None
159 531.048884 0.865460 None
如果要确保空闲期在大于 520 的值之后/之前开始和结束,可以使用附加掩码:
def idle_finder(col, flat_value=225, flat_tol=2, high_thresh=520):
m1 = col.gt(high_thresh)
m2 = col.sub(flat_value).abs().lt(flat_tol)
m3 = m1.mask(m2)
m4 = m3.ffill() & m3.bfill() & m2
return pd.Series(np.select([m1.shift()&m4, m1.shift(-1)&m4, m4],
['idl_strt', 'idl_ends', 'idle'],
''),
index=col.index
).replace('', None)
df['status'] = idle_finder(df['disp'])
输出:
disp temp status
148 528.253551 0.908375 None
149 337.832220 0.944138 None
150 225.073475 0.890493 None
151 225.247861 0.892878 None
152 225.487333 0.895262 None
153 225.515279 0.926256 None
154 525.515003 0.909567 None
155 225.518680 0.901222 idl_strt
156 225.537893 0.927448 idle
157 225.068878 0.865460 idl_ends
158 540.460613 0.873804 None
159 531.048884 0.865460 None
中间体:
disp temp status m1 m2 m1.shift()&m2 m1.shift(-1)&m2 m3 m4 m1.shift()&m4 m1.shift(-1)&m4
148 528.253551 0.908375 None True False False False True False False False
149 337.832220 0.944138 None False False False False False False False False
150 225.073475 0.890493 None False True False False NaN False False False
151 225.247861 0.892878 None False True False False NaN False False False
152 225.487333 0.895262 None False True False False NaN False False False
153 225.515279 0.926256 None False True False True NaN False False False
154 525.515003 0.909567 None True False False False True False False False
155 225.518680 0.901222 idl_strt False True True False NaN True True False
156 225.537893 0.927448 idle False True False False NaN True False False
157 225.068878 0.865460 idl_ends False True False True NaN True False True
158 540.460613 0.873804 None True False False False True False False False
159 531.048884 0.865460 None True False False False True False False False