質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

4回答

2420閲覧

Pythonで行列の計算をしたい。

takes.it.easy

総合スコア18

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/07/23 09:44

編集2020/07/23 16:38

Pythonで行列の計算をし,パラメータを算出したいです.xとyの値は例として挙げています.予定ではクリックで点を生成し,その点をふやしていくことを考えています.つまり点の個数が決まっていなくても,図のような行列の計算はできますでしょうか.最終的な結果としてcというパラメータの値を取り出したいです.
よろしくお願い致します.

(追記)
手計算によって求めた解を載せます。また,これらの行列は離散点を3次スプライン補間をする際の3次多項式のパラメータの一部(c)を求める式になります。
よろしくお願い致します。

xy
00
13
43
51
82

イメージ説明

手計算によって求めた解

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

can110

2020/07/23 10:07 編集

まずは点の数がたとえば5個と決まっている場合はコードは書けますでしょうか? 書けない場合でも、A,bおよびcを手計算で求めた結果を提示ください。 さらに、この問題、数式に名前(~の式、~の解法など)がある場合はそれを提示ください。
can110

2020/07/23 17:05

Aの最も右下の値は0ではなく1のはずではないでしょうか? またb=[ 0 -9 -6 7 0]ではないでしょうか? 今一度、数式または手計算の結果が正しいか確認ください。
takes.it.easy

2020/07/24 03:53

どちらもおっしゃる通りです。再度計算すると b=[0, -9, -6, 7, 0] c=[0, -0.930556, -0.518519, 0.939815, 0] となりました。
guest

回答4

0

x,yにリストとして座標を追加し、numpyの配列に変換すれば以下のソースコードで計算できると思います。
Ax=rとして解いた。a,b,c,dは三次関数の係数。

python

1import numpy as np 2 3x = np.array([0, 1, 4, 5, 8]) 4y = np.array([0, 3, 3, 1, 2]) 5n = len(x)-1 6h = x[1:]-x[:-1] 7a = y 8 9# 対角成分 10Adiag = np.eye(n+1) 11Adiag[1:-1, 1:-1] *= 2*(h[:-1]+h[1:]) 12 13# 対角成分の一つ下の斜めの成分 14Alower = np.eye(n+1, k=-1) 15Alower[1:, :-1] *= h 16Alower[-1, -2] = 0 17 18# 対角成分の一つ上の斜めの成分 19Aupper = np.eye(n+1, k=1) 20Aupper[:-1, 1:] *= h 21Aupper[0, 1] = 0 22 23A = Adiag + Alower + Aupper 24 25# Aの逆行列 26Ainv = np.linalg.inv(A) 27 28r = np.zeros(n+1) 29r[1:-1] = (3/h)[1:]*(a[2:]-a[1:-1])-(3/h)[:-1]*(a[1:-1]-a[:-2]) 30 31c = np.dot(Ainv, r) 32 33d = (c[1:]-c[:-1])/(3*h) 34b = (a[1:]-a[:-1])/h-h/3*(2*c[:-1]+c[1:]) 35print("x", x, "y", y) 36print("h", h, "a", a) 37print("A") 38print(A) 39print("r", r) 40 41print("a", a) 42print("b", b) 43print("c", c) 44print("d", d)

text

1x [0 1 4 5 8] y [0 3 3 1 2] 2h [1 3 1 3] a [0 3 3 1 2] 3A 4[[1. 0. 0. 0. 0.] 5 [1. 8. 3. 0. 0.] 6 [0. 3. 8. 1. 0.] 7 [0. 0. 1. 8. 3.] 8 [0. 0. 0. 0. 1.]] 9r [ 0. -9. -6. 7. 0.] 10a [0 3 3 1 2] 11b [ 3.31018519 2.37962963 -1.96759259 -1.5462963 ] 12c [ 0. -0.93055556 -0.51851852 0.93981481 0. ] 13d [-0.31018519 0.04578189 0.48611111 -0.10442387]

イメージ説明
イメージ説明

投稿2020/07/23 11:26

編集2020/07/23 21:22
Penpen7

総合スコア698

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takes.it.easy

2020/07/24 04:11

丁寧な回答をありがとうございます。 お聞きしたいのですが、  h = x[:1] - x[:1] という記述は,  h = x[i] - x[i-1] と同様に扱ってもよいものなのでしょうか。
Penpen7

2020/07/24 04:22 編集

h = x[1:]-x[:-1]は for i in range(1, len(x)): h = x[i]-x[i-1] と同等になりますね。 x[1:]は要素x[1]からx[n-1]までの配列を表しており、 x[:-1]は要素x[0]からx[n-2]までの配列を表しています。 これを上から下に引くと, x[1]-x[0], x[2]-x[1], ... , x[n-1]-x[n-2] の成分をもつhが得られ, for文を使わなくとも一括で複数のデータが得られることになります。 かなりこのソースコードではnumpyのスライス機能を使っているので、初めはわかりにくいのかもしれませんが、慣れるとfor文を書かずに済み、実行速度が上がり、ソースコードがスッキリします。 もちろんfor文で貪欲に書いてもいいですが、その分反復回数が増えると遅くなります。
takes.it.easy

2020/07/24 08:29

ありがとうございます。 スプライン曲線を描く際,このコードではノンパラメトリックとして計算されていると思いますが,xは短調増加でなくてはならない制限を解決したく、パラメトリックの式として描画したいと考えています。パラメトリックな3次多項式とするにはどのようにすればよういでしょうか。変数をtとおいたときのx,yの式やパラメータの算出などご教授いただけると幸いです。
Penpen7

2020/07/24 09:19 編集

パラメトリックの式ではxは任意の順序でもスプライン曲線を描けるという理由が申し訳ありませんが、わかりませんでした... それよりもxが常に単調増加するように座標を挿入するところを選んで挿入するか、スプライン曲線を描く前にxとyの対応を崩さないようにxをソートしてから各パラメータを求めるようにするのが自然なように感じます。例えば, xとyの対応を崩さないようにソートする場合は y = y[np.argsort(x)] x = np.sort(x) でxを単調増加数列に変えることができます。 なお、スプライン曲線は三次関数を滑らかに繋いでいるにすぎないため、三次関数をパラメータ表示できるかということと同値ですが、それは可能だと思います。(が、やって効果はあるかは不明です)
Penpen7

2020/07/25 14:04

媒介変数表示しても一切やることは変わらないので(文字が入れ替わるだけ)、回答を参考に改変してください。
guest

0

ベストアンサー

パラメータ表示でやってみた。

python

1import numpy as np 2import matplotlib.pyplot as plt 3 4# スプライン曲線のパラメータを求める。 5def calculateSplineParameter(x): 6 # t = 0,1,2,...,x.size-1とする。 7 n = x.size-1 8 h = np.ones(n) 9 a = x 10 11 # 対角成分 12 Adiag = np.eye(n+1) 13 Adiag[1:-1, 1:-1] *= 2*(h[:-1]+h[1:]) 14 15 # 対角成分の一つ下の斜めの成分 16 Alower = np.eye(n+1, k=-1) 17 Alower[1:, :-1] *= h 18 Alower[-1, -2] = 0 19 20 # 対角成分の一つ上の斜めの成分 21 Aupper = np.eye(n+1, k=1) 22 Aupper[:-1, 1:] *= h 23 Aupper[0, 1] = 0 24 25 A = Adiag + Alower + Aupper 26 27 # Aの逆行列 28 Ainv = np.linalg.inv(A) 29 30 r = np.zeros(n+1) 31 r[1:-1] = (3/h)[1:]*(a[2:]-a[1:-1])-(3/h)[:-1]*(a[1:-1]-a[:-2]) 32 33 c = np.dot(Ainv, r) 34 d = (c[1:]-c[:-1])/(3*h) 35 b = (a[1:]-a[:-1])/h-h/3*(2*c[:-1]+c[1:]) 36 37 return [a,b,c,d] 38 39# 三次関数の係数から, 元の点から間の点を求める。 40def calculateInterpolationPoints(splineParameter, orignalPointsNumber, interpolationPointsNumber=1000): 41 a, b, c, d = splineParameter 42 43 index = np.repeat(np.arange(orignalPointsNumber-1), interpolationPointsNumber, axis=0) 44 t = np.tile(np.linspace(0, 1, interpolationPointsNumber), orignalPointsNumber-1) 45 46 return a[index] + b[index]*t + c[index]*t**2 + d[index]*t**3 47 48# 補間したい点の座標 49x = np.random.rand(20) 50y = np.random.rand(x.size) 51 52parameterX = calculateSplineParameter(x) 53parameterY = calculateSplineParameter(y) 54 55X = calculateInterpolationPoints(parameterX, x.size) 56Y = calculateInterpolationPoints(parameterY, y.size) 57 58plt.plot(X, Y, label="spline curve") 59plt.plot(x, y, marker='o', linestyle='None', label='original points') 60plt.legend() 61plt.savefig("graph.png", dpi=200,figsize=(4,3))

イメージ説明

周期3次スプライン曲線を使って閉曲線にしました。
Periodic cubic smoothing splines as a quadratic
minimization problem

python

1import numpy as np 2import matplotlib.pyplot as plt 3 4 5# 周期3次スプライン曲線のパラメータを求める。 6def calculatePeriodicSplineParameter(x): 7 # t = 0,1,2,...,x.size-1とする。 8 n = x.size - 1 9 h = np.ones(n) 10 a = x 11 12 # 対角成分 13 Adiag = np.zeros((n, n)) 14 Adiag[1:, 1:] = np.diag(2 * (h[:-1] + h[1:])) 15 Adiag[0][0] = 2 * (h[-1] + h[0]) 16 Alower = np.diag(h[:-1], k=-1) 17 Aupper = np.diag(h[:-1], k=1) 18 19 A = Adiag + Alower + Aupper 20 A[-1][0] = h[-1] 21 A[0][-1] = h[-1] 22 23 # 対角成分 24 Vdiag = np.zeros((n, n)) 25 Vdiag[1:, 1:] = np.diag(-(1 / h[:-1] + 1 / h[1:])) 26 Vdiag[0][0] = -(1 / h[-1] + 1 / h[0]) 27 Vlower = np.diag(1 / h[:-1], k=-1) 28 Vupper = np.diag(1 / h[:-1], k=1) 29 30 V = Vdiag + Vlower + Vupper 31 V[-1][0] = h[-1] 32 V[0][-1] = h[-1] 33 34 r = 3 * np.dot(V, a[:-1]) 35 36 c = np.linalg.solve(A, r) 37 38 c = np.insert(c, c.size, c[0]) 39 40 d = (c[1:] - c[:-1]) / (3 * h) 41 b = (a[1:] - a[:-1]) / h - h / 3 * (2 * c[:-1] + c[1:]) 42 a = a[:-1] 43 c = c[:-1] 44 return [a, b, c, d] 45 46 47# 三次関数の係数から, 元の点から間の点を求める。 48def calculateInterpolationPoints(splineParameter, 49 interpolationPointsNumber=1000): 50 a, b, c, d = splineParameter 51 assert (a.size == b.size == c.size == d.size) 52 index = np.repeat(np.arange(a.size), interpolationPointsNumber, axis=0) 53 t = np.tile(np.linspace(0, 1, interpolationPointsNumber), a.size) 54 return a[index] + b[index] * t + c[index] * t**2 + d[index] * t**3 55 56 57# 補間したい点の座標 58x = np.random.rand(100) 59y = np.random.rand(x.size) 60x = np.insert(x, x.size, x[0]) 61y = np.insert(y, y.size, y[0]) 62 63parameterX = calculatePeriodicSplineParameter(x) 64parameterY = calculatePeriodicSplineParameter(y) 65 66X = calculateInterpolationPoints(parameterX) 67Y = calculateInterpolationPoints(parameterY) 68 69plt.plot(X, Y, label="spline curve") 70plt.plot(x, y, marker='o', linestyle='None', label='original points') 71plt.legend() 72plt.savefig("graph.png", dpi=200, figsize=(4, 3)) 73

イメージ説明

投稿2020/07/25 15:45

編集2020/07/26 07:05
Penpen7

総合スコア698

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takes.it.easy

2020/07/27 03:16

ありがとうございます。 勉強させていただきます。
guest

0

予定ではクリックで点を生成し,その点をふやしていくことを考えています.

上記を実現するため、クラスを使って以前の状態を保持しておく例です。
なお、点の追加において、x値`は単純増加で与える(制御点が左側にぐるっと戻らない)ことが前提です。

Python

1import numpy as np 2import matplotlib.pyplot as plt 3 4# 3次スプライン補間法 5# http://www.civil.kumamoto-u.ac.jp/matsu/spline.pdf 6 7class Spline: 8 # xys : 最低3点ある配列 9 def __init__(self, xys): 10 self.xys = np.array(xys) 11 N = self.xys.shape[0] 12 assert N >= 3 13 14 self.h = np.array([self.xys[i,0]-self.xys[i-1,0] for i in range(1,N)]) 15 self.a = self.xys[:,1] 16 17 self.A = np.eye(N) 18 for i in range(2,N): 19 self.A[i-1,i-2:i+1] = self.get_A_line(i) 20 21 self.r = np.zeros(N) 22 for i in range(2,N): 23 self.r[i-1] = self.get_r_val(i) 24 25 # 指定行のAの値を計算して返す 26 def get_A_line(self, i): 27 return [self.h[i-2], 2*(self.h[i-2]+self.h[i-1]), self.h[i-1]] 28 29 # 指定位置のrの値を計算して返す 30 def get_r_val(self, i): 31 return 3*(self.a[i]-self.a[i-1])/self.h[i-1] - 3*(self.a[i-1]-self.a[i-2])/self.h[i-2] 32 33 # 新たな点を追加 34 def add(self,xy): 35 self.xys = np.vstack([self.xys, np.array(xy)]) 36 N = self.xys.shape[0] 37 self.h = np.append(self.h, self.xys[N-1,0]-self.xys[N-2,0]) 38 self.a = self.xys[:,1] 39 40 Anew = np.zeros((N,N)) 41 Anew[0:N-1,0:N-1] = self.A 42 self.A = Anew 43 self.A[N-2,N-3:N] = self.get_A_line(N-1) 44 self.A[N-1,N-1] = 1 45 46 self.r = np.append(self.r, 0) 47 self.r[N-2] = self.get_r_val(N-1) 48 49 # パラメータを算出 50 def calc_param(self): 51 Ainv = np.linalg.inv(self.A) 52 self.c = np.dot(Ainv, self.r) 53 N = self.xys.shape[0] 54 self.b = np.array([ (self.a[i]-self.a[i-1])/self.h[i-1] - self.h[i-1]/3*(2*self.c[i-1]+self.c[i]) for i in range(1,N)]) 55 self.d = np.array([ (self.c[i]-self.c[i-1])/(3*self.h[i-1]) for i in range(1,N)]) 56 57 # 補間されたy値を返す 58 def get_y(self, x): 59 xs = self.xys[:,0] 60 if x < xs[0] or x > xs[-1]: 61 return 0 62 elif x == self.xys[0,1]: 63 return xs[0] 64 elif x == xs[-1]: 65 return self.xys[-1,1] 66 67 # 区間を決定 68 i = 0 69 while True: 70 if xs[i] > x: 71 break 72 i += 1 73 i -= 1 74 75 dx = (x-xs[i]) 76 return self.a[i] + self.b[i]*dx + self.c[i]*dx*dx + self.d[i]*dx*dx*dx 77 78 79sp = Spline([[0,0],[1,3],[4,3]]) # 初期の3点は最初に与える 80sp.add([5,1]) 81sp.add([8,2]) 82sp.calc_param() 83 84print(sp.r)# [ 0. -9. -6. 7. 0.] 85print(sp.a)# [0 3 3 1 2] 86print(sp.b)# [ 3.31018519 2.37962963 -1.96759259 -1.5462963 ] 87print(sp.c)# [ 0. -0.93055556 -0.51851852 0.93981481 0. ] 88print(sp.d)# [-0.31018519 0.04578189 0.48611111 -0.10442387] 89 90# 描画 91xs = np.linspace( np.min(sp.xys[:,0]), np.max(sp.xys[:,0]), 100) 92ys = np.array([sp.get_y(x) for x in xs]) 93plt.scatter(sp.xys[:,0], sp.xys[:,1]) 94plt.plot(xs, ys) 95plt.show()

イメージ説明

投稿2020/07/24 04:23

can110

総合スコア38262

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takes.it.easy

2020/07/24 07:14

丁寧な回答ありがとうございます。 こちらのコードではxは単純増加ということですが、自由な曲線を描くために、媒介変数t(0≦t≦1)を用いて、補間したいと考えています。媒介変数でスプライン補間をする場合、それぞれのパラメータはどのように決めるのでしょうか。
can110

2020/07/24 10:46

> こちらのコードではxは単純増加ということですが もともとの数式、考えが単純増加を前提としていると思うのですが、違いますでしょうか? > 自由な曲線を描くために~ そのようにできる数式、考えはどのようなものでしょうか?
takes.it.easy

2020/07/25 04:58

もともとの式はxが決まるとyが決まってしまうため、コースを一周するような曲線を描くことができません。そこで変数tを用いて媒介変数表示してみたらどうかと考えています。 t = [0,1] h = t_i+1 - t_i x(t) = a_x + b_x * t + c_x * t^2 + d_x * t^3 a_x,i = x_i y(t) = a_y + b_y * t + c_y * t^2 + d_y * t^3 a_y,i = y_i よろしくお願いします。 参考サイト:https://tajimarobotics.com/cubic-spline-interpolation-parameter/
can110

2020/07/25 05:12

なるほど。 まずは固定の点の数で動くコードを書いてみてはいかがでしょうか?
guest

0

できるかとという問いでしたら、できます。
numpy.insert()とかで行と列を拡張していけばいいんではないでしょうか。

投稿2020/07/23 09:54

jeanbiego

総合スコア3966

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問