Python 如何使用字符串键索引多维数组,就像字典一样
Python how to index multidimensional array with string key, like a dict
我想将 numpy 的 array
的功能与本机 python 的 dict
的功能结合起来,即创建一个可以用字符串索引的多维数组。
例如,我可以这样做:
dict_2d = {'a': {'x': 1, 'y': 2},
'b': {'x': 3, 'y': 4}}
print dict_2d['a','y'] # returns 2
我知道我可以做到 dict_2d['a']['x']
但从长远来看,我希望能够像对待 numpy 数组一样对待它们,包括进行矩阵乘法等等,而这对于分层字典来说是不可能的。
写一个 class 的简单版本也不难,我只是使用 class 将所有字符串转换为 int 索引,然后使用 numpy,但我想尽可能使用已经存在的东西。
编辑:我不需要令人难以置信的性能。我可能会使用 10x10 数组。我的目标是使编写的代码简单而健壮。使用 numpy 数组与仅使用 Fortran 编写并没有太大区别。我花了足够多的时间来追踪 Fortran 索引错误...
您可能正在寻找 pandas,它提供了包装 numpy 数组的便捷数据类型,允许您按名称而不是仅按数字访问行和列。
我不喜欢给出现成的答案 - 但我认为用英语解释它会花费更多时间 -
fetch objects 的基本思想是自定义 __getitem__
方法 - 逗号分隔值作为元组呈现给方法 - 你只是按顺序使用元组中的值作为嵌套字典的索引。
除此之外,Python 使用 collections.abc 类 可以轻松创建功能齐全的 dict 等价物:如果您在从 collections[.abc].MutableMapping
继承时实现了一组最小的方法,所有字典行为都被模拟 - (__getitem__, __setitem__, __delitem__, __iter__, __len__
) - 然后,只需适当地迭代关键组件,并创建新的、空的、常规的字典来存储所需的值。
try:
from collections import MutableMapping
except ImportError:
# Python3 compatible import
from collections.abc import MutableMapping
class NestedDict(MutableMapping):
def __init__(self, *args, **kw):
self.data = dict(*args, **kw)
def get_last_key_levels(self, key, create=False):
if not isinstance(key, tuple):
key = (key,)
current_data = self.data
for subkey in key:
previous = current_data
current_data = current_data[subkey] if not create else current_data.setdefault(subkey, {})
return previous, current_data, subkey
def __getitem__(self, key):
previous, current_data, lastkey = self.get_last_key_levels(key)
return current_data
def __setitem__(self, key, value):
previous, current_data, lastkey = self.get_last_key_levels(key, True)
previous[lastkey] = value
def __delitem__(self, key):
previous, current_data, lastkey = self.get_last_key_levels(key)
del previous[lastkey]
def __iter__(self):
return iter(self.data)
def __len__(self):
return len(self.data)
def __repr__(self):
return "NestedDict({})".format(repr(self.data))
你准备好了:
>>> from nesteddict import NestedDict
>>> x = NestedDict(a={})
NestedDict({'a': {}})
>>> x["a", "b"] = 10
>>> x
NestedDict({'a': {'b': 10}})
>>> x["a", "c", "e"] = 25
>>> x
NestedDict({'a': {'c': {'e': 25}, 'b': 10}})
>>> x["a", "c", "e"]
25
>>>
请注意,这是一个高级实现,它可以正常工作,但您将无法接近您在 NumPy 上获得的优化级别——恰恰相反。如果您需要在这些对象中执行快速数据操作,您可以检查 "cython" - 或者诉诸将 dict 键转换为 nuemric 键并使用 NumPy 的想法(这个想法仍然可以从这个答案中挑选一些想法)
使用pandas
假设文件是这样的:
test.csv:
Params, Val1, Val2, Val3
Par1,23,58,412
Par2,56,45,123
Par3,47,89,984
所以你可以在python中做这样的事情:
import pandas as pd
x = pd.read_csv('test.csv', index_col='Params')
x['Val1']['Par3']
47
我想将 numpy 的 array
的功能与本机 python 的 dict
的功能结合起来,即创建一个可以用字符串索引的多维数组。
例如,我可以这样做:
dict_2d = {'a': {'x': 1, 'y': 2},
'b': {'x': 3, 'y': 4}}
print dict_2d['a','y'] # returns 2
我知道我可以做到 dict_2d['a']['x']
但从长远来看,我希望能够像对待 numpy 数组一样对待它们,包括进行矩阵乘法等等,而这对于分层字典来说是不可能的。
写一个 class 的简单版本也不难,我只是使用 class 将所有字符串转换为 int 索引,然后使用 numpy,但我想尽可能使用已经存在的东西。
编辑:我不需要令人难以置信的性能。我可能会使用 10x10 数组。我的目标是使编写的代码简单而健壮。使用 numpy 数组与仅使用 Fortran 编写并没有太大区别。我花了足够多的时间来追踪 Fortran 索引错误...
您可能正在寻找 pandas,它提供了包装 numpy 数组的便捷数据类型,允许您按名称而不是仅按数字访问行和列。
我不喜欢给出现成的答案 - 但我认为用英语解释它会花费更多时间 -
fetch objects 的基本思想是自定义 __getitem__
方法 - 逗号分隔值作为元组呈现给方法 - 你只是按顺序使用元组中的值作为嵌套字典的索引。
除此之外,Python 使用 collections.abc 类 可以轻松创建功能齐全的 dict 等价物:如果您在从 collections[.abc].MutableMapping
继承时实现了一组最小的方法,所有字典行为都被模拟 - (__getitem__, __setitem__, __delitem__, __iter__, __len__
) - 然后,只需适当地迭代关键组件,并创建新的、空的、常规的字典来存储所需的值。
try:
from collections import MutableMapping
except ImportError:
# Python3 compatible import
from collections.abc import MutableMapping
class NestedDict(MutableMapping):
def __init__(self, *args, **kw):
self.data = dict(*args, **kw)
def get_last_key_levels(self, key, create=False):
if not isinstance(key, tuple):
key = (key,)
current_data = self.data
for subkey in key:
previous = current_data
current_data = current_data[subkey] if not create else current_data.setdefault(subkey, {})
return previous, current_data, subkey
def __getitem__(self, key):
previous, current_data, lastkey = self.get_last_key_levels(key)
return current_data
def __setitem__(self, key, value):
previous, current_data, lastkey = self.get_last_key_levels(key, True)
previous[lastkey] = value
def __delitem__(self, key):
previous, current_data, lastkey = self.get_last_key_levels(key)
del previous[lastkey]
def __iter__(self):
return iter(self.data)
def __len__(self):
return len(self.data)
def __repr__(self):
return "NestedDict({})".format(repr(self.data))
你准备好了:
>>> from nesteddict import NestedDict
>>> x = NestedDict(a={})
NestedDict({'a': {}})
>>> x["a", "b"] = 10
>>> x
NestedDict({'a': {'b': 10}})
>>> x["a", "c", "e"] = 25
>>> x
NestedDict({'a': {'c': {'e': 25}, 'b': 10}})
>>> x["a", "c", "e"]
25
>>>
请注意,这是一个高级实现,它可以正常工作,但您将无法接近您在 NumPy 上获得的优化级别——恰恰相反。如果您需要在这些对象中执行快速数据操作,您可以检查 "cython" - 或者诉诸将 dict 键转换为 nuemric 键并使用 NumPy 的想法(这个想法仍然可以从这个答案中挑选一些想法)
使用pandas 假设文件是这样的:
test.csv:
Params, Val1, Val2, Val3
Par1,23,58,412
Par2,56,45,123
Par3,47,89,984
所以你可以在python中做这样的事情:
import pandas as pd
x = pd.read_csv('test.csv', index_col='Params')
x['Val1']['Par3']
47