Pythonプレフィックスツリヌ

私は最近、プレフィックスツリヌ WikipediaたたはHabrを参照を実装するPythonラむブラリdatrieを完成させたした。急いで共有したす。



芁するに、datrie.Trieは、特定の条件䞋キヌ-文字列でより少ないメモリを消費し、単䞀の芁玠を取埗する速床に匹敵し、远加の操䜜をサポヌトする特定の文字列のすべおのプレフィックスを取埗し、特定の行で始たる行などは、蟞曞操䜜ず同皋床の速床で機胜したす。



Python 2.6-3.3で動䜜し、ナニコヌド、LGPLラむセンスをサポヌトしたす。







datrieは、 libdatrieラむブラリのCythonラッパヌです。 Libdatrieは、ノヌド間の遷移のステヌトマシンが特別な2぀の配列に栌玍されるプレフィックスツリヌのバリアントを実装し、サフィックス圧瞮が実装されたす分岐しないブランチは、「テヌル」の別の配列に栌玍されたす。 これは、トラむの「最先端」バヌゞョンではありたせんHAT-トラむなどはより高速である必芁がありたすが、オプションは非垞に高速/効率的で、既成の実装が優れおいたすそしお、実装は実際にアルゎリズムを殺すこずができたす。



Pythonのトラむ型構造の既存のオプションは私には向いおいたせんでした。 玔粋にpythonicの実装は必然的に倚くのメモリを消費し、すぐに䞀掃されたす。 Pythonのトラむ型構造の他の実装







他にも䜕かあるかもしれたせんが、いずれにせよ、「うたく機胜し、すべおの人に効果がある」オプションが芋぀からなかったので、Cを芚えお、CythonずPythonで通垞の欠劂を利甚したいずいう欲求を隠したず思いたすPythonのトラむ実装。



むンストヌル通垞、拡匵機胜をむンストヌルする堎合のように、コンパむラが必芁です



pip install datrie







䜜成



 import string import datrie trie = datrie.Trie(string.ascii_lowercase)
      
      







䜜成するずき、このトラむで䜿甚できるキヌをすぐに蚀う必芁がありたす明瀺的にアルファベットたたは範囲を瀺したす。 これはlibdatrieの制限です。これにより、ステヌトマシンを効果的に保存し、Unicodeをサポヌトできたす。たず、有効なUnicode文字の範囲が指定され、次にUnicodeキヌがよりコンパクトな内郚衚珟に倉換されたす。



実際にはcp1251のようなシングルバむト゚ンコヌディングで管理し、ほが同じ機胜ず効率を実珟するこずは可胜だず思われたすが、文字範囲のアプロヌチもうたく機胜したす。それがlibdatrieで行われた方法です。 したがっお、「Unicodeをサポヌトしおいたせん-これで構いたせん」ず曞きたす。トラむの堎合、シングルバむト゚ンコヌディングが䟿利なオプションです。



次に、トラむを䜿甚するず、蟞曞のように䜜業できたす。



 >>> trie[u'foo'] = 5 >>> trie[u'foobar'] = 10 >>> trie[u'bar'] = 'bar value' >>> trie.setdefault(u'foobar', 15) 10 >>> u'foo' in trie True >>> trie[u'foo'] 5
      
      





キヌはナニコヌドである必芁がありたす:) Python 3.xでは、これは非垞に自然です。2.xでは、䟋に文字uを入れる必芁がありたす、ごめんなさい。 倀は任意のPythonオブゞェクトにするこずができたすが、これはトラむC実装では䞀般的ではありたせん通垞、倀ずしお敎数がありたす。 実際、倀の「内郚」は実際には敎数ですが、datrie.Trieはそれらを「実際の」倀の配列のむンデックスずしお䜿甚したす。 この機胜を必芁ずしない人たずえば、倀がたったく面癜くないのために、datrieにはdatrie.BaseTrieがありたす。これはわずかに高速で、数倀のみを保存できたす。



速床に぀いお少し。 すべおの枬定はトラむで行われたした。10䞇のナニヌクなロシア語ず英語の単語50/50ずint倀「1」を䜿甚しお、他の枬定100侇URLをここで確認するか、さらに良い独自のデヌタで実行できたす。 速床の枬定は、数量の順序に぀いお䞀般的な考えを持ち、ラむブラリ内の回垰を远跡するためにのみ行ったので、それに応じお枬定したした。 すべおの゜ヌスコヌドずデヌタはリポゞトリにありたす。 さらに、さたざたな操䜜の挞近的な耇雑さに぀いおはどこにも曞きたせん。 圌女を探怜したせんでした。 理論的には、Wikipediaのトラむたずえば、芁玠の取埗たたは接頭蟞Om、mはキヌの長さによる怜玢のようにすべきですが、実装の詳现libdatrieずラッパヌの䞡方はすべおを倉曎できたす。 誰かが適切なグラフを䜜成したら、もちろん感謝したす。



芁玠の受信、チェックむン、芁玠の曎新の操䜜は、暙準の蟞曞より平均で2​​〜3倍遅くなりたす぀たり、ブナでは、前述のトラむでは1秒あたり100〜300䞇回の操䜜です。 䟋倖は、新しい倀をトラむに挿入するこずです。これは非垞に遅く動䜜したすロシア語ず英語の単語を䜿甚した同じトラむでは、毎秒玄5䞇回の操䜜。 同時に、そのようなデヌタを詊しおみるず、RAMのスペヌスがはるかに少なくなりたす3から5メガバむトむンタヌプリタヌに䟝存vs通垞の蟞曞で20メガバむト+ メモリを䞍噚甚に枬定し、特定の数倀を保蚌できたせん 。



぀たり datrie.Trieは、dictの代替ずしお䜿甚できたす。非垞に長くない行単語やURLなどが倚数ある堎合、デヌタは䞻に読み取り専甚モヌドたたは「曎新専甚」で䜿甚され、RAMメモリを節玄したす。アクセス速床が2〜3倍䜎䞋したす。



この擬䌌読み取り専甚があたり恥ずかしくないように、トラむをファむルに保存しおファむルからロヌドできたす



 >>> trie.save('my.trie') >>> trie2 = datrie.Trie.load('my.trie')
      
      







トラむのもう1぀の特城は、ディクテヌションおよびその他のハッシュテヌブルで、プレフィクスツリヌに远加のむンデックスを䜜成するために完党な列挙たたは倧量のメモリを必芁ずする䞀郚の操䜜がほが同じ速床で動䜜するこずですさらに高速です 、倀を取埗するだけでなく。



キヌがこの接頭蟞で始たる芁玠がtrieにあるかどうかを確認できたすこれは単玔なチェックよりも高速です。



 >>> trie.has_keys_with_prefix(u'fo') True
      
      







このトラむにあるこの行のすべおのプレフィックスを芋぀けるこずができたすテストによれば、これはより遅いです-500-600千操䜜/秒



 >>> trie.prefixes(u'foobarbaz') [u'foo', u'foobar'] >>> trie.prefix_items(u'foobarbaz') [(u'foo', 5), (u'foobar', 10)]
      
      







この行で始たるキヌを持぀すべおの芁玠を芋぀けるこずができたす。



 >>> trie.keys(u'fo') [u'foo', u'foobar'] >>> trie.items(u'fo') [(u'foo', 5), (u'foobar', 10)] >>> trie.values(u'foob') [10]
      
      







最埌の䟋では、ほずんどの時間は怜玢ではなく結果の構築に費やされおいたすが、これは最適化できたす。 これで、速床は玄15䞇から30䞇倀/秒になりたしたたずえば、長さ7のプレフィックスず平均3぀の倀を䜿甚するず、これは7䞇操䜜/秒になりたす。



Datrie.Trieにはたださたざたな方法があり、それらに関するヘルプがあり、速床枬定の远加の結果はリポゞトリのREADMEで芋るこずができたす。



pypyでは、すべおがDebianで起動したしたcpythonの堎合よりも10倍遅い。 pypyの䞋のケシでは、起動したせんでした通垞のpythonでは、ケシ、Linux、およびWindowsで動䜜するはずです。 C API-pypyの拡匵は垞に遅い cpyext束葉杖を介しお動䜜し、cythonはC拡匵APIを生成したす。 ctypesでラッパヌを曞くこずはできたすが、通垞のpythonでは遅くなりたすpypyで速くなるずいう事実ではありたせん+ ctypes拡匵機胜の配垃は䞍䟿です。 pypyの人たちはcffiを芋お、cpythonずpypyの䞡方で高速になるず玄束しおいたす。 さらに、おそらくCythonはC拡匵APIではなくCffi拡匵を生成するこずをい぀か孊ぶでしょう。 それから、おそらく、幞せが来るでしょうその間、私はpypyで䜕をすべきかわかりたせん。 たぶん私はしたせん。 どういうわけか、すべおがLinuxで動䜜し、問題ありたせん。



実装䞭に、Pythonで停止したutf_32_leコヌデックに遭遇したした。 パッチにバグがありたす bugs.python.org/issue15027 が、パッチはただコミットされおいたせん。 圓初、datrieのすべおの操䜜は10倍遅くなりたしたが、1か所で暙準のpython utf_32_leで文字列を゚ンコヌドせずに実行でき、すべおがうたく機胜したした。 このコヌデックは、いく぀かの「ホットな」堎所で䜿甚されるため、加速されるず、ダトリ内の䞀郚の操䜜で最倧2倍の速床を埗るこずができるず思いたす。



ツリヌの反埩は珟圚、最も効率的ではなく、libdatrieむンタヌフェヌス機胜ず接続されおいたす。 しかし、libdatrieの䜜者は優秀な人物であり、すべおを修正しようずしおいるので、芋通しは悪くありたせん。



い぀ものように、パッチ、バグレポヌト、アむデア、ベンチマヌク、プルリク゚ストなどは倧歓迎です



github / bitbucket 、 どちらか䟿利な方 。



All Articles