一维数据去噪

作者: drmeng 分类: Python,编程学习 发布时间: 2022-10-01 04:26
# -*- coding: utf-8 -*-
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import math
import pywt


#平滑噪声—等深分箱—均值平滑
def aequilatus_box_mean(data,bins):
    length=data.shape[0]
    labels=[]
    for i in range(bins):
        labels.append('a'+str(i+1))#添加标签
    new_data=pd.qcut(data.iloc[:,0],bins,labels=labels)#等深分箱
    data['label']=new_data
    for label in labels:
        label_index_min=data[data.label==label].index.min()#分箱后索引最小值
        label_index_max=data[data.label==label].index.max()#分箱后索引最大值
        data.loc[label_index_min:label_index_max,data.columns[0]]=np.mean(
            data.A[label_index_min:label_index_max+1,])#根据label及索引,修改A为各箱均值
    return data

def aequilatus_box_median(data,bins):
    length=data.shape[0]
    labels=[]
    for i in range(bins):
        labels.append('a'+str(i+1))
    new_data=pd.qcut(data.A,bins,labels=labels)#等深分箱
    data['label']=new_data
    for label in labels:
        label_index_min=data[data.label==label].index.min()#分箱后索引最小值
        label_index_max=data[data.label==label].index.max()#分箱后索引最大值
        data.loc[label_index_min:label_index_max,'A']=np.median(
            data.A[label_index_min:label_index_max+1,])#根据label及索引,修改A为各箱均值
    return data

#平滑噪声—等深分箱—边界平滑
def aequilatus_box_border(data,bins):
    length=data.shape[0]
    labels=[]
    for i in range(bins):
        labels.append('a'+str(i+1))
    new_data=pd.qcut(data.A,bins,labels=labels)#等深分箱
    data['label']=new_data
    for label in labels:
        label_index_min=data[data.label==label].index.min()
        label_index_max=data[data.label==label].index.max()
        data_min=np.min(data.A[label_index_min:label_index_max+1,])
        data_max=np.max(data.A[label_index_min:label_index_max+1,])
        for i in range(label_index_min,label_index_max):
            if(data.loc[i,'A']==data_min or data.loc[i,'A']==data_max):
                data.loc[i,'A']=data.loc[i,'A']
            elif(np.abs(data.loc[i,'A']-data_min)<=np.abs(data.loc[i,'A']-data_max)):
                 data.loc[i,'A']=data_min
            else:
                data.loc[i,'A']=data_max
    return data
#一维数据小波阈值去噪
#封装成函数
def sgn(num):
    if(num > 0.0):
        return 1.0
    elif(num == 0.0):
        return 0.0
    else:
        return -1.0

def wavelet_noising(new_df):
    data = new_df
    data = data.values.T.tolist()  # 将np.ndarray()转为列表
    w = pywt.Wavelet('sym8')#选择sym8小波基
    [ca5, cd5, cd4, cd3, cd2, cd1] = pywt.wavedec(data, w, level=5)  # 5层小波分解

    length1 = len(cd1)
    length0 = len(data)

    Cd1 = np.array(cd1)
    abs_cd1 = np.abs(Cd1)
    median_cd1 = np.median(abs_cd1)

    sigma = (1.0 / 0.6745) * median_cd1
    lamda = sigma * math.sqrt(2.0 * math.log(float(length0 ), math.e))#固定阈值计算
    usecoeffs = []
    usecoeffs.append(ca5)  # 向列表末尾添加对象

    #软硬阈值折中的方法
    a = 0.5

    for k in range(length1):
        if (abs(cd1[k]) >= lamda):
            cd1[k] = sgn(cd1[k]) * (abs(cd1[k]) - a * lamda)
        else:
            cd1[k] = 0.0

    length2 = len(cd2)
    for k in range(length2):
        if (abs(cd2[k]) >= lamda):
            cd2[k] = sgn(cd2[k]) * (abs(cd2[k]) - a * lamda)
        else:
            cd2[k] = 0.0

    length3 = len(cd3)
    for k in range(length3):
        if (abs(cd3[k]) >= lamda):
            cd3[k] = sgn(cd3[k]) * (abs(cd3[k]) - a * lamda)
        else:
            cd3[k] = 0.0

    length4 = len(cd4)
    for k in range(length4):
        if (abs(cd4[k]) >= lamda):
            cd4[k] = sgn(cd4[k]) * (abs(cd4[k]) - a * lamda)
        else:
            cd4[k] = 0.0

    length5 = len(cd5)
    for k in range(length5):
        if (abs(cd5[k]) >= lamda):
            cd5[k] = sgn(cd5[k]) * (abs(cd5[k]) - a * lamda)
        else:
            cd5[k] = 0.0

    usecoeffs.append(cd5)
    usecoeffs.append(cd4)
    usecoeffs.append(cd3)
    usecoeffs.append(cd2)
    usecoeffs.append(cd1)
    recoeffs = pywt.waverec(usecoeffs, w)#信号重构
    return recoeffs


def wavelet_noising2(new_df):
    data = new_df
    data = data.values.T.tolist()  # 将np.ndarray()转为列表
    w = pywt.Wavelet('dB10')#选择dB10小波基
    ca3, cd3, cd2, cd1 = pywt.wavedec(data, w, level=3)  # 3层小波分解
    ca3=ca3.squeeze(axis=0) #ndarray数组减维:(1,a)->(a,)
    cd3 = cd3.squeeze(axis=0)
    cd2 = cd2.squeeze(axis=0)
    cd1 = cd1.squeeze(axis=0)
    length1 = len(cd1)
    length0 = len(data[0])

    abs_cd1 = np.abs(np.array(cd1))
    median_cd1 = np.median(abs_cd1)

    sigma = (1.0 / 0.6745) * median_cd1
    lamda = sigma * math.sqrt(2.0 * math.log(float(length0 ), math.e))
    usecoeffs = []
    usecoeffs.append(ca3)

    #软阈值方法
    for k in range(length1):
        if (abs(cd1[k]) >= lamda/np.log2(2)):
            cd1[k] = sgn(cd1[k]) * (abs(cd1[k]) - lamda/np.log2(2))
        else:
            cd1[k] = 0.0

    length2 = len(cd2)
    for k in range(length2):
        if (abs(cd2[k]) >= lamda/np.log2(3)):
            cd2[k] = sgn(cd2[k]) * (abs(cd2[k]) - lamda/np.log2(3))
        else:
            cd2[k] = 0.0

    length3 = len(cd3)
    for k in range(length3):
        if (abs(cd3[k]) >= lamda/np.log2(4)):
            cd3[k] = sgn(cd3[k]) * (abs(cd3[k]) - lamda/np.log2(4))
        else:
            cd3[k] = 0.0

    usecoeffs.append(cd3)
    usecoeffs.append(cd2)
    usecoeffs.append(cd1)
    recoeffs = pywt.waverec(usecoeffs, w)#信号重构
    return recoeffs


if __name__=="__main__":
    data=pd.DataFrame({'A':[11,13,15,20,20,23,26,29,35]})
    bins=3
    print("均值平滑")
    print(aequilatus_box_mean(data,3))

    #############################################################
    print("中值平滑")
    print(aequilatus_box_median(data, 3))

    ##############################
    print("边界平滑")
    print(aequilatus_box_border(data, 3))

    #参考:   https://zhuanlan.zhihu.com/p/157540476
    #####################################################
    print("一维数据小波阈值去噪")
    data_denoising = wavelet_noising(data["A"])  # 调用函数进行小波阈值去噪
    print(data_denoising)

    #####################################################
    print("一维数据小波阈值去噪2")
    data_denoising2 = wavelet_noising2(data["A"])  # 调用函数进行小波阈值去噪
    print(data_denoising2)