If you go back to your original list format data and create a structured array, then determining the unique values is much easier.
a = [['1', 'a'], ['2', 'b'], ['3', 'a'],['1', 'a'],['5', 'c'], ['6', 'b'], ['3', 'a']]
tup = [tuple(i) for i in a] # you need a list of tuples, a kludge for now
dt = [('f1', '<U5'), ('f2', '<U5')] # specify a dtype with two columns
b = np.array(tup, dtype=dt) # create the array with the dtype
np.unique(b) # get the unique values
array([('1', 'a'), ('2', 'b'), ('3', 'a'), ('5', 'c'), ('6', 'b')],
dtype=[('f1', '<U5'), ('f2', '<U5')])
np.unique(b).tolist() # and if you need a list, just change the array
[('1', 'a'), ('2', 'b'), ('3', 'a'), ('5', 'c'), ('6', 'b')]
Reference: Find unique rows in numpy.array
A combination of Joe Kingston and Jaime recommendations deal with views and the above can be simplified to the following. Nicely, this option relies on view, a change of dtype to a structured array and a slice into the original array using the indices of the unique values in the structured view.
>>> dt = a.dtype.descr * a.shape[1]
>>> a_view = a.view(dt)
>>> a_uniq, a_idx = np.unique(a_view, return_index=True)
>>> a[a_idx]
array([['1', 'a'],
['2', 'b'],
['3', 'a'],
['5', 'c'],
['6', 'b']],
dtype='<U1')