鉴于我有一个X和Y数组,如下所示:
import Foundation
import UIKit
import SwiftKeychainWrapper
import Firebase
import CoreFoundation
import AVFoundation
import FirebaseDatabase
class homepage:UITableViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if educationCache.count < 0 {
self.performSegue(withIdentifier: "toFeed", sender: nil)
}
}
override func viewDidLoad() {
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Sign Out", style: .plain, target: self, action: #selector(signOut))
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@objc func signOut (_sender: AnyObject) {
KeychainWrapper.standard.removeObject(forKey: "uid")
do {
try Auth.auth().signOut()
} catch let signOutError as NSError {
print ("Error signing out: %@", signOutError)
}
dismiss(animated: true, completion: nil)
}
}
和
X = np.array([1,2,3,4,5,6,7,8,9,10,11,12])
我得到一个类似的情节:
在这里我可以看到3个非常清晰的峰。我可以使用以下数据拟合该数据:
Y = np.array([-19.9, -19.6, -17.6, -15.9, -19.9, -18.4, -17.7, -16.6, -19.5, -20.4, -17.6, -15.9])
我可以得到以下内容,该信号显示了一年中信号的变化-在这种情况下,水稻农业和农业周期数(3个峰值):
在这里,我使用scipy.signal.argrelextrema查找曲线的峰谷。但是,要获得一条拟合得很好的曲线是一种非常“手动”的方法,为了选择多项式阶数,我必须先用肉眼来解释数据。我将在许多数据集(100,000个)上重复此过程,因此无法每次都手动进行此操作。
此外,我拥有的峰数可能会改变。实际上,我的最终目标是将我拥有的数据集归类为可以检测到的峰数。在某些情况下,信号会有更多的噪声。
我研究了scipy.signal.find_peaks(和相关算法),但是它发现了每个峰,而不仅仅是主要峰,尤其是在嘈杂的数据中。我也研究了savgol滤波器和高斯滤波器,并且能够得到结果,但是经常必须指定多项式的阶数等,而阶数可能会随峰数的变化而变化。
是否有一种方法可以使信号平滑以得到峰值数量的近似值,而不必手动指定多项式阶数等?有没有可用的算法/方法可以检测总体趋势而无需过多的用户输入?
如果有比曲线拟合更好的方法,我也愿意接受其他方法。我担心我得到的结果只会和我输入的结果一样好,因此任何常规的曲线拟合方法都会产生较差的结果。
答案 0 :(得分:1)
这是使用您的数据和一个简单方程式(带有偏移量的Fourier级数1项)的图形拟合器,看起来可以自动平滑拟合。
import numpy, scipy, matplotlib
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
xData = numpy.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0])
yData = numpy.array([-19.9, -19.6, -17.6, -15.9, -19.9, -18.4, -17.7, -16.6, -19.5, -20.4, -17.6, -15.9])
# Fourier Series 1 Term (scaled X) from zunzun.com
def func(x, offset, a1, b1, c1):
return a1 *numpy.sin(c1 * x) + b1 *numpy.cos(c1 * x) + offset
# these are the same as the scipy defaults
initialParameters = numpy.array([1.0, 1.0, 1.0, 1.0])
# curve fit the test data
fittedParameters, pcov = curve_fit(func, xData, yData, initialParameters)
modelPredictions = func(xData, *fittedParameters)
absError = modelPredictions - yData
SE = numpy.square(absError) # squared errors
MSE = numpy.mean(SE) # mean squared errors
RMSE = numpy.sqrt(MSE) # Root Mean Squared Error, RMSE
Rsquared = 1.0 - (numpy.var(absError) / numpy.var(yData))
print('Parameters:', fittedParameters)
print('RMSE:', RMSE)
print('R-squared:', Rsquared)
print()
##########################################################
# graphics output section
def ModelAndScatterPlot(graphWidth, graphHeight):
f = plt.figure(figsize=(graphWidth/100.0, graphHeight/100.0), dpi=100)
axes = f.add_subplot(111)
# first the raw data as a scatter plot
axes.plot(xData, yData, 'D')
# create data for the fitted equation plot
xModel = numpy.linspace(min(xData), max(xData))
yModel = func(xModel, *fittedParameters)
# now the model as a line plot
axes.plot(xModel, yModel)
axes.set_xlabel('X Data') # X axis data label
axes.set_ylabel('Y Data') # Y axis data label
plt.show()
plt.close('all') # clean up after using pyplot
graphWidth = 800
graphHeight = 600
ModelAndScatterPlot(graphWidth, graphHeight)
答案 1 :(得分:0)
pip install findpeaks
from findpeaks import findpeaks
X = [-19.9, -19.6, -17.6, -15.9, -19.9, -18.4, -17.7, -16.6, -19.5, -20.4, -17.6, -15.9]
# Initialize
fp = findpeaks(lookahead=1)
# Make the fit
results1 = fp.fit(X)
results1['df']
# x y labx valley peak labx_topology valley_topology peak_topology persistence
# 0 0 -19.9 1.0 True False 1.0 True False
# 1 1 -19.6 1.0 False False 1.0 False False
# 2 2 -17.6 1.0 False False 1.0 False False
# 3 3 -15.9 1.0 False True 1.0 False True
# 4 4 -19.9 1.0 False False 2.0 True False
# 5 5 -18.4 2.0 True False 2.0 False False
# 6 6 -17.7 2.0 False False 2.0 False False
# 7 7 -16.6 2.0 False True 2.0 False True
# 8 8 -19.5 2.0 False False 2.0 False False
# 9 9 -20.4 3.0 True False 2.0 False False
# 10 10 -17.6 3.0 False False 2.0 False False
# 11 11 -15.9 3.0 True False 2.0 True False
# Make plot
fp.plot()
# Initialize
fp = findpeaks(lookahead=1, interpolate=10)
# Make the fit
results2 = fp.fit(X)
# Results
results1['df']
# Make plot
fp.plot()