【问题标题】:Python how to index multidimensional array with string key, like a dictPython如何用字符串键索引多维数组,如字典
【发布时间】:2015-07-23 19:19:30
【问题描述】:

我想将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 数组一样对待它们,包括进行矩阵乘法等,而分层 dicts 则不可能。

编写一个简单版本的类也不难,我只是使用该类将所有字符串转换为 int 索引,然后使用 numpy,但如果可能的话,我想使用已经存在的东西。

编辑:我不需要令人难以置信的表现。我将使用 10x10 数组。我的目标是让编写代码变得简单而健壮。使用 numpy 数组与仅在 Fortran 中编写它并没有太大的不同。我已经花费了足够多的时间来追踪 Fortran 索引错误...

【问题讨论】:

  • 您真的需要将数据存储在嵌套结构中吗?你可以只使用一个键是元组的字典。
  • @BrenBarn 可能会使用 大量 内存
  • 你想通过不使用 numpy 来实现什么?如果您只想要行/列的字符串标签,请查看pandas,它提供了很好的表格数据类型,可以包装 numpy 数组。
  • @BrenBarn 我根本不想避免 numpy。它似乎并没有自己做字符串标签。 pandas 看起来就像我希望的那样。我会更详细地检查一下
  • @BrenBarn Pandas 正是我想要的。如果你想把它写成答案,我会接受。

标签: python numpy dictionary indexing pandas


【解决方案1】:

您可能正在寻找 pandas,它提供了包装 numpy 数组的便捷数据类型,允许您按名称而不是仅按数字访问行和列。

【讨论】:

    【解决方案2】:

    我不喜欢给出现成的答案 - 但我认为用英语解释它需要更多时间 -

    fetch 对象的基本思想是 numpy 的方式是自定义 __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 键转换为数字键并使用 NumPy 的想法(这个想法仍然可以从这个答案中挑选一些想法)

    【讨论】:

    • BrenBarn 的 pandas 建议可以满足我的大部分需求,尽管它似乎不允许 NestedDict['a', 'x']。正如你所描述的那样,用__getitem____setitem__ 在 pandas 上包裹一层薄薄的层会将它们拉到一起。
    【解决方案3】:

    使用熊猫 假设文件是​​这样的:

    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
    

    【讨论】:

      猜你喜欢
      • 2013-11-05
      • 1970-01-01
      • 2011-07-28
      • 1970-01-01
      • 2016-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-16
      相关资源
      最近更新 更多