47

ヒストグラムを計算するPythonプログラムを作成する方法はたくさんあります。

ヒストグラムとは、でオブジェクトの出現をカウントiterableし、そのカウントを辞書に出力する関数を意味します。例えば:

>>> L = 'abracadabra'
>>> histogram(L)
{'a': 5, 'b': 2, 'c': 1, 'd': 1, 'r': 2}

この関数を作成する1つの方法は次のとおりです。

def histogram(L):
    d = {}
    for x in L:
        if x in d:
            d[x] += 1
        else:
            d[x] = 1
    return d

この関数を書くためのより簡潔な方法はありますか?

Pythonで辞書の内包表記があれば、次のように書くことができます。

>>> { x: L.count(x) for x in set(L) }

しかし、Python 2.6にはそれらがないため、次のように記述する必要があります。

>>> dict([(x, L.count(x)) for x in set(L)])

このアプローチは読みやすいかもしれませんが、効率的ではありません。Lは複数回ウォークスルーされます。さらに、これはシングルライフジェネレーターでは機能しません。この関数は、次のようなイテレータジェネレータでも同様に機能するはずです。

def gen(L):
    for x in L:
        yield x

reduce関数(RIP)を使おうとするかもしれません:

>>> reduce(lambda d,x: dict(d, x=d.get(x,0)+1), L, {}) # wrong!

おっと、これは機能しません。キー名は'x'、ではなく、xです。:(

私はで終わりました:

>>> reduce(lambda d,x: dict(d.items() + [(x, d.get(x, 0)+1)]), L, {})

(Python 3では、のlist(d.items())代わりに記述する必要がありますd.items()が、そこにないため、これは架空のreduceものです。)

より良い、より読みやすいワンライナーで私を打ち負かしてください!;)

4

9 に答える 9

76

Python 3.xにはがありreduceます、あなたはただする必要がありますfrom functools import reduce。また、「dictの内包表記」もあります。これは、例の構文とまったく同じです。

Python 2.7および3.xには、必要な処理を正確に実行するCounterクラスもあります。

from collections import Counter
cnt = Counter("abracadabra")

Python 2.6以前では、私は個人的にdefaultdictを使用し、2行で実行します。

d = defaultdict(int)
for x in xs: d[x] += 1

これは、クリーンで効率的、Pythonicであり、ほとんどの人にとって、を含むものよりもはるかに理解しやすいものreduceです。

于 2010-05-20T01:33:21.733 に答える
7

ワンライナー用のモジュールをインポートするのはちょっと安っぽいので、これがO(n)で、少なくともPython2.4までさかのぼって機能するワンライナーです。

>>> f=lambda s,d={}:([d.__setitem__(i,d.get(i,0)+1) for i in s],d)[-1]
>>> f("ABRACADABRA")
{'A': 5, 'R': 2, 'B': 2, 'C': 1, 'D': 1}

__そして、メソッドがハッキーだと思うなら、いつでもこれを行うことができます

>>> f=lambda s,d=lambda:0:vars(([setattr(d,i,getattr(d,i,0)+1) for i in s],d)[-1])
>>> f("ABRACADABRA")
{'A': 5, 'R': 2, 'B': 2, 'C': 1, 'D': 1}

:)

于 2010-08-18T04:47:10.337 に答える
6
$d{$_} += 1 for split //, 'abracadabra';
于 2010-11-18T02:33:41.743 に答える
6
import pandas as pd

pd.Series(list(L)).value_counts()
于 2015-02-20T15:18:39.707 に答える
5

Python 2.7の場合、次の小さなリスト内包表記を使用できます。

v = list('abracadabra')
print {x: v.count(x) for x in set(v)}
于 2013-08-15T21:44:45.963 に答える
4

2.3に戻って動作するもの(Timmermanのものよりわずかに短い、私はより読みやすいと思います):

L = 'abracadabra'
hist = {}
for x in L: hist[x] = hist.pop(x,0) + 1
print hist
{'a': 5, 'r': 2, 'b': 2, 'c': 1, 'd': 1}
于 2012-12-13T19:04:09.003 に答える
1

Python 2.2から2.7までで動作するには、ヒストグラムの実装が必要でしたが、次のように思いつきました。

>>> L = 'abracadabra'
>>> hist = {}
>>> for x in L: hist[x] = hist.setdefault(x,0)+1
>>> print hist
{'a': 5, 'r': 2, 'b': 2, 'c': 1, 'd': 1}

私はEliCourtwrightのdefaultdictの投稿に触発されました。これらはPython2.5で導入されたため、使用できません。ただし、dict.setdefault(key、default)を使用してエミュレートできます。

これは基本的にgnibblerが行っていることと同じですが、彼のラムダ関数を完全に理解する前に、最初にこれを作成する必要がありました。

于 2012-02-21T16:24:59.730 に答える
1

しばらくの間、使用するものはすべてitertools定義上Pythonicでした。それでも、これは少し不透明な面です。

>>> from itertools import groupby
>>> grouplen = lambda grp : sum(1 for i in grp)
>>> hist = dict((a[0], grouplen(a[1])) for a in groupby(sorted("ABRACADABRA")))
>>> print hist
{'A': 5, 'R': 2, 'C': 1, 'B': 2, 'D': 1}

私は現在Python2.5.4を実行しています。

于 2010-05-20T02:21:01.370 に答える
1

ワンライナーの使用reduceはほぼ問題ありませんでした。少し調整するだけで済みました。

>>> reduce(lambda d, x: dict(d, **{x: d.get(x, 0) + 1}), L, {})
{'a': 5, 'b': 2, 'c': 1, 'd': 1, 'r': 2}

もちろん、これはインプレースソリューション(速度やpythonicity)に勝るものはありませんが、その代わりに、純粋に機能的なスニペットを手に入れることができます。ところで、Pythonにメソッドがある場合、これはややきれいになりますdict.merge()

于 2010-09-06T14:58:05.657 に答える