# Author: Lee Wu Love Lele # Datetime: 2024/12/8 12:58 from config import DATETIME_FORMAT from datetime import datetime from scipy.signal import savgol_filter import numpy as np from config import STABILITY_THRESHOLD import pandas as pd def smooth_data(data, window_length=5, polyorder=3): """ 平滑数据降噪,使用Savitzky-Golay滤波 * 通过算法(Savitzky-Golay滤波),将短期波动平滑化,突出重量变化的主要趋势,从而更接近牛的真实体重曲线。 * 在牛走上或走下地磅时,体重数据会从小到大(走上)或从大到小(走下)发生变化。平滑处理可以让“从小到大”或“从大到小”的趋势更加清晰,便于后续算法找到牛完整通过地磅的时间段。 * 如果直接对噪声较大的数据进行分析(如提取最大值、计算均值等),可能需要大量的异常值处理或复杂的算法来排除干扰。 * 平滑数据可以简化后续计算过程,使得分析模型更加高效。 * 牛在地磅上可能出现诸如抬腿、摇晃等小幅动作,这些动作会导致短时间内体重数据发生波动。平滑能够消除这些短时间的小波动,使得体重数据更加稳定。 * 平滑可以让真正的异常值(如多头牛站上地磅)更加显著,便于识别。例如:没有平滑时,普通波动和异常值可能混淆在一起。平滑后,正常数据的波动范围变小,异常值更加容易识别。 :param data: :param window_length: int :param polyorder: int :return: """ """ window_length * 含义: * 表示滑动窗口的长度,即在每次滤波计算中使用的点的数量。 * 它必须是一个正奇数,如 3、5、7 等,因为 Savitzky-Golay 滤波需要确保窗口中心有一个对称点。 * 作用: * 窗口越大: * 数据被平滑得越明显,但可能会导致细节丢失。 * 更适合处理噪声较多但关注长期趋势的情况。 * 窗口越小: * 保留更多的细节,但对噪声的抑制效果较差。 * 更适合处理数据变化较快且噪声较少的情况。 polyorder * 含义: * 表示拟合多项式的阶数,用于滑动窗口内的数据拟合。 * 它必须小于 window_length,因为阶数不能超过拟合点的数量(否则拟合就无意义)。 * 作用: * 多项式阶数越高: * 滤波器拟合数据的能力更强,可以保留更多复杂的细节,但同时可能引入噪声(过拟合)。 * 更适合处理具有快速变化趋势的数据。 * 多项式阶数越低: * 滤波器更倾向于平滑数据,减少噪声,但可能会忽略一些数据细节。 * 更适合处理平稳的数据或去除高频噪声。 """ print(f'window_len: {window_length}, polyorder: {polyorder}') smoothed_data = savgol_filter(data, window_length=window_length, polyorder=polyorder) return smoothed_data def calc_one_cattle(data): print('data: ', data) # print('data len: ', len(data)) # 计算变化率 rate_of_change = np.abs(np.diff(data)) # 一阶差分后的绝对值,比data长度少1 print('np.diff: ', np.diff(data)) # print('np.diff len: ', len(np.diff(data))) print('rate_of_change: ', rate_of_change) # print('rate_of_change len: ', len(rate_of_change)) # 设置阈值,识别稳定时间段 stability_threshold = STABILITY_THRESHOLD # 变化率小于此值视为稳定 stable_indices = np.where(rate_of_change < stability_threshold)[0] print('stable_indices: ', stable_indices) # 找到稳定时间段的体重中值 stable_weights = [data[i] for i in stable_indices] print('stable_weights: ', stable_weights) stable_median_weight = np.median(stable_weights) # TODO:这里取了所有稳定值的中位数,这里包含了异常稳定值形成干扰,如何识别这些异常? print('stable_median_weight: ', stable_median_weight) return stable_median_weight