Transcript Document
MATLAB測位プログラミングの
基礎とGT (3)
東京海洋大学産学官連携研究員
高須 知二
行列演算プログラミング
•
•
•
•
•
行列生成
行列操作
行列演算
\ (バックスラッシュ)
組込関数
行列生成 (1)
• 空 : a=[];
• スカラー (0次元配列) :
a=1; b=3+3i; c=pi; d=NaN; c=Inf;
• ベクトル (1次元配列) : a=[1 2]; b=[3;4;5]
• 行列 (2次元配列) : a=[1 2 3 4; 5 6 7 8];
• (3階以上) テンソル(3次元以上配列)
a=cat(3,[1 2 3;4 5 6],[7 8 9;10 11 12]);
行列生成 (2)
•
•
•
•
零行列 : a=zeros(10); a=zeros(4,5);
単位行列 : a=eye(10);
等間隔(行)ベクトル : a=1:10; b=0:-0.5:-10;
単一値行列:
a=ones(10); a=4*ones(10);
a=repmat(NaN,10,10); a(1:10,1:10)=Inf;
• 乱数 : a=rand(10); a=randn(10,1);
行列生成 (3)
• 要素への直接代入
a(1,1)=1; a(1,2)=2; a(1,3:7)=3;
• 行列サイズ自動拡張 (ゼロfill)
clear; a(10,8:10)=1;
• 行列の連結
a=[1 2 3]; b=[4 5]; c=[a b];
d=[1:4 10:12 8:-1:6];
e=[[1;2;3];[[4;5;6],[7;8;9]]];
行列操作 (1)
• 要素参照・代入
a=[1 2 3 4;5 6 7 8;9 10 11 12];
b=a(1,3); c=a(:,1); d=a(2,:); e=a(1:3,1:2);
f=a([1 2],[1 3]); g=a(end,2); h=(1,end-2);
k=a([1 1 1 1 1],[1 2 1 2]);
a(1,1)=-1; a(1,2:3)=0; a(end,:)=3:6;
• 行列サイズ、次元
[n,m]=size(a); n=length(b); n=ndims(c);
行列操作 (2)
• 転置
a=[1 2 3;4 5 6;7 8 9]; b=a'; c=(1:10)'; (or .')
• サイズ変更
b=reshape(a,9,1);
c=a(:); d=zeros(1,9); d(:)=a;
• 交換
b=a(:,[2 1 3]); c=a([3 2 1],[3 1 2]);
d=flipud(a); e=fliplr(a);
行列操作 (3)
• 要素追加
a=[1 2 3;4 5 6;7 8 9];
b=[a;[10 11 12]]; b=[10;11;12;a];
a(end+1,:)=[10 11 12];
• 要素削除
a(:,1)=[]; a(end,:)=[];
行列操作 (4)
• FIND() : 非ゼロ要素のインデックス
a=[0 0 0 1 0 1]; i=find(a); i->4;6
a=[2 0;0 1;0 0]; [i,j]=find(a); i->1;2, j=1;2
• ベクトル演算関数、演算子との組み合わせ
→forループ代替 : matlab表現, 実行効率
• 行列要素参照中ではfind()を省略可能
a(find(a<0)) <-> a(a<0)
a(find(a(:,1)==3),end) <-> a(a(:,1)==3,end)
行列操作 (5)
• 例1 : 0.5未満の要素の個数を数える
(1) n=0; for i=1:length(a), if a(i)<0.5, n=n+1; end, end, n
(2) n=length(find(a<0.5))
(3) n=sum(a<0.5)
• 例2 : NaN以外の値の平均を求める
(1) s=0;n=0;
for i=1:length(a)
if ~isnan(a(i)), s=s+a(i); n=n+1; end
end, m=s/n
(2) m=mean(a(~isnan(a)))
行列操作 (6)
• 例3 : for文とfindの組み合わせ
a=rand(100,4);
for i=find(a(:,1)<0.5)'
disp(sprintf('%f',a(i,:)))
end
行列演算 (1)
•
•
•
•
•
•
•
加減算:行列+スカラー : A+2, 3+A
加減算:行列+行列 : A+B
乗算:行列×スカラー : A*4, 5*A
乗算:行列×行列 : A*B
要素乗算:行列×行列 : A.*B
べき乗 : A^3 =A*A*A (A:正方行列)
要素べき乗:A.^3
行列演算 (2)
• 比較 (==, ~=, <, >, <= >=)
行列 : 行列
行列 : スカラー
結果は(0,1)要素行列で得られる→FIND()
• 零行列判定 : isempty(a) (×a==[])
• 行列内容一括比較
c=isequal(a,b) (サイズ+内容)
d=all(all(a>b)); e=any(any(a<b));
\ (バックスラッシュ) (1)
• 線形方程式(系)
ym1 Amn xn1
y1 a11x1 a12x2 a13x3 ... a1n xn
y2 a21x1 a22x2 a23x3 ... a2n xn
y3 a31x1 a32x2 a33x3 ... a3n xn
...
ym am1 x1 am2 x2 am3 x3 ... am nxn
\ (バックスラッシュ) (2)
• matlabでの解法 : x=A\y
(1) n=m : 線形方程式→ ガウス消去法 等
(2) n<m : 最小二乗解→QR分解
(3) n>m : 一般解の一つ (basic解?)
• Aが三角、対称、スパースか否か等を判定
し最適(精度、効率)な解法を内部選択
• x=y/A (スラッシュ)→y=x*Aの解
A/B = (B'\A')'
\ (バックスラッシュ) (3)
• 例1 : 観測値の2次多項式フィッティング
(1) A=[x.^2 x ones(size(x))]; a=A\y;
(2) a=polyfit(x,y,2);
• 例2 : 単独測位アルゴリズム
最小二乗各種解法 (1)
x=A\y;
x=(A*A')\(A'*y);
x=inv(A*A')*(A'*y);
R=chol(A‘*A); x=R\(R'\(A'*y));
[Q,R]=qr(A,0); x=R\(Q'*y);
10.8s Matlab任せ
5.3s 正規方程式
6.0s
正規方程式
5.2s コレスキ分解
11.8s
QR分解
[U,D,V]=svd(A,0); x=V*(D\(U'*y)); 46.4s 特異値分解
x=pinv(A)*y;
51.9s 疑似逆行列
(n=1000, m=5000, Pentium 4 3.2GHz, Matlab 6.5.1)
最小二乗の各種解法 (2)
• Aがランク落ちしていた場合の動作の違い
(1) x=A\y;
→ ランク落ち警告+ basic解
(2) x=inv(A'*A)*(A'*y)
→ エラーまたは不正解
(3) x=pinv(A)*y;
→警告無し、ノルム最小解
• 基本的に(2)は使うべきでない。
大規模最小二乗問題 (1)
•
•
•
•
パラメータ数>数1000
観測データ数>数100000
計画行列が実メモリ上に載り切らない
実用的なパラメータ推定問題ですぐ現れる
→
計算は結構やっかい
大規模最小二乗問題 (2)
• 戦略1:逐次最小二乗に置き換え
1
x ( A A) A y x
T
T
( A A ) ( A
1
T
i
i
i
T
yi )
• 戦略2 : カルマンフィルタに置き換え
• 戦略3 : スパース計画行列 + matlab + \
• 戦略4 : 最小二乗演算ライブラリを使う
行列用組込関数 (1)
• 行列用演算 :
diag(), norm(), rank(), det(), trace(), inv(),
dot(), cross(), meshgrid()... (see help)
• 行列入力→行列出力関数 :
sin(), cos(), tan(), sqrt(), exp(), log(), floor(),
mod(), ...
(ほとんどの初等関数、特殊関数)
• スカラ計算式→行列計算式
行列用組込関数 (2)
• 例1 :
• 例2 : 2次元メッシュ/3Dグラフ生成
[x,y]=meshgrid(0:0.1:20,0:0.1:20);
surf(x,y,sin(x)+cos(y))
行列演算高速化 (1)
• 行列サイズの事前割当
→サイズ自動拡張をなるべく使わない
• 行列のまま計算、find()の利用
→forループをなるべく使わない
• find()の高速化 :
インデックス操作の工夫
sort(), sortrows(); unique(), intersect()
行列演算高速化 (2)
• 例1 : 100万回ループ
x=0:0.1:100000; y=zeros(1000000,1);
y=sin(x);→0.4秒
for i=1:length(x), y(i)=sin(x(i)); end;→3秒
• 例2 : 100万回ループ
x=zeros(1000000,1);
for i=1:length(x), x(i)=i; end→1.4秒
x=[]; for i=1:1000000, x=[x;i]; end>1000秒