2022年2月6日日曜日

c++でデータマイニングをする。

 おじさん、先週は勾配ブーストの機械学習ライブラリの使い方がわかったので、今週はデータマイニングのやり方を勉強します。


データマイニングって意味がよくわからないし。日本語で言うと統計解析?

統計解析とデータマイニングは違うといってる人もいるし。

データマイニングとは、上の図のように相関行列を求めたりしてデータの中から意味のある情報を取りだすことらしいです。

そしてその手法が統計解析っぽいです。

PythonのPandasなどの統計解析のライブラリを使うと上の図のような相関行列を簡単に作り出せます。

なんかデータマイニングしてる感じが出てかっこいいね。


そもそも統計解析はR言語やPythonを使って行うのが一般的なのですが、R言語とかでやると遅いらしく、海外ではC++で高速に行ったりもしています。

でもC++で統計解析を行っている日本語の記事が一つもない。

どうやってC++で統計解析をやるのか日本語で正しく書かれているサイトがひとつもないのです。

さみしいなぁ。

日本の金融業界とか証券業界ってどうやって統計解析をやっているのでしょうか?

きっと外部に丸投げ?

ということで、今日はC++で統計解析を行って相関係数を求めてみたいと思います。


C++で統計解析を行うには、DataFrameというライブラリを使用します。

https://github.com/hosseinmoein/DataFrame

これ名前がよくなくて、DetaFrameなんていう一般的によく使われる単語の組み合わせなので、なかなか検索で出てきません。

でもこれを使うと簡単に相関係数を求めることができます。


統計解析のライブラリってどれもだいぶ癖が強めです。

というかDetaFrameという概念に癖がありますね。

普通、データをCSVファイルとかで読むときとかは、まず行を読んでそのあと列に分割して処理するのですが、行を中心に行います。

しかし、統計解析って列選択して統計処理を行うので行と列が逆なのです。。

そもそも英語でcolとrowどっちがどっちかわからないし。

年を取ってくると頭が固くなってこういう柔軟な思考に頭が瞬時に追いつかない。

でもDetaFrameの使い方がわかれば、ついでにR言語やPandasの使い方もわかります。


いろいろ書きましたが、C++でDetaFrameのライブラリを使ってボストンの住宅価格の相関行列を求めてみました。



ソースコード

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

#include <stdio.h>

#include <iostream>

#include <stdexcept>


#include <DataFrame_DataFrame.h>


using namespace hmdf;

using MyDataFrame = StdDataFrame<int>;


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[])

{

    MyDataFrame df;

    std::vector<int> index;

    std::vector<float> tmp;

    StatsVisitor<float>    stats_visitor;

std::vector<std::string> col_lbl;

char col_name[256];

struct datapair* dp;

int ret;


dp = readboston("housing.data");

for (int j = 0; j < dp->rows; j++) {

index.push_back(j);

}

df.load_index(std::move(index));


for (int j = 0; j < dp->cols; j++) {

sprintf(col_name, "col_%d", j);

tmp.clear();

for (int i = 0; i < dp->rows; i++) {

tmp.push_back(dp->data[j+i*dp->cols]);

}

col_lbl.push_back(col_name);

df.load_column<float>(col_name, std::move(tmp));

}


sprintf(col_name, "col_%d", 24);

tmp.clear();

for (int j = 0; j < dp->rows; j++) {

tmp.push_back(dp->label[j]);

}

df.load_column<float>(col_name, std::move(tmp));

col_lbl.push_back(col_name);


CorrVisitor<float> corr_visitor;

for (int j = 0; j < dp->cols + 1; j++) {

for (int i = 0; i < dp->cols + 1; i++) {

printf("+-----");

}

printf("+\n");

for (int i = 0; i < dp->cols + 1; i++) {

auto fut10 = df.visit<float, float>(col_lbl[i].c_str(), col_lbl[j].c_str(), corr_visitor);

float res = corr_visitor.get_result();

printf("|%5.2f", res);

}

printf("|\n");

}

for (int i = 0; i < dp->cols + 1; i++) {

printf("+-----");

}

printf("+\n");

return 0;

}


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


結果


これでC++を使ってプログラムで自動でデータマイニングができそう。


0 件のコメント:

コメントを投稿