TensorFlowを投資につかうまで 衝撃のサンプル編 (4)

#前置き
衝撃のサンプルとはGoogle公式の以下です。
[財務時系列データを使用した機械学習](https://cloud.google.com/solutions/machine-learning-with-financial-time-series-data)

サンプルをもとにTensorFlow1.3でN225の予測を試みます。

#予測するもの

- N225のcloseが前日のcloseより価格が上か下か予測します。
- ダウンロードしたデータを全部つかってみます。
- 日本の市場は開くのがはやいのですべて1~3日前のデータを使用します。

上がるか下がるかの２つのものに分類することを
バイナリ分類(binary classification)またはロジスティック回帰(logistic regression)というそうです。

# 予測する列の追加

予測する列を追加し正解も入力しておきます。対数差分をとっているのでN225が0以上か0以下かで判断できます。
positiveが上がったとき、negativeが下がったときです。

```
    closing["positive"] = 0
    #closing["N225"] >= 0の行のpositiveに1をいれる。
    closing.ix[closing["N225"] >= 0, "positive"] = 1
    closing["negative"] = 0
    #closing["N225"] < 0の行のnegativeに1をいれる。
    closing.ix[closing["N225"] < 0, "negative"] = 1
```

#トレーニングと検証用データの作成
サンプル通りダウンロードしてきたデータの80%を学習に20%をテストに使用します。

```
    #1~3日前のデータを予測に使う
    days_before = range(1,4)

    columns = ["positive", "negative"]
    for i in days_before :
        columns += [index + "_" + str(i) for index in INDEIES]

    training = pd.DataFrame(
        # ['positive', 'negative', 'N225_1', 'HSI_1', 'GDAXI_1', 'DJI_1', 'GSPC_1', 'SSEC_1', 'BVSP_1', 'N225_2', 'HSI_2', 'GDAXI_2', 'DJI_2', 'GSPC_2', 'SSEC_2', 'BVSP_2', 'N225_3', 'HSI_3', 'GDAXI_3', 'DJI_3', 'GSPC_3', 'SSEC_3', 'BVSP_3']
        columns = columns
    )

    #なんで7から？
    for i in range(7, len(closing)):
        data = {}
        #予測の部分は当日のデータで
        data["positive"] = closing["positive"].ix[i]
        data["negative"] = closing["negative"].ix[i]
        #ほかの指標は１個前のデータを使用する。
        for index in INDEIES:
            for before in days_before :
                data[index + "_" + str(before)] = closing[index].ix[i - before]
        training = training.append(data, ignore_index=True)
    #一応確認
    print(training.describe())
```

サンプルはrangeが7からになっているのはなんでなんでしょう。
対数差分の時に最初の行がNANになってるのと3日前までのデータをみるのでrange(4, len(closing))でいいきがするんですけど。ちびっとデータが減るだけだしいっか。

以下の表がコンソールにでるはずです。長いので一部です。

|      |    positive |    negative |      N225_1  |      HSI_1  |    GDAXI_1  \|
|:-----|:------------|:------------|:-------------|:------------|:-------------|
|count | 2441.000000 | 2441.000000 | 2441.000000  |2441.000000  |2441.000000   |
|mean  |    0.521098 |    0.478902 |    0.000077  |   0.000058  |   0.000197   |
|std   |    0.499657 |    0.499657 |    0.016424  |   0.016591  |   0.014922   |
|min   |    0.000000 |    0.000000 |   -0.121110  |  -0.135820  |  -0.074335   |
|25%   |    0.000000 |    0.000000 |   -0.007568  |  -0.006612  |  -0.006390   |
|50%   |    1.000000 |    0.000000 |    0.000574  |   0.000000  |   0.000569   |
|75%   |    1.000000 |    1.000000 |    0.008792  |   0.007450  |   0.007199   |
|max   |    1.000000 |    1.000000 |    0.132346  |   0.134068  |   0.134627   |

あとはテスト用、学習用にわけるだけです。

```
    training_predictors = predictors[:training_size]
    training_classes = classes[:training_size]
    test_predictors = predictors[training_size:]
    test_classes = classes[training_size:]
```

# やっとtensorflow

把握しきれなかったのでとりあえず今回は動かします。
以下の関数を追加python3の記述に変えた以外はほとんどサンプルそのまんまです。

```
def tf_confusion_metrics(model, actual_classes, session, feed_dict):
    predictions = tf.argmax(model, 1)
    actuals = tf.argmax(actual_classes, 1)

    ones_like_actuals = tf.ones_like(actuals)
    zeros_like_actuals = tf.zeros_like(actuals)
    ones_like_predictions = tf.ones_like(predictions)
    zeros_like_predictions = tf.zeros_like(predictions)

    tp_op = tf.reduce_sum(
      tf.cast(
        tf.logical_and(
          tf.equal(actuals, ones_like_actuals),
          tf.equal(predictions, ones_like_predictions)
        ),
        "float"
      )
    )

    tn_op = tf.reduce_sum(
      tf.cast(
        tf.logical_and(
          tf.equal(actuals, zeros_like_actuals),
          tf.equal(predictions, zeros_like_predictions)
        ),
        "float"
      )
    )

    fp_op = tf.reduce_sum(
      tf.cast(
        tf.logical_and(
          tf.equal(actuals, zeros_like_actuals),
          tf.equal(predictions, ones_like_predictions)
        ),
        "float"
      )
    )

    fn_op = tf.reduce_sum(
      tf.cast(
        tf.logical_and(
          tf.equal(actuals, ones_like_actuals),
          tf.equal(predictions, zeros_like_predictions)
        ),
        "float"
      )
    )

    tp, tn, fp, fn = \
      session.run(
        [tp_op, tn_op, fp_op, fn_op],
        feed_dict
      )

    tpr = float(tp)/(float(tp) + float(fn))
    fpr = float(fp)/(float(tp) + float(fn))

    accuracy = (float(tp) + float(tn))/(float(tp) + float(fp) + float(fn) + float(tn))

    recall = tpr
    precision = float(tp)/(float(tp) + float(fp))

    f1_score = (2 * (precision * recall)) / (precision + recall)

    print('Precision = ', precision)
    print('Recall = ', recall)
    print('F1 Score = ', f1_score)
    print('Accuracy = ', accuracy)
```

以下を最後に追加

```
    # 予測する列の数
    num_predictors = len(training_predictors.columns)
    # 予測するべき列の数
    num_classes = len(training_classes.columns)

    session = tf.Session()
    feature = tf.placeholder(tf.float32, shape=(None, num_predictors))
    actual_classes = tf.placeholder(tf.float32,  shape=(None, num_classes))
    weights = tf.Variable(tf.truncated_normal([num_predictors, num_classes], stddev=0.0001))
    biases = tf.Variable(tf.ones([num_classes]))
    model = tf.nn.softmax(tf.matmul(feature, weights) + biases)
    cost = -tf.reduce_sum(actual_classes*tf.log(model))
    training_step = tf.train.AdamOptimizer(learning_rate=0.0001).minimize(cost)
    init = tf.global_variables_initializer()
    session.run(init)
    correct_prediction = tf.equal(tf.argmax(model, 1), tf.argmax(actual_classes, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
    actual_classes_param = training_classes.values.reshape(len(training_classes.values), 2)

    for i in range(1, 30001):
        session.run(
          training_step,
          feed_dict={
            feature: training_predictors.values,
            actual_classes: actual_classes_param
          }
        )
        if i%5000 == 0:
            print( i, session.run(
             accuracy,
             feed_dict={
               feature: training_predictors.values,
               actual_classes: actual_classes_param
             }
           ))
    feed_dict= {
      feature: test_predictors.values,
      actual_classes: test_classes.values.reshape(len(test_classes.values), 2)
    }

    tf_confusion_metrics(model, actual_classes, session, feed_dict)
```

隠れ層なしで30000回学習させています。

```
5000 0.56916
10000 0.61834
15000 0.647541
20000 0.653688
25000 0.65625
30000 0.660861
Precision =  0.6015037593984962
Recall =  0.3389830508474576
F1 Score =  0.4336043360433604
Accuracy =  0.5725971370143149
```
Accuracyがテストデータでの正解率で57%だそうです。まあダメダメですね。
こんどは隠れ層２個いれて学習させます。

```
    session2 = tf.Session()

    feature = tf.placeholder(tf.float32, shape=(None, num_predictors))
    actual_classes = tf.placeholder(tf.float32,  shape=(None, num_classes))

    weights1 = tf.Variable(tf.truncated_normal([num_predictors, 50], stddev=0.0001))
    biases1 = tf.Variable(tf.ones([50]))

    weights2 = tf.Variable(tf.truncated_normal([50, 25], stddev=0.0001))
    biases2 = tf.Variable(tf.ones([25]))

    weights3 = tf.Variable(tf.truncated_normal([25, 2], stddev=0.0001))
    biases3 = tf.Variable(tf.ones([2]))

    hidden_layer_1 = tf.nn.relu(tf.matmul(feature, weights1) + biases1)
    hidden_layer_2 = tf.nn.relu(tf.matmul(hidden_layer_1, weights2) + biases2)
    model = tf.nn.softmax(tf.matmul(hidden_layer_2, weights3) + biases3)

    cost = -tf.reduce_sum(actual_classes*tf.log(model))

    train_op1 = tf.train.AdamOptimizer(learning_rate=0.0001).minimize(cost)

    init = tf.global_variables_initializer()
    session2.run(init)

    correct_prediction = tf.equal(tf.argmax(model, 1), tf.argmax(actual_classes, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

    for i in range(1, 30001):
        session2.run(
            train_op1,
            feed_dict={
              feature: training_predictors.values,
              actual_classes: actual_classes_param
            }
          )
        if i%5000 == 0:
            print( i, session2.run(
              accuracy,
              feed_dict={
                feature: training_predictors.values,
                actual_classes: actual_classes_param
              }
            ))

    tf_confusion_metrics(model, actual_classes, session2, feed_dict)
```

結果

```
5000 0.67418
10000 0.678279
15000 0.679815
20000 0.679303
25000 0.68084
30000 0.68084
Precision =  0.6363636363636364
Recall =  0.5338983050847458
F1 Score =  0.5806451612903226
Accuracy =  0.6278118609406953
```
正解率が62%まであがりました。明らかに精度があがっています。ちょこっとは参考になりそう。
次回より一気に追加した部分をまたちびっとずつ把握して行こうと思います。

この後我慢できなくてヒストリカルデータを3個増やし、30万回学習させたら隠れ層なしで正解率65%,隠れ層ありで正解率66%になりました。
アカン興奮してきた。

前 [TensorFlowを投資につかうまで 衝撃のサンプル編 (3)](http://qiita.com/verizi/items/8ca3018de8a3f15dc2b1)
次 [TensorFlowを投資につかうまで 衝撃のサンプル編 (5)](http://qiita.com/verizi/items/40f77af5e079c9406a99)