def minimum_spanning_tree(weight_by_edge):
    # Keeps track of the components each node belongs to, initially each is in its own group
    parent = {}
    
    def find(node):
        if parent[node] != node:
            parent[node] = find(parent[node])
        return parent[node]
    
    def union(node1, node2):
        root1 = find(node1)
        root2 = find(node2)
        if root1 != root2:
            parent[root2] = root1
    
    # Initialize each node to be its own parent to form isolated components
    for (u, v) in weight_by_edge:
        parent.setdefault(u, u)
        parent.setdefault(v, v)
    
    # Kruskal's Algorithm main logic
    mst_edges = set()
    for edge in sorted(weight_by_edge, key=weight_by_edge.get):
        u, v = edge
        if find(u) != find(v):
            mst_edges.add(edge)
            union(u, v)
    
    return mst_edges