【個人メモ】サイズの大きなテキストファイルのデータからOD集計する

# 概要
　お役所から提供されたデータは，固定長のテキストファイルで提供されることがあり，サイズが大きいため，扱いがめんどくさい．
　MATLABで，テキストファイルを読み取って.matファイルに変換・保存した．また，提供されたのは某交通に関するデータで，保存した.matファイルを用いてOD集計を行った．

# テキストファイルを.matファイルに変換
 まあ，変数名やら型やらを指定してファイルを読み込むだけである．ただ，日本語・ファイルサイズがでかい場合にはいくつか注意すべき点がある．
　一応，データ自体は大っぴらにしていいものではないので，一応変数名などを伏せたり変更したりしてある．

```matlab:txt2mat.m
%% txt2mat.m

datafilename = '○○.txt'; % テキストファイル名およびパス
DataStartLine = 1; % 読み込み開始位置
NumVariables = 4; % 変数の数
VariableNames  = {'変数の名前1','変数の名前2','変数の名前3','変数の名前4'}; % 変数名
VariableWidths = [1,1,3,4]; % 固定長なので，各変数の長さを入力
DataType       = {'double','uint64','categorical','double'}; % データ型
opts = fixedWidthImportOptions('NumVariables',NumVariables,...
    'DataLines',DataStartLine,...
    'VariableNames',VariableNames,...
    'VariableWidths',VariableWidths,...
    'VariableTypes',DataType,...
    'PreserveVariableNames',true); % オプション，PreserveVariableNamesを入れないと日本語の変数名が上手くいかない
T = readtable(datafilename,opts); % 読み込み
save('○○.mat','T','-v7.3') % .matとして保存
% 2GB以上のファイルの場合，matファイルのversion7.3以降でないと対応できないので'-v7.3'を入れる
```

# OD集計
　上記の.matファイルを読み込んで，車種，ゾーン別にODを集計する．

```matlab:OD_aggregator.m
%% OD集計プログラム
tic

load('○○.mat');

% 車種
vehicle_type=table2array(T(:,15));

% 出発地コード(Origin)
O=table2array(T(:,20));

% 目的地コード(Destination)
D=table2array(T(:,21));

% 拡大係数
expansion_rate=table2array(T(:,34));


%% OD集計
% 集計したいエリア内はゾーンごと，それ以外は域外として集計．
zone=readmatrix('コード表～～.csv'); % エリアのコード表．コード表と同じ順にしたかった
zone(:,2)=[];
zone(end+1,1)=9999999;% 域外のコード

% 結果を格納する配列
results=zeros(車種数*(size(zone,1)^2),4);% O,D,車種,トリップ数で4列

% resultsの1,2列にO,Dのコードを入力
for i=1:車種数
    for j=1:size(zone,1)
        results((i-1)*(size(zone,1)^2)+(j-1)*size(zone,1)+1:((i-1)*(size(zone,1)^2)+j*size(zone,1)),1)=zone(j,1);
        results((i-1)*(size(zone,1)^2)+(j-1)*size(zone,1)+1:((i-1)*(size(zone,1)^2)+j*size(zone,1)),2)=zone;
    end
    results((i-1)*(size(zone,1)^2)+1:i*(size(zone,1)^2),3)=i;
end
toc

% 域外のコードを9999999に置換する
% 今回は，コードの大小でエリアを判定
parfor i=1:size(O,1)
    % Oのコードを置換
    if O(i)<コード
        O(i)=9999999;
    elseif O(i)>コード
        O(i)=9999999;
    end
    
    % Dのコードを置換
    if D(i)<コード
        D(i)=9999999;
    elseif D(i)>コード
        D(i)=9999999;
    end
end
toc

% 集計
for i=1:size(O,1)
    % O,Dがコード表のどこに位置するか
    O_position=find(zone==O(i));
    D_position=find(zone==D(i));
    
    if or(isempty(O_position),isempty(D_position))
        disp('error')
    else
        % O,Dの位置と車種で
        results((vehicle_type(i)-1)*(size(zone,1)^2)+(O_position-1)*size(zone,1)+D_position,4)=...
            results((vehicle_type(i)-1)*(size(zone,1)^2)+(O_position-1)*size(zone,1)+D_position,4)+...
            expansion_rate(i);
    end
end
toc

%% 保存
save('OD.mat','results') % matファイルに保存

% csvに保存
resultsfile_path=sprintf('OD_~~.csv');
varNames={'code_Origin','code_Destination','Vehicle_type','Num_trips'};
results_table=table(results(:,1),results(:,2),results(:,3),results(:,4),...
    'VariableNames',varNames);
writetable(results_table,resultsfile_path)

% 車種別にcsvに保存
for i=1:車種数
    resultsfile_path=sprintf('OD_~~_%d.csv',i);
    varNames={'code_Origin','code_Destination','Vehicle_type','Num_trips'};
    results_table=table(results((i-1)*(size(Bzone,1)^2)+1:i*(size(Bzone,1)^2),1),...
        results((i-1)*(size(Bzone,1)^2)+1:i*(size(Bzone,1)^2),2),...
        results((i-1)*(size(Bzone,1)^2)+1:i*(size(Bzone,1)^2),3),...
        results((i-1)*(size(Bzone,1)^2)+1:i*(size(Bzone,1)^2),4),...
        'VariableNames',varNames);
    writetable(results_table,resultsfile_path)
end
```

# 〆
授業向けに学生に作ってあげたのに，使われなくて悲しいので供養でした．
プログラミングはほぼ独学なのでアドバイスもらえるとうれしいです．