自定义索引的数据结构

时间:2013-08-28 01:30:35

标签: python numpy indexing

我希望编写一个数据结构来表示一些遗传数据。这个数据可以表示为大小n的列表,其中每个条目也有一个“遗传位置”,它是0到1之间的实数。为了使术语清晰,我将在列表中调用该位置id和基因位置gpos。我实现这个的方式是一个带

的类
class Coords(object):

    def __init__(self, *args, **kwargs):
        self.f = list(*args, **kwargs)
        self.r = dict()
        for i,e in enumerate(self.f):
            self.r[e] = i

    def __setitem__(self,x,y):
        self.f.__setitem__(x,y)
        self.r.__setitem__(y,x)

    def __getitem__(self,x):
        return self.f.__getitem__(x)

    def __len__(self):
        return self.f.__len__()

现在,我有两个问题。第一个是self.r的浮点数是浮点数,这显然是一个坏主意。我想将它们转换为字符串(具有固定数字的数字),但有更好的想法吗?我遇到的另一个问题是我想通过gpos实现访问条目,所以如果我想访问gpos 0.2和0.4之间的所有内容,我希望能够做到使用

import numpy as np
Coords(np.arange(1,0,-.1))
c.r[0.2:0.4]

有一种简单的方法可以定义吗?我正在考虑使用二进制搜索找到正确的id开始和结束位置,然后使用这些ID访问self.f,但有没有办法实现上述语法?

2 个答案:

答案 0 :(得分:5)

使用切片索引对象时,Python会使用您提供的输入创建一个slice对象。例如,如果您执行c[0.2:0.4],则传递给c.__getitem__的参数将为slice(0.2, 0.4)。因此,您可以在__getitem__方法中使用此代码:

def __getitem__(self, x):
    if isinstance(x, slice):
        start = x.start
        stop = x.stop
        step = x.step
        # Do whatever you want to do to define your return
    ...

如果你想在Coords对象上但不在self.r字典中使用这个花哨的索引,我认为最简单的方法是创建一个FancyIndexDict,它是一个子类。 dict,修改其__getitem__方法,然后将self.r设为FancyIndexDict,而不是dict

答案 1 :(得分:3)

如果您知道您的gpos值将(或可以)始终按排序顺序存储,那么我肯定建议使用二进制搜索来完成此任务。您可以利用searchsorted的数组语法和numpy内置实现:

>>> gpos_vals = np.linspace(0, 1, 11)
>>> gpos_vals
array([ 0. ,  0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7,  0.8,  0.9,  1. ])
>>> lo, hi = gpos_vals.searchsorted([0.22, 0.52])
>>> lo, hi
(3, 6)
>>> gpos_vals[lo:hi]
array([ 0.3,  0.4,  0.5])

我认为这很好地避免了你指出的关于为字典键使用浮点数的问题,这可能会有问题。

您还可以将此答案与Jaime合并,并创建一个在自定义__getitem__内查找切片的类,然后将切片参数传递给searchsorted,如我的代码段所示:

class GeneticPositions(object):
    def __init__(self, gpos_values):
        self.gpos_values = np.asarray(gpos_values)

    def __getitem__(self, x):
        if isinstance(x, slice):
            lo, hi = self.gpos_values.searchsorted(
                [x.start or 0, x.stop or 1])
            return self.gpos_values[lo:hi]
        return self.gpos_values[x]