Birden çok tuşun aynı listeye bellek etkin bir şekilde işaret ettiği Python sözlüğü


9

Ben bu kod ile açıklanabilir bu benzersiz gereksinimi var. Bu çalışma kodu ama bellek verimli değil.

data = [[
        "A 5408599",
        "B 8126880",
        "A 2003529",
    ],
    [
        "C 9925336",
        "C 3705674",
        "A 823678571",
        "C 3205170186",
    ],
    [
        "C 9772980",
        "B 8960327",
        "C 4185139021",
        "D 1226285245",
        "C 2523866271",
        "D 2940954504",
        "D 5083193",
    ]]

temp_dict = {
    item: index for index, sublist in enumerate(data)
        for item in sublist
}

print(data[temp_dict["A 2003529"]])

out: ['A 5408599', 'B 8126880', 'A 2003529']

Kısacası, her bir alt liste öğesinin dizine eklenebilir olmasını istiyorum ve alt listeyi döndürmelidir.

Yukarıdaki yöntem işe yarıyor ancak veri büyük olduğunda çok fazla bellek gerekiyor. Daha iyi, bellek ve CPU dostu bir yol var mı? Veriler JSON dosyası olarak saklanır.

Düzenle Mümkün olan en büyük kullanım senaryosu (1000 alt liste, her alt listede 100 öğe, 1 milyon sorgu) için yanıtları denedim ve sonuçlar (ortalama 10 çalıştırma):

Method,    Time (seconds),    Extra Memory used
my,        0.637              40 Mb
deceze,    0.63               40 Mb
James,     0.78               200 kb
Pant,      > 300              0 kb
mcsoini,   forever            0 kb

{item: sublist for sublist in data for item in sublist}biraz daha verimli ve doğrudan olabilir… ?!
deceze

Evet. benim örnek durumda. Benim gerçek durum senaryomda, alt listede 100 öğe ve binlerce alt liste var. Kodun kullanıcı küçük bir bellek (<2gb) sahip olduğundan, diğer ağır uygulama çalışırken, komut dosyanızın yavaş olduğundan şikayet ediyorlar.
Rahul

Tam olarak hangi sorunu çözmeye çalışıyorsunuz? Belki de ilk harfe göre dizine eklediğiniz ve daha sonra tam değerinizi bulmak için bir kaç tablo listesi üzerinden yineleme yaptığınız karma bir yaklaşım işe yarayabilir.
deceze

Verimli bir yol için verim () gibi jeneratörler kullanın.
Saisiva A

Teşekkürler. "Karma tablo çarpışma çözümlemesi" nin ne anlama geldiğini öğreneceğim.
Rahul

Yanıtlar:


2

Gerçekten, sözlüğü oluşturmak için gereken zaman / bellek ile anında tüm yöntem için tüm verileri taramak için geçen zaman arasında bir değiş tokuş alanındasınız.

Düşük bellek yöntemi istiyorsanız, her alt listede değeri arayan bir işlev kullanabilirsiniz. Bir jeneratör kullanmak ilk sonuçları kullanıcı için daha hızlı elde edecektir, ancak büyük veri setleri için bu iadeler arasında yavaş olacaktır.

data = [[
        "A 5408599",
        "B 8126880",
        "A 2003529",
    ],
    [
        "C 9925336",
        "C 3705674",
        "A 823678571",
        "C 3205170186",
    ],
    [
        "C 9772980",
        "B 8960327",
        "C 4185139021",
        "D 1226285245",
        "C 2523866271",
        "D 2940954504",
        "D 5083193",
    ]]


def find_list_by_value(v, data):
    for sublist in data:
        if v in sublist:
            yield sublist

for s in find_list_by_value("C 9772980", data):
    print(s)

Yorumlarda belirtildiği gibi, sadece ilk harfe veya ilk 2 veya 3 karaktere dayalı bir karma tablo oluşturmak başlangıç ​​için iyi bir yer olabilir. Bu, alt listelerin bir aday listesini oluşturmanıza, ardından değerin alt listede olup olmadığını görmek için bunları taramanıza olanak tanır.

from collections import defaultdict

def get_key(v, size=3):
    return v[:size]

def get_keys(sublist, size=3):
    return set(get_key(v, size) for v in sublist)

def find_list_by_hash(v, data, hash_table, size=3):
    key = get_key(v, size)
    candidate_indices = hash_table.get(key, set())
    for ix in candidates:
        if v in data[ix]:
            yield data[ix]

# generate the small hash table
quick_hash = defaultdict(set)
for i, sublist in enumerate(data):
    for k in get_keys(sublist, 3):
        quick_hash[k].add(i)

# lookup a value by the small hash
for s in find_list_by_hash("C 9772980", data, quick_hash, 3):
    print(s)

Bu kodda quick_hash, tüm veri yapınızı taradığınız için, derlenmesi biraz zaman alacaktır. Ancak, bellek ayağı baskısı çok daha küçük olacaktır. Ayar performansının ana parametresi size. Daha küçük boyutta bellek alanı daha az olacaktır, ancak find_list_by_hashaday havuzunuz daha büyük olacağı için çalışırken daha uzun sürecektir . Verileriniz için doğru olanın ne olduğunu görmek için bazı testler yapabilirsiniz size. Sadece tüm değerlerinizin en az kadar uzun olduğuna dikkat edin size.


Python ve programlamayı bildiğimi düşündüm. Teşekkürler. Öğrenecek çok şey var.
Rahul

2

Böyle bir şey deneyebilirsiniz:

list(filter(lambda x: any(["C 9772980" in x]),data))

Haritalama yapısına gerek yoktur.


Teşekkür ederim dostum. Bunun daha hızlı olup olmadığını kontrol etmem gerekecek.
Rahul

1
başlangıçta çok daha hızlı olacaktır çünkü hesaplamak için bir anlama yoktur, ancak kullanımda çok daha yavaştır, çünkü her bir elemanın bulması için bu yöntem tüm verileri yeniden tarar.
Edouard Thiel

Elbette, bunun sizin için işe yarayıp yaramadığını bana bildirin.
Bhushan Pant

@EdouardThiel: Ben de aynı şeyi hissediyorum. Asıl kullanımım, başlangıç ​​durumlarından daha fazla kullanım durumuna sahip.
Rahul

@EdouardThiel doğru. Ancak kesin kullanım durumundan emin değilim.
Bhushan Pant

2

pandaları kullanarak bunu dene

import pandas as pd
df=pd.DataFrame(data)
rows = df.shape[0]
for row in range(rows):
    print[[row]]    #Do something with your data

bu basit bir çözüm gibi görünüyor, verileriniz büyürken bile, bu verimli bir şekilde


boyutunuzu kontrol edin df: verilen örnek veriler için listeden data(> x12) ve dikte temp_dict(~ x2) önemli ölçüde daha büyük - tam olarak bellek verimli değil diyebilirim
MrFuppes

@MrFuppes Bu argümanın geçerli olduğunu düşünmüyorum, çünkü pandalar bu durumda dizeleri fiziksel olarak kopyalamıyor
mcsoini

@mcsoini, yorumumun biraz yüzeysel olduğunu itiraf ediyorum - pandasbu sorunun yerleşik python işlevselliğinden daha verimli olup olmadığını belirlemek için daha ayrıntılı bir analiz gerekli olacaktır .
MrFuppes

@ MRFuppes: Kabul ediyorum. Kullanılabilirse neden pandaskullanılır stdlib? Sadece süslü göründüğü için?
Rahul

1
Ancak veri çerçevesini nasıl sorgulayacağımı belirtmediniz. Çözümünüzün sorunumu nasıl çözeceğini bana gösterebilir misiniz? @ Mcsoini'nin pandalar için çözümünü denedim ama 1 milyon sorgu sonsuza kadar sürüyor. Nedenini bilmiyorum. Çeşitli yöntemlerin sonuçları için lütfen güncellenmiş soruma bakın.
Rahul

0

Bunun daha büyük miktarlarda veriler için nasıl davranacağından tam olarak emin değilim, ancak aşağıdaki satırlarda bir şeyler deneyebilirsiniz:

import pandas as pd
df = pd.DataFrame(data).T
df.loc[:, (df == 'A 2003529').any(axis=0)]
Out[39]: 
           0
0  A 5408599
1  B 8126880
2  A 2003529
3       None
4       None
5       None
6       None

Düzenleme: Bazı sahte büyük ölçekli veriler ile hızlı bir test dayalı, zaman açısından yararlı görünmüyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.