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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# -*- 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))