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