2022年2月4日金曜日

lightGBMで回帰分析をする。

 おじさん、毎日システムトレードに向けてプログラムを勉強しています。

株価の予想ってたぶん回帰分析なので、本日はlightGBMで回帰分析をしてみます。


回帰分析と言えば、ボストンの住宅価格予想!

アメリカのボストンの住宅のデータをもとにその価格を予想する定番のやつです。

これを住宅データの代わりに株のデータにすれば、株価の予想ができるはず。



むかし、このブログでもタイタニックの生存者の判定とかマンションの価格推定とかをやりました。

混同行列の図を見ればわかりますが、このふざけた複雑な相関関係。

いかにも普通のプログラムでは難しそう。でも原理は全く同じです。


作ってみてわかったのですが、先日作ったlightGBMのMNISTのソースコードをほんの少し直すだけで、住宅価格の回帰分析ができます。

学習の関数に渡すパラメーターを変えるだけでいろんなタイプの学習ができるんですね。

これはすごい。

たぶん、株価の予想もこれを少し直すだけできっとできるようになるんですね。


ネットでも書かれている通り、回帰分析って作ったプログラムの結果が正しいかどうか結果の数値だけからはなかなかわからない。

解けた感が全くありません。

むしろこれが本当に正しいのかという猜疑心が常にわいてきます。

同じデータを別のプログラムでもう一つ作らないと正しいことがわからないのです。

おじさんもネットに落ちていたPythonのlightGBMのボストンの住宅価格のプログラムの結果と比較して自分のプログラムが正しいことを確かめました。

いろいろ勉強になるね。


ソースコード

---------------------------------

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <string>

#include <vector>

#include "LightGBM/c_api.h"



template<class T> inline std::vector<std::string> split(const std::string& s, const T& separator, bool ignore_empty = 0, bool split_empty = 0) {

struct {

auto len(const std::string& s) { return s.length(); }

auto len(const std::string::value_type* p) { return p ? std::char_traits<std::string::value_type>::length(p) : 0; }

auto len(const std::string::value_type  c) { return c == std::string::value_type() ? 0 : 1; /*return 1;*/ }

} util;


if (s.empty()) { /// empty string ///

if (!split_empty || util.len(separator)) return { "" };

return {};

}


auto v = std::vector<std::string>();

auto n = static_cast<std::string::size_type>(util.len(separator));

if (n == 0) {    /// empty separator ///

if (!split_empty) return { s };

for (auto&& c : s) v.emplace_back(1, c);

return v;

}


auto p = std::string::size_type(0);

while (1) {      /// split with separator ///

auto pos = s.find(separator, p);

if (pos == std::string::npos) {

if (ignore_empty && p - n + 1 == s.size()) break;

v.emplace_back(s.begin() + p, s.end());

break;

}

if (!ignore_empty || p != pos)

v.emplace_back(s.begin() + p, s.begin() + pos);

p = pos + n;

}

return v;

}


struct datapair {

float* data;

float* label;

int rows;

int cols;

};


struct datapair* readboston(const char* fn)

{

FILE* fp;

struct datapair * ret = NULL;

char buf[256];

std::string str;

std::vector<std::string> rows;

std::vector<std::string> cols;

fp = fopen(fn, "rt");

if (fp == NULL)return ret;

while (1) {

buf[0] = 0;

fgets(buf, sizeof(buf), fp);

if (buf[0] == 0)break;

str = buf;

rows.push_back(str);

}

ret = new(struct  datapair);

ret->cols = 13;

ret->rows = rows.size();

ret->data = new float[13*rows.size()];

ret->label = new float[rows.size()];


for(int i=0;i<rows.size();i++){

cols=split(rows[i], " ", 1, 1);

if (cols.size() < 14)continue;

for (int j = 0; j < 13; j++) {

ret->data[13*i+j]=std::stod(cols[j]);

}

ret->label[i]= std::stod(cols[13]);

}

return ret;

}


void freedata(struct datapair*d)

{

if (d == nullptr)return;

delete[] d->data;

delete[] d->label;

delete d;

}


int main(int argc, char* argv[])

{

int ret;


DatasetHandle hx_train, hx_test;

struct datapair* dp;



dp=readboston("housing.data");

int pos = dp->rows * 0.8;

int n = dp->rows - pos;


#if 0

for (int i = 0; i < pos; i++) {

printf("%d ",i);

for (int j = 0; j < 13; j++)printf("%f ",dp->data[i*13+j]);

printf(">>%f\n",dp->label[i]);

}

#endif


ret = LGBM_DatasetCreateFromMat(dp->data, C_API_DTYPE_FLOAT32, pos,

dp->cols, 1, "", nullptr, &hx_train);

if (ret) {

printf("Error: LGBM_DatasetCreateFromMat()\n");

return 1;

}

ret = LGBM_DatasetSetField(hx_train, "label", dp->label, pos, C_API_DTYPE_FLOAT32);

if (ret) {

printf("Error: LGBM_DatasetSetField()\n");

return 1;

}


ret = LGBM_DatasetCreateFromMat(&dp->data[dp->cols*pos], C_API_DTYPE_FLOAT32, n,

dp->cols, 1, "", hx_train, &hx_test);

if (ret) {

printf("Error: LGBM_DatasetCreateFromMat()\n");

return 1;

}

ret = LGBM_DatasetSetField(hx_test, "label", &dp->label[pos], n, C_API_DTYPE_FLOAT32);

if (ret) {

printf("Error: LGBM_DatasetSetField()\n");

return 1;

}


printf("Create Data OK!!\n");


BoosterHandle bh;

ret = LGBM_BoosterCreate(hx_train, "objective=regression "

"metric=rmse", &bh);

if (ret) {

printf("Error: LGBM_BoosterCreate()\n");

return 1;

}


ret = LGBM_BoosterAddValidData(bh, hx_test);

if (ret) {

printf("Error: LGBM_BoosterAddValidData()\n");

return 1;

}


int is_finished = 0;

for (int i = 0; i < 100; i++) {

double d = 0;

ret = LGBM_BoosterUpdateOneIter(bh, &is_finished);

if (ret) {

printf("Error: LGBM_BoosterUpdateOneIter()\n");

return 1;

}

int out_len = 10;

ret = LGBM_BoosterGetEval(bh, 1, &out_len, &d);

if (ret) {

printf("Error: LGBM_BoosterGetEval()\n");

return 1;

}

printf("%d %f\n",i,d);

}


printf("Update OK!!\n");


long long d_len = 1;

double d;


ret = LGBM_BoosterPredictForMat(bh, &dp->data[dp->cols * pos], C_API_DTYPE_FLOAT32, 1, 13,

1, C_API_PREDICT_NORMAL, 0, -1, "", &d_len, &d);

if (ret) {

printf("Error: LGBM_BoosterPredictForMat()\n");

return 1;

}

printf("input\n");

for (int i = 0; i < 13; i++) {

printf("%d  %f\n",i, dp->data[dp->cols * pos+i]);

}

printf("predict\n");

printf("d=%f\n", d);


LGBM_BoosterFree(bh);

LGBM_DatasetFree(hx_train);

LGBM_DatasetFree(hx_test);


freedata(dp);


return 0;

}

---------------------------------



結果

---------------------------------

Create Data OK!!
[LightGBM] [Warning] Auto-choosing row-wise multi-threading, the overhead of testing was 0.000566 seconds.
You can set `force_row_wise=true` to remove the overhead.
And if memory is not enough, you can set `force_col_wise=true`.
[LightGBM] [Info] Total Bins 1028
[LightGBM] [Info] Number of data points in the train set: 404, number of used features: 13
[LightGBM] [Info] Start training from score 24.175743
[LightGBM] [Warning] No further splits with positive gain, best gain: -inf
0 8.902198
[LightGBM] [Warning] No further splits with positive gain, best gain: -inf
1 8.128168
...
[LightGBM] [Warning] No further splits with positive gain, best gain: -inf
99 5.225559
Update OK!!
input
0  41.529202
1  0.000000
2  18.100000
3  0.000000
4  0.693000
5  5.531000
6  85.400002
7  1.607400
8  24.000000
9  666.000000
10  20.200001
11  329.459991
12  27.379999
predict
d=9.342857

---------------------------------



0 件のコメント:

コメントを投稿