3

我有一个字典,它提供从实数元组到标识整数的映射。给定一个包含在公差范围内但不完全等于字典中的数字的元组列表,我想生成一个相应整数的列表。

例子:

tdict = {(0.334, 0.333, 0.333):1, (0.167, 0.666, 0.167):2, (0.5, 0.5, 0):3}
tlist = [(0.333, 0.333, 0.333), (0.16667, 0.6666667, 0.17), (0.34, 0.33, 0.33), (0.5001, 0.4999, 0.0)]
tol = 0.01

运行我想要的代码应该会产生结果

ilist = [1,2,1,3]

因为每个元组中的所有数字都在tdict. 我可以通过迭代tdict.keys()并分别比较每个来做到这一点,但我觉得应该有更好的方法。获取这些元组的相应整数的最有效方法是什么?它不必涉及字典,这对我来说似乎是最自然的。我正在使用 Python 3。

4

5 回答 5

6

您显然希望在具有一定网格间距(与您的容差值直接相关)的 3D 网格上投影 3D 空间中的点并创建某种直方图。给自己写一个投影函数:它将任意的 3 元素列表/元组(描述空间中的点的向量)作为参数,并将其投影到某个网格点上。你这样做是为了填满你的字典,也为了把它读出来。此外,关于字典中的键,我认为你应该使用整数元组而不是浮点数,因为我不确定浮点数是否可以相同。

这是一个实现示例:

from collections import defaultdict
from random import random as rn

class Grid(object):
    def __init__(self, spacing):
        self.spacing = spacing
        self.griddict = defaultdict(int)

    def add_point(self, coords):
        """
        `vid`, a voxel id, is a tuple of indices, indicating one grid
        bin for each dimension, e.g. (1, 5, 2)
        rule: i_x = int(floor(x_coord / spacing))
        """
        vid = tuple([int(c//self.spacing) for c in coords])
        self.griddict[vid] += 1

    def get_point(self, coords):
        vid = tuple([int(c//self.spacing) for c in coords])
        return self.griddict[vid]

    def vid_centercoords(self, vid):
        """
        Return the real coordinates in space for a certain voxel,
        which is identified by its voxel id `vid` (a tuple of indices).
        """
        return tuple([(i-1)*self.spacing + self.spacing/2 for i in vid])



N = 20
fillpoints = [(rn(),rn(),rn()) for _ in xrange(N)]
testpoints = [(rn(),rn(),rn()) for _ in xrange(N)]

grid = Grid(spacing=0.3)

for p in fillpoints:
    grid.add_point(p)

print [grid.get_point(p) for p in testpoints]

它的作用:它在 3D 空间中创建 20 个随机向量(所有坐标都在 0 和 1 之间)。它使用空间中的这些点填充 3D 网格。网格在每个维度上的间距为 0.3。这 20 个空间点中的每一个都分配给网格中的某个体素(只是 3D 像素的一个词)。每个分配将相应体素的计数器增加 1(将网格渲染为直方图)。然后,使用另一组随机的 20 个向量来读出体素。这些点再次投影到体素上,但这一次计数器只是返回而不是增加。执行测试:

$ python gridtest.py 
[2, 1, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0]

使用您的数据执行:

fillpoints = [(0.334, 0.333, 0.333), (0.167, 0.666, 0.167), (0.167, 0.666, 0.167), (0.5, 0.5, 0), (0.5, 0.5, 0), (0.5, 0.5, 0)]
testpoints = [(0.333, 0.333, 0.333), (0.16667, 0.6666667, 0.17), (0.34, 0.33, 0.33), (0.5001, 0.4999, 0.0)]

grid = Grid(spacing=0.03)
for p in fillpoints:
    grid.add_point(p)
print [grid.get_point(p) for p in testpoints]

它根据需要打印[1, 2, 1, 3]。我没有深入思考过这种关系spacing=3*tolerance。这很可能是错误的。我只知道存在确定性关系。证明/找到这个公式留给你作为练习:)

于 2012-08-31T16:03:31.243 回答
2

如果您有权访问 numpy,则可以使用numpy.allclose来检查匹配项:

>>> import numpy
>>> numpy.allclose((0.334, 0.333, 0.333), (0.333, 0.333, 0.333))
False
>>> numpy.allclose((0.334, 0.333, 0.333), (0.333, 0.333, 0.333), atol=0.1)
True
于 2012-08-31T16:15:46.263 回答
2
  1. 依次按tdict.keys()到每个点的距离排序。tlist
  2. 选择前几个并在 中查找它们tdict
于 2012-08-31T16:03:10.303 回答
1

您可以创建一个查找函数(查找元组的舍入版本):

def look_up_tdict( t ):
    return tdict[ (float('%.3f' % t[0]),
                   float('%.3f' % t[1]),
                   float('%.3f' % t[2])
                 ]

注意:如果字典中没有任何内容接近t. 然后你可以填充ilist

ilist = [ look_up_tdict(t) for t in tlist ]
于 2012-08-31T16:11:25.783 回答
0
 tolerance = 0.1
 for i in tlist:
      list2 = filter(lambda x:abs(sum(i)-sum(x))<tolerance,tdict
      print [tdict[itm] for itm in list2]

我认为这会起作用......虽然不是积极的......事实上它看起来并没有给你想要的输出

于 2012-08-31T16:06:37.247 回答