Пересмотренное скользящее окно - Добавление скользящего количества окна в качестве параметра - Прогулочный анализ - PullRequest
0 голосов
/ 15 декабря 2018

Я искал в интернете методы, которые могли бы создать скользящие окна , чтобы я мог обобщенным образом выполнить метод перекрестной проверки, известный как Walk Forward Analysis для временных рядов.

Однако я не нашел ни одного решения, которое бы включало гибкость с точки зрения 1) размера окна (это есть почти во всех методах, например, pandas , скользящего или немногоразличное np.roll ) и 2) количество прокручиваемого окна, понимаемое как количество индексов, которые мы хотим перевернуть окно (т.е. не нашли ни одного, которое включает это).

У меня естьпытался оптимизировать и сделать краткий код, с помощью @ coldspeed в этого ответа (я не могу комментировать там, потому что не достиг нужной репутации; надеюсь, чтодоберитесь скоро!), но я не был в состоянии включить количество проката окна.

Мои мысли:

  1. Я пробовал с np.roll вместе с моим примером ниже, но безуспешно.

  2. Я также попытался изменить приведенный ниже код, умножив значение ith, но не смог уместить его в пределах понимания списка, которое я хотел бы сохранить.

3.Приведенный ниже пример отлично подходит для любого размера окна, НО, он только «катит» окно на один шаг вперед, и я хотел бы, чтобы его можно было обобщить на любой шаг.

Итак, ¿Есть ли способ, чтобы эти два параметра были доступны в рамках подхода к пониманию списка?или, ¿есть ли другой ресурс, который я не нашел, который облегчает это? Вся помощь очень ценится.Мой пример кода выглядит следующим образом:

In [1]: import numpy as np
In [2]: arr = np.random.random((10,3))

In [3]: arr

Out[3]: array([[0.38020065, 0.22656515, 0.25926935],
   [0.13446667, 0.04386083, 0.47210474],
   [0.4374763 , 0.20024762, 0.50494097],
   [0.49770835, 0.16381492, 0.6410294 ],
   [0.9711233 , 0.2004874 , 0.71186102],
   [0.61729025, 0.72601898, 0.18970222],
   [0.99308981, 0.80017134, 0.64955358],
   [0.46632326, 0.37341677, 0.49950571],
   [0.45753235, 0.55642914, 0.31972887],
   [0.4371343 , 0.08905587, 0.74511753]])

In [4]: inSamplePercentage = 0.4
In [5]: outSamplePercentage = 0.3 * inSamplePercentage

In [6]: windowSizeTrain = round(inSamplePercentage * arr.shape[0])
In [7]: windowSizeTest = round(outSamplePercentage * arr.shape[0])
In [8]: windowTrPlusTs = windowSizeTrain + windowSizeTest

In [9]: sliceListX = [arr[i: i + windowTrPlusTs] for i in range(len(arr) - (windowTrPlusTs-1))]

Учитывая длину окна 5 и количество окон 2, я мог бы указать что-то вроде этого:

Out [15]: 

[array([[0.38020065, 0.22656515, 0.25926935],
    [0.13446667, 0.04386083, 0.47210474],
    [0.4374763 , 0.20024762, 0.50494097],
    [0.49770835, 0.16381492, 0.6410294 ],
    [0.9711233 , 0.2004874 , 0.71186102]]),
 array([[0.4374763 , 0.20024762, 0.50494097],
    [0.49770835, 0.16381492, 0.6410294 ],
    [0.9711233 , 0.2004874 , 0.71186102],
    [0.61729025, 0.72601898, 0.18970222],
    [0.99308981, 0.80017134, 0.64955358]]),
 array([[0.9711233 , 0.2004874 , 0.71186102],
    [0.61729025, 0.72601898, 0.18970222],
    [0.99308981, 0.80017134, 0.64955358],
    [0.46632326, 0.37341677, 0.49950571],
    [0.45753235, 0.55642914, 0.31972887]]),
 array([[0.99308981, 0.80017134, 0.64955358],
   [0.46632326, 0.37341677, 0.49950571],
   [0.45753235, 0.55642914, 0.31972887],
   [0.4371343 , 0.08905587, 0.74511753]])]

(Это включает в себяпоследний массив, хотя его длина меньше 5).

ИЛИ:

Out [16]: 

[array([[0.38020065, 0.22656515, 0.25926935],
    [0.13446667, 0.04386083, 0.47210474],
    [0.4374763 , 0.20024762, 0.50494097],
    [0.49770835, 0.16381492, 0.6410294 ],
    [0.9711233 , 0.2004874 , 0.71186102]]),
 array([[0.4374763 , 0.20024762, 0.50494097],
    [0.49770835, 0.16381492, 0.6410294 ],
    [0.9711233 , 0.2004874 , 0.71186102],
    [0.61729025, 0.72601898, 0.18970222],
    [0.99308981, 0.80017134, 0.64955358]]),
 array([[0.9711233 , 0.2004874 , 0.71186102],
    [0.61729025, 0.72601898, 0.18970222],
    [0.99308981, 0.80017134, 0.64955358],
    [0.46632326, 0.37341677, 0.49950571],
    [0.45753235, 0.55642914, 0.31972887]])]

(Только массивы с длиной == 5 -> Однако это можно получить из приведенного вышес простой маской).

РЕДАКТИРОВАТЬ: Забыл упомянуть это также - Что-то может быть сделано, если вращающиеся объекты панд поддерживают iter мето.

Ответы [ 2 ]

0 голосов
/ 16 декабря 2018

Итак, давая мои два цента ( с помощью @ Ben.T ), здесь приведен код для создания базового инструмента Walk Forward Analysis, чтобы получить представление о том, как будет работать ваша модель / модели.выступать в более обобщенном порядке.

WFA без привязки

def walkForwardAnal(myArr, windowSize, rollQty):

    from numpy.lib.stride_tricks import as_strided

    ArrRows, ArrCols = myArr.shape

    ArrItems = myArr.itemsize

    sliceQtyAndShape = (int((ArrRows - windowSize) / rollQty + 1), windowSize, ArrCols)
    print('The final view shape is {}'.format(sliceQtyAndShape))

    ArrStrides = (rollQty * ArrCols * ArrItems, ArrCols * ArrItems, ArrItems)
    print('The final strides are {}'.format(ArrStrides))

    sliceList = list(as_strided(myArr, shape=sliceQtyAndShape, strides=ArrStrides, writeable=False))

    return sliceList

wSizeTr = 400
wSizeTe = 100
wSizeTot = wSizeTr + wSizeTe
rQty = 200

sliceListX = wf.walkForwardAnal(X, wSizeTot, rQty)
sliceListY = wf.walkForwardAnal(y, wSizeTot, rQty)

for sliceArrX, sliceArrY in zip(sliceListX, sliceListY):

    ## Consider having to make a .copy() of each array, so that we don't modify the original one. 

    # XArr = sliceArrX.copy() and hence, changing Xtrain, Xtest = XArr[...]
    # YArr = sliceArrY.copy() and hence, changing Ytrain, Ytest = XArr[...]

    Xtrain = sliceArrX[:-wSizeTe,:]
    Xtest = sliceArrX[-wSizeTe:,:]

    Ytrain = sliceArrY[:-wSizeTe,:]
    Ytest = sliceArrY[-wSizeTe:,:]

WFA с привязкой

timeSeriesCrossVal = TimeSeriesSplit(n_splits=5)

    for trainIndex, testIndex in timeSeriesCrossVal.split(X):
        ## Check if the training and testing quantities make sense. If not, increase or decrease the n_splits parameter. 

        Xtrain = X[trainIndex]
        Xtest = X[testIndex]

        Ytrain = y[trainIndex]
        Ytest = y[testIndex]

Затем вы можете просто создать следующее (в любом из двух подходов) и продолжить моделирование:

        # Fit on training set only - The targets (y) are already encoded in dummy variables, so no need to standarize them.
    scaler = StandardScaler()
    scaler.fit(Xtrain)

    # Apply transform to both the training set and the test set.
    trainX = scaler.transform(Xtrain)
    testX = scaler.transform(Xtest)

    ## PCA - Principal Component Analysis #### APPLY PCA TO THE STANDARIZED TRAINING SET! :::: Fit on training set only.
    pca = PCA(.95)
    pca.fit(trainX)

    # Apply transform to both the training set and the test set.
    trainX = pca.transform(trainX)
    testX = pca.transform(testX)

    ## Predict and append predictions...

Один вкладыш для не закрепленного ящика с обобщенным количеством прокатных окон:

sliceListX = [arr[i: i + wSizeTot] for i in range(0, arr.shape[0] - wSizeTot+1, rQty)]
0 голосов
/ 16 декабря 2018

IIUC, что вы хотите, вы можете использовать np.lib.stride_tricks.as_strided, чтобы создать представление о размере окон и количестве проката, таких как:

#redefine arr to see better what is happening than with random numbers
arr = np.arange(30).reshape((10,3))
#get arr properties
arr_0, arr_1 = arr.shape
arr_is = arr.itemsize #the size of element in arr
#parameter window and rolling
win_size = 5
roll_qty = 2
# use as_stribed by defining the right parameters:
from numpy.lib.stride_tricks import as_strided
print (as_strided( arr, 
                   shape=(int((arr_0 - win_size)/roll_qty+1), win_size,arr_1),
                   strides=(roll_qty*arr_1*arr_is, arr_1*arr_is, arr_is)))

array([[[ 0,  1,  2],
        [ 3,  4,  5],
        [ 6,  7,  8],
        [ 9, 10, 11],
        [12, 13, 14]],

       [[ 6,  7,  8],
        [ 9, 10, 11],
        [12, 13, 14],
        [15, 16, 17],
        [18, 19, 20]],

       [[12, 13, 14],
        [15, 16, 17],
        [18, 19, 20],
        [21, 22, 23],
        [24, 25, 26]]])

и для другого размера окна иколичество прокатки:

win_size = 4
roll_qty = 3
print( as_strided( arr, 
                   shape=(int((arr_0 - win_size)/roll_qty+1), win_size,arr_1),
                   strides=(roll_qty*arr_1*arr_is, arr_1*arr_is, arr_is)))

array([[[ 0,  1,  2],
        [ 3,  4,  5],
        [ 6,  7,  8],
        [ 9, 10, 11]],

       [[ 9, 10, 11],
        [12, 13, 14],
        [15, 16, 17],
        [18, 19, 20]],

       [[18, 19, 20],
        [21, 22, 23],
        [24, 25, 26],
        [27, 28, 29]]])
...