与えられたルーチン(scipyを使用してMatlab .matファイルをロードする方法)を使用すると、より深くネストされた構造にアクセスして辞書に復元できませんでした
私が遭遇する問題をより詳細に示すために、次のおもちゃの例を示します。
load scipy.io as spio
a = {'b':{'c':{'d': 3}}}
# my dictionary: a['b']['c']['d'] = 3
spio.savemat('xy.mat',a)
次に、mat-FileをPythonに読み戻します。私は以下を試しました:
vig=spio.loadmat('xy.mat',squeeze_me=True)
取得したフィールドにアクセスしたい場合:
>> vig['b']
array(((array(3),),), dtype=[('c', '|O8')])
>> vig['b']['c']
array(array((3,), dtype=[('d', '|O8')]), dtype=object)
>> vig['b']['c']['d']
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
/<ipython console> in <module>()
ValueError: field named d not found.
ただし、オプションstruct_as_record=False
フィールドにアクセスできます:
v=spio.loadmat('xy.mat',squeeze_me=True,struct_as_record=False)
今ではそれにアクセスすることが可能でした
>> v['b'].c.d
array(3)
以下は、scipy.ioのロードマットの代わりにこのロードマットを使用するだけで辞書を再構築する関数です。
import scipy.io as spio
def loadmat(filename):
'''
this function should be called instead of direct spio.loadmat
as it cures the problem of not properly recovering python dictionaries
from mat files. It calls the function check keys to cure all entries
which are still mat-objects
'''
data = spio.loadmat(filename, struct_as_record=False, squeeze_me=True)
return _check_keys(data)
def _check_keys(dict):
'''
checks if entries in dictionary are mat-objects. If yes
todict is called to change them to nested dictionaries
'''
for key in dict:
if isinstance(dict[key], spio.matlab.mio5_params.mat_struct):
dict[key] = _todict(dict[key])
return dict
def _todict(matobj):
'''
A recursive function which constructs from matobjects nested dictionaries
'''
dict = {}
for strg in matobj._fieldnames:
elem = matobj.__dict__[strg]
if isinstance(elem, spio.matlab.mio5_params.mat_struct):
dict[strg] = _todict(elem)
else:
dict[strg] = elem
return dict
マージの回答に対する単なる拡張機能です。残念ながら、オブジェクトのセル配列に到達すると再帰が停止します。次のバージョンでは、代わりにそれらのリストを作成し、可能であればセル配列要素への再帰を続行します。
import scipy
import numpy as np
def loadmat(filename):
'''
this function should be called instead of direct spio.loadmat
as it cures the problem of not properly recovering python dictionaries
from mat files. It calls the function check keys to cure all entries
which are still mat-objects
'''
def _check_keys(d):
'''
checks if entries in dictionary are mat-objects. If yes
todict is called to change them to nested dictionaries
'''
for key in d:
if isinstance(d[key], spio.matlab.mio5_params.mat_struct):
d[key] = _todict(d[key])
return d
def _todict(matobj):
'''
A recursive function which constructs from matobjects nested dictionaries
'''
d = {}
for strg in matobj._fieldnames:
elem = matobj.__dict__[strg]
if isinstance(elem, spio.matlab.mio5_params.mat_struct):
d[strg] = _todict(elem)
Elif isinstance(elem, np.ndarray):
d[strg] = _tolist(elem)
else:
d[strg] = elem
return d
def _tolist(ndarray):
'''
A recursive function which constructs lists from cellarrays
(which are loaded as numpy ndarrays), recursing into the elements
if they contain matobjects.
'''
elem_list = []
for sub_elem in ndarray:
if isinstance(sub_elem, spio.matlab.mio5_params.mat_struct):
elem_list.append(_todict(sub_elem))
Elif isinstance(sub_elem, np.ndarray):
elem_list.append(_tolist(sub_elem))
else:
elem_list.append(sub_elem)
return elem_list
data = scipy.io.loadmat(filename, struct_as_record=False, squeeze_me=True)
return _check_keys(data)
私はscipyメーリングリスト( https://mail.python.org/pipermail/scipy-user/ )で、このデータにアクセスする方法が2つあるとアドバイスされました。
これは機能します:
import scipy.io as spio
vig=spio.loadmat('xy.mat')
print vig['b'][0, 0]['c'][0, 0]['d'][0, 0]
私のマシンの出力:3
この種のアクセスの理由:「歴史的な理由により、Matlabではすべてがスカラーでさえ、少なくとも2D配列です。」したがって、scipy.io.loadmatはデフォルトでMatlabの動作を模倣します。
解決策が見つかると、「scipy.io.matlab.mio5_params.mat_structオブジェクト」のコンテンツにアクセスできます。
v['b'].__dict__['c'].__dict__['d']
機能する別の方法:
import scipy.io as spio
vig=spio.loadmat('xy.mat',squeeze_me=True)
print vig['b']['c'].item()['d']
出力:
3
私はこの方法をscipyメーリングリストでも学びました。私は確かに(まだ) '.item()'を追加する必要がある理由を理解していません:
print vig['b']['c']['d']
代わりにエラーをスローします:
IndexError:整数、スライスのみ(:
)、省略記号(...
)、numpy.newaxis(None
)および整数またはブール配列は有効なインデックスです
しかし、私がそれを知っているとき、私は説明を補足するために戻ってきます。 numpy.ndarray.itemの説明(numpyリファレンスから):配列の要素を標準のPythonスカラーにコピーして返します。
(この回答は基本的に最初の質問に対するhpauljのコメントと同じですが、コメントは「見えない」または十分に理解できないと感じました。最初の解決策を探したとき、私は確かにそれに気付きませんでした。時間、数週間前)。