MATLAB R2022b の新機能:辞書型(dictionary)を触ってみよう
※この投稿は 2022 年 9 月 15 日に The MATLAB blog (Mike Croucher) に投稿されたものの抄訳です。
最近リリースされた MATLAB R2022b の注目の新機能といえば Dictionaries ですね。
この新しいデータ型の何が嬉しいのか、詳細に見ていきます。
辞書(ディクショナリ)はキーと値のペアの集まり
ディクショナリー(プログラミング言語によっては連想配列や連想リスト、辞書とも呼ばれます)は、キーと値のペアの集まりで、それぞれのキーが値に対応します。 例えば、Mike、Dave、Bob という 3 人の体重を記録するために、gym という辞書を使用するとします。MATLAB でこれを作成するにはどうしたらよいでしょうか?
names = [“Mike”,“Dave”,“Bob”];
weights = [89,75,68]; % 体重 (kg)
gym = dictionary(names,weights)
この辞書オブジェクトがあれば、関連するキー(この場合は人名)を指定することで、任意のエントリーの重さを確認することができます。
gym(“Dave”)
gym(“Bob”)
このルックアップ操作は、位置ではなく、ユニークなキーに依存し、辞書のうま味の鍵(ダジャレ感・・)となっています。 辞書は高速に検索できるように完全に最適化されており、定数時間(ビッグO表記だと O(1))で検索できます。つまり、10 要素の辞書の項目を検索するのも、1000 万要素の辞書と同じくらいの処理時間です(少なくとも理論上は!)。
また「辞書のキーは一意」であるという点が重要です。 この辞書でもう1つ 別の値を “Bob “に割り当てると、”Bob ” という 2 番目のエントリーを作成するのではなく、”Bob “がマッピングされていた値を上書きすることになります。
大事なのでもう一度言います。各キーは1つだけです。
gym(“Bob”)=110
キーが辞書になかったらどうなる?
isKey(gym,“Michelle”)
存在しないキーを検索しようとすると、エラーになります。
gym(“Michelle”)
ただ、今度は存在しないキーに代入すると、そのキーと値のペアが辞書に挿入さることになります。
gym(“Michelle”) = 70
全部のキーと値を配列として取り出す
gymkeys = keys(gym)
同様に、存在する値も value 関数で確認できます。
gymvalues = values(gym)
gymkeys 配列の各要素は gymvalues 配列の各要素に対応していることに気が付かれたと思います。 例えば,”Bob” は gymkeys の 3 番目の要素であり,体重は gymvalues の 3 番目の要素ですね。 また、キーと値は、辞書に挿入されたのと同じ順序で返されます。 理論的には、辞書は順序のないオブジェクトですが、MATLABの実装では挿入順序が維持される点に注意ください。。
辞書を構築する 3 つの方法
MATLAB で辞書を作成するには、現在 3 つの方法があります。上で使った方法は、ある意味 MATLAB らしい方法=ベクトル化された方法です。キーの配列と値の配列をそれぞれ作成し、その両方を dictionary に渡すことで辞書を作成しました。こんな感じです。
ベクトル化
fruits = [“Apple”,“Pear”,“Banana”];
colours = [“Red”,“Green”,“Yellow”];
d1 = dictionary(fruits,colours)
キーと値を交互に入力する
別の方法として、次のようにキーと値を交互に入力する方法でも OK です。
d2 = dictionary(“Apple”,“Red”, …
“Pear”,“Green”, …
“Banana”,“Yellow”)
改行は読みやすさのためで、以下でも 大丈夫。
d2 = dictionary(“Apple”,“Red”,“Pear”,“Green”,“Banana”,“Yellow”)
空の辞書から始める
最後の方法は、空の辞書から始める方法です
d3 = dictionary()
空の辞書にキーと値のペアをひとつずつ追加していきます。
d3(“Apple”) = “Red”
d3(“Pear”) = “Green”
d3(“Banana”) = “Yellow”
それぞれ処理速度に差はあるものの、結果として同じ辞書ができあがります。
辞書型がもつ項目数を数える
辞書の項目数を返すには、新しい関数 numEntries を使用します。
numEntries(d3)
初めて辞書を使ってみたときに代わりに numel を使ってみたのですが・・こんな結果でした。
numel(d3)
実はこれバグとして報告しちゃたんですが、ここでは d3 という 1 つの辞書がありその中にエントリーを含んでいると考えるのでので、結果が 1 というのは正しいんですね。
空の辞書について深掘り: isConfigured
空の辞書をもう少し詳しく見てみましょう。
newDict = dictionary()
isConfigured(newDict)
未設定?それがどうした・・と思われるかもしれません。 未設定の辞書ではできないことがあります。 例えば、あるキーが存在するかどうかを確認することはできません。
isKey(newDict,“SomeKey”)
辞書を定義するには単にエントリーを追加するだけで OK。
newDict(datetime(“2022-09-06”)) = “today”
1 つのエントリを追加しすることで、キーが datetime 型、値が string 型になるように辞書 newDict が設定されました。
isConfigured(newDict)
では・・空だけど設定された辞書を持つにはどうしたらいいのか。 R2022b では必要な型の空の配列で辞書を作成すれば OK です。
emptyAndConfigured = dictionary(string.empty,double.empty)
isConfigured(emptyAndConfigured)
もちろんベクトル処理可能
「MATLAB なんだから当然ベクトル化されてますよ!」というのが、この質問をしたときに開発から返ってきた答えでした。少し掘り下げてみます。
names = [“Mike”,“Dave”,“Bob”];
weights = [89,75,68]; % 体重 (kg)
gym = dictionary(names,weights)
ベクトル化された”割り当て”を行うことも当然できます。Mike と Bob の重みを同時に変えてみます。
gym([“Mike”,“Bob”]) = [80,73]
スカラー展開も大丈夫。 二人の双子がジムに入会し、体重が同じだった場合とか。
gym([“Twin 1”,“Twin 2”]) = 100
また、ベクトル化された”検索”も可能です。 返される値の配列の形は、キーのクエリと同じになります。
gym([“Mike”,“Bob”;“Twin 1”,“Dave”])
そうなると当然気になるのが・・“入力されたキーに存在しないものが入っていたらどうなるのか “ですね。
gym([“Mike”,“Bob”;“DoesNotExist”,“Dave”])
こうなります。エラーです。
辞書の出力・保存方法
辞書オブジェクトの保存方法ですが・・まずは .mat ファイル。行列やその他のものと同じように保存できます。
% gym を mydictionary.mat に保存
save(“mydictionary”,‘gym’)
辞書を .csv ファイルにエクスポートしたい場合、まず table に変換してから出力します。
entries 関数で辞書から table 型、構造体、セルへの変換できます。 例えば table の場合はこんな感じ。
gymTable = entries(gym,“table”)
このテーブルの項目は、元の辞書に挿入された順番になっていることに注意してください。 これを.csvファイルに出力するには writetable ですね。
writetable(gymTable,“gym.csv”)
辞書の活用例:単語の出現回数
辞書の古典的な使い方の 1 つはファイル内の単語の出現回数でしょうか。MATLAB にも同梱されている、William Shakespeareの「The Sonnets」でやってみましょう。まず、テキストを読み込み不要な句読点を削除し、すべてを小文字に変換します。
sonnets = string(fileread(‘sonnets.txt’));
punctuationCharacters = [“.” “?” “!” “,” “;” “:”];
sonnets = replace(sonnets,punctuationCharacters,” “);
sonnets = lower(sonnets);
文字列を単語の配列に分割します。
words = split(sonnets);
全単語数と、ユニークな単語数を確認すると・・
numberOfWords = numel(words)
numberOfUniqueWords = numel(unique(words))
各単語の出現回数を数えるために、まず、キーが string、値が double の空の辞書を作成します。
d = dictionary(string.empty,double.empty);
次に、すべての単語を繰り返し処理します。 各単語について、それがすでに辞書に存在するかどうかを確認します。 存在する場合は、値を1つ増やし、存在しない場合は、値を 1 にして新しいエントリーを作成します。
for word = words’
if isKey(d,word) % 辞書に存在するかどうか
d(word) = d(word) +1; % したら値を +1
else
d(word) = 1; % しない場合は 1
end
end
d
この辞書には 3436 の項目があり、これは先ほど見つけたユニークな単語数と同じ。いいですね。もう 1 つのチェックとして、すべての値を合計して、先ほど見つけた単語の総数と同じであることも確認しておきます。
numberOfWords=sum(values(d))
シェイクスピアは、憎しみ(hate)よりも愛(love)についてたくさん語っていたことがわかりますね。
d(“love”)
d(“hate”)
話しは続く・・
MATLAB におけるこの新しいデータ型についての紹介はひとまず以上です。今回の投稿は辞書をテーマとした 3 つの投稿のうちの 1 つです。次の 2 つでは、辞書で使用できるユーザー定義クラスを含むさまざまな型について深く掘り下げるとともに、この辞書と由緒ある containers.map とを比較する予定です。引き続き MATLAB の新バージョンを楽しんでください!
- Category:
- 機能と使い方
Comments
To leave a comment, please click here to sign in to your MathWorks Account or create a new one.