我有一个列表(包含元组),我想基于第一个元素是否在其他元素的最大距离内来合并列表(如果delta值<0.05)。我将以下列表作为示例:
[(0.0, 0.9811758192941256), (1.00422, 0.9998252466431066), (0.0, 0.9024831978342827), (2.00425, 0.9951777494430947)]
这应该产生类似的东西:
[(0.0, 1.883659017),(1.00422, 0.9998252466431066),(2.00425,0.9951777494430947)]
我想我可以使用与此问题类似的东西(Merge nested list items based on a repeating value),但许多其他问题也会产生类似的答案。我看到的唯一问题是他们使用collections.defaultdict
或itertools.groupby
,这需要元素的精确匹配。这里一个重要的补充是我希望合并元组的第一个元素是元素的加权混合,例如如下:
(1.001,80)
和(0.99,20)
,结果应为(0.9988,100)
。
是否有类似的可能,但基于价值差异和不完全匹配的匹配?
我自己尝试(但不喜欢它的外观)是:
Res = 0.05
combinations = itertools.combination(list,2)
for i in combinations:
if i[0][0] > i[1][0]-Res and i[0][0] < i[1][0]+Res:
newValue = ...
- 更新 -
基于一些评论和Dawgs回答,我尝试了以下方法:
for fv, v in total:
k=round(fv, 2)
data[k]=data.get(k, 0)+v
使用以下列表(实际数据示例,而不是简短示例列表):
total = [(0.0, 0.11630591852564721), (1.00335, 0.25158664272201053), (2.0067, 0.2707487305913156), (3.0100499999999997, 0.19327075057473678), (4.0134, 0.10295042331357719), (5.01675, 0.04364856520231155), (6.020099999999999, 0.015342958201863783), (0.0, 0.9811758192941256), (1.00422, 0.018649427348981), (0.0, 0.9024831978342827), (2.00425, 0.09269455160881204), (0.0, 0.6944298762418107), (0.99703, 0.2536959281304138), (1.99406, 0.045877927988415786)]
然后产生问题,例如2.0067(四舍五入到2.01)和1.99406(四舍五入到1.99(其中总差异是0.01264(远远低于0.05),我想到的一个值是'限制'现在,但应该设置可更改)。将值舍入到1位小数也不是一个选项,因为这将导致窗口为~0.09,其值为2.04999
和1.95001
,两者均产生2.0那种情况。
确切的输出是:
{0.0: 2.694394811895866, 1.0: 0.5239319982014053, 4.01: 0.10295042331357719, 5.02: 0.04364856520231155, 2.0: 0.09269455160881204, 1.99: 0.045877927988415786, 3.01: 0.19327075057473678, 6.02: 0.015342958201863783, 2.01: 0.2707487305913156}
答案 0 :(得分:2)
您可以对浮点值进行舍入,然后使用setdefault:
li=[(0.0, 0.9811758192941256), (1.00422, 0.9998252466431066), (0.0, 0.9024831978342827), (2.00425, 0.9951777494430947)]
data={}
for fv, v in li:
k=round(fv, 5)
data.setdefault(k, 0)
data[k]+=v
print data
# {0.0: 1.8836590171284082, 2.00425: 0.9951777494430947, 1.00422: 0.9998252466431066}
如果你想要一些更复杂的比较(除了固定的舍入),你可以根据你想要的epsilon值创建一个hashable对象,并从那里使用相同的方法。
正如评论中所指出的,这也有效:
data={}
for fv, v in li:
k=round(fv, 5)
data[k]=data.get(k, 0)+v
答案 1 :(得分:2)
accum = list()
data = [(0.0, 0.9811758192941256), (1.00422, 0.9998252466431066), (0.0, 0.9024831978342827), (2.00425, 0.9951777494430947)]
EPSILON = 0.05
newdata = {d: True for d in data}
for k, v in data:
if not newdata[(k,v)]: continue
newdata[(k,v)] = False
# use each piece of data only once
keys,values = [k*v],[v]
for kk, vv in [d for d in data if newdata[d]]:
if abs(k-kk) < EPSILON:
keys.append(kk*vv)
values.append(vv)
newdata[(kk,vv)] = False
accum.append((sum(keys)/sum(values),sum(values)))