Будет ли результат numpy.as_strided зависеть от входного dtype?

Будет ли результат numpy.lib.stride_tricks.as_strided зависеть от dtype массива NumPy?

Этот вопрос возникает из определения .strides, которое

Кортеж байтов для шага в каждом измерении при перемещении массива.

Возьмите следующую функцию, которую я использовал в других вопросах здесь. Он принимает массив 1d или 2d и создает перекрывающиеся окна длиной window. Результат будет на один размер больше входного.

def rwindows(a, window):
    if a.ndim == 1:
        a = a.reshape(-1, 1)
    shape = a.shape[0] - window + 1, window, a.shape[-1]
    strides = (a.strides[0],) + a.strides
    windows = np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)
    return np.squeeze(windows)

# examples
# rwindows(np.arange(5), window=2)
# rwindows(np.arange(20).reshape((5,4)), window=2)

Из-за определения шагов и потому, что, например, в противном случае эквивалентные массивы dtype float32 и float64 будут иметь разные шаги, это когда-нибудь взорвет мою функцию rwindows выше

Я попытался протестировать, но это было не исчерпывающим образом, и я ищу ответ, который (1) объясняет, имеет ли отказ или отказ от функции doc иметь какое-либо отношение к тому, что я прошу здесь, и (2) объясняет, почему или почему не эквивалентные друг другу массивы с разными типами и степенями будут приводить к различным результатам в приведенном выше.

Ответ 1

Нет, предупреждение для as_strided - это две проблемы, которые не связаны с размером данных и больше результата при записи в результирующее представление.

  • Во-первых, нет защиты, чтобы гарантировать, что view = as_strided(a . . . ) указывает только на память в a. Вот почему перед тем, как позвонить as_strided, сделано так много преднамеренной подготовки. Если ваш алгоритм выключен, вы можете легко указать view в памяти, которая не находится в a, и которая действительно может быть адресована мусору, другим переменным или вашей операционной системе. Если вы затем напишете на это представление, ваши данные могут быть потеряны, неуместны, повреждены., или сбой вашего компьютера.

Для вашего конкретного примера, насколько безопасно это зависит от того, какие данные вы используете. Вы установили strides с помощью a.strides, чтобы он был динамическим. Вы можете assert, чтобы dtype of a не был чем-то странным, как object.

Если вы уверены, что у вас всегда будет 2-d a, который больше, чем window, вы, вероятно, будете в порядке с вашим алгоритмом, но вы также можете assert, чтобы убедиться. Если нет, вы можете убедиться, что вывод as_strided работает для массивов n-d a. Например:

shape = a.shape[0] - window + 1, window, a.shape[-1]

Вероятно,

shape = (a.shape[0] - window + 1, window) + a.shape[1:]

чтобы принять вход n-d. Вероятно, это никогда не будет проблемой для ссылки на плохую память, но текущий shape будет ссылаться на неверные данные в a, если у вас больше измерений.

  1. Во-вторых, представление создало несколько ссылок на одни и те же блоки данных. Если вы затем выполните параллельную запись в это представление (через view = foo или bar( . . ., out = view)), результаты могут быть непредсказуемыми и, вероятно, не то, что вы ожидаете.

Тем не менее, если вы боитесь проблем и не нуждаетесь в записи в представлении as_strided (так как вы не используете большинство приложений свертки, где это обычно используется), вы всегда можете установить его как writable = False, что предотвратит обе проблемы, даже если ваши strides и/или shape неверны.

EDIT: Как указано в @hpaulj, в дополнение к этим двум проблемам, если вы что-то делаете с view, который создает копию (например, .flatten() или причудливую индексацию большого фрагмента из этого), это может вызвать MemoryError.