- ベストアンサー
スプライン関数を使ってデータ数を揃える方法
- matlab初心者の方が、データ数が異なる2つのデータ群をスプライン関数を使って揃える方法について質問しています。データ数の揃え方によって、後の検定をスムーズに行うことができます。
- 例えば、AとBという2つの条件で5秒ごとの心拍を測定する場合、データ数が異なっていることがあります。この場合、スプライン関数を使ってデータ数を揃えることができます。
- 具体的には、データ数の多い方のデータを補完することでデータ数を揃えることができます。プログラムを組む際には、matlabのスプライン関数を使用することで簡単に実現することができます。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
Kules Part5です。 >Kulesさんに添付していただいたグラフのように曲線になっておらず >点と点の間が直線になっていました。 >そこでツール→基本的な近似→スプライン補間とすると >曲線になり、補間したグラフに元データがのっていました。 >使用しているmatlabはR2010aですが >このような方法であっていますでしょうか? というかそもそも前回黒線をどうやって描いていたのかって話になるんですが…。 元のデータ(青丸)を直線で結んでも補間データ(赤丸)を直線で結んでも黒線はできません。 黒線は全く別の方法で引いています(A No.3にも書いていますが) >そこでツール→基本的な近似→スプライン補間とすると >曲線になり、補間したグラフに元データがのっていました。 ということは添付図で言うところの赤丸に対してツールからスプライン補間を選択したんでしょうか? ん~まあそれでも思ったものは出ると思います。問題ないんじゃないかと。 ただ私の黒線は別の方法で描いています。 参考になれば幸いです。
その他の回答 (4)
- Kules
- ベストアンサー率47% (292/619)
Kules Part4です。 >どういった補間が今回の場合、適しているのかはなんとも判断しずらい状況です。 これは…私にもどうしようもないです(笑)私自身SPSSの何たるかも全く知りません。 ここに関しては私以外の人が答えた方がよいでしょう。 >実際のデータで私が行うとわずかですが線にのらないものもありました。 これはいくつか理由が考えられます。 (1)黒線の分解能が足りていない (2)縦軸(x方向)の設定が間違えている (1)の場合は確認は簡単です。黒線ではなく黒点で描けば、赤丸が黒点のいないところにあるのがわかると思います。 (2)の場合はちょっと難しいですね…スクリプトの全部を見ても理由がわかる自信はありません。 ただ、補足を見る限りはlinspaceの使い方や:を使った等差数列の作り方に若干の不安が残るので、 その辺りを確認する必要があるかも。 ただ、私が添付したグラフも本当に載っている保証はありません。spline関数の内挿がどの程度の精度を持っているのかもわかりませんし。 添付のグラフでちょっとずれてるかも…ぐらいのレベルではなく明らかにわかるぐらいずれているんでしょうか?その辺り補足願います。 参考になれば幸いです。
補足
たびたびご返答ありがとうございます。 いろいろ検討してみましたが どうやらグラフの描き方に問題があったようです。 Kulesさんに添付していただいたグラフのように曲線になっておらず 点と点の間が直線になっていました。 そこでツール→基本的な近似→スプライン補間とすると 曲線になり、補間したグラフに元データがのっていました。 使用しているmatlabはR2010aですが このような方法であっていますでしょうか? 基本的なことをすみません。
- Kules
- ベストアンサー率47% (292/619)
三度Kulesです。 とりあえず謝罪と訂正です。 size(B)は最低2要素のベクトルを出力すると言いましたが、 :を使ったベクトルの生成などに使った時は1つ目の要素のみ出力するみたいです。 従って、13行1列のベクトルの場合は13を出力しますし、1行13列のベクトルの場合は1を出力します。また、関数を使って行列を生成する時、例えばlinspace(1,10,size(B))とする時にはエラーが出ます。 やはりsizeというと(縦、横)と2要素以上持っているイメージになりやすいので、ベクトルの長さを出力するlengthや、行列の要素の数を出力するnumelを使った方が、イメージに即したものになるんじゃないかなあ…と思います。別に直さなくてもいいんですけどね。 また、蛇足ではありますがアドバイスです。質問者様のベクトル表記が A=[80,82,…,87]; となっていたため私は横ベクトルと解釈し、それを解消するため補足で改行を用いて縦ベクトルを表現して下さったのだとは思いますが、 縦ベクトルを表現したければ A=[80;82;…;87]; のように;(セミコロン)を使っていただければMatlabやっている人間には通じますので。 改行使うと文章が縦に伸びてわかりにくいですしね。 本題に入ります。 まずspline関数についてですが、これは3次スプライン内挿という操作をしています。 3次スプラインとは、ざっくり言ってしまうと「元となる配列において、各々2点を結ぶ3次関数を考える。各境目において、滑らかに接続するよう係数を決める」 ということです。 例えば元のx軸方向の配列が[1,2,4,5,8]だとすると、 ・1~2の間 ・2~4の間 ・4~5の間 ・5~8の間 をそれぞれ3次関数でつなげます。そして、全ての節点(今回でいうと1,2,4,5,8)で各区間の3次関数が滑らかにつながるようにします。 具体的には、1~2の間での3次関数におけるx=2での1次微分係数と、2~4の間を表わす3次関数におけるx=2での1次微分係数 が一致するようにします。同様に2次微分係数も一致するように係数を決めます。 このように書くと非常に複雑なことをしているように見えますが、実際は簡単な行列の積で求まるようです。 次に質問者様が書かれている手法についての是非ですが、結論から言うと 「スプライン内挿としては正しいが、意図しているものが出ているとは限らない」 ということになります。 添付図をご覧ください(正しく添付されるかな?) 青丸が元のデータ(13個あります) 黒線が0.01刻みでスプライン補間したデータ 赤丸がxxでスプライン補間したデータですが、 上の図はxx=1:size(B)/10:size(B); 下の図はxx=linspace(1,length(B),10)です。 両者とも、赤丸は黒線にのっていることから正しく補間されていることはわかりますが、 赤丸がいる位置は違います。 ここから先はどちらの形のデータが欲しいか、ということだと思います。 上の場合は10個目のデータと元の13個目のデータは一致しない形、 下の場合は一致する形になります。 これ以外のデータの取り方が必要であれば、そのようにxxを設定すれば済む話です。 どのような形の補間データが欲しいのでしょうか? 参考になれば幸いです。
補足
再三のご回答ありがとうございます。 図まで添付していただいて大変感謝しております。 今回、このようなことをしているのはSPSSで条件間に有意差があるのか ということを検定するためです。 しかし、データ数が異なると検定はできるのですが例でいうBの最後3つの データが全く無視されて、Bの10個までのデータとAとで検定するような仕様になっています。 そういったことを回避するためにデータ数を揃えようという発想が出てきたのですが どういった補間が今回の場合、適しているのかはなんとも判断しずらい状況です。 また、回答者様の添付図ですと赤丸がすべて黒線にのっていたのですが 実際のデータで私が行うとわずかですが線にのらないものもありました。 これはデータ数が多いために起こる現象なのでしょうか? (データ数は120ほどで、 plot(x,y,'o',xx,yy) と入力しております。) もしくはなにか手違いが生じているのでしょうか? たびたび申し訳ないです。
- Kules
- ベストアンサー率47% (292/619)
再びKulesです。 x=1:size(B); y=B; xx=1:size(B)/10:size(B); yy=spline(x,y,xx); と教わりました。 う~んこの書き方で動いたんでしょうか?私の感覚からすると間違いなくエラーになるんですが(苦笑) まず、sizeという関数は入力変数が1つの場合最低2つの値を持つベクトルを出力します。 今回の場合Bはデータ数が13個の横ベクトルですので、 m=size(B) とした場合n=[1,13] となると思うのですが。:での等間隔のベクトルを作る時の一要素に使われる時はデフォルトでスカラー量を返してくれるんでしょうか? ちなみにこれでエラーが出る場合は、size(B)ではなくnumel(B)かlength(B)を使えば解決すると思います。 xx=1:size(B)/10:size(B); も相当怪しいですね。これだと等間隔のベクトルができないのでは?size(B)が13のことでれば、 xxの増分size(B)/10は1.3です。ということはxxをそのまま書くと xx=[1,2.3,3.6,4.9,6.2,7.5,8.8,10.1,11.4,12.7,13] となり、最後の2つの間隔が明らかに狭いですね。これは最初が1からスタートしていることが原因です。 そういう意味では最初を1ではなくsize(B)/10にすればよいと思います。あるいは xx=(1:10)/10*length(B);とか。 また、こうしたとしても10個のデータと時系列を合わせられるかというとそんなことはありません。 ただ、今回はどうやらデータの個数を合わせることのみが目的のようですので、それでもよさそうですね。 参考になれば幸いです。
補足
たびたびのご回答ありがとうございます。 説明不足だったのですがBは13×1で B=[76 83 86 90 94 95 93 87 86 89 93 79 90]; と入力しました。 help splineで例として表示されたものと同様に x=1:size(B); y=B; xx=1:size(B)/10:size(B); yy=spline(x,y,xx); というプログラムを入力してエラーなく結果が出力されたのですが splineについて無知なため、どういう原理で計算されていて このプログラムが今回の場合、正しいのか正しくないのかも理解しきれていません。 なにかアドバイス等ありましたら宜しくお願いしたいです。
- Kules
- ベストアンサー率47% (292/619)
データの数を揃えるためにスプライン関数を使うんですか? 確認なのですが、Aという条件もBという条件も5秒ごとのデータなんですよね? 私自身の知識も曖昧なのですが、もともとスプライン関数というのは補間をするためのものなので、 データの取得間隔をもっと狭くする(つまり、5秒ごとのデータから1秒ごとのデータを作り出す)時には 有効ですが、今回のように13個のデータを10個に揃えるといった使い方には使えないと思います。 もし仮に、10個のデータは5秒ごとで0秒~45秒、13個のデータも45/12秒ごとで0秒~45秒なんだけど、 13個のデータから5秒ごとのデータを作りたい、ということであれば、 Aの波形をBeatA、Bの波形をBeatBとして、 TimeA=linspace(0,45,10); TimeB=linspace(0,45,13); BeatB1=interp1(TimeB,BeatB,TimeA,'spline'); でBの波形から5秒ごとのデータを作ることができます。 「こういうことではないんだよ」とか「こういうことなんだけど、うまくいかないんだよ」とかありましたらその旨補足願います。 参考になれば幸いです。
補足
ご回答ありがとうございます。 先生にきいてみたところ、 x=1:size(B); y=B; xx=1:size(B)/10:size(B); yy=spline(x,y,xx); と教わりました。 これでデータの個数は揃えることができました。 ちなみにどこかおかしな点はありますか?
お礼
複数にわたるご回答ありがとうございました。 大変貴重なご意見でした。 最後の件に関しましては、 私の勘違いもあり、解決しました。 お騒がせしました。 また何かありましたら宜しくお願い致します。 ありがとうございました。