np.roll без переворачивания края - PullRequest
2 голосов
/ 10 января 2020

У меня есть 1D-массив, который я хочу преобразовать в 2D-массив, где в строке i исходный 1D катится по шагам i . Я реализовал это следующим образом:

import numpy as np
data=np.arange(0,10,2)
rolling=np.arange(len(data))

array=np.array([np.roll(data,-i) for i in rolling])

array
array([[0, 2, 4, 6, 8],
       [2, 4, 6, 8, 0],
       [4, 6, 8, 0, 2],
       [6, 8, 0, 2, 4],
       [8, 0, 2, 4, 6]])

. Для более поздних целей я бы хотел, чтобы скатывание происходило таким образом, чтобы массив не переворачивался через край, а соответствующие значения заменялись чем-то другим, например np.nan.

Мой предполагаемый вывод -

array([[0, 2, 4, 6, 8],
       [2, 4, 6, 8, np.nan],
       [4, 6, 8, np.nan, np.nan],
       [6, 8, np.nan, np.nan, np.nan],
       [8, np.nan, np.nan, np.nan, np.nan]])

Данные не обязательно являются такими же однородными, как в этом примере, поэтому обнаружение края невозможно, как это было бы в пример. Я пробовал использовать отступы, но они не являются ни короткими, ни удобными, поскольку в каждом ряду требуется разный отступ. Кроме того, я думал о np.tril или np.triu, но они работали только для главной диагонали, но уклон не по главной диагонали. В этом примере он находится на противоположной диагонали, но в реальном примере это может измениться, что будет выглядеть так:

array=np.array([np.roll(data,-i+manualshift) for i in rolling])

РЕДАКТИРОВАТЬ: Дополнительный пример

Если я введу матрицу большего размера и добавлю дополнительный сдвиг, как этот

data=np.arange(0,20,2)
rolling=np.arange(len(data))
manualshift=3
array=np.array([np.roll(data,-i+manualshift) for i in rolling])

, тогда массив будет выглядеть так:

array([[nan, nan, nan,  0,  2,  4,  6,  8, 10, 12],
       [nan, nan,  0,  2,  4,  6,  8, 10, 12, 14],
       [nan,  0,  2,  4,  6,  8, 10, 12, 14, 16],
       [ 0,  2,  4,  6,  8, 10, 12, 14, 16, 18],
       [ 2,  4,  6,  8, 10, 12, 14, 16, 18,  nan],
       [ 4,  6,  8, 10, 12, 14, 16, 18,  nan,  nan],
       [ 6,  8, 10, 12, 14, 16, 18,  nan,  nan,  nan],
       [ 8, 10, 12, 14, 16, 18,  nan,  nan,  nan,  nan],
       [10, 12, 14, 16, 18,  nan,  nan,  nan,  nan,  nan],
       [12, 14, 16, 18,  nan,  nan,  nan,  nan,  nan, nan]])

EDIT END


Есть краткое решение для этого?

1 Ответ

3 голосов
/ 10 января 2020

Подход № 1

Для этого есть встроенная функция hankel-matrix, которая может удовлетворить ваши "короткие" требования к решению -

In [43]: from scipy.linalg import hankel

In [59]: hankel(data,np.full(len(data),np.nan))
Out[59]: 
array([[ 0.,  2.,  4.,  6.,  8.],
       [ 2.,  4.,  6.,  8., nan],
       [ 4.,  6.,  8., nan, nan],
       [ 6.,  8., nan, nan, nan],
       [ 8., nan, nan, nan, nan]])

Подход № 2

Другой, основанный на NumPy -стридах -

In [49]: from skimage.util import view_as_windows

In [50]: b = np.r_[data,np.full(len(data)-1,np.nan)]

In [51]: view_as_windows(b,len(data))
Out[51]: 
array([[ 0.,  2.,  4.,  6.,  8.],
       [ 2.,  4.,  6.,  8., nan],
       [ 4.,  6.,  8., nan, nan],
       [ 6.,  8., nan, nan, nan],
       [ 8., nan, nan, nan, nan]])

Более подробная информация об использовании as_strided на основе view_as_windows.

NumPy native way for getting sliding windows.

Подход № 3

Еще один короткий способ повторного использования b с предыдущего шага -

In [56]: b[np.add.outer(*[np.arange(len(data))]*2)]
Out[56]: 
array([[ 0.,  2.,  4.,  6.,  8.],
       [ 2.,  4.,  6.,  8., nan],
       [ 4.,  6.,  8., nan, nan],
       [ 6.,  8., nan, nan, nan],
       [ 8., nan, nan, nan, nan]])

Подход № 4

Pandas путь -

In [65]: import pandas as pd

In [66]: pd.DataFrame([data[i:] for i in range(len(data))]).values
Out[66]: 
array([[ 0.,  2.,  4.,  6.,  8.],
       [ 2.,  4.,  6.,  8., nan],
       [ 4.,  6.,  8., nan, nan],
       [ 6.,  8., nan, nan, nan],
       [ 8., nan, nan, nan, nan]])

Подход № 5

С помощью itertools -

In [93]: from itertools import zip_longest

In [94]: d = [data[i:] for i in range(len(data))]

In [95]: np.array(list(zip_longest(*d, fillvalue=np.nan)))
Out[95]: 
array([[ 0.,  2.,  4.,  6.,  8.],
       [ 2.,  4.,  6.,  8., nan],
       [ 4.,  6.,  8., nan, nan],
       [ 6.,  8., nan, nan, nan],
       [ 8., nan, nan, nan, nan]])

Включение manualshift

Чтобы включить manualshift для пользовательского заполнения на передней стороне, мы может расширяться Подход № 2, # 3 . Таким образом, b необходимо изменить, выполнив что-то вроде следующего, оставив при этом то же самое -

b = np.r_[np.full(manualshift,np.nan),data,np.full(len(data)-manualshift-1,np.nan)]

Для более короткой альтернативы, пожалуйста, посмотрите на np.pad для заполнения с NaNs.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...