diff --git a/DefinedTestData/一次函数.txt b/DefinedTestData/一次函数.txt new file mode 100644 index 0000000..1b60975 --- /dev/null +++ b/DefinedTestData/一次函数.txt @@ -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 diff --git a/DefinedTestData/三次函数.txt b/DefinedTestData/三次函数.txt new file mode 100644 index 0000000..eb6c019 --- /dev/null +++ b/DefinedTestData/三次函数.txt @@ -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 diff --git a/DefinedTestData/二次函数.txt b/DefinedTestData/二次函数.txt new file mode 100644 index 0000000..10614a7 --- /dev/null +++ b/DefinedTestData/二次函数.txt @@ -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 diff --git a/DefinedTestData/四次函数.txt b/DefinedTestData/四次函数.txt new file mode 100644 index 0000000..9023afe --- /dev/null +++ b/DefinedTestData/四次函数.txt @@ -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 diff --git a/DefinedTestData/对数.txt b/DefinedTestData/对数.txt new file mode 100644 index 0000000..32d83cc --- /dev/null +++ b/DefinedTestData/对数.txt @@ -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 diff --git a/DefinedTestData/指数函数.txt b/DefinedTestData/指数函数.txt new file mode 100644 index 0000000..d34b980 --- /dev/null +++ b/DefinedTestData/指数函数.txt @@ -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 diff --git a/DefinedTestData/数据集生成.py b/DefinedTestData/数据集生成.py new file mode 100644 index 0000000..6360f03 --- /dev/null +++ b/DefinedTestData/数据集生成.py @@ -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]) diff --git a/FuncNameFormula/formula.py b/FuncNameFormula/formula.py new file mode 100644 index 0000000..18b7440 --- /dev/null +++ b/FuncNameFormula/formula.py @@ -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 diff --git a/TestCode/GDM20240302.py b/TestCode/GDM20240302.py new file mode 100644 index 0000000..f5e8d2c --- /dev/null +++ b/TestCode/GDM20240302.py @@ -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() + + diff --git a/TestCode/draft.py b/TestCode/draft.py new file mode 100644 index 0000000..98ebd16 --- /dev/null +++ b/TestCode/draft.py @@ -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----------------------------------------- + diff --git a/TestCode/draft2.py b/TestCode/draft2.py new file mode 100644 index 0000000..2539315 --- /dev/null +++ b/TestCode/draft2.py @@ -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) + diff --git a/TestCode/leassquareM.py b/TestCode/leassquareM.py new file mode 100644 index 0000000..7ffd6c3 --- /dev/null +++ b/TestCode/leassquareM.py @@ -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) diff --git a/TestCode/testdecent.py b/TestCode/testdecent.py new file mode 100644 index 0000000..f3b217a --- /dev/null +++ b/TestCode/testdecent.py @@ -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) \ No newline at end of file diff --git a/TestCode/testlsM.py b/TestCode/testlsM.py new file mode 100644 index 0000000..49ffac4 --- /dev/null +++ b/TestCode/testlsM.py @@ -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) diff --git a/X1.py b/X1.py new file mode 100644 index 0000000..6c49b15 --- /dev/null +++ b/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----------------------------------------- diff --git a/X2.py b/X2.py new file mode 100644 index 0000000..326c697 --- /dev/null +++ b/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 diff --git a/X3.py b/X3.py new file mode 100644 index 0000000..3075f66 --- /dev/null +++ b/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(' ') # 以空格分割x,y + print(f'sx: {float(sx)}, sy: {float(sy)}') # 将sx、sy转换为浮点数并打印 + + +def read_sample_data(file_path): + x, y = [], [] # 初始化x,y + with open(file_path, 'r') as file: + for line in file: # 逐行读文件 + line = line.strip('\n') # 移除换行符 + sx, sy = line.split(' ') # 以空格分割x,y + x.append(float(sx)) # 将sx转换为浮点数并加入数组 + y.append(float(sy)) # 将sy转换为浮点数并加入数组 + # x,y数组转为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----------------------------------------- \ No newline at end of file diff --git a/X4.py b/X4.py new file mode 100644 index 0000000..4a5c6d2 --- /dev/null +++ b/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(' ')#以空格分割x,y + print(f'sx: {float(sx)}, sy: {float(sy)}')#将sx、sy转换为浮点数并打印 + + +def read_sample_data(file_path): + x, y = [], []#初始化x,y + with open(file_path, 'r') as file: + for line in file:#逐行读文件 + line = line.strip('\n')#移除换行符 + sx, sy = line.split(' ')#以空格分割x,y + x.append(float(sx))#将sx转换为浮点数并加入数组 + y.append(float(sy))#将sy转换为浮点数并加入数组 + gl_data.SampleData = np.array(list(zip(x, y)))#x,y数组转为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除了没有使用自己定义的方法以外基本差不多了 + + diff --git a/X5.py b/X5.py new file mode 100644 index 0000000..821239a --- /dev/null +++ b/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('', 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 diff --git a/background/+.png b/background/+.png new file mode 100644 index 0000000..9293f8c Binary files /dev/null and b/background/+.png differ diff --git a/background/add.png b/background/add.png new file mode 100644 index 0000000..9293f8c Binary files /dev/null and b/background/add.png differ diff --git a/background/img.png b/background/img.png new file mode 100644 index 0000000..a5d79f5 Binary files /dev/null and b/background/img.png differ diff --git a/background/下方输入框.png b/background/下方输入框.png new file mode 100644 index 0000000..7a219fa Binary files /dev/null and b/background/下方输入框.png differ diff --git a/background/右侧未选中.png b/background/右侧未选中.png new file mode 100644 index 0000000..da25b12 Binary files /dev/null and b/background/右侧未选中.png differ diff --git a/background/右侧背景.png b/background/右侧背景.png new file mode 100644 index 0000000..d4ff27d Binary files /dev/null and b/background/右侧背景.png differ diff --git a/background/右侧选中.png b/background/右侧选中.png new file mode 100644 index 0000000..d5035f9 Binary files /dev/null and b/background/右侧选中.png differ diff --git a/background/大背景.png b/background/大背景.png new file mode 100644 index 0000000..d7ec27d Binary files /dev/null and b/background/大背景.png differ diff --git a/background/导航拦.png b/background/导航拦.png new file mode 100644 index 0000000..3158200 Binary files /dev/null and b/background/导航拦.png differ diff --git a/background/导航输入框.png b/background/导航输入框.png new file mode 100644 index 0000000..9051c67 Binary files /dev/null and b/background/导航输入框.png differ diff --git a/background/小直线.png b/background/小直线.png new file mode 100644 index 0000000..e1cc1df Binary files /dev/null and b/background/小直线.png differ diff --git a/background/手动输入数据集.png b/background/手动输入数据集.png new file mode 100644 index 0000000..177e1c9 Binary files /dev/null and b/background/手动输入数据集.png differ diff --git a/background/拟合.png b/background/拟合.png new file mode 100644 index 0000000..6e71af4 Binary files /dev/null and b/background/拟合.png differ diff --git a/background/新增拟合曲线类型.png b/background/新增拟合曲线类型.png new file mode 100644 index 0000000..2d118ec Binary files /dev/null and b/background/新增拟合曲线类型.png differ diff --git a/background/显示数据集.png b/background/显示数据集.png new file mode 100644 index 0000000..f778aad Binary files /dev/null and b/background/显示数据集.png differ diff --git a/background/显示数据集与曲线.png b/background/显示数据集与曲线.png new file mode 100644 index 0000000..881c7d4 Binary files /dev/null and b/background/显示数据集与曲线.png differ diff --git a/background/未选中.png b/background/未选中.png new file mode 100644 index 0000000..a1355cf Binary files /dev/null and b/background/未选中.png differ diff --git a/background/生成数据集.png b/background/生成数据集.png new file mode 100644 index 0000000..c5454aa Binary files /dev/null and b/background/生成数据集.png differ diff --git a/background/矩形.png b/background/矩形.png new file mode 100644 index 0000000..2907e8e Binary files /dev/null and b/background/矩形.png differ diff --git a/background/背景图片.png b/background/背景图片.png new file mode 100644 index 0000000..a12bebe Binary files /dev/null and b/background/背景图片.png differ diff --git a/background/装载.png b/background/装载.png new file mode 100644 index 0000000..7c605f4 Binary files /dev/null and b/background/装载.png differ diff --git a/background/选中.png b/background/选中.png new file mode 100644 index 0000000..abd6f42 Binary files /dev/null and b/background/选中.png differ diff --git a/data.py b/data.py new file mode 100644 index 0000000..e1684ac --- /dev/null +++ b/data.py @@ -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 diff --git a/dot.png b/dot.png new file mode 100644 index 0000000..ac2ba66 Binary files /dev/null and b/dot.png differ diff --git a/dot2.png b/dot2.png new file mode 100644 index 0000000..1fac0d3 Binary files /dev/null and b/dot2.png differ diff --git a/dot5.png b/dot5.png new file mode 100644 index 0000000..0eba4a9 Binary files /dev/null and b/dot5.png differ diff --git a/function.py b/function.py new file mode 100644 index 0000000..5a89ef8 --- /dev/null +++ b/function.py @@ -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 diff --git a/functions.xlsx b/functions.xlsx new file mode 100644 index 0000000..f157103 Binary files /dev/null and b/functions.xlsx differ diff --git a/functions_new.xlsx b/functions_new.xlsx new file mode 100644 index 0000000..4b84662 Binary files /dev/null and b/functions_new.xlsx differ diff --git a/input.py b/input.py new file mode 100644 index 0000000..e092817 --- /dev/null +++ b/input.py @@ -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) diff --git a/line.png b/line.png new file mode 100644 index 0000000..17984a0 Binary files /dev/null and b/line.png differ diff --git a/main.py b/main.py new file mode 100644 index 0000000..5596b44 --- /dev/null +++ b/main.py @@ -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/ diff --git a/new_line.png b/new_line.png new file mode 100644 index 0000000..3c178b5 Binary files /dev/null and b/new_line.png differ diff --git a/test/一次函数.txt b/test/一次函数.txt new file mode 100644 index 0000000..1b60975 --- /dev/null +++ b/test/一次函数.txt @@ -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 diff --git a/test/三次函数.txt b/test/三次函数.txt new file mode 100644 index 0000000..eb6c019 --- /dev/null +++ b/test/三次函数.txt @@ -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 diff --git a/test/二次函数.txt b/test/二次函数.txt new file mode 100644 index 0000000..10614a7 --- /dev/null +++ b/test/二次函数.txt @@ -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 diff --git a/test/四次函数.txt b/test/四次函数.txt new file mode 100644 index 0000000..9023afe --- /dev/null +++ b/test/四次函数.txt @@ -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 diff --git a/test/对数.txt b/test/对数.txt new file mode 100644 index 0000000..32d83cc --- /dev/null +++ b/test/对数.txt @@ -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 diff --git a/test/指数函数.txt b/test/指数函数.txt new file mode 100644 index 0000000..d34b980 --- /dev/null +++ b/test/指数函数.txt @@ -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 diff --git a/test/数据集生成.py b/test/数据集生成.py new file mode 100644 index 0000000..6360f03 --- /dev/null +++ b/test/数据集生成.py @@ -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])