Compare commits

...

2 Commits

@ -0,0 +1,30 @@
-1000.000000 -303.919733
-934.000000 -350.424580
-868.000000 -193.369993
-802.000000 -474.832293
-736.000000 -101.068322
-670.000000 -33.916365
-604.000000 -164.504704
-538.000000 -147.298119
-472.000000 -124.814141
-406.000000 -139.033018
-340.000000 -69.265051
-274.000000 -90.553084
-208.000000 -114.709905
-142.000000 -103.201058
-76.000000 -108.245882
-10.000000 56.710600
56.000000 18.503031
122.000000 185.633626
188.000000 152.615324
254.000000 47.216669
320.000000 256.009421
386.000000 270.790257
452.000000 61.971014
518.000000 121.635726
584.000000 163.906089
650.000000 166.204626
716.000000 315.640621
782.000000 425.649206
848.000000 454.347899
914.000000 289.943295

@ -0,0 +1,30 @@
-1000.000000 -2412.037897
-934.000000 -1906.704565
-868.000000 -1515.407287
-802.000000 -1286.984468
-736.000000 -991.348043
-670.000000 -699.579002
-604.000000 -834.074507
-538.000000 -694.557977
-472.000000 -503.237387
-406.000000 -288.033015
-340.000000 -248.449961
-274.000000 -317.763223
-208.000000 -254.540871
-142.000000 -269.952677
-76.000000 -252.274149
-10.000000 -373.987676
56.000000 -129.655207
122.000000 -325.928443
188.000000 -98.240616
254.000000 -325.921235
320.000000 -161.796895
386.000000 96.648543
452.000000 -245.636986
518.000000 190.848311
584.000000 225.026237
650.000000 317.523583
716.000000 772.606080
782.000000 645.906241
848.000000 1091.495759
914.000000 1225.588183

@ -0,0 +1,30 @@
-1000.000000 1318.415137
-934.000000 971.366429
-868.000000 950.320306
-802.000000 635.325663
-736.000000 774.823634
-670.000000 659.035975
-604.000000 449.284057
-538.000000 262.096521
-472.000000 141.521962
-406.000000 65.441983
-340.000000 162.273141
-274.000000 209.914028
-208.000000 62.504373
-142.000000 -160.439640
-76.000000 -201.140961
-10.000000 -178.764894
56.000000 -194.056288
122.000000 -221.386689
188.000000 -236.245098
254.000000 -317.086262
320.000000 -385.718988
386.000000 -198.736083
452.000000 -256.246461
518.000000 -226.361577
584.000000 -329.214396
650.000000 98.251218
716.000000 -132.314476
782.000000 62.741428
848.000000 120.654860
914.000000 356.397702

@ -0,0 +1,30 @@
-1000.000000 6580.374854
-934.000000 5230.299130
-868.000000 4064.603309
-802.000000 2824.002023
-736.000000 2151.187862
-670.000000 1341.067791
-604.000000 997.401541
-538.000000 512.994167
-472.000000 103.881466
-406.000000 85.927912
-340.000000 -256.482213
-274.000000 -97.197686
-208.000000 -264.665117
-142.000000 -237.702195
-76.000000 -151.105677
-10.000000 -130.269796
56.000000 -102.814456
122.000000 -62.662181
188.000000 -357.518806
254.000000 -149.197016
320.000000 -350.461131
386.000000 -264.914106
452.000000 -94.032078
518.000000 -188.344844
584.000000 -60.854287
650.000000 85.277762
716.000000 413.822510
782.000000 695.033449
848.000000 1169.069640
914.000000 1762.153163

@ -0,0 +1,16 @@
1.000000 -14.349565
67.000000 321.611473
133.000000 375.298867
199.000000 386.511032
265.000000 408.069269
331.000000 423.359694
397.000000 435.982565
463.000000 458.199244
529.000000 451.417416
595.000000 471.376855
661.000000 484.015127
727.000000 489.640132
793.000000 500.047206
859.000000 499.698564
925.000000 492.870266
991.000000 509.779156

@ -0,0 +1,30 @@
-1000.000000 282.188733
-934.000000 -121.080276
-868.000000 89.565718
-802.000000 -36.875112
-736.000000 -2.179209
-670.000000 -33.756961
-604.000000 -199.536348
-538.000000 -50.378169
-472.000000 7.288867
-406.000000 197.918480
-340.000000 18.543165
-274.000000 -80.038062
-208.000000 -0.092604
-142.000000 24.234519
-76.000000 112.628196
-10.000000 57.868872
56.000000 -75.900181
122.000000 53.411782
188.000000 14.463053
254.000000 -157.854773
320.000000 3.419914
386.000000 -95.442953
452.000000 -511.818439
518.000000 -785.633833
584.000000 -1377.367723
650.000000 -2606.119973
716.000000 -5115.078474
782.000000 -9770.399635
848.000000 -19298.079697
914.000000 -37316.681269

@ -0,0 +1,133 @@
import numpy as np
import matplotlib.pyplot as plt
def generate_dataset(func_type, coeff, n_samples=100, noise_level=0.0):
"""
Generate a dataset based on a mathematical function.
Parameters:
func_type (str): Type of function ('linear', 'quadratic', 'cubic', 'quartic', 'exponential', 'logarithmic').
coeff (list): Coefficients of the function.
n_samples (int): Number of samples to generate.
noise_level (float): Standard deviation of Gaussian noise added to the data.
Returns:
np.ndarray: Generated dataset.
"""
# Generate x values
x_values = np.linspace(-1000, 1000, n_samples)
# Define the functions
functions = {
'linear': lambda x: coeff[0] + coeff[1] * x,
'quadratic': lambda x: coeff[0] + coeff[1] * x + coeff[2] * x**2,
'cubic': lambda x: coeff[0] + coeff[1] * x + coeff[2] * x**2 + coeff[3] * x**3,
'quartic': lambda x: coeff[0] + coeff[1] * x + coeff[2] * x**2 + coeff[3] * x**3 + coeff[4] * x**4,
'exponential': lambda x: coeff[0] * np.exp(coeff[1] * x),
'logarithmic': lambda x: coeff[0] + coeff[1] * np.log(np.abs(x) + 1) # Avoid log(0)
}
# Generate y values based on the selected function
y_values = functions[func_type](x_values)
# Add noise
noise = np.random.normal(0, noise_level, n_samples)
y_values_noisy = y_values + noise
# Combine x and y values
dataset = np.vstack((x_values, y_values_noisy)).T
return dataset
def plot_dataset(dataset, func_type, coeff):
"""
Plot the generated dataset.
Parameters:
dataset (np.ndarray): Generated dataset.
func_type (str): Type of function used to generate the dataset.
coeff (list): Coefficients of the function.
"""
x_values = dataset[:, 0]
y_values = dataset[:, 1]
# Plotting the dataset
plt.figure(figsize=(10, 6))
plt.scatter(x_values, y_values, color='blue', label='Generated Data')
# Plot the original function without noise for comparison
if func_type == 'linear':
y_original = coeff[0] + coeff[1] * x_values
elif func_type == 'quadratic':
y_original = coeff[0] + coeff[1] * x_values + coeff[2] * x_values**2
elif func_type == 'cubic':
y_original = coeff[0] + coeff[1] * x_values + coeff[2] * x_values**2 + coeff[3] * x_values**3
elif func_type == 'quartic':
y_original = coeff[0] + coeff[1] * x_values + coeff[2] * x_values**2 + coeff[3] * x_values**3 + coeff[4] * x_values**4
elif func_type == 'exponential':
y_original = coeff[0] * np.exp(coeff[1] * x_values)
elif func_type == 'logarithmic':
y_original = coeff[0] + coeff[1] * np.log(np.abs(x_values) + 1)
plt.plot(x_values, y_original, color='red', label='Original Function')
plt.title(f'{func_type.capitalize()} Function Dataset Visualization')
plt.xlabel('X Values')
plt.ylabel('Y Values')
plt.legend()
plt.grid(True)
plt.show()
def generate_dataset2(func_type, coeff, x_range=(-1000, 1000), n_samples=100, noise_level=0.0):
"""
Generate a dataset based on a mathematical function with a specified x range.
Parameters:
func_type (str): Type of function ('linear', 'quadratic', 'cubic', 'quartic', 'exponential', 'logarithmic').
coeff (list): Coefficients of the function.
x_range (tuple): The range of x values (min, max).
n_samples (int): Number of samples to generate.
noise_level (float): Standard deviation of Gaussian noise added to the data.
Returns:
np.ndarray: Generated dataset.
"""
# Generate x values within the specified range
x_values = np.linspace(x_range[0], x_range[1], n_samples)
# Define the functions
functions = {
'linear': lambda x: coeff[0] + coeff[1] * x,
'quadratic': lambda x: coeff[0] + coeff[1] * x + coeff[2] * x**2,
'cubic': lambda x: coeff[0] + coeff[1] * x + coeff[2] * x**2 + coeff[3] * x**3,
'quartic': lambda x: coeff[0] + coeff[1] * x + coeff[2] * x**2 + coeff[3] * x**3 + coeff[4] * x**4,
'exponential': lambda x: coeff[0] * np.exp(coeff[1] * x),
'logarithmic': lambda x: coeff[0] + coeff[1] * np.log(np.abs(x) + 1) # Avoid log(0)
}
# Generate y values based on the selected function
y_values = functions[func_type](x_values)
# Clip y values to stay within the specified range
y_values = np.clip(y_values, x_range[0], x_range[1])
# Add noise
noise = np.random.normal(0, noise_level, n_samples)
y_values_noisy = y_values + noise
# Clip noisy y values to stay within the specified range
y_values_noisy = np.clip(y_values_noisy, x_range[0], x_range[1])
# Combine x and y values
dataset = np.vstack((x_values, y_values_noisy)).T
return dataset
# Example usage
dataset = generate_dataset('quadratic', [1, 2, 3], n_samples=10, noise_level=10)
print(dataset)
# Visualize the dataset
dataset = generate_dataset('quadratic', [1, 2, 3], n_samples=10, noise_level=10)
plot_dataset(dataset, 'quadratic', [1, 2, 3])

@ -0,0 +1,126 @@
import re
'''
对给定的代数表达式字符串进行处理包括格式化和转换最终返回两个值
表达式中的参数列表
经过转换后的表达式字符串
'''
def convert_log(expression):
# 匹配log(x,b)的正则表达式
pattern = r'log\((\w+),(\w+)\)'
match = re.match(pattern, expression)
if match:
x = match.group(1)
b = match.group(2)
# 构造新表达式
new_expression = f'(np.log({x}) + 1e-5) / (np.log({b}) + 1e-5)'
return new_expression
else:
return None
# 将表达式中的e^x转换为numpy库函数的形式np.exp(x)。
def convert_e(expression):
new_expression = 'np.exp'+expression[2:]
return new_expression
# 将三角函数sin, cos, tan等转换为使用numpy库函数的形式例如sin(x)转换为np.sin(x)。
def convert_trigonometric(expression):
# 构造新表达式
new_expression = 'np.'+expression
return new_expression
# 将指数形式x^y转换为numpy库函数的形式np.power(x, y)
def convert_x(expression):
# 匹配log(x,b)的正则表达式
pattern = r'(\w+)\^(\w+)'
match = re.match(pattern, expression)
if match:
base = match.group(1)
exponent = match.group(2)
# 构造新表达式
new_expression = f'np.power({base}, {exponent})'
return new_expression
else:
return None
# 移除表达式括号内的空格
def remove_inner_spaces(expression):
# 匹配括号内的空格的正则表达式
pattern = r'\((.*?)\)'
# 替换匹配到的括号内的空格
new_expression = re.sub(pattern, lambda match: '(' + match.group(1).replace(' ', '') + ')', expression)
return new_expression
# 在表达式中的运算符前后添加空格,以便后续操作。
def add_spaces(expression):
# 匹配运算符的正则表达式
pattern = r'([+\-*/])'
# 替换匹配到的运算符
new_expression = re.sub(pattern, r' \1 ', expression)
return new_expression
# 查找表达式中x前面直接跟着字母但没有乘号*的位置,并修正
def find_letter_index(string):
pattern = r'([a-zA-Z])x\b'
matches = re.findall(pattern, string)
# print(matches)
letter_indices = []
for i in range(len(string)):
if string[i] in matches:
if string[i+1] == 'x':
letter_indices.append(i)
return letter_indices
# 主要目的是处理一个代数表达式字符串,对其进行格式化和转换,然后返回两个值:一个是表达式中的参数列表,另一个是经过转换的表达式字符串。
def expression_output(expression):
# 示例使用
modified_list = find_letter_index(expression) # 将x前没有*的加上
index = 1
for i in modified_list:
expression = expression[0:index+i]+'*'+expression[index+i:]
index += 1
# print(expression)
expression = add_spaces(expression)
new_expression = remove_inner_spaces(expression)
list_expression = new_expression.split(' ')
conforms = ['e^', 'log', 'sin', 'cos', 'tan', '^']
new_list = []
for expres in list_expression:
new_list.append(expres)
for i in range(6):
if conforms[i] in expres:
index = list_expression.index(expres)
if i == 0:
list_expression[index] = convert_e(expres)
elif i == 1:
list_expression[index] = convert_log(expres)
elif i == 5:
list_expression[index] = convert_x(expres)
else:
list_expression[index] = convert_trigonometric(expres)
new_list[-1] = new_list[-1].replace(conforms[i], "")
break
new_list = [char for item in new_list for char in item if char.isalpha()]
parameter = 'x,'
for item in new_list:
if item not in parameter and item != 'x':
parameter = parameter+item+','
for item in new_list:
if item not in parameter:
parameter = parameter+item+','
str_expression = ''
for item in list_expression:
str_expression = str_expression + item
if len(parameter[:-1]) > 1:
return parameter[:-1], str_expression
else:
return None, None

@ -0,0 +1,49 @@
import numpy as np
from scipy.optimize import approx_fprime
import matplotlib.pyplot as plt
# 调整梯度下降法以动态适应参数数量
def gradient_descent_adjusted(func, sx, sy, learning_rate=0.001, iterations=5000):
# 动态确定func需要的参数数量减去sx
params_count = func.__code__.co_argcount - 1
# 基于参数数量初始化theta
theta = np.random.randn(params_count) * 0.01
# 定义损失函数和梯度的计算
def loss_grad(theta):
pred = func(sx, *theta)
error = pred - sy
loss = np.mean(error ** 2)
grad = approx_fprime(theta, lambda t: np.mean((func(sx, *t) - sy) ** 2), epsilon=1e-6)
return loss, grad
# 梯度下降循环
for _ in range(iterations):
_, grad = loss_grad(theta)
theta -= learning_rate * grad
return theta
# 示例函数:简单的线性函数
def example_func(sx,c, a, b):
return c*sx**2 + a * sx + b
# 生成模拟数据
np.random.seed(0)
sx = np.linspace(-1, 1, 100)
sy = 0.1*sx**2+ 3 * sx + 2 + np.random.randn(100) * 0.5
# 使用调整后的梯度下降法拟合模型
params_adjusted = gradient_descent_adjusted(example_func, sx, sy)
# 绘制调整后的结果
plt.scatter(sx, sy, label="Data Points")
plt.plot(sx, example_func(sx, *params_adjusted), color="red", label="Fitted Line Adjusted")
plt.legend()
plt.xlabel("sx")
plt.ylabel("sy")
plt.title("Fitting with Adjusted Gradient Descent")
plt.show()

@ -0,0 +1,104 @@
import numpy as np
import matplotlib.pyplot as plt
from X1 import random_points, compute_curveData
from X2 import draw_axis
# # (1) 定义x和y坐标数据
# x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# y = np.array([1, 2, 3, 5, 8, 13, 21, 34, 55, 89])
#
# # (2) 定义多项式阶数m这里以3阶多项式为例
# m = 2
#
# # 使用x的幂次来构造A矩阵
# A = np.vander(x, m + 1)
#
# # (3) 计算拟合系数theta使用最小二乘法的正规方程
# theta = np.linalg.inv(A.T @ A) @ A.T @ y
# print(theta)
# # (4) 使用theta和x的幂次计算拟合曲线
# x_fit = np.linspace(min(x), max(x), 100)
# A_fit = np.vander(x_fit, m + 1)
# y_fit = A_fit @ theta
#
# # 创建图形对象并绘制拟合曲线和样本点
# fig, ax = plt.subplots()
# ax.plot(x_fit, y_fit, label=f'Polynomial Fit of degree {m}')
# ax.scatter(x, y, color='red', label='Sample Points')
# ax.set_xlabel('X')
# ax.set_ylabel('Y')
# ax.legend()
# plt.show()
# 编程4.5-----------------------------------------
# m次多项式的最小二乘法
def least_square_method(m, sampleData):
x = sampleData[:,0]
y = sampleData[:,1]
# (2) 多项式阶数m这里以3阶多项式为例
# 使用x的幂次来构造A矩阵
A = np.vander(x, m + 1)
# (3) 计算拟合系数theta使用最小二乘法的正规方程
theta = np.linalg.inv(A.T @ A) @ A.T @ y
# (4) 使用theta和x的幂次计算拟合曲线
x_fit = np.linspace(min(x), max(x), 100)
A_fit = np.vander(x_fit, m + 1)
y_fit = A_fit @ theta
plt.plot(x_fit, y_fit)
plt.show()
# 计算残差平方和
residuals = y - A @ theta
residuals_squared_sum = residuals.T @ residuals
# 计算均方误差
degrees_of_freedom = len(y) - (m + 1)
mean_squared_error = residuals_squared_sum / degrees_of_freedom
# 计算协方差矩阵
covariance_matrix = np.linalg.inv(A.T @ A) * mean_squared_error
return theta, covariance_matrix
def curve_draw_line(curveData,sampleData):
x_fit = curveData[:,0]
y_fit = curveData[:,1]
x = sampleData[:,0]
y = sampleData[:,1]
# 创建图形对象并绘制拟合曲线和样本点
ax = draw_axis(0, 1000,step=250)
ax.plot(x_fit, y_fit, label=f'FitCurve')
ax.scatter(x, y, color='red', label='SampleData')
# ax.set_xlabel('X')
# ax.set_ylabel('Y')
plt.legend()
plt.show()
if __name__ == '__main__':
LimitNum = 1000
sampleData = random_points(20, 0, 1000)
# 这里为了便于观察使用设计好的数据
# x = np.array([0, 150, 250, 350, 450, 550, 650, 700, 750, 850])
# y = np.array([6, 30, 90, 160, 220, 340, 490, 620, 730, 1000])
# x = np.array([10, 100, 200, 300, 400, 500, 600, 700, 800, 900])
# y = np.array([10, 20, 30, 50, 80, 130, 210, 340, 550, 890])
# x = np.array([0, 10, 20, 30, 40, 50, 60, 70, 80, 90])
# y = np.array([1, 2, 1, 5, 8, 13, 21, 34, 55, 89])
x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
y = np.array([1, 2, 1, 5, 8, 13, 21, 34, 55, 89])
sampleData = np.array(list(zip(x, y))) # 将两个一维数组拼接成二维数组
m = 3
theta, covariance_matrix = least_square_method(m, sampleData)
# print(theta)
curveData = compute_curveData(LimitNum, 1, theta, m, )
# print("curveData",curveData)
curve_draw_line(curveData,sampleData)
# 编程4.5 END-----------------------------------------

@ -0,0 +1,77 @@
import numpy as np
import matplotlib.pyplot as plt
def gradient_descent_poly_fit(sampleData, degree, learning_rate=0.001, iterations=50000):
def error_function(y_pred, y): # 定义误差函数error_function()
return y_pred - y
def gradient(degree,error,x_normalized,sampleNum,learning_rate): # 定义梯度函数gradient()
# 对每个参数计算梯度
for i in range(degree + 1):
# 计算损失函数对参数的偏导数(梯度)
gradient = np.dot(error, x_normalized**i) * 2 / sampleNum
# 梯度下降更新参数
theta[i] -= learning_rate * gradient
return theta
x = sampleData[:,0]
y = sampleData[:,1]
# 初始化参数多项式系数为0
theta = np.zeros(degree + 1)
sampleNum = len(x) # 样本数量
# 归一化x以改善数值稳定性
x_normalized = (x - x.mean()) / x.std()
# 迭代梯度下降
for _ in range(iterations):
# 通过当前参数计算多项式的值
y_pred = np.polyval(theta[::-1], x_normalized)
# 计算预测值与真实值之间的误差
error = error_function(y_pred, y)
# 计算梯度并更新theta
theta = gradient(degree,error,x_normalized,sampleNum,learning_rate)
return theta, x_normalized
# 设置一个较小的学习率和较多的迭代次数
learning_rate = 0.001
iterations = 50000
degree = 4
x = np.array([0, 100, 200, 300, 400, 500, 600, 700, 800, 900])
y = np.array([10, 20, 10, 50, 80, 130, 210, 340, 550, 890])
sampleData = np.array(list(zip(x, y)))
# 运行梯度下降算法
theta, x_normalized = gradient_descent_poly_fit(sampleData, degree, learning_rate, iterations)
# 用拟合的参数计算多项式的值
x_fit_normalized = np.linspace(x_normalized.min(), x_normalized.max(), 100)
y_fit = np.polyval(theta[::-1], x_fit_normalized)
# 反归一化x_fit
x_fit = x_fit_normalized * x.std() + x.mean()
# 绘制原始数据点和拟合的多项式
plt.scatter(x, y, color='red', label='Sample Data')
plt.plot(x_fit, y_fit, label='Polynomial Fit')
plt.legend()
plt.show()
# 输出拟合参数
print(theta)
# if __name__ == '__main__':
# LimitNum = 1000
# sampleData = random_points(20,0, 1000)
# # 这里为了便于观察使用设计好的数据
# # x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# # y = np.array([1, 2, 1, 5, 8, 13, 21, 34, 55, 89])
# # sampleData = np.array(list(zip(x, y))) # 将两个一维数组拼接成二维数组
# m = 3
# theta, covariance_matrix = least_square_method(m, sampleData)
# # print(theta)
# curveData = compute_curveData(0,1000,1,theta,m)
# # print("curveData",curveData)
# draw_dots_and_line(curveData,sampleData,0,1000)

@ -0,0 +1,47 @@
import numpy as np
import matplotlib.pyplot as plt
# 示例函数定义,比如二次多项式
def func(x, theta):
# 二次多项式: theta[0] + theta[1]*x + theta[2]*x^2
return theta[0] + theta[1]*x + theta[2]*x**2
# 修改后的最小二乘法函数
def least_square_method(func, m, sampleData):
x = sampleData[:,0]
y = sampleData[:,1]
# 构造 A 矩阵,使用 func 函数
A = np.array([func(xi, np.arange(m + 1)) for xi in x])
print(A)
# (2) 多项式阶数m这里以3阶多项式为例
# 使用x的幂次来构造A矩阵
A = np.vander(x, m + 1)
# 计算拟合系数theta
theta = np.linalg.inv(A.T @ A) @ A.T @ y
# 其他步骤保持不变...
plt.scatter(x, y, color='red')
x_fit = np.linspace(min(x), max(x), 100)
y_fit = np.array([func(xi, theta) for xi in x_fit])
plt.plot(x_fit, y_fit)
plt.show()
# 计算残差平方和等...
residuals = y - np.dot(A, theta)
residuals_squared_sum = np.dot(residuals.T, residuals)
degrees_of_freedom = len(y) - (m + 1)
mean_squared_error = residuals_squared_sum / degrees_of_freedom
covariance_matrix = np.linalg.inv(A.T @ A) * mean_squared_error
return theta, covariance_matrix
# 示例用法
if __name__ == '__main__':
sampleData = np.array([[0, 1], [1, 2], [2, 1], [3, 5], [4, 8], [5, 13], [6, 21], [7, 34], [8, 55], [9, 89]])
m = 2 # 为二次多项式
theta, covariance_matrix = least_square_method(func, m, sampleData)
print("Theta:", theta)
print("Covariance Matrix:", covariance_matrix)

@ -0,0 +1,57 @@
import data as gl_data
import numpy as np
import matplotlib.pyplot as plt
def gradient_descent_poly_fit(x, y, degree, learning_rate, iterations):
# 初始化参数多项式系数为0
theta = np.zeros(degree + 1)
m = len(x) # 样本数量
# 归一化x以改善数值稳定性
x_normalized = (x - x.mean()) / x.std()
# 迭代梯度下降
for _ in range(iterations):
# 通过当前参数计算多项式的值
y_pred = np.polyval(theta[::-1], x_normalized)
# 计算预测值与真实值之间的误差
error = y_pred - y
# 对每个参数计算梯度
for i in range(degree + 1):
# 计算损失函数对参数的偏导数(梯度)
gradient = np.dot(error, x_normalized**i) * 2 / m
# 梯度下降更新参数
theta[i] -= learning_rate * gradient
return theta, x_normalized
# 设置一个较小的学习率和较多的迭代次数
learning_rate = 0.001
iterations = 50000
# x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
x = np.array([0, 10, 20, 30, 40, 50, 60, 70, 80, 90])
y = np.array([1, 2, 1, 5, 8, 13, 21, 34, 55, 89])
degree = 2
# 运行梯度下降算法
theta, x_normalized = gradient_descent_poly_fit(x, y, degree, learning_rate, iterations)
# 用拟合的参数计算多项式的值
x_fit_normalized = np.linspace(x_normalized.min(), x_normalized.max(), 100)
y_fit = np.polyval(theta[::-1], x_fit_normalized)
# 反归一化x_fit
x_fit = x_fit_normalized * x.std() + x.mean()
# 绘制原始数据点和拟合的多项式
plt.scatter(x, y, color='red', label='Sample Data')
plt.plot(x_fit, y_fit, label='Polynomial Fit')
plt.legend()
plt.show()
# 输出拟合参数
print(theta)

@ -0,0 +1,69 @@
import numpy as np
import matplotlib.pyplot as plt
def least_square_method(m, sampleData):
x = sampleData[:, 0]
y = sampleData[:, 1]
# 标准化x
x_mean = x.mean()
x_std = x.std()
x_normalized = (x - x_mean) / x_std
# 使用标准化的x构造A矩阵
A = np.vander(x_normalized, m + 1, increasing=True)
# 计算拟合系数theta使用最小二乘法的正规方程
theta = np.linalg.inv(A.T @ A) @ A.T @ y
# 计算残差平方和和其他统计量
residuals = y - A @ theta
residuals_squared_sum = residuals.T @ residuals
degrees_of_freedom = len(y) - (m + 1)
mean_squared_error = residuals_squared_sum / degrees_of_freedom
covariance_matrix = np.linalg.inv(A.T @ A) * mean_squared_error
return theta, covariance_matrix, x_mean, x_std
def compute_curveData(low, high, step, theta, m, x_mean, x_std):
x_fit = np.arange(low, high, step)
# 将x_fit标准化
x_fit_normalized = (x_fit - x_mean) / x_std
A_fit = np.vander(x_fit_normalized, m + 1, increasing=True)
y_fit = A_fit @ theta
return np.column_stack((x_fit, y_fit))
def draw_dots_and_line(curveData, sampleData, low, high):
x_fit = curveData[:, 0]
y_fit = curveData[:, 1]
x = sampleData[:, 0]
y = sampleData[:, 1]
plt.plot(x_fit, y_fit, label='FitCurve')
plt.scatter(x, y, color='red', label='SampleData')
plt.xlim(low, high)
plt.legend()
plt.show()
def random_points(n, low, high):
np.random.seed(0) # For reproducibility
# x = np.random.uniform(low, high, n)
# y = np.random.uniform(low, high, n) # This is just an example
x = np.array([0, 100, 200, 300, 400, 500, 600, 700, 800, 900])
y = np.array([10, 20, 10, 50, 80, 130, 210, 340, 550, 890])
return np.column_stack((x, y))
if __name__ == '__main__':
sampleData = random_points(20, 0, 1000)
print(len(sampleData))
m = 3
theta, covariance_matrix, x_mean, x_std = least_square_method(m, sampleData)
curveData = compute_curveData(0, 1000, 1, theta, m, x_mean, x_std)
draw_dots_and_line(curveData, sampleData, 0, 1000)

83
X1.py

@ -0,0 +1,83 @@
import random
import numpy as np
import data as gl_data
def linear_function(coefficient, x): # 构造一次函数y = a * X + b
return coefficient[0] * x + coefficient[1]
def quadratic_function(coefficient, x): # 构造二次函数y = a * X^2 + b * X + c
return coefficient[0] * x ** 2 + coefficient[1] * x + coefficient[2]
def qubic_function(coefficient, x): # 构造三次函数y = a* X^3 + b * X^2 + c * X + d
return coefficient[0] * x ** 3 + coefficient[1] * x ** 2 + coefficient[2] * x + coefficient[3]
def quartic_function(coefficient, x): # 构造四次函数
return coefficient[0] * x ** 4 + coefficient[1] * x ** 3 + coefficient[2] * x ** 2 + coefficient[3] * x + \
coefficient[4]
# 编程4.1 -----------------------------------------
def random_points(sampleNum, Low, High):
sx, sy=[], []
for i in range(sampleNum):
sx.append(random.uniform(Low, High)) # 生成随机浮点数
sy.append(random.uniform(Low, High))
sx, sy = np.array(sx), np.array(sy) # 列表转数组
gl_data.SampleData = np.array(list(zip(sx, sy))) # 拼接成二维数组并存入全局变量
return gl_data.SampleData
# if __name__ == '__main__':
# sampleData = random_points(20, 0, 1000)
# print(sampleData )
# 编程4.1 END-----------------------------------------
# 编程4.2 -----------------------------------------
def compute_curveData(Low, High, step, coefficient, m): # coefficient代表二次函数系数
x_values = np.arange(Low, High, step)
if m == 1:
y_values = linear_function(coefficient, x_values)
if m == 2:
y_values = quadratic_function(coefficient, x_values) # 调用quadratic_function(x)函数得到y值
if m == 3:
y_values = qubic_function(coefficient, x_values)
if m == 4:
y_values = quartic_function(coefficient, x_values)
gl_data.CurveData = np.column_stack((x_values, y_values)) # 将x,y堆叠成二维数组
return gl_data.CurveData
# if __name__ == '__main__':
# coefficient = [1, 2, 3]
# curveData = compute_curveData(gl_data.LOW, gl_data.HIGH, 1, coefficient,2)
# print(curveData)
# 由于出现了数据稳定性的问题,因此在这里多了一个需要进行标准化处理的步骤
def compute_curveData2(low, high, step, theta, m, x_mean, x_std):
x_fit = np.arange(low, high, step)
# 将x_fit标准化
x_fit_normalized = (x_fit - x_mean) / x_std
A_fit = np.vander(x_fit_normalized, m + 1, increasing=True)
y_fit = A_fit @ theta
gl_data.CurveData = np.column_stack((x_fit, y_fit))
return gl_data.CurveData
# 在X5中由于拓展了函数因此修改
def compute_curveData_X5(func, popt):
x_values = np.arange(gl_data.LOW, gl_data.HIGH, 1)
y_values = func(x_values, *popt)
gl_data.CurveData = np.column_stack((x_values, y_values))
return gl_data.CurveData
# 进行标准化的X5函数
def compute_curveData_X5_2(func, popt, sampleData):
sx, sy = sampleData[:, 0], sampleData[:, 1]
x_values = np.arange(gl_data.LOW, gl_data.HIGH, 1)
x_values_normalized = (x_values - np.mean(sx)) / np.std(sx)
y_values = func(x_values_normalized, *popt)
gl_data.CurveData = np.column_stack((x_values, y_values))
return gl_data.CurveData
# 编程4.2 END-----------------------------------------

333
X2.py

@ -0,0 +1,333 @@
import inspect
from tkinter import *
import tkinter as tk
import mpl_toolkits.axisartist as axisartist
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from scipy.optimize import approx_fprime
import data as gl_data
import numpy as np
from X1 import *
#------------------借用setphoto
set_img1 = None
set_img2 = None
# 这里有个将图像输出到主界面的函数
def set_phtot(index1):
global set_img1,set_img2
# 显示图像
Canvas2 = gl_data.Canvas2
if index1 == 1:
if set_img2 != None:
Canvas2.delete(set_img2)
gl_data.Img1=PhotoImage(file=r"dot.png")
# print(gl_data.Img1)
gl_data.Img1 = gl_data.Img1.zoom(2, 2)
set_img1=Canvas2.create_image(2, 10, image=gl_data.Img1, anchor=NW)
# Canvas2.itemconfigure(set_img1,int(420 * gl_data.MAGNIDICATION), int(300 * gl_data.MAGNIDICATION))
Canvas2.update()
print("已输出数据点")
elif index1 == 2:
if set_img1 != None:
Canvas2.delete(set_img1)
gl_data.Img2=PhotoImage(file=r"line.png")
# print(gl_data.Img2)
gl_data.Img2 = gl_data.Img2.zoom(2, 2)
set_img2=Canvas2.create_image(2, 10, image=gl_data.Img2, anchor=NW)
# Canvas2.itemconfigure(set_img2, 0,0,int(420*gl_data.MAGNIDICATION), int(300*gl_data.MAGNIDICATION))
Canvas2.update()
print("已输出数据点和曲线")
def window():
root_window = Tk()
root_window.title('函数拟合')
root_window.geometry('900x600') # 设置窗口大小:宽x高,注,此处不能为 "*",必须使用 "x"
# 设置主窗口的背景颜色,颜色值可以是英文单词或者颜色值的16进制数,除此之外还可以使用Tk内置的颜色常量
root_window["background"] = "white"
root_window.resizable(0, 0) # 防止用户调整尺寸
label1 = tk.Label(root_window, text="样本数据\n集文件", font=('Times', 8), bg="white",
width=13, height=3, # 设置标签内容区大小
padx=0, pady=0, borderwidth=0, )
label1.place(x=10, y=4) # 设置填充区距离、边框宽度和其样式(凹陷式)
label3 = tk.Label(root_window, text="", font=('Times', 8), bg="white", fg="black",
width=39, height=2, padx=0, pady=0, borderwidth=0, relief="ridge", highlightcolor="blue")
label3.place(x=122, y=10)
return root_window
# if __name__ == '__main__':
# root_window = window()
# root_window.mainloop()
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轴的刻度范围设置
# 把x轴和y轴的刻度范围设置
ax.set_xlim(low, high)
ax.set_ylim(low, high)
ax.set_xticks(np.arange(low, high + 5, step)) # 把x轴的刻度间隔设置
ax.set_yticks(np.arange(low, high + 5, step)) # 把y轴的刻度间隔设置
# plt.show()
return ax
# if __name__ == '__main__':
# draw_axis(gl_data.LOW, gl_data.HIGH)
def selfdata_show(sampleData, low, high):
x = sampleData[:,0]
y = sampleData[:,1]
ax = draw_axis(low, high) # 绘制x、y轴
ax.scatter(x, y, c='red') # 绘制样本数据点
# plt.show() #显示图片
plt.savefig(r"dot.png", facecolor='w', bbox_inches='tight') # 保存为png文件
plt.clf()
set_phtot(1) # 后续函数将图像显示在主界面中
# if __name__ == '__main__':
# sampleData = random_points(20, 0, 1000) # 生成样本点
# selfdata_show(sampleData, 0, 1000) # 绘制样本数据点
# 编程4.5-----------------------------------------
# m次多项式的最小二乘法
# 这里是没有对数据进行了标准化处理的
def least_square_method_UnNormalized(m, sampleData):
x = sampleData[:, 0]
y = sampleData[:, 1]
# 使用标准化的x构造A矩阵
A = np.vander(x, m + 1, increasing=True)
# 计算拟合系数theta使用最小二乘法的正规方程
theta = np.linalg.inv(A.T @ A) @ A.T @ y
# 计算残差平方和和其他统计量
residuals = y - A @ theta
residuals_squared_sum = residuals.T @ residuals
degrees_of_freedom = len(y) - (m + 1)
mean_squared_error = residuals_squared_sum / degrees_of_freedom
covariance_matrix = np.linalg.inv(A.T @ A) * mean_squared_error
return theta, covariance_matrix
# 这里是对数据进行了标准化处理的
def least_square_method(m, sampleData):
x = sampleData[:, 0]
y = sampleData[:, 1]
# 标准化x
x_mean = x.mean()
x_std = x.std()
x_normalized = (x - x_mean) / x_std
# 使用标准化的x构造A矩阵
A = np.vander(x_normalized, m + 1, increasing=True)
# 计算拟合系数theta使用最小二乘法的正规方程
theta = np.linalg.inv(A.T @ A) @ A.T @ y
# 计算残差平方和和其他统计量
residuals = y - A @ theta
residuals_squared_sum = residuals.T @ residuals
degrees_of_freedom = len(y) - (m + 1)
mean_squared_error = residuals_squared_sum / degrees_of_freedom
covariance_matrix = np.linalg.inv(A.T @ A) * mean_squared_error
return theta, covariance_matrix
# def curve_draw_line(curveData,sampleData):
# x_fit = curveData[:,0]
# y_fit = curveData[:,1]
# x = sampleData[:,0]
# y = sampleData[:,1]
# # 创建图形对象并绘制拟合曲线和样本点
# ax = draw_axis(0, 1000,step=250)
# ax.plot(x_fit, y_fit, label=f'FitCurve')
# ax.scatter(x, y, color='red', label='SampleData')
# # ax.set_xlabel('X')
# # ax.set_ylabel('Y')
# plt.legend()
# plt.show()
def draw_dots_and_line(curveData, sampleData, low,high):
x_fit, y_fit = curveData[:, 0], curveData[:, 1]
x, y = sampleData[:, 0], sampleData[:, 1]
# 创建图形对象并绘制拟合曲线和样本点
ax = draw_axis(low,high,step=250)
ax.plot(x_fit, y_fit, label=f'FitCurve')
ax.scatter(x, y, color='red', label='SampleData')
# ax.set_xlabel('X')
# ax.set_ylabel('Y')
plt.legend()
plt.show()
# 重写compute_curveData以适应标准化的需要
def compute_curveData2(low, high, step, theta, m, x_mean, x_std):
x_fit = np.arange(low, high, step)
# 将x_fit标准化
x_fit_normalized = (x_fit - x_mean) / x_std
A_fit = np.vander(x_fit_normalized, m + 1, increasing=True)
y_fit = A_fit @ theta
return np.column_stack((x_fit, y_fit))
if __name__ == '__main__':
# sampleData = random_points(20,0, 1000)
# x = sampleData[:,0]
# y = sampleData[:,1]
# 这里为了便于观察使用设计好的数据
x = np.array([0, 100, 200, 300, 400, 500, 600, 700, 800, 900])
sy = np.array([10, 20, 10, 50, 80, 130, 210, 340, 550, 890])
sampleData = np.array(list(zip(x, sy)))# 将两个一维数组拼接成二维数组
m = 3 # 使用三次函数拟合
theta, covariance_matrix = least_square_method(m, sampleData)
curveData = compute_curveData2(0,1000,1,theta,m, x.mean(), x.std())
draw_dots_and_line(curveData,sampleData,0,1000)
# 编程4.5 END-----------------------------------------
# 编程 4.12 -----------------------------------------
def gradient_descent_method(sampleData, degree, learning_rate=0.001, iterations=50000):
def error_function(y_pred, y): # 定义误差函数error_function()
return y_pred - y
def gradient(degree,error,x_normalized,sampleNum,learning_rate): # 定义梯度函数gradient()
# 对每个参数计算梯度
for i in range(degree + 1):
# 计算损失函数对参数的偏导数(梯度)
gradient = np.dot(error, x_normalized**i) * 2 / sampleNum
# 梯度下降更新参数
theta[i] -= learning_rate * gradient
return theta
sx, sy = sampleData[:, 0], sampleData[:, 1]
# 初始化参数多项式系数为0
theta = np.zeros(degree + 1)
sampleNum = len(sx) # 样本数量
# 归一化x以改善数值稳定性
x_normalized = (sx - sx.mean()) / sx.std()
# 迭代梯度下降
for _ in range(iterations):
# 通过当前参数计算多项式的值
y_pred = np.polyval(theta[::-1], x_normalized)
# 计算预测值与真实值之间的误差
error = error_function(y_pred, sy)
# 计算梯度并更新theta
theta = gradient(degree, error, x_normalized, sampleNum, learning_rate)
# --------------------
# 设计矩阵
A = np.vander(x_normalized, N=degree + 1, increasing=True)
# 计算残差方差
residuals = sy - np.polyval(theta[::-1], x_normalized)
residuals_squared_sum = np.sum(residuals ** 2)
variance = residuals_squared_sum / (sampleNum - (degree + 1))
# 估计协方差矩阵
# 这里使用A的伪逆来近似最小二乘法中的(A^T A)^-1项
covariance_matrix = np.linalg.pinv(A.T @ A) * variance
# --------------------
return theta, covariance_matrix
def compute_curveData2(low, high, step, theta, m, x_mean, x_std):
x_fit = np.arange(low, high, step)
# 将x_fit标准化
x_fit_normalized = (x_fit - x_mean) / x_std
A_fit = np.vander(x_fit_normalized, m + 1, increasing=True)
y_fit = A_fit @ theta
return np.column_stack((x_fit, y_fit))
if __name__ == '__main__':
# sampleData = random_points(20,0, 1000)
# sx, sy = sampleData[:, 0], sampleData[:, 1]
# 这里为了便于观察使用设计好的数据
sx = np.array([0, 100, 200, 300, 400, 500, 600, 700, 800, 900])
sy = np.array([10, 20, 10, 50, 80, 130, 210, 340, 550, 890])
sampleData = np.array(list(zip(sx, sy)))
# 设置一个较小的学习率和较多的迭代次数
learning_rate = 0.001
iterations = 50000
degree = 4
# 梯度下降算法求解
theta, covariance_matrix = gradient_descent_method(sampleData, degree, learning_rate, iterations)
# 计算画图所需要的拟合数据
curveData = compute_curveData2(0, 1000, 1, theta, degree, sx.mean(), sx.std())
# 画拟合结果
draw_dots_and_line(curveData, sampleData, 0, 1000)
# 这里是为了后续fit函数中调用梯度下降法
# 这里将梯度下降法的输入变为了与curve_fit相同由于协方差矩阵只对于多项式函数适用因此这里返回的第二个值为False
# 这里搞好了就是函数的梯度不能够确定因此调用了包approx_fprime
def gradient_descent_method_X5(func, sx, sy, learning_rate=0.001, iterations=5000):
def error_function(y_pred, y): # 定义误差函数error_function()
return (y_pred - y) ** 2
# 定义损失函数和梯度的计算
def loss_grad(theta):
y_pred = func(sx_normalized, *theta)
# 计算预测值与真实值之间的误差
error = error_function(y_pred, sy)
# 调用包来实现对任意函数计算梯度
grad = approx_fprime(theta, lambda t: np.mean((func(sx_normalized, *t) - sy) ** 2), epsilon=1e-6)
return error, grad
# 因为X4和X5中的函数方式不一样X5中不是function类没有self参数因此要处理不同的参数要求
sig = inspect.signature(func) # 获取所有参数的名称
params = [param.name for param in sig.parameters.values()]
# print(params)
# 动态确定func需要的参数数量减去self, sx或者只有sx
if 'self' in params:
params_count = func.__code__.co_argcount - 2
else:
params_count = func.__code__.co_argcount - 1
# print(params_count)
# 基于参数数量初始化theta
theta = np.random.randn(params_count) * 0.01
# 标准化sx
mean_sx = np.mean(sx)
std_sx = np.std(sx)
sx_normalized = (sx - mean_sx) / std_sx
# 梯度下降循环
for _ in range(iterations):
err, grad = loss_grad(theta)
theta -= learning_rate * grad
# 由于不再特定于多项式函数,以下部分相关于残差方差和协方差矩阵的计算需要根据实际情况调整
# 但是实际没有使用到这个矩阵因此返回False
return theta, False

478
X3.py

@ -0,0 +1,478 @@
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 pandas as pd
import tkinter
import sys
import tkinter as tk
from tkinter import filedialog
import re
import function
import data as gl_data
from X1 import *
from X2 import *
mpl.rcParams['font.sans-serif'] = ['SimHei'] # 解决matplotlib中文不显示问题
plt.rcParams['axes.unicode_minus'] = False # 解决matplotlib负数坐标显示问题
# 创建一个二维数组sampleData用于存储样本数据
sampleData = None
global Q_root,F_root
global root_window
global label1,label2,label3
# 编程4.6 -----------------------------------------
# 定义一个处理文件的相关函数
def askfile():
# 选择需要加载的数据文件,并返回文件的路径
filename = tkinter.filedialog.askopenfilename()
if filename != '': # 若选中了一个文件,则对文件进行读取
label3.config(text=filename) # 显示文件路径,其中label3为对应的按钮
read_sample_data(filename) # 将文件读取并存到sampleData中
# print_sample_data(filename)# 将文件读取并逐行输出
selfdata_show(gl_data.SampleData[:,0], gl_data.SampleData[:,1], gl_data.LOW, gl_data.HIGH)
else: # 若未选择文件,则显示为空
label3.config(text='')
def print_sample_data(file_path):#打开对应文件
with open(file_path, 'r') as file:
for line in file: # 逐行读取文件
line = line.strip('\n') # 移除换行符
sx, sy = line.split(' ') # 以空格分割xy
print(f'sx: {float(sx)}, sy: {float(sy)}') # 将sx、sy转换为浮点数并打印
def read_sample_data(file_path):
x, y = [], [] # 初始化xy
with open(file_path, 'r') as file:
for line in file: # 逐行读文件
line = line.strip('\n') # 移除换行符
sx, sy = line.split(' ') # 以空格分割xy
x.append(float(sx)) # 将sx转换为浮点数并加入数组
y.append(float(sy)) # 将sy转换为浮点数并加入数组
# xy数组转为array并赋值给全局变量sampleData
x = np.array(x) # 列表转数组
y = np.array(y)
gl_data.SampleData = np.array(list(zip(x, y)))
# 编程4.6 END-----------------------------------------
# 编程4.7 -----------------------------------------
def generate_and_plot_sample_data(sampleData, Low, High):
sx,sy = sampleData[:, 0],sampleData[:, 1]
draw_axis(Low, High) # 绘制坐标轴
plt.scatter(sx, sy, color='red') # 绘制样本数据点
plt.savefig(r"dot.png", facecolor='w', bbox_inches='tight') # 保存到本地
plt.close() # 清除内存
set_phtot(1) # 显示到主界面 4.7示例时没有编程该函数
# if __name__ == '__main__':
# num_samples = 25 #设置样本点数量
# sampleData = random_points(num_samples, -1000, 1000) # 生成随机样本数据25个
# generate_and_plot_sample_data(sampleData, gl_data.LOW, gl_data.HIGH)
# 编程4.7 END-----------------------------------------
# 编程4.8 -----------------------------------------
def draw_dots_and_line(curveData, sampleData, low, high):
x_fit, y_fit = curveData[:, 0], curveData[:, 1]
x, y = sampleData[:, 0], sampleData[:, 1]
draw_axis(low, high) # 画xy坐标轴
positive_mask = y >= 0.0 # 给样本点分类
negative_mask = y < 0.0 # 给样本点分类
positive_colors = ['red' if xx >= 0.0 else 'blue' for xx in x] # 给样本点分类
negative_colors = ['green' if xx >= 0.0 else 'purple' for xx in x] # 给样本点分类
# 创建图形对象并绘制拟合曲线和样本点
ax = draw_axis(low,high,step=250)
# 根据样本点类型决定样本点颜色
ax.scatter(x[positive_mask], y[positive_mask], color=np.array(positive_colors)[positive_mask], lw=1)
ax.scatter(x[negative_mask], y[negative_mask], color=np.array(negative_colors)[negative_mask], lw=1)
plt.plot(x_fit, y_fit, color='blue', label='Fitted Curve')# 绘制拟合曲线
# plt.savefig(r"dot5.png", facecolor='w') # 保存到本地
# plt.legend()
# plt.show()
# X5修改后展示到主界面中
plt.legend(loc='center left', bbox_to_anchor=(1, 0.9), fontsize=9)
plt.savefig(r"line.png", facecolor='w', bbox_inches='tight')# 将图片保存到本地
plt.close()# 清除内存
set_phtot(2)# 将图片显示到程序中
# if __name__ == '__main__':
# gl_data.SampleData = random_points(25,-1000, 1000)
# # print("gl_data.SampleData",gl_data.SampleData)
# draw_dots_and_line(gl_data.LOW, gl_data.HIGH, gl_data.SampleData)
# if __name__ == '__main__':
# LimitNum = 1000
# # sampleData = random_points(20,0, 1000)
# # x, y = sampleData[:, 0], sampleData[:, 1]
# # 这里为了便于观察使用设计好的数据
# x = np.array([0, 100, 200, 300, 400, 500, 600, 700, 800, 900])
# y = np.array([10, 20, 10, 50, 80, 130, 210, 340, 550, 890])
# sampleData = np.array(list(zip(x, y))) # 将两个一维数组拼接成二维数组
# m = 3 # 使用三次函数拟合
# theta, covariance_matrix = least_square_method(m, sampleData)
# curveData = compute_curveData2(0,1000,1,theta,m, x.mean(), x.std())
# draw_dots_and_line(curveData,sampleData,0,1000)
# 编程4.8 END-----------------------------------------
# 编程4.9 -----------------------------------------
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()
# 编程4.9 END-----------------------------------------
# 编程4.10 -----------------------------------------
def error_func(func, sampleData, theta): # 定义误差函数
sx, sy = sampleData[:, 0], sampleData[:, 1]
y_pred = func(theta, sx) # 使用func函数和参数theta计算预测值
error = np.sum((sy - y_pred) ** 2) # 计算误差平方和
ss_tot = np.sum((sy - np.mean(sy)) ** 2) # 计算总平方和
r_squared = 1 - (error / ss_tot) # 计算决定系数(R^2)
return error, r_squared
# 这里是处理了标准化的error_func
def error_func2(func, sampleData, theta): # 定义误差函数
sx, sy = sampleData[:, 0], sampleData[:, 1]
x_normalized = (sx - sx.mean()) / sx.std()
# 使用func函数和参数theta计算预测值
y_pred = func(theta, x_normalized)
# 计算误差平方和
error = np.sum((sy - y_pred) ** 2)
# 计算总平方和
ss_tot = np.sum((sy - np.mean(sy)) ** 2)
# 计算决定系数(R^2)
r_squared = 1 - (error / ss_tot)
return error, r_squared
# fit函数中修改使用方法为梯度下降法并输出拟合结果
def fit(sampleData, m):
theta, covariance_matrix = least_square_method(m, sampleData) # 计算拟合结果
# 计算拟合误差
if m == 1: func = linear_function
if m == 2: func = quadratic_function # 此处以m=2为例省略其他函数
if m == 3: func = qubic_function
if m == 4: func = quartic_function
error,r_squared = error_func2(func, sampleData, theta)
fit_function_name = func.__name__ # 打印拟合函数的形式、系数、误差和优度
print("拟合函数形式:{}".format(fit_function_name))
print("标准化拟合系数:{}".format(theta))
print("误差:{:.4f}".format(error))
print("拟合优度R^2{:.4f}".format(r_squared))
return theta, covariance_matrix
# if __name__ == '__main__':
# # sampleData = random_points(20,0, 1000)
# # x = sampleData[:,0]
# # y = sampleData[:,1]
# # 这里为了便于观察使用设计好的数据
# x = np.array([0, 100, 200, 300, 400, 500, 600, 700, 800, 900])
# y = np.array([10, 20, 10, 50, 80, 130, 210, 340, 550, 890])
# sampleData = np.array(list(zip(x, y))) # 将两个一维数组拼接成二维数组
# m = 2 # 假设选择使用二次函数拟合
# theta, covariance_matrix = fit(sampleData, m)
# ------fit_X4前提函数-------
# 为了适应扩展的函数,需要根据用户输入的函数类型构造函数
def fitting(letters,result):
code_str = '''
def func({}):
return {}
'''.format(letters,result)
return code_str
# 构造用户自定义的函数
def create_func(code_str):
# 创建一个空的命名空间
namespace = {}
# 使用exec函数执行字符串代码并指定命名空间为locals
exec(code_str, globals(), namespace)
# 返回命名空间中的函数对象
return namespace['func']
# 简化版本的goodness_of_fit
def goodness_of_fit_easy(y_fitting, y_no_fitting):
"""
计算拟合优度R^2
:param y_fitting: List[int] or array[int] 拟合好的y值
:param y_no_fitting: List[int] or array[int] 待拟合y值
:return: 拟合优度R^2
"""
y_mean = sum(y_no_fitting) / len(y_no_fitting)
# 计算SST
sst = sum((y - y_mean) ** 2 for y in y_no_fitting)
# 计算SSE
sse = sum((y_fitting[i] - y_no_fitting[i]) ** 2 for i in range(len(y_fitting)))
# 计算R^2
r_squared = 1 - sse / sst
return r_squared
# ------fit_X4前提函数-------
# 这里是为了后续的fit能够直接用到按钮中而不是BF_Fit写一大堆
def fit_X4(xian_index, sampleData):
sx, sy = sampleData[:, 0], sampleData[:, 1]
cur = function.Fun[xian_index] # 装载正在选择的函数
func = cur.get_fun() # 获取当前函数func
popt, pcov = gradient_descent_method_X5(func, sx, sy) # 用curve_fit来对数据进行拟合
x_normalized = (sx - np.mean(sx)) / np.std(sx) # 标准化处理的x
y_pred = func(x_normalized, *popt) # 获取y的预测值
gl_data.CurveData = compute_curveData_X5_2(func, popt, sampleData) # 计算拟合曲线的数据
rr = goodness_of_fit_easy(y_pred, sy) # 计算本次拟合的R*R值用于表示拟合优度
# 输出拟合后的各个参数值
ans = '\n函数标准化系数F(x) = '
for i in range(cur.variable):
if i == 4:
ans += '\n'
if i != 0:
ans += ', '
ans += chr(ord('a') + i) + '=' + '{:.2e}'.format(popt[i]) # str(round(gl_data.popt[i], 3))
gl_data.Out = '函数形式:' + cur.name + ' '
gl_data.Out += cur.demo
gl_data.Out += ans
gl_data.Out += '\n拟合优度(R\u00b2)' + str(round(rr, 5))
# 编程4.17-----------------------------------------
# 选择
def fit_X4(xian_index, sampleData):
sx, sy = sampleData[:, 0], sampleData[:, 1]
cur = function.Fun[xian_index] # 装载正在选择的函数
func = cur.get_fun() # 获取当前函数func
# params_count = func.__code__.co_argcount - 2 # 计算参数数量
# if params_count <= 3 and len(sampleData) <= 20 : # 当参数和样本点数量较少时
# popt, pcov = least_square_method(func, sx, sy) # 用最小二乘法来对数据进行拟合
# else: # 当参数和样本点数量较多时
# popt, pcov = gradient_descent_method_X5(func, sx, sy) # 用梯度下降法来对数据进行拟合
popt, pcov = gradient_descent_method_X5(func, sx, sy)
x_normalized = (sx - np.mean(sx)) / np.std(sx) # 标准化处理的x
y_pred = func(x_normalized, *popt) # 获取y的预测值
gl_data.CurveData = compute_curveData_X5_2(func, popt, sampleData) # 计算拟合曲线的数据
rr = goodness_of_fit_easy(y_pred, sy) # 计算本次拟合的R*R值用于表示拟合优度
# 输出拟合后的各个参数值
ans = '\n函数标准化系数F(x) = '
for i in range(cur.variable):
if i == 4:
ans += '\n'
if i != 0:
ans += ', '
ans += chr(ord('a') + i) + '=' + '{:.2e}'.format(popt[i])
gl_data.Out = '函数形式:' + cur.name + ' '
gl_data.Out += cur.demo
gl_data.Out += ans
gl_data.Out += '\n拟合优度(R\u00b2)' + str(round(rr, 5))
# 编程4.17 END-----------------------------------------
# 这里是为了后续的fit能够直接用到按钮中而不是BF_Fit写一大堆
def fit_X5(xian_index, sampleData):
sx, sy = sampleData[:, 0], sampleData[:, 1]
letters, result = gl_data.FITT_SAVE['variable'][xian_index], gl_data.FITT_SAVE['function'][xian_index]
code_str = fitting(letters, result) # 获取当前选择函数的表达式
func = create_func(code_str) # 构造当前函数的func方法
popt, pcov = gradient_descent_method_X5(func, sx, sy) # 用curve_fit来对数据进行拟合
x_normalized = (sx - np.mean(sx)) / np.std(sx)
y_pred = func(x_normalized, *popt) # 获取y的预测值
gl_data.CurveData = compute_curveData_X5_2(func, popt, sampleData) # 计算拟合曲线的数据
rr = goodness_of_fit_easy(y_pred, sy) # 计算本次拟合的R*R值用于表示拟合优度
# 输出拟合后的各个参数值
ans = '\n函数系数F(x) = '
letter = str(letters[2:]).split(',')
pattern = re.compile('|'.join(letter))
s = pattern.sub('{:.2g}', gl_data.FITT_SAVE['demo'][xian_index])
print(pattern)
print(gl_data.FITT_SAVE['demo'][xian_index])
print("s:", s)
ans += str(s.format(*popt))
gl_data.Out = '函数形式:' + gl_data.FITT_SAVE['name'][xian_index] + ' '
gl_data.Out += gl_data.FITT_SAVE['demo'][xian_index]
gl_data.Out += ans
gl_data.Out += '\n拟合优度(R\u00b2)' + str(round(rr, 5))
# 这里是使用curve_fit实现的实际使用的方式
def fit_XX(xian_index, sampleData):
sx, sy = sampleData[:, 0], sampleData[:, 1]
letters, result = gl_data.FITT_SAVE['variable'][xian_index], gl_data.FITT_SAVE['function'][xian_index]
code_str = fitting(letters, result) # 获取当前选择函数的表达式
func = create_func(code_str) # 构造当前函数的func方法
popt, pcov = curve_fit(func, sx, sy) # 用curve_fit来对数据进行拟合
y_pred = func(sx, *popt) # 获取y的预测值
gl_data.CurveData = compute_curveData_X5(func, popt) # 计算拟合曲线的数据
rr = goodness_of_fit_easy(y_pred, sy) # 计算本次拟合的R*R值用于表示拟合优度
# 输出拟合后的各个参数值
ans = '\n函数系数F(x) = '
letter = str(letters[2:]).split(',')
pattern = re.compile('|'.join(letter))
s = pattern.sub('{:.2g}', gl_data.FITT_SAVE['demo'][xian_index])
print(pattern)
print(gl_data.FITT_SAVE['demo'][xian_index])
print("s:", s)
ans += str(s.format(*popt))
gl_data.Out = '函数形式:' + gl_data.FITT_SAVE['name'][xian_index] + ' '
gl_data.Out += gl_data.FITT_SAVE['demo'][xian_index]
gl_data.Out += ans
gl_data.Out += '\n拟合优度(R\u00b2)' + str(round(rr, 5))
# 编程4.10 END-----------------------------------------
# 编程4.11 -----------------------------------------
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_X3() #更新象限显示面板
def q_button_X3():
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,)
# 四象限按钮
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")# 绘制象限
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_X3()
Q_root.mainloop()
# 编程4.11 END-----------------------------------------

454
X4.py

@ -0,0 +1,454 @@
import sys
import numpy as np
import data as gl_data
import tkinter as tk
from tkinter import *
import tkinter.filedialog # 注意次数要将文件对话框导入
import re
import inspect
from X1 import *
from X2 import *
from X3 import *
import function
import input
global Q_root,F_root
global root_window
global label1,label2,label3
def window():
global root_window
global label1, label2, label3
root_window = Tk()
root_window.title('函数拟合')
root_window.geometry('900x600') # 设置窗口大小:宽x高,注,此处不能为 "*",必须使用 "x"
# 设置主窗口的背景颜色,颜色值可以是英文单词或者颜色值的16进制数,除此之外还可以使用Tk内置的颜色常量
root_window["background"] = "white"
root_window.resizable(0, 0) # 防止用户调整尺寸
label1 = tk.Label(root_window, text="样本数据\n集文件", font=('Times', 8), bg="white",
width=13, height=3, # 设置标签内容区大小
padx=0, pady=0, borderwidth=0, )
label1.place(x=10, y=4) # 设置填充区距离、边框宽度和其样式(凹陷式)
label3 = tk.Label(root_window, text="", font=('Times', 8), bg="white", fg="black",
width=39, height=2, padx=0, pady=0, borderwidth=0, relief="ridge", highlightcolor="blue")
label3.place(x=122, y=10)
# 使用按钮控件调用函数
tk.Button(root_window, text="装载", relief=RAISED, command=lambda: askfile(label3)).place(x=370, y=12)
label2 = tk.Label(root_window, text="拟合曲线类型", font=('Times', 12), bg="white",
width=20, height=3, # 设置标签内容区大小
padx=0, pady=0, borderwidth=0, )
# 设置填充区距离、边框宽度和其样式(凹陷式)
label2.place(x=450, y=4)
gl_data.Canvas2 = tk.Canvas(root_window, bg='white', width=450, height=330)
gl_data.Canvas2.place(x=4, y=60)
# 定义一个处理文件的相关函数
def askfile(label3):
# 从本地选择一个文件,并返回文件的路径
filename = tkinter.filedialog.askopenfilename()
if filename != '':#若选中了一个文件,则对文件进行读取
label3.config(text=filename)#显示文件路径
read_sample_data(filename)#将文件读取并存到sampleData中
# print_sample_data(filename)#将文件读取并逐行输出
selfdata_show(gl_data.SampleData, gl_data.LOW, gl_data.HIGH)
else:#若未选择文件,则显示为空
label3.config(text='')
def print_sample_data(file_path):#打开对应文件
with open(file_path, 'r') as file:
for line in file:#逐行读取文件
line = line.strip('\n')#移除换行符
sx, sy = line.split(' ')#以空格分割xy
print(f'sx: {float(sx)}, sy: {float(sy)}')#将sx、sy转换为浮点数并打印
def read_sample_data(file_path):
x, y = [], []#初始化xy
with open(file_path, 'r') as file:
for line in file:#逐行读文件
line = line.strip('\n')#移除换行符
sx, sy = line.split(' ')#以空格分割xy
x.append(float(sx))#将sx转换为浮点数并加入数组
y.append(float(sy))#将sy转换为浮点数并加入数组
gl_data.SampleData = np.array(list(zip(x, y)))#xy数组转为array并赋值给全局变量
# x=np.array(x) # 列表转数组
# y=np.array(y)
# gl_data.SampleData = np.array(list(zip(x, y)))
# #################################拟合优度R^2的计算######################################
def __sst(y_no_fitting):
"""
计算SST(total sum of squares) 总平方和
:param y_no_predicted: List[int] or array[int] 待拟合的y
:return: 总平方和SST
"""
y_mean = sum(y_no_fitting) / len(y_no_fitting)
s_list =[(y - y_mean)**2 for y in y_no_fitting]
sst = sum(s_list)
return sst
def __ssr(y_fitting, y_no_fitting):
"""
计算SSR(regression sum of squares) 回归平方和
:param y_fitting: List[int] or array[int] 拟合好的y值
:param y_no_fitting: List[int] or array[int] 待拟合y值
:return: 回归平方和SSR
"""
y_mean = sum(y_no_fitting) / len(y_no_fitting)
s_list =[(y - y_mean)**2 for y in y_fitting]
ssr = sum(s_list)
return ssr
def __sse(y_fitting, y_no_fitting):
"""
计算SSE(error sum of squares) 残差平方和
:param y_fitting: List[int] or array[int] 拟合好的y值
:param y_no_fitting: List[int] or array[int] 待拟合y值
:return: 残差平方和SSE
"""
s_list = [(y_fitting[i] - y_no_fitting[i])**2 for i in range(len(y_fitting))]
sse = sum(s_list)
return sse
def goodness_of_fit(y_fitting, y_no_fitting):
"""
计算拟合优度R^2
:param y_fitting: List[int] or array[int] 拟合好的y值
:param y_no_fitting: List[int] or array[int] 待拟合y值
:return: 拟合优度R^2
"""
sse = __sse(y_fitting, y_no_fitting)
sst = __sst(y_no_fitting)
rr = 1 - sse /sst
return rr
# 简化版本的goodness_of_fit
def goodness_of_fit_easy(y_fitting, y_no_fitting):
"""
计算拟合优度R^2
:param y_fitting: List[int] or array[int] 拟合好的y值
:param y_no_fitting: List[int] or array[int] 待拟合y值
:return: 拟合优度R^2
"""
y_mean = sum(y_no_fitting) / len(y_no_fitting)
# 计算SST
sst = sum((y - y_mean) ** 2 for y in y_no_fitting)
# 计算SSE
sse = sum((y_fitting[i] - y_no_fitting[i]) ** 2 for i in range(len(y_fitting)))
# 计算R^2
r_squared = 1 - sse / sst
return r_squared
# 由于之前的函数修改了,这里需要对四个按钮的函数进行编程
def BF_generate_plot_dada(low, high):
num_samples = 25 # 设置样本点数量
sampleData = random_points(num_samples, low, high) # 生成随机样本数据25个
generate_and_plot_sample_data(sampleData, low, high)
def BF_plot_data(sampleData,low,high):
selfdata_show(sampleData,low,high)
def BF_plot_data_and_curve(curveData, sampleData,low,high):
# curveData = compute_curveData2(low,high,1,theta,m, x.mean(), x.std())
draw_dots_and_line(curveData,sampleData,low,high)
# # X4版本
def BF_fit_X4(xian_index, sampleData):
# gl_data.yvals_pow = []
print(xian_index)
cur = function.Fun[xian_index] # 装载正在选择的函数
func = cur.get_fun()#获取当前函数func
sx = sampleData[:,0]
sy = sampleData[:,1]
popt, pcov = curve_fit(func, sx, sy)# 用curve_fit来对点进行拟合
yvals_pow = func(sx, *popt)
# 这里直接套用会没有CurveData
x_values = np.arange(gl_data.LOW, gl_data.HIGH, 1)
y_values = func(x_values, *popt)
gl_data.CurveData = np.column_stack((x_values, y_values))
rr = goodness_of_fit(yvals_pow, sy)# 计算本次拟合的R*R值用于表示拟合优度
# 输出拟合后的各个参数值
ans = '\n函数系数F(x) = '
for i in range(cur.variable):
if i == 4:
ans += '\n'
if i != 0:
ans += ', '
ans += chr(ord('a') + i) + '=' + '{:.2e}'.format(popt[i]) # str(round(gl_data.popt[i], 3))
gl_data.Out = '函数形式:' + cur.name + ' '
gl_data.Out += cur.demo
gl_data.Out += ans
gl_data.Out += '\n拟合优度(R\u00b2)' + str(round(rr, 5))
show_fit_X4()# 显示函数信息到输出框
# # X4版本
# 这里是梯度下降法更新后的新的按钮函数
def BF_fit_X4_testnew(xian_index, sampleData):
# # print(xian_index)
#
# cur = function.Fun[xian_index] # 装载正在选择的函数
# func = cur.get_fun()#获取当前函数func
#
# sx = sampleData[:,0]
# sy = sampleData[:,1]
#
# popt, pcov = gradient_descent_method_X5(func, sx, sy)# 用curve_fit来对点进行拟合
#
# x_normalized = (sx - np.mean(sx)) / np.std(sx)
# yvals_pow = func(x_normalized, *popt)
#
# # print("yvals_pow", yvals_pow)
# # print("sy", sy)
#
# # 这里直接套用会没有CurveData
# x_values = np.arange(gl_data.LOW, gl_data.HIGH, 1)
# x_values_normalized = (x_values - np.mean(sx)) / np.std(sx)
# y_values = func(x_values_normalized, *popt)
# gl_data.CurveData = np.column_stack((x_values, y_values))
#
# rr = goodness_of_fit(yvals_pow, sy)# 计算本次拟合的R*R值用于表示拟合优度
# # 输出拟合后的各个参数值
# ans = '\n函数系数F(x) = '
# for i in range(cur.variable):
# if i == 4:
# ans += '\n'
# if i != 0:
# ans += ', '
# ans += chr(ord('a') + i) + '=' + '{:.2e}'.format(popt[i]) # str(round(gl_data.popt[i], 3))
# gl_data.Out = '函数形式:' + cur.name + ' '
# gl_data.Out += cur.demo
# gl_data.Out += ans
# gl_data.Out += '\n拟合优度(R\u00b2)' + str(round(rr, 5))
fit_X4(xian_index, sampleData)
show_fit_X4()# 显示函数信息到输出框
# 编程4.18 -----------------------------------------
def fitting(letters,result):
code_str = '''
def func({}):
return {}
'''.format(letters,result)
print("code_str",code_str)
return code_str
def create_func(code_str):
# 创建一个空的命名空间
namespace = {}
# 使用exec函数执行字符串代码并指定命名空间为locals
exec(code_str, globals(), namespace)
# 返回命名空间中的函数对象
return namespace['func']
# 这里由于拓展的各种函数因此使用的curve_fit
def BF_fit(root_window, screen_size, xian_index, sampleData):
fit_XX(xian_index, sampleData)
show_fit(root_window, screen_size) # 显示函数信息到输出框,包括上述信息
# 这里是因为自己的梯度下降法可以使用了所以整一个新的同时按照X4中的工作将BF_Fit修改为简单的函数调用形式而不是一大片
def BF_fit_X5_new(root_window, screen_size, xian_index, sampleData):
fit_X5(xian_index, sampleData)
show_fit(root_window, screen_size) # 显示函数信息到输出框,包括上述信息
# 编程4.18 END-----------------------------------------
def buttons():
# 随机生成样本点并显示
b_dot = tk.Button(root_window, text="生成\n数据集", relief=RAISED, bd=4, bg="white", font=("微软雅黑", 10),
command=lambda: BF_generate_plot_dada(gl_data.LOW, gl_data.HIGH))
b_dot.place(x=455, y=410)
# 显示当前样本点
b_show = tk.Button(root_window, text="显示\n数据集", relief=RAISED, bd=4, bg="white", font=("微软雅黑", 10),
command=lambda: BF_plot_data(gl_data.SampleData, gl_data.LOW, gl_data.HIGH))
b_show.place(x=510, y=410)
# 显示数据集与曲线
b_line = tk.Button(root_window, text="显示数据\n集与曲线", relief=RAISED, bd=4, bg="white", font=("微软雅黑", 10),
command=lambda: BF_plot_data_and_curve(gl_data.CurveData, gl_data.SampleData, gl_data.LOW, gl_data.HIGH))
b_line.place(x=565, y=410)
# 手动输入数据集
b_input = tk.Button(root_window, text="手动输入数据集", relief=RAISED, bd=4, bg="white", pady=7, font=("微软雅黑", 13),
command=lambda: input.input_num(root_window))
b_input.place(x=633, y=410)
# 拟合并输出拟合结果
b_fit = tk.Button(root_window, text="拟合", relief=RAISED, bd=4, bg="white", pady=7, font=("微软雅黑", 13),
command=lambda: BF_fit_X4_testnew(gl_data.Xian_index, gl_data.SampleData))
b_fit.place(x=771, y=410)
# 这里是X4版本的代码X5修改了界面
def show_fit_X4():
L = tk.Label(root_window, text='结果输出:', bg='white', font=("微软雅黑", 16)
, anchor=W)
L.place(x=20, y=480, width=100, height=30)
ans = tk.Label(root_window, text=gl_data.Out, font=("微软雅黑", 14)
, anchor=W, justify='left')
ans.place(x=120, y=480, width=760, height=100)
print(gl_data.Out)
def show_fit(root_window, screen_size):
sout = str(gl_data.Out)
ans = tk.Label(root_window, text=sout, font=("微软雅黑", 14)
, anchor=W, justify='left')
ans.place(x=int(120*screen_size), y=int(480*screen_size), width=int(760*screen_size), height=100)
print(sout)
# 拟合按钮所对应的函数
def fit_data(xian_index, sampleData):
# gl_data.yvals_pow = []
cur = function.Fun[xian_index] # 装载正在选择的函数
func = cur.get_fun()#获取当前函数func
sx, sy = sampleData[:, 0], sampleData[:, 1]
# 使用 inspect.signature 获取函数的签名信息
sig = inspect.signature(func)
# 获取所有参数的名称
params = sig.parameters
print(params)
popt, pcov = curve_fit(func, sx, sy)# 用curve_fit来对点进行拟合
yvals_pow = func(sx, *popt)
rr = goodness_of_fit(yvals_pow, sy)# 计算本次拟合的R*R值用于表示拟合优度
# 输出拟合后的各个参数值
ans = '\n函数系数:'
for i in range(cur.variable):
if i == 4:
ans += '\n'
if i != 0:
ans += ', '
ans += chr(ord('a') + i) + '=' + '{:.2e}'.format(popt[i]) # str(round(gl_data.popt[i], 3))
gl_data.Out = '函数形式:' + cur.name + ' '
gl_data.Out += cur.demo
gl_data.Out += ans
gl_data.Out += '\n拟合优度(R\u00b2)' + str(round(rr, 5))
show_fit_X4() # 显示函数信息到输出框
def change_Q_X4(no):
gl_data.Quadrant = no #更改全局变量的象限显示
if no:#若为一象限则修改显示下限为0
gl_data.LOW = 0
else:#若为四象限,则修改显示下限为-gl_data.maxV
gl_data.LOW = -gl_data.MAXV
q_button_X4()#更新象限显示面板
def q_button_X4():
r = 7.5
rr = 2.5
for widget in Q_root.winfo_children():
widget.destroy()
q_cv = tk.Canvas(Q_root, width=400, height=50)
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,)
# 四象限按钮
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")
else:
q_cv.create_oval(290 - rr, 25 - rr, 290 + rr, 25 + rr
, fill="black", width=1, outline="black")
def change_f_X4(no):
gl_data.Xian_index = no#设置全局函数编号为该函数
f_button_X4()#重新绘制函数显示界面
def f_button_X4():
r = 7.5#设置按钮大小
rr = 2.5#设置按钮大小
for widget in F_root.winfo_children():
widget.destroy()#清空原有按钮
f_cv = tk.Canvas(F_root, width=400, height=330)#新建画布
f_cv.place(x=0, y=0)#放置画布
f_cv.create_rectangle(2, 2, 398, 328, fill='white', outline="#0099ff")#设置画布边框及底色
cur = 0#函数计数
for fun in function.Fit_type_library:#遍历函数库
f = function.Fit_type_library.get(fun)#获取函数具体信息
if function.Show[f[0]] == 1:# 如果show为1则显示
f_cv.create_oval(20 - r, 20 + 15 + cur * 30 - r, 20 + r, 20 + 15 + cur * 30 + r
, fill="white", width=1, outline="black")# 绘制标记框
if f[0] == gl_data.Xian_index:# 若选择为当前函数则标记
f_cv.create_oval(20 - rr, 20 + 15 + cur * 30 - rr, 20 + rr, 20 + 15 + cur * 30 + rr
, fill="black", width=1, outline="black")
# 绘制切换按钮,单击则将当前使用函数切换为该函数
button = tk.Button(F_root, text=f[2] + ' ' + f[1], bd=0, bg="white", font=("微软雅黑", 12)
, command=lambda x=f[0]: change_f_X4(x), anchor=W)
button.place(x=40, y=20 + cur * 30, width=300, height=30)
cur += 1#计数加一
def close_window():
sys.exit()
def main():
global Q_root, F_root, root_window
gl_data.X = []
gl_data.X = []
window()
function.f_read()
# 函数选择相关界面
F_root = tk.Frame(root_window, width=400, height=330, bg='white', )
F_root.place(x=490, y=60)
# 象限选择相关界面
Q_root = tk.Frame(root_window, width=400, height=50, bg='white', )
Q_root.place(x=20, y=410)
buttons()
f_button_X4()
q_button_X4()
show_fit_X4()
root_window.protocol("WM_DELETE_WINDOW", close_window)
root_window.mainloop()
if __name__ == '__main__':
main()
# X4除了没有使用自己定义的方法以外基本差不多了

492
X5.py

@ -0,0 +1,492 @@
# -*- coding: utf-8 -*-
import random
from tkinter import messagebox
import pandas as pd
from sympy import sympify, SympifyError
import sys
import numpy as np
import tkinter as tk
from tkinter import ttk
from tkinter import *
from screeninfo import get_monitors
import os
from PIL import ImageTk, Image
import tkinter.filedialog # 注意次数要将文件对话框导入
from scipy.optimize import leastsq
import input
from FuncNameFormula.formula import *
import data as gl_data
from X1 import *
from X2 import *
from X3 import *
from X4 import *
global Q_root,F_root
global root_window
global label1,label2,label3
# 编程4.15-----------------------------------------
def create_func(code_str):
# 创建一个空的命名空间
namespace = {}
# 使用exec函数执行字符串代码并指定命名空间为locals
exec(code_str, globals(), namespace)
# 返回命名空间中的函数对象
return namespace['func']
def check_formula_syntax(formula):
try:
sympify(formula)
return True
except SympifyError:
return False
# 负责处理用户输入并验证数学表达式的正确性
def add_func():
result1 = entry1.get()
result2 = entry2.get()
if result1 and result2:
if check_formula_syntax(result2):
letters, result = expression_output(result2)
if result == None:
messagebox.showinfo('提示', '你输入的数学公式错误!')
else:
make_func(letters,result)
else:
messagebox.showinfo('提示', '你输入的数学公式错误!')
else:
messagebox.showinfo('提示','你未输入的完成!')
def functional_formula(letter,result,decimals):
# 使用 zip() 函数将两个列表组合成元组的迭代器
pairs = zip(letter, decimals)
# 使用字典推导式构建字典
target = {key: str(value) for key, value in pairs}
# print(target)
# # 依次替换字符串中的元素
for key, value in target.items():
indices = [i for i, c in enumerate(result) if c == key]
for i in indices:
if (i + 1) == len(result) or result[i + 1] in ['*', '+', '-', '/', ')', '']:
result = result[0:i] + value + result[i + 1:]
return result
def fitting(letters,result):
code_str = '''
def func({}):
return {}
'''.format(letters,result)
return code_str
def show_image():
from PIL import ImageTk, Image
# 加载图像
image = Image.open("new_line.png")
image = image.resize((850, 700))
# 在画布上显示图像
image_tk = ImageTk.PhotoImage(image)
root_window.image_tk = image_tk
show_canvas.create_image(0, 0, anchor="nw", image=image_tk)
def curve_func(func):
# 绘制拟合结果
draw_axis(-100, 100, 20)
x_fit = np.linspace(-100, 100, 100)
y_fit = func(x_fit)
plt.plot(x_fit, y_fit, 'r-', label='sample curve')
# 将图例放在图的外面
# plt.legend(loc='upper left')
plt.legend(loc='center left', bbox_to_anchor=(1, 0.9))
plt.xlabel('x')
plt.ylabel('y')
# plt.show()
# plt.subplots_adjust(right=0.7)
plt.savefig('new_line.png', bbox_inches='tight')
# 清除当前图形状态
plt.clf()
show_image()
# 基于验证通过的表达式创建函数并在GUI中展示该函数的图形化表示。
def make_func(letters,result):
# print(letters,result)
letter = str(letters).split(',')
n = len(letter)-1
decimals = [round(random.uniform(-10, 10), 1) for _ in range(n)]
target_result = functional_formula(letter[1:], result, decimals)
# 清除以前的值
entry3.delete(0, tk.END)
# 填入函数
entry3.insert(0, target_result)
code_str = fitting('x', target_result)
target_func = create_func(code_str) # 获取当前函数func
curve_func(target_func)
# 函数曲线按钮对应的函数
def customized_curve():
result1 = entry2.get()
result2 = entry3.get()
if result1 and result2:
if check_formula_syntax(result1):
letters, result = expression_output(result1)
if result == None:
messagebox.showinfo('提示', '你输入的数学公式错误!')
else: # 如果用户输入的公式正确
# 删除空格
result2 = result2.replace(' ', '')
# 使用正则表达式替换数字为空字符串
result3 = re.sub(r'[-]?\d+(\.\d+)?', '', result2)
letter = str(letters).split(',')
decimals = [1 for _ in range(len(letter)-1)]
result4 = functional_formula(letter[1:], result, decimals)
result4 = result4.replace('1', '')
result4 = re.sub(r'[-]?\d+(\.\d+)?', '', result4)
result4 = result4.replace(' ', '')
# print(result3,result4)
if result3 == result4:
code_str = fitting('x', result2)
func = create_func(code_str) # 获取当前函数func
curve_func(func)
else:
messagebox.showinfo('提示', '请检查你修改的函数是否与函数式相对应!')
# 函数确认按钮对应的函数
def save(result1, letters, result , result2):
gl_data.INDEX = len(gl_data.FITT_SAVE['no'])
gl_data.FITT_SAVE['no'][gl_data.INDEX] = gl_data.INDEX
gl_data.FITT_SAVE['name'][gl_data.INDEX] = result1
gl_data.FITT_SAVE['variable'][gl_data.INDEX] = letters
gl_data.FITT_SAVE['function'][gl_data.INDEX] = result
gl_data.FITT_SAVE['demo'][gl_data.INDEX] = result2
file_path = 'functions_new.xlsx'#设置路径
# 将字典转换为DataFrame
df = pd.DataFrame(gl_data.FITT_SAVE)
# 将DataFrame保存为Excel文件
df.to_excel(file_path, index=False)
# 完成添加函数后保存函数
def func_save():
result1 = entry1.get()
result2 = entry2.get()
if result1 and result2:
if check_formula_syntax(result2):
letters, result = expression_output(result2)
if result== None:
messagebox.showinfo('提示', '你输入的数学公式错误!')
else:
save(result1, letters, result, result2)
subwindow.destroy() # 关闭子页面
gl_data.Xian_index = gl_data.INDEX
f_button()
else:
messagebox.showinfo('提示', '你输入的数学公式错误!')
else:
messagebox.showinfo('提示', '你未输入的完成!')
# 输出一个新窗口,用于增加拟合的函数类型
def show_subwindow():
global subwindow
subwindow = tk.Toplevel(root_window)
subwindow.geometry('1400x700') # 更新窗口尺寸
subwindow.title('新增拟合函数')
# 创建画布
global show_canvas
canvas_width = 1400 # 更新画布宽度
canvas_height = 700 # 更新画布高度
canvas = Canvas(subwindow, width=canvas_width, height=canvas_height, bg="#ADD8E6")
canvas.pack()
show_canvas = Canvas(canvas, width=840, height=700, bg="white") # 更新内部画布尺寸
show_canvas.place(x=0, y=0)
global entry1, entry2, entry3
# 创建输入框及标签
label_font_size = 14 # 设置字体大小
label1 = tk.Label(canvas, text="函数名:", font=("", label_font_size))
label1.place(x=910, y=70) # 更新位置
entry1 = tk.Entry(canvas, font=("", label_font_size))
entry1.place(x=910, y=140, width=420, height=56) # 更新位置和尺寸
label2 = tk.Label(canvas, text="函数式:", font=("", label_font_size))
label2.place(x=910, y=210)
entry2 = tk.Entry(canvas, font=("", label_font_size))
entry2.place(x=910, y=280, width=420, height=56)
label3 = tk.Label(canvas, text="测试函数式:", font=("", label_font_size))
label3.place(x=910, y=350)
entry3 = tk.Entry(canvas, font=("", label_font_size))
entry3.place(x=910, y=420, width=420, height=56)
# 创建按钮
button_font_size = 14 # 设置按钮字体大小
button1 = tk.Button(canvas, text="生成函数", command=add_func, font=("", button_font_size))
button1.place(x=910, y=560)
button2 = tk.Button(canvas, text="函数曲线", command=customized_curve, font=("", button_font_size))
button2.place(x=1050, y=560)
button3 = tk.Button(canvas, text="函数确认", command=func_save, font=("", button_font_size))
button3.place(x=1190, y=560)
# 编程4.15 END-----------------------------------------
# 创建弹出窗口
def creat_window(title):
top = tk.Toplevel(root_window)
top.geometry("300x350")
top.title(title)
return top
# 输入框
def create_input_box(top, text, value):
box_label = tk.Label(top, text=text)
box_label.pack(padx=10, pady=10)
box_size = tk.IntVar(top, value=value) # 创建一个IntVar对象并设置默认值为3
box_size_entry = tk.Entry(top, textvariable=box_size) # 关联IntVar对象
box_size_entry.pack(padx=20, pady=20)
return box_size_entry
def read_fitting():
file_path = 'functions_new.xlsx' # 设置路径
df = pd.read_excel(io=file_path, header=0) # 设置表格
gl_data.FITT_SAVE = df.to_dict()
def element1(path):
# print(path)
# 加载图像并创建一个 PhotoImage 对象
image = tk.PhotoImage(file=path)
# 保存图片的引用,防止被垃圾回收
root_window.image = image
return image
def element(path, width, height):
# 加载图元对应的图片文件
from PIL import ImageTk, Image
# print(path)
img = Image.open(path)
# # 使用resize方法调整图片
img = img.resize((width, height))
# 把Image对象转换成PhotoImage对象
img = ImageTk.PhotoImage(img)
# 保存图片的引用,防止被垃圾回收
root_window.img = img
return img
def jis():
global screen_size
# 获取当前屏幕的宽度和高度
monitors = get_monitors()
screen_width = monitors[0].width
# 计算按钮的宽度和高度
button_width = int(screen_width * 0.85)
# 打印按钮的宽度和高度
screen_size = round(button_width*0.9/900, 1)
gl_data.MAGNIDICATION = screen_size
read_fitting()
# def show_fit():
# sout = str(gl_data.Out)
# ans = tk.Label(root_window, text=sout, font=("微软雅黑", 14)
# , anchor=W, justify='left')
# ans.place(x=int(120*screen_size), y=int(480*screen_size), width=int(760*screen_size), height=100)
# print(sout)
## GUI part-----------------------------------------------------
def window():
global root_window
global label1, label2, label3
root_window = Tk()
root_window.title('函数拟合')
width, height = int(900*screen_size), int(560*screen_size)
root_window.geometry(str(width)+'x'+str(height)) # 设置窗口大小:宽x高,注,此处不能为 "*",必须使用 "x"
# 设置主窗口的背景颜色,颜色值可以是英文单词或者颜色值的16进制数,除此之外还可以使用Tk内置的颜色常量
img_path = ["background/add.png", "background/下方输入框.png", "background/右侧未选中.png", "background/右侧背景.png",
"background/右侧选中.png","background/大背景.png", "background/导航拦.png", "background/导航输入框.png",
"background/小直线.png", "background/手动输入数据集.png", "background/拟合.png", "background/新增拟合曲线类型.png",
"background/显示数据集与曲线.png", "background/未选中.png", "background/生成数据集.png", "background/矩形.png",
"background/背景图片.png", "background/装载.png", "background/选中.png", "background/显示数据集.png",
"background/img.png"
]
global list_image
list_image = []
for i in range(len(img_path)):
if i in [17, 14, 19, 10, 12]:
list_image.append(element(img_path[i], 110, 80))
elif i == 16:
list_image.append(element(img_path[i], width, height))
elif i in [11, 9]:
list_image.append(element(img_path[i], 240, 80))
else:
list_image.append(element1(img_path[i]))
# root_window["background"] = "#87ceeb"
canvas = tk.Canvas(root_window, width=width-10, height=int(560*screen_size)-10)
canvas.place(x=0, y=0)
canvas.create_image(0, 0, image=list_image[16], anchor=tk.NW)
root_window.resizable(0, 0) # 防止用户调整尺寸
canvas.create_text(int(40*screen_size), int(26*screen_size), text='样本数据\n集文件', font='Arial 14', fill='black')
label3 = tk.Label(root_window, text="", font=('Times', 12), bg="#ADD8E6", fg="black",
width=50, height=3, padx=0, pady=0, borderwidth=0, relief="ridge", highlightcolor="blue")
label3.place(x=int(122*screen_size), y=int(10*screen_size))
# 使用按钮控件调用函数
tk.Button(root_window, image=list_image[17], relief=tk.FLAT, bd=0, command=lambda: askfile()).place(x=int(490*screen_size), y=int(12*screen_size))
canvas.create_text(int(610*screen_size), int(40 * screen_size), text='拟合曲线类型', font='Arial 16', fill='black')
gl_data.Canvas2 = tk.Canvas(root_window, bg='white', width=int(550*screen_size), height=int(330*screen_size))
gl_data.Canvas2.place( x=int(4*screen_size), y=int(60*screen_size))
canvas.create_text(int(60*screen_size), int(490*screen_size),text="结果输出:", font='Arial 18', fill='black')
def buttons():
# 随机生成样本点并显示
b_dot = tk.Button(root_window, image=list_image[14], relief=tk.FLAT, bd=0,
command=lambda: BF_generate_plot_dada(gl_data.LOW, gl_data.HIGH))
b_dot.place(x=int(435*screen_size), y=int(410*screen_size))
# 显示当前样本点
b_show = tk.Button(root_window, image=list_image[19], relief=tk.FLAT, bd=0,
command=lambda: BF_plot_data(gl_data.SampleData, gl_data.LOW, gl_data.HIGH))
b_show.place(x=int(515*screen_size), y=int(410*screen_size))
# 显示数据集与曲线
b_line = tk.Button(root_window, image=list_image[12], relief=tk.FLAT, bd=0,
command=lambda: BF_plot_data_and_curve(gl_data.CurveData, gl_data.SampleData, gl_data.LOW, gl_data.HIGH))
b_line.place(x=int(595*screen_size), y=int(410*screen_size))
# 手动输入数据集
b_input = tk.Button(root_window, image=list_image[9], relief=tk.FLAT, bd=0,
command=lambda: input.input_num(root_window))
b_input.place(x=int(675*screen_size), y=int(410*screen_size))
# 拟合并输出拟合结果
b_fit = tk.Button(root_window, image=list_image[10], relief=tk.FLAT, bd=0,
command=lambda: BF_fit_X5_new(root_window,screen_size, gl_data.Xian_index, gl_data.SampleData))
b_fit.place(x=int(821*screen_size), y=int(410*screen_size))
# 编程4.16 -----------------------------------------
def change_f(no):
gl_data.Xian_index = no # 设置全局函数编号为该函数
f_button() # 重新绘制函数显示界面
def f_button():
r = 7.5 # 设置按钮大小
rr = 2.5 # 设置按钮大小
for widget in F_root.winfo_children():
widget.destroy() # 清空原有按钮
gl_data.INDEX = len(gl_data.FITT_SAVE['no'])
canvas = Canvas(F_root, width=int(320 * screen_size), height=int(270 * screen_size))
# # 将图像添加到 Canvas 组件中
canvas.pack(side="left", fill="both", expand=True)
scrollbar = Scrollbar(F_root, orient="vertical", command=canvas.yview)
scrollbar.pack(fill="y", side="right")
canvas.configure(yscrollcommand=scrollbar.set)
canvas.bind('<Configure>', lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
if gl_data.INDEX - 10 <= 0:
result = 0
else:
result = gl_data.INDEX - 10
canvas_height = int(328 * screen_size) + result*50 # 或根据需要调整适当的高度增加值
# # 绘制矩形边框及底色
canvas.create_rectangle(2, 2, int(398 * screen_size), canvas_height, fill='#ADD8E6', outline="#0099ff")
# canvas.create_image(4, 4, image=list_image[3], anchor=tk.NW)
cur = 0 # 函数计数
for i in range(gl_data.INDEX): # 遍历函数库
if gl_data.FITT_SAVE['no'][i] == gl_data.Xian_index: # 若选择为当前函数则标记
# 在指定位置绘制图片
canvas.create_image(int((20 - rr) * screen_size), int((20 + 15 + cur * 30 - rr) * screen_size), image=list_image[4])
else:
# 在指定位置绘制图片
canvas.create_image(int((20 - rr) * screen_size), int((20 + 15 + cur * 30 - rr) * screen_size),
image=list_image[2])
# 绘制切换按钮,单击则将当前使用函数切换为该函数
button = tk.Button(F_root, text=gl_data.FITT_SAVE['name'][i] + ' ' + gl_data.FITT_SAVE['demo'][i], bd=0,
bg="#ADD8E6", font=("微软雅黑", 10),
command=lambda x=gl_data.FITT_SAVE['no'][i]: change_f(x), anchor=W)
# 将按钮放置在Canvas中
canvas.create_window(int(40 * screen_size), int((30 + cur * 30) * screen_size), window=button, anchor="w")
cur += 1 # 计数加一
canvas.configure(scrollregion=canvas.bbox("all"))
# 编程4.16 END-----------------------------------------
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=int(400*screen_size), height=int(50*screen_size))
q_cv.place(x=0, y=0)
# q_cv.create_image(0, 0, image=list_image[20], anchor=tk.NW)
l = tk.Label(Q_root, text='坐标轴', bd=0, font=("微软雅黑", 16), anchor=W)
l.place(x=20, y=0, width=int(80*screen_size), height=int(50*screen_size),)
# 四象限按钮
b1 = tk.Button(Q_root, text='四象限', bd=0, font=("微软雅黑", 16)
, command=lambda: change_Q(0), anchor=W)
b1.place(x=int(170*screen_size), y=0, width=int(80*screen_size), height=int(50*screen_size),)
# 一象限按钮
b2 = tk.Button(Q_root, text='一象限', bd=0, font=("微软雅黑", 16)
, command=lambda: change_Q(1), anchor=W)
b2.place(x=int(320*screen_size), y=0, width=int(80*screen_size), height=int(50*screen_size),)
# # 绘制标记框
q_cv.create_image(int((145 - r)*screen_size), int((35 - r)*screen_size),
image=list_image[2])
q_cv.create_image(int((295 - r)*screen_size), int((35 - r)*screen_size),
image=list_image[2])
# 根据当前的象限选择值来填充标记框
if gl_data.Quadrant == 0:
q_cv.create_image(int((140 - rr)*screen_size), int((30 - rr)*screen_size),
image=list_image[18])
else:
q_cv.create_image(int((290 - rr)*screen_size), int((30 - rr)*screen_size),
image=list_image[18])
def main():
global Q_root, F_root, root_window
jis()
# gl_data.LOW, gl_data.HIGH = int(gl_data.LOW*screen_size), int(gl_data.HIGH*screen_size)
gl_data.X = []
gl_data.X = []
window()
# 函数选择相关界面
F_root = tk.Canvas(root_window, width=int(310*screen_size), height=int(290*screen_size))
F_root.place(x=int(560*screen_size), y=int(60*screen_size))
# 象限选择相关界面
Q_root = tk.Canvas(root_window, width=int(400*screen_size), height=int(50*screen_size))
Q_root.place(x=int(20*screen_size), y=int(410*screen_size))
buttons()
f_button()
q_button()
show_fit(root_window, screen_size)
tk.Button(root_window, image=list_image[11], command=show_subwindow, relief=tk.FLAT, highlightthickness=0).place(x=int(640*screen_size), y=int(350)*screen_size)
# 设置Grid布局的列和行权重
root_window.protocol("WM_DELETE_WINDOW", close_window)
root_window.mainloop()
if __name__ == '__main__':
main()
pass

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 808 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1,28 @@
# -*- encoding: utf-8 -*-
import tkinter as tk
from tkinter import *
import random
import numpy as np
FITT_SAVE = {}
FITT_LIST = []
global Canvas2 # 用于显示函数的画布
Img1 = None # 绘制的dot.png图像
Img2 = None # 绘制的line.png图像
Xian_index = 0 # 当前选择的函数编号
Quadrant = 0 # 当前选择的象限信息0为四象限1为一象限
MAXV = 1000 # 最大值
INDEX = 5 # 拟合函数索引
Out = '' # 拟合输出信息
LOW = -MAXV # 坐标轴显示上界
HIGH = MAXV # 坐标轴显示下界
MAGNIDICATION = 1.0 # 放大倍数
SampleData = None # 样本数据
CurveData = None # 拟合数据
set_img1 = None
set_img2 = None
global Q_root,F_root
global root_window
global label1,label2,label3

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

@ -0,0 +1,145 @@
# -*- encoding: utf-8 -*-
"""
@Author: packy945
@FileName: function.py
@DateTime: 2023/6/6 14:45
@SoftWare: PyCharm
"""
import numpy as np
import math
import data
import pandas as pd
from pandas import DataFrame
# 函数库
Show = []
Fun = []
Fit_type_library = {}
class Function:
def __init__(self, no, name, v, fun, complete='', demo=''):
# 函数名称
self.name = name
# 变量个数
self.variable = v
self.function = fun # 函数表达式
# 函数编号
self.no = no
# 是否显示
self.show = 0
# 完整函数
self.complete = complete
# self.print = ''
self.demo = demo
def get_fun(self):
if self.variable == 2:
return self.fun2
elif self.variable == 3: # 以二次函数为例,省略其他函数
return self.fun3
elif self.variable == 4:
return self.fun4
elif self.variable == 5:
return self.fun5
elif self.variable == 6:
return self.fun6
def fun2(self, x, a0, a1):
return eval(self.function)
def fun3(self, x, a0, a1, a2):
return eval(self.function)
def fun4(self, x, a0, a1, a2, a3):
return eval(self.function)
def fun5(self, x, a0, a1, a2, a3, a4):
return eval(self.function)
def fun6(self, x, a0, a1, a2, a3, a4, a5):
return eval(self.function)
def print_f(self, a):
# print('self.show='+self.complete)
exec('self.show='+self.complete)
# print(self.show)
return self.show
# def f_init():
# cur = 0 # 函数编号
# # 一次函数
# newfun = Function(cur, '一次函数', 2, 'a0*x+a1', "f'{a[0]}x+{a[1]}'", 'ax+b')
# newfun.show = 1
# Fun.append(newfun)
# cur += 1
# # 二次函数
# newfun = Function(cur, '二次函数', 3, 'a0*x*x+a1*x+a2', "f'{a[0]}x^2+{a[1]}x+{a[2]}'", 'ax^2+bx+c')
# newfun.show = 1
# Fun.append(newfun)
# cur += 1
# # 三次函数
# newfun = Function(cur, '三次函数', 4, 'a0*x*x*x+a1*x*x+a2*x+a3', "f'{a[0]}x^3+{a[1]}x^2+{a[2]}x+{a[3]}'", 'ax^3+bx^2+cx+d')
# newfun.show = 0
# Fun.append(newfun)
# cur += 1
# # 四次函数
# newfun = Function(cur, '四次函数', 5, 'a0*x*x*x*x+a1*x*x*x+a2*x*x+a3*x+a4'
# , "f'{a[0]}x^4+{a[1]}x^3+{a[2]}x^2+{a[3]}x+{a[4]}'", 'ax^4+bx^3+cx^2+dx+e')
# newfun.show = 0
# Fun.append(newfun)
# cur += 1
# # 指数函数
# newfun = Function(cur, '指数函数', 2, 'a0*np.exp(0.01*x)+a1', "f'{a[0]}e^(0.01x)+{a[1]}'", 'a*e^(0.01x)+b')
# newfun.show = 0
# Fun.append(newfun)
# cur += 1
# # 对数函数
# newfun = Function(cur, '对数函数', 3, 'a0*(np.log(x) + 1e-5) / (np.log(a1) + 1e-5) + a2',
# "f'{a[0]}log(x,{a[1]})+{a[2]}'", 'alog(x,b)+c')
# newfun.show = 0
# Fun.append(newfun)
# cur += 1
# # 高斯函数
# F_init()
def write():
file_path = 'functions.xlsx'#设置路径
df = pd.read_excel(io=file_path, header=1)#设置表格
print(df)
df.columns = ['no', 'name', 'variable', 'function', 'complete', 'demo', 'show']#设置表格标题
cur = 0#重置计数
for f in Fun:#遍历函数类型
df.loc[cur] = [cur, f.name, f.variable, f.function, f.complete, f.demo, f.show]#写进表格
cur += 1#计数加一
DataFrame(df).to_excel(file_path, sheet_name='Sheet1', index=False, header=True)#保存xlsx
def f_read():
file_path = 'functions.xlsx'#设置路径
df = pd.read_excel(io=file_path, header=0)#设置表格
cur = 0
for i in range(len(df)):#逐行读取excel
newfun = Function(df.loc[i][0], df.loc[i][1], df.loc[i][2], df.loc[i][3], df.loc[i][4], df.loc[i][5])
newfun.show = df.loc[i][6]
Show.append(df.loc[i][6])#读取函数显示信息
Fun.append(newfun)#读取函数信息并添加
cur += 1
for f in Fun:#建立简表fit_type_library
Fit_type_library[f.name] = [f.no, f.demo, f.name]
if __name__ == '__main__':
f_read()
# for f in fun:
# print([f.no, f.demo, f.name])
for f in Fun:
Fit_type_library[f.name] = [f.no, f.demo, f.name]
print("Fun",Fun)
print(Fit_type_library)
a = [1,2,3,4,5]
x = 2
pass

Binary file not shown.

Binary file not shown.

@ -0,0 +1,89 @@
# -*- encoding: utf-8 -*-
"""
@Author: packy945
@FileName: input.py
@DateTime: 2023/7/19 16:59
@SoftWare: PyCharm
"""
import tkinter as tk
from tkinter import *
import numpy as np
import data as gl_data
from X2 import selfdata_show
global top
def input_num(root_tk):
global top
top = tk.Toplevel(root_tk)
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 input_data(root_tk, num):
global top
sample_x = []
sample_y = []
sample_data = []
top.destroy()
top = tk.Toplevel(root_tk)
def add_sample_data():
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) < num:
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():
if len(sample_data) == num:
label_status.config(text="已达到最大数量")
gl_data.X = np.array(sample_x)
gl_data.Y = np.array(sample_y)
print('已添加', sample_data)
top.destroy()
selfdata_show(gl_data.SampleData, gl_data.LOW, gl_data.HIGH)
else:
label_status.config(text="还需输入{}个点对".format(num - len(sample_data)))
print(sample_data)
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()
input_num(root)

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

@ -0,0 +1,16 @@
# This is a sample Python script.
# Press Shift+F10 to execute it or replace it with your code.
# Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings.
def print_hi(name):
# Use a breakpoint in the code line below to debug your script.
print(f'Hi, {name}') # Press Ctrl+F8 to toggle the breakpoint.
# Press the green button in the gutter to run the script.
if __name__ == '__main__':
print_hi('PyCharm')
# See PyCharm help at https://www.jetbrains.com/help/pycharm/

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

@ -0,0 +1,30 @@
-1000.000000 -303.919733
-934.000000 -350.424580
-868.000000 -193.369993
-802.000000 -474.832293
-736.000000 -101.068322
-670.000000 -33.916365
-604.000000 -164.504704
-538.000000 -147.298119
-472.000000 -124.814141
-406.000000 -139.033018
-340.000000 -69.265051
-274.000000 -90.553084
-208.000000 -114.709905
-142.000000 -103.201058
-76.000000 -108.245882
-10.000000 56.710600
56.000000 18.503031
122.000000 185.633626
188.000000 152.615324
254.000000 47.216669
320.000000 256.009421
386.000000 270.790257
452.000000 61.971014
518.000000 121.635726
584.000000 163.906089
650.000000 166.204626
716.000000 315.640621
782.000000 425.649206
848.000000 454.347899
914.000000 289.943295

@ -0,0 +1,30 @@
-1000.000000 -2412.037897
-934.000000 -1906.704565
-868.000000 -1515.407287
-802.000000 -1286.984468
-736.000000 -991.348043
-670.000000 -699.579002
-604.000000 -834.074507
-538.000000 -694.557977
-472.000000 -503.237387
-406.000000 -288.033015
-340.000000 -248.449961
-274.000000 -317.763223
-208.000000 -254.540871
-142.000000 -269.952677
-76.000000 -252.274149
-10.000000 -373.987676
56.000000 -129.655207
122.000000 -325.928443
188.000000 -98.240616
254.000000 -325.921235
320.000000 -161.796895
386.000000 96.648543
452.000000 -245.636986
518.000000 190.848311
584.000000 225.026237
650.000000 317.523583
716.000000 772.606080
782.000000 645.906241
848.000000 1091.495759
914.000000 1225.588183

@ -0,0 +1,30 @@
-1000.000000 1318.415137
-934.000000 971.366429
-868.000000 950.320306
-802.000000 635.325663
-736.000000 774.823634
-670.000000 659.035975
-604.000000 449.284057
-538.000000 262.096521
-472.000000 141.521962
-406.000000 65.441983
-340.000000 162.273141
-274.000000 209.914028
-208.000000 62.504373
-142.000000 -160.439640
-76.000000 -201.140961
-10.000000 -178.764894
56.000000 -194.056288
122.000000 -221.386689
188.000000 -236.245098
254.000000 -317.086262
320.000000 -385.718988
386.000000 -198.736083
452.000000 -256.246461
518.000000 -226.361577
584.000000 -329.214396
650.000000 98.251218
716.000000 -132.314476
782.000000 62.741428
848.000000 120.654860
914.000000 356.397702

@ -0,0 +1,30 @@
-1000.000000 6580.374854
-934.000000 5230.299130
-868.000000 4064.603309
-802.000000 2824.002023
-736.000000 2151.187862
-670.000000 1341.067791
-604.000000 997.401541
-538.000000 512.994167
-472.000000 103.881466
-406.000000 85.927912
-340.000000 -256.482213
-274.000000 -97.197686
-208.000000 -264.665117
-142.000000 -237.702195
-76.000000 -151.105677
-10.000000 -130.269796
56.000000 -102.814456
122.000000 -62.662181
188.000000 -357.518806
254.000000 -149.197016
320.000000 -350.461131
386.000000 -264.914106
452.000000 -94.032078
518.000000 -188.344844
584.000000 -60.854287
650.000000 85.277762
716.000000 413.822510
782.000000 695.033449
848.000000 1169.069640
914.000000 1762.153163

@ -0,0 +1,16 @@
1.000000 -14.349565
67.000000 321.611473
133.000000 375.298867
199.000000 386.511032
265.000000 408.069269
331.000000 423.359694
397.000000 435.982565
463.000000 458.199244
529.000000 451.417416
595.000000 471.376855
661.000000 484.015127
727.000000 489.640132
793.000000 500.047206
859.000000 499.698564
925.000000 492.870266
991.000000 509.779156

@ -0,0 +1,30 @@
-1000.000000 282.188733
-934.000000 -121.080276
-868.000000 89.565718
-802.000000 -36.875112
-736.000000 -2.179209
-670.000000 -33.756961
-604.000000 -199.536348
-538.000000 -50.378169
-472.000000 7.288867
-406.000000 197.918480
-340.000000 18.543165
-274.000000 -80.038062
-208.000000 -0.092604
-142.000000 24.234519
-76.000000 112.628196
-10.000000 57.868872
56.000000 -75.900181
122.000000 53.411782
188.000000 14.463053
254.000000 -157.854773
320.000000 3.419914
386.000000 -95.442953
452.000000 -511.818439
518.000000 -785.633833
584.000000 -1377.367723
650.000000 -2606.119973
716.000000 -5115.078474
782.000000 -9770.399635
848.000000 -19298.079697
914.000000 -37316.681269

@ -0,0 +1,133 @@
import numpy as np
import matplotlib.pyplot as plt
def generate_dataset(func_type, coeff, n_samples=100, noise_level=0.0):
"""
Generate a dataset based on a mathematical function.
Parameters:
func_type (str): Type of function ('linear', 'quadratic', 'cubic', 'quartic', 'exponential', 'logarithmic').
coeff (list): Coefficients of the function.
n_samples (int): Number of samples to generate.
noise_level (float): Standard deviation of Gaussian noise added to the data.
Returns:
np.ndarray: Generated dataset.
"""
# Generate x values
x_values = np.linspace(-1000, 1000, n_samples)
# Define the functions
functions = {
'linear': lambda x: coeff[0] + coeff[1] * x,
'quadratic': lambda x: coeff[0] + coeff[1] * x + coeff[2] * x**2,
'cubic': lambda x: coeff[0] + coeff[1] * x + coeff[2] * x**2 + coeff[3] * x**3,
'quartic': lambda x: coeff[0] + coeff[1] * x + coeff[2] * x**2 + coeff[3] * x**3 + coeff[4] * x**4,
'exponential': lambda x: coeff[0] * np.exp(coeff[1] * x),
'logarithmic': lambda x: coeff[0] + coeff[1] * np.log(np.abs(x) + 1) # Avoid log(0)
}
# Generate y values based on the selected function
y_values = functions[func_type](x_values)
# Add noise
noise = np.random.normal(0, noise_level, n_samples)
y_values_noisy = y_values + noise
# Combine x and y values
dataset = np.vstack((x_values, y_values_noisy)).T
return dataset
def plot_dataset(dataset, func_type, coeff):
"""
Plot the generated dataset.
Parameters:
dataset (np.ndarray): Generated dataset.
func_type (str): Type of function used to generate the dataset.
coeff (list): Coefficients of the function.
"""
x_values = dataset[:, 0]
y_values = dataset[:, 1]
# Plotting the dataset
plt.figure(figsize=(10, 6))
plt.scatter(x_values, y_values, color='blue', label='Generated Data')
# Plot the original function without noise for comparison
if func_type == 'linear':
y_original = coeff[0] + coeff[1] * x_values
elif func_type == 'quadratic':
y_original = coeff[0] + coeff[1] * x_values + coeff[2] * x_values**2
elif func_type == 'cubic':
y_original = coeff[0] + coeff[1] * x_values + coeff[2] * x_values**2 + coeff[3] * x_values**3
elif func_type == 'quartic':
y_original = coeff[0] + coeff[1] * x_values + coeff[2] * x_values**2 + coeff[3] * x_values**3 + coeff[4] * x_values**4
elif func_type == 'exponential':
y_original = coeff[0] * np.exp(coeff[1] * x_values)
elif func_type == 'logarithmic':
y_original = coeff[0] + coeff[1] * np.log(np.abs(x_values) + 1)
plt.plot(x_values, y_original, color='red', label='Original Function')
plt.title(f'{func_type.capitalize()} Function Dataset Visualization')
plt.xlabel('X Values')
plt.ylabel('Y Values')
plt.legend()
plt.grid(True)
plt.show()
def generate_dataset2(func_type, coeff, x_range=(-1000, 1000), n_samples=100, noise_level=0.0):
"""
Generate a dataset based on a mathematical function with a specified x range.
Parameters:
func_type (str): Type of function ('linear', 'quadratic', 'cubic', 'quartic', 'exponential', 'logarithmic').
coeff (list): Coefficients of the function.
x_range (tuple): The range of x values (min, max).
n_samples (int): Number of samples to generate.
noise_level (float): Standard deviation of Gaussian noise added to the data.
Returns:
np.ndarray: Generated dataset.
"""
# Generate x values within the specified range
x_values = np.linspace(x_range[0], x_range[1], n_samples)
# Define the functions
functions = {
'linear': lambda x: coeff[0] + coeff[1] * x,
'quadratic': lambda x: coeff[0] + coeff[1] * x + coeff[2] * x**2,
'cubic': lambda x: coeff[0] + coeff[1] * x + coeff[2] * x**2 + coeff[3] * x**3,
'quartic': lambda x: coeff[0] + coeff[1] * x + coeff[2] * x**2 + coeff[3] * x**3 + coeff[4] * x**4,
'exponential': lambda x: coeff[0] * np.exp(coeff[1] * x),
'logarithmic': lambda x: coeff[0] + coeff[1] * np.log(np.abs(x) + 1) # Avoid log(0)
}
# Generate y values based on the selected function
y_values = functions[func_type](x_values)
# Clip y values to stay within the specified range
y_values = np.clip(y_values, x_range[0], x_range[1])
# Add noise
noise = np.random.normal(0, noise_level, n_samples)
y_values_noisy = y_values + noise
# Clip noisy y values to stay within the specified range
y_values_noisy = np.clip(y_values_noisy, x_range[0], x_range[1])
# Combine x and y values
dataset = np.vstack((x_values, y_values_noisy)).T
return dataset
# Example usage
dataset = generate_dataset('quadratic', [1, 2, 3], n_samples=10, noise_level=10)
print(dataset)
# Visualize the dataset
dataset = generate_dataset('quadratic', [1, 2, 3], n_samples=10, noise_level=10)
plot_dataset(dataset, 'quadratic', [1, 2, 3])
Loading…
Cancel
Save