実現したいこと
多項式の係数を正しく導出する.
前提
pythonでcsvからデータを読み込み,
lu分解,前進代入,後退代入を用いて最小二乗法を行い,
得られた係数から曲線をプロットするプログラムを作りました.
しかし,検算のためにライブラリ(polyfit)を使用し求めたところ
自作したものから導出された係数と違う値が出ました.
1次式,2次式は正しくもとまりましたが,
3次式以降の係数が間違って導出されてしまいます.
発生している問題・エラーメッセージ
3次式近似の時の自作プログラムから導出された値 -62289409924.034035 93004892.05532321 -46288.47113927059 7.679190499441964 polyfit関数から求められた値 -3.12020048e+10 4.65818816e+07 -2.31807582e+04 3.84516090e+00
該当のソースコード
python
1import matplotlib.pyplot as plt 2import numpy as np 3import csv 4 5def read(filename): 6 csv_file = open(filename,'r') 7 x = [] 8 y = [] 9 for row in csv.reader(csv_file): 10 x.append(float(row[0])) 11 y.append(float(row[1])) 12 return x,y 13 14def a_list(x,n): 15 m = len(x) #データの個数 16 a = [[float(0.0) for i in range(n + 1)] for j in range(n + 1)] 17 for i in range(n + 1): 18 for j in range(n + 1): #n 19 sum_ = 0.0 20 for k in range(m): 21 sum_ += pow(x[k],i + j) 22 a[i][j] = sum_ 23 return a 24 25def b_list(x,y,n): 26 n += 1 27 b = [float(0.0) for i in range(n)] 28 m = len(x) 29 for i in range(n): 30 sum_ = 0.0 31 for k in range(m): 32 sum_ += y[k] * pow(x[k],i) 33 b[i] = sum_ 34 return b 35 36#a行列をLU分解 37def luBunkai(data,n): 38 n += 1 39 a = [[float(0.0) for i in range(n)] for j in range(n)] 40 b = [[float(0.0) for i in range(n)] for j in range(n)] 41 for i in range(n): 42 a[i][i] = 1.0 43 for j in range(n): 44 for i in range(j + 1): #j+1 45 sum_ = 0.0 46 for k in range(i): #i 47 sum_ += a[i][k] * b[k][j] 48 b[i][j] = data[i][j] - sum_ 49 50 for i in range(j + 1,n): #j #j+1 51 sum_ = 0.0 52 for k in range(j): #j 53 sum_ += a[i][k] * b[k][j] 54 a[i][j] = (data[i][j] - sum_) / b[j][j] #j 55 return a,b 56 57#前進代入 58def zensin(l,b,n): 59 n += 1 60 y = [float(0.0) for i in range(n)] 61 y[0] = b[0] / l[0][0] 62 for i in range(1,n): 63 sum_ = 0.0 64 for j in range(i): #i 65 sum_ += l[i][j] * y[j] 66 y[i] = (b[i] - sum_) / l[i][i] 67 return y 68 69#後退代入 70def koutai(y,u,n): 71 n += 1 72 x = [float(0.0) for i in range(n)] 73 x[n - 1] = y[n - 1] / u[n - 1][n - 1] 74 for i in range(n - 2,-1,-1): #n-1 75 sum_ = 0.0 76 for j in range(i + 1,n): #n 77 sum_ += u[i][j] * x[j] 78 x[i] = (y[i] - sum_) / u[i][i] 79 80 print("係数") 81 for _ in x: 82 print(_) 83 84 return x 85 86#得られた係数でプロットする関数 87def fit_plot(c,x,y,n): 88 n += 1 89 fit = 0.0 90 p = np.linspace(1996,2022,1000) 91 for i in range(n): 92 fit += c[i] * pow(p,i) 93 plt.plot(p,fit,label = "n =" + str(n - 1)) 94 plt.xlabel("year") 95 plt.ylabel("y") 96 plt.legend() 97 return 0 98 99#1~nまでプロットする 100#最終的に1~nとするためfor 101for n in range(3,4): 102 x,y = read("data.csv") 103 a = a_list(x,n) 104 b = b_list(x,y,n) 105 l,u = luBunkai(a,n) 106 lu_y = zensin(l,b,n) 107 c = koutai(lu_y,u,n) 108 fit_plot(c,x,y,n) 109plt.xlim(1995,2022) 110plt.ylim(3000,20000) 111plt.scatter(x,y,label = "data") 112plt.show() 113 114#検算 115for i in range(3,4): 116 p4 = np.polyfit(x, y, i) 117 print('ライブラリの値{0}'.format(p4)) 118 plt.plot(x, np.poly1d(np.polyfit(x, y, i))(x)) 119plt.xlim(1995,2022) 120plt.ylim(3000,20000) 121plt.scatter(x,y,label = "data") 122plt.show() 123 124"""data.datの内容 1251996,6216.833333333333 1261997,10050.819444444443 1271998,12947.568287037036 1281999,11282.380690586418 1292000,12065.031724215534 1302001,9488.919310351295 1312002,11673.326609195943 1322003,14021.860550766329 1332004,16618.821712563862 1342005,16300.151809380322 1352006,17646.09598411503 1362007,21248.091332009586 1372008,13241.674277667466 1382009,12615.556189805624 1392010,16353.713015817135 1402011,9480.726084651427 1412012,5124.893840387619 1422013,4430.157820032302 1432014,4850.513151669358 1442015,14092.876095972446 1452016,18467.406341331036 1462017,20329.700528444253 1472018,17423.975044037023 1482019,17081.74792033642 1492020,14347.562326694702 1502021,18582.130193891226 1512022,11001.927516157602 152""" 153 154
試したこと
プログラム中のa,b,l,u,y,xをトレースして,lu分解,前進代入,後退代入が間違っていないことを確認しました.
data.datを用いて最小二乗法を行う外部のツールで計算したところ,polyfit関数と同じ値になりました.
追記

回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2023/12/31 00:43