Вот чистое решение на основе PyTorch, использующее broadcasting
, torch.unique()
и torch.nonzero()
.Это будет большим подспорьем, особенно для реализации / запуска на основе графического процессора, что невозможно, если нам придется переключиться обратно на NumPy, argsort
it, а затем перенести обратно на PyTorch (как предлагается в других подходах).
# our input tensor
In [50]: A = torch.tensor([0,1,2,3,0,0,1,1,2,2,3,3])
# construct an intermediate boolean tensor
In [51]: boolean = A[:, None] == torch.unique(A)
In [52]: boolean
Out[52]:
tensor([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1],
[1, 0, 0, 0],
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 1, 0],
[0, 0, 0, 1],
[0, 0, 0, 1]], dtype=torch.uint8)
Получив этот булевский тензор, мы можем найти нужные индексы, проверив позиции, где есть 1
после транспонирования булева тензора.
Это даст нам обоим отсортированные input
и indices
.Поскольку нам нужны только индексы, мы можем просто получить их, проиндексировав последний столбец (1
или -1
)
In [53]: torch.nonzero(boolean.t())[:, -1]
Out[53]: tensor([ 0, 4, 5, 1, 6, 7, 2, 8, 9, 3, 10, 11])
Вот результат для еще одного примера, представленного OP вкомментарии:
In [55]: A_large = torch.tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9])
In [56]: boolean_large = A_large[:, None] == torch.unique(A_large)
In [57]: torch.nonzero(boolean_large.t())[:, -1]
Out[57]:
tensor([ 0, 10, 11, 1, 12, 13, 2, 14, 15, 3, 16, 17, 4, 18, 19, 5, 20, 21,
6, 22, 23, 7, 24, 25, 8, 26, 27, 9, 28, 29])
Примечание : В отличие от решения на основе NumPy, предложенного в других ответах, здесь нам не нужно беспокоиться о том, какой kind
алгоритм сортировки мы используемиспользовать, потому что мы вообще не используем сортировку.