4

私はこのようなデータセットを持っています(簡略化):

foods_dict = {}
foods_dict['fruit'] = ['apple', 'orange', 'plum']
foods_dict['veg'] = ['cabbage', 'potato', 'carrot']

そして、分類したいアイテムのリストがあります:

items = ['orange', 'potato', 'cabbage', 'plum', 'farmer', 'egg']

itemsでの出現に基づいて、リストのアイテムをより小さなリストに割り当てることができるようにしたいと考えていfoods_dictます。setsこれらのサブリストは、重複したくないので、実際にはそうあるべきだと思います。

コードでの私の最初のパスは次のようなものでした:

fruits = set()
veggies = set()
others = set()
for item in items:
    if item in foods_dict.get('fruit'):
        fruits.add(item)
    elif item in foods_dict.get('veg'):
        veggies.add(item)
    else:
        others.add(item)

しかし、これは本当に非効率的で、不必要に冗長に思えます。私の質問は、このコードをどのように改善できるでしょうか? ここではリストの理解が役立つと思いますが、リストの数についてはわかりません。

4

4 に答える 4

6

効率的な解決策として、明示的なループをできるだけ避けたいと考えています。

items = set(items)
fruits = set(foods_dict['fruit']) & items
veggies = set(foods_dict['veg']) & items
others = items - fruits - veggies

これは、明示的なループを使用するよりも確実に高速です。特にitem in foods_dict['fruit']、果物のリストが長い場合、実行に時間がかかります。


これまでのソリューション間の非常に単純なベンチマーク:

In [5]: %%timeit
   ...: items2 = set(items)
   ...: fruits = set(foods_dict['fruit']) & items2
   ...: veggies = set(foods_dict['veg']) & items2
   ...: others = items2 - fruits - veggies
   ...: 
1000000 loops, best of 3: 1.75 us per loop

In [6]: %%timeit
   ...: fruits = set()
   ...: veggies = set()
   ...: others = set()
   ...: for item in items:
   ...:     if item in foods_dict.get('fruit'):
   ...:         fruits.add(item)
   ...:     elif item in foods_dict.get('veg'):
   ...:         veggies.add(item)
   ...:     else:
   ...:         others.add(item)
   ...: 
100000 loops, best of 3: 2.57 us per loop

In [7]: %%timeit
   ...: veggies = set(elem for elem in items if elem in foods_dict['veg'])
   ...: fruits = set(elem for elem in items if elem in foods_dict['fruit'])
   ...: others = set(items) - veggies - fruits
   ...: 
100000 loops, best of 3: 3.34 us per loop

確かに、選択する前に、「実際の入力」でいくつかのテストを行う必要があります。問題に含まれる要素の数についてはわかりません。入力が大きくなると、タイミングが大きく変わる可能性があります。とにかく、私の経験から、少なくとも CPython では、明示的なループは組み込み操作のみを使用するよりも遅くなる傾向があることがわかります。


Edit2:より大きな入力の例:

In [9]: foods_dict = {}
   ...: foods_dict['fruit'] = list(range(0, 10000, 2))
   ...: foods_dict['veg'] = list(range(1, 10000, 2))

In [10]: items = list(range(5, 10000, 13))  #some odd some even

In [11]: %%timeit
    ...: fruits = set()
    ...: veggies = set()
    ...: others = set()
    ...: for item in items:
    ...:     if item in foods_dict.get('fruit'):
    ...:         fruits.add(item)
    ...:     elif item in foods_dict.get('veg'):
    ...:         veggies.add(item)
    ...:     else:
    ...:         others.add(item)
    ...: 
10 loops, best of 3: 68.8 ms per loop

In [12]: %%timeit
    ...: veggies = set(elem for elem in items if elem in foods_dict['veg'])
    ...: fruits = set(elem for elem in items if elem in foods_dict['fruit'])
    ...: others = set(items) - veggies - fruits
    ...: 
10 loops, best of 3: 99.9 ms per loop

In [13]: %%timeit
    ...: items2 = set(items)
    ...: fruits = set(foods_dict['fruit']) & items2
    ...: veggies = set(foods_dict['veg']) & items2
    ...: others = items2 - fruits - veggies
    ...: 
1000 loops, best of 3: 445 us per loop

ご覧のとおり、組み込みのみを使用すると、明示的なループよりも約 20 倍速くなります。

于 2013-10-03T18:17:22.517 に答える
1

これはあなたが探していることをするかもしれません(例えば、野菜の場合):

veggies = set(elem for elem in items if elem in foods_dict['veg'])

より完全に:

veggies = set(elem for elem in items if elem in foods_dict['veg'])
fruits = set(elem for elem in items if elem in foods_dict['fruit'])
others = set(items) - veggies - fruits
于 2013-10-03T18:12:27.237 に答える
1

より多くのカテゴリがある場合、これはより一般的なものです。(したがって、カテゴリごとに個別の変数はありません。)

from collections import defaultdict

foods_dict = {}
foods_dict['fruit'] = set(['apple', 'orange', 'plum'])
foods_dict['veg']   = set(['cabbage', 'potato', 'carrot'])

items = set(['orange', 'potato', 'cabbage', 'plum', 'farmer', 'egg'])

dict_items = set.union(*foods_dict.values())

assignments = defaultdict(set)

assignments['other'] = dict_items.copy()
for key in foods_dict.keys():
    assignments[key] = foods_dict[key] & items
    assignments['other'] -= foods_dict[key]
于 2013-10-03T18:37:05.677 に答える