【问题标题】:python tensors with named field access具有命名字段访问的python张量
【发布时间】:2014-04-05 16:47:48
【问题描述】:

我想在 Python 中使用类似于或优于 R 数组的东西。 R 数组是具有 dimnames 属性的类张量对象,它允许直接允许基于名称(字符串)对张量进行子集化。在 numpy 中,recarrays 允许列名,pandas 允许灵活高效的二维数组子集。 Python 中是否有一些东西允许通过使用名称(或者更好的是,在 Python 中可散列且不可变的对象)来进行与 ndarray 的切片和子集类似的操作?

【问题讨论】:

  • 这就是你要找的东西:pandas Panel
  • 没有。 pandas.panel 只是在宽矩阵上返回一个长表示(或者用类似重塑的行话,它会融化它)。我正在寻找具有命名轴标签的真正张量对象。

标签: python r numpy multidimensional-array recarray


【解决方案1】:

从字符串列表到索引的快速而肮脏的映射怎么样?您可以使用可调用类清理符号。

def make_dimnames(names):
    return [{n:i for i,n in enumerate(name)} for name in names]
def foo(d, *args):
    return [d[x] for x in args]

A = np.arange(9).reshape(3,3)
dimnames = [('x','y','z'),('a','b','c')]
Adims = make_dimnames(dimnames)
A[foo(Adims[0],'x','z'),foo(Adims[1],'b')]  # A[[0,2],[1]]
A[foo(Adims[0],'x','z'),slice(*foo(Adims[1],'b','c'))]  # A[[0,2],slice(1,2)]

或者R 是否对暗名做了更重要的事情?

一个类稍微压缩了语法:

class bar(object):
    def __init__(self,dimnames):
        self.dd = {n:i for i,n in enumerate(dimnames)}
    def __call__(self,*args):
        return [self.dd[x] for x in args]
    def __getitem__(self,key):
        return self.dd[key]
d0, d1 = bar(['x','y','z']), bar(['a','b','c'])
A[d0('x','z'),slice(*d1('a','c'))]

http://docs.scipy.org/doc/numpy/user/basics.subclassing.html sublassing ndarray,带有添加属性(可能是 dinnames)的简单示例。大概扩展索引以使用该属性应该不难。

numpy/index_tricks__getitem__ 的使用启发,我概括了索引:

class DimNames(object):
    def __init__(self, dimnames):
        self.dd = [{n:i for i,n in enumerate(names)} for names in dimnames]
    def __getitem__(self,key):
        # print key
        if isinstance(key, tuple):
            return tuple([self.parse_key(key, self.dd[i]) for i,key in enumerate(key)])
        else:
            return self.parse_key(key, self.dd[0])
    def parse_key(self,key, dd):
        if key is None:
            return key
        if isinstance(key,int):
            return key
        if isinstance(key,str):
            return dd[key]
        if isinstance(key,tuple):
            return tuple([self.parse_key(k, dd) for k in key])
        if isinstance(key,list):
            return [self.parse_key(k, dd) for k in key]
        if isinstance(key,slice):
            return slice(self.parse_key(key.start, dd),
                         self.parse_key(key.stop, dd),
                         self.parse_key(key.step, dd))
        raise KeyError

dd = DimNames([['x','y','z'], ['a','b','c']])

print A[dd['x']]              # A[0]
print A[dd['x','c']]          # A[0,2]
print A[dd['x':'z':2]]        # A[0:2:2]
print A[dd[['x','z'],:]]      # A[[0,2],:]
print A[dd[['x','y'],'b':]]   # A[[0,1], 1:]
print A[dd[:'z', :2]]         # A[:2,:2]

我想进一步的步骤是继承A,添加dd作为属性,并更改其__getitem__,将符号简化为A[['x','z'],'b':]

【讨论】:

  • R 在子集化方面并没有做更多的事情。实际上,您的第二个示例正在做 R 不能做的事情。但是,对于大多数示例,R 的语法更简洁(我无法在 Python 中重现——我的错)并且不需要携带 Adims 对象;即 A[['x','z'],'b' ], 或 A[['x','z'], ['b']]。我的第二个担心是当堆叠张量时,R 会处理属性,而这种方法不会。我的第三个担心是我我反对重新发明轮子,宁愿使用已经成熟的东西。
  • 我为__getitem__ 添加了更多功能,因此它可以直接处理切片、元组等。它尝试复制现有的numpy getitem,并在字符串的情况下添加字典查找。
猜你喜欢
  • 2021-07-31
  • 2017-11-21
  • 1970-01-01
  • 1970-01-01
  • 2018-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多