Используйте общее упорядочение на скалярных элементах тензора.Это эффективно перечисляет ваши элементы, то есть выравнивает их.Тем не менее, вы можете сделать это, сохраняя первоначальную форму.Рассмотрим этот псевдокод (в Python-подобном синтаксисе):
def sample_tensor(tensor, chosen_index: int) -> Tuple[int]:
"""Maps a chosen random number to its index in the given tensor.
Args:
tensor: A ragged-array n-tensor.
chosen_index: An integer in [0, num_scalar_elements_in_tensor).
Returns:
The index that accesses this element in the tensor.
NOTE: Entirely untested, expect it to be fundamentally flawed.
"""
remaining = chosen_index
for (i, sub_list) in enumerate(tensor):
if type(sub_list) is an iterable:
if |sub_list| > remaining:
remaining -= |sub_list|
else:
return i joined with sample_tensor(sub_list, remaining)
else:
if len(sub_list) <= remaining:
return tuple(remaining)
Прежде всего, я знаю, что это не здравый алгоритм.Идея состоит в том, чтобы вести обратный отсчет, пока вы не достигнете своего элемента, с учетом для индексов.
Здесь необходимо сделать важные предположения.1) Все списки в конечном итоге будут содержать только скаляры.2) По прямому следствию, если список содержит списки, предположим, что он также не содержит скаляров на том же уровне.(Остановитесь и убедите себя в (2).)
Здесь мы также должны сделать критическое замечание: мы не можем измерить количество скаляров в любом заданном списке, если список не состоит из однородных скаляров.,Чтобы избежать измерения этой величины в каждой точке, мой алгоритм выше должен быть подвергнут рефакторингу для спуска сначала, а затем вычитания.
Этот алгоритм имеет некоторые последствия:
- Это быстрая во всем своем подходе к проблеме.Если вы хотите написать функцию
f: [0, total_elems) -> Tuple[int]
, вы должны знать количество предшествующих скалярных элементов вдоль полного упорядочения тензора.Это эффективно ограничено значением Theta(l)
, где l
- количество списков в тензоре (поскольку мы можем вызвать len
для списка скаляров). - Это медленно .Это слишком медленно по сравнению с выборочными лучшими тензорами, которые имеют определенную форму.
Возникает вопрос: можем ли мы добиться большего успеха?См. Следующее решение.
Используйте распределение вероятностей в сочетании с numpy.random.choice
.Идея заключается в том, что если мы заранее знаем, каково распределение скаляров, мы можем проводить выборку на каждом уровне нисходящего тензора.Сложная проблема заключается в создании этого дистрибутива.
Я не буду писать для этого псевдокод, но изложу некоторые цели:
- Это можно вызвать только один раз для построения структуры данных..
- Алгоритм должен объединять итеративные и рекурсивные методы для а) построения распределений для списков родных и дочерних объектов и б) построения распределений для потомков соответственно.
- Алгоритму потребуется сопоставить индексы с вероятностьюраспределение, соответствующее спискам братьев и сестер (обратите внимание на предположения, рассмотренные выше).Для этого требуется , зная количество элементов в произвольном подтензоре.
- На нижних уровнях, где списки содержат только скаляры, мы можем упростить, просто сохранив количество элементов в указанном списке (в отличие от хранения вероятностей случайного выбора скаляров из одномерного массива).
- Скорее всего, вам потребуется 2-3 функции: одна, которая использует распределение вероятностей для возврата индекса, функция, которая строит объект распределения, ивозможно, функция, которая просто считает элементы, чтобы помочь построить распределение.
Это также быстрее в O(n)
, где n
- ранг тензора.Я убежден, что это самый быстрый из возможных алгоритмов, но мне не хватает времени, чтобы попытаться это доказать.
Вы можете сохранить распределение как упорядоченный словарь, который отображает вероятность либо в другой словарь, либо в число.элементов в одномерном массиве.Я думаю, что это может быть самой разумной структурой.