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

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

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

Nisikaの中古マンション価格予測のデータをグラフで可視化する

はじめに

  • 下記の記事でデータ前処理を行ったので、今回は、そのデータ前処理を行ったデータをグラフで確認する px-wing.hatenablog.com

ヒストグラム表示

fig, axes = plt.subplots(2,2, figsize=(20,10))
axes[0][0].hist(df["最寄駅:距離(分)"],bins=20)
axes[0][1].hist(df["面積(㎡)"],bins=200)
axes[0][1].set_xlim(0, 250)
axes[1][0].hist(df["建築年"],bins=20)
axes[1][1].hist(df["取引価格(総額)_log"],bins=20)
plt.show()

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

散布図

  • 散布図の見方はこちらが参考になります。 next-sfa.jp
fig, axes = plt.subplots(3,1, figsize=(20,10))
axes[0].scatter(df["最寄駅:距離(分)"],df["取引価格(総額)_log"], alpha=0.1, color="red")
axes[0].set_xlabel("Distance (in minutes)", fontsize=20) # (6)x軸ラベル
axes[0].set_ylabel("Transaction price (total)", fontsize=20) # (7)y軸ラベル
axes[1].scatter(df["面積(㎡)"],df["取引価格(総額)_log"], alpha=0.1, color="red")
axes[1].set_xlabel("Area (m2)", fontsize=20) # (6)x軸ラベル
axes[1].set_ylabel("Transaction price (total)", fontsize=20) # (7)y軸ラベル
axes[2].scatter(df["建築年"],df["取引価格(総額)_log"], alpha=0.1, color="red")
axes[2].set_xlabel("Year of construction", fontsize=20) # (6)x軸ラベル
axes[2].set_ylabel("Transaction price (total)", fontsize=20) # (7)y軸ラベル
plt.show()

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

相関関係の確認

  • 説明変数どうしの、相関がありすぎるものが混ざっていると推定精度が悪化する可能性があるので、目視でチェックする
df[['最寄駅:距離(分)','面積(㎡)','建築年', '取引価格(総額)_log']].corr()

## 下記は上記の出力結果
    最寄駅:距離(分) 面積(㎡) 建築年   取引価格(総額)_log
最寄駅:距離(分) 1.000000    0.151880    0.117809    -0.215520
面積(㎡) 0.151880    1.000000    -0.067415   0.382755
建築年   0.117809    -0.067415   1.000000    -0.538493
取引価格(総額)_log    -0.215520   0.382755    -0.538493   1.000000

ヒートマップの出力

#日本語の文字化け対応※うまくいかない
#import matplotlib
#matplotlib.rcParams["font.family"] = "AppleGothic"
## 利用できるフォントの種類の一覧が表示することができる
#matplotlib.font_manager.fontManager.ttflist 

sns.heatmap(df[['最寄駅:距離(分)','面積(㎡)','建築年', '取引価格(総額)_log']].corr())

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

棒グラフの表示

df["取引年"] = df["取引時点"].apply(lambda x:str(x)[:4])
fig, axes = plt.subplots(2,1, figsize=(20,10))
sns.countplot(x="取引年", data=df.sort_values("取引年"), ax=axes[0])
sns.countplot(x="取引時点", data=df.sort_values("取引時点"), ax=axes[1])

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

Nisikaの中古マンション価格予測でデータ前処理をしてみる

はじめに

  • 下記のコンペデータを利用してデータの前処理をしてみる www.nishika.com

google colabを利用して検証する

  • サイトから検証データ、テストデータをダウンロードし、google colabにアップロードする。
  • 前処理を行うために必要なライブラリをインストールする
  • 初期値を設定する
# trainデータを解凍する
!unzip train.zip
## 和暦を西暦に変換するライブラリ
!pip install jeraconv

import datetime

currentDateTime = datetime.datetime.now()
date = currentDateTime.date()
current_year = date.strftime("%Y")
  • 標準でインストールされているライブラリをインポートする
## 必要なライブラリーのimport
import glob
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

%matplotlib inline

データの読み込み

  • 訓練データが複数のCSVファイルに分かれているので1つにDataFrameにまとめる
  • データ量や欠損値データの確認を行う
files = glob.glob("train/*.csv")

data_list = []
for file in files:
  # trainフォルダにあるすべてのCSVファイルをdata_frameに変換し、その値を配列に格納する
  # index_col=0のようにindexとして使いたい列の列番号を0始まりで指定する。
  data_list.append(pd.read_csv(file, index_col=0))

# 配列に格納したデータフレームを1つにまとめる
df = pd.concat(data_list)

# データの行数とカラム数の確認
df.shape

# 欠損値やデータ型の確認
# 0 non-nullのデータは欠損値のため、削除する
df.info()

欠損値データの削除

## 欠損値のカラムの削除
#for col in df.columns:
#  if df[col].count() == 0:
#    df = df.drop(col, axis=1)
nonnull_list = []
for col in df.columns:
  count = df[col].count()
  if count == 0:
    nonnull_list.append(col)
df = df.drop(nonnull_list, axis=1)    
df.info()

特徴量パラメータの加工

市区町村データの削除

  • 市区町村名と市区町村コードは、一致するデータが入っている。 全く一致するデータが入っていることはモデルとしてよくない。 全く一致するようなデータが入っていると多重共線性が発生する。

※多重共線性とは、言ってみれば類似度の高い説明変数の間で回帰係数の「取り合い」のような現象が発生しているケースです。

# value_countsは一意の値のカウントを含むシリーズを返します。同じ結果となる場合、多重共線性が発生する可能性がたかいデータとして想定できるのでカラムを削除する
df["市区町村コード"].value_counts()
#df["市区町村名"].value_counts()
df = df.drop("市区町村名", axis=1)

種類データの削除

## describeはint型、float型のデータの統計量を返す。object型は表示されない
df.describe()
## 文字列型の統計量のデータを参照したい場合
## 文字列のデータを確認しuniqueで表示されるデータが1件の場合、すべて同じデータなので意味のなさないデータだとわかる
## そのため、種類のカラムを削除する
df.astype("str").describe()
df = df.drop("種類", axis=1)

最寄駅:距離(分)データの加工

## 数字に文字列が入ってデータを加工する
pd.set_option("display.max_rows", 500)
## 分とかHなどの文字が入っていることを確認する
df["最寄駅:距離(分)"].value_counts()
## 対象の文字列を数値に変換するリストを作成する
dis = {
    "30分?60分": 45,
    "1H?1H30": 75,
    "2H?": 120,
    "1H30?2H": 105
}
## 上記のリストの内容に変換し、float型に変換して再設定する
df["最寄駅:距離(分)"] = df["最寄駅:距離(分)"].replace(dis).astype(float)

面積の加工

pd.set_option("display.max_rows", 500)
df["面積(㎡)"].value_counts()
df["面積(㎡)"] = df["面積(㎡)"].replace({"2000㎡以上": "2000"}).astype(float)
df["面積(㎡)"].value_counts()

建築年の加工

  • jeraconv ライブラリを利用して和暦を西暦に変換する
  • 上記で算出した値から現在の年を引くことで築年数を算出する
## 和暦のデータを西暦に変換して現在からの経過年数を格納する
from jeraconv import jeraconv
j2w = jeraconv.J2W()

#df["建築年"].valueでループすることも可能だが1行づつ全データに対して置換をしないといけないので時間がかかる
y_list = {}
for i in df["建築年"].value_counts().keys():
  try:
    tikunensu = int(current_year) - j2w.convert(i)
  except:
    ## 戦前という文字列は置換できないので、固定値で
    tikunensu = int(current_year) - 1945
  finally:
    y_list[i] = tikunensu
df["建築年"] = df["建築年"].replace(y_list)

取引時点の加工

##  取引時点
year = {
    "年第1四半期": ".25",
    "年第2四半期": ".5",
    "年第3四半期": ".75",
    "年第4四半期": ".99",
}
year_list = {}
year_replace = ""
for i in df["取引時点"].value_counts().keys():
    for k, j in year.items():
       if k in i:
           year_replace = i.replace(k,j)
    year_list[i] = year_replace

df["取引時点"] = df["取引時点"].replace(year_list).astype(float)

加工後のデータ

 市区町村コード   最寄駅:距離(分) 面積(㎡) 建築年   建ぺい率(%)   容積率(%)  取引時点    取引価格(総額)_log
count   637351.000000   614306.000000   637351.000000   619117.000000   614848.000000   614848.000000   637351.000000   637351.000000
mean    18513.985300    11.731487   58.663570   26.978080   67.601944   301.601876  2013.633153 7.217424
std 9596.722442 12.197090   26.712019   11.496701   10.402295   148.105400  3.884546    0.353935
min 1101.000000 0.000000    10.000000   2.000000    30.000000   50.000000   2005.750000 2.653213
25% 13106.000000    5.000000    45.000000   18.000000   60.000000   200.000000  2010.500000 7.000000
50% 14104.000000    8.000000    65.000000   26.000000   60.000000   200.000000  2013.750000 7.255273
75% 27114.000000    14.000000   75.000000   35.000000   80.000000   400.000000  2016.990000 7.447158
max 47213.000000    120.000000  2000.000000 77.000000   80.000000   1300.000000 2019.990000 9.934498

pandasとMatplotlibを動画で学習

はじめに

  • 下記の動画でpandasとMatplotlibの勉強をする

www.youtube.com

www.youtube.com

pandas

  • pandasで勉強したこと
# データの数
df.shape

df.info()
df.columns
# pclassのユニークの値取得
df["pclass"].unique()
## pclassのカテゴリごとの数
df["pclass"].value_counts()
# データの件数、平均値、最小値、最大値取得
df.describe()
## survivedを基準とした各カラムの平均値を算出
df.groupby("survived").mean()
##  データの降順ソート
df.sort_values("age", ascending=False)
## 欠損値の数
df.isnull().sum()

## 欠損値の行を削除する。行の中で1つでもNULLのカラムがあった行データは削除する
df.dropna()
## 欠損値の補完
df["age"].fillna(df["age"].mean()).head(10)

## 文字列データのダミー変数化
df= pd.get_dummies(df)

## 各カラムの相関値の取得
df.corr()

## indexの値をカラムとして利用できるようにする
df = df.reset_index()
df_a = df[["index", "survived"]]
df_b = df[["index", "pclass"]]

## データフレームの結合①
## index(onパラメータ)をキーとしてinnerJoin(howパラメータ)をする
pd.merge(df_a, df_b, on="index", how="inner")

## データフレームの結合②
## axis=1の場合、横に結合、axis=0の場合、縦の結合になる
pd.concat([df_a, df_b], axis=1)

Matplotlib

  • matplotlibで勉強したこと
## ヒストグラム
##bins  ビン (表示する棒) の数。階級数。(デフォルト値: 10)
##range ビンの最小値と最大値を指定。(デフォルト値: (x.min(), x.max())) 
plt.hist(df["fare"], bins=40, range=(0,100))
plt.show()

## 折れ線グラフ
### figure グラフのサイズを指定する
plt.figure(figsize=(20,10))
### グラフのラベルを表示
plt.title("test")
plt.xlabel("data_index")
plt.ylabel("farel")

plt.plot(df["fare"])
plt.show()

### 性別ごとのfareの値をヒストグラムで表示
df["fare"].hist(by=df["sex"])


## ヒストグラムのグラフを複数表示する
fig, axes = plt.subplots(2,2,figsize=(20,10))
axes[0][0].hist(df["age"], bins=20)
axes[0][1].hist(df["fare"], bins=20)
axes[0][1].set_xlim(0,200)
axes[1][0].hist(df["sex"], bins=20)
axes[1][1].hist(df["pclass"], bins=20)

## 棒グラフ
df.groupby("pclass").count().index
### pclass毎のsurviedの数
df.groupby("pclass").count()["survived"]

plt.bar(df.groupby("pclass").count().index, df.groupby("pclass").count()["survived"])

## 散布図
plt.scatter(df["fare"], df["age"], alpha=0.2)

pandasの20本ノックをやってみた。

はじめに

  • 下記の動画の20本ノックを試してみた。 www.youtube.com

20本ノックを試した結果

import pandas as pd

# 1本目 データの読み込み
df = pd.read_csv("./weather.csv");

# 2本目 データの中身の確認(先頭3行、末尾10行を表示)
df.head(3)
df.tail(10)

# 3本目 不要な列、特定の行の削除
df.columns

## 下記の方法は必要な列だけを指定してデータを抽出する方法
df = df[['年月日', '平均気温(℃)', '最高気温(℃)','最低気温(℃)','降水量の合計(mm)','最深積雪(cm)','平均雲量(10分比)','平均蒸気圧(hPa)','平均風速(m/s)','日照時間(時間)']][1:]
df
# 不要な列の削除は下記のようにdropでもできる。 axis=1は行、axis=0は列
#df = df.drop(["日照時間(時間).1","日照時間(時間).2"],axis=1)
#df

# 列の削除
#df = df.drop(["年月日","最高気温(℃)"],axis=1)
#df
# 行の削除
#df = df.drop(3,axis=0)
#df

# 4本目 データの型、サイズ、列名、行名の確認
# データ型の確認
df.dtypes
# データのサイズの確認
df.shape
# 列名の確認
df.index
# 列名確認
df.columns

# 5本目 任意の要素を取得する
# 自分の答え
#df.loc[5:10]
#df.loc[3:6][['最高気温(℃)','最低気温(℃)','降水量の合計(mm)','最深積雪(cm)']]

# ilocを利用する場合
# indexは0スタートとなるため、5行目のデータを取得する場合、4を指定する、カラム名もindexで指定する
df.iloc[4:10, 2:6]

# locを利用する場合
# 5行目から10行目を取得して、カラム名が「最高気温(℃)」~「最深積雪(cm)」を指定する 
df.loc[5:10, '最高気温(℃)':'最深積雪(cm)']

# 6本目 条件抽出
# nationalityがAmericaである
# ageが20以上30未満である
# 自分の答え
df_peple = pd.read_csv("./people.csv")
df_peple.query('20 <= age < 30 and nationality == "America"')

## 別の書き方
df_peple[df_peple['nationality'] == 'America']
df_peple[df_peple['nationality'].isin(['America'])]
df_peple[(df_peple['age'] >= 20) & (df_peple['age'] < 30)]
df_peple.query('age >= 20 & age < 30')

# 7本目 ユニークな値を抽出
## pandas.core.frame.DataFrameの場合、uniqueは使えない。
## pandas.core.series.Seriesの場合、uniqueが使える
df_peple['nationality'].unique()

# 8本目 重複除去
df_peple.drop_duplicates(subset='nationality')

# 9本目 カラム名変更

## 一括でカラム名を変更する場合
df.columns = ['年月日', '平均気温', '最高気温', '最低気温', '降水量の合計', '最深積雪',
              '平均雲量', '平均蒸気圧', '平均風速', '日照時間']

## 特定のカラム名を変更する場合
df.rename(columns={'平均気温' : '平均'})

# 10本目 並び替え
## 昇順
df.sort_values('最高気温')

## 降順にする場合、ascending=Falseを指定する
df.sort_values('最高気温', ascending=False)

## 11本目 ダミー変数への処理

## 文字列の値を数値に変換
pd.get_dummies(df_peple['nationality'])

## データフレームに結合したい場合
pd.get_dummies(df_peple, columns=['nationality'])

## 12本目 欠損値の確認
df.isnull()
df.isnull().sum()

## 13本目 欠損値の補完
df = df.fillna(0)
## https://qiita.com/0NE_shoT_/items/8db6d909e8b48adcb203
df