3

以下は私のリストです:

col = [['red', 'yellow', 'blue', 'red', 'green', 'yellow'],
       ['pink', 'orange', 'brown', 'pink', 'brown']
      ]

私の目標は、各リストに一度だけ表示されるアイテムを排除することです。

これが私のコードです:

eliminate = [[w for w in c if c.count(w)>1]for c in col]

Output: [['red', 'red', 'yellow','yellow'], ['pink','pink', 'brown','brown']]

上記のリストのような小さなデータセットではコードは正常に機能しますが、私のデータセットは非常に大きいです。各リストには最大 1000 個のアイテムが含まれます。

上記のコードをより速く動作させる方法はありますか? コードを 2 つ以上の for ループに分割するようなものです。私の理解では、通常の for ループはリスト内包表記よりも高速です。

助言がありますか?ありがとう。

4

4 に答える 4

9

OrderedCounter繰り返しの.count()呼び出しを避けるために試してみます:

from collections import OrderedDict, Counter

col=[['red', 'yellow', 'blue', 'red', 'green', 'yellow'],['pink', 'orange', 'brown', 'pink', 'brown']]

class OrderedCounter(Counter, OrderedDict):
    pass

new = [[k for k, v in OrderedCounter(el).iteritems() if v != 1] for el in col]
# [['red', 'yellow'], ['pink', 'brown']]

そして、1回だけ繰り返したい場合は、(Martijnのものと同様に-さらにセットでのプレイを減らします):

from itertools import count
def unique_plurals(iterable):
    seen = {}
    return [el for el in iterable if next(seen.setdefault(el, count())) == 1]

new = map(unique_plurals, col)

これは、必要なオカレンスの数を指定するという点でより柔軟であり、dict複数ではなく1 つを保持しsetます。

于 2013-10-09T13:29:26.723 に答える
7

各要素.count()のリストをスキャンするため、使用しないでください。さらに、アイテムが入力に 3 回以上出現する場合、アイテムを複数回出力に追加します。

ここで、以前に見たアイテムのみを生成するジェネレーター関数を使用した方がよいでしょうが、一度だけです。

def unique_plurals(lst):
    seen, seen_twice = set(), set()
    seen_add, seen_twice_add = seen.add, seen_twice.add
    for item in lst:
        if item in seen and item not in seen_twice:
            seen_twice_add(item)
            yield item
            continue
        seen_add(item)

[list(unique_plurals(c)) for c in col]

これは、各リストを1 回だけ繰り返します ( a を使用する場合とは異なりますCounter())。

この方法ははるかに高速です。

>>> timeit('[[k for k, v in OrderedCounter(el).iteritems() if v != 1] for el in col]', 'from __main__ import col, OrderedCounter')
52.00807499885559
>>> timeit('[[k for k, v in Counter(el).iteritems() if v != 1] for el in col]', 'from __main__ import col, Counter')
15.766052007675171
>>> timeit('[list(unique_plurals(c)) for c in col]', 'from __main__ import col, unique_plurals')
6.946599006652832
>>> timeit('[list(unique_plurals_dict(c)) for c in col]', 'from __main__ import col, unique_plurals_dict')
6.557853937149048

これは、メソッドの約 8 倍、OrderedCounterメソッドの 2.2 倍高速Counterです。

ただし、Jon の one-dictionary-plus-counter メソッドはさらに高速です。

ただし、一度だけ表示される値を削除する必要があるだけで、残りは繰り返しを含めてそのままにしておく必要がある場合は、次を使用します (Jon から借用):

from itertools import count
from collections import defaultdict

def nonunique_plurals(lst):
    seen = defaultdict(count)
    for item in lst:
        cnt = next(seen[item])
        if cnt:
            if cnt == 1:
                # yield twice to make up for skipped first item
                yield item
            yield item

これにより、次が生成されます。

>>> [list(nonunique_plurals(c)) for c in col]
[['red', 'red', 'yellow', 'yellow'], ['pink', 'pink', 'brown', 'brown']]
>>> timeit('[non_uniques(c) for c in col]', 'from __main__ import col, non_uniques')
17.75499200820923
>>> timeit('[list(nonunique_plurals(c)) for c in col]', 'from __main__ import col, unique_plurals')
9.306739091873169

これは FMc によって提案されCounter()たソリューションのほぼ 2 倍の速度ですが、順序は正確には保持されません。

>>> list(nonunique_plurals(['a', 'a', 'b', 'a', 'b', 'c']))
['a', 'a', 'a', 'b', 'b']
>>> non_uniques(['a', 'a', 'b', 'a', 'b', 'c'])
['a', 'a', 'b', 'a', 'b']
于 2013-10-09T13:31:49.087 に答える
2

私の理解では、通常の for ループはリスト内包表記よりも高速です。

いいえ。

操作が重複するため、ループが遅くなります。のネストされた各リスト内のすべての文字列に対してcol、その文字列のインスタンス数のカウントが実行されるため、各cincolに対してlen(c)**2比較が実行されます。それがO(NM^2)二乗アルゴリズムです。それはすぐに遅くなります。

これを高速化するには、より優れたデータ構造を使用してください。を使用しcollections.Counterます。

于 2013-10-09T13:29:07.480 に答える
1

これは、修正された質問に対処します。内部リストを 2 回通過するため (最初にカウントし、次に取得する)、可能な限り高速ではありません。ただし、順序が保持され、非常に読みやすくなっています。いつものように、トレードオフはたくさんあります!

from collections import Counter

cols = [
    ['red', 'yellow', 'blue', 'red', 'green', 'yellow'],
    ['pink', 'orange', 'brown', 'pink', 'brown'],
]

def non_uniques(vals):
    counts = Counter(vals)
    return [v for v in vals if counts[v] > 1]

non_uniqs = map(non_uniques, cols)

# [
#    ['red', 'yellow', 'red', 'yellow'],
#    ['pink', 'brown', 'pink', 'brown'],
# ]
于 2013-10-09T14:11:00.237 に答える