从d字典创建累积百分比

2024-05-17 08:22:00 发布

您现在位置:Python中文网/ 问答频道 /正文

给定一个理货数据字典(或计数器),如下所示:

d={'dan':7, 'mike':2, 'john':3}

还有一本新字典“d峎cump”,我想包含累计百分比

^{pr2}$

编辑:应该澄清顺序对我的输入集来说并不重要,这就是为什么我使用字典或计数器。在计算累计百分比时,顺序是很重要的,所以我需要对该操作的数据进行排序,一旦我有了每个名称的累计百分比,那么我就把它放回字典中,因为如果我只查看单个值,顺序应该不重要。在

从d到d的最优雅的方式是什么?在

以下是我看起来有点笨拙的地方:

from numpy import cumsum
d={'dan':7, 'mike':2, 'john':3}
sorted_keys = sorted(d,key=lambda x: d[x])
perc = [x*100/sum(d.values()) for x in cumsum([ d[x] for x in sorted_keys ])]
d_cump=dict(zip(sorted_keys,perc))

>>> d_cump
{'mike': 16, 'john': 41, 'dan': 100}

Tags: 数据infor字典顺序计数器keysjohn
3条回答

既然您使用的是numpy,那么您可以绕过/简化列表理解:

>>> from numpy import cumsum
>>> d={'dan':7, 'mike':2, 'john':3}
>>> sorted_keys = sorted(d,key=d.get)
>>> z = cumsum(sorted(d.values())) # or z = cumsum([d[k] for k in sorted_keys])
>>> d2 = dict(zip(sorted_keys, 100.0*z/z[-1]))
>>> d2
{'mike': 16, 'john': 41, 'dan': 100}

但正如其他地方提到的那样,用这种方式使用字典会让人觉得很奇怪。在

计算累计值?听上去像是折叠!在

d = {'dan':7, 'mike':2, 'john':3}
denominator = float(sum(d.viewvalues()))
data = ((k,(v/denominator)) for (k, v) in sorted(d.viewitems(), key = lambda (k,v):v))


import functional
f = lambda (k,v), l : [(k, v+l[0][1])]+l
functional.foldr(f, [(None,0)], [('a', 1), ('b', 2), ('c', 3)])
#=>[('a', 6), ('b', 5), ('c', 3), (None, 0)]

d_cump = { k:v for (k,v) in functional.foldr(f, [(None,0)], data) if k is not None }

Functional不是一个内置的包。您还可以重新调整f以使用右折,因此如果需要,可以使用标准reduce。在

如您所见,这并不是很短,但是它利用了序列分解来避免拆分/压缩,并且它使用一个生成器作为中间data,从而避免了构建列表。在

如果您想进一步减少对象的创建,您可以使用这个替代函数来修改传入的初始列表(但是必须使用一个愚蠢的技巧来返回适当的值,因为list.append返回{})。在

^{pr2}$

顺便说一下,使用ireduce(来自本页http://www.ibm.com/developerworks/linux/library/l-cpyiter/index.html),左折叠非常容易,因为它消除了列表结构:

ff = lambda (l, ll), (k,v), : (k, v+ll)
g = ireduce(ff, data, (None, 0))

tuple(g)
#=>(('mike', 0.16666666666666666), ('john', 0.41666666666666663), ('dan', 1.0))

def ireduce(func, iterable, init=None):
    if init is None:
        iterable = iter(iterable)
        curr = iterable.next()
    else:
        curr = init
    for x in iterable:
        curr = func(curr, x)
        yield curr

这是有吸引力的,因为初始值不包括在内,而且生成器是懒惰的,因此特别适合于链接。在

请注意,上面的ireduce相当于:

def ireduce(func, iterable, init=None):
    from functional import scanl
    if init is None: init = next(iterable)
    sg = scanl(func, init, iterable)
    next(sg)
    return sg

考虑到原始词典的顺序是任意的,很难判断累计百分比的价值。在

也就是说,我会这样做:

from numpy import cumsum
from operator import itemgetter

d={'dan':7, 'mike':2, 'john':3}

#unzip keys from values in a sorted order
keys, values = zip(*sorted(d.items(), key=itemgetter(1)))
total = sum(values)

# calculate cumsum and zip with keys into new dict
d_cump = dict(zip(keys, (100*subtotal/total for subtotal in cumsum(values))))

请注意,由于字典没有排序,因此结果没有特殊顺序:

^{pr2}$

相关问题 更多 >