0

myDict次の形式で1,000万件のエントリを保持する辞書を作成しました。辞書の各エントリは{(id, age): code}

>>> myDict = {('1039', '68.0864'): '42731,42781,V4501', 
              ('1039', '68.1704'): '4770,4778,V071', 
              ('0845', '60.4476'): '2724,27800,4019', 
              ('0983', '63.3936'): '41401,4168,4240,V1582,V7281'
             }

定数ageOffsetは値=で定義されます0.1

タプルが与えられた場合、キーを持つ(id,age)すべての値を取得するにはどうすればよいですか?myDict(id, X)

age <= X <= age+ageOffset 

このフェッチ操作を200億回実行する必要があります。

Examples: 
1. 
myTup = ('1039', '68.0')
the answer is: '42731,42781,V4501'

2. 
myTup = ('0845', '60.0')
Ans : No value returned 

編集:キーの最初の要素の部分的な一致に基づいて、サブ辞書を作成できますか?つまり、タプルキーの最初の要素が一致した場合は、サブディクショナリを作成します。私のデータによると、これは数百より長くなることはありません。次に、タプルキーの2番目の要素を比較し、対応する値を見つける線形範囲検索を実行します。

4

3 に答える 3

3

この操作を200億(!)回実行するには、データを少し前処理する必要があります。

まず、idでグループ化します。

def preprocess(data):
    from collections import defaultdict # Python 2.5+ only
    preprocessed = defaultdict(list)
    # group by id
    for (id, age), value in data.iteritems():
        preprocessed[id].append((float(age), value))
    # sort lists for binary search, see edit
    for key, value in preprocessed.iteritems():
        value.sort()
    return preprocessed

結果は次のようになります。

>>> preprocess(myDict)
defaultdict(<type 'list'>, {
    '0845': [(60.4476, '2724,27800,4019')],
    '0983': [(63.3936, '41401,4168,4240,V1582,V7281')],
    '1039': [(68.0864, '42731,42781,V4501'), (68.1704, '4770,4778,V071')]} 

同じIDを共有するアイテムが比較的少なく、リストが短くなる場合は、リストのフィルタリングを回避できる可能性があります。

def lookup(data, id, age, age_offset=0.1):
    if id in data:
        return [value for x, value in data[id] if age <= x <= age+age_offset]
    else:
        return None     

lookup(preprocessed, '1039', 68.0) # Note that I use floats for age
['42731,42781,V4501']

ただし、多くのアイテムが同じIDを共有している場合は、長いリストをトラバースする必要があり、ルックアップが比較的遅くなります。この場合、さらに最適化を適用する必要があります。

編集:@AndreyPetrovによって提案されたように

from bisect import bisect_left
from itertools import islice, takewhile
def optimized_lookup(data, id, age, age_offset=0.1):
    if id in data:
        l = data[id]
        idx = bisect_left(l, age)
        return [a for a,v in takewhile(lambda (x, value): x <= age+age_offset, islice(l, idx, None))]
    else:
        return None 
于 2013-02-20T15:40:31.590 に答える
1

これがnumpyでそれを行う方法です、そして私はそれをテストしていませんが、私はそれが辞書をループするよりもはるかに速いだろうとかなり確信しています。辞書の構造をNumpyレコード配列に置き換え、np.whereを使用して、指定したパラメーターと一致する行を見つけました。

import numpy as np

myDict = {('1039', '68.0864'): '42731,42781,V4501', 
              ('1039', '68.1704'): '4770,4778,V071', 
              ('0845', '60.4476'): '2724,27800,4019', 
              ('0983', '63.3936'): '41401,4168,4240,V1582,V7281'
             }

records=[]
for k,v in myDict.iteritems():
    records.append([k[0], float(k[1]), v])

myArr = np.rec.fromrecords(records, formats='S10, f4, S100', 
                             names="ID, Age, Code")

def findInMyArray(arr, requestedID, requestedAge, tolerance=0.1):
    idx = np.where(((arr["Age"] - requestedAge) < tolerance) & (arr["ID"] == requestedID))
    return idx

idx = findInMyArray(myArr, "1039", 68.0, tolerance=0.1)
print "The index found is: ", idx
print "The values are: ", myArr["Code"][idx[0]]
于 2013-02-20T16:03:18.107 に答える
0
def getr(t):
  id = float(t[0])
  age = float(t[1])
  os = 0.1
  rs = []
  correct_id=fixed[id]
  for k in correct_id.keys():
      if (k > age and k <= age + os):
          rs.append(correct_id.get(k))
  return rs

ct = {('1039', '68.0864'): '42731,42781,V4501',
      ('1039', '68.1704'): '4770,4778,V071',
      ('0845', '60.4476'): '2724,27800,4019',
      ('0983', '63.3936'): '41401,4168,4240,V1582,V7281' }

fixed={}

for k in ct:
    if not(float(k[0]) in fixed):
        fixed[float(k[0])]={}
    fixed[float(k[0])][float(k[1])] = ct[k]

print "1"
myTup = ('1039', '68.0')
assert(getr(myTup) == ['42731,42781,V4501'])

#the answer is: '42731,42781,V4501'

print "2"
myTup = ('0845', '60.0')
assert(getr(myTup) == [])
#Ans : No value returned 
于 2013-02-20T15:44:00.680 に答える