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) • 線形方程式(系) y m1 Amn x n1 y1 a11 x1 a12 x2 a13 x3 ... a1n xn y 2 a 21 x1 a 22 x2 a 23 x3 ... a2 n xn y3 a31 x1 a32 x2 a33 x3 ... a3n xn ... y m a m1 x1 a m 2 x2 a m3 x3 ... amn xn \ (バックスラッシュ) (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 i T (A Ai ) 1 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秒
© Copyright 2024 ExpyDoc