一维数据中的步进检测
Step detection in one-dimensional data
Python 中是否存在用于检测一维数据中的步骤的现有实现?
例如检测此数据中的一个步骤的东西:
有很多算法描述 out there 但我想知道 Python 中是否存在适合该工作的内容?
我不确定 if/how 我应该提供该数据,但这里是:
[ 594. 568.55555556 577.22222222 624.55555556 546.66666667
552.88888889 575.55555556 592.33333333 528.88888889 576.11111111
625. 574.22222222 556.33333333 567.66666667 576.66666667
591.66666667 566.33333333 567.33333333 547.44444444 631.11111111
555.66666667 548.66666667 579.44444444 546.88888889 597.55555556
519.88888889 582.33333333 618.88888889 574.55555556 547.44444444
593.11111111 565.66666667 544.66666667 562.66666667 554.11111111
543.88888889 602.33333333 609.77777778 550.55555556 561.88888889
719.33333333 784.44444444 711.22222222 843.66666667 691.33333333
690.11111111 684.33333333 749.11111111 759.11111111 653.33333333
817.11111111 705.22222222 689.44444444 712.33333333 659.
683.88888889 713. 740.44444444 692.22222222 677.33333333
681.44444444 640. 717.55555556 717.88888889 769.22222222
690.88888889 786. 774.66666667 799.44444444 743.44444444
789.88888889 673.66666667 685.66666667 709.88888889 645.55555556
846.11111111 792.77777778 702.22222222 749.44444444 678.55555556
707.55555556 665.77777778 643.55555556 671.44444444 795.66666667
627.22222222 684.55555556 708.44444444 829.66666667 719. ]
一步步卷积,看峰分辨率够不够好
import numpy as np
from matplotlib import pyplot as plt
d = '''594. 568.55555556 577.22222222 624.55555556 546.66666667
552.88888889 575.55555556 592.33333333 528.88888889 576.11111111
625. 574.22222222 556.33333333 567.66666667 576.66666667
591.66666667 566.33333333 567.33333333 547.44444444 631.11111111
555.66666667 548.66666667 579.44444444 546.88888889 597.55555556
519.88888889 582.33333333 618.88888889 574.55555556 547.44444444
593.11111111 565.66666667 544.66666667 562.66666667 554.11111111
543.88888889 602.33333333 609.77777778 550.55555556 561.88888889
719.33333333 784.44444444 711.22222222 843.66666667 691.33333333
690.11111111 684.33333333 749.11111111 759.11111111 653.33333333
817.11111111 705.22222222 689.44444444 712.33333333 659.
683.88888889 713. 740.44444444 692.22222222 677.33333333
681.44444444 640. 717.55555556 717.88888889 769.22222222
690.88888889 786. 774.66666667 799.44444444 743.44444444
789.88888889 673.66666667 685.66666667 709.88888889 645.55555556
846.11111111 792.77777778 702.22222222 749.44444444 678.55555556
707.55555556 665.77777778 643.55555556 671.44444444 795.66666667
627.22222222 684.55555556 708.44444444 829.66666667 719. '''
dary = np.array([*map(float, d.split())])
dary -= np.average(dary)
step = np.hstack((np.ones(len(dary)), -1*np.ones(len(dary))))
dary_step = np.convolve(dary, step, mode='valid')
# get the peak of the convolution, its index
step_indx = np.argmax(dary_step) # yes, cleaner than np.where(dary_step == dary_step.max())[0][0]
# plots
plt.plot(dary)
plt.plot(dary_step/10)
plt.plot((step_indx, step_indx), (dary_step[step_indx]/10, 0), 'r')
我自己对此很感兴趣。我不是专家,但正如建议的那样,scikit-image 中的 in this answer, if you de-noise the signal first, it might help distinguish the true step from the noise. The total variation denoising 算法可以解决问题:
import numpy as np
from matplotlib import pyplot as plt
from skimage.restoration import denoise_tv_chambolle
data = '''594. 568.55555556 577.22222222 624.55555556 546.66666667
552.88888889 575.55555556 592.33333333 528.88888889 576.11111111
625. 574.22222222 556.33333333 567.66666667 576.66666667
591.66666667 566.33333333 567.33333333 547.44444444 631.11111111
555.66666667 548.66666667 579.44444444 546.88888889 597.55555556
519.88888889 582.33333333 618.88888889 574.55555556 547.44444444
593.11111111 565.66666667 544.66666667 562.66666667 554.11111111
543.88888889 602.33333333 609.77777778 550.55555556 561.88888889
719.33333333 784.44444444 711.22222222 843.66666667 691.33333333
690.11111111 684.33333333 749.11111111 759.11111111 653.33333333
817.11111111 705.22222222 689.44444444 712.33333333 659.
683.88888889 713. 740.44444444 692.22222222 677.33333333
681.44444444 640. 717.55555556 717.88888889 769.22222222
690.88888889 786. 774.66666667 799.44444444 743.44444444
789.88888889 673.66666667 685.66666667 709.88888889 645.55555556
846.11111111 792.77777778 702.22222222 749.44444444 678.55555556
707.55555556 665.77777778 643.55555556 671.44444444 795.66666667
627.22222222 684.55555556 708.44444444 829.66666667 719. '''
x = np.array(data.split()).astype('float')
x_std = (x - x.mean()) / x.std()
x_denoise = denoise_tv_chambolle(x_std, weight=1) # adjust the parameters
x_step = -2*np.cumsum(x_denoise)
step_indicator = x_step == x_step.max()
n = x.shape[0]
plt.subplot(211)
plt.plot(range(n), x_std, label='standardized')
plt.plot(range(n), x_denoise, label='denoised (TV)')
plt.legend()
plt.grid()
plt.subplot(212)
plt.step(range(n), step_indicator)
plt.show()
输出:
注:
使用这些方法的一个警告,您必须确保信号中只有一个步骤(并且必须有一个)。
Python 中是否存在用于检测一维数据中的步骤的现有实现?
例如检测此数据中的一个步骤的东西:
有很多算法描述 out there 但我想知道 Python 中是否存在适合该工作的内容?
我不确定 if/how 我应该提供该数据,但这里是:
[ 594. 568.55555556 577.22222222 624.55555556 546.66666667
552.88888889 575.55555556 592.33333333 528.88888889 576.11111111
625. 574.22222222 556.33333333 567.66666667 576.66666667
591.66666667 566.33333333 567.33333333 547.44444444 631.11111111
555.66666667 548.66666667 579.44444444 546.88888889 597.55555556
519.88888889 582.33333333 618.88888889 574.55555556 547.44444444
593.11111111 565.66666667 544.66666667 562.66666667 554.11111111
543.88888889 602.33333333 609.77777778 550.55555556 561.88888889
719.33333333 784.44444444 711.22222222 843.66666667 691.33333333
690.11111111 684.33333333 749.11111111 759.11111111 653.33333333
817.11111111 705.22222222 689.44444444 712.33333333 659.
683.88888889 713. 740.44444444 692.22222222 677.33333333
681.44444444 640. 717.55555556 717.88888889 769.22222222
690.88888889 786. 774.66666667 799.44444444 743.44444444
789.88888889 673.66666667 685.66666667 709.88888889 645.55555556
846.11111111 792.77777778 702.22222222 749.44444444 678.55555556
707.55555556 665.77777778 643.55555556 671.44444444 795.66666667
627.22222222 684.55555556 708.44444444 829.66666667 719. ]
一步步卷积,看峰分辨率够不够好
import numpy as np
from matplotlib import pyplot as plt
d = '''594. 568.55555556 577.22222222 624.55555556 546.66666667
552.88888889 575.55555556 592.33333333 528.88888889 576.11111111
625. 574.22222222 556.33333333 567.66666667 576.66666667
591.66666667 566.33333333 567.33333333 547.44444444 631.11111111
555.66666667 548.66666667 579.44444444 546.88888889 597.55555556
519.88888889 582.33333333 618.88888889 574.55555556 547.44444444
593.11111111 565.66666667 544.66666667 562.66666667 554.11111111
543.88888889 602.33333333 609.77777778 550.55555556 561.88888889
719.33333333 784.44444444 711.22222222 843.66666667 691.33333333
690.11111111 684.33333333 749.11111111 759.11111111 653.33333333
817.11111111 705.22222222 689.44444444 712.33333333 659.
683.88888889 713. 740.44444444 692.22222222 677.33333333
681.44444444 640. 717.55555556 717.88888889 769.22222222
690.88888889 786. 774.66666667 799.44444444 743.44444444
789.88888889 673.66666667 685.66666667 709.88888889 645.55555556
846.11111111 792.77777778 702.22222222 749.44444444 678.55555556
707.55555556 665.77777778 643.55555556 671.44444444 795.66666667
627.22222222 684.55555556 708.44444444 829.66666667 719. '''
dary = np.array([*map(float, d.split())])
dary -= np.average(dary)
step = np.hstack((np.ones(len(dary)), -1*np.ones(len(dary))))
dary_step = np.convolve(dary, step, mode='valid')
# get the peak of the convolution, its index
step_indx = np.argmax(dary_step) # yes, cleaner than np.where(dary_step == dary_step.max())[0][0]
# plots
plt.plot(dary)
plt.plot(dary_step/10)
plt.plot((step_indx, step_indx), (dary_step[step_indx]/10, 0), 'r')
我自己对此很感兴趣。我不是专家,但正如建议的那样,scikit-image 中的 in this answer, if you de-noise the signal first, it might help distinguish the true step from the noise. The total variation denoising 算法可以解决问题:
import numpy as np
from matplotlib import pyplot as plt
from skimage.restoration import denoise_tv_chambolle
data = '''594. 568.55555556 577.22222222 624.55555556 546.66666667
552.88888889 575.55555556 592.33333333 528.88888889 576.11111111
625. 574.22222222 556.33333333 567.66666667 576.66666667
591.66666667 566.33333333 567.33333333 547.44444444 631.11111111
555.66666667 548.66666667 579.44444444 546.88888889 597.55555556
519.88888889 582.33333333 618.88888889 574.55555556 547.44444444
593.11111111 565.66666667 544.66666667 562.66666667 554.11111111
543.88888889 602.33333333 609.77777778 550.55555556 561.88888889
719.33333333 784.44444444 711.22222222 843.66666667 691.33333333
690.11111111 684.33333333 749.11111111 759.11111111 653.33333333
817.11111111 705.22222222 689.44444444 712.33333333 659.
683.88888889 713. 740.44444444 692.22222222 677.33333333
681.44444444 640. 717.55555556 717.88888889 769.22222222
690.88888889 786. 774.66666667 799.44444444 743.44444444
789.88888889 673.66666667 685.66666667 709.88888889 645.55555556
846.11111111 792.77777778 702.22222222 749.44444444 678.55555556
707.55555556 665.77777778 643.55555556 671.44444444 795.66666667
627.22222222 684.55555556 708.44444444 829.66666667 719. '''
x = np.array(data.split()).astype('float')
x_std = (x - x.mean()) / x.std()
x_denoise = denoise_tv_chambolle(x_std, weight=1) # adjust the parameters
x_step = -2*np.cumsum(x_denoise)
step_indicator = x_step == x_step.max()
n = x.shape[0]
plt.subplot(211)
plt.plot(range(n), x_std, label='standardized')
plt.plot(range(n), x_denoise, label='denoised (TV)')
plt.legend()
plt.grid()
plt.subplot(212)
plt.step(range(n), step_indicator)
plt.show()
输出:
注:
使用这些方法的一个警告,您必须确保信号中只有一个步骤(并且必须有一个)。