numpy не сможет вернуть матрицу со строками разных размеров. в вашем примере ровно 3 различных значения в строке, что делает np.apply_along_axis работоспособным, но если бы у вас было значение 4 в одной из строк или только 1 и 2 в строке, это не получилось бы.
Чтобы получить то, что вы ищите, вам нужно будет использовать обычный список Python в качестве результата. Вы можете построить его, используя понимание списка:
import numpy as np
a = np.array([[1, 2, 2, 2, 1, 1, 1, 2, 1, 2, 1, 2, 2, 2, 1, 1],
[3, 2, 3, 2, 3, 3, 3, 3, 2, 2, 3, 1, 2, 1, 2, 1],
[3, 3, 3, 2, 3, 3, 4, 2, 2, 2, 3, 2, 2, 3, 1, 1]])
r = [ np.unique(row) for row in a ]
print(r)
# [array([1, 2]), array([1, 2, 3]), array([1, 2, 3, 4])]
r = [ np.unique(row,return_index=True)for row in a ]
print(r)
# [(array([1, 2]), array([0, 1])),
# (array([1, 2, 3]), array([11, 1, 0])),
# (array([1, 2, 3, 4]), array([14, 3, 0, 6]))]
Одна вещь, которую вы можете сделать, это создать маску значений, которые являются первыми в своем роде в каждой строке. Это можно сделать, используя numpy.
Вот один из способов сделать это (надеюсь, эксперты numpy могли бы предложить что-то менее запутанное):
np.sum(np.cumsum(np.cumsum(a==np.unique(a)[:,None,None],axis=2),axis=2)==1,axis=0)
array([[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0]])
Такая маска предлагает много обработки такие параметры, как поиск индексов первого вхождения в каждой строке (используя np.argwhere), удаление / назначение первого или последующих вхождений и т. д.