numpy 基于最佳点组自动计算数组的导数

up9lanfz  于 2023-10-19  发布在  其他
关注(0)|答案(2)|浏览(87)

我有一个问题,我似乎找不到任何解决方案。我有一组像下面这样的观点。

import numpy as np
import matplotlib.pyplot as plt

x = np.array([1,1,1,1,2,3,4,4,4,4,4.5,5,5.5,6,6.5,7,7.5,8,8.1,8.2,8.3,8.4,8.5,8.5,8.5,8.5])
y = np.linspace(10,20,len(x))

plt.plot(x*0.1,y,'o', label='x')
plt.xlabel('x * 0.1')
plt.ylabel('y')

图1

我想计算导数,这样它就能找到一组具有共同增长趋势的点的最佳组合。最后,我希望有这样一个结果:

x_diff = np.diff(x)
y_diff = np.linspace(10.5,19.5,len(x_diff))
plt.plot(x_diff,y_diff, label='diff(x)')
plt.legend()

图2

为了得到上面的结果,我使用了Numpy的diff函数,它逐点计算导数。由于数据是无噪声的,它工作得很好。但在带有随机噪声的真实的数据中,diff函数会给予这样的结果:

x_noise = x + np.random.rand(len(x))*0.3
plt.plot(x_noise*0.1,y,'o', label='x + noise')
plt.xlabel('x + noise * 0.1')
plt.ylabel('y')

x_diff = np.diff(x_noise)
y_diff = np.linspace(10.5,19.5,len(x_diff))
plt.plot(x_diff,y_diff, label='diff(x + noise)')
plt.legend()

图3

是否有任何方法可以使用图3中的噪声数据获得与图2相同的结果?换句话说,一种不是逐点计算导数的方法,而是一种自动找到导数最平滑的最佳点组的算法?
我愿意接受任何建议。谢谢你,谢谢

pod7payv

pod7payv1#

根据我们在评论中的讨论,我得出了这个结论:它依赖于一个名为PWLF的库,该库将分段线性函数拟合到给定段数的数据。可以使用pip install pwlf安装
这是一个想法,不需要神经网络。另外,我冒昧地切换了xy轴,因为你的命令有点伤我的大脑。

import numpy as np
import matplotlib.pyplot as plt
import pwlf

# data
y = np.array([1, 1, 1, 1, 2, 3, 4, 4, 4, 4, 4.5, 5, 5.5, 6, 6.5, 7, 7.5, 8, 8.1, 8.2, 8.3, 8.4, 8.5, 8.5, 8.5, 8.5])
x = np.linspace(10, 20, len(y))

# add noise
y = y + np.random.rand(len(x))*0.3

# options for number of segments
segments_count = list(range(2, 10))

# bookkeeping lists
mse_list = []
breaks_list = []

# initiate PWLF
my_pwlf = pwlf.PiecewiseLinFit(x, y)

# iterate over possible number of segments and calculate piece-wise linear fit
# for each option and store the mean square error vs the data
for i in segments_count:
    print(f"Calculating fit for {i} segments")
    breaks = my_pwlf.fit(i)
    mse = np.square((y - my_pwlf.predict(x))).mean()
    mse_list.append(mse)
    breaks_list.append(breaks)

print("\nDone")

# convert to numpy array
mse_array = np.array(mse_list)

# find the number of segments for which the improvement relative to the
# previous number of segments is largest
mse_ratio = mse_array[:-1]/mse_array[1:]
best_idx = np.argmax(mse_ratio) + 1

# recalculate best fit
breaks = my_pwlf.fit(segments_count[best_idx])

# plot improvement as number of segments increases
plt.figure()
plt.plot(segments_count, mse_array, 'o')
plt.show()

# plot best fit
x_hat = np.linspace(x.min(), x.max(), 100)
y_hat = my_pwlf.predict(x_hat)
plt.figure()
plt.plot(x, y, 'o')
plt.plot(x_hat, y_hat, '-')
plt.show()

实际上,我是在遍历一个可能的段数列表。对于每一个,我拟合一个分段线性函数。我通过找到改进最大的段的数量来找到最佳段的数量。

t8e9dugd

t8e9dugd2#

我的一个朋友想出了一个好主意。他没有Stack Overflow账户,所以我代表他写在这里。
这个想法是使用一个带有relu激活的神经网络,其中隐藏层的神经元数量等于你想要找到的层数。

import numpy as np
import matplotlib.pyplot as plt

x = np.array([1,1,1,1,2,3,4,4,4,4,4.5,5,5.5,6,6.5,7,7.5,8,8.1,8.2,8.3,8.4,8.5,8.5,8.5,8.5])
y = np.linspace(10,20,len(x))

x_diff = np.diff(x)
y_diff = np.linspace(10.5,19.5,len(x_diff))

x = x + np.random.rand(len(x))*0.3

plt.plot(x*0.1,y,'o', label='x')
plt.xlabel('x')
plt.ylabel('y')

from sklearn.neural_network import MLPRegressor
import sklearn.pipeline as skp
import sklearn.preprocessing as skpp

nreps = 100
best_score = 0

for n in range(nreps):
    regr = MLPRegressor(hidden_layer_sizes=(10,), activation='relu', max_iter=10000, alpha=0, solver='lbfgs')
    pipe = skp.make_pipeline(skpp.StandardScaler(), regr)
    pipe.fit(y.reshape(-1,1),x)
    score = pipe.score(y.reshape(-1,1),x)
    if score > best_score:
        best_pipe  = pipe
        best_score = score
    if score > 1-1e-6:
        break

x_pred = best_pipe.predict(y.reshape(-1,1))
x_pred_diff = np.diff(x_pred)
x_pred_diff[x_pred_diff < 0] = 0

plt.plot(x_pred*0.1,y, color='red')

plt.plot(x_diff,y_diff, label='diff(x)')
plt.plot(x_pred_diff,y_diff, label='diff(x pred)')
plt.legend()

唯一的问题是,神经网络很容易陷入局部最小值,所以他建议尝试几个网络(在例子中,100个网络)来找到找到最佳解决方案的网络。这就是上面代码中for循环的作用。
网络接收y作为输入,x作为输出。调整网络后,只需使用y预测x并导出预测的x。结果非常好。
我希望我能帮助任何遇到这样问题的人!

相关问题