Вот пример кода подгонки поверхности с вашими данными, который имеет подгонку плоской и изогнутой поверхности, пожалуйста, поищите фразу «выберите модель, комментируя».
import numpy, scipy, scipy.optimize
import matplotlib
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm # to colormap 3D surfaces from blue to red
import matplotlib.pyplot as plt
graphWidth = 800 # units are pixels
graphHeight = 600 # units are pixels
# 3D contour plot lines
numberOfContourLines = 16
xData = numpy.array([971.0, 691.0, 841.0, 970.0, 755.0, 684.0, 938.0, 956.0, 658.0, 838.0, 879.0, 752.0, 690.0, 970.0, 964.0, 966.0, 901.0, 671.0, 660.0, 666.0, 765.0, 831.0, 899.0, 668.0, 969.0, 967.0, 651.0, 929.0, 805.0, 812.0, 936.0, 650.0, 964.0, 719.0, 654.0, 646.0, 932.0, 827.0, 917.0, 945.0, 724.0, 956.0, 966.0, 969.0, 968.0, 967.0, 718.0, 966.0, 812.0, 649.0, 645.0, 675.0, 959.0, 966.0, 962.0, 967.0, 956.0, 757.0, 964.0, 817.0, 666.0, 812.0, 902.0, 969.0, 661.0, 962.0, 752.0, 802.0, 670.0, 663.0, 966.0, 967.0, 773.0, 663.0, 818.0, 917.0, 952.0, 834.0, 516.0, 547.0, 846.0, 458.0, 490.0, 835.0, 579.0, 472.0, 557.0, 652.0, 471.0, 455.0, 837.0, 842.0, 832.0, 675.0, 529.0, 509.0, 533.0, 493.0, 572.0, 695.0, 464.0, 846.0, 845.0, 505.0, 833.0, 544.0, 550.0, 594.0, 486.0, 847.0, 471.0, 533.0, 497.0, 838.0, 832.0, 830.0, 847.0, 844.0, 837.0, 831.0, 671.0, 844.0, 824.0, 841.0, 532.0, 576.0, 852.0, 471.0, 496.0, 839.0, 587.0, 478.0, 565.0, 657.0, 481.0, 463.0, 841.0, 842.0, 832.0, 682.0, 532.0, 509.0, 539.0, 497.0, 574.0, 704.0, 472.0, 850.0, 849.0, 512.0, 834.0, 540.0, 542.0, 603.0, 481.0, 847.0, 472.0, 529.0, 496.0, 836.0, 570.0, 588.0, 837.0, 474.0, 781.0, 842.0, 855.0, 846.0, 845.0, 518.0, 854.0, 585.0, 531.0, 539.0, 536.0])
yData = numpy.array([956.0, 825.0, 963.0, 731.0, 939.0, 879.0, 523.0, 962.0, 880.0, 962.0, 536.0, 942.0, 902.0, 954.0, 662.0, 959.0, 550.0, 798.0, 836.0, 778.0, 945.0, 959.0, 532.0, 880.0, 783.0, 733.0, 833.0, 526.0, 955.0, 956.0, 959.0, 863.0, 714.0, 924.0, 778.0, 849.0, 523.0, 957.0, 960.0, 559.0, 925.0, 959.0, 955.0, 760.0, 953.0, 952.0, 921.0, 713.0, 955.0, 838.0, 819.0, 781.0, 956.0, 950.0, 714.0, 937.0, 955.0, 947.0, 739.0, 957.0, 864.0, 957.0, 531.0, 896.0, 796.0, 954.0, 945.0, 955.0, 762.0, 878.0, 951.0, 953.0, 951.0, 877.0, 959.0, 958.0, 609.0, 791.0, 496.0, 786.0, 597.0, 615.0, 574.0, 432.0, 805.0, 599.0, 793.0, 344.0, 617.0, 615.0, 792.0, 456.0, 807.0, 328.0, 504.0, 543.0, 494.0, 644.0, 803.0, 319.0, 611.0, 690.0, 471.0, 543.0, 392.0, 774.0, 783.0, 812.0, 597.0, 478.0, 627.0, 508.0, 576.0, 799.0, 803.0, 421.0, 534.0, 645.0, 791.0, 422.0, 321.0, 790.0, 384.0, 803.0, 520.0, 797.0, 563.0, 629.0, 581.0, 441.0, 809.0, 602.0, 797.0, 354.0, 625.0, 621.0, 796.0, 463.0, 806.0, 333.0, 511.0, 543.0, 501.0, 648.0, 804.0, 323.0, 620.0, 689.0, 483.0, 554.0, 396.0, 767.0, 777.0, 806.0, 596.0, 479.0, 625.0, 506.0, 574.0, 411.0, 801.0, 811.0, 426.0, 626.0, 811.0, 809.0, 515.0, 805.0, 804.0, 651.0, 564.0, 795.0, 589.0, 576.0, 495.0])
zData = numpy.array([-2.0, -105.0, -26.0, 44.0, -69.0, -65.0, 60.0, -22.0, -77.0, -24.0, 58.0, -36.0, -66.0, -3.0, 34.0, -8.0, 57.0, -82.0, -98.0, -90.0, -55.0, -23.0, 60.0, -61.0, 29.0, 36.0, -72.0, 61.0, -44.0, -47.0, -27.0, -73.0, 40.0, -37.0, -107.0, -89.0, 68.0, -32.0, -38.0, 63.0, -54.0, -33.0, 16.0, 34.0, 3.0, 15.0, -61.0, 54.0, -39.0, -72.0, -77.0, -97.0, -16.0, 0.0, 45.0, 11.0, -9.0, -57.0, 47.0, -37.0, -82.0, -15.0, 63.0, 21.0, -73.0, 4.0, -55.0, -23.0, -87.0, -74.0, 24.0, -1.0, -46.0, -59.0, -47.0, -18.0, 41.0, 18.0, -104.0, -25.0, 18.0, -55.0, -64.0, 55.0, -35.0, -56.0, -25.0, 63.0, -46.0, -70.0, 16.0, 59.0, -17.0, 78.0, -86.0, -102.0, -113.0, -41.0, -53.0, 68.0, -56.0, 28.0, 24.0, -88.0, 42.0, -59.0, -35.0, -38.0, -79.0, 48.0, -65.0, -113.0, -73.0, 4.0, -8.0, 63.0, 28.0, 23.0, 25.0, 48.0, 74.0, 7.0, 45.0, 11.0, -92.0, -38.0, 29.0, -69.0, -87.0, 56.0, -31.0, -60.0, -29.0, 59.0, -43.0, -53.0, -4.0, 50.0, -5.0, 74.0, -89.0, -84.0, -116.0, -53.0, -42.0, 46.0, -69.0, 32.0, 36.0, -83.0, 57.0, -64.0, -36.0, -18.0, -94.0, 52.0, -72.0, -87.0, -77.0, 44.0, -57.0, -33.0, 53.0, -76.0, -33.0, -12.0, 15.0, 9.0, -6.0, -70.0, 43.0, -58.0, -100.0, -78.0, -97.0])
# Simple_SimpleEquation_42_Offset_model from zunzun.com
def curvedModel(data, a, b, c, Offset):
x = data[0]
y = data[1]
return numpy.exp(a+b/y+c*numpy.log(x)) + Offset
def flatModel(data, a, b, Offset):
x = data[0]
y = data[1]
return a*x + b*y + Offset
# choose model by commenting
#func = flatModel
#initialParameters = [1.0, 1.0, 1.0] # these are the same as scipy default values in this example
func = curvedModel
initialParameters = [1.0, 1.0, 1.0, 1.0] # these are the same as scipy default values in this example
def SurfacePlot(func, data, fittedParameters):
f = plt.figure(figsize=(graphWidth/100.0, graphHeight/100.0), dpi=100)
matplotlib.pyplot.grid(True)
axes = Axes3D(f)
x_data = data[0]
y_data = data[1]
z_data = data[2]
xModel = numpy.linspace(min(x_data), max(x_data), 20)
yModel = numpy.linspace(min(y_data), max(y_data), 20)
X, Y = numpy.meshgrid(xModel, yModel)
Z = func(numpy.array([X, Y]), *fittedParameters)
axes.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm, linewidth=1, antialiased=True)
axes.scatter(x_data, y_data, z_data) # show data along with plotted surface
axes.set_title('Surface Plot (click-drag with mouse)') # add a title for surface plot
axes.set_xlabel('X Data') # X axis data label
axes.set_ylabel('Y Data') # Y axis data label
axes.set_zlabel('Z Data') # Z axis data label
plt.show()
plt.close('all') # clean up after using pyplot or else thaere can be memory and process problems
def ContourPlot(func, data, fittedParameters):
f = plt.figure(figsize=(graphWidth/100.0, graphHeight/100.0), dpi=100)
axes = f.add_subplot(111)
x_data = data[0]
y_data = data[1]
z_data = data[2]
xModel = numpy.linspace(min(x_data), max(x_data), 20)
yModel = numpy.linspace(min(y_data), max(y_data), 20)
X, Y = numpy.meshgrid(xModel, yModel)
Z = func(numpy.array([X, Y]), *fittedParameters)
axes.plot(x_data, y_data, 'o')
axes.set_title('Contour Plot') # add a title for contour plot
axes.set_xlabel('X Data') # X axis data label
axes.set_ylabel('Y Data') # Y axis data label
CS = matplotlib.pyplot.contour(X, Y, Z, numberOfContourLines, colors='k')
matplotlib.pyplot.clabel(CS, inline=1, fontsize=10) # labels for contours
plt.show()
plt.close('all') # clean up after using pyplot or else thaere can be memory and process problems
def ScatterPlot(data):
f = plt.figure(figsize=(graphWidth/100.0, graphHeight/100.0), dpi=100)
matplotlib.pyplot.grid(True)
axes = Axes3D(f)
x_data = data[0]
y_data = data[1]
z_data = data[2]
axes.scatter(x_data, y_data, z_data)
axes.set_title('Scatter Plot (click-drag with mouse)')
axes.set_xlabel('X Data')
axes.set_ylabel('Y Data')
axes.set_zlabel('Z Data')
plt.show()
plt.close('all') # clean up after using pyplot or else thaere can be memory and process problems
if __name__ == "__main__":
data = [xData, yData, zData]
# here a non-linear surface fit is made with scipy's curve_fit()
fittedParameters, pcov = scipy.optimize.curve_fit(func, [xData, yData], zData, p0 = initialParameters)
ScatterPlot(data)
SurfacePlot(func, data, fittedParameters)
ContourPlot(func, data, fittedParameters)
print('fitted prameters', fittedParameters)
modelPredictions = func(data, *fittedParameters)
absError = modelPredictions - zData
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(zData))
print('RMSE:', RMSE)
print('R-squared:', Rsquared)