• ベストアンサー

MATLAB 複数のmkdirを実行したい

MATLAB 複数のmkdirを実行したい いつもお世話になります。 matlabにて pass={pass1,pass2,pass3} %pass1~3は文字列が格納されてます。 passnum=1:length(pass) mkdir(pass{passnum}) を実行しようと思ったんですが、引数が多すぎて無理でした。 forループなどを使えば実行出来るんですが、どうにかしてこのような簡易的な書き方で実行出来ないものなんでしょうか? お手数ですがご回答よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • Kules
  • ベストアンサー率47% (292/619)
回答No.4

4度目のKulesです。 >まだ少しだけ締め切らずにおいておきますが、自分でも頑張ってみますので無理なさらないで下さいね。 私自身それほど多くのMatlabの関数を知っているわけではありませんし、 大抵の処理は自分の知っている知識を使って力ずくで書き、 それで問題が発生(時間がものすごくかかるとか、メモリを半端じゃなく使ってメモリ不足と言われるとか) が起きて初めて他の手がないか探すような状況です。 こういった他の人のニーズを見ながら自分の知識を増やすことはマイナスにはなっていないのでご安心を(笑) さて、本題に入ります。 とりあえず今使うデータは、 =====の区切り線 変数がなんやかんや =====の区切り線 データ となってるわけですね? 変数部分は使うんでしょうか? もし使わないなら、 ・fid=fopen('ファイル名');でfidを取得してから、fgetl(fid)で変数の数+2回(=====の行2つ)データを読み捨てる なんかが簡単そうですね。 使うのであれば、今回の場合は(%などなど の行はないものとして扱います) fid=fopen('ファイル名'); textscan(fid,'%[=]'); a=textscan(fid,'wavestart=%d\n'); b=textscan(fid,'waveend=%d\n'); textscan(fid,'%[=]'); c=textscan(fid,'%f'); とすれば aにwavestartの値が、bにwaveendの値が、cに数値がそれぞれセル配列として入ります。 これでどれくらい時間がかかるんですかね…2000万行のdouble値を行列として確保できるかは 知りませんけど。 また、textscanを使っているのなら回数を減らして(500万ずつぐらい)複数回回すと早くなったり するかも。(配列サイズの関係で) 参考になれば幸いです。

aiueoborn
質問者

お礼

毎度ご回答ありがとうございます。 質問2にの所にちょうど補足2つ目を付け足したタイミングで回答を頂けるとは思いませんでした。 投稿時間たった1秒差でしたね。(笑) >こういった他の人のニーズを見ながら自分の知識を増やすことはマイナスにはなっていないのでご安心を(笑) そーいって頂けるなら幸いです。複数回答を頂いてますので手間かけて申し訳ないなぁと思っていたもので。 >変数部分は使うんでしょうか? はい、変数部は使ってます。例えばwavestart waveendは返したい値ですので、 if nargout > 1 .....色々..... .....色々..... if strfind(str, 'wavestart') [a, b, c, wavestart] = strread(str, '%s%s%s%f'); %a b cは wave start = を格納し、wavestartに値を%fで格納。 end; end; ....色々..... ....色々..... if nargout > 2 if strfind(str, 'waveend') [a, b, c, waveend] = strread(str, '%s%s%s%f'); end; という風に各々のデータを出力しています。a b c は使わないので放置してます。 >また、textscanを使っているのなら回数を減らして(500万ずつぐらい)複数回回すと早くなったり >するかも。(配列サイズの関係で) textscanの配列を分解してみるって所が気になったので試みました。 しかし プロパティを調べるとheadlinesで前半スキップは出来るんですが、 textscanを途中で止める方法が分からなく思いつかないので、まだ成功してません。。

その他の回答 (3)

  • Kules
  • ベストアンサー率47% (292/619)
回答No.3

三度Kulesです。 まあ乗りかかった船ってやつですよね(笑) >ところでプロファイラなんて便利な機能があったんですね。 ある程度どこで時間がかかっているのか分かっているならticとtocを使うという手もありますが、 ボトルネックを探すには素直にプロファイラを使うのが早いでしょうね。 fscanfとsaveasですか…どちらもちょっと迷いますね。 ただ1つ言えそうなのはどちらも割りと上流にある関数っぽいということでしょうか (違うかも知れませんが) 先ほど、forループを使わなくてもいいところではforループを使わない方が よいということを書きました。 これはMatlabを高速化する上で1つ重要なテクニックだと思います。 もう1つ高速化するためには、「関数を使い分ける」ということだと思います。 例えば、 reshape(1:10,10,1)と(1:10)'は共に同じものが出来ますが、 実行速度で言えば多分(1:10)'の方が早いと思います。(実際に試したわけではありません) これは、「1行10列の行列を、10行1列に作り替える」よりは「1行10列の行列を転置する」方が 速いだろうという私の予想です。 つまり、「転置」というシンプルな操作を、わざわざ行列を並び替えるreshapeで実現する必要はないよね、ということです。 話を戻します。 fscanf。果たして今実現しようとしているものはfscanfでしかできないのでしょうか?単純に文字列を読み込み、フォーマット指定子で変換していくならtextscanでも出来ます。 数値データで区切り文字が共通ならdlmreadでも読めますし、カンマ区切りならcsvreadも使えます。fgetsや改行が使われているならfgetlでとりあえず文字列として読み込んでしまって、sscanfでフォーマットを指定して読み込んでいくことも出来ます。 これは私の勝手な予想ですが、 fscanfはいくつの数字を読み込むか明示しないため、読み込む先の変数のサイズが動的に確保されていくのだと思われます。Matlabは配列のサイズがどんどん肥大化していくようなプログラムには弱いですし、メモリも使います。例えば、 for k=1::1000; a(k)=k; end; と書く前にa=zeros(1,1000);のように配列のサイズを確定させるだけでも実行速度は変わってきます。 fscanfの特性上このように配列サイズを確定しないまま延々と読み込むので遅くなるのかなあ…と思います。 実際私自身fscanfはあまり使わないですし、使ってもそれほど遅いと感じたことがないのでよくわからないんですが。 あとsaveasですね。これも「何を保存するのか」で使い分けた方がよいと思います。 変数を保存したい場合はsaveが使えますし、画像ファイルを保存したいのならimwriteなんかが使えます。 いろいろ試してみて、今組んでいる内容に相性のいいものを探す作業が必要だと思われます。 以上、参考になれば幸いです。

aiueoborn
質問者

お礼

3度目のご回答ありがとうございます。 長文有り難いです。非常に勉強になります!全く知らないことばかりです。 pngは単なる保存なので、教えて頂けたことをきっかけにどうにか出来そうな気がしてきました。 しかし、fscanfのほうなんですが、現ファイルは ======= wavestart=2 waveend=200000 %などなど。 ======= 3.232 2.221 -0.142 %と言う風にここからdouble値として欲しい値の行が続く。。計約2000万行の数値データ羅列。 といった感じです。そこでKulesさんの文章を頼りに色々調べてみますと textscanが早いようなので、どうにかしてtextscanで読み込んでdoubleで数値を読み込めないか、、と思ってきました。 しかし現データファイルはこのように ==で囲まれたヘッダー部分があるため、 どうすればこれを除いた途中から得ることが出来るのかが、上手くいかないといった状況です。 dlmreadでも同じく===が邪魔してエラーになります。 どうにかしてif文、strfind(str,'===')と組み合わせて出来るかもと思っているんですが、 いかんせん経験不足のためまだ上手くいかない状況です。fgetlなどは-1しかはき出さなくまずは理解からです。 色々書きましたが文章に迷いが出ている通り、現在試行錯誤中です。 それにしても元のコードは何故か[A,count]=fscanf(fid,'%f',inf)で読み込めてるんですよねぇ。。 もっと各コマンドの持つ意味をしっかり理解するべきですね。 まだ少しだけ締め切らずにおいておきますが、自分でも頑張ってみますので無理なさらないで下さいね。 もし上手く行けば補足に書くつもりです。

aiueoborn
質問者

補足

色々試してみました。textscanだとfscanfの場合に比べ読み込みが2倍以上早くなりました。 しかし、一つのセル配列内に2000万行が読み込まれている状態になっていました。 これをどうにかして各行の数値に直せればといった所です。 試してみたのは、簡易的に書くと以下のような流れです。 fid=fopen(filename,'r') str=fgetl(fid) sikiri1=strfind(str,'===') if (sikiri1) while 1 str =fgetl(fid) sikiri2=strfind(str,'===') if sikiri2 break; end end data=textscan(fid,'%f','Delimiter','\n'); おわり。 このfgetlやっとくと、行が進んだ状態から読み込むことが出来るんですね。 これでどうにか数値データのみを抽出し 1×1cell にすることまで出来ました。 あとはこの中に格納されている、2000万×1のdoubleを各行に格納し直すだけで以前のものを再現出来そうです。 残る問題はこの2000万を各行に変換するのにどれだけ時間を要するかですね。 そもそも読み込む際に各行に格納できたら問題無いんですけども。。ちょっと探してみます。

  • Kules
  • ベストアンサー率47% (292/619)
回答No.2

A No.1のKulesです。 なるほど…やはり高速化が目的でしたか。 ただそうなると出てくる疑問は、 「本当にmkdirは計算速度のボトルネックになっているのか?」 ということです。 試しにこんなコードを書いてプロファイラに解析させてみました。 for k=1:300; fname=sprintf('%03d',k); mkdir(fname); end; 所要時間はおおよそ0.286秒(cpu time)、 そのうちmkdirの行に費やした時間は0.08秒です。 mkdirは300回呼び出しているので、 実質1回実行するのに1msかかっていません。 この時間も惜しいぐらいシビアな高速化を行っているのでしょうか? (全体で1秒かからない関数中で、mkdirを1000回以上呼び出すとか) このぐらいは勘弁してあげられないですか?(笑) おそらくここ以外のループ構造が高速化を妨げているのではないかなあ… と思います。 まずは ツール->プロファイラを開く でどこに時間がかかっているのか探すのが先決かと思われます。 (もうされているかもしれませんが) 一般にmatlabはforループを使うと遅いと言われますが、 それなりにパワーのあるPCを使っていればforループの有無による差を そこまで強く感じることはありません。(感じることもありますが) どちらかというと見栄えの問題、プログラムの流れを シンプルに見せる目的 (例えば正方行列A,Bの積を2重のforループで書くと何をしているのか わかりにくいですが←私だけ? MatlabならA*Bの1行で済み、しかも何をしているのかわかりやすい) のような気もします。 で、forループを使わないことで高速化できる場面というのは、 「forループを使わなくても書けるのにforをわざわざ使っているところ」 が圧倒的に多いような気がします。 そこで今回の例を見てみると、関数mkdirはMatlabのヘルプ http://www.mathworks.co.jp/help/ja_JP/techdoc/ref/mkdir.html を見る限り複数フォルダを作るようには出来ていません。 そう考えると、ここを高速化しようと思うと 複数フォルダを生成するmex関数を自分で作るしかないのかなあ… と思います。 ただし、お使いのPCがマルチコア(CPUが2つ以上?)の場合は別です。 Matlabを動作させている時、基本的には1つのCPUしか動作しませんが、 自作関数などを経由させると2つ目のCPUを使い始める時があります。 (私の場合、全ての処理を1つのmファイルに書くとCPU使用率は 最大でも50%ですが、いくつかの処理を関数に分け、別ファイルにして メインの処理から呼びだすようにすることで、CPU使用率を100%にして 処理時間も若干ですが短縮できました) ということで、前回書いたように自作関数を作るというのは高速化の 1つの手段になりうるかも知れません。 長文失礼しました。他にボトルネックになっているところが判明したら、 補足に書いていただければもう少し有用な回答が出来るかも知れません。 参考になれば幸いです。

aiueoborn
質問者

お礼

再びご回答ありがとうございます。 わざわざ試して頂いて助かります。mkdir自体はそんなに時間かからないものなんですね・・ ところでプロファイラなんて便利な機能があったんですね。早速使用して確認してみました。 すると、 fscanfと、図のpngを保存するsaveasのforループの場所が大幅に時間を使っていることが判明しました。 fscanfはASCIIファイルを読み取るために使っています。 fscanfはループさせてませんのでこれ自体が遅いみたいで、改善方法が思いつきませんが、 saveasはmkdirと同じようにforループで実行させてます。なんだか元のmkdirから逸れていて申し訳ありません。

aiueoborn
質問者

補足

補足その2です。 間違い訂正です、2倍じゃなかったです、違う物を見てました。 その読み込み箇所は21秒→16秒に短縮されました。 それでも早くなったのは間違いなさそうです。 あと、cell→行列に でしたが、cell2matというのがあっさり見つかりましたので data=cell2mat(textscan(fid,'%f','Delimiter','\n')); に書き換えたら速度低下なく2000万×1 行列に変換出来ました。 危惧していた変換時間ですがcell2matってのは2000万行あっても0.001秒なんですね。 測定可能単位が0.001までしかなさそうなのでそれ以下かもしれません。 やはりそれ特化のものは素晴らしい性能を持っているようで。。 ちゃんと前とデータの違いがないか確認していませんがおそらく大丈夫そうです。 あとはおっしゃった通り最初に配列を当てるためfgetlで行数を獲得し、 その長さ分先に配列を作ってメモリ確保など、更なる試行していこうと思います。 これ以上は流石に申し訳ないので自分でやってみます。 補足欄で申し訳ないですが改めて、Kulesさんのおかげです。本当に感謝感謝です。

  • Kules
  • ベストアンサー率47% (292/619)
回答No.1

これは…難しい問題ですね。 というのも私自身 for k=1:length(pass); mkdir(pass{k}); end; 以上の回答が思いつかないので(苦笑) ただこうしたくないということは実際のプログラムはもっと長くて、 いちいちforループに入れたくないって感じなんですかね? だとすると後は自作関数ですかね… m_mkdir(pathname)みたいなものを作って、 pathnameが単なる文字列の場合はそのままmkdirに渡して、 pathnameが文字の行列(フォルダ名が全て同じ長さなら行列にすることも可能なので) またはセル配列の時はforループ内でmkdirを複数回実行する、というような 分岐ができる関数にするぐらいでしょうか。 これなら一行でフォルダを複数作成できますね。 「そういうことじゃないんだよ」とかありましたら補足に書いていただければと思います。 あまり役には立たないかも…出直してきます。 参考になれば幸いです。

aiueoborn
質問者

お礼

ご回答ありがとうございます。 質問目的はそれも含みです。今は仕方なくforで回してます。 書き忘れましたがプログラムの高速化が主目的ですので、 forではない書き方で一気に作成は無理なのかなぁと。無理なら無理で諦めつくんですけども。。 mkdirだけの問題ではないんですが、これと似たような箇所がプログラム内に多くありまして、 とりあえずこれが解決できると他の所も同様に改善できるかなと思い、今回質問させて頂きました。 見栄えなら自作関数って手もありますね。多少行数はすっきりしそうです。参考にさせて頂きます。