フリーランス 技術調査ブログ

フリーランス/エンジニア Ruby Python Nodejs Vuejs React Dockerなどの調査技術調査の備忘録

Kaggle Tabular Playground Series - Mar 2022 コンペに参加してみた

はじめに

データ分析・前処理

  • xは0,1,2の3種類だったので、カテゴリ変数の扱いにしてOne-Hotエンコーディングを行ってみて。
  • yは0,1,2,3の4種類だったので、カテゴリ変数の扱いにしてOne-Hotエンコーディングを行ってみて。
  • timeは年、月、日、時、分で分けるが、説明変数として時間と分と曜日で利用した。  テストデータが、とある日の月曜日分のデータしかなかったため。
  • directionも、カテゴリ変数の扱いにしてOne-Hotエンコーディングを行ってみて。
  • 欠損値は存在しなかったので、何も対応していない。
  • 外れ値もなさそうなので、何も対応していない。
  • 目的変数と、その他のデータに相関関係があまりなさそうに見えたので、ほとんどの項目を説明変数にした

モデル構築時

  • 説明変数は,x,y,時間,分,directionを使った。
  • 線形回帰モデルとXGBoost回帰モデルを作成して、XGBoost回帰で作成したほうが精度はよかった。  kaggleの順位は線形回帰モデル(700位)とXGBoost回帰モデル(405位)になった

よくわからず進めたところ

  • XGBoostのハイパーパラメータは参考サイトをコピペして利用した。  XGBoostのサンプルを探していたときに、最初分類のサンプルに気づかず分類の記述方法をしていたが、回帰の書き方を  見つけて、調査に遠回りした。
  • ハイパーパラメータの生成するのに1時間以上掛かったのがよくわからず、もっと早く生成できないものかと思いました。
  • 学習する際に月曜日のデータだけに絞ってテストしたほうがよかったのかなぁと思いました。テストデータが月曜日のデータしかなかったので。
  • グラフを使いこなせないので、グラフでデータの可視化をしなかった。可視化してデータを見れるようにしたい

コンペ時に利用したコード

import math
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
import xgboost as xgb
import optuna
from datetime import datetime as dt
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import make_scorer
from sklearn.preprocessing import LabelEncoder 
from sklearn.model_selection import cross_val_score

#現在の最大表示列数の出力
pd.get_option("display.max_columns")

#最大表示列数の指定(ここでは50列を指定)
pd.set_option('display.max_columns', 50)

## データの読み込み
train = pd.read_csv("train.csv")
test = pd.read_csv("test.csv")

## 欠損値の確認
train.isnull().sum()
## directionのデータの確認
train.groupby('direction').size()

def objective(trial,df_X,df_y):
    #評価するハイパーパラメータの値を規定
    params ={
        'max_depth':trial.suggest_int("max_depth",1,10),
        'min_child_weight':trial.suggest_int('min_child_weight',1,5),
        'gamma':trial.suggest_uniform('gamma',0,1),
        'subsample':trial.suggest_uniform('subsample',0,1),
        'colsample_bytree':trial.suggest_uniform('colsample_bytree',0,1),
        'reg_alpha':trial.suggest_loguniform('reg_alpha',1e-5,100),
        'reg_lambda':trial.suggest_loguniform('reg_lambda',1e-5,100),        
        'learning_rate':trial.suggest_uniform('learning_rate',0,1)}

    model = xgb.XGBRegressor(n_estimators=10,
                            verbosity=0,
                            n_jobs=-1,
                            random_state=0,
                            **params)

    #交差検証
    scores = cross_val_score(model, df_X, df_y, scoring='neg_mean_squared_error',cv=5)
    score_mean = -1 * np.mean(scores)

    return score_mean

## データ前処理
def pre_data(df):
  ## 日時を月、日、時、分、週に分割
  df_date_time = pd.DataFrame({'datetime': pd.to_datetime(df['time'])})
  df['Month'] = df_date_time['datetime'].dt.month
  df['Day'] = df_date_time['datetime'].dt.day
  df['Hour'] = df_date_time['datetime'].dt.hour
  df['Minute'] = df_date_time['datetime'].dt.minute 
  df['Week'] = df_date_time['datetime'].dt.strftime('%A')
  
  ## One-hot-Encoding
  df = pd.concat([df, pd.get_dummies(df['x'],prefix='x'),pd.get_dummies(df['y'],prefix='y'), pd.get_dummies(df['direction']), pd.get_dummies(df['Week'])], axis=1)
  ## 不要なカラムを削除
  df = df.drop(columns=['time', 'direction', 'Week'])

  ## 月曜日データのみ抽出。
  ## テストデータが月曜日だけのため。
  #train = train[train['Monday'] == 1]
  return df

## 1時間以上経過して生成されたハイパーパラメータ
## {'max_depth': 10, 'min_child_weight': 3, 'gamma': 0.8627614678291173, 'subsample': 0.9488395992082753, 'colsample_bytree': 0.9978454006405445, 'reg_alpha': 0.00048624833228949274, 'reg_lambda': 0.00016168213697343028, 'learning_rate': 0.6462794245516749}
def create_hyperparameter(X, y):
  study = optuna.create_study()
  #studyインスタンスのoptimize()に作った関数を渡して最適化する。
  study.optimize(lambda trial: objective(trial,X,y), n_trials=100)
  print(study.best_params)    
  print(study.best_value)  
  return study.best_params

## 線形回帰モデル(個人的な最大スコア:0.23 / kaggle : 700/756位)
def create_linear_regression_model(df):
  # 説明変数
  #target= ['x_0','x_1','x_2','y_0','y_1','y_2','y_3','Hour','Minute','EB','NB','NE','NW','SB','SE','SW','WB','Friday','Monday','Saturday','Sunday','Thursday','Tuesday','Wednesday']
  target= ['x_0','x_1','x_2','y_0','y_1','y_2','y_3','Hour','Minute','EB','NB','NE','NW','SB','SE','SW','WB','Monday']
  x = df[target].values
  # 目的変数
  y = train['congestion'].values
  # 学習データ/テストデータ分割
  # 訓練データ: 70% / テストデータ: 30%
  X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=0)

  # 重回帰のインスタンス
  model = LinearRegression()

  # モデル学習
  model.fit(X_train, y_train)

  # 予測値(学習データ)
  y_train_pred = model.predict(X_train)

  # 学習データの結果
  print("##学習データの結果")
  print(model.coef_)  #回帰変数の表示
  print(model.intercept_)  #回帰直線の切片
  print(model.get_params())  #パラメータの取得
  print(model.predict(X_test))  #予測値の表示
  print(model.score(X_train,y_train))  #決定係数の表示

  # 予測値(テストデータ)
  y_test_pred  = model.predict(X_test)

  # テストデータの結果
  print("##テストデータの結果")
  print(model.coef_)  #回帰変数の表示
  print(model.intercept_)  #回帰直線の切片
  print(model.get_params())  #パラメータの取得
  print(model.predict(X_test))  #予測値の表示
  print(model.score(X_test,y_test))  #決定係数の表示

  return model

def create_xgb_model(df):
  # 説明変数
  #target= ['x_0','x_1','x_2','y_0','y_1','y_2','y_3','Hour','Minute','EB','NB','NE','NW','SB','SE','SW','WB','Friday','Monday','Saturday','Sunday','Thursday','Tuesday','Wednesday']
  target= ['x_0','x_1','x_2','y_0','y_1','y_2','y_3','Hour','Minute','EB','NB','NE','NW','SB','SE','SW','WB','Monday']
  #x = df[target].values
  # 目的変数
  #y = train['congestion'].values

  # 目的変数
  y = df["congestion"].values
  # 説明変数
  x = df[target].values

  X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=100, stratify=y)
  # ハイパーパラメータを生成 1時間以上経過してようやく生成された
  #params = create_hyperparameter(X_train,y_train)

  # 上記で取得したパラメータをXGBRegressorの引数に指定する
  grid_xgb_reg = xgb.XGBRegressor(max_depth=10, min_child_weight=3, gamma=0.8627614678291173, subsample=0.9488395992082753, colsample_bytree=0.9978454006405445, reg_alpha=0.00048624833228949274, reg_lambda=0.00016168213697343028, learning_rate=0.6462794245516749)
  grid_xgb_reg.fit(X_train, y_train)

  y_train_pred = grid_xgb_reg.predict(X_train)
  y_test_pred = grid_xgb_reg.predict(X_test)

  # 裁量スコアとなるパラメータ値を出力
  #print(grid_xgb_reg.best_score_)
  print(y_train_pred)
  print(y_test_pred)
  
  return grid_xgb_reg



## メイン
train = pre_data(train)
# 重回帰モデル 700位の結果
#model = create_linear_regression_model(train)

# xgboostモデル 405位の結果 
model = create_xgb_model(train)

## 検証データでモデルの評価
test = pre_data(test)
target= ['x_0','x_1','x_2','y_0','y_1','y_2','y_3','Hour','Minute','EB','NB','NE','NW','SB','SE','SW','WB','Monday']
x = test[target].values
result = model.predict(x)
test['congestion'] = result

## 提出用CSVファイル生成
test[['row_id','congestion']].to_csv('submission.csv', index = False)

参考文献

## 参考文献
# https://ohke.hateblo.jp/entry/2019/02/16/230000
# LabelEncoder
# https://note-tech.com/table_preprocess_summary/
# ロジット変換
# https://uribo.github.io/practical-ds/02/numeric.html
# 層化抽出: 引数stratify
# https://note.nkmk.me/python-sklearn-train-test-split/
# 【初心者】コピペでできるXGBoost回帰(※分類だった)
# https://dataanablog.com/xgboost-regression-that-can-be-done-by-copy-and-paste/
# XGBoost 回帰サンプル
# https://dataanablog.com/xgboost-regression-that-can-be-done-by-copy-and-paste/
# optuna
# https://qiita.com/mamorous3578/items/912f1a2be0e9da7e9140
# Optunaを使ったXGBoostのハイパーパラメータ最適化
# https://datadriven-rnd.com/optuna_xgboost/
# XGBoostについて(ハイパーパラメータ最適化)
# https://datadriven-rnd.com/2021-01-23-161630/

参考文献

- LabelEncoder
https://note-tech.com/table_preprocess_summary/
- ロジット変換
https://uribo.github.io/practical-ds/02/numeric.html
- 層化抽出: 引数stratify
https://note.nkmk.me/python-sklearn-train-test-split/
- 【初心者】コピペでできるXGBoost回帰(※分類だった)
https://dataanablog.com/xgboost-regression-that-can-be-done-by-copy-and-paste/
- XGBoost 回帰サンプル
https://dataanablog.com/xgboost-regression-that-can-be-done-by-copy-and-paste/
- optuna
https://qiita.com/mamorous3578/items/912f1a2be0e9da7e9140
- Optunaを使ったXGBoostのハイパーパラメータ最適化
https://datadriven-rnd.com/optuna_xgboost/
- XGBoostについて(ハイパーパラメータ最適化)
https://datadriven-rnd.com/2021-01-23-161630/

コンペ参加結果

  • 405位でした。

Amplify+Nextjs環境構築

はじめに

  • はてなブログをAmplify+Nextjs環境に移行するためにまず初めに環境構築を行う。

Amplify CLI のインストール

npm install -g @aws-amplify/cli

AWSアカウントの紐付け

 amplify configure
  • リージョンの選択
Follow these steps to set up access to your AWS account:

Sign in to your AWS administrator account:
https://console.aws.amazon.com/
Press Enter to continue

Specify the AWS Region
? region:
  us-west-2
  eu-north-1
  eu-west-1
❯ eu-west-2
  eu-west-3
  eu-central-1
  ap-northeast-1
(Move up and down to reveal more choices)
  • ユーザー名が聞かれますがEnterを押す
? user name:  amplify-mdjVQ
Complete the user creation using the AWS console

アカウントの作成

f:id:PX-WING:20220310235458p:plain

-ユーザー名「amplify-XXXXX(ランダム文字列)」 - アクセスの種類「プログラムによるアクセスのみ許可」

f:id:PX-WING:20220310235852p:plain

  • ポリシー名「AdministratorAccess-Amplify」を選択する

  • タグの追加は何か指定する必要があれば f:id:PX-WING:20220316204632p:plain

  • 内容を確認して問題なければ「ユーザーの作成」をクリックします。 f:id:PX-WING:20220316204914p:plain

  • ユーザーの作成が完了しました。 表示されているアクセスキー情報を使用してターミナルでIAMユーザーを設定していきます。 f:id:PX-WING:20220316205447p:plain

amplifyのCLIの設定

  • アカウント作成時に発行されたアクセスキー、シークレットアクセスキー、ユーザー名を入力するし、設定完了
Enter the access key of the newly created user:
? accessKeyId:  ********************
? secretAccessKey:  ****************************************
This would update/create the AWS Profile in your local machine
? Profile Name:  amplify-xxxxxx

Amplifyの初期化

amplify init

? Enter a name for the project 【example-project-name】
The following configuration will be applied:

Project information
| Name: winlogic
| Environment: dev
| Default editor: Visual Studio Code
| App type: javascript
| Javascript framework: none
| Source Directory Path: src
| Distribution Directory Path: dist
| Build Command: npm run-script build
| Start Command: npm run-script start

? Initialize the project with the above configuration? 【No】
? Enter a name for the environment 【dev】
? Choose your default editor: 【Visual Studio Code】
? Choose the type of app that you're building 【javascript】
Please tell us about your project
? What javascript framework are you using 【react】
? Source Directory Path:  【src】
? Distribution Directory Path: 【.next】
? Build Command: 【npm run-script build】
? Start Command: 【npm run-script start】
Using default provider  awscloudformation
? Select the authentication method you want to use: 【AWS profile】

amplifyのホスティングの追加

$ amplify add hosting
? Select the plugin module to execute 【Hosting with Amplify Console (Managed hosting with custom】 domains, Continuous deployment)
? Choose a type 【Continuous deployment (Git-based deployments)】
? Continuous deployment is configured in the Amplify Console. Please hit enter once you connect your repository

f:id:PX-WING:20220316220822p:plain

f:id:PX-WING:20220316221533p:plain

f:id:PX-WING:20220316221936p:plain

f:id:PX-WING:20220316222136p:plain

f:id:PX-WING:20220316222330p:plain

f:id:PX-WING:20220316222450p:plain

  • amplifyのデプロイ用ロールが作成される f:id:PX-WING:20220316222735p:plain

  • 「パッケージバージョンの上書きを追加」ボタンを押して「nextjs version」を選択してバージョンに「latest」を指定して次へボタンをクリックする f:id:PX-WING:20220316223249p:plain

f:id:PX-WING:20220316223605p:plain

デプロイ開始

  • デプロイ開始から15分後にデプロイ完了 f:id:PX-WING:20220316231311p:plain

参考にしたサイト

  • 下記の2つの記事を読めば、ほぼできる

dev.classmethod.jp

dev.classmethod.jp

DockerでPostgreSQLの環境構築

Docker-Compose

version: "3"
services:
  postgres:
    container_name: "db"
    image: postgres:latest
    restart: always
    environment:
      POSTGRES_USER: test
      POSTGRES_PASSWORD: password
      PGPASSWORD: password123
      POSTGRES_DB: test
      PGDATA: /var/lib/postgresql/data/pgdata
      TZ: "Asia/Tokyo"
    ports:
      - 5432:5432
    volumes:
      - db-pg-data:/var/lib/postgresql/data
    networks:
      - test-network
  pgadmin:
    image: dpage/pgadmin4
    restart: always
    ports:
      - 8080:80
    environment:
      PGADMIN_DEFAULT_EMAIL: test@example.com
      PGADMIN_DEFAULT_PASSWORD: password
    volumes:
      - admin-data:/var/lib/pgadmin
    networks:
      - test-network
networks:
  test-network:
    driver: bridge
volumes:
  db-pg-data:
  admin-data:

Dockerから外部のサーバーへ接続する方法

設定手順

  • portsに22を指定する(ポートフォーディング用のポートを指定する)
  • extra_hostsに外部サーバー用のサーバーのIPを指定する
version: "3"
services:
  app:
    container_name: app-service
    build:
      context: ./node
    volumes:
      - ../app:/srv/app
    command: /bin/sh -c "entrypoint.sh"
    ports:
      - "3000:3000"
      - "22:22"
    networks:
      - hoge-network
    extra_hosts:
      - "db_test:192.168.0.10"

Dockerfileファイルの設定

  • openssh-clientをインストールする
  • ポートフォーワーディング時に利用する公開鍵をDocker内に追加する
  • アプリケーション起動用のコマンドとポートフォーワーディングの設定を追加したシェルスクリプトをDockerfileに設定する
FROM node

ENV LANG C.UTF-8
ENV TZ Asia/Tokyo

RUN apt-get update && \
    apt-get install -y vim less procps libssl-dev curl python make g++  && \
                                             openssh-client

# 公開鍵を設定する
RUN mkdir -p /home/node/.ssh
ADD key.pem /home/node/.ssh
ADD config /home/node/.ssh
RUN chown node:node -R /home/node
RUN chmod 700 /home/node/.ssh
RUN chmod 600 /home/node/.ssh/key.pem
RUN chmod 600 /home/node/.ssh/config

# yarn install / dev とポートフォーワーディングの設定
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT "/entrypoint.sh"

ポートフォーワーディングの設定用シェルスクリプト

  • oStrictHostKeyChecking=noで接続確認のメッセージをスキップすることができる。
#entrypoint.sh
#!/bin/sh
yarn install
yarn dev &
ssh -oStrictHostKeyChecking=no -N -L 3307:hoge.ap-northeast-2.rds.amazonaws.com:3306 -i ~/.ssh/key.pem -p 22 ec2-user@192.168.0.10

ポートフォーワーディングがすぐに切断されるため、下記の設定ファイルをdocker内に追加する

Host *
  ServerAliveInterval 15

prismaで複数データベースに接続する手順

prisma複数データベースの接続方法

追加分のデータベースの接続情報を指定したschemaServiceB.prismaファイルを作成する

  • schema.prismaファイル(既存)
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "mysql"
  url      = env("ServiceA_MySQL")
}
  • schemaServiceB.prismaファイル(追加分)
generator client {
  provider = "prisma-client-js"

}

datasource db {
  provider = "mysql"
  url      = env("ServiceB_MySQL")
}

DBの情報からスキマーファイルの生成

- DBの情報からスキマーを作成する
npx prisma db pull --schema prisma/schema.prisma
npx prisma db pull --schema prisma/schemaServiceB.prisma

npx prisma generate --schema prisma/schema.prisma
npx prisma generate --schema prisma/schemaServiceB.prisma

上記のコマンドを実行するとprismaフォルダ内に「generated」フォルダが作成される

prisma
├── client.ts
├── generated
│   ├── client
│   │   ├── index-browser.js
│   │   ├── index.d.ts
│   │   ├── index.js
│   │   ├── libquery_engine-debian-openssl-1.1.x.so.node
│   │   ├── runtime
│   │   │   ├── esm
│   │   │   │   ├── index-browser.mjs
│   │   │   │   ├── index.mjs
│   │   │   │   └── proxy.mjs
│   │   │   ├── index-browser.d.ts
│   │   │   ├── index-browser.js
│   │   │   ├── index.d.ts
│   │   │   ├── index.js
│   │   │   ├── proxy.d.ts
│   │   │   └── proxy.js
│   │   └── schema.prisma
│   └── clientServiceB
│       ├── index-browser.js
│       ├── index.d.ts
│       ├── index.js
│       ├── libquery_engine-debian-openssl-1.1.x.so.node
│       ├── runtime
│       │   ├── esm
│       │   │   ├── index-browser.mjs
│       │   │   ├── index.mjs
│       │   │   └── proxy.mjs
│       │   ├── index-browser.d.ts
│       │   ├── index-browser.js
│       │   ├── index.d.ts
│       │   ├── index.js
│       │   ├── proxy.d.ts
│       │   └── proxy.js
│       └── schema.prisma
├── schema.prisma
└── schemaServiceB.prisma

schemaファイルにoutputを追加する

  • generatedフォルダのパスを指定する
  • schema.prismaファイル
generator client {
  provider = "prisma-client-js"
    output   = "./generated/client"
}

datasource db {
  provider = "mysql"
  url      = env("ServiceA_MySQL")
}
  • schemaServiceB.prismaファイル
generator client {
  provider = "prisma-client-js"
 output   = "./generated/clientServiceB"
}

datasource db {
  provider = "mysql"
  url      = env("ServiceB_MySQL")
}

prisma/client.tsファイルを修正する

  • 修正前
import { PrismaClient } from "@prisma/client";
const {
  ServiceA_MySQL,
} = process.env

const prisma = new PrismaClient({});
  • 修正後

各クライアントのインスタンス生成時にdatasourceを指定する。指定しないとうまくDB接続できませんでした。

import { PrismaClient  } from './generated/client'
import { PrismaClient as ServiceBPrismaClient } from './generated/clientServiceB'
const {
  ServiceA_MySQL,
  ServiceB_MySQL
} = process.env

const prisma = new PrismaClient({
  datasources: { db: { url: ServiceA_MySQL } },
});

export const serviceBPrisma = new ServiceBPrismaClient({
  datasources: { db: { url: ServiceB_MySQL } },

});

prismaを利用している箇所の修正

  • 既存DBを参照しているprismaの箇所をgeneratedフォルダ内のclientファイルを利用するように修正する
-import { user, PrismaClient } from '@prisma/client'
+import { user, PrismaClient } from '../../../prisma/generated/client'
  • 追加分のDBを参照しているprismaの箇所はgeneratedフォルダ内のclientファイルを利用するようにする
import { user, PrismaClient as ServiceBPrismaClient } from '../../../prisma/generated/clientServiceB'

参考文献

prisma複数データベースの接続方法

追加分のデータベースの接続情報を指定したschemaServiceB.prismaファイルを作成する

  • schema.prismaファイル(既存)
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "mysql"
  url      = env("ServiceA_MySQL")
}
  • schemaServiceB.prismaファイル(追加分)
generator client {
  provider = "prisma-client-js"

}

datasource db {
  provider = "mysql"
  url      = env("ServiceB_MySQL")
}

DBの情報からスキマーファイルの生成

- DBの情報からスキマーを作成する
npx prisma db pull --schema prisma/schema.prisma
npx prisma db pull --schema prisma/schemaServiceB.prisma

npx prisma generate --schema prisma/schema.prisma
npx prisma generate --schema prisma/schemaServiceB.prisma

上記のコマンドを実行するとprismaフォルダ内に「generated」フォルダが作成される

prisma
├── client.ts
├── generated
│   ├── client
│   │   ├── index-browser.js
│   │   ├── index.d.ts
│   │   ├── index.js
│   │   ├── libquery_engine-debian-openssl-1.1.x.so.node
│   │   ├── runtime
│   │   │   ├── esm
│   │   │   │   ├── index-browser.mjs
│   │   │   │   ├── index.mjs
│   │   │   │   └── proxy.mjs
│   │   │   ├── index-browser.d.ts
│   │   │   ├── index-browser.js
│   │   │   ├── index.d.ts
│   │   │   ├── index.js
│   │   │   ├── proxy.d.ts
│   │   │   └── proxy.js
│   │   └── schema.prisma
│   └── clientServiceB
│       ├── index-browser.js
│       ├── index.d.ts
│       ├── index.js
│       ├── libquery_engine-debian-openssl-1.1.x.so.node
│       ├── runtime
│       │   ├── esm
│       │   │   ├── index-browser.mjs
│       │   │   ├── index.mjs
│       │   │   └── proxy.mjs
│       │   ├── index-browser.d.ts
│       │   ├── index-browser.js
│       │   ├── index.d.ts
│       │   ├── index.js
│       │   ├── proxy.d.ts
│       │   └── proxy.js
│       └── schema.prisma
├── schema.prisma
└── schemaServiceB.prisma

schemaファイルにoutputを追加する

  • generatedフォルダのパスを指定する
  • schema.prismaファイル
generator client {
  provider = "prisma-client-js"
    output   = "./generated/client"
}

datasource db {
  provider = "mysql"
  url      = env("ServiceA_MySQL")
}
  • schemaServiceB.prismaファイル
generator client {
  provider = "prisma-client-js"
 output   = "./generated/clientServiceB"
}

datasource db {
  provider = "mysql"
  url      = env("ServiceB_MySQL")
}

prisma/client.tsファイルを修正する

  • 修正前
import { PrismaClient } from "@prisma/client";
const {
  ServiceA_MySQL,
} = process.env

const prisma = new PrismaClient({});
  • 修正後

各クライアントのインスタンス生成時にdatasourceを指定する。指定しないとうまくDB接続できませんでした。

import { PrismaClient  } from './generated/client'
import { PrismaClient as ServiceBPrismaClient } from './generated/clientServiceB'
const {
  ServiceA_MySQL,
  ServiceB_MySQL
} = process.env

const prisma = new PrismaClient({
  datasources: { db: { url: ServiceA_MySQL } },
});

export const serviceBPrisma = new ServiceBPrismaClient({
  datasources: { db: { url: ServiceB_MySQL } },

});

prismaを利用している箇所の修正

  • 既存DBを参照しているprismaの箇所をgeneratedフォルダ内のclientファイルを利用するように修正する
-import { user, PrismaClient } from '@prisma/client'
+import { user, PrismaClient } from '../../../prisma/generated/client'
  • 追加分のDBを参照しているprismaの箇所はgeneratedフォルダ内のclientファイルを利用するようにする
import { user, PrismaClient as ServiceBPrismaClient } from '../../../prisma/generated/clientServiceB'

参考文献

https://www.memory-lovers.blog/entry/2021/10/13/113000
https://zenn.dev/frog/articles/073af49880452f
https://github.com/prisma/prisma/issues/2443

はてなブログからMovableTypeへ移設、そしてCSV出力・JSONデータへ

はじめに

  • はてなブログを移設したく、APIやいろいろな方法を試したが、過去データ全部移設するには、MovableTypeに一度移設したほうがよさそうだということで、MovableTypeを10年ぶりに触ってみる。

インストール

  • メールアドレスを登録しないと無償版はダウンロードできないらしい。

  • Perlの環境を構築しないといけないので面倒だ。公式のDockerもないらしい www.sixapart.jp

14日間無料で使える

  • 下記のサイトからメールアドレスを登録するだけで14日間は無料で利用できるらしい。
  • 環境構築しないので、すぐに、はてなブログの検証が行えそうである。

movabletype.net

f:id:PX-WING:20220225214603p:plain

はてなブログ エクスポート

f:id:PX-WING:20220225215732p:plain

MovableTypeへインポート

  • 下記のメニューからインポートを選択する f:id:PX-WING:20220225220038p:plain

  • はてなブログからダウンロードしたファイルを指定して読み込みボタンをクリックする f:id:PX-WING:20220225220132p:plain

  • 出来上がりはメールでお知らせしてくれるらしい。 f:id:PX-WING:20220225220237p:plain

インポート完了後のMovableTypeの画面

  • はてなブログの記事がきれいに移設できていることを確認できる。 f:id:PX-WING:20220225221807p:plain

早速MovableTypeの記事をCSVファイルへエクスポート

  • MovableTypeだと記事をCSVファイルへ出力できる。  これで、はてなブログの過去記事すべてがCSVファイル形式でデータを入手できた。 f:id:PX-WING:20220225222010p:plain

CSVファイルからJSONにデータを変換する

  • 下記のサイトのようにCSVファイルからJSONに変換してくれるサイトがあるので、ブログデータをJSON形式にすることができる。 www.aconvert.com

次は

  • はてなブログのデータをJSON形式に変換できたので、次は作成したJSONを利用してReactから呼びさしてブログの記事を表示してみる。

Nisikaの中古マンション価格予測のデータでモデル構築する

はじめに

  • 前回と前々回でデータの加工及び可視化を行ったので、今度はモデルの構築を行ってみる

px-wing.hatenablog.com

px-wing.hatenablog.com

モデル構築

## モデル構築
import lightgbm as lgb
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error as mea

## 学習データを検証データと学習データを分ける。test_sizeで0.2を指定しているので、ランダムで20%のデータを検証データとする
df_train, df_val = train_test_split(df, test_size=0.2)

## 目的変数と説明変数とで分ける
### 目的変数をtrain_y,val_yに説明変数をtrain_x,val_xに格納する
col = "取引価格(総額)_log"
### 学習データ
train_y = df_train[col]
train_x = df_train.drop(col, axis=1)
### 検証データ
val_y = df_val[col]
val_x = df_val.drop(col, axis=1)

trains = lgb.Dataset(train_x, train_y)
valids = lgb.Dataset(val_x, val_y)

### LightGBMに設定するパラメータ
params = {
    "objective": "regression",
    "metrics": "mae"
}

## num_boost_roundはLightGMBの学習回数を指定するパラメータ。defaultは100になっている
## 複数の決定木を作成して直列に実行していく。
## early_stopping_roundsは過学習が発生した場合、過学習を停止させるパラメータ
model = lgb.train(params, trains, valid_sets=valids, num_boost_round=1000, early_stopping_rounds=100)

モデルの検証

## predictに検証データ用の説明変数(val_x)を設定する
## vals変数に目的変数の予測値が代入される
vals = model.predict(val_x)
## 平均絶対誤差 モデルで算出した予測値(vals)と実際の観測地(val_y)を比較する
mea(vals, val_y)

テストデータで検証とコンペ提出用CSVファイル出力

## テストデータの読みとデータの加工処理
df_test = pd.read_csv("test.csv",index_col=0)
df_test = data_pre(df_test)
predict = model.predict(df_test)
df_test["取引価格(総額)_log"] = predict
df_test[["取引価格(総額)_log"]].to_csv("submit_test.csv")

特徴量重要度の確認

### あるモデルモデルを作ったときに、そのモデルでつかっている説明変数の中で、どの説明変数が目的変数に寄与しているかを確認する
pd.DataFrame(model.feature_importance(), index=val_x.columns, columns=["importance"]).sort_values("importance", ascending=False)

結果

f:id:PX-WING:20220225001040p:plain