Weighted union-find with path compression in Python 3
unite should check if p and q are in the same set already and do nothing in that case.
Using dictionaries instead of lists as internal data structures would make this more flexible. Now the elements must be from range(N) and N has to be known at the start. Wikipedia suggests a MakeSet function which you could implement like this, and your other functions would continue to work unchanged:

def __init__(self):
    self.id = {}
    self._rank = {}

def make_set(self, element):
    self.id[element] = element
    self._rank[element] = 1

id is a non-obvious name for a data structure stores the parent of each node in a tree. Why not parent?
A single leading underscore is conventionally used to indicate private data. 
It is possible condense these two lines to one and avoid the extra lookup of self.id[x]

self.id[x] = self.id[self.id[x]]
x = self.id[x]


with a chained assignment. However, you risk confusing a reader who is not well familiar with the order of evaluation. The right hand side is evaluated first, and the assignments are carried out starting from self.id[x] on the left, and the value of  x changes after:

self.id[x] = x = self.id[self.id[x]]