You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
fitt/X3.py

343 lines
14 KiB

# -*- coding: utf-8 -*-
# Time : 2023/8/9 10:20
# Author : lirunsheng
# User : l'r's
# Software: PyCharm
# File : X3.py
import mpl_toolkits.axisartist as axisartist
from scipy.optimize import curve_fit
from pandas import DataFrame
import matplotlib.pyplot as plt
import numpy as np
import pylab as mpl
from tkinter import *
import data as gl_data
import pandas as pd
import tkinter
import sys
import tkinter as tk
from tkinter import filedialog
mpl.rcParams['font.sans-serif'] = ['SimHei'] # 解决matplotlib中文不显示问题
plt.rcParams['axes.unicode_minus'] = False # 解决matplotlib负数坐标显示问题
# 创建一个二维数组sampleData用于存储样本数据
sampleData = []
def askfile():# 从本地选择一个文件,并返回文件的路径
global sampleData
# 弹出文件选择对话框,选择要打开的文本文件
file_path = filedialog.askopenfilename(filetypes=[('Text Files', '*.txt')])
# 如果没有选择文件,直接返回
if not file_path:
return
# 步骤1打开样本数据集文件并读取每行数据
with open(file_path, 'r') as file:
lines = file.readlines()
# 步骤2遍历所有行将每行数据解析为sx和sy值转换为浮点数并存储到sampleData中
for line in lines:
sx, sy = line.strip().split(' ')
sx = float(sx)
sy = float(sy)
sampleData.append([sx, sy])
# # 步骤3使用循环遍历样本数据并打印出来
# for data in sampleData:
# print(data)
# if __name__ == '__main__':
# askfile()
def draw_axis(low, high, step=250):
fig = plt.figure(figsize=(4.4, 3.2)) # 设置显示大小
ax = axisartist.Subplot(fig, 111) # 使用axisartist.Subplot方法创建一个绘图区对象ax
fig.add_axes(ax) # 将绘图区对象添加到画布中
ax.axis[:].set_visible(False)# 通过set_visible方法设置绘图区所有坐标轴隐藏
ax.axis["x"] = ax.new_floating_axis(0, 0) # 添加新的x坐标轴
ax.axis["x"].set_axisline_style("-|>", size=1.0) # 给x坐标轴加上箭头
ax.axis["y"] = ax.new_floating_axis(1, 0) # 添加新的y坐标轴
ax.axis["y"].set_axisline_style("-|>", size=1.0) # y坐标轴加上箭头
ax.axis["x"].set_axis_direction("bottom") # 设置x、y轴上刻度显示方向
ax.axis["y"].set_axis_direction("left") # 设置x、y轴上刻度显示方向
plt.xlim(low, high) # 把x轴的刻度范围设置
plt.ylim(low, high) # 把y轴的刻度范围设置
ax.set_xticks(np.arange(low, high + 5, step)) # 把x轴的刻度间隔设置
ax.set_yticks(np.arange(low, high + 5, step)) # 把y轴的刻度间隔设置
def generate_and_plot_sample_data(low, high):
num_samples = 25 #设置样本点数量
gl_data.X = np.random.randint(low=low, high=high, size=num_samples)#随机生成x值
print(gl_data.X)
gl_data.Y = np.random.randint(low=low, high=high, size=num_samples)#随机生成y值
# 提取样本数据的x坐标和y坐标
# x_values = [point[0] for point in sampleData]
# print(x_values)
# y_values = [point[1] for point in sampleData]
draw_axis(low, high) #绘制坐标轴
plt.scatter(gl_data.X,gl_data.Y, color='red') # 绘制样本数据点
plt.savefig(r"dot2.png", facecolor='w') # 保存到本地
plt.close() # 清除内存
# set_phtot(1) #显示到主界面
# if __name__ == '__main__':
# askfile()
# # generate_and_plot_sample_data(gl_data.LOW, gl_data.HIGH)
def quadratic_function(x, a, b, c):#构造二次函数y = a * X^2 + b * X + C
return a * x ** 2 + b * x + c
def draw_dots_and_line(low, high, sx, sy):
draw_axis(low, high)
popt, pcov = curve_fit(quadratic_function, sx, sy)# 用curve_fit来对点进行拟合
positive_mask = sy >= 0.0#给样本点分类
negative_mask = sy < 0.0#给样本点分类
positive_colors = ['red' if x >= 0.0 else 'blue' for x in sx]#给样本点分类
negative_colors = ['green' if x >= 0.0 else 'purple' for x in sx]#给样本点分类
#根据样本点类型决定样本点颜色
plt.scatter(gl_data.X[positive_mask], gl_data.Y[positive_mask], color=np.array(positive_colors)[positive_mask], lw=1)
plt.scatter(gl_data.X[negative_mask], gl_data.Y[negative_mask], color=np.array(negative_colors)[negative_mask], lw=1)
curve_x = np.arange(low, high)#按照步长生成的一串数字
curve_y = [quadratic_function (i, * popt) for i in curve_x]# 根据x来计算y1值
plt.plot(curve_x, curve_y, color='blue', label='Fitted Curve')#绘制拟合曲线
plt.savefig(r"dot5.png", facecolor='w') # 保存到本地
plt.legend()
plt.show()
return popt
# if __name__ == '__main__':
# askfile()
# gl_data.x = np.array([point[0] for point in sampleData]) # 为二次函数.txt
# gl_data.y = np.array([point[1] for point in sampleData])
# popt = draw_dots_and_line(gl_data.low, gl_data.high, gl_data.x, gl_data.y)
# a,b,c = popt
# print(a,b,c)
def input_num(root_tk):
global top
top = tk.Toplevel(root_tk)
top.geometry("300x50")
top.title('坐标点个数')
label1 = Label(top, text="坐标点个数")
label1.grid(row=0) # 这里的side可以赋值为LEFT RTGHT TOP BOTTOM
num1 = IntVar()
entry1 = Entry(top, textvariable=num1)
num1.set(0)
entry1.grid(row=0, column=1)
Label(top, text=" ").grid(row=0, column=3)
Button(top, text="确定", command=lambda: input_data(root_tk, int(entry1.get()))).grid(row=0, column=3)
top.mainloop()
def add_sample_data():
global sample_x, sample_y, sample_data
global entry_x,entry_y,label_status, numx
try:
x = float(entry_x.get())
y = float(entry_y.get())
except:
label_status.config(text="输入不合法")
return
entry_x.delete(0, tk.END)
entry_y.delete(0, tk.END)
if min(x, y) < gl_data.LOW or max(x, y) > gl_data.HIGH:
label_status.config(text="输入超过范围")
return
elif len(sample_data) < numx:
label_status.config(text="点对已添加")
sample_data.append((x, y))
sample_x.append(x)
sample_y.append(y)
else:
label_status.config(text="已达到最大数量")
def check_sample_data():
global label_status,numx,sample_x,sample_y,sample_data
if len(sample_data) == numx:
label_status.config(text="已达到最大数量")
gl_data.X = np.array(sample_x)
gl_data.Y = np.array(sample_y)
print('已添加', sample_data)
sys.exit()
else:
label_status.config(text="还需输入{}个点对".format(numx - len(sample_data)))
print(sample_data)
def input_data(root_tk, num):
global top
global sample_x,sample_y,sample_data
global numx
numx = num
sample_x = []
sample_y = []
sample_data = []
top.destroy()
top = tk.Toplevel(root_tk)
top.geometry("300x200")
top.title('坐标')
global entry_x, entry_y, label_status
label_x = tk.Label(top, text="X 值:")
label_x.pack()
entry_x = tk.Entry(top)
entry_x.pack()
label_y = tk.Label(top, text="Y 值:")
label_y.pack()
entry_y = tk.Entry(top)
entry_y.pack()
button_add = tk.Button(top, text="添加", command=add_sample_data)
button_add.pack()
button_check = tk.Button(top, text="检查", command=check_sample_data)
button_check.pack()
label_status = tk.Label(top, text="")
label_status.pack()
top.mainloop()
# if __name__ == '__main__':
# root = tk.Tk()
# root.withdraw()
# input_num(root)
# 定义误差函数
def error_func(x_data, y_data, a, b, c):
y_pred = exponential_function(x_data, a, b, c)
error = np.sum((y_data - y_pred) ** 2)
residual = y_data - y_pred
ss_res = np.sum(residual ** 2)
ss_tot = np.sum((y_data - np.mean(y_data)) ** 2)
r_squared = 1 - (ss_res / ss_tot)
return error,r_squared
# 给出一个二次函数拟合的例子,读者可自己写拟合函数
def exponential_function(x, a, b, c):
return a * x ** 2 + b * x + c
def fit(sample_data): # 随机生成样本数据
x_data = np.array([data[0] for data in sample_data])
y_data = np.array([data[1] for data in sample_data]) # 拟合样本数据
popt, pcov = curve_fit(exponential_function, x_data, y_data) # 计算拟合结果
# 计算拟合误差
error,r_squared = error_func(x_data, y_data, *popt)
fit_function_name = exponential_function.__name__# 打印拟合函数的形式、系数、误差和优度
print("拟合函数形式:{}".format(fit_function_name))
print("拟合系数:{}".format(popt))
print("误差:{:.4f}".format(error))
print("拟合优度R^2{:.4f}".format(r_squared))
# if __name__ == '__main__':
# askfile()
# fit(sampleData) # 对当前x、y值进行拟合
# # 给出一个指数函数拟合的例子,读者可自己写拟合函数
# def fit_function(x,a,b,c):
# return a * np.exp(b * x) + c
#
# def fit(sample_data): # 随机生成样本数据
# x_data = np.array([data[0] for data in sample_data])
# y_data = np.array([data[1] for data in sample_data]) # 拟合样本数据
# popt, pcov = curve_fit(fit_function, x_data, y_data) # 计算拟合结果
# y_fit = fit_function(x_data, *popt)
# residuals = y_data - y_fit
# ss_res = np.sum(residuals**2)
# ss_tot = np.sum((y_data - np.mean(y_data))**2)
# r_squared = 1 - (ss_res / ss_tot)
# fit_function_name = fit_function.__name__# 打印拟合函数的形式、系数、误差和优度
# print("拟合函数形式:{}".format(fit_function_name))
# print("拟合系数:{}".format(popt))
# print("误差:{:.4f}".format(np.sqrt(np.mean(residuals**2))))
# print("拟合优度R^2{:.4f}".format(r_squared))
# if __name__ == '__main__':
# askfile()
# fit(sampleData) # 对当前x、y值进行拟合
def change_Q(no):
gl_data.Quadrant = no #更改全局变量的象限显示
if no: #若为一象限则修改显示下限为0
gl_data.LOW = 0
else: #若为四象限,则修改显示下限为-gl_data.MAXV
gl_data.LOW = -gl_data.MAXV
q_button() #更新象限显示面板
def q_button():
r = 7.5
rr = 2.5
for widget in q_root.winfo_children():
widget.destroy()
q_cv = tk.Canvas(q_root, width=450, height=500)
q_cv.place(x=0, y=0)
l = tk.Label(q_root, text='坐标轴', bd=0, font=("微软雅黑", 16) , anchor=W)
l.place(x=20, y=0, width=80, height=50,)
# 四象b限按钮
b1 = tk.Button(q_root, text='四象限', bd=0, font=("微软雅黑", 16)
, command=lambda: change_Q(0), anchor=W)
b1.place(x=170, y=0, width=80, height=50,)
# 一象限按钮
b2 = tk.Button(q_root, text='一象限', bd=0, font=("微软雅黑", 16)
, command=lambda: change_Q(1), anchor=W)
b2.place(x=320, y=0, width=80, height=50,)
# 绘制标记框
q_cv.create_oval(140 - r, 25 - r, 140 + r, 25 + r, fill="white", width=1, outline="black")
q_cv.create_oval(290 - r, 25 - r, 290 + r, 25 + r , fill="white", width=1, outline="black")
# 根据当前的象限选择值来填充标记框
if gl_data.Quadrant == 0:
q_cv.create_oval(140 - rr, 25 - rr, 140 + rr, 25 + rr, fill="black", width=1, outline="black")# 绘制象限
# Q_cv.create_rectangle(80, 80, 270, 270, fill="white") # 第一象限
# Q_cv.create_rectangle(270, 80, 500, 270, fill="red") # 第二象限
# Q_cv.create_rectangle(80, 270, 270, 480, fill="blue") # 第三象限
# Q_cv.create_rectangle(270, 270, 500, 480, fill="green") # 第四象限
else:
q_cv.create_oval(290 - rr, 25 - rr, 290 + rr, 25 + rr, fill="black", width=1, outline="black")
# if __name__ == '__main__':
# # 象限选择相关界面
# q_root = tk.Tk()
# q_root.geometry("500x550") # 设置窗口的大小和位置
# q_button()
# q_root.mainloop()
# 定义模型为y=ax+b
def model(x, a, b):
return a*x + b
# 定义误差函数error_function()
def error_function(x,y,a, b):
y_pred = model(x, a, b)
error = np.mean((y - y_pred)**2)
return error
# 定义梯度函数gradient()
def gradient(a, b,x,y):
y_pred = model(x, a, b)
gradient_a = 2*np.mean((y_pred - y)*x)
gradient_b = 2*np.mean(y_pred - y)
return gradient_a, gradient_b
if __name__ == '__main__':
# 读取sampledata值
sampledata = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
x = np.array(sampledata)
y = np.array([-2, 1, 0, 1, 2, 3, 4, 5, 6, 8])
# 初始化参数
a = 0
b = 0
learning_rate = 0.01
num_iterations = 1000
# 梯度下降算法
for i in range(num_iterations):
grad_a, grad_b = gradient(a, b,x,y)
a -= learning_rate * grad_a
b -= learning_rate * grad_b
# 输出最终拟合结果
final_error = error_function(x,y,a, b)
# gl_data.X = x # 为二次函数.txt
# gl_data.Y = y
# draw_axis(-100, 100)
# positive_mask = x >= 0.0 # 给样本点分类
# negative_mask = y < 0.0 # 给样本点分类
# positive_colors = ['red' if x >= 0.0 else 'blue' for x in x] # 给样本点分类
# negative_colors = ['green' if x >= 0.0 else 'purple' for x in x] # 给样本点分类
# # 根据样本点类型决定样本点颜色
# plt.scatter(gl_data.X[positive_mask], gl_data.Y[positive_mask], color=np.array(positive_colors)[positive_mask],
# lw=1)
# plt.scatter(gl_data.X[negative_mask], gl_data.Y[negative_mask], color=np.array(negative_colors)[negative_mask],
# lw=1)
# curve_x = np.arange(-1000, 1000) # 按照步长生成的一串数字
# curve_y = [model(i, a, b) for i in curve_x] # 根据x来计算y1值
# plt.plot(curve_x, curve_y, color='blue', label='Fitted Curve') # 绘制拟合曲线
# plt.legend()
# plt.show()
print("拟合函数形式: y = ax + b")
print("系数 a:{:.2f}".format(a))
print("系数 b:{:.2f}".format( b))
print("误差计算方法: 均方误差")
print("最终误差:{:.2f}".format(final_error))