পাইথনে গ্রাফ (ডেটা স্ট্রাকচার) উপস্থাপন করা


105

কিভাবে এক সুন্দরভাবে একটি উপস্থাপন করতে পারেন গ্রাফ মধ্যে পাইথন ? (স্ক্র্যাচ থেকে শুরু করে কোনও লাইব্রেরি নেই!)
কোন ডেটা স্ট্রাকচার (যেমন ডিক্টস / টিপলস / ডিক্ট (টিপলস)) দ্রুত হবে তবে মেমোরিও দক্ষ?
একটিকে অবশ্যই বিভিন্ন গ্রাফ অপারেশন করতে সক্ষম হতে হবে।

হিসাবে উল্লেখ করা হয়েছে, বিভিন্ন গ্রাফ উপস্থাপনা সাহায্য করতে পারে। কীভাবে পাইথনে সেগুলি বাস্তবায়ন করা যায়?

লাইব্রেরি হিসাবে, এই প্রশ্নের বেশ ভাল উত্তর আছে।


1
সেখানে লাইব্রেরি অনেক ইতিমধ্যে: graph-tool.skewed.de/performance , code.google.com/p/python-graph , networkx.github.io
Kassym Dorsel

1
উইকিপিডিয়া নিবন্ধটিতে গ্রাফ বর্ণন প্রয়োগের জন্য যা সাধারণ প্রয়োগ এবং মেমরি এবং গতি উভয় ক্ষেত্রে তাদের দক্ষতার তালিকা প্রদর্শন করে: en.wikedia.org/wiki/…
কাসিম ডরসেল

আপনি গিটহব.কম / থিপাস্টর / পেঙ্গাইয়া চেষ্টা করতে পারেন। এটি স্ট্যান্ডার্ড লাইব্রেরির ডিফল্টডিক্ট্ট (যা কোডটি লেখার সময় ছিল না) ব্যবহার করার জন্য এটি পুনরায় লেখার প্রয়োজন। এটি অন্যান্য বাস্তবায়নগুলির তুলনায় এটি আরও মার্জিত করতে একটি পুনরাবিপন্ন ডেটা কাঠামো ব্যবহার করে।
ডক্টর

1
জন্য নির্দেশ গ্রাফ, এই python.org থেকে প্রবন্ধ একটি প্রস্তাব দেওয়া dictএর listগুলি। মূলত ভালো কিছু {<parent>: [<child>, ...], ...}
djvg

আপনি নোড হিসাবে কীগুলি এবং প্রতিটি কীগুলির সংলগ্ন নোডের একটি তালিকা হিসাবে মানগুলির সাথে সংলগ্ন তালিকা হিসাবে অভিধান ব্যবহার করে প্রয়োগ করতে পারেন।
শাহরুখ খান

উত্তর:


140

যদিও এটি কিছুটা পুরানো প্রশ্ন, আমি ভেবেছিলাম যে এই যে কেউ হোঁচট খাচ্ছে তার জন্য আমি একটি ব্যবহারিক উত্তর দেব।

যাক এরকম টিউপসগুলির তালিকা হিসাবে আপনি আপনার সংযোগগুলির জন্য আপনার ইনপুট ডেটা পান:

[('A', 'B'), ('B', 'C'), ('B', 'D'), ('C', 'D'), ('E', 'F'), ('F', 'C')]

ডাটা স্ট্রাকচার আমি সবচেয়ে দরকারী এবং পাইথন মধ্যে গ্রাফ জন্য দক্ষ হওয়ার জন্য পেয়েছি একটি হল সেট অভি । এটি আমাদের Graphশ্রেণীর অন্তর্নিহিত কাঠামো হবে । আপনাকে এইও জানতে হবে যে এই সংযোগগুলি আর্কস (নির্দেশিত, একভাবে সংযোগ করুন) বা প্রান্তগুলি (পুনর্নির্দেশিত, উভয় উপায়ে সংযুক্ত)। আমরা পদ্ধতিতে একটি directedপরামিতি যুক্ত করে এটি পরিচালনা করব Graph.__init__। আমরা আরও কিছু সহায়ক পদ্ধতি যুক্ত করব।

import pprint
from collections import defaultdict


class Graph(object):
    """ Graph data structure, undirected by default. """

    def __init__(self, connections, directed=False):
        self._graph = defaultdict(set)
        self._directed = directed
        self.add_connections(connections)

    def add_connections(self, connections):
        """ Add connections (list of tuple pairs) to graph """

        for node1, node2 in connections:
            self.add(node1, node2)

    def add(self, node1, node2):
        """ Add connection between node1 and node2 """

        self._graph[node1].add(node2)
        if not self._directed:
            self._graph[node2].add(node1)

    def remove(self, node):
        """ Remove all references to node """

        for n, cxns in self._graph.items():  # python3: items(); python2: iteritems()
            try:
                cxns.remove(node)
            except KeyError:
                pass
        try:
            del self._graph[node]
        except KeyError:
            pass

    def is_connected(self, node1, node2):
        """ Is node1 directly connected to node2 """

        return node1 in self._graph and node2 in self._graph[node1]

    def find_path(self, node1, node2, path=[]):
        """ Find any path between node1 and node2 (may not be shortest) """

        path = path + [node1]
        if node1 == node2:
            return path
        if node1 not in self._graph:
            return None
        for node in self._graph[node1]:
            if node not in path:
                new_path = self.find_path(node, node2, path)
                if new_path:
                    return new_path
        return None

    def __str__(self):
        return '{}({})'.format(self.__class__.__name__, dict(self._graph))

আমি এটিকে "পাঠকের অনুশীলন" হিসাবে রেখে দেব find_shortest_pathএবং অন্যান্য পদ্ধতি তৈরি করব ।

চলুন তবে এটি কার্যকরভাবে দেখুন ...

>>> connections = [('A', 'B'), ('B', 'C'), ('B', 'D'),
                   ('C', 'D'), ('E', 'F'), ('F', 'C')]
>>> g = Graph(connections, directed=True)
>>> pretty_print = pprint.PrettyPrinter()
>>> pretty_print.pprint(g._graph)
{'A': {'B'},
 'B': {'D', 'C'},
 'C': {'D'},
 'E': {'F'},
 'F': {'C'}}

>>> g = Graph(connections)  # undirected
>>> pretty_print = pprint.PrettyPrinter()
>>> pretty_print.pprint(g._graph)
{'A': {'B'},
 'B': {'D', 'A', 'C'},
 'C': {'D', 'F', 'B'},
 'D': {'C', 'B'},
 'E': {'F'},
 'F': {'E', 'C'}}

>>> g.add('E', 'D')
>>> pretty_print.pprint(g._graph)
{'A': {'B'},
 'B': {'D', 'A', 'C'},
 'C': {'D', 'F', 'B'},
 'D': {'C', 'E', 'B'},
 'E': {'D', 'F'},
 'F': {'E', 'C'}}

>>> g.remove('A')
>>> pretty_print.pprint(g._graph)
{'B': {'D', 'C'},
 'C': {'D', 'F', 'B'},
 'D': {'C', 'E', 'B'},
 'E': {'D', 'F'},
 'F': {'E', 'C'}}

>>> g.add('G', 'B')
>>> pretty_print.pprint(g._graph)
{'B': {'D', 'G', 'C'},
 'C': {'D', 'F', 'B'},
 'D': {'C', 'E', 'B'},
 'E': {'D', 'F'},
 'F': {'E', 'C'},
 'G': {'B'}}

>>> g.find_path('G', 'E')
['G', 'B', 'D', 'C', 'F', 'E']

6
যদিও এই প্রশ্নটি খুব পুরানো, আমি মনে করি এটি ঠিক সেই সময়ের উত্তর যা আমি প্রত্যাশা করছিলাম। উদাহরণটি সত্যিই ব্যাখ্যা করতে সহায়তা করে যে কীভাবে বাস্তবায়ন করা যায় একই সময়ে এটি বাস্তবকে সরল রেখে। কেউ বিভিন্ন ওপেন সোর্স লাইব্রেরি থেকে বাস্তবায়ন পেতে পারে, তবে ব্যাখ্যাটি সমান হবে না। ধন্যবাদ!
sha0w_wa1k3r

2
প্রান্তগুলিতে ওজন যুক্ত করতে কোন ধরণের পরিবর্তন প্রয়োজন?
pshirishreddy

3
@pshirishreddy আকর্ষণীয় প্রশ্ন! আমি এটি সম্পর্কে ভাবিনি, তবে আমার প্রবৃত্তিটি heapqসেটগুলির পরিবর্তে টিপলগুলির তালিকাটি হিপিফায়েড করার জন্য লিবটি ব্যবহার করবে । উদাহরণস্বরূপ গ্রাফটি হিপসের মতো একটি ডিক হবে: _graph = {'A': heapify([(0.3, 'D'), (0.5, 'B'), (0.75, 'A'), (0.9, 'C')])}(দ্রষ্টব্য: আপনি আসলে এর heapifyমতো ব্যবহার করবেন না , লিবের জন্য সহায়তা পড়ুন), তারপরে আপনি heapqভারসাম্যযুক্ত প্রান্তগুলি সন্নিবেশ করানোর জন্য ফাংশনগুলি ব্যবহার করতে পারেন ।
এমভিসিএইচআর

@ এমভিসিএইচআর এর অর্থ একটি logসময়ের অ্যাক্সেস। তবে আপনি যে অভিধানটি নোডআইডি এবং ওজন উভয়ই মানচিত্রের জন্য ব্যবহার করেছেন তা কীভাবে প্রসারিত করবেন?
ওরেজভানি

সুন্দর! ফাংশনটিকে পুনরাবৃত্তভাবে বলা হয় it এটি নোডগুলি প্রসারিত করতে থাকায় এটি একটি ডিএফএস বলে মনে হচ্ছে। সংক্ষিপ্ততম পথের জন্য আমরা পাথগুলির দৈর্ঘ্য তুলনা করতে পারি এবং শেষে কেবলমাত্র সংক্ষিপ্ততমটিতে ফিরে আসতে পারি।
জওলান্ট ভট্ট

36

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

এবং এটি ওপেন সোর্স যাতে আপনি দেখতে পারেন যে তারা কীভাবে তাদের অ্যালগোরিদম প্রয়োগ করেছে। আপনি অতিরিক্ত অ্যালগরিদম যুক্ত করতে পারেন।

https://github.com/networkx/networkx/tree/master/networkx/algorithms


7
এজন্যই নেটওয়ার্কএক্স একটি দুর্দান্ত উত্স। এটি ওপেন সোর্স যাতে আপনি দেখতে পারেন যে তারা কীভাবে তাদের অ্যালগোরিদম প্রয়োগ করেছে। আপনি অতিরিক্ত অ্যালগরিদম যুক্ত করতে পারেন।
জেটেরেস

2
জন্য কোড 2000 লাইন graph.py --> class Graph। এবং কেবলমাত্র আমি দেখতে চাই তারা কীভাবে ব্যবহার করে __iter__
ডুডি

8

প্রথমত, ক্লাসিকাল তালিকা বনাম ম্যাট্রিক্স উপস্থাপনার পছন্দটি নির্ভর করে (আপনি উপস্থাপনের সাথে কী করতে চান) তার উপর নির্ভর করে। সুপরিচিত সমস্যা এবং অ্যালগরিদমগুলি পছন্দের সাথে সম্পর্কিত। বিমূর্ত প্রতিনিধিত্বমূলক ধরণের পছন্দ এটি কীভাবে প্রয়োগ করা উচিত তা নির্দেশ করে।

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

পাইথন অন্তর্নির্মিত ডেটা টাইপ পয়েন্ট-ভিউ থেকে, অন্য কোথাও থাকা যে কোনও মান লক্ষ্য অবজেক্টের (গোপন) রেফারেন্স হিসাবে প্রকাশ করা হয়। যদি এটি একটি পরিবর্তনশীল (যেমন নামযুক্ত রেফারেন্স) হয় তবে নাম এবং রেফারেন্সটি সর্বদা (অভ্যন্তরীণ) অভিধানে সঞ্চিত থাকে। যদি আপনার নামের প্রয়োজন না হয় তবে রেফারেন্সটি আপনার নিজের পাত্রে সংরক্ষণ করা যেতে পারে - এখানে সম্ভবত পাইথন তালিকা সর্বদা বিমূর্ত হিসাবে তালিকার জন্য ব্যবহৃত হবে ।

পাইথন তালিকাটি রেফারেন্সগুলির গতিশীল অ্যারে হিসাবে প্রয়োগ করা হয়, পাইথন টিপল স্থির বিষয়বস্তু সহ রেফারেন্সের স্ট্যাটিক অ্যারে হিসাবে প্রয়োগ করা হয় (রেফারেন্সের মান পরিবর্তন করা যায় না)। যে কারণে এগুলি সহজেই সূচকযুক্ত করা যায়। এইভাবে, তালিকাটি ম্যাট্রিক্স প্রয়োগের জন্যও ব্যবহার করা যেতে পারে।

ম্যাট্রিক্স উপস্থাপনের আরেকটি উপায় হ'ল স্ট্যান্ডার্ড মডিউল দ্বারা প্রয়োগ করা অ্যারেগুলি array- সঞ্চিত ধরণের, একজাতীয় মানের ক্ষেত্রে আরও সীমাবদ্ধ। উপাদানগুলি সরাসরি মূল্য সঞ্চয় করে। (তালিকার পরিবর্তে মান বস্তুর রেফারেন্স সঞ্চয় করে)। এইভাবে, এটি আরও মেমরির দক্ষ এবং মানটির অ্যাক্সেসও দ্রুত।

কখনও কখনও, আপনি দরকারী এমনকি আরও সীমাবদ্ধ উপস্থাপনা পেতে পারেন bytearray


7

দুটি দুর্দান্ত গ্রাফ লাইব্রেরি নেটওয়ার্কএক্সএক্স এবং ইগ্রাফ রয়েছে । আপনি উভয়ই গিটহাবে লাইব্রেরির উত্স কোডগুলি পেতে পারেন। ফাংশনগুলি কীভাবে লেখা হয় তা আপনি সর্বদা দেখতে পারবেন। তবে আমি নেটওয়ার্কএক্সকে বেশি পছন্দ করি কারণ এটি বুঝতে সহজ।
তারা কীভাবে কার্য সম্পাদন করে তা জানতে তাদের কোডগুলি দেখুন। আপনি একাধিক ধারণা পাবেন এবং তারপরে আপনি কীভাবে ডেটা স্ট্রাকচার ব্যবহার করে গ্রাফ তৈরি করতে চান তা চয়ন করতে পারেন।

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