2017-08-03 5 views
0

2つの辞書で、2つのリスト内の一意の文字列のインスタンス数を数えます。2つの辞書を結合して値リストを作成するための理解

d1 = {'pig':10, 'cow':40, 'sheep':50} 
d2 = {'pig':40, 'cow':20, 'sheep':10, 'tiger':30} 

d1_total = 100 #sum of the dictionary values 
d2_total = 100 #my actual dictionaries have different sums 

私がD1およびD2の両方に表示されたキーが移入される新しい辞書をしたい:彼らはエントリの数千を持っている以外彼らはこのようになります。私は、各キーの値は、以下でリストVになりたい:

v[0] = d2_value/d1_value #fold change 
v[1] = d1_value/d1_total #fraction of the total count (d1) 
v[2] = d2_value/d2_total #fraction of the total count (d2) 

だから、最終的な結果は次のとおりです。

d_new = {'pig':[4, 0.1, 0.4], 'cow':[0.5, 0.4, 0.2], 'sheep':'[0.2, 0.5, 0.1]} 

私はしかし、巨大なサイズで、作品次のコードを書きました辞書の、それが実行にあまりにも時間がかかり:

def common_keys(d1, d2, d1_total, d2_total): 
    common = {} 
    for x, y in d1.iteritems(): 
     for k, v in d2.iteritems(): 

      d1_frac = y/d1_total 
      d2_frac = v/d2_total 
      fold_change = d2_frac/d1_frac 

      if x == k: 
       common[x] = [fold_change, d1_frac, d2_frac] 
    return commmon 

私は速度を上げるために、辞書内包表記でこれを行う必要があるように私は感じるが、私は両方から値を収集については移動する方法がわかりません辞書など...何かのように:

common = {k:[???, (v/d1_total), (???/d2_total)] for k, v in d1.items() if k in d2.items()} 

これを正しく書いてもらえますか?ご助力ありがとうございます。私は最終的に辞書の包括の周りに私の頭を包んでいるが、辞書を組み合わせて、このようなリストに値を変更すると混乱する。

答えて

3

スピードを上げるために理解する必要はありません。個人的には、リストの作成があまりにも混乱して読みにくくなるので、私はそれを避けたいと思います。必要なのはアルゴリズムです。

def common_keys(d1, d2, d1_total, d2_total): 
    common = {} 
    for x, y in d1.iteritems(): 
     try: 
      v = d2[x] 
     except KeyError: 
      continue 

     d1_frac = y/d1_total 
     d2_frac = v/d2_total 
     fold_change = d2_frac/d1_frac 

     common[x] = [fold_change, d1_frac, d2_frac] 
    return commmon 

は、このように膨大な時間の節約である内部ループを取り除くことをやって:具体的には、キーのルックアップを行うのではなく、共通のアイテムを見つけることがd2を反復処理することによって、この優れた操作を行うことができます。

+0

これは素晴らしいです、ありがとう。私はループ内のループが不要で非効率的であることは知っていましたが、それ以外の方法はわかりませんでした。私はこの構造が理解よりもはるかに読みやすいことに同意します。 – ddrsee

+0

Pythonコードの最適化については、https://drive.google.com/file/d/0Bw5McUt95YdeMlNiX2VSR1lFRHM/viewをご覧ください。ここでは、プロファイリングの後にボトルネック(p。14)は、@ mgilsonとして提案されています - より良いアルゴリズムを見つけようとしています。 – boardrider

3

あなたは、Python 3でキー交差点を取って行うことができます。

d_new = {k: [d2[k]/d1[k], d1[k]/d1_total, d2[k]/d2_total] 
              for k in d1.keys() & d2.keys()} 

set(d1).intersection(d2)またはd1.viewkeys() & d2.viewkeys()とPythonの2の交差点を取ります。

また、あなたが床分裂を避けるためにd2[k]/float(d1[k]), ...を使用することができ

のPython 2にオペレータ/で2つの整数オペランドの床部門に留意します。

+1

python2.7では 'd1.viewkeys()&d2.viewkeys()'を使います。ありがとう、追加されました: – mgilson

+0

@ mgilson –

1

条件付きの辞書の理解度を使用できます。 d1の各キーを反復処理し、それがd2

d1_total = float(sum(d1.values())) 
d2_total = float(sum(d2.values())) 
>>> {k: [d2[k]/float(d1[k]), d1[k]/d1_total, d2[k]/d2_total] 
    for k in d1 if k in d2} 
{'cow': [0.5, 0.4, 0.2], 'pig': [4.0, 0.1, 0.4], 'sheep': [0.2, 0.5, 0.1]} 

タイミング

d1 = {n: 'a' for n in range(100000)} 
d2 = {n: 'b' for n in range(50000, 150000)} 

>>> %timeit [k for k in d1 if k in d2] 
100 loops, best of 3: 10.1 ms per loop 

>>> %timeit [k for k in d1.viewkeys() & d2.viewkeys()] 
100 loops, best of 3: 10.5 ms per loop 

タイミングが類似しているはずであるかどうかを確認します。

関連する問題