ML.NETドキュメントリーディング#3

#1 概要
機械学習をするときにデータを加工したい場合、SQLを使うことがあると思うのでPostgreSQLのデータベース上にあるデータをML.NETから取り込んで学習できるか試してみました。
前回の続きになります。

[ML.NETドキュメントリーディング#2](https://qiita.com/sunnyyone/items/0e527626910862351009)

【動作環境】

+ Windows 10 Home(1903)
+ VisualStudio2019 v16.5.2
+ .NetCore v2.2, v3.1
+ ML.NET Model Builder(Preview) v16.0.2003.302
+ Npgsql v4.1.3.1
+ PostgreSQL v12.2.2(x64)

【事前準備】

+ [ML.NETチュートリアル](https://docs.microsoft.com/ja-jp/dotnet/machine-learning/tutorials/predict-prices-with-model-builder)を実施してソリューションを作成しておく。
+ [PostgreSQLダウンロード](https://www.postgresql.org/)からダウンロードしインストールしておく。

#2 フォルダ構成
チュートリアルに従い、ソリューションを作成した後のフォルダ構成は以下になっています。
まずは、ダウンロードしたCSVをデータベースに取り込みます。

[動作環境]
TaxiFarePrediction
　├TaxiFarePrediction
　│　└Data
　│　　└taxi-fare-train.csv　　　・・・ ダウンロードしたデータ
　├TaxiFarePredictionML.ConsoleApp
　├TaxiFarePredictionML.Model
　└TaxiFarePrediction.sln

#3 データベース作成
pgAdmin4を使いデータベースを作成しますので、pgAdmin4を起動します。

【データベース名】TaxiFare

1. サイドバーのデータベースを右クリックし、「作成」>「データベース...」からデータベースを作成する
![手順1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263183/3cf4ba90-fb57-ebda-9d7f-7cec042bef48.png)


2. データベースに「TaxiFare」を入力し、保存ボタンを押す。
![手順2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263183/34d5efa4-12c9-2258-2d70-e35454d5f64a.png)

3. クエリエディタを開き、SQL文を張り付ける。
![手順3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263183/fdde4682-6d30-5161-82b6-56cd66e7fb03.png)



```sql:taxi-fare-train.csv取り込み
drop table if exists taxi_fare_train;
create table taxi_fare_train
(
	vendor_id			text,
	rate_code			integer,
	passenger_count		integer,
	trip_time_in_secs	integer,
	trip_distance		real,
	payment_type		text,
	fare_amount			real
);

copy taxi_fare_train 
from 'C:\[任意のローカル環境]\TaxiFarePrediction\TaxiFarePrediction\Data\taxi-fare-train.csv' 
CSV HEADER;
```
※[任意のローカル環境]は作成したソリューションまでのパスにする。
　PostgreSQLのバージョンによりパスが日本語の場合はエラーとなる場合があるため英語にする
4. SQLを実行する
![手順4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263183/879c80b9-a14d-6fad-6599-702cbb728bb0.png)

これで、「taxi-fare-train.csv」を「taxi_fare_train」テーブルに取り込めました。
セレクト文を実行すると取り込んだデータが確認できます。

```sql
select * from taxi_fare_train;
```


#4 Npgsqlインストール
.NetからPostgreSQLにアクセスするライブラリをnugetからダウンロードしてきます。
VisualStudioツールバーの「ツール」>「NuGetパッケージマネージャ(N)」>「ソリューションのNuGetパッケージの管理(N)...」を開き、検索バーから「npgsql」を入力し検索するとでてきます。
「TaxiFarePredictionML.ConsoleApp」プロジェクトにチェックを入れ、Npgsqlをインストールします。
![手順5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263183/aed2f1bc-781e-1007-7c39-843238c6c7cc.png)
![手順6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263183/0c34da07-7801-df55-d465-9cb847efba93.png)



#5 PostgreSQLテーブル読み込み方法
モデルビルダーで生成した「TaxiFarePredictionML.ConsoleApp」プロジェクトの以下のソースコードを修正します。

+ ModelBuilder.cs
+ Program.cs


[動作環境]
TaxiFarePrediction
　├TaxiFarePrediction
　│　└Data
　│　　└taxi-fare-train.csv　　　・・・ ダウンロードしたデータ
　├TaxiFarePredictionML.ConsoleApp
　│　├ModelBuilder.cs　　　　　　・・・ ファイル読み込み処理をDBアクセス処理に変更
　│　└Program.cs　　　　　　　　　・・・ CreateModel関数コールを追加
　├TaxiFarePredictionML.Model
　└TaxiFarePrediction.sln

① インクルードにNpgsqlを追加します。
② 生成されたコードのファイル読み込み処理をデータベースアクセスに変更します。
　このとき、DB接続情報はPostgreSQLをインストールしたときの情報にします。


```C#:ModelBuilder.cs
// ⓵インクルードにNpgsqlを追加する
using Npgsql;

～～～

namespace TaxiFarePredictionML.ConsoleApp
{
    public static class ModelBuilder
    {
～～～
// ⓶CreateModel関数の”Load Data”コメント箇所をファイル読み込みからデータベースアクセスの変更する
        public static void CreateModel()
        {
            // Load Data
            //IDataView trainingDataView = mlContext.Data.LoadFromTextFile<ModelInput>(
            //                                path: TRAIN_DATA_FILEPATH,
            //                                hasHeader: true,
            //                                separatorChar: ',',
            //                                allowQuoting: true,
            //                                allowSparse: false);
            DatabaseLoader loader = mlContext.Data.CreateDatabaseLoader<ModelInput>(); 
            string connectionString = "Server=localhost;Port=5432;User ID=postgres;Database=TaxiFare;Password=password;Enlist=true";
            string sqlCommand = "select * from taxi_fare_train;";
            DatabaseSource dbSource = new DatabaseSource(NpgsqlFactory.Instance, connectionString, sqlCommand);
            IDataView trainingDataView = loader.Load(dbSource);

～～～
        }

```


③Main関数の先頭にCreateModel関数コールを追加します。


```C#:Program.cs
namespace TaxiFarePredictionML.ConsoleApp
{
    class Program
    {
～～～
        static void Main(string[] args)
        {
            // ⓷Main関数の先頭にCreateModel関数コールを追加
            ModelBuilder.CreateModel();
～～～
        }

```

#6 実行
今回は、デバッグ実行でDBアクセスを確認しつつ行ったため、スタートアッププロジェクトを「TaxiFarePredictionML.ConsoleApp」に設定して実行しました。
スタートアッププロジェクトはソリューションのプロパティから設定できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263183/31e4afed-53e0-b875-ebd4-2b6ed933161f.png)
![手順7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263183/c87f86d5-e1a5-1429-b9d7-c4224fcb1076.png)

#7 まとめ
ML.NETでPostgreSQLにアクセスして学習する方法についてみてきました。
DBはSQL Server、Azure SQL Database、Oracle、SQLite、PostgreSQL、Progress、IBM DB2などが使えるようです。
最初の学習はCSVファイルが使いやすいと思いますが、データを蓄積して再学習したい場合にデータベースが使えればデータの管理がしやすいと思います。

続く
[ML.NETドキュメントリーディング#3](https://qiita.com/sunnyyone/items/4bed6f986ca36c5aa86c)