You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用自适应方法替换FVC计算函数中的常量阈值?

问题

我写了一个计算用力肺活量(FVC)的函数,逻辑是检测数据序列中负值出现前的最后一个正值,代码如下:

def FVC(self, data):
    count = 0
    for i in range(len(data)):
        # 检测是否存在足够多的负值以判断吸气阶段开始
        if (data[i][1] > 1) and (data[i][2] < 0):
            count += 1
        elif count > 110:
            return data[i-115][1]
        else:
            count = 0

目标序列示例

目标值为[8340.0, 3.0616, 0.0]:

[8280.0, 3.0611, 0.01]
[8290.0, 3.0612, 0.01]
[8300.0, 3.0613, 0.01]
[8310.0, 3.0614, 0.01]
[8320.0, 3.0615, 0.01]
[8330.0, 3.0616, 0.01]
[8340.0, 3.0616, 0.0]
[8350.0, 3.0615, -0.01125]
[8360.0, 3.0614, -0.01125]
[8370.0, 3.0613, -0.01125]
[8380.0, 3.0611, -0.01625]
[8390.0, 3.0609, -0.0275]
[8400.0, 3.0605, -0.033125]
[8410.0, 3.0601, -0.044375]
[8420.0, 3.0595, -0.055625]
[8430.0, 3.0589, -0.06625]
[8440.0, 3.0582, -0.06625]
[8450.0, 3.0575, -0.06625]
[8460.0, 3.0568, -0.0775]
[8470.0, 3.056, -0.0775]
[8480.0, 3.0551, -0.08875]
[8490.0, 3.0541, -0.105]
[8500.0, 3.0527, -0.1325]
[8510.0, 3.051, -0.17125]
[8520.0, 3.0489, -0.21]
[8530.0, 3.0465, -0.24375]
[8540.0, 3.0437, -0.2825]
[8550.0, 3.0406, -0.31]
[8560.0, 3.0371, -0.34312]
[8570.0, 3.0334, -0.37062]
[8580.0, 3.0294, -0.39875]
[8590.0, 3.0251, -0.43125]
[8600.0, 3.0204, -0.47625]
[8610.0, 3.0151, -0.52625]
[8620.0, 3.0091, -0.5975]

异常数据示例

数据中会出现短暂负值后又回到正值的情况,导致误判:

[6860.0, 3.0468, 0.0]
[6870.0, 3.0467, -0.005625]
[6880.0, 3.0466, -0.01125]
[6890.0, 3.0465, -0.01125]
[6900.0, 3.0464, -0.01125]
[6910.0, 3.0463, -0.01125]
[6920.0, 3.0461, -0.01125]
[6930.0, 3.046, -0.01125]
[6940.0, 3.0459, -0.01125]
[6950.0, 3.0457, -0.021875]
[6960.0, 3.0455, -0.021875]
[6970.0, 3.0452, -0.0275]
[6980.0, 3.0449, -0.033125]
[6990.0, 3.0445, -0.033125]
[7000.0, 3.0443, -0.021875]
[7010.0, 3.0441, -0.021875]
[7020.0, 3.0439, -0.021875]
[7030.0, 3.0437, -0.021875]
[7040.0, 3.0435, -0.021875]
[7050.0, 3.0433, -0.01125]
[7060.0, 3.0433, -0.005625]
[7070.0, 3.0433, 0.0]
[7080.0, 3.0433, 0.0]
[7090.0, 3.0433, 0.0]
[7100.0, 3.0433, 0.0]
[7110.0, 3.0433, 0.0]
[7120.0, 3.0433, 0.0]
[7130.0, 3.0433, 0.0]
[7140.0, 3.0433, 0.0]
[7150.0, 3.0433, 0.0]
[7160.0, 3.0434, 0.01]
[7170.0, 3.0435, 0.01]

现在我用固定的110次连续负值来判断真正的吸气阶段,但这个常量适应性差,想换成自适应的判断逻辑,怎么实现?

解决方案

1. 基于趋势的自适应判断

真正的吸气阶段(FVC之后),负值的绝对值会呈现持续增大的趋势,而异常波动的负值会先小幅度变化后回归。可以通过跟踪连续负值的变化特征判断:

  • 记录连续负值序列,计算其绝对值的变化斜率
  • 当斜率持续为正(绝对值越来越大)且连续次数超过动态阈值时,判定为真正的吸气阶段

示例代码:

def FVC(self, data):
    neg_sequence = []
    last_positive_idx = 0
    for i in range(len(data)):
        val = data[i][2]
        if data[i][1] > 1:
            if val < 0:
                neg_sequence.append(val)
                # 用最近20个负值判断趋势
                if len(neg_sequence) >= 20:
                    abs_vals = [abs(x) for x in neg_sequence[-20:]]
                    slope = (abs_vals[-1] - abs_vals[0]) / 20
                    # 斜率大于最小变化率,且连续次数超过数据总长度的1/20
                    if slope > 0.005 and len(neg_sequence) > len(data) // 20:
                        return data[last_positive_idx][1]
            else:
                last_positive_idx = i
                neg_sequence = []
    return data[last_positive_idx][1]

2. 状态机阶段划分

把呼吸过程划分为呼气阶段、疑似吸气阶段、确认吸气阶段三个状态,通过状态转移实现自适应判断:

  • 呼气阶段:持续记录最后一个正值的位置,遇到负值进入疑似状态
  • 疑似吸气阶段:统计连续负值的数量和变化,若回归正值则回到呼气阶段;若负值持续且绝对值增大,则进入确认状态
  • 确认吸气阶段:返回之前记录的最后一个正值

3. 统计特征动态阈值

先遍历数据统计呼气阶段的特征,再生成动态阈值:

  • 统计呼气阶段(FVC之前)连续非负值的平均长度
  • 将判断阈值设为该平均长度的1/3~1/4,过滤短暂异常波动

示例代码:

def FVC(self, data):
    # 先统计呼气阶段的连续非负值长度
    expiratory_lengths = []
    current_len = 0
    for i in range(len(data)):
        val = data[i][2]
        if val >= 0 and data[i][1] > 1:
            current_len += 1
        else:
            if current_len > 0:
                expiratory_lengths.append(current_len)
                current_len = 0
    # 生成自适应阈值
    avg_exp_len = sum(expiratory_lengths)/len(expiratory_lengths) if expiratory_lengths else 50
    adaptive_threshold = int(avg_exp_len * 0.2)

    # 正式检测FVC
    count = 0
    last_positive_idx = 0
    for i in range(len(data)):
        if (data[i][1] > 1) and (data[i][2] < 0):
            count += 1
            if count >= adaptive_threshold:
                # 额外验证后续5个点的趋势
                if all(data[j][2]<0 and abs(data[j][2])>abs(data[j-1][2]) for j in range(max(i-5,0), i+1)):
                    return data[last_positive_idx][1]
        else:
            if data[i][1]>1 and data[i][2]>=0:
                last_positive_idx = i
            count = 0
    return data[last_positive_idx][1]

关键注意点

  • 保留data[i][1]>1的有效性判断,避免无效数据干扰
  • 加入滞后验证:达到阈值后再验证后续数据点的趋势,减少误判
  • 可根据数据集调整斜率阈值、比例系数等参数,或引入简单分类模型区分正常吸气和异常波动

内容的提问来源于stack exchange,提问作者Noerigarnhy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 15:55:54