2

この問題を明確に説明できればと思います。私はPythonの実験者です(以下のクエリがナイーブに見える場合に備えて)

次の形式のデータセットがあると仮定します。

a = ( ('309','308','308'), ('309','308','307'), ('308', '309','306', '304'))

('309','308','308')それぞれをパスと呼びましょう。

私はの数を見つけたい:

a。Count('309','308', <any word>)

b。Count('309',<any word>,'308')

そしてすべての可能な順列。

この検索を実現するのに役立つ、ある種の正規表現を考えています。そして、私が持っているパスの数は50000になります。

Pythonでこの種の操作を実行する方法を誰かが提案できますか?私はトライ、基数を調べましたが、それが私を助けるとは思いません。

ありがとう、Sagar

4

3 に答える 3

2

これを行うために使用できますcollections.Counter

>>> from collections import Counter
>>> a = ( ('309','308','308'), ('309','308','307'), ('308', '309','306', '304'))
>>> Counter((x, y) for (x, y, *z) in a)
Counter({('309', '308'): 2, ('308', '309'): 1})
>>> Counter((x, z) for (x, y, z, *w) in a)
Counter({('308', '306'): 1, ('309', '308'): 1, ('309', '307'): 1})

ここでは、Python 3.xより前には存在しなかった拡張タプルアンパックも使用しています。これは、長さが不確かなタプルがある場合にのみ必要です。python 2.xでは、代わりに次のことを行うことができます。

Counter((item[0], item[1]) for item in a)

しかし、これがどれほど効率的かは言えませんでした。悪いことではないと思います。

ACounterには-のdictような構文があります。

>>> count = Counter((x, y) for (x, y, *z) in a)
>>> count['309', '308']
2

編集:長さが1より大きい可能性があるとおっしゃいましたが、この場合、必要な長さより短いと開梱できないため、問題が発生する可能性があります。解決策は、ジェネレータ式を変更して、必要な形式でないものを無視することです。

Counter((item[0], item[1]) for item in a if len(item) >= 2)

例えば:

>>> a = ( ('309',), ('309','308','308'), ('309','308','307'), ('308', '309','306', '304'))
>>> Counter((x, y) for (x, y, *z) in a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.2/collections.py", line 460, in __init__
    self.update(iterable, **kwds)
  File "/usr/lib/python3.2/collections.py", line 540, in update
    _count_elements(self, iterable)
  File "<stdin>", line 1, in <genexpr>
ValueError: need more than 1 value to unpack
>>> Counter((item[0], item[1]) for item in a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.2/collections.py", line 460, in __init__
    self.update(iterable, **kwds)
  File "/usr/lib/python3.2/collections.py", line 540, in update
    _count_elements(self, iterable)
  File "<stdin>", line 1, in <genexpr>
IndexError: tuple index out of range
>>> Counter((item[0], item[1]) for item in a if len(item) >= 2)
Counter({('309', '308'): 2, ('308', '309'): 1})

可変長カウントが必要な場合、最も簡単な方法はリストスライスを使用することです。

start = 0
end = 2
Counter(item[start:end] for item in a if len(item) >= start+end)

もちろん、これは連続実行でのみ機能します。列を個別に選択する場合は、もう少し作業を行う必要があります。

def pick(seq, indices):
    return tuple([seq[i] for i in indices])

columns = [1, 3]
maximum = max(columns)
Counter(pick(item, columns) for item in a if len(item) > maximum)
于 2012-04-20T09:27:03.960 に答える
2

CSスタイルの効率的な方法でこれを実行したい場合は、trysを確認する必要があります。各サブツリーのサイズをルートに保存するには、少し変更する必要がありますが、それほど難しくはありません。

于 2012-04-20T09:50:02.687 に答える
0

Python 2.7より前の場合は、リスト内包表記を使用できます。

#Number of: ('309','308', <any word>)
>>> len([i[0] for i in a if i[0]=='309' and i[1]=='308'])
2
#Number of:('309',<any word>,'308')
>>> len([i[0] for i in a if i[0]=='309' and i[-1]=='308'])
1

リスト内包表記を使用することも、を使用するよりもいくらか高速であるように思われますCounter。タプルのアンパックは優れていますが、処理が少し遅くなります。defaultdict同様のことを少し早く達成できます:

from collections import Counter, defaultdict

a = []
for i in range(500000):
    a.append(('309','308','308'))

def ww(a):
    return Counter((item[0], item[1]) for item in a)

def xx(a):
    return len([i[0] for i in a if i[0]=='309' and i[1]=='308'])

def yy(a):
    g = defaultdict(int)
    for i in a:
        g[(i[0],i[1])] += 1
    return g

def zz(a):
    return Counter((i, j) for (i, j, *k) in a)

from timeit import timeit
print('Counter..:',timeit("ww(a)", "from __main__ import ww, a", number=100))
print('compreh..:',timeit("xx(a)", "from __main__ import xx, a", number=100))
print('defdict..:',timeit("yy(a)", "from __main__ import yy, a", number=100))
print('Count+un.:',timeit("zz(a)", "from __main__ import zz, a", number=100))
#output:
Counter..: 8.411258935928345
compreh..: 2.8653810024261475
defdict..: 4.256785154342651
Count+un.: 18.45333218574524
于 2012-04-20T09:28:11.500 に答える