Couseraの機械学習講座を受講した

オンライン教育サービスであるCouseraで、機械学習の基礎的な学習講座として有名なMachine Learning講座を受講した。

前々から気になりつつ、「自分がついていけるレベルだろうか」「英語わかんないしな」(講義には日本語訳がついているけどテストや課題は英語)、「Pythonじゃないし」(プログラミング課題はOctaveで提出する)となかなか踏み出せずにいた。
在宅勤務になり家にいる時間が増えたことも後押しになって、受講することができたので、感想等記録しておく。

扱われる内容

下記のキーワードに関連する内容について、11週にわたり講義が行われる。

Week 1 機械学習の概要
線形単回帰、最小二乗法、最急降下法

Week 2 線形重回帰
特徴量のスケーリング、正則化

Week 3 分類 ロジスティック回帰
過学習、正則化、One-vs-All

Week 4・5 ニューラルネットワーク
隠れ層、論理ゲート、backpropagation、gradient checking、ランダム初期化

Week 6 機械学習の評価
交差検証、high bias、high variance、学習曲線、適合率、再現率、F値

Week 7 サポートベクタマシン(SVM)
マージン、決定境界、カーネル法

Week 8 クラスタリング・主成分分析(PCA)
K平均法、局所最適、エルボー法
次元削減、射影誤差、共分散行列

Week 9 異常検知・レコメンドシステム
正規分布、多変量正規分布
協調フィルタリング、類似度

Week 10 大規模データ
確率的勾配降下法、ミニバッチ勾配降下法、逐次学習、並列化

Week 11 Photo OCR
パイプライン、スライディングウインドウ、データ合成、ceiling analysis

学習の進め方

ノート
こんな感じでノートにメモしていった

各週、動画による講義 + テスト + プログラミング課題から構成されている。
私は講義を平日にざっと見て(わからないところがあってもあまり気にせず最後までいったん見る)、休日にもう1回見直しながら話の流れをノートにメモしていった。平日見たときは「何言ってるか全然わからん」と思った箇所も、2回目に休日に見た時は「あれ、なんで理解できなかったんだろう」となることも多かった(何回見直してもやっぱりわからん、となる箇所ももちろんあった)。
講師のAndrew先生の説明がわかりやすかったのはもちろんだけど、ノートにまとめようとする過程で理解が曖昧な箇所をつぶし、流れをしっかり捉えられるのが自分にはよかったのかなと思う。

かかった時間

ネット上の体験談だと1ヶ月未満で完了したという方も割と見かけたけど(みんな天才なのかな?と思った)、私は設定されているのと同じペースで進めていったので、約2ヶ月かかった。週により内容の重さの差が大きくて、3時間で終わった週もあれば15時間以上かかった週もあった。

感想

講座全体を通じて感じたことを記録しておく。

  • 勉強を続けて納得感を高めていきたいと思った

とても勉強になったので受講してよかったなと思う。
説明が非常にわかりやすいので、そのアルゴリズムの意図や、数式の意味するところの大枠について理解することができた。全体的に納得しながら進めることができたのだけど、「この数式がなぜこうなるかは、ここでは説明しない」という説明で次に進む部分もしばしばあったので、数式の導出などは少しもやもやが残った。また、課題は一から自分でコードを書くのではなく、重要な数式部分のみ自分で書くという形式だった。そのため、ふんわりとした理解になっている自覚がある。自分でPythonで書き直してみるとか、数式の導出をしてみるとかするべきなのだろう。勉強を続けていって、理解を深めていきたいと思う。

  • 英語をもうちょっと読めるようになると色々楽だなと思った

講義には有志の方がつけてくれた訳文がついているけど、テストや課題は英語で書かれている。最初の数週は頑張って単語を調べながら読んでいたけど、途中から面倒になってDeepLに突っ込んで訳文を読むようになった。俄然課題の進みが速くなって、自分の英語力の低さを改めて実感した。DeepLは訳が自然で、訳文だと意味が不明で結局原文を読むみたいなことはほとんど発生しなかった(訳文を読んで「解くのに必要な前提条件が足りない…」となって、原文見たら訳されていない箇所があった、ということは数度あった)。

  • ペース配分を自分でしなくて済むのって楽だなと思った
課題を提出すると、何割終わったか示してくれる

オンライン講座では当たり前なのかもしれないけど、見終わった動画にはチェックマークがついたり、プログラミング課題も途中提出の度にどこまで終わったか明確に表してくれる。「今週中にあと3個動画見て課題を解くから、x時間くらいで終わる」とわかると、残りの時間は別の学習に充てようなど見通しが立てやすい。ペース配分を自分でしなくて済むこと、どこまで進んでいるか示してくれることがこんなに楽なのかというのは意外な発見だった。

今後機械学習の勉強をしていく上で、非常に役に立つ講座だった。継続して学習していきたい。

データ分析者がCS経験から得たこと

※ ここでのCSはカスタマーサービス(コンピュータサイエンスではない)

昨年、分析を中心としたディレクター職から、CS職に異動して半年ほど過ごした。
この半年間の経験から何を得て、意識や行動がどう変わったのか、再びディレクターに戻り数ヶ月経った現在までに感じた差分をふりかえってみる。

  • ユーザーの姿が以前より立体的になった
    CS業務の中心である問合せ対応を行うなかで、自分の中のユーザー像が少しずつ具体的になっていった。以前はデータから「こういうお客様がいるのかな」と思ったり、周りから「こういう傾向のユーザーが多いよ」と聞いて、漠然とユーザーの姿を想像していた。それが、お客様からの問合せを千数百人分読み、1件ずつ自分の手で回答文を作成することで、「〜を目的として操作する人には〜でつまずく人が多く、それはこの部分が理解しづらいことが原因かもしれない」などの仮説が自分の中に蓄積されていった。
    データを見るとき全体的な視点になりがちだったけど、1件のデータの裏にいる1人のユーザーを実感を伴った形で想像できるようになったことで、データから仮説を考えやすくなったと感じている。1

  • 「分析が役に立てる」と認識する範囲が広がった
    CS業務を毎日していると、「こういう傾向の問合せが多いから改善したい」という部分(明らかな不具合であれば即エンジニア等に対応してもらうけど、そうではなく、より使いやすくなるような改善点)が見えてくる。そう感じる部分は同じサービスに携わるCS内では大抵共通認識となっていたけど、他職種の人も同様に認識しているかというと必ずしもそうではない場合もあった。
    その内の1つについて、事象の起こっている件数、それによる損失額、具体な原因と改善案を問合せ対応の合間にまとめ、CS外に提案したところ、実際に改善に至ることができた。
    以前は、当たり前なことを可視化しても「そうだね」「知ってる」となるだけで、さほど意味がないのではと思っていた。でも、当たり前の範囲は人により差があり、各自が認識しているサービスの姿は思っている以上に異なっていることがわかってきた。また、当たり前であってもその課題の大きさや姿は具体的に認識されていない場合もあることもわかった。
    こういった点について、分析者が媒介になる(課題を適切に可視化して共有することで、解決につなげる)ことも分析が役に立てる範囲なんだなと認識が広がった。
    媒介となるためには、分析者が課題の存在を認識している必要がある。CSにいればサービスへの反応を自然と知ることができるけど、現在は離れているし半年で認識できた範囲はわずかだと思うので、これからもCSのメンバーに積極的に話を聞かせてもらいに行こうと思っている。

  • 分析を通じて貢献するぞ、という意識が強くなった
    CS在籍中、エンジニアやデザイナーなど色々な人が折にふれ、気にかけて声をかけてくれた。また、CSの同僚も私が分析をやりたい(CSとして今後やっていきたいわけではない)ことを知った上で、色々質問しても、どの部分を見てどう考えた結果その判断に至ったのか、サービスがそうなっている経緯など納得するまで教えてくれた。
    ディレクターに戻り、それらに報いたいという気持ちとともに、分析面でしっかり貢献できないと(分析専門でない部署で分析中心にやっている分余計に)自分がここに存在する意味がなくなってしまうなと思うようになった。
    存在意義を示すためには、分析により改善につながる部分を見定めること、分析結果を示すだけでなくそれを施策に落として提案することが必要だと思っている(そもそもの分析能力も当然まだまだ精進が必要だけど)。色々スマートにできなくて転げながらやっている毎日だけど、分析を業務としてやれることが嬉しいから、かっこわるくてもやっていく。


  1. 利用中に一度も問合せをされないお客様も多いので、問合せだけからユーザーの姿を思い込みすぎるのは危険である、という点も留意する必要はあると思っている 

暖かいルートを検索するWebアプリを作ろうとした話_うまくいかなかった部分

こちらでふりかえりを書いたWebアプリについて、デプロイでうまくいかなかった部分を記録しておく。

概要

ローカルでは一応意図した形で動いてくれていたDjangoをHerokuにデプロイしたところ、エラーが出てうまく動かなかった。そして、そのエラーを解決することができなかった。
自分の理解では、利用しているライブラリが参照しているファイルをうまく参照させることができなかったのでエラーとなったと認識している。
コードはここにいったん置いた。

詳細

1- ログの確認

Herokuでデプロイして、該当サイトにアクセスしたところ「Application error」という表示になっていた。

その下に表示されていた文に従い、ログを確認した。

$ heroku logs --tail

(前略)
2019-12-30T05:46:04.064263+00:00 app[web.1]: import osmnx as ox
2019-12-30T05:46:04.064272+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/osmnx/__init__.py", line 9, in
2019-12-30T05:46:04.064274+00:00 app[web.1]: from .core import *
2019-12-30T05:46:04.064276+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/osmnx/core.py", line 10, in
2019-12-30T05:46:04.064278+00:00 app[web.1]: import geopandas as gpd
2019-12-30T05:46:04.064288+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/geopandas/__init__.py", line 1, in
2019-12-30T05:46:04.064290+00:00 app[web.1]: from geopandas.geoseries import GeoSeries # noqa
2019-12-30T05:46:04.064292+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/geopandas/geoseries.py", line 15, in
2019-12-30T05:46:04.064294+00:00 app[web.1]: from geopandas.base import GeoPandasBase, _delegate_property
2019-12-30T05:46:04.064296+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/geopandas/base.py", line 16, in
2019-12-30T05:46:04.064298+00:00 app[web.1]: from rtree.core import RTreeError
2019-12-30T05:46:04.064300+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/rtree/__init__.py", line 1, in
2019-12-30T05:46:04.064302+00:00 app[web.1]: from .index import Rtree
2019-12-30T05:46:04.064310+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/rtree/index.py", line 5, in
2019-12-30T05:46:04.064312+00:00 app[web.1]: from . import core
2019-12-30T05:46:04.064314+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/rtree/core.py", line 125, in
2019-12-30T05:46:04.064316+00:00 app[web.1]: raise OSError("Could not find libspatialindex_c library file")

計算して求めたルートを地図にプロットするのに、osmnxというライブラリを利用している。そして、osmnxではRtreeというライブラリが使用されている。Rtreeのコードの中で、libspatialindex_c library fileが見つからなかったことによりエラーになっていると理解した。

2- ローカルではエラーが起きなかったのは何が違うのか確認する

上記のエラー文にFile "/app/.heroku/python/lib/python3.7/site-packages/rtree/core.py", line 125 とあり、.venv/lib/python3.7/site-packages/rtree/core.pyの125行目付近を確認した。
/app/.heroku/~というのがどのように確認できるかわからなかったのでvenvでローカルでインストールしたものと同じだろうと考えて上記を確認した)

elif os.name == 'posix':
    if 'SPATIALINDEX_C_LIBRARY' in os.environ:
        lib_name = os.environ['SPATIALINDEX_C_LIBRARY']
    else:
        lib_name = find_library('spatialindex_c')

    if lib_name is None:
        raise OSError("Could not find libspatialindex_c library file")

    rt = ctypes.CDLL(lib_name)
else:
    raise RTreeError('Unsupported OS "%s"' % os.name)

lib_nameが定義できていなかった(環境変数の中にSPATIALINDEX_C_LIBRARYがなく、またspatialindex_cというライブラリも見つけられなかった)ためにエラーとなっていたことがわかった。

ターミナルでPythonを立ち上げて、ローカル環境だとどうなっているか確認してみた。

>>> import os
>>> os.name
'posix'
>>> os.environ
environ({'TERM_PROGRAM': 'Apple_Terminal',(後略)

>>> from ctypes.util import find_library
>>> find_library('spatialindex_c')
'/usr/local/lib/libspatialindex_c.dylib'

os.environでSPATIALINDEX_C_LIBRARYがなかったことから、ローカル環境ではlib_name = find_library('spatialindex_c')の方が実行されたのだろうこと、またspatialindex_cはローカル環境だと/usr/local/lib/libspatialindex_c.dylibにあるのだということがわかった。

検索してみると、ローカル環境で同じような問題にぶつかっている人がいた。Homebrewでspatialindexをインストールしたら解決したとされており、$ brew listで確認してみるとインストール済みだった。そのため、ローカルでは問題が起きなかったのだろうと思った。

3- どうしたら本番環境でも参照できるようになるか考える

ローカル環境では該当ファイルが存在していたため参照できたが、本番環境には該当のファイルがないためエラーになる。
pipでインストールできるファイルならrequirements.txtに書いておけるけど、そうではなさそうだ。それなら本番環境にもそのファイルを置いて、参照できればとりあえずは解決できるのではと考えた。

/usr/local/lib/libspatialindex_c.dylibをコピーして、本番環境のプロジェクト直下にlibディレクトリを作り、置いてみた。

これが正しい行為なのかわからないけど、環境変数にパスを設定してみた。
$ heroku configで、登録できていることが確認できた。

(前略)
SPATIALINDEX_C_LIBRARY: lib/libspatialindex_c.dylib

この修正をしても同様のエラー画面だったため、再度、$ heroku logs --tailでログを確認した。

(前略)
2019-12-30T06:38:08.950338+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/rtree/core.py", line 127, in
2019-12-30T06:38:08.950339+00:00 app[web.1]: rt = ctypes.CDLL(lib_name)
2019-12-30T06:38:08.950340+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/ctypes/__init__.py", line 364, in __init__
2019-12-30T06:38:08.950342+00:00 app[web.1]: self._handle = _dlopen(self._name, mode)
2019-12-30T06:38:08.950344+00:00 app[web.1]: OSError: lib/libspatialindex_c.dylib: invalid ELF header

表示が前回と変わっている。
最初のエラーログで出ていたraise OSError("Could not find libspatialindex_c library file")はなく、次の行のrt = ctypes.CDLL(lib_name)が表示されているので、libspatialindex_cを見つけること自体はできたと考えてよいのだろうか。

エラーの最後の行で、invalid ELF headerと表示されている。検索すると、違うOSでのビルドだから読み込めない場合に表示されるという記載があった。

「2- ローカルではエラーが起きなかったのは何が違うのか確認する」に記載した.venv/lib/python3.7/site-packages/rtree/core.pyで、もう少し上の方に以下のような記載箇所がある。

if 'SPATIALINDEX_C_LIBRARY' in os.environ:
  lib_path, lib_name = os.path.split(os.environ['SPATIALINDEX_C_LIBRARY'])
  rt = _load_library(lib_name, ctypes.cdll.LoadLibrary, (lib_path,))
else:
  rt = _load_library('spatialindex_c.dll', ctypes.cdll.LoadLibrary)
if not rt:
  raise OSError("could not find or load spatialindex_c.dll")

このspatialindex_c.dllの方が必要なのかなと思い(多分違う)、探したが見つけられなかった。

4- いったん諦める

いったん諦める。もう少し知識がついたらまた考えてみる。

暖かいルートを検索するWebアプリを作ろうとした話_作業経過

初めてWebアプリを作ろうとして、方法の検索からデプロイ(失敗した)まで色々試行錯誤したので、経過を記録しておく。

目的

そもそも作ろうと思ったのは以下のようなことが理由だった。

  • 途中まで作った日陰の計算を一般的に使えるものにしたい
    以前、道路にかかる影の割合を計算して、任意のルートの涼しさを調べようとしたことがあったので(「夏には日陰を歩きたい」という欲望を満たすために計算する)、これをローカルで実行できるだけでなく一般的に使えるようにしたいと考えた。
    考えた時点ですでに夏が過ぎていたので、涼しい道でなく暖かい道を調べられるよう、直射日光の量を計算するように変えた。

  • Webサイトの仕組みについて、雰囲気だけでもつかみたい
    「ブラウザからリクエストが来たら、なんか処理して、レスポンスが返されるんでしょ…?」という非常にふわっとした理解だったので、「なんか処理」の部分がどのように作られているのか少しでもイメージできるようになりたいという気持ちがあった。
    普段仕事をしていても、エンジニアやデザイナーが何をして、サイトの表示やアカウントの登録等ができているのか、それを実現するコードがどのようなものなのか想像ができなかった。一緒に仕事するにあたり、詳しくはわからなくても、概略をイメージできるとよいなあという気持ちがあったので、自分で作ってみることにした。

できたこと

緯度経度と日時を入れたら、暖かいルートを表示する仕組みを作った(ローカルでは動く)

できなかったこと

ライブラリがうまく扱えず、デプロイができなかった
※うまくできなかった部分の詳細については、こちらに記載した。

作業経過

1- 調べる : 1h
「Pythonでweb上で動く仕組みを作るにはどうしたら良いのかな〜」と思い、そのまま「Python Webアプリ」と検索した。
DjangoとかFlaskというのが有名で、Djangoの方が色々やれることが多いらしいとわかった。自分のやりたいことに対してFlaskでもできるかの判断がつかず(多分できた)、Djangoでやってみることにした。

2- Djangoの学習をする : 24h
最初にDjangoのチュートリアルをやった。
丁寧に手順を追ってくれていてその通りに操作をすることはできたけど、各操作が何を目的としたものなのかや、全体的なファイル構成とかがわからなかったので、下記のような感じで各ファイルのつながりをメモしながら再度なぞってみたら少し理解ができた。

この時点で実際に自分の作りたいものに着手して、よくわからなくなったら本や動画を参照する形で進めた。以下を参考にさせていただいた。
本:現場で使える-Django-の教科書《基礎編》
動画:【3日でできる】Django 入門

3- 暖かいルートを計算するにはどうしたら良いか考える : 18h
以前計算した道路にかかる影の割合(「夏には日陰を歩きたい」という欲望を満たすために計算する)をベースに、暖かいルートをどのように計算したら良いか考えた。
結果、厳密には正確ではないだろうが「距離当たりの体の受ける直射日射の量」で代替することにした。太陽から降り注ぐ日射のうち、角度のついた鉛直面の日射量を計算する方法を本やネット上の論文から調べた。また、計算に用いる道路の緯度経度をOpenStreetMapから得て、各道路の方位角と長さを求めた。
大まかには、以下のような計算を行っている。コードはこちら

4- コードを書く : 28h
日射の計算のコードを書いていたのが10hくらいで、残りはDjango関係のコードを書いていた。地図の表示や、Djangoでの画像の表示がうまくいかず、時間がかかった。
コードはとりあえずこちらに置いてある。

5- デプロイする(失敗) : 22h
最初は別サービスを使ってデプロイしようとしたがうまくいかず(色々いじっているうちになぜかpipがうまく働かなくなり、最終的にOSの再インストールに至った)、Herokuを利用して進めていった。
Herokuのアカウントを作って、チュートリアルをやった。丁寧に説明されていて、例となるコードをクローンして進める形だったので静的ファイルの取り扱い等も参考にでき、初めてでもすごくわかりやすかった。
結局、ライブラリの扱いの部分でうまくいかず、年内の完成を目指していたのでいったん諦めることにした。
※うまくできなかった部分の詳細については、こちらに記載した。

やってみてどうだったか

当初の目的に対し、どうだったかをふりかえる。

  • 途中まで作った日陰の計算を一般的に使えるものにしたい
    → 結局デプロイできなかったので、一般に使えるものにならなかった。悔しいので、またもう少し理解が深まったら、つまづいた部分を解決してデプロイまで至るようにしたい。

  • Webサイトの仕組みについて、雰囲気だけでもつかみたい
    → (Djangoの場合の)各ファイルがどのように関係して、サイトが表示されるのか(MTVモデル)がうっすらわかった。Djangoの内部でどのような処理が行われているかはわかっていないので、「フレームワークすごいな〜」という気持ちになった。Webサイトの作りについて、さわりだけ知れたかな…という感じ。

何に時間を使ったか_2019上期

統計検定を受けた時のふりかえりで「何に時間をかけているか意識をしよう」と考えてから、ちまちまと記録をしていたので、半年間の時間の使い方をふりかえってみる。
以下、自分で「学び」系の区分に入れていた時間の内訳を記載する(なので、一般に「これは学びというより趣味なのでは…」という部分も含まれる)。

⑴ データ分析関係

  • 分析手法を学ぶ 18h 7冊
    データ分析の手法や、業務として分析を進めていく方法などについて書かれている本を読んだ。読んだ中では、以下の本が一番実際の業務に当てはめながら読めて、学びが多かった。
    ビジネス活用事例で学ぶ データサイエンス入門

  • 機械学習について学ぶ 15h 2冊
    scikit-learnのライブラリを利用して実行する方法と、機械学習に使われている数学の基礎について書かれた本を途中まで読んだ。半年で15hと、お前やる気あるのかという状態なので、来期はもう少しまじめに勉強する。
    機械学習を理解するための数学のきほん
    Pythonではじめる機械学習 scikit-learnで学ぶ特徴量エンジニアリングと機械学習の基礎

  • 実際のデータで試す 62h
    上記で学んだ手法を実際のデータで試して遊んでいた時間。けっこう時間かけている割には、ちゃんとまとめておらず、ちょっと試してみたJupyter Notebookが散逸しているような状態で、自分の中に残っているものが少ないのが反省点。

⑵ エンジニアリング関係の学び

⑶ 業務理解

  • ビジネス系の本を読む 34h 16冊
    周りの人がごく普通に感覚として持っていることでも、自分は知らないなと思い、なるべく業務に関係しそうな本を読んだ。

この辺は、知識として読んでよかったなと思う。
カスタマーサクセス――サブスクリプション時代に求められる「顧客の成功」10の原則
サブスクリプション――「顧客の成功」が収益を生む新時代のビジネスモデル

逆に、直接的に業務とつながるわけではないけど、「面白い」と思ったのはこの辺り。
TRUST 世界最先端の企業はいかに〈信頼〉を攻略したか
Airbnbが登場当初、「見知らぬ人の家に宿泊する」というアイデアへの理解・信頼を得るため、どのようなサイト構成にしたのかという部分が興味深かった。

すいません、ほぼ日の経営。
“いまは「あなたはなにもしなくていい」という商品ばかりが売れる時代です。でも手帳は、あなたがなにかをしなければいけない商品です。使いながら完成させていくものです。ぼくらは、いわば未完成品を売っているわけで、それを完成品にするのは使う人です。”

色々条件は異なるけど、作ってもらうという部分は今の仕事で扱うサービスと共通で、なんかヒントがありそうだなと思った。

  • インタビューについての本を読む 17h 3冊
    社内で分析課題について探る時、「その業務に精通している人から的確に話を聞いて、分析課題に落とす」ことが上手くできていないなという気持ちから、インタビューにヒントがないだろうか、と考え読んだ。メモを取ってまとめたは良いものの、そのままになってしまっていたので、見返して日々に活かすにはどうしたらよいかを考える必要がある。

マーケティング・インタビュー 問題解決のヒントを「聞き出す」技術
ユーザーインタビューをはじめよう ―UXリサーチのための、「聞くこと」入門
インタビュー 木村俊介

⑷ アウトプット

仕事でPythonに触れる割合が減ったので、忘れないようにという意味合いもあって行った。作成のふりかえりはすでに書いた。
はじめてのLTで緊張したけど、一人で作っていたものについて人が話を聞いてくれて、感想まで教えてくれるってすばらしいなと思った。

ブログへのまとめに時間がかかっている。本編より長い。まとめ出すとよくわかっていない部分に気づいて調べたり、どう書いたらわかりやすいのか考えたりとかしているうちに時間がかかってしまっている状態。もう少し短縮したい。

⑸ その他

  • ふりかえり 14h
    主に「今週のふりかえり」(何をしたか、何を考えたか)をしていた時間。平均0.5h/週。今のところ「やっててよかった」と思う機会は訪れていない。

  • 色々考える時間 23h
    仕事/仕事外両者について、「こういう分析やれないかな」「やるには具体的にどうしたらいいか」等考えていた時間。のはずなんだけど、しっかりまとめてメモしていなかったせいで、かかっている時間の割には実りが少ない。平均1h/週。

  • その他 28h
    Pythonのライブラリ入れてうまくいかなくて調べたり、疑問に思ったことを調べたりしていた時間。

  • 不明 26h
    「何やったか書くのめんどいな…」と思ってその場で書かないとこうなる。⑴〜⑶のいずれかに入ると思われる。

ふりかえっての所感

記録を取ることで時間に対する感覚が転換した

以前から、時間の使い方は毎日記録していた。ただ、それは睡眠x時間、仕事y時間…という項目別のレベルの記録だった。それだと、学びに対して「今週はx時間かー」というふりかえりになり、「いかに学びにかける時間を増やせるか」という見方になっていた。
それが学びの中身を具体的に記録するようになったら、「この本読むのにもうx時間かかってるのか…急ごう」となり、「いかに短い時間で学べるか」という見方に変わった。
どちらも「記録する」という点では同じなのに、自分の見方が逆に変わったのは面白いなと思う。

漫然と学んでしまっている

その週、仕事で触れていた分野だったり、図書館で偶然借りた本だったりを学んでいることが多かった。計画性に欠けていた。
半年単位で集計すると数十時間かけていたことでも、ふりかえると「こんなにかけてた…?ていうか何も得てなくない…?」と思う分野もあった。特に「本を読んだ」分野だと、メモを取っていないと内容がほぼ記憶に残っていない(メモを取っていても、鮮明には残っていない)。

勉強すること自体には意味がない

そう、「勉強すること」自体には意味がないのである(※ 娯楽として勉強する場合は別として)。今の自分の学びは、基本的に「データ分析の観点から役に立てるようになる」ためにやっているので、学んで「なるほど」で終わったら意味がないのである。この点の意識が不十分だったなと思う。

半年あったら、もっとできるんじゃねーの、と思った

総量的な意味でも、時間あたりの質的な意味でも、ふりかえるともっとできるよね?という感じ。

図書館を利用することの弊害が出ている

8割方の本は図書館で借りさせていただいて読んだ。図書館で借りることのメリットは、返却期限があることで、強制的に勉強する期限が設定できることだ。
一方、図書館で借りて「腰を据えて勉強しよう」と思った本は買って読むんだけど、そうすると「いつでも読める」と思ってしまう。結果、自分にとって重要度の高い本を読まずに、返却期限のある本を優先することになってしまっていた。

バックアップはちゃんと取ろう

6/29、PCが壊れ、ここ半年で学んでローカルに保存していたファイルやデータベースが消えた。バックアップの重要性が身にしみた。この記事もスマホで書いているけど、画面が小さくてつらい。

で、これからどうするの?

  • もう少しこまめにふりかえって、軌道修正するようにする
  • 学んだ内容をちゃんと文に落とす
  • 図書館で本を借りるのはもう少し抑える
  • 理論面、技術面を真剣に学ぶ

「『夏には日陰を歩きたい』という欲望を満たすために計算する」のふりかえり

やろうと思った目的

  • GW10日間チャレンジ
    今回、10日間という例年にない長期休みだったため、普段の勉強とは違い、何か具体的な課題に取り組みたいと考えた。

  • 課題への時間の見積もりができるようになりたい
    業務で分析課題を行う際、「どのくらいでできるか」と問われてもなかなか答えられなかった。これは、経験値が少ないことも当然あるのだけど、自分が「何の作業にどのくらいかけているか」をあまり意識できていないこともあると思った。
    今回、解決までが見通せていない課題に取り組む中で、どのような過程で何を考え、何に何時間かけたかを記録して、時間感覚を得たいと考えた。

  • 見えていないものを見える化してみたい
    普段漠然と感じていることを数字に落とし、それを視覚化することで容易に理解できる形にする。すでにある数字から何かを作るのではなく、数字化する部分からやってみたいと思っていた。

当初目標としていた内容

当初は、地図の画像を読み込んで建物を検出し、それぞれに高さを与えて任意の時間における影を地図に重ねて描きたいと考えていた。
結果的に、以下の理由により断念した。

  • 建物の輪郭だけを得るのが大変
    無料で使用できる白地図が見つからなかったので、OpenStreetMapを利用させてもらうことを考えた。だが、自分の技量不足により、建物の輪郭を検出する際に、地図上の建物名や通り名等も検出されてしまい、うまくできなかった。

  • 建物高さを得るのが大変
    とりあえず自分の行動範囲だけでよかったので、Googleマップ等で目視で調べようかと思っていた。だが、GW中に完成させるという目標に対し、それをしている時間がなかった。また、地図上の建物と高さを機械的に紐づける方法も思いつけなかった。

8日目の時点で諦め、目標を「単純化した建物モデルに対し、道路の方位角ごとに影のでき方を調べる」に変更した。

作業の変遷

開始時点では、以下のような認識だった。

  • 各建物のコーナー部の座標が得られれば、そこから影は求められそう
  • 建物の色と地の色に差があれば、画像処理でうまく建物だけ検出できないかな? 画像処理ってどうやるのかわからないけど
  • 著作権の問題で、Googleマップとかは使えないかもなあ… 無料で使える地図ってないのだろうか

そのような認識から始めたので、作業は以下の3分野を並行して進めていくことになった。

  • 地図から建物外形を得る:地図に描かれた建物の枠線を検出しようとしていた。建物名や通りの名前が入った状態の地図から枠線をうまく検出できず、最終的に断念した。

  • 建物の座標を得る:テスト用の図を自分で用意し、その図の中の建物の枠線を検出し、コーナー部のみになるよう間引き、その座標を得ることができた。

  • 影を計算して描く:建物のコーナー部の座標に対し影の位置を計算し、影の枠線を描き、道路のうち影の重なる面積を求めた。また、ある経路の方位角を求め、日陰になる割合を求めた。

3分野ごとの作業内容を時系列で示すと以下の通り。

円の面積はかかった時間に比例している。また、灰色の円は結果的に不要だった作業を示す。
かかった時間は全体で60時間、そのうち結果的に不要だった作業は9時間くらいだった。また、色々調べたり検討したりしていたのが12時間、コードを書いていたのが48時間くらい(後者はコードを書くために調べていた時間も多いとは思う)だった。60時間と聞くと「かかりすぎだな」と思うけど、上図のように一つずつの作業に分解すると、「今の自分の力だとそのくらいはかかるか…」という気もする。

次回の改善点

  • 作業に取りかかる前にゴールを明確に設定する
    今回、8日目の段階で当初の目標を断念して目標を変えたため、結果的に無駄になる作業が出たり、回りくどいコードになったりしてしまった。開始当初の時点で「現時点の知識からして、10日間でこの目標を達成するのは難しそう」と感じていたので、変更した目標を当初から目標としていれば、もう少し短時間で目標を達成できたと思う。

  • もう少し系統立てて進められるようにする
    やり方を調べるところから始める部分が多く、最後の数日になるまではずっと混沌の中で進めていた。
    「今どこまでできていて、何が課題なのか」を脳内で考えるだけでなく書き出して進めていけば、自分の脳内を整理する意味でもよかったかなと思う。

感想

  • 普段の土日を何週か使って進めていたら、たぶん途中でやめていた。「遊びのコード書いてないで、普段の業務に直結することやろう…勉強したいこともたくさんあるし」となっていたと思う。「この10日間で完成まで持っていく、何らかの形にする」と決めてやったことで、集中してやることができた。
  • 段階ごとに自分で小さな問いを立てて、それをクリアするとゴールに近づいていく嬉しさがあった。今回の課題は、さらにそれが現実世界とつながっている面白さみたいなものもあったと思う。
  • 楽しかったけど、やっている最中は「どこが間違っているかわからない」「落ち着け」「あと3日なのに、全然ゴールが見えない」「ここ直したいけど数時間かかるだろうし」とほぼ焦燥感の中にいた。他者が作ってくれたライブラリを利用させてもらっているだけで、しかもうまく使えてないし、色々わかってないし、と道のりの長さを感じるけど、足元に目を落として一歩ずつ淡々と進んでいくしかない。

「夏には日陰を歩きたい」という欲望を満たすために計算する

目的

昨年の夏、外出のたびに「暑い…少しでも日陰を歩きたい」と思っていた。出かける前に、道路の方位と太陽の位置から影の出来かたを脳内でなんとなくシミュレートするんだけど、だいたい実際の影とずれていた。
夏を迎える前に、時間帯ごとの影の位置を求めておきたい。何時に出かけるのがベストなのかを知った上で、覚悟を持って日差しの元に出て行きたい。
そう思ったので計算した。

作ったもの

まず、与えた建物と道路のモデルに対し、道路の何割が日陰になるかを求めるコードを書いた。
– 入力:求める地点の緯度経度、日付、建物と道路の平面図、建物の高さ
– 出力:建物と道路の平面図に影を重ねた図、道路の方位角ごとの影の割合を求めたグラフ

次に、この結果を使って経路の何割が日陰になるかを求めるコードを書いた。
– 入力:出発地点と到着地点の緯度経度
– 出力:時間帯ごとの影の割合を求めたグラフ

結果

先に結果を示す。

影の計算は、下図のような単純化した建物と道路のモデルを対象とした。4.0mの道路から1.0m後退した位置に、幅・奥行・高さが外法で6,000mmの建物が、1.0mの離れで立ち並んでいる状態とした。
モデル

道路の方位を22.5°ずつ変え、日の出〜日の入りまで、15分ごとに道路のうち影のかかる割合を計算した。(道路の方位は北を0°とした。南北に通る道路なら0°、北西-南東に通る道路なら45°となる) 地点は福岡市(ここでは福岡県庁の緯度経度を代表として利用)とした。

まずは、夏至(2019/6/22)の結果を示す。

  • 南中時刻には、どの方位でもほとんど影ができていない(太陽高度が約80°とかなり天頂に近い位置に太陽があるので、どの方位であっても影ができにくい)。
  • 方位によってかなり影の割合が異なることがわかる。例えば90°(東西の道路)だと、8時過ぎには影がなくなり、16時をすぎるまでそれが続く。一方、0°(南北の道路)だと、10時でもまだ半分以上影ができている。

  • 特徴的なのは67.5°と112.5°の時。前者を取り出して見てみる。
    67.5°

太陽方位と道路の方位が一致、あるいは180°となる(つまり影のできる方位と道路が平行になる)のが日が出ている間に2回あり、その前後は道路に全く影ができない状態になる。
南中後、他の方位だとどんどん影の割合が増えるのに比べ、16時頃を頂点として影の割合が増えた後は太陽方位が道路の方位に近づくのに比例してまた影が減っていっている。

次に、真夏(2019/8/1)の場合の結果を見てみる。

1ヶ月強で、けっこう変化があることがわかる。
方位角と時間帯によって影の割合が違うので、すごく頑張って毎日方違えとかすれば、日差しを避けて生きていけそう。

方位角と時間帯ごとの影の割合がわかったところで、目的地まで至る経路上の影の割合を時間ごとに求めてみる。
今回は緯度経度の代表として利用した福岡県庁から、天神駅までの経路を対象とした。最短経路の方位と距離を求めて、方位については22.5°ずつの方位で近似した。

route

この方位ごとの延長距離から、経路上の影の割合を時間帯ごとに求めてみた。

方位角に偏りのある経路を選んだので、一番長い方位角(135°)の形状を概ね踏襲した結果となった。

計算方法

Pythonで画像処理ができるOpenCVと地理情報を得られるosmnxを利用して求めた。
コードはJupyter Notebookの形式でGitHubに置いた

大まかな計算の流れは以下のとおり
1. モデルとなる画像を読み込み、建物の高さを画像のピクセル数に変換しておく
2. 道路の方位ごとの計算を行うため画像を回転させる
3. 建物の輪郭を検出、間引いてから座標化
4. 緯度経度・日付・時刻から太陽高度・方位角を求める
5. 建物の輪郭の座標ごとに影の位置を求め、それを図形化する
6. (建物と影を重ねた図を書き出し)
7. 影と道路の重なる割合を求め、グラフ化
8. ある経路上における道路の方位とその距離を調べる
9. 方位の割合に応じた時間ごとの影の割合を算出する

反省点/改善点

  • モデルは適当なの?
    正直十分ではないと思う。道路からの後退距離や隣の建物との離れなど、もっと色々なパターンを用意したモデルの平均値を取るなどした方がよかったかもしれない。例えば、今回のモデルでは隣の建物との離れの位置を道路の両側で同じにしているけど、これを互い違いにしたモデルで計算したら影の割合が10%程度違う時間帯もあった。

  • 建物の高さが均一というのはどうなの?
    道路の幅と建物の高さは、ある程度一定(幅の広い道路沿いほど建物の高さは高い)となる傾向にあるのでは、と思う。そうすると、高層地域と低層地域で時間帯間で比べた影の割合は似た傾向になるのでは…という仮説になった。(経路上に高層地域と低層地域両方がある場合は上記の仮説は成り立たなくなるので、現実的ではない)
    今回、GWの10連休中に作り切る、と決めていたので、かなり乱暴な近似をしているけど、影のでき方の傾向性を見る程度には使えるのでは、と考えている。

  • 道路全面に対する影の割合を計算しているけど、真ん中を歩くことは実際にはないよね?
    ある程度幅の広い道路なら、中心でなく端の方を歩くので、道路の端1.0m程度での影の割合を計算する方が実際的だったと思う。ただ、そうすると左右の端ごとの計算が必要になり、結果が複雑になるので今回はやらなかった。

  • ある程度幅の広い道路だと、街路樹があるよね?
    街路樹は今回考慮に入れることができなかった。建物は垂直方向の遮蔽物だけど、樹木は水平方向の遮蔽物で、影のできる面積がかなり大きいので、本当は考慮に入れたかった。幅の広い道路に対しては、x[m]おきにy[m]の高さの円錐状の木のモデルが立っている、というようにすれば良いかもしれない。

  • 隣の建物にかかった影の形が再現できていない
    隣の建物の壁に影がかかると影の形が変形するけど、それは再現できていない。ただ、影を遮った隣の建物による影もあることを考えると、道路にかかる影の量は結果的に変わらないはずと考えている。

  • わざわざ画像として読み込まなくても、もっと簡単にモデルを作れたんじゃない?
    たぶんそうだと思う。当初は実際の地図から建物を読み込んでそれに対する影を計算しようとしていたので、そういう回りくどい形式になってしまった。1回計算するのに20分くらいかかる。

  • コードが整理できていない
    そう思う。後日整理する。

その他全般的な反省は別記事に書いた。
→ 「『夏には日陰を歩きたい』という欲望を満たすために計算する」のふりかえり

MySQLでCSVファイルからデータベースを作る

MySQLをインストールして、CSVファイルからテーブルを作るところまでやってみた過程を記録する。
きっかけは、趣味で計測している時間の使い方記録が11,000行を超え、Excelによる取り回しが重くなってきていたこと。CSVのままPythonで操作するのでもよかったけど、せっかくなのでデータベース化をやってみた。

バージョン

  • macOS 10.13.6
  • MySQL 8.0.15

具体的な操作

以下、リンク先は公式ドキュメントの参照したページ

1 – MySQLのインストール

まず、homebrewでMySQLをインストールした。

$ brew install mysql

(前略)
==> Caveats
We've installed your MySQL database without a root password. To secure it run:
mysql_secure_installation

MySQL is configured to only allow connections from localhost by default

To connect run:
mysql -uroot

To have launchd start mysql now and restart at login:
brew services start mysql
Or, if you don't want/need a background service you can just run:
mysql.server start
(後略)

一番目に書かれている$ mysql_secure_installationをやろうとする。

$ mysql_secure_installation

Securing the MySQL server deployment.

Enter password for user root:
Error: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

パスワードの設定をしていなかったので、Enter password for user root:でそのままEnterを押したが、エラーになった。

can-not-connect-to-server

A MySQL client on Unix can connect to the mysqld server in two different ways: By using a Unix socket file to connect through a file in the file system (default /tmp/mysql.sock), or by using TCP/IP, which connects through a port number.

とあり、接続方法の一つであるソケット接続に失敗したようだ。

結局、MySQLの起動($ mysql.server start)が必要だったようで、その後なら$ mysql_secure_installationを行えた。

$ mysql.server start

Starting MySQL
........ SUCCESS!
$ mysql_secure_installation

Securing the MySQL server deployment.
(長いので後略)

これにより、どのようにセキュリティが向上するかがmysql-secure-installation に書かれている。

  • anonymousユーザー(匿名ユーザー)の削除
  • リモートホストからroot ユーザー(MySQLの操作に対し全権限を持つユーザー)でのログイン禁止
  • testデータベースの削除

などを行った。

2 – MySQLに接続する

$ mysql -u user -pという形で接続する。-uでユーザー名を指定し、-pとすると Enter password: というプロンプトが表示されるのでパスワードを入力する。

rootユーザーでつないでみる。

$ mysql -u root -p

Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 8.0.15 Homebrew

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

つながった!

どんなデータベースがあるか見てみる(testデータベースが消えていることが確認できる)。

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.06 sec)

3 – データベースを作る

lifeというデータベースを作り、その中にtime_bookというテーブルを作成する。

データベースを作る

mysql> CREATE DATABASE life;
Query OK, 1 row affected (0.08 sec)

テーブルを作る

mysql> CREATE TABLE life.time_book(
-> id INTEGER PRIMARY KEY AUTO_INCREMENT,
-> start_datetime DATETIME NOT NULL,
-> end_datetime DATETIME NOT NULL,
-> duration TIME NOT NULL,
-> content VARCHAR(24) NOT NULL,
-> memo VARCHAR(60)
-> );

Query OK, 0 rows affected (0.69 sec)

CREATE TABLE db_name.table_name(col_name data_type, …);という形で作れる。

  • data_typeはデータ型 今回使用しているのはDATETIME(日付と時刻),TIME(時刻),VARCHAR(可変長文字列)
  • NOT NULL:そのカラムにはNULLを格納することができなくなる
  • PRIMARY KEY:主キー制約 行の一意性を確保する
  • AUTO_INCREMENT:連番を自動的に振る

テーブル一覧を確認する

mysql> SHOW TABLES FROM life;
+----------------+
| Tables_in_life |
+----------------+
| time_book      |
+----------------+
1 row in set (0.09 sec)

テーブルのカラム一覧を確認する

mysql> SHOW COLUMNS FROM time_book FROM life;
+----------------+-------------+------+-----+---------+----------------+
| Field          | Type        | Null | Key | Default | Extra          |
+----------------+-------------+------+-----+---------+----------------+
| id             | int(11)     | NO   | PRI | NULL    | auto_increment |
| start_datetime | datetime    | NO   |     | NULL    |                |
| end_datetime   | datetime    | NO   |     | NULL    |                |
| duration       | time        | NO   |     | NULL    |                |
| content        | varchar(24) | NO   |     | NULL    |                |
| memo           | varchar(60) | YES  |     | NULL    |                |
+----------------+-------------+------+-----+---------+----------------+
6 rows in set (0.06 sec)

4 – CSVファイルからデータを挿入する

まずデータベースを選択する。

mysql> use life;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed

CSVを準備する
~/time_book.csv

id,start_datetime,end_datetime,duration,content,memo
1,2017-01-02 09:45,2017-01-02 10:34,00:49,'移動',
2,2017-01-02 10:34,2017-01-02 11:34,01:00,'家事','料理'
…

データをローカルから読み込もうとする。

mysql> LOAD DATA LOCAL INFILE '~/time_book.csv'
-> INTO TABLE time_book
-> FIELDS TERMINATED BY ','
-> IGNORE 1 LINES;

ERROR 1148 (42000): The used command is not allowed with this MySQL version
  • FIELDS TERMINATED BY ','はカンマ区切りを指定している
  • IGNORE 1 LINESはCSVの1行目がカラム名なので、読み込まないようにするため

エラーになった。
load-data-localを参照すると

  • セキュリティの問題から、デフォルトではLOAD DATA LOCALを使えないようにしてある
  • サーバー側、クライアント側それぞれで許可の設定が必要

なことがわかった。

サーバーサイド

The local_infile system variable controls server-side LOCAL capability. Depending on the local_infile setting, the server refuses or permits local data loading by clients that have LOCAL enabled on the client side. By default, local_infile is disabled.

option-modifiers

The “enabled” form of the option may be specified in any of these ways:
(中略)
–column-names=1

とあるので、1にすれば有効になる。

mysql> SET PERSIST local_infile = 1;
Query OK, 0 rows affected (0.08 sec)

SET文でシステム変数を変更できる(再起動すると設定した内容が失われる)。 SET PERSISTでパラメーターの値を設定すると、再起動後も値が保持される。

mysql> SELECT @@local_infile;
+----------------+
| @@local_infile |
+----------------+
| 1              |
+----------------+
1 row in set (0.00 sec)

クライアントサイド

For the mysql client, local data loading is disabled by default. To disable or enable it explicitly, use the –local-infile=0 or –local-infile[=1] option.

接続時に–local-infile=1と指定する
$ mysql -u root --local-infile=1 -p

サーバー側、クライアント側それぞれで設定できたので、改めてLOAD DATA LOCAL INFILEしたところ、先ほどのエラーは出なくなったが、以下の結果になった。

Query OK, 0 rows affected (0.10 sec)
Records: 0 Deleted: 0 Skipped: 0 Warnings: 0

OKって出てるけど、Records: 0ということはつまり…中身を確認する。

mysql> select * from time_book;
Empty set (0.04 sec)

やっぱり読み込まれていない。

試行錯誤しながら問題がある部分を修正していったので、以下1つずつ示す。

  • datetimeとtimeの型の部分を””で囲っていなかった

最初はLOAD DATA LOCAL INFILEでやっているのが原因かと思い、試しにinsert文で読み込めるかやっていた中で気づいた。

mysql> insert into time_book (start_datetime,end_datetime,duration,content,memo) values(1990-01-01 00:00, 1990-01-01 00:01, 00:01:00, "a","b");

ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '00:00, 1990-01-01 00:01, 00:01:00, "a","b")' at line 1
mysql> insert into time_book (start_datetime,end_datetime,duration,content,memo) values("1990-01-01 00:00", "1990-01-01 00:01", "00:01:00", "a","b");
Query OK, 1 row affected (0.03 sec)

“”で日時を囲ったら読み込めた。ごく基本的な話なんだけど、わかっていなかった。
CSVファイルを修正し、LOAD DATA LOCAL INFILEにFIELDS ENCLOSED BY "'"を追加した(これは要素を囲むのに’ ‘を使っていることを指定している)。

  • 文字コードを変えた

まず、MySQL側での文字コードを確認する。

mysql> SHOW VARIABLES LIKE 'char%';
+--------------------------+------------------------------------------------------+
| Variable_name            | Value                                                |
+--------------------------+------------------------------------------------------+
| character_set_client     | utf8mb4                                              |
| character_set_connection | utf8mb4                                              |
| character_set_database   | utf8mb4                                              |
| character_set_filesystem | binary                                               |
| character_set_results    | utf8mb4                                              |
| character_set_server     | utf8mb4                                              |
| character_set_system     | utf8                                                 |
| character_sets_dir       | /usr/local/Cellar/mysql/8.0.15/share/mysql/charsets/ |
+--------------------------+------------------------------------------------------+
8 rows in set (0.00 sec)

utf8mb4って何…?と思い内容を見てみる。

mysql> SHOW CHARACTER SET LIKE "utf8%";
+---------+---------------+--------------------+--------+
| Charset | Description   | Default collation  | Maxlen |
+---------+---------------+--------------------+--------+
| utf8    | UTF-8 Unicode | utf8_general_ci    | 3      |
| utf8mb4 | UTF-8 Unicode | utf8mb4_0900_ai_ci | 4      |
+---------+---------------+--------------------+--------+
2 rows in set (0.00 sec)

utf8mb4もUTF-8の一種っぽい。

csvファイルの文字コードを確認する

$ file --mime time_book.csv

time_book.csv: text/plain; charset=unknown-8bit

UTF-8でなかったので、$ iconvで文字コードを変えようとする。

$ iconv -f unknown-8bit -t utf8 time_book.csv > time_book.csv

iconv: conversion from unknown-8bit unsupported
iconv: try 'iconv -l' to get the list of supported encodings

unknown-8bitという文字コードは対応していないと言われる。$ iconv -lで見てみると、確かにunknown-8bitというのはない。$ iconvでは出来ないのか…と思ったが、unknown-8bitはshift_JISのことのようだとわかった。

$ iconv -f shift_JIS -t utf8 time_book.csv > time_book.csv
$ file --mime time_book.csv

time_book.csv: text/plain; charset=utf-8

CSVファイルをUTF-8に変換できた。

  • 改行コードを指定していなかった

上記を修正しても、LOAD DATA LOCAL INFILEで1行目しか読み込まれなかったことから気づいた。
LOAD DATA LOCAL INFILEにLINES TERMINATED BY '\r'を追加した。

  • (これは、読み込みができなかったのと直接関係しないが)id列について、auto_incrementなのに数字を入れていた

mysql> SHOW COLUMNS FROM time_book FROM life;で見ると、id列のNullがnoになっていたので、auto_incrementだけど数値を入れていた。
example-auto-increment

No value was specified for the AUTO_INCREMENT column, so MySQL assigned sequence numbers automatically. You can also explicitly assign 0 to the column to generate sequence numbers, unless the NO_AUTO_VALUE_ON_ZERO SQL mode is enabled.

とあったので、id列は0に変更した。

結果、CSVはこのような形になった。

id,start_datetime,end_datetime,duration,content,memo
0,'2017-01-02 09:45','2017-01-02 10:34','00:49','移動',
0,'2017-01-02 10:34','2017-01-02 11:34','01:00','家事','料理'

再度csvを読み込み

mysql> LOAD DATA LOCAL INFILE '~/time_book.csv'
-> INTO TABLE time_book
-> FIELDS TERMINATED BY ',' ENCLOSED BY "'"
-> LINES TERMINATED BY '\r'
-> IGNORE 1 LINES;

Query OK, 11348 rows affected, 1 warning (0.59 sec)
Records: 11348 Deleted: 0 Skipped: 0 Warnings: 1

読み込みができたっぽいぞ!

mysql> SELECT * FROM life.time_book LIMIT 2;
+----+---------------------+---------------------+----------+---------+--------------+
| id | start_datetime      | end_datetime        | duration | content | memo         |
+----+---------------------+---------------------+----------+---------+--------------+
|  1 | 2017-01-02 09:45:00 | 2017-01-02 10:34:00 | 00:49:00 | 移動    |              |
|  2 | 2017-01-02 10:34:00 | 2017-01-02 11:34:00 | 01:00:00 | 家事    | 料理          |
+----+---------------------+---------------------+----------+---------+--------------+
2 rows in set (0.00 sec)

できた!

感想

なるべく公式ドキュメント(英語)のみで理解しようとして進めたけど、けっこうつらかった。今回よりも古いバージョンなら日本語のドキュメントもあって、わからない場合はそちらも参照したけど、英語で読んでわからない場合は日本語でもだいたいわからず、英語力でなく知識不足が原因か、と思いつつ不明な単語等を調べて進めていった。

単に1つのテーブルを作るだけなのに各所で色々引っかかったけど、作業自体は全般的に楽しかった。やっとデータが読み込めた時はうれしくて、ひとり小躍りした。

楽しんで働くへの現時点の返答

前職にいた時、必要以上に真面目に取り組むことで許されようとする悪癖があった(今もちょっと残っている)。
期限に間に合わせるため、土日や年末年始にも非公式に職場にやってきて働くとか、そういう行動のことです。

この行動は、前職においておおむね批判されなかった。仕事量も人員数も調整がきかない場だったので、便利な存在という側面もあったと思う(そうやって働く人も多かった)1
一方で、その姿勢を諌めてくれる先輩もいた。「お前のまじめさは美徳なんかじゃねーからな」と。
だって、やるしかないじゃん、と思っていた。さらには、この日々は何らかの形で報われると勝手に思っていた。

3年目のある日、気づいた。
部長や課長、あるいは組織がこの頑張りに報いてくれるわけでないし、私の人生に責任を持ってくれるわけではない(当然、持つ必要もない)。
頑張りによる成果は彼らを喜ばせ、それは単純に嬉しいけど、それを自分の最終目的にしても、(頑張っている内容からして)自分に何かが残るわけではない。

この人生を生きているのは誰?
私だ。
まじか、そうかと思った。

目前の仕事だけでいっぱいな日々は、その間思考停止できて、実は楽だ。「でも今はこれをしなきゃ」が汎用的な言い訳になる。
でも、それを何年も続けていると、自分の価値は目前の仕事だけだから、その出来に精神状態が100%左右されるようになる。そして、頑張る見返りとして、自分の人生の責任を取るのは自分であるということを放棄したい心持ちになっていった。

(しつこいですが、ここまで前職での話です)

転職して数ヶ月、楽しんで働くってなんだ、とぼんやり考え続けていた2

まだ考えがまとまっていないけど、一つ考えたことは、真面目であることは、真剣なのと似ているけど違うということだ。真面目さは義務感から発している一方、真剣さはその対象を自分ごととして捉えることから発している。真面目さは深刻さへつながっていく一方、真剣さはユーモアと同居できる。
「どうしたらそれができるって思う?」「今の自分・状況で取りうる、最善の行動ってなんだろうね?」と自分に問いかけてやって、困難3にも、にいっと笑って、楽しんでやっていきたい。今、自分は事業にしっかり貢献できるだけの実力が持てていないけれど、その中でも、考えることはできるはずなのだ。

真面目さで評価されようとするよりも、真剣に取り組んで成果を出す方が厳しい世界なのは気づいている。
無意識に慣れた手法を取ってしまうけど、頑張り方も変えていきたい。1歩進んで、1歩下がって、の繰り返しだろうけど、それでも振り返れば進んでいる。


  1. 数年前の話なので、今は改善されている部分もある。また、強制されたものではない 
  2. 入った当初言われた「楽しんでやりましょう」の衝撃が大きくて、ずっと心の中にあった 
  3. ここでいう困難とは、あくまで現段階の自分から見ての話 他の人から見たらそんなの困難と呼ばないよ、というものも含む 

混乱した統計検定2級の用語をまとめる

統計検定2級の過去問を解いていた時、似た単語がよく出てきて「何でしたっけ…」となっていた。忘れないうちに、それらの単語を書き出してみる。

標本の抽出方法

母集団の要素全てに対して調べることは現実的にできない場合、その中からいくつか取り出して調べることになる。どのように取り出すのがなるべく偏りが出ないかというのと、調べるにあたってどれだけ手間をかけられるか、両者をどこでバランスさせるかによって、色々な手法がある。

単純無作為抽出法

母集団の要素から、どの要素も同じ確率となるよう無作為に抽出する方法。
– 母集団N個から標本n個を抽出する時に、各個体が標本として選択される確率n/N
– どのn個の個体の組も選択される確率が1/NCn
→ 10人から4人選ぶ時に、男2女2という条件がつくと、単純無作為抽出ではなくなる(層化無作為抽出法になる)

系統抽出法

要素全てに番号をふり、1つ目の要素は無作為に抽出し、2つ目以降は等間隔の番号を抽出する方法

層化無作為抽出法

性別、年代、…などで母集団が複数の層にわかれる場合に、いずれかの層に偏りが出ないよう、層ごとにランダム抽出する方法

多段抽出法

例)全国から複数の県を抽出、各県から複数の学校を抽出、各学校からクラスを抽出…というように絞り込んでいく方法
段数が多くなるほど、平均などの推定精度は悪くなる

層化多段抽出法

層化抽出法と多段抽出法を組み合わせたもの

クラスター(集落)抽出法

母集団を分割してクラスターを作った上で複数のクラスターを抽出し、その成員全てを対象とする方法
精度は低め

二相抽出法

調査しやすい項目をまず調査し、それを補助情報として調べたい項目の調査を行う方法(標本を抽出する操作を2度行う)

価格に関係して出てくる用語

ローレンツ曲線、ジニ係数

ローレンツ曲線:
分布を持つようなある事象の偏り(所得の偏りでよく出てくるので、その場合偏りが格差となる)がどの程度あるかを表す
完全に偏りがない場合、下図の点線(均等配分線という)で示す直線になる
ジニ係数:
均等配分線とローレンツ曲線で囲まれた面積の2倍が、縦軸・横軸で囲まれた面積に対して占める割合
0(ローレンツ曲線と均等配分線が一致)だと偏りがないことを示す 最大値は1となる

ラスパイレス指数

物価の変動を表す時によく使われる
下に示すように、基準時とそれと比較する時の価格の変化を基準時の数量をウエイトとして計算する

オッズ比

2つの群を比較した時に、起こりやすさを示す尺度
オッズ比が1だと2つの群の間に起こりやすさの差がないことを意味する