MATLABで日本語混じりのEXCELのデータを操作する

## はじめに
　さて、年中行事のアドベントカレンダーにおける"MATLAB de EXCEL"を今年も紹介していきたいと思います。

 MATLAB de EXCEL の過去記事：
　[MATLABにファイルデータを読みこむ関数](https://qiita.com/Monzo_N/items/ddcb5d80bed3a3ceb66c)
　[MATLABからファイルデータを書き出す関数](https://qiita.com/Monzo_N/items/0927e71b2b38f524001f)
 　[MATLABからEXCELに書き出す](https://qiita.com/Monzo_N/items/d8188ae9cb86b02de75a)

 
 今回は日本語混じりのファイルを読み込み、データ操作を行い、書き出す、というものをご紹介します。なお、今回の内容は、MATLAB R2023b Windows版で動作させたものとなります。

 ## 1. 素材データの用意
 まず、素材として、csvファイルを用意します。ここでは、特許検索サイトの [JPlatPat](https://www.j-platpat.inpit.go.jp/) で検索した結果をcsvファイルに落としたものを用意しました。
 『ビットコイン』、『採掘者』をキーワードとして検索した結果をcsvファイルでダウンロードします（csvファイルのダウンロードは無料ですが、登録が必要です。余談ですが）。
 『ビットコイン』について195件、『採掘者』について187件のデータがあります。
 
![ビットコイン.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/a403a6a9-5fe9-a7d7-f28a-613e098ae125.jpeg)
    『ビットコイン』の検索結果（部分）

  ## 2.文字を含むファイルを読み込む関数（readtable, readcell, readmatrix)
MATLABでcsvファイルを読み込む関数は、古いところではcsvreadがありますが、今回は新しい関数を用いてみます。
新しい関数はreadcell、readtable、readmatrixがあります。
readmatrixで普通に読み出すとNaNしか出てきませんので、出力データ型の指定が必要となります。
また、readtableでテーブルの見出しを表示したい場合は、'VariableNamingRule','preserve'が必要となります。

 ```matlab
filename = 'ビットコイン.csv';% ファイル名は日本語もOK　

MC = readcell(filename); % MCにセル型で出力される

MT = readtable(filename,'VariableNamingRule','preserve'); % MTにtable型で出力される

MX = readmatrix(filename,'OutputType','string'); % 出力型の指定が必要 　
```

readmatrixの場合には、数値と文字列が混在しているときに、全てが文字列になってしまうため、用途によってはお勧めできません。

  ## 3.読み込んだファイルをマージする

"ビットコイン.csv"と”採掘者.csv”を読み込んでマージさせてみましょう。

 ```matlab
filename1 = 'ビットコイン.csv';
filename2 = '採掘者.csv';　

% ビットコイン.csvの読み込み
MC1 = readcell(filename1); % セルに読み込み
MT1 = readtable(filename1,'VariableNamingRule','preserve'); % tableに読み込み
MX1 = readmatrix(filename1,'OutputType','string'); % マトリクスに読み込み

% 採掘者.csvの読み込み
MC2 = readcell(filename2); % セルに読み込み
MT2 = readtable(filename2,'VariableNamingRule','preserve'); % tableに読み込み
MX2 = readmatrix(filename2,'OutputType','string'); % マトリクスに読み込み
```

これらを同じタイプのもの同士でマージするわけですが、それぞれのcsvにはタイトル行があります。
なので、マージのときには連結するほうの（後ろのほうの）csvのタイトル行を削除しなければなりません。

 ```matlab
%セル配列の結合
MC12 = [MC1;MC2(2:end,:)]; % MC2は2行目以下を用いる

%tableの結合
MT12 = [MT1;MT2]; % table型はタイトル行は自動的に修正される

%マトリクスの結合
MX12 = [MX1;MX2(2:end,:)]; % MX2は2行目以下を用いる

```

これでマージできます。
と、思いきや、Table型のマージで失敗しているようです。

 ```matlab
次を使用中のエラー: tabular/vertcat
table 変数 '公告番号' は、ある table では cell 配列で、別の
table では cell 配列ではないため、連結することができません。
```

csvファイルの中に、値がないところがあり、読み込む際にcell配列になるところと、ならないところがあって、マージがうまくいかないようです。
この問題は、次のように入力オプションをつけることで、解決するようです。

```matlab
filename1 = 'ビットコイン.csv';
filename2 = '採掘者.csv';

opts = detectImportOptions(filename1,'VariableNamingRule','preserve');
opts = setvaropts(opts,'FillValue',' ');

% ビットコイン.csvの読み込み
MT1 = readtable(filename1,opts); % tableに読み込み

% 採掘者.csvの読み込み
MT2 = readtable(filename2,opts); % tableに読み込み

%両者をマージする
MT12 = [MT1;MT2]; % table型はタイトル行は自動的に修正される
```

  ## 4. optsって何？
前の章で、いきなり "opts" が出てきます。MathWorksのドキュメント、例えば [readtable](https://jp.mathworks.com/help/matlab/ref/readtable.html) の項でも、インポート オプション オブジェクト optsとあるのですが、わかりにくいです。
簡単に説明してみます。
```matlab
T = readtable(filename);
% これは、filenameの中身をtable型で読み込み、Tに入力するものです。
% 細かい読み込み設定は、"デフォルト" となります。

T = readtable(filename,Name,Value);
% これは、デフォルトの設定では不都合があって、設定を変えたい場合に
% 使います。設定の名前(Name)と設定値(Value) を組み合わせて指定します。

T = readtable(filename,Name1,Value1,Name2,Value2);
% こういう風にして、複数の設定を変更することができます。ですが、
% 変更箇所が多くなると、やたら長くなったりして面倒です。
% そこで、
opts = detectImportOptions(filename);
% これを実行すると、optsの中に読み込み時の設定が全て入力されます。
% なので、必要なところを適宜変更します。
% 変更するには、setvaroptsを用います。例えば、本稿では、
opts = setvaropts(opts,'FillValue',' ');
% で、読み込む値がないセルを、スペース（' ')で埋めるようにしています。

T = readtable(filename,opts);
% とすると、変更された設定で読み込んでくれるようになります。

%%%%% 備考 %%%%%
%※optsのプロパティ'MissingRule'が'fill'でない場合、
　opts = setvaropts(opts,'FillValue',' ');
% を行なっても、「値を入れて埋める」設定にはなっていないので、
% 空白に置き換えることはされません（このあたり、何かノウハウがある
% みたいなんですが、今回はパスします）
%※※optsの値の設定パラメータについては、ドキュメントに部分的に
% 載っているところしか発見できませんでした。
%※※※optsの中のパラメータ（disp(opts)で表示されるもの）については、
 opts.Encoding = 'SHIFT_JIS'; 
%のようにして設定します。もしくは、
 opts1 = detectImportOptions('myDataTT.csv','Encoding','SHIFT_JIS');
% のようにします。
```


  ## 5. ダブリを除く
これでマージできたわけですが、「ビットコイン」をキーワードにした特許と、「採掘者」をキーワードにした特許にはダブリがあり、両方のキーワードを含む特許が重複されてしまいます。

読み込んだ２つのcsvファイルに対し、ここでは1列目の"文献番号"を参照して、同じものを排除しましょう。
重複を探すには ismember を用います。
```matlab
% セルの場合
Lia1C = ~ismember(MC1(:,1),MC2(:,1)); % MC2と重複していないMC1の項目にフラグ１を立てる（~はNOT）
Lia2C = ~ismember(MC2(:,1),MC1(:,1)); % MC1と重複していないMC2の項目にフラグ１を立てる
MC2P = MC2(Lia2C,:); % MC1と重複しないMC2を取り出す
MC12 = [MC1;MC2P]; % マージする

% Tableの場合
Lia2T = ~ismember(MT2(:,1),MT1(:,1)); % MT1と重複していないMT2の項目にフラグ１を立てる
MT2P = MT2(Lia2T,:); % MT1と重複しないMT2を取り出す
MT12 = [MT1;MT2P]; % マージする

% マトリクスの場合
Lia2X = ~ismember(MX2(:,1),MX1(:,1)); % MX1と重複していないMX2の項目にフラグ１を立てる
MX2P = MX2(Lia2X,:); % MX1と重複しないMX2を取り出す
MX12 = [MX1;MX2P]; % マージする
```

## 6. ソートする
ダブリがないようにしてマージしましたが、２つをくっつけただけなので、ここでソートして順番を整えます。
ソートにはsortrowsを用います。
```matlab
%セルの場合
MC12_Sort = sortrows(MC12,2); % 2行目の要素に基づいてソート

%テーブルの場合
MT12_Sort = sortrows(MT12,'文献番号'); % 行名が使える

%マトリクスの場合
MX12_Sort = sortrows(MX12,1);%1列目の要素に基づいてソート
```

## 7. 書き出す

最後にソートしたデータを書き出してみましょう。csvファイルに書き出す場合、そのままですと UTF-8 で書き出されて（そしてそれをShift-JISで読み込まれた結果）文字化けしてしまうので、encodingをSHIFT_JISにするオプションをつける必要があります。
それと、セルの場合において、空白のセルが "Missing" になっており、このまま書き出そうとするとエラーが出るので、下記のようにして"Missing" を"　 " (空白）に変換してから書き出します。
cellfunは、セル配列の個々のセルに対して、演算を行う場合に使います。

```matlab
%セルの場合
MC12_Sort(cellfun(@(x) all(ismissing(x)), MC12_Sort)) = {' '}; % Missingを空白に変換する
writecell(MC12_Sort,'セル.xlsx');
writecell(MC12_Sort,'セル.csv','Encoding','SHIFT_JIS');

%テーブルの場合
writetable(MT12_Sort,'テーブル.xlsx');
writetable(MT12_Sort,'テーブル.csv','Encoding','SHIFT_JIS');

%マトリクスの場合
writematrix(MX12_Sort,'マトリクス.xlsx');
writematrix(MX12_Sort,'マトリクス.csv','Encoding','SHIFT_JIS');
```

## 8. エクセルファイルの読み込み
今回、CSVファイルの読み込みから話を始めてしまいましたが、エクセルファイル（xlsxなど）においても同様に読み込むことができます。
ただし、指定できるオプションが異なるところがあり、

```matlab
% CSVの場合
opts_csv = detectImportOptions("ビットコイン.csv")

% EXLSの場合
opts_xlsx = detectImportOptions("ビットコイン.xlsx")

```
を実行してみますと、例えばデリミタとかエンコーティングなどの設定はCSVにしかなく、逆にsheet、DataRangeなどはエクセルにしかありません。このあたりには注意が必要です。


## 9．終わりに
以上、MATLABでEXCELのデータを操作する方法をまとめてみました。
パラメータがデフォルトのままで、サクッと動いてくれればよいのですが、引っ掛かるところがあるため、TIPSとして書かせていただきました。
誰かのお役に立てば幸いです。