前回はスライダーを使ってfigureを更新する方法について2記事にわたって紹介しました。
今回は研究や業務の現場でも非常によく使う複数のファイルを読み込んで同じ処理を実施する方法についてご紹介します。1ファイルについての処理を行うスクリプトなどを一生懸命作成したのち、同じ処理を複数のファイルに対して行いたいという場面は多々あります。
実際の業務依頼でもスクリプトファイルをご提供いただき、ほかの100ファイルでも実行してほしいといったご依頼をいただくことがあります。
今回は複数ファイルを読み込んで処理する流れをご説明いたします。
1、ダミーデータの作成
2、読み込むファイルのリストを作成する
3、ファイルを読み込む
4、目的の処理を実行する
5、処理結果を保存する
6、一括で処理を実施する
7、便利なテクニック
1、ダミーデータの作成
まず初めに、一括処理を行う際に必要なダミーデータを作成します。新規のスクリプトファイルを用意して、下記のコードを実行してください。実行すると、現在のフォルダに「randSample_*.csv」というファイルが10個生成されます。今回はそのファイルを読み込んで、処理をして結果をファイルとして保存する方法をご紹介します。
numFiles = 10;
t = transpose(0:0.01:100);
omega = 2*pi/20;
WriteData = zeros(length(t),2);
WriteData(:,1) = t;
for i=1:numFiles
WriteData(:,2) = rand() * sin(omega*t) + 0.1*rand();
writematrix(WriteData,['randSinData_' num2str(i) '.csv']);
end上記例では、WriteDataという変数(1001,2)の1行目にタイムスタンプ、2行目に生成したデータを代入しています(8行目)。データはsin関数を使って生成しています。randで生成した乱数倍し、乱数の0.1倍を加えた値を使用します。
9行目のwirtematrix関数でcsvファイルを生成しています。WriteDataという行列を、randSinData_i.csvという名前で保存しています。下記のようにcsvが10個生成できればOKです。

2、読み込むファイルのリストを作成する
それでは早速、上記のデータを読み取って処理を追加していきます。今回読み込むためのデータを生成しましたが、計測データなどがすでにある前提ですので、0から新たなスクリプトファイルを生成します。まず初めに、読み込むファイルのリストを生成する必要があります。Listを作成するのにdir関数を使用します。「***.csv」というファイル名のリストだけ生成したいので引数に「’*.csv’」を指定しました。
List = dir('*.csv');作成されたList変数の中身を確認します。ワークスペースのListをダブルクリックすると、List変数の詳細が確認できます。List.nameにファイル名が保存されています。ほかにもList.filderにファイルの絶対パスが保存されています。

3、ファイルを読み込む
それではcsvファイルを読み込む処理を記載します。まずは1ファイルだけ読み込むコードを記述します。
% 2、読み込むファイルのリストを作成する
List = dir('*.csv');
%3、ファイルを読み込む
Data = readmatrix(List(1).name);readmatrix関数を使用して、Listの1番目のnameという名前のファイルを読み込み、Dataという変数に代入しています。Data変数をダブルクリックして中身を確認すると、10001行2列の行列として読み込まれていることがわかります。
データ確認のため、下記コードでグラフを作成します。
plot(Data(:,1),Data(:,2))
4、目的の処理を実行する
グラフを確認して問題なさそうなので、読み取ったデータに処理を加えます。今回の目的外なので説明は最小限にとどめますが、読み取ったデータをオフセットと定数倍することによりsin(ωt)に戻すような処理を追記します。
% 2、読み込むファイルのリストを作成する
List = dir('*.csv');
% 3、ファイルを読み込む
Data = readmatrix(List(1).name);
% 4、目的の処理を実行する
Data(:,3) = Data(:,2) - Data(1,2);
gain = 0.5 * (max(Data(:,3)) - min(Data(:,3)));
Data(:,3) = Data(:,3)/gain;8行目でData(:,2)からData(1,2)を引いた値をData(:,3)に格納しています。
また、Data(:,3)の最大値から最小値を引き算して、0.5かけることでsinカーブに対するゲインが計算できます。
10行目でゲインを割り算することでゲイン1のsinカーブを求めることができます。(通常は0で割り算することを防ぐための処理を記述しますが、今回は割愛しました。)先ほど作成したのグラフと併せて表示するため、下記コードでグラフを表示しました。
plot(Data(:,1),Data(:,2))
hold on
plot(Data(:,1),Data(:,3))
5、処理結果を保存する
処理済みのデータがData変数の3列目に格納されているので、Data変数を新たなファイルに書き込みます。
writematrixは「1、ダミーデータの作成」でも使用しましたが、行列をファイルに書き込むための関数です。今回はprocessedData.csvというファイル名で保存しました。
% 2、読み込むファイルのリストを作成する
List = dir('*.csv');
% 3、ファイルを読み込む
Data = readmatrix(List(1).name);
% 4、目的の処理を実行する
Data(:,3) = Data(:,2) - Data(1,2);
gain = 0.5 * (max(Data(:,3)) - min(Data(:,3)));
Data(:,3) = Data(:,3)/gain;
% 5、figure更新用の関数作成
writematrix(Data,'processed.csv');processed.csvが無事生成されているはずです。
6、一括で処理を実施する
無事1ファイルに対して処理が完了したので、for文を用いて一気に10ファイルの処理を行います。
下記のハイライト箇所を変更しました。
% 2、読み込むファイルのリストを作成する
List = dir('*.csv');
len = length(List);% 6
for i=1:len
% 3、ファイルを読み込む
Data = readmatrix(List(i).name);% 6
% 4、目的の処理を実行する
Data(:,3) = Data(:,2) - Data(1,2);
gain = 0.5 * (max(Data(:,3)) - min(Data(:,3)));
Data(:,3) = Data(:,3)/gain;
% 5、figure更新用の関数作成
writematrix(Data,['processed_' List(i).name]); %6
clear Data gain %6
end4行目でList変数の長さを取得しlenという変数に代入
6, 20行目でfor文を作成
9行目で読み取るファイルをList(1).name→List(i).nameに変更
17行目で生成するファイル名がprocessed_randSinData_i.csvとなるようにしています。List(i).nameに「randSinData_i.csv」が格納されているので、先頭に「processed_」の文字列を追加するよう変更
19行目で変数をクリアしています。今回は特に必要ない処理ですがfor文で同じ変数を使いまわす際に、前回ループの値が残ってしまわないように変数をクリアしておきます。
きちんと実行できればフォルダにprocessed_randSinData_i.csvが10ファイル生成されているはずです。
7、便利なテクニック
最後に便利なテクニックを紹介します。今回はダミーデータを生成したため、問題なく読み込んで処理が実行できました。しかし、実際に計測したデータ等を用いると例外が発生してエラーで止まってしまうということがよくあります。例えば、「読み込むcsvファイルの中身が欠損している」なんてことはよくあります。
せっかく一括で処理できるように記述したつもりが、途中で何回もエラーで止まってしまって、結局1回ずつ実行してもあまり変わらなかったとなってしまってはとても残念です。
そいった場合に使用するtry catch文を追加したコードが下記になります。
% 2、読み込むファイルのリストを作成する
List = dir('randSinData_*.csv');
len = length(List);% 6
for i=1:len
try
% 3、ファイルを読み込む
Data = readmatrix(List(i).name);% 6
% 4、目的の処理を実行する
Data(:,3) = Data(:,2) - Data(1,2);
gain = 0.5 * (max(Data(:,3)) - min(Data(:,3)));
Data(:,3) = Data(:,3)/gain;
% 5、figure更新用の関数作成
writematrix(Data,['processed_' List(i).name]); %6
clear Data gain%6
catch
disp(List(i).name);
end
end「try」のあとで記述したコードでエラーが発生した場合「catch」以降の記述を実行してくれます。今回の場合、読み込んだcsvファイルの中身が空だと13行目でエラーが発生します。catchのあとに、disp(List(i).name)を記述することでエラーが発生したファイル名をコマンドウィンドウに表示するようにしておきます。
こうすることでエラーでいちいち処理が止まることなく最後まで実行することができます。そして、コマンドウィンドウに表示されているcsvファイル名を確認することで対処すべき問題なのか判断できます。csvファイルの中身が空の場合は明らかに無視していい事象ですね。
下記はrandSinData_5.csvの中身を空して実行した結果です。

エラーが発生したファイル名だけコマンドウィンドウに表示されています。生成されたファイルを確認すると、processed_randSinData_5.csv以外はファイル生成されてます。
まとめ
今回は複数ファイルの一括処理について解説しました。業務や研究では「計測したファイルを読み込み、処理を実行し、別ファイルに保存」といったことはよく行います。その際に1ファイルずつコードのファイル名と保存用のファイル名を書き換えて処理を行うのは非効率ですし人為的なミスが発生しがちです。
今回ご紹介した方法は、業界や分野を問わず使い回しが可能な手法だと思いますので、ぜひご参考にしていただければと思います。
最終的に作成したコードを載せておきますのでご活用ください。
↓ファイル生成用のコード
numFiles = 10;
t = transpose(0:0.01:100);
omega = 2*pi/20;
WriteData = zeros(length(t),2);
WriteData(:,1) = t;
for i=1:numFiles
WriteData(:,2) = rand() * sin(omega*t) + 0.1*rand();
writematrix(WriteData,['randSinData_' num2str(i) '.csv']);
end↓一括処理用コード
% 2、読み込むファイルのリストを作成する
List = dir('randSinData_*.csv');
len = length(List);% 6
for i=1:len
try
% 3、ファイルを読み込む
Data = readmatrix(List(i).name);% 6
% 4、目的の処理を実行する
Data(:,3) = Data(:,2) - Data(1,2);
gain = 0.5 * (max(Data(:,3)) - min(Data(:,3)));
Data(:,3) = Data(:,3)/gain;
% 5、figure更新用の関数作成
writematrix(Data,['processed_' List(i).name]); %6
clear Data gain%6
catch
disp(List(i).name);
end
end
コメント