dlmwrite
dlmwrite
関数は、GNU Octaveで数値データを区切り文字で区切られたテキストファイル(デリミテッドファイル)に書き出すために使用されます。MATLABのdlmwrite
関数と互換性があります。
書式 (基本的な使い方)
基本的な書式は以下の通りです。
dlmwrite(filename, M)
dlmwrite(filename, M, 'delimiter', delim)
dlmwrite(filename, M, 'delimiter', delim, 'precision', precision)
dlmwrite(filename, M, 'delimiter', delim, 'precision', precision, 'roffset', row, 'coffset', col)
引数の説明
'coffset', col
: オプションの引数で、ファイルに書き込みを開始する列のオフセット(0-indexed)を指定します。'roffset', row
: オプションの引数で、ファイルに書き込みを開始する行のオフセット(0-indexed)を指定します。'precision', precision
: オプションの引数で、数値の書き込み精度を指定します。precision
はフォーマット文字列(例:'%f'
、'%.4g'
)または整数(小数点以下の桁数)です。'delimiter', delim
: オプションの引数で、データ間の区切り文字を指定します。delim
は区切り文字を表す文字列です。M
: 書き込みたい数値データを含む行列(またはベクトル)です。filename
: データを書き込むファイルの名前を指定する文字列です。ファイルが存在しない場合は新しく作成され、存在する場合は上書きされます。
具体例
いくつかの使用例を見てみましょう。
基本的な書き込み(カンマ区切り)
data = [1 2 3; 4 5 6; 7 8 9];
dlmwrite("output.csv", data);
このコードを実行すると、output.csv
というファイルが作成され、以下の内容が書き込まれます。デフォルトではタブ区切りですが、Octaveのバージョンによってはカンマ区切りになる場合もあります。
1,2,3
4,5,6
7,8,9
セミコロン区切りで書き込み
区切り文字を明示的に指定する場合。
data = [10 11 12; 13 14 15];
dlmwrite("output.txt", data, 'delimiter', ';');
output.txt
の内容:
10;11;12
13;14;15
書き込み精度の指定
数値の表示形式を制御する場合。
data = [1.23456 7.89012; 3.45678 9.01234];
dlmwrite("output_precision.txt", data, 'precision', '%.2f');
output_precision.txt
の内容:
1.23,7.89
3.46,9.01
オフセットを指定して書き込み
ファイルの特定の位置から書き込みを開始する場合。
data = [1 2; 3 4];
dlmwrite("output_offset.txt", data, 'delimiter', ',', 'roffset', 1, 'coffset', 2);
output_offset.txt
の内容(先頭に1行、2列分の空白ができます):
, ,1,2
, ,3,4
(実際にはオフセット分は空の区切り文字で埋められるか、または何も書き込まれない空白として表現されます。上の例では、roffset
が1なので2行目から、coffset
が2なので3列目からデータが始まります)
注意点
- 大きなデータを書き込む場合、
dlmwrite
はメモリ効率が悪い場合があります。その場合、fprintf
やcsvwrite
(CSVファイルの場合)などの関数がより適している可能性があります。 - ファイルが存在する場合、
dlmwrite
は既存の内容を上書きします。既存のファイルに追記したい場合は、dlmwrite
の代わりにfdisp
やfprintf
を使用し、ファイルモードを追記モード('a'
)で開く必要があります。 dlmwrite
は数値データのみを扱います。文字列を書き込む場合は、fprintf
などの関数を使用する必要があります。
ファイル書き込み権限のエラー (Permission Denied)
エラーメッセージの例
error: dlmwrite: unable to open file 'output.txt' for writing
error: fopen: unable to open file 'output.csv': Permission denied
原因
- ファイル名に無効な文字が含まれている(OSの制限)。
- ファイルがすでに存在し、他のプログラム(例: テキストエディタ、Excel)によって開かれているため、ロックされている。
- 指定されたディレクトリにファイルを作成または上書きするための書き込み権限がない。
トラブルシューティング
- 別のディレクトリでの試行
- 一時的にデスクトップやドキュメントフォルダなど、書き込み権限が確実にある別の場所にファイルを保存できるか試してください。
- ファイル名の検証
- ファイル名に特殊文字やOSで予約されている名前(例:
CON
,PRN
など)を使用していないか確認します。
- ファイル名に特殊文字やOSで予約されている名前(例:
- ファイルのロック解除
- 書き込み対象のファイルが他のアプリケーションで開かれていないか確認し、開かれている場合は閉じてください。
- 書き込み権限の確認
- ファイルを保存しようとしているディレクトリに、Octaveを実行しているユーザーが書き込み権限を持っているか確認してください。
- Linux/macOSの場合、
ls -l
コマンドでディレクトリのパーミッションを確認し、必要に応じてchmod
で権限を変更します。 - Windowsの場合、フォルダのプロパティからセキュリティ設定を確認します。
無効なファイルパスまたはファイル名
エラーメッセージの例
error: dlmwrite: unable to open file 'C:\My Folder\output.txt' for writing
(パスにスペースがある場合など)
原因
- ドライブレターやネットワークパスの指定が誤っている。
- パスにスペースが含まれている場合、適切に引用符で囲まれていない。
- ファイルパスが正しくない(typoなど)。
トラブルシューティング
- 現在のディレクトリの確認
- ファイル名をパスなしで指定した場合、Octaveは現在の作業ディレクトリにファイルを保存します。
pwd
コマンドで現在の作業ディレクトリを確認し、目的の場所であることを確かめてください。
- ファイル名をパスなしで指定した場合、Octaveは現在の作業ディレクトリにファイルを保存します。
- スペースを含むパスの処理
- パスにスペースが含まれる場合は、必ず全体を引用符で囲んでください。
- 例:
dlmwrite("C:/My Documents/data.txt", M)
- ファイルパスの確認
- 指定したファイルパスが正しいか、スペルミスがないかを慎重に確認します。
- Windowsではバックスラッシュ (
\
) を使用しますが、Octave(およびMATLAB)ではスラッシュ (/
) を使用するのが一般的で、推奨されます。または、バックスラッシュを二重にする (\\
) 必要があります。例:'C:/Users/YourName/data.csv'
または'C:\\Users\\YourName\\data.csv'
。
書き込み対象のデータが数値ではない (非数値データ)
原因
dlmwrite
は基本的に数値行列の書き込みを想定しています。文字列(セル配列や文字配列)を直接書き込もうとすると、意図しない結果になるかエラーが発生することがあります。
トラブルシューティング
- 文字列の書き込み
- 文字列(特にヘッダー行など)を書き込みたい場合は、
dlmwrite
ではなくfprintf
を使用することを検討してください。 - 例:
fid = fopen("output_with_header.csv", "w"); fprintf(fid, "Header1,Header2,Header3\n"); fclose(fid); data = [1 2 3; 4 5 6]; dlmwrite("output_with_header.csv", data, "-append", "delimiter", ",");
"-append"
オプションは、既存のファイルに追記する場合に重要です。
- 文字列(特にヘッダー行など)を書き込みたい場合は、
- データ型の確認
isnumeric(M)
で書き込みたい変数M
が数値型であるか確認します。
精度の問題 (データが丸められる、小数点以下の桁数が足りない/多すぎる)
原因
precision
オプションの指定が誤っている。dlmwrite
のデフォルトの精度が、期待する表示形式と異なる。
トラブルシューティング
- 元のデータ型の確認
- Octave内部での数値の表現は常に倍精度浮動小数点数(double)です。表示上の問題か、それともデータ自体の丸めが問題なのかを区別してください。
- precision オプションの使用
- 書き込みたい数値の精度を明示的に
precision
オプションで指定します。 - 例:
- 浮動小数点数で小数点以下2桁:
dlmwrite("data.txt", M, "precision", "%.2f")
- 指数表記で有効数字4桁:
dlmwrite("data.txt", M, "precision", "%.4e")
- Octaveのデフォルト精度(通常5桁):
dlmwrite("data.txt", M, "precision", "%g")
- 浮動小数点数で小数点以下2桁:
- 書き込みたい数値の精度を明示的に
大規模データのパフォーマンス問題またはメモリ不足
原因
dlmwrite
は内部的にデータをバッファリングするため、非常に大きなデータでは非効率になることがあります。- 非常に大きな行列(数百万行、数千列など)を一度に
dlmwrite
で書き込もうとすると、メモリを大量に消費したり、処理に時間がかかりすぎたりすることがあります。
トラブルシューティング
- Octaveのメモリ制限の確認
- 64ビット版のOctaveを使用しているか確認します。32ビット版では利用可能なメモリに制限があります。
- Octaveのバージョンやシステムのリソース(RAM)を確認してください。
- データを分割して書き込み
- データをいくつかのチャンクに分割し、ループで順次書き込むことも有効です。
- fprintf の使用を検討
- 大規模なデータセットの場合は、
dlmwrite
よりもfprintf
を使用して、行ごとにデータを書き込む方がメモリ効率が良い場合があります。 - 例:
data = rand(100000, 10); % 10万行10列のデータ fid = fopen("large_data.csv", "w"); for i = 1:rows(data) fprintf(fid, "%f,%f,%f,%f,%f,%f,%f,%f,%f,%f\n", data(i, :)); endfor fclose(fid);
- 大規模なデータセットの場合は、
ヘッダー行や文字列と数値の混在
原因
dlmwrite
は直接ヘッダー行のような文字列と数値を混在させて書き込む機能を持っていません。
トラブルシューティング
- fprintf と dlmwrite の組み合わせ
- 前述の「文字列の書き込み」の例のように、
fprintf
でヘッダーを書き込んだ後、dlmwrite
でデータを行ごとに追記するのが一般的な方法です。
- 前述の「文字列の書き込み」の例のように、
ファイルが適切に閉じられていない
原因
dlmwrite
は通常、ファイルを自動的に開いて閉じます。しかし、もしfopen
などでファイルを自分で開いて書き込み、その後にdlmwrite
を同じファイルに対して使用しようとすると、ファイルがロックされているためにエラーになることがあります。
- fclose の確認
- 自分でファイルを開いている場合は、
dlmwrite
を呼び出す前にfclose(fid)
で適切にファイルを閉じていることを確認してください。
- 自分でファイルを開いている場合は、
dlmwrite
関数は、Octave で数値データを区切り文字で区切られたテキストファイルに書き出すためのものです。ここでは、様々なシナリオでの具体的な使用例を挙げ、それぞれのコードと出力ファイルの内容を説明します。
例 1: 最も基本的な書き込み(デフォルトの区切り文字)
これは dlmwrite
の最も基本的な使い方です。データを行列として与え、ファイル名を指定するだけです。デフォルトでは、通常タブ区切りまたはカンマ区切り(Octaveのバージョンや設定による)で書き込まれます。
Octave コード
% 1. 基本的な書き込み
data_basic = [10 20 30; 40 50 60; 70 80 90];
filename_basic = "basic_output.txt";
dlmwrite(filename_basic, data_basic);
fprintf('"%s" に基本的なデータが書き込まれました。\n', filename_basic);
basic_output.txt の内容
10 20 30
40 50 60
70 80 90
(注: 環境によってはタブではなくカンマで区切られることもあります。)
例 2: カンマ区切り(CSVファイル)での書き込み
最も一般的な使い方の一つで、CSV (Comma Separated Values) ファイルを作成する場合です。'delimiter'
オプションを使ってカンマを指定します。
Octave コード
% 2. カンマ区切り(CSV)での書き込み
data_csv = [1.1 2.2 3.3; 4.4 5.5 6.6];
filename_csv = "data.csv";
dlmwrite(filename_csv, data_csv, 'delimiter', ',');
fprintf('"%s" にCSV形式のデータが書き込まれました。\n', filename_csv);
data.csv の内容
1.1,2.2,3.3
4.4,5.5,6.6
例 3: セミコロン区切りでの書き込みと精度の指定
区切り文字をセミコロンに変更し、さらに precision
オプションを使って浮動小数点数の書き込み精度を制御します。ここでは小数点以下2桁まで表示するように指定しています。
Octave コード
% 3. セミコロン区切りと精度の指定
data_precision = [123.456 789.012; 345.678 901.234];
filename_precision = "data_precision.txt";
dlmwrite(filename_precision, data_precision, 'delimiter', ';', 'precision', '%.2f');
fprintf('"%s" に指定された精度でデータが書き込まれました。\n', filename_precision);
data_precision.txt の内容
123.46;789.01
345.68;901.23
(注: 丸めが行われる場合があります。)
例 4: 特定の行と列のオフセットを指定して書き込み
'roffset'
と 'coffset'
オプションを使用すると、ファイルの特定の位置からデータの書き込みを開始できます。これは既存のファイルの一部を更新したり、特定のフォーマットに合わせる場合に便利です。オフセットは0から始まるインデックスです。
Octave コード
% 4. オフセットを指定して書き込み
data_offset = [100 200; 300 400];
filename_offset = "data_offset.txt";
% まずファイルを作成し、空の場所を確保するために初期データを書き込む
% この例ではファイルが存在しないものと仮定し、直接オフセットを指定
% 既存ファイルに追記する場合、dlmwrite は上書きするので注意が必要
% 既存ファイルへの追記は 例7 を参照
% r=1, c=2 は、2行目、3列目から書き込みを開始することを意味します
dlmwrite(filename_offset, data_offset, 'delimiter', ',', 'roffset', 1, 'coffset', 2);
fprintf('"%s" にオフセット指定でデータが書き込まれました。\n', filename_offset);
data_offset.txt の内容
,,100,200
,,300,400
(注: roffset
と coffset
で指定された空白部分は、区切り文字で埋められるか、または単なる空白として表現されます。上記の例ではカンマが挿入されています。)
例 5: ヘッダー行とデータを書き込む(fprintf
と組み合わせる)
dlmwrite
は基本的に数値データのみを扱います。ファイルにヘッダー行(文字列)を含めたい場合は、fprintf
と組み合わせて使用するのが一般的です。
Octave コード
% 5. ヘッダー行とデータを書き込む(fprintf と組み合わせる)
data_with_header = [101 102; 201 202];
filename_header = "data_with_header.csv";
% ファイルを書き込みモードで開く
fid = fopen(filename_header, "w");
% ヘッダー行を書き込む
fprintf(fid, "ID,ValueA,ValueB\n"); % "\n" で改行
% ファイルを閉じる
fclose(fid);
% データを追記モードで書き込む (dlmwrite の "-append" オプションを使用)
dlmwrite(filename_header, data_with_header, 'delimiter', ',', '-append');
fprintf('"%s" にヘッダー付きデータが書き込まれました。\n', filename_header);
data_with_header.csv の内容
ID,ValueA,ValueB
101,102
201,202
(注: dlmwrite
はヘッダーの列数とデータの列数が一致しない場合でもそのまま書き込みます。ヘッダーの列数とデータの列数を合わせる場合は、data_with_header
の前にID列などを追加する必要があります。)
例 6: 空の行列を書き込もうとした場合
空の行列を dlmwrite
で書き込もうとすると、通常は空のファイルが作成されるか、既存のファイルが空に上書きされます。エラーにはなりません。
% 6. 空の行列の書き込み
data_empty = []; % または zeros(0, 3) など
filename_empty = "empty_output.txt";
dlmwrite(filename_empty, data_empty);
fprintf('"%s" に空のデータが書き込まれました(ファイルは空になります)。\n', filename_empty);
dlmwrite
は手軽に数値データを区切り文字付きテキストファイルに書き出すことができる便利な関数ですが、より細かい制御が必要な場合、大規模なデータを扱う場合、または特定のフォーマットに準拠する必要がある場合には、他の代替手段を検討する価値があります。
主な代替方法は以下の通りです。
- fprintf 関数
最も柔軟性が高く、あらゆるテキスト形式のファイル出力に対応できます。 - csvwrite 関数
CSV (Comma Separated Values) ファイルに特化した関数で、dlmwrite
より直感的にCSVを扱えます。 - save -ascii (または save -text) コマンド
変数の内容をASCIIテキスト形式で保存するシンプルな方法です。
それでは、それぞれの方法について詳しく見ていきましょう。
fprintf 関数
fprintf
はC言語の fprintf
に似ており、書式指定文字列を使ってデータを整形しながらファイルに書き込むことができます。最も強力で柔軟性がありますが、その分、書式指定を正しく行う必要があります。
特徴
- 複雑さ
書式指定文字列の知識が必要です。 - メモリ効率
大規模なデータをループ処理で書き込むことで、メモリ消費を抑えられます。 - 制御性
小数点以下の桁数、パディング、科学表記など、出力形式を細かく制御できます。 - 柔軟性
数値、文字列、混合データなど、あらゆる種類のデータを任意の区切り文字と書式で書き込めます。
使用例
% データを準備
data = [1.2345 6.7890; 10.1112 13.1415];
headers = {"Header1", "Header2"};
% 1. 基本的なカンマ区切り (dlmwrite の代替)
filename_fprintf_basic = "fprintf_basic.csv";
fid = fopen(filename_fprintf_basic, "w"); % 'w' で書き込みモードでファイルを開く
fprintf(fid, "%.2f,%.2f\n", data'); % データを行ごとに書き込む (転置して列方向をループ)
fclose(fid);
fprintf('"%s" に fprintf で基本的なデータが書き込まれました。\n', filename_fprintf_basic);
% 2. ヘッダー行とデータを書き込む
filename_fprintf_header = "fprintf_header.csv";
fid = fopen(filename_fprintf_header, "w");
fprintf(fid, "%s,%s\n", headers{:}); % ヘッダーを書き込む
fprintf(fid, "%.1f,%.1f\n", data'); % データ(例として小数点以下1桁)を書き込む
fclose(fid);
fprintf('"%s" に fprintf でヘッダー付きデータが書き込まれました。\n', filename_fprintf_header);
% 3. 大規模データを効率的に書き込む(行ごとにループ)
large_data = rand(1000, 5); % 1000行5列のランダムデータ
filename_fprintf_large = "fprintf_large_data.txt";
fid = fopen(filename_fprintf_large, "w");
for i = 1:rows(large_data)
fprintf(fid, "%.4f,%.4f,%.4f,%.4f,%.4f\n", large_data(i, :)); % 各行をカンマ区切りで書き出す
endfor
fclose(fid);
fprintf('"%s" に fprintf で大規模データが書き込まれました。\n', filename_fprintf_large);
出力ファイルの例
fprintf_basic.csv
:
1.23,6.79
10.11,13.14
fprintf_header.csv
:
Header1,Header2
1.2,6.8
10.1,13.1
csvwrite 関数
csvwrite
は、名前の通りCSVファイル(カンマ区切り)に特化した関数です。dlmwrite
の delimiter
オプションでカンマを指定するのと同じような結果が得られますが、CSV用途に特化しているため、より明確な意図を示せます。
特徴
- ヘッダー
ヘッダー行を直接書き込む機能はありません(fprintf
と組み合わせる必要があります)。 - 特定用途
カンマ区切りファイル以外の区切り文字には対応していません。 - シンプルさ
CSVファイルの書き込みに特化しており、シンプルに記述できます。
使用例
% データを準備
data_csvwrite = [1.0 2.0; 3.0 4.0];
% 1. 基本的な CSV 書き込み
filename_csvwrite = "csvwrite_output.csv";
csvwrite(filename_csvwrite, data_csvwrite);
fprintf('"%s" に csvwrite でデータが書き込まれました。\n', filename_csvwrite);
% 2. 特定の開始行・列から書き込み(roffset, coffset)
% csvwrite は dlmwrite と同様にオフセットをサポートします。
filename_csvwrite_offset = "csvwrite_offset.csv";
csvwrite(filename_csvwrite_offset, data_csvwrite, 1, 1); % r=1, c=1 は2行目、2列目から
fprintf('"%s" に csvwrite でオフセット指定でデータが書き込まれました。\n', filename_csvwrite_offset);
出力ファイルの例
csvwrite_output.csv
:
1.0,2.0
3.0,4.0
csvwrite_offset.csv
:
,
,1.0,2.0
,3.0,4.0
save -ascii (または save -text) コマンド
これは関数ではなく、Octave の save
コマンドのオプションです。ワークスペース内の変数をテキストファイルとして保存する場合に非常に便利です。デフォルトではスペース区切りで、科学表記が使われることがあります。
特徴
- 複数の変数
複数の変数を1つのファイルに保存すると、それぞれの変数が個別の行列としてファイルに出力されます。 - 制限
区切り文字の変更、書き込み精度の細かな制御、特定の行・列からの書き込みはできません。 - 手軽さ
変数の内容を最も簡単にテキスト形式で保存できます。
使用例
% データを準備
data_save = [123.45 678.90; 11.22 33.44];
vector_save = [1 2 3];
% 1. 行列をASCII形式で保存
filename_save_matrix = "save_matrix.txt";
save(filename_save_matrix, "data_save", "-ascii");
fprintf('"%s" に save -ascii で行列が保存されました。\n', filename_save_matrix);
% 2. 複数の変数をASCII形式で保存
filename_save_multi = "save_multi.txt";
save(filename_save_multi, "data_save", "vector_save", "-ascii");
fprintf('"%s" に save -ascii で複数の変数が保存されました。\n', filename_save_multi);
出力ファイルの例
save_matrix.txt
:
1.2345000e+02 6.7890000e+02
1.1220000e+01 3.3440000e+01
save_multi.txt
:
# name: data_save
# type: matrix
# rows: 2
# columns: 2
1.2345000e+02 6.7890000e+02
1.1220000e+01 3.3440000e+01
# name: vector_save
# type: row vector
# rows: 1
# columns: 3
1.0000000e+00 2.0000000e+00 3.0000000e+00
(注: save -ascii
は変数名やデータ型などのヘッダー情報を自動的に追加します。これは Octave や MATLAB で再読み込みする際に便利ですが、単なるデータファイルとして使用する場合は邪魔になることがあります。純粋なデータのみを保存したい場合は fprintf
の方が適しています。)