hms_cattle_research/util.py
2024-12-22 09:58:15 +08:00

75 lines
3.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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