|
|
|
@ -0,0 +1,343 @@
|
|
|
|
|
# -*- 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))
|