একাধিক কী সহ পাইথন অভিধান মেমরি দক্ষতার সাথে একই তালিকার দিকে নির্দেশ করে


9

আমার এই অনন্য প্রয়োজনীয়তা রয়েছে যা এই কোড দ্বারা ব্যাখ্যা করা যেতে পারে। এটি কোড কাজ করছে তবে মেমরির দক্ষ নয়।

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']

সংক্ষেপে, আমি উপ-তালিকার প্রতিটি আইটেমটি সূচীযোগ্য হতে চাই এবং সাবলিস্টটি ফিরিয়ে আনতে চাই।

উপরের পদ্ধতিটি কাজ করে তবে ডেটা বড় হলে অনেক বেশি মেমরি লাগে। এর চেয়ে ভাল, মেমোরি এবং সিপিইউ বান্ধব উপায় আছে কি? ডেটা একটি JSON ফাইল হিসাবে সংরক্ষণ করা হয়।

সম্পাদনা আমি সর্বাধিক সম্ভাব্য ব্যবহারের কেস দৃশ্যের জন্য উত্তরগুলি চেষ্টা করেছি (1000 সাবলিস্ট, প্রতিটি সাবলিস্টে 100 টি আইটেম, 1 মিলিয়ন কোয়েরি) এবং এখানে ফলাফল (10 রানের গড়):

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}কিছুটা দক্ষ এবং সরাসরি হতে পারে… ?!
ছদ্মবেশ

হ্যাঁ. আমার নমুনা কেস জন্য। আমার আসল কেস দৃশ্যে, সাবলিস্টে 100 টি আইটেম রয়েছে এবং এমন হাজার হাজার সাবলিস্ট রয়েছে। কোডটির ব্যবহারকারীর ছোট মেমোরি রয়েছে (<2gb) তাই যখন অন্যান্য ভারী অ্যাপ্লিকেশনটি চলমান থাকে তখন তারা অভিযোগ করে যে আপনার স্ক্রিপ্টটি ধীর গতিতে রয়েছে।
রাহুল

ঠিক কোন সমস্যাটি আপনি সমাধান করার চেষ্টা করছেন? সম্ভবত একটি হাইব্রিড পদ্ধতির কাজ করবে, যার মধ্যে আপনি প্রথম অক্ষর অনুসারে সূচক রেখেছিলেন এবং তারপরে আপনার সঠিক মানটি খুঁজে পেতে কয়েকটি পরীক্ষার্থী তালিকার মাধ্যমে পুনরাবৃত্তি করুন, হ্যাশ টেবিলের সংঘর্ষের রেজোলিউশন অ্যালগরিদমের মতো সাজানো।
ছদ্মবেশ

দক্ষ উপায়ে জেনারেটর যেমন ফলন () ব্যবহার করুন।
সইসিভা এ

ধন্যবাদ। "হ্যাশ টেবিলের সংঘর্ষের রেজোলিউশন" এর অর্থ কী তা আমি শিখব।
রাহুল

উত্তর:


2

অন-ফ্লাই পদ্ধতির জন্য পুরো ডেটা স্ক্যান করতে সময় এবং মেমরির সময় অভিধান তৈরি করতে সময় লাগে তুলনায় আপনি সত্যই একটি বাণিজ্য বন্ধ জায়গায় রয়েছেন।

আপনি যদি কম মেমরি পদ্ধতি চান তবে আপনি এমন একটি ফাংশন ব্যবহার করতে পারেন যা প্রতিটি সাবলিস্টকে মানটির জন্য অনুসন্ধান করে। একটি জেনারেটর ব্যবহার করা প্রাথমিক ব্যবহারকারীর কাছে দ্রুত ফলাফল পাবে, তবে বড় ডেটা সেটগুলির ক্ষেত্রে, এটি রিটার্নের মধ্যে ধীর হবে।

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)

মন্তব্যে উল্লিখিত হিসাবে, ঠিক প্রথম অক্ষর বা প্রথম 2 বা 3 অক্ষরের উপর ভিত্তি করে একটি হ্যাশ টেবিল তৈরি করা শুরু করার জন্য ভাল জায়গা হতে পারে। এটি আপনাকে সাবলিস্টগুলির একটি প্রার্থী তালিকা তৈরি করতে অনুমতি দেবে, তারপরে মান সাব-লিস্টে রয়েছে কিনা তা স্ক্যান করে।

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)

এই কোডটি quick_hashতৈরিতে কিছুটা সময় লাগবে, কারণ আপনি আপনার সম্পূর্ণ ডেটা স্ট্রাকচারটি স্ক্যান করছেন। তবে মেমোরি ফুট মুদ্রণটি আরও ছোট হবে। টিউনিং পারফরম্যান্সের জন্য আপনার প্রধান পরামিতি size। ছোট আকারের একটি ছোট মেমরির পদচিহ্ন থাকবে তবে এটি চলতে সময় লাগবে find_list_by_hashকারণ আপনার প্রার্থীর পুলটি আরও বড় হবে। sizeআপনার ডেটার জন্য সঠিক কী হওয়া উচিত তা দেখতে আপনি কিছু পরীক্ষা করতে পারেন । আপনার মনে রাখা উচিত যে আপনার সমস্ত মান কমপক্ষে দীর্ঘ size


এবং আমি ভেবেছিলাম যে আমি পাইথন এবং প্রোগ্রামিং জানি। ধন্যবাদ। শেখার মতো অনেক কিছুই আছে।
রাহুল

2

আপনি এরকম কিছু চেষ্টা করতে পারেন:

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

কোনও ম্যাপিং কাঠামো তৈরি করার দরকার নেই।


আপনি মানুষ ধন্যবাদ. এটি আরও দ্রুত কিনা তা আমাকে খতিয়ে দেখতে হবে।
রাহুল

1
এটি শুরুতে আরও দ্রুত হবে কারণ গণনা করার কোনও বোধগম্যতা নেই তবে ব্যবহারের ক্ষেত্রে ধীর গতি রয়েছে কারণ প্রতিটি উপাদান অনুসন্ধান করার জন্য, এই পদ্ধতিটি পুরো ডেটাটিকে আবার স্ক্যান করবে।
এডুয়ার্ড থিল

অবশ্যই, আমাকে জানাতে এটি আপনার পক্ষে কাজ করে কিনা।
ভূষণ পান্ত

@ এডওয়ার্ড থিল: আমিও একইরকম অনুভব করছি। আমার আসল ব্যবহারের ক্ষেত্রে প্রারম্ভিক কেসগুলির চেয়ে বেশি ব্যবহারের কেস রয়েছে।
রাহুল

পুনঃটুইট তবে সঠিক ব্যবহারের ক্ষেত্রে আমি নিশ্চিত নই।
ভূষণ পান্ত

2

পান্ডা ব্যবহার করে এটি চেষ্টা করুন

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

এটি সহজ সমাধান দেখায়, এমনকি যদি আপনার ডেটা বড় হয় তবে এটি দক্ষতার সাথে পরিচালনা করবে


আপনার আকারটি যাচাই করুন df: প্রদত্ত উদাহরণের ডেটার জন্য এটি তালিকা data(> x12) এবং ডিক temp_dict(~ x2) এর চেয়ে যথেষ্ট বড় - আমি যা বলতে চাইছি ঠিক সেই স্মৃতিশক্তি নয়
মিঃফুপেস

@ এমআরফুপেস আমি এই যুক্তিটি বৈধ বলে মনে করি না, যেহেতু
পান্ডস

@ এমসিসোইনি, আমি স্বীকার করি যে আমার মন্তব্যটি কিছুটা অতিমাত্রার - এটি একটি বিশদ বিশ্লেষণ বিশ্লেষণের জন্য নির্ধারিত হবে যা pandasএই সমস্যাটি পাইথনের কার্যকারিতা থেকে আরও দক্ষতার সাথে পরিচালনা করে।
মিঃফুপ্পেস

@ মিঃফুপ্পস: আমি সম্মত। কেন এটি ব্যবহার pandasকরে করা যেতে পারে stdlib। দেখতে দেখতে অভিনব?
রাহুল

1
কিন্তু আপনি কীভাবে ডেটাফ্রেমকে জিজ্ঞাসা করবেন তা আপনি সরবরাহ করেননি। আপনার সমাধান কীভাবে আমার সমস্যার সমাধান করবে তা আমাকে দেখাতে পারেন। আমি পান্ডসের জন্য @ এমসোসাইনের সমাধানটি চেষ্টা করেছি তবে এটি 1 মিলিয়ন প্রশ্নের জন্য চিরতরে নিচ্ছে। কেন জানি না। বিভিন্ন পদ্ধতির ফলাফলের জন্য দয়া করে আমার আপডেট হওয়া প্রশ্নটি দেখুন।
রাহুল

0

আমি এটির পরিমাণে পুরোপুরি নিশ্চিত নই যে এটি বৃহত্তর পরিমাণের ডেটার জন্য কী আচরণ করবে তবে আপনি এই লাইনে কিছু চেষ্টা করতে পারেন:

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

সম্পাদনা: কিছু নকল বৃহত্তর স্কেল ডেটা সহ একটি দ্রুত পরীক্ষার ভিত্তিতে সময়ের বিবেচনায় সুবিধাজনক বলে মনে হচ্ছে না।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.