【问题标题】:Efficiently creating lists in Python due to dynamic variable由于动态变量,在 Python 中有效地创建列表
【发布时间】:2016-10-21 20:36:16
【问题描述】:

我正在使用Keras 来构建LSTM recurrent neural network。我的代码运行良好,但可以进行认真的重构。我正在预测时间序列值,并且根据我想要预测的窗口大小,我最终编写的代码似乎过于特定于该窗口大小,即很难满足许多不同大小的需求。

我将数据集分成训练集和测试集

print "Dataset length: %d" % len(dataset)
train_size = int(len(dataset) * 0.67)
test_size = len(dataset) - train_size
train, test = dataset[0:train_size,:], dataset[train_size:len(dataset),:]
print "Train length: %d, Test length: %d" % (len(train), len(test))

数据集长度:1826 训练长度:1223,测试长度:603

那么对于traintest,我需要创建一个X 作为输入和一个Y 作为输出(我试图预测)

def create_dataset(dataset, look_back=1, predict_steps=1):

    dataX, dataY = [], []

    for i in range(dataset.shape[0] - look_back - predict_steps):
        dataX.append(dataset[i:(i + look_back), 0])
        dataY.append(dataset[i + look_back:i + look_back + predict_steps, 0])

    return np.array(dataX), np.array(dataY)

look_back = 10
predict_steps = 5
input_dim = look_back + 1
trainX, trainY = create_dataset(train, look_back=look_back, predict_steps=predict_steps)
testX, testY = create_dataset(test, look_back=look_back, predict_steps=predict_steps)
print "trainX shape: %s, trainY shape: %s" % (trainX.shape, trainY.shape,)

trainX 形状:(1208, 10),trainY 形状:(1208, 5)

如果我想提前 5 个时间步进行预测,那么存储在变量 trainY 中的预测将采用 [[t+6, t+7, t+8, t+9, t+10], [t+7, t+8, t+9, t+10, t+11]] 的形式,即

prediction 1    [t+6,   t+7,    t+8,    t+9,    t+10]
prediction 2    [t+7,   t+8,    t+9,    t+10,   t+11]
prediction 3    [t+8,   t+9,    t+10,   t+11,   t+12]
prediction 4    [t+9,   t+10,   t+11,   t+12,   t+13]
prediction 5    [t+10,  t+11,   t+12,   t+13,   t+14]

现在,如果我想按逻辑顺序取回这些值,即t+6, t+7, t+8,...,t+14 我正在使用此代码

output = trainY
output_plot = np.array([])
output_plot = np.append(output_plot, output[0][0])
output_plot = np.append(output_plot, np.mean([output[0][1], output[1][0]]))
output_plot = np.append(output_plot, np.mean([output[0][2], output[1][1], output[2][0]]))
output_plot = np.append(output_plot, np.mean([output[0][3], output[1][2], output[2][1], output[3][0]]))

for i in range (len(output) - predict_steps + 1):
    tmp = np.mean([output[i][4], output[i+1][3], output[i+2][2], output[i+3][1], output[i+4][0]])
    output_plot = np.append(output_plot, tmp)

当我想将预测窗口扩展到 10 个时间步时,我的问题就出现了。然后我手动扩展前面的代码如下

output = trainY
output_plot = np.array([])
output_plot = np.append(output_plot, output[0][0])
output_plot = np.append(output_plot, np.mean([output[0][1], output[1][0]]))
output_plot = np.append(output_plot, np.mean([output[0][2], output[1][1], output[2][0]]))
output_plot = np.append(output_plot, np.mean([output[0][3], output[1][2], output[2][1], output[3][0]]))
output_plot = np.append(output_plot, np.mean([output[0][4], output[1][3], output[2][2], output[3][1], output[4][0]]))
output_plot = np.append(output_plot, np.mean([output[0][5], output[1][4], output[2][3], output[3][2], output[4][1], output[5][0]]))
output_plot = np.append(output_plot, np.mean([output[0][6], output[1][5], output[2][4], output[3][3], output[4][2], output[5][1], output[6][0]]))
output_plot = np.append(output_plot, np.mean([output[0][7], output[1][6], output[2][5], output[3][4], output[4][3], output[5][2], output[6][1], output[7][0]]))
output_plot = np.append(output_plot, np.mean([output[0][8], output[1][7], output[2][6], output[3][5], output[4][4], output[5][3], output[6][2], output[7][1], output[8][0]]))


for i in range (len(output) - predict_steps + 1):
    tmp = np.mean([output[i][9], output[i+1][8], output[i+2][7], output[i+3][6], output[i+4][5], output[i+5][4], output[i+6][3], output[i+7][2], output[i+8][1], output[i+9][0]])
    output_plot = np.append(output_plot, tmp)

虽然这可行,但效率极低。如何最好地重构这些步骤以使代码更适合更广泛的预测窗口?另外,我的问题标题可能会有所改进,所以请编辑!

【问题讨论】:

  • 在您的代码示例的第一部分中,您似乎只是在取正方形二维列表的主要对角线上方的每个对角线的平均值。但我不明白你的循环试图做什么。 len(output) 不总是等于predict_steps 吗?如果i 不是0,循环中的第一行不会引发IndexError 吗?
  • 没有输出可以是任何长度,具体取决于数据集,例如它可能来自t+6,...,t+500,但在长度等于predict_steps 的窗口中预测输出。那有意义吗?或者我会用我的意思的例子来更新问题吗?
  • 但是output 仍然是二维列表形式的方形对称矩阵,对吧?你能举个例子,比如predict_steps3len(output)5output 是什么样的,你的循环是什么样的?
  • 我已更新显示我目前正在处理的代码中的示例,其中predict_steps5。希望这有助于澄清事情

标签: python algorithm design-patterns refactoring


【解决方案1】:

(注意:我对你的神经网络问题一无所知,我只是在解决你的编码/数组遍历问题)

可以通过循环来获取矩阵的对角线——您只需将循环的参数调整到适当的尺寸即可。以下代码是纯 Python 中的简化模型,根据我对数据形状的理解,您尝试完成的工作。

from pprint import pprint

def create_mock_data(n):
    return [[100 + i] for i in range(n)]

def create_dataset(dataset, look_back = 1, predict_steps = 1):
    X, Y = [], []

    for i in range(len(dataset) - look_back - predict_steps):
        X.append([row[0] for row in dataset[i : i+look_back]])
        Y.append([row[0] for row in dataset[i+look_back : i+look_back+predict_steps]])

    return X, Y

def antidiagonals(a):
    m, n = len(a), len(a[0])

    for k in range(0, n):
        yield [a[k-i][i] for i in range(k + 1)]

    for k in range(n, m):
        yield [a[k-i][i] for i in range(n)]

def pp(label, x):
    print('---', label, '---')
    pprint(x, width = 108)
    print()

def test(n, look_back, predict_steps):
    print('=' * 72)
    print('n =', n)
    print('look_back =', look_back)
    print('predict_steps =', predict_steps)
    print()

    dataset = create_mock_data(n)
    pp('dataset', dataset)

    X, Y = create_dataset(dataset, look_back, predict_steps)
    pp('X', X)
    pp('Y', Y)

    diagonals = list(antidiagonals(Y))
    pp('diagonals of Y', diagonals)

    print()

test(50, look_back = 10, predict_steps = 5)
test(50, look_back = 10, predict_steps = 10)
# test(50, look_back = 15, predict_steps = 10)

注意:

  • 我使用 Python 列表而不是 numpy 数组,所以如果我误解了您的数组索引,尤其是在 create_dataset 函数中,请纠正我。
  • 为简单起见,我跳过了将原始数据集拆分为训练和测试数据集的部分。

感兴趣的主要代码在antidiagonals 函数中。对于MxN 矩阵的每一行,它产生从该行的第一个元素开始的上升对角线。第一个循环产生第一个N 对角线,它们都有不同的长度。第二个循环产生下一个M-N 对角线,它们都有N 元素。当您运行上面的代码时,您可以检查模拟 Y 数组及其对角线的输出。

假设这些是您希望添加到output_plot 的正确数据系列,您只需修改函数以对 numpy 数组进行操作并取每个对角线的平均值。然后您应该能够调整预测窗口而无需复制太多代码。

让我知道这是否符合您的目标。

【讨论】:

  • 效果很好,谢谢。出于某种原因,当我这样实现它时,我在返回的数字中失去了一点精度,我在antidiagonal 循环中用yield np.mean([a[k-i][i] for i in range(k + 1)], dtype=np.float64) 纠正了这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-28
  • 1970-01-01
  • 2021-08-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-27
相关资源
最近更新 更多