どこにでもいる30代SEの学習ブログ

主にプログラミング関連の学習内容。読んだ本の感想や株式投資についても書いてます。

【読書】「7つの習慣」の感想

f:id:predora005:20201019220334j:plain
<7つの習慣>*1

言わずと知れたキングオブ自己啓発書である「7つの習慣」を読みました。

初版は1989年と昔ですし、世界中でベストセラーとなった書籍なので読んだことのある方が多いのではないかと思います。

私も、有名だし色々な人が薦めているからという動機で読みました。内容は想像してた以上に良くて、多くの人に読まれているだけあるなと感じました。

https://www.amazon.co.jp/%E5%AE%8C%E8%A8%B3-7%E3%81%A4%E3%81%AE%E7%BF%92%E6%85%A3-%E4%BA%BA%E6%A0%BC%E4%B8%BB%E7%BE%A9%E3%81%AE%E5%9B%9E%E5%BE%A9-%E3%82%B9%E3%83%86%E3%82%A3%E3%83%BC%E3%83%96%E3%83%B3%E3%83%BBR%E3%83%BB%E3%82%B3%E3%83%B4%E3%82%A3%E3%83%BC-ebook/dp/B00KFB5DJCwww.amazon.co.jp

現代ビジネスマンにおすすめ

特に管理職やリーダーと呼ばれる人におすすめの内容でした。

内容は、いわゆるテクニックの類ではなく、もっと根本的な内容でした。一言で言えば「成功するためには人格を磨け」です。

本書でいう成功は、経済的な成功や名声を得ることではなく、精神的な成功を意味しています。仕事の充実も含まれますが、家族や友人との関係も含めた広い意味での成功です。

管理職やリーダーと呼ばれる人達は、仕事ではある程度成功していると言えるかもしれません。しかし、部下のことで悩み、上司からは無理難題を言われ、仕事の時間が増えることで家族からは文句を言われ、精神的には最も疲弊するポジションかもしれません。

そのような方が読むと、自身の本当に大切なことを見直したり、部下や上司、家族との接し方を変えるきっかけとなるかもしれません。

買う価値はあるのか?

本書の要約はネット上に山ほどあります。要約を読んで、7つの習慣がすでに実践できていると思った方は買わなくてよいと思います。なので、興味のある人はネットで概要を調べてから購入するとよいでしょう。

私は7つの習慣の半分も実践できてなかったので買う価値がありました。

第一次世界大戦後の文献は表面的なものばかり

筆者のコヴィー氏は、成功に関する文献の調査をしていくなかで、第一次世界大戦後の文献は、表面的なスキルやテクニックに関するものがほとんどであると分かったそうです。一方、建国から150年間に書かれたのは人間の内面にある人格的なことを成功の条件に挙げています。

そんななか、コヴィー氏は学校生活になじめず苦労する息子とのやりとりを通じて、コヴィー氏夫婦は、純粋に息子のためを思う親心よりも、世間の目に映る自分たちの姿の方を気にしていたと気づいたそうです。

そのことからコヴィー氏は、息子をそれまでと違う目で見るためには、夫婦があり方を変えなくてはならなかった。あり方を変えずに見方を変えることはできないと述べています。

終わりに

500ページ以上あるるため読むのが躊躇われるかもしれません。実際、読み終えるまでに時間がかかりました。

しかしながら、7つの習慣のうち最初の3つだけでも読む価値があります。なので、興味がある方には読んでみることをオススメします。

*1:Elias Sch.によるPixabayからの画像

【読書】「みんなが書き手になる時代の あたらしい文章入門」の感想

f:id:predora005:20201011193311j:plain
<みんなが書き手になる時代の あたらしい文章入門>*1

内容はコンパクトで分かりやすいです。
文章の目的は読者を動かすことだと述べており、ポイントを8講に絞ってまとめています。1時間ほどで読み終わりました。

1時間ほどのボリュームに対して¥540*2という価格を、高いと取るか妥当と取るかは人それぞれだと思います。 私は内容が良かったので妥当だと思いました。また、短い方が後で読み返しやすいので、短いのはむしろメリットだと捉えています。

https://www.amazon.co.jp/%E3%81%BF%E3%82%93%E3%81%AA%E3%81%8C%E6%9B%B8%E3%81%8D%E6%89%8B%E3%81%AB%E3%81%AA%E3%82%8B%E6%99%82%E4%BB%A3%E3%81%AE-%E3%81%82%E3%81%9F%E3%82%89%E3%81%97%E3%81%84%E6%96%87%E7%AB%A0%E5%85%A5%E9%96%80-%E3%82%B9%E3%83%9E%E3%83%BC%E3%83%88%E6%96%B0%E6%9B%B8-%E5%8F%A4%E8%B3%80%E5%8F%B2%E5%81%A5-ebook/dp/B077X8C7LV/www.amazon.co.jp

文章を書き慣れている人であったり、既に人を惹き付ける文章を書ける人にとっては、物足りないかもしれませんね。

また、Twitterなど短い文章の書き方を知りたい人にも参考にはなりますが、どちらかと言えばブログや記事を書く人に向けた内容という印象を受けました。

演習問題は無く具体例も多くはないため、一冊の書籍でガッツリと文章の書き方を学びたいという方は別の書籍で補いましょう。

本書のポイント

全8講のうち、各講の中で印象に残ったポイントをピックアップしました。

このポイントを見てピンとこない方にとっては、本書を読む価値ありでしょう。

  • 接続詞を意識する
  • 主張、理由、事実を含む
  • カメラワーク(主観、客観)を意識する
  • 起転承結を使う
  • 説得するのではなく納得させる
  • 自分にツッコむ
  • 引き算できない要素を見極める
  • あのころの自分に向けて書く

*1:PexelsによるPixabayからの画像

*2:価格は10/11時点のKindle

pygribで気象庁の数値予報GPVデータを読み込む

f:id:predora005:20200921202207j:plain ※ 2020/08/16にQrunchで書いた記事を移行しました。

気象庁の数値予報データをPythonで扱いました。 pygribというライブラリでデータを読み込み、数値予報データの中身を確認する方法を紹介します。

[1] 数値予報GPVデータ

[1-1] 数値予報とは

気象庁が行っている気象予測の一つが数値予報です。地球全体を一定の大きさの格子に区切り、各格子点の気温や風速などを予測しています。GPVはGrid Point Valueの略で、各格子点の値を指します。 詳しくは気象庁のページを見ていただいた方がわかるでしょう。

[1-2] 数値予報の種類

全球数値予報モデル(GSM), メソ数値予報モデル(MSM), 局地数値予報モデル(LFM)の3種類があります。 今回扱ったのは全球数値予報モデル(GSM)です。

名称 説明 格子点の間隔(水平方向)
全球数値予報モデル(GSM) 地球全体の大気を対象とした気象庁の数値予報モデル。Global Spectral Model。 日本域は20km四方(緯度0.2度x経度0.25度)。全球域は緯度0.5度x経度0.5度
メソ数値予報モデル(MSM) 日本及びその近海の大気を対象とした気象庁の数値予報モデル。Meso-Scale Model。 5km四方
局地数値予報モデル (LFM) 日本領域の大気を対象とした気象庁の数値予報モデル。Local Forecast Model。 2km四方

[1-3] データの形式

GRIB2という気象データ向けのバイナリフォーマットです。

[1-4] データの取得元

数値予報データは基本的には有償で、月額¥15,000ほどかかります。 しかしながら、ありがたいことに京都大学生存研究所教育機関向けにデータを提供してくださっているので、こちらを使わせていただきました。

[2] pygrib

pygribは、GRID形式のデータを読み書きするためのPythonモジュールです。 私はAmazon Linux2を使用していますが、Amazon Linux2でのインストール方法は「pygribのインストール方法:Amazon Linux2」にまとめてあります。

[3] 全球数値予報モデル(GSM)データの読み込み

[3-1] GRIB2形式のファイルをオープン

GSMの日本域データは、地上データと気圧面データ(高層のデータ)とに分かれています。 まずは、地上データをダウンロードし、開きます。

# coding: utf-8

import os
import subprocess
import pygrib

# 2020/08/01 15:00(UTC 06:00)の地上データをダウンロードする
cwd = os.getcwd()
url_surf = 'http://database.rish.kyoto-u.ac.jp/arch/jmadata/data/gpv/original/2020/08/01/Z__C_RJTD_20200801060000_GSM_GPV_Rjp_Lsurf_FD0000-0312_grib2.bin'
subprocess.run(['curl', '-O', url_surf], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, cwd=cwd)

## GRIB2ファイルを読み込む
file_surf = os.path.join(cwd, os.path.basename(url_surf))
grbs = pygrib.open(file_surf)

[3-2] 中身を表示する

# GRIB2ファイルの中身を表示する
for grb in grbs:
    print(grb)

for文でデータを取り出しprint文で表示すると、下記の結果が得られます。

1:Pressure reduced to MSL:Pa (instant):regular_ll:meanSea:level 0:fcst time 0 hrs:from 202008010600
2:Surface pressure:Pa (instant):regular_ll:surface:level 0:fcst time 0 hrs:from 202008010600
3:10 metre U wind component:m s**-1 (instant):regular_ll:heightAboveGround:level 10 m:fcst time 0 hrs:from 202008010600
4:10 metre V wind component:m s**-1 (instant):regular_ll:heightAboveGround:level 10 m:fcst time 0 hrs:from 202008010600

...(中略)...

1015:High cloud cover:% (instant):regular_ll:surface:level 0:fcst time 84 hrs:from 202008010600
1016:Total cloud cover:% (instant):regular_ll:surface:level 0:fcst time 84 hrs:from 202008010600
1017:Total precipitation:kg m-2 (accum):regular_ll:surface:level 0:fcst time 0-84 hrs (accum):from 202008010600
1018:Downward short-wave radiation flux:W m**-2 (avg):regular_ll:surface:level 0:fcst time 83-84 hrs (avg):from 202008010600

「level」は高さ(主に気圧面データで使う)を示し「fcst time」は初期時刻から何時間後のデータであるかを示しています。

GSM日本域の地上データは初期時刻(この場合は15時)から、1時間ごとに84時間後まで予測データを含んでいます。気圧面データは3時間ごとです。

[3-3] 指定した観測データを取り出す(地上データ)

selectメソッドで取り出します。parameterNameに観測データの名称を指定します。

# 指定した観測データを取り出す
prmsl = grbs.select(parameterName='Pressure reduced to MSL')
sp    = grbs.select(parameterName='Pressure')
uwind = grbs.select(parameterName='u-component of wind')
vwind = grbs.select(parameterName='v-component of wind')
temp  = grbs.select(parameterName='Temperature')
rh    = grbs.select(parameterName='Relative humidity')
lcc   = grbs.select(parameterName='Low cloud cover')
mcc   = grbs.select(parameterName='Medium cloud cover')
hcc   = grbs.select(parameterName='High cloud cover')
tcc   = grbs.select(parameterName='Total cloud cover')
tp    = grbs.select(parameterName='Total precipitation')
dswrf = grbs.select(parameterName='Downward short-wave radiation flux')

戻り値はリスト形式で、初期時刻から84時間後のデータまでが含まれます。 nameやshortNameでも指定可能ですが、'Total cloud cover'と'Total precipitation'のname, shortNameがunknownのため、parameterNameで指定しています。

[3-4] 指定した予報時刻のデータを取り出す(地上データ)

selectメソッドで取り出します。初期時刻から何時間後のデータを取り出すのかをforecastTimeに整数値で指定します。

# 初期時刻から12時間後のデータを取り出す
fc12 = grbs.select(forecastTime=12)

[3-5] 観測値を取り出す

指定した観測データの数値を取り出したい場合は、dataメソッドを使います。 戻り値として、観測値, 緯度, 経度が返ってきます。

# 観測値を取得する
prmsl_fc0 = grbs.select(parameterName='Pressure reduced to MSL', forecastTime=0)[0]
values, lats, lons = prmsl_fc0.data()
print(values)
# [[ 99642.71240234  99664.58740234  99680.21240234 ... 101829.43115234
#   101820.05615234 101809.89990234]
#  [ 99645.05615234  99666.93115234  99685.68115234 ... 101840.36865234
#   101830.99365234 101820.05615234]
#  [ 99660.68115234  99677.08740234  99695.83740234 ... 101852.08740234
#   101842.71240234 101830.99365234]
#  ...(以下省略)...

取り出し元のデータは、特定時刻の特定の観測データである必要があります。

[3-6] 指定した範囲(緯度, 経度)のデータを取り出す

dataメソッドに緯度, 経度の範囲を指定します。 緯度, 経度を指定しない場合は、全領域のデータが返されます。

# 北緯34度から36度、東経135度から140度のデータを取り出す
prmsl_fc0 = grbs.select(parameterName='Pressure reduced to MSL', forecastTime=0)[0]
values, lats, lons = prmsl_fc0.data(lat1=34, lat2=36, lon1=135, lon2=140)
print(values)
#[[101209.11865234 101213.80615234 101219.27490234 101216.93115234
#  101197.39990234 101138.02490234 101043.49365234 100913.80615234
#  100827.86865234 100809.11865234 100765.36865234 100755.21240234
#  100780.21240234 100797.39990234 100867.71240234 100953.64990234
#  101014.58740234 101058.33740234 101093.49365234 101123.96240234
#  101152.08740234]
#  ...(以下省略)...
print(lats)
# [[36.  36.  36.  36.  36.  36.  36.  36.  36.  36.  36.  36.  36.  36.
#   36.  36.  36.  36.  36.  36.  36. ]
#  [35.8 35.8 35.8 35.8 35.8 35.8 35.8 35.8 35.8 35.8 35.8 35.8 35.8 35.8
#   35.8 35.8 35.8 35.8 35.8 35.8 35.8]
#  ...(以下省略)...
print(lons)
# [[135.   135.25 135.5  135.75 136.   136.25 136.5  136.75 137.   137.25
#   137.5  137.75 138.   138.25 138.5  138.75 139.   139.25 139.5  139.75
#   140.  ]
#  ...(以下省略)...

全データ(grbs)から取り出せればよかったのですが、それは出来ないようです。

[3-7] 気圧面データを開き、中身を表示する

今度は、気圧面データを開き、中身を表示してみます。

# 2020/08/01 15:00(UTC 06:00)の気圧面データをダウンロードする
cwd = os.getcwd()
url_pall = 'http://database.rish.kyoto-u.ac.jp/arch/jmadata/data/gpv/original/2020/08/01/Z__C_RJTD_20200801060000_GSM_GPV_Rjp_L-pall_FD0000-0312_grib2.bin'
subprocess.run(['curl', '-O', url_pall], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, cwd=cwd)

## GRIB2ファイルを読み込む
file_pall = os.path.join(cwd, os.path.basename(url_pall))
grbs = pygrib.open(file_pall)

# GRIB2ファイルの中身を表示する
for grb in grbs:
    print(grb)

for文でデータを取り出しprint文で表示すると、下記の結果が得られます。

1:Geopotential Height:gpm (instant):regular_ll:isobaricInhPa:level 100000.0 Pa:fcst time 0 hrs:from 202008010600
2:U component of wind:m s**-1 (instant):regular_ll:isobaricInhPa:level 100000.0 Pa:fcst time 0 hrs:from 202008010600
3:V component of wind:m s**-1 (instant):regular_ll:isobaricInhPa:level 100000.0 Pa:fcst time 0 hrs:from 202008010600
4:Temperature:K (instant):regular_ll:isobaricInhPa:level 100000.0 Pa:fcst time 0 hrs:from 202008010600
5:Vertical velocity:Pa s**-1 (instant):regular_ll:isobaricInhPa:level 100000.0 Pa:fcst time 0 hrs:from 202008010600
6:Relative humidity:% (instant):regular_ll:isobaricInhPa:level 100000.0 Pa:fcst time 0 hrs:from 202008010600
...(以下省略)...

気圧面で扱えるのは、上記の6観測データです。 parameterNameを用いた取り出し方法は次の通りです。

# 指定した観測データを取り出す
gh    = grbs.select(parameterName='Geopotential height')
uwind = grbs.select(parameterName='u-component of wind')
vwind = grbs.select(parameterName='v-component of wind')
temp  = grbs.select(parameterName='Temperature')
vv    = grbs.select(parameterName='Vertical velocity (pressure)')
rh    = grbs.select(parameterName='Relative humidity')

[3-8] 指定気圧面のデータを取り出す(気圧面データ)

気圧面データは、指定気圧面と呼ばれる同じ気圧の平面上に格子点を持っています。1000hPa面, 925hPa面など。 selectメソッドでlevelに気圧面を指定します。

# 指定した気圧面のデータを取り出す
data_850hPa = grbs.select(level=850)
data_700hPa = grbs.select(level=700)
data_500hPa = grbs.select(level=500)

[3-9] 取り出したデータから緯度, 経度を取得する

dataメソッドでも取得可能ですが緯度, 経度のみを取得したい場合はlatlonsメソッドを使います。

# 緯度,経度を取得する。
rh_500hPa = grbs.select(parameterName='Relative humidity', level=500, forecastTime=0)[0]
lats, lons = rh_500hPa.latlons()
print(lats)
# [50.  50.  50.  ... 50.  50.  50. ]
#  [49.8 49.8 49.8 ... 49.8 49.8 49.8]
#  [49.6 49.6 49.6 ... 49.6 49.6 49.6]
#  ...
#  [20.4 20.4 20.4 ... 20.4 20.4 20.4]
#  [20.2 20.2 20.2 ... 20.2 20.2 20.2]
#  [20.  20.  20.  ... 20.  20.  20. ]]
print(lons)
# [[120.   120.25 120.5  ... 149.5  149.75 150.  ]
#  [120.   120.25 120.5  ... 149.5  149.75 150.  ]
#  [120.   120.25 120.5  ... 149.5  149.75 150.  ]
#  ...
#  [120.   120.25 120.5  ... 149.5  149.75 150.  ]
#  [120.   120.25 120.5  ... 149.5  149.75 150.  ]
#  [120.   120.25 120.5  ... 149.5  149.75 150.  ]]

[3-9] GRIB2ファイルを閉じる

closeメソッドで閉じます。

# GRIB2ファイルを閉じる
grbs.close()

終わりに

最初の方は取っ付きづらく感じますが、慣れてしまえば難しいことはそれほどありませんでした。

注意した方が良いのは、ファイルサイズが大きいことです。 GSM日本域データは1ファイルのサイズが地上データで25MB, 気圧面データで70MBと非常に大きいです。6時間ごとに予測が更新されるため、1日に4ファイルあります。数年分のデータなどを扱う場合には、一定以上のストレージ容量が必要です。

また、データの読み出しに結構時間がかかる点も注意が必要です。

参考文献

pygribのインストール方法:Amazon Linux2

f:id:predora005:20200921203743p:plain
<pygribのインストール方法:Amazon Linux2>*1

※ 2020/06/09にQrunchで書いた記事を移行しました。

Amazon Linux2で、pygribのインストールに、かなり手間取りました。 自分や他の方が、再び同じ所で躓かないように、備忘録として解決法をまとめました。

何が起きるのか

pygribをpipでインストールしようとするとエラーが表示されます。

sudo pip3 install numpy
sudo pip3 install pygrib
# ModuleNotFoundError: No module named 'pyproj'

pyprojをインストールしてリトライすると、こうなります。

sudo pip3 install pyproj
sudo pip3 install pygrib
# pygrib.c:614:10: 致命的エラー: grib_api.h: No such file or directory
#      #include "grib_api.h"
#               ^~~~~~~~~~~~

"grib_api.h"が無い問題が解決できませんでした。 試行錯誤して"grib_api.h"は入っても、結局pygribに失敗しました。 最終的には以下の手順で無事インストールできたわけですが、随分と時間を要してしまいました。

色々インストールすることになった

インストールしたかったのはpygribだけでした。しかし、最終的に以下のモノをインストールするに至りました。

  • pygrib
  • pyproj, numpy (pygribで使用しているため)
  • setuptools (アップグレード。pygribインストール時にエラーが出るため)
  • ecCodes (pygribで使用しているため)
  • gfortran (ecCodesインストールのため)
  • CMake (ecCodesインストールのため)
  • OpenSSL (CMakeで使用しているため)

そもそもは、気象データの読み込みがしたかったのです。 気象データがGRIB2というフォーマットであり、GRIB2ファイル読み込みのためにpygribを使おうとしました。

[1] CMake3のインストール方法

[1-1] OpenSSLをインストールする

CMakeの依存関係にOpenSSLが含まれているため、事前にインストールします。

sudo yum install openssl openssl-devel

ちなみに、OpenSSLをインストールせずCMakeをインストールしようとすると、以下のエラーが表示されます。

# Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system variable OPENSSL_ROOT_DIR (missing: OPENSSL_CRYPTO_LIBRARY OPENSSL_INCLUDE_DIR) 

[1-2] CMakeをインストールする

公式の手順。 最新版はココにあります。wgetcurlコマンドでダウンロードします。 また、configure実行時にインストール先を指定できます。 指定する場合はprefixに指定します。

wget https://github.com/Kitware/CMake/releases/download/v3.17.3/cmake-3.17.3.tar.gz
tar xzf cmake-3.17.3.tar.gz
cd cmake-3.17.3/
./configure --prefix=/usr/local/cmake/3.17.3/
make
sudo make install

インストール完了後、CMakeが使えるようにパスを通しておきます。 export "PATH=$PATH:/usr/local/cmake/3.17.3/bin/"でも良かったのですが、/usr/local/bin/にシンボリックリンクを作成しました。

sudo ln -s /usr/local/cmake/3.17.3/bin/cmake /usr/local/bin/cmake
sudo ln -s /usr/local/cmake/3.17.3/bin/cpack /usr/local/bin/cpack 
sudo ln -s /usr/local/cmake/3.17.3/bin/ctest /usr/local/bin/ctest

[2] ecCodesのインストール方法

かつては、GRIB APIが使われていましたが、ecCodesに移行されています。 2018年12月現在、GRIB APIはメンテナンスされなくなったと公式にも書いてあります。

[2-1] gfortranのインストール

ecCodesインストール前にgfortranをインストールします。

sudo yum install gcc-gfortran  

インストールしないと、ecCodesをmakeする際に以下のエラーが発生します。 ecCodesインストール時にfortranを使用しない選択肢もありそうでしたが、面倒なのでインストールしました。

# CMake Error: your Fortran compiler: "CMAKE_Fortran_COMPILER-NOTFOUND" was not found.   Please set CMAKE_Fortran_COMPILER to a valid compiler path or name.  

[2-2] ecCodesのインストール

公式の手順。 最新版はココからダウンロードします。 -DCMAKE_INSTALL_PREFIXにインストール先を指定することが可能です。

wget https://confluence.ecmwf.int/download/attachments/45757960/eccodes-2.17.0-Source.tar.gz
tar xzf eccodes-2.17.0-Source.tar.gz
mkdir build ; cd build
cmake -DCMAKE_INSTALL_PREFIX=/usr/local/eccodes/2.17.0 ../eccodes-2.17.0-Source
make
ctest
sudo make install

インストール終了後に、python用のモジュールをインストールします。

sudo pip3 install eccodes-python

[3] pygribのインストール方法

[3-1] setuptoolsのアップグレード

sudo pip3 install --upgrade setuptools

[3-2] numpy, pyprojのインストール

sudo pip3 install numpy pyproj

[3-3] pygribのインストール

公式のソースと手順

pipでpygribをインストールすることも出来ます。 しかし、私の環境ではエラーとなり解決できませんでした。ネットで調べてみてもインストールできないケースは多いようです。 そのため、githubからソースをダウンロードしインストールしました。

git clone https://github.com/jswhit/pygrib
cd pygrib
cp -p setup.cfg.template setup.cfg

"setup.cfg"のgrib_api_dirを変更し、ecCodesのインストール先を指定します。 インストール先は環境によって異なります。私の環境では以下の通りです。

grib_api_dir = /usr/local/eccodes/2.17.0/

.gitディレクトリを削除したのち圧縮し、pipでインストールします。

sudo rm -rf .git
zip -r ../pygrib.zip *
cd ../
sudo pip3 install pygrib.zip

終わりに

最近はインストールも便利になって忘れていましたが、コマンド一つでインストールできることのありがたみを感じました。

参考文献

以下の記事を参考にさせていただきました。

*1:Clker-Free-Vector-ImagesによるPixabayからの画像

【機械学習】matplotlibの日本語文字化け対策(Amazon Linux2)

f:id:predora005:20200921201935p:plain

※ 2020/05/20にQrunchで書いた記事を移行しました。

matplotlibの文字化け対策は多くの情報がありますが、Amazon Linux2向けの情報はありませんでした。他のOSと基本的な対策方針は同様です。日本語フォントをインストールし、キャッシュを削除します。

対策手順

[1] 日本語フォントのインストール

IPAexフォントの一つである'IPAGothic'をインストールします。

sudo yum -y install ipa-gothic-fonts

[2] ソースコードに追記

キャッシュの削除、及び、日本語フォントを指定するコードを追加します。

import matplotlib as mpl
import matplotlib.pyplot as plt

mpl.font_manager._rebuild()    # キャッシュの削除
plt.rcParams['font.family'] = 'IPAGothic'    # 日本語フォントを指定

[3] 設定ファイルの変更

matplotlibの設定ファイルを変更します。 この方法で上手くいくようなら、[2]ソースコードの追記は不要です。

まずは以下のソースコードで、設定ファイルの場所を把握します。

import matplotlib as mpl
print(mpl.matplotlib_fname())
# /home/ec2-user/.local/lib/python3.7/site-packages/matplotlib/mpl-data/matplotlibrc

設定ファイルに以下の行を追加します。

font.family  : IPAGothic

終わりに

他OS向けの対策をしても若干手順が異なり上手くいかず、思いのほか時間がかかりました。

ソースコードに追記する方法は、下記記事を参考にさせていただきました。

SageMaker上のmatplotlibを日本語表記にする | Developers.IO

備忘録

matplotlibの情報表示

import matplotlib as mpl

print(mpl.get_configdir())       # 設定ディレクトリの表示
print(mpl.get_cachedir())        # キャッシュディレクトリの表示
print(mpl.matplotlib_fname())    # 設定ファイルの表示
print(mpl.font_manager.findSystemFonts())    # フォントリストの表示
print(mpl.rcParams['font.family'])           # 使用中フォントの表示

IPAGothic以外のIPAexフォントのインストール

sudo yum -y install ipa-gothic-fonts ipa-mincho-fonts ipa-pgothic-fonts ipa-pmincho-fonts

【機械学習】xgboostでグリッドサーチ(GridSearchCV)

f:id:predora005:20200921203514p:plain
<xgboostでグリッドサーチ(GridSearchCV)>*1

※ 2020/04/09にQrunchで書いた記事を移行しました。

scikit-learnのGridSearchCVを利用して、グリッドサーチを行いました。 xgboostにはscikit-learnのWrapperが用意されているため、scikit-learnを使ったことがある人であれば、違和感なく使うことが出来ます。

使い方

データの読み込み等を除いたソースは以下の通りです。

import xgboost as xgb
from sklearn.model_selection import StratifiedKFold, GridSearchCV

# サーチするパラメータをセット
params = {'eta': [0.01, 0.1, 1.0], 'gamma': [0, 0.1], 
                  'n_estimators': [10, 100], 'max_depth':[2, 4], 
                  'min_child_weigh': [1, 2], 'nthread': [2] }

# クラス分類用のモデルを作成
model = xgb.XGBClassifier()

# StratifiedKFoldでグリッドサーチ
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=1)
clf = GridSearchCV(estimator=model, param_grid=params, 
                    cv=skf, scoring="accuracy", n_jobs=1, verbose=3)
clf.fit(train_x, train_y)

GridSearchCV()がグリッドサーチのオブジェクトを作成している部分でclf.fit()で実行します。 各パラメータ(引数)の意味は次の通りです。

パラメータ(引数) 内容
estimator モデル
param_griddict サーチするパラメータ
cv クロスバリデーションの分割方法(※1)
scoring 評価指標("accuracy", "neg_mean_squared_error"等) (※2)
n_jobs 並行して実行するジョブの数。
verbose 冗長性(サーチ中のメッセージ表示の種類) (※3)

cv (※1)

設定できるパラメータは次の通りです。 - None: 自動で5 foldのクロスバリデーションになる - 整数値:指定した分割数のKFoldになる(分類の場合はStratified KFold) - CV splitter (KFoldオブジェクト等) - インデックスのリスト

scoring (※2)

公式に一覧が載っています。

3.3. Metrics and scoring: quantifying the quality of predictions — scikit-learn 0.22.2 documentation

verbose (※3)

公式に正確な情報はありませんが、 3はテスト毎にパラメータ・スコア・経過時間を表示、 2はテスト毎にパラメータ・経過時間を表示、 1はサーチの開始と終了、 0は表示しない。

ソースコード

データはscikit-learnのdatasetより、load_breast_cancerを使用しました。

[1] データ読み込みと分割

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

# 乳がんの診断結果データ
cancer = load_breast_cancer()
cancer_data = pd.DataFrame(cancer.data, columns=cancer.feature_names)
cancer_target = pd.Series(cancer.target)

# 80%を学習用、20%をテスト用に使用する。
train_x, test_x, train_y, test_y = \
        train_test_split(cancer_data, cancer_target, test_size=0.2, shuffle=True)

[2] グリッドサーチ

import xgboost as xgb
from sklearn.model_selection import StratifiedKFold, GridSearchCV

# サーチするパラメータをセット
params = {'eta': [0.01, 0.1, 1.0], 'gamma': [0, 0.1], 
                  'n_estimators': [10, 100], 'max_depth':[2, 4], 
                  'min_child_weigh': [1, 2], 'nthread': [2] }

# クラス分類用のモデルを作成
model = xgb.XGBClassifier()

# StratifiedKFoldでグリッドサーチ
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=1)
clf = GridSearchCV(estimator=model, param_grid=params, 
                    cv=skf, scoring="accuracy", n_jobs=1, verbose=3)
clf.fit(train_x, train_y)

[3] グリッドサーチの結果を表示

import pandas as pd

# 各パラメータのスコア・標準偏差をDataFrame化
means = clf.cv_results_['mean_test_score']
stds = clf.cv_results_['std_test_score']
params = clf.cv_results_['params']
df = pd.DataFrame(data=zip(means, stds, params), columns=['mean', 'std', 'params'])

# スコアの降順に並び替え
df = df.sort_values('std', ascending=True)
df = df.sort_values('mean', ascending=False)

# スコア・標準偏差・パラメータを表示
for index, row in df.iterrows():
    print("score: %.3f +/-%.4f, params: %r" % 
          (row['mean'], row['std']*2, row['params']))
# score: 0.963 +/-0.0431, params: {'eta': 1.0, 'gamma': 0, 'max_depth': 4, 'min_child_weigh': 1, 'n_estimators': 100, 'nthread': 2}
# score: 0.963 +/-0.0431, params: {'eta': 1.0, 'gamma': 0, 'max_depth': 4, 'min_child_weigh': 2, 'n_estimators': 100, 'nthread': 2}
# score: 0.960 +/-0.0531, params: {'eta': 0.1, 'gamma': 0, 'max_depth': 4, 'min_child_weigh': 2, 'n_estimators': 100, 'nthread': 2}
# score: 0.960 +/-0.0531, params: {'eta': 0.1, 'gamma': 0, 'max_depth': 4, 'min_child_weigh': 1, 'n_estimators': 100, 'nthread': 2}
# score: 0.956 +/-0.0501, params: {'eta': 0.1, 'gamma': 0.1, 'max_depth': 4, 'min_child_weigh': 2, 'n_estimators': 100, 'nthread': 2}
# 〜〜〜 (以下省略) 〜〜〜

[4] 最良のパラメータを取得

print("Best score: %.4f" % (clf.best_score_))
print(clf.best_params_)
# Best score: 0.9626
# {'eta': 1.0, 'gamma': 0, 'max_depth': 4, 'min_child_weigh': 1, 'n_estimators': 100, 'nthread': 2}

model = clf.best_estimator_
pred = model.predict(test_x)
score = accuracy_score(test_y, pred)
print('score:{0:.4f}'.format(score))
# Score:0.9561

参考資料

sklearn.model_selection.GridSearchCV — scikit-learn 0.22.2 documentation

*1:Darwin LaganzonによるPixabayからの画像

pandasで複数行の列を持つDataFrameを作成する方法

f:id:predora005:20200921203155j:plain
<pandasで複数行の列を持つDataFrameを作成する方法>*1

※ 2020/04/04にQrunchで書いた記事を移行しました。

列が複数行となっているDataFrameを作成する方法の覚書です。 結論は「pd.MultiIndexを使う」です。

例えば、次のようなDataFrameを作成したいとします。

#     One   Two Three
#    Four  Five   Six
# 0  1.11  2.22  3.33
# 1  4.44  5.55  6.66
# 2  7.77  8.88  9.99

MultiIndexは行にも列にも使えますが、今回は列を作るために利用しました。

MultiIndexの種類

作成の仕方は以下の4種類です。 元となるデータに応じて種類が変わります。

  • MultiIndex.from_arrays()
  • MultiIndex.from_tuples()
  • MultiIndex.from_product()
  • MultiIndex.from_frame()

MultiIndex.from_arrays()

名前の通り、array(list)から作成します。 4種類の中で一番オーソドックスな方法です。

data = [ [1.11,2.22,3.33], [4.44,5.55,6.66], [7.77,8.88,9.99] ]
arrays = [ ['One','Two','Three'], ['Four','Five','Six'] ]
columns = pd.MultiIndex.from_arrays(arrays)
df = pd.DataFrame(data=data, columns=columns)
#     One   Two Three
#    Four  Five   Six
# 0  1.11  2.22  3.33
# 1  4.44  5.55  6.66
# 2  7.77  8.88  9.99

MultiIndex.from_tuples()

名前の通り、tupleから作成します。 from_arrays()とは異なり、同一tupleの要素は異なる行に配置されます。

data = [ [1.11,2.22,3.33], [4.44,5.55,6.66], [7.77,8.88,9.99] ]
tuples = [ ('One', 'Four'), ('Two', 'Five'), ('Three','Six') ]
columns = pd.MultiIndex.from_tuples(tuples)
df = pd.DataFrame(data=data, columns=columns)
#     One   Two Three
#    Four  Five   Six
# 0  1.11  2.22  3.33
# 1  4.44  5.55  6.66
# 2  7.77  8.88  9.99

MultiIndex.from_product()

from_product()は要素の全組み合わせがほしいときに使います。 array(list)に限らず、iterableな要素が指定できます。

data = [ [1.11,2.22,3.33,4.44], [5.55,6.66,7.77,8.88] ]
arrays = [ ['One','Two'], ['Three','Four'] ]
columns = pd.MultiIndex.from_product(arrays)
df = pd.DataFrame(data=data, columns=columns)
#     One         Two      
#   Three  Four Three  Four
# 0  1.11  2.22  3.33  4.44
# 1  5.55  6.66  7.77  8.88

MultiIndex.from_frame()

今回の主旨にはそぐわないですが、DataFrameからMultiIndexを作成します。

data = [ [1.11,2.22,3.33], [4.44,5.55,6.66], [7.77,8.88,9.99] ]
arrays = [ ['One','Two','Three'], ['Four','Five','Six'] ]
columns = pd.MultiIndex.from_arrays(arrays)
df = pd.DataFrame(data=data, columns=columns)
#     One   Two Three
#    Four  Five   Six
# 0  1.11  2.22  3.33
# 1  4.44  5.55  6.66
# 2  7.77  8.88  9.99

index = pd.MultiIndex.from_frame(df)
# MultiIndex([(1.11, 2.22, 3.33),
#             (4.44, 5.55, 6.66),
#             (7.77, 8.88, 9.99)],
#            names=[('One', 'Four'), ('Two', 'Five'), ('Three', 'Six')])

自動でMultiIndexになる場合

DataFrameを作成する元になるデータがndarray、かつ、列がarray(list)の場合には、MultiIndexを明示的に使用せずとも自動でMultiIndex変換してくれます。

data = [ [1.11,2.22,3.33], [4.44,5.55,6.66], [7.77,8.88,9.99] ]
data = np.array(data)
arrays = [ ['One','Two','Three'], ['Four','Five','Six'] ]
df = pd.DataFrame(data=data, columns=arrays)
#     One   Two Three
#    Four  Five   Six
# 0  1.11  2.22  3.33
# 1  4.44  5.55  6.66
# 2  7.77  8.88  9.99

tupleは自動で変換してくれず、tupleがそのまま列になります。

data = [ [1.11,2.22,3.33], [4.44,5.55,6.66], [7.77,8.88,9.99] ]
data = np.array(data)
tuples = [ ('One', 'Four'), ('Two', 'Five'), ('Three','Six') ]
df = pd.DataFrame(data=data, columns=tuples)
#    (One, Four)  (Two, Five)  (Three, Six)
# 0         1.11         2.22          3.33
# 1         4.44         5.55          6.66
# 2         7.77         8.88          9.99

参考資料

MultiIndex / advanced indexing — pandas 1.0.3 documentation

*1:Mihai SurduによるPixabayからの画像