ギークなエンジニアを目指す男

SIerが機械学習系の知識を蓄えようとするブログ

MENU

機械学習初心者が約10ヶ月でメダルより大切なものを獲得できた話【kaggle Advent Calendar 17日目】

本記事は、kaggle Advent Calendar 2018の17日目の記事です。

qiita.com

何を書くか直前まで悩んでいましたが、16日に参加したAIもくもく会の中で、
機械学習に興味はあるけど、どのような手順で、何から勉強していったら良いかわからない
という方が数名いたので、自分が今年の3月くらい〜今日に至るまで勉強してきた中から
今の自分ならこのような手順で勉強することをオススメする!という記事を書いてみようと思います。

※自分の勉強した教材の中からのオススメになるので、偏った内容になることをご了承ください。
※これもオススメ!というものがありましたら、ぜひ教えていただけると嬉しいです。

タイトルにあるメダルより大切なものについては最後に記載しております。

対象読者

以下の読者を想定して記事を作成しています。

  • 機械学習に興味はあるんだけれども、何から勉強して良いか分からないor悩んでいる人
  • kaggleでタイタニックやって満足して終わってしまった人
  • カーネルFork→submit(ッターーーーン)で終わってしまっている人

2018年3月時点の筆者スペック

大学は工学部の情報学科でしたが、機械学習の木の字も知らない学生でした。
pythonを勉強し始めたのも2018年3月からです。
kaggle初心者というどころか、機械学習初心者でした。

2018年3月〜今日に至るまで勉強したこと羅列

カテゴリに分けて羅列します。
(現在進行形で勉強している教材も載せています)

書籍

ネットで検索して、いわゆる良書であろう本を買って勉強したつもりです。

動画

動画はudemyとcourseraを利用しました。
udemyは頻繁に割引セール(1万円の講座が1300円とかになる)をやっているので、そのときにまとめての購入をオススメします。

ここで紹介しているcourseraの動画は英語音声で、日本語は字幕のみです。(この字幕もgoogle翻訳した日本語ぐらいの精度です) 機械学習も英語も勉強できてお得という人もいますが、機械学習だけでもそんなに優しい内容ではないのに、 それを英語で説明されたときに挫折しない程の英語力もしくは鋼の心が必要だと思いますので、動画自体はudemyをオススメします。

もちろん、ここで紹介しているcourseraの動画はとてもわかりやすく、機械学習を一通り学んだ後に見るとより理解が深まるかと思います。

udemy

coursera

kaggle

kaggleではチュートリアル含め下記データセットで学びました。

その他

初学者に伝えたいオレオレ勉強ルート

ここが本題です。

先に掲載した中から、どの順番でどの教材を用いれば良さそうか、私なりの勉強ルートをお伝えできればと思います。

STAGE1:機械学習の土台作り

まずは機械学習の基礎の数学を学ぶことで、今後様々なモデルを学ぶときに、理解しやすくなります。
そこで、下記書籍と動画をオススメします。

STAGE2:ライブラリの使い方や一般的なモデルを理解する

土台づくりが終了したら、pythonを用いながら機械学習に触れていきます。
ここでは、基本的なモデルから各種ライブラリの使い方を体系的に学ぶことを意識し、かつ、実際のkaggleデータセット等を用いて仮説検証することで、ある程度実力がつくと思います。

まずは、

こちらの書籍で機械学習を体系的に学び、下記kaggleのデータセットで実際に予測モデルを作成してみるのが良いと思います。

STAGE3:深層学習を学ぶ

ある程度機械学習に慣れてきた頃に、深層学習というワードに興味を持つようになると思います。
(実際にSTAGE2で挙げた書籍でもディープラーニングの話が載っています)

そこでオススメしたいのが下記書籍です。

このシリーズは、ライブラリに極力頼らずに、ゼロからニューラルネットワークを構築してみる、という内容で、図解も多く大変わかりやすいです。

初版無印(画像処理編)が大変人気で、続編である2部(自然言語処理編)が発売されました。

まずは、初版無印(画像処理編)の方でCNN等を学び、下記データセットなどで学んだ技術を試してみるのが良いと思います。

そのあと、2部(自然言語処理編)でRNN等を学び、下記データセットなどで学んだ技術を試してみるのが良いと思います。(こちらは私自身現在進行形で取り組んでいます)

ここで紹介しているデータセットは、あくまで自分がチャレンジしたことのあるものを挙げているだけなので、 kaggleなどでいろいろ探してみて、自分のやりたいデータで取り組むのがモチベーション維持にも繋がると思います。

STAGE4:やりたい分野に特化して学習する

これ以降は、自分のやりたい分野に特化して取り組むのが良いのではないでしょうか。(自分もそうしていく予定です)

今までも紹介してきましたが、kaggleには様々なデータセットが転がっており、その中でもコンペが開催されたデータセットであれば、世界中の強いデータサイエンティストの人がさいつよカーネルを公開してくれているので、それを眺めて実行するだけでも多くの知見が得られると思います。

勉強のモチベーション維持方法

勉強していく上で、モチベーションを維持することはとても重要だと思います。
そこで、いくつか自分が実践していたモチベーション維持方法をお伝えします。

Twitter

kaggleに毒されている積極的に取り組んでいる方が大勢います。
そういった方々をフォローしておくだけでも、モチベーションは無限大になるかと。
本記事もそうですが、kaggle Advent Calendar 2018に投稿している方々はフォローしておくことをオススメします。

私もフォローお待ちしております。
takapy (@takapy0210) | Twitter

ブログ

アウトプットは正義です。
ブログの開設が面倒臭いという方にはQiitaをオススメします。
いいねが付きやすいですし、多くの人の目に触れる確率が高いです。

ここではアウトプットすることのメリットについての言及は控えますが、記事を書いて誰かから反応が貰えると、とてもモチベーションになります。

kaggle-ja slack

kaggleをやっている日本人が日々意見を交換し合うコミュニティがあります。
ここへ参加しているだけで、様々な知見が流れてきます。

yutori-datascience.hatenablog.com

勉強会

自分はconnpassTECH PLAYから気になる勉強会やイベントに参加して、いろんな人から刺激を受けることでモチベーションの維持も行うことができました。 (住んでいる場所的に新宿、渋谷界隈が多め)

最後に

以上、少し長文となりましたが、本記事が機械学習初心者にとって有意義な記事となってくれれば幸いです。

そして本当の最後に。

タイトルにも書いているメダルより大切なものですが・・・

それは

内定です。

これはこれで別記事として書こうと思いますが、2019年3月よりMLエンジニアとして仕事をさせて頂くことになりました!

本当に楽しみで仕方ありません。

これまで転職活動に使っていたエネルギーを、スキルアップの方に惜しみなく使っていきたい所存です。

GCI 社会人向け Data Science Online Course 6週目の感想

f:id:taxa_program:20181111113255p:plain

第3期社会人向け Data Science Online Courseコースの6週目を終えました。

今週学んだことをアウトプットしていきます。

記事を書くことが目的化しないように、要点だけまとめていこうと思います。(先週分の戒め)


スケジュール
第1回(11/5) : Numpy、Scipy、Pandas、Matplotlibの基礎
第2回(11/12) :記述統計学と単回帰分析
第3回(11/19) :確率と統計の基礎
第4回(11/26): Pythonによる科学計算の基礎(NumpyとScipy)
第5回(12/3) : Pandasを使ったデータ加工処理
第6回(12/10): Matplotlibを使ったデータ可視化← Now!!
第7回(12/17) :データベースとSQLの基礎
第8回(12/24): データベースの応用(高度なSQL処理と高速化)
第9回(1/7) :ドキュメント型DB(MongoDB)
第10回(1/14):機械学習の基礎(教師あり学習
第11回(1/21): 機械学習の基礎(教師なし学習
第12回(1/28): モデルの検証方法とチューニング方法
第13回(2/4) : データサイエンスティスト中級者への道


  • データ可視化の基礎
    • 棒グラフ
    • 円グラフ
    • バブルチャート
  • まとめ
  • おまけ

データ可視化の基礎

棒グラフ

縦の棒グラフを描画する場合はbarを使用する。

横の棒グラフを描画する場合はbarhを使用する。

複数のグラフを比較したい場合や、積み上げ棒グラフの描画について学べた。

f:id:taxa_program:20181216134822p:plain:w300
積み上げ棒グラフ例

円グラフ

全体的な割合がどの程度あるのかを見るときに使用する。

labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
sizes = [15, 30, 45, 10]
colors = ['yellowgreen', 'gold', 'lightskyblue', 'lightcoral']
explode = (0, 0.1, 0, 0)  # 円から切り離して表示させることが可能

# グラフの大きさ指定
plt.figure(figsize=(15, 6))

# startangleは各要素の出力を開始する角度を表す(反時計回りが正), 向きはcounterclockで指定可能
plt.pie(sizes, explode=explode, labels=labels, colors=colors,
        autopct='%1.1f%%', shadow=True, startangle=90)
plt.axis('equal')

f:id:taxa_program:20181216135411p:plain:w300
円グラフ例

バブルチャート

個人的に一番面白かったのがこのバブルチャートでした。

続きを読む

GCI 社会人向け Data Science Online Course 5週目の感想

f:id:taxa_program:20181111113255p:plain

第3期社会人向け Data Science Online Courseコースの5週目を終えました。

今週学んだことをアウトプットしていきます。


スケジュール
第1回(11/5) : Numpy、Scipy、Pandas、Matplotlibの基礎
第2回(11/12) :記述統計学と単回帰分析
第3回(11/19) :確率と統計の基礎
第4回(11/26): Pythonによる科学計算の基礎(NumpyとScipy)
第5回(12/3) : Pandasを使ったデータ加工処理 ← Now!!
第6回(12/10): Matplotlibを使ったデータ可視化
第7回(12/17) :データベースとSQLの基礎
第8回(12/24): データベースの応用(高度なSQL処理と高速化)
第9回(1/7) :ドキュメント型DB(MongoDB)
第10回(1/14):機械学習の基礎(教師あり学習
第11回(1/21): 機械学習の基礎(教師なし学習
第12回(1/28): モデルの検証方法とチューニング方法
第13回(2/4) : データサイエンスティスト中級者への道


  • Pandas 基本的なデータ操作
    • 階層型インデックス
    • データの結合
      • 内部結合
      • 外部結合
      • indexによる結合
      • 縦結合
    • データの操作と変換
      • ピポット操作
      • 重複データの削除
      • マッピング処理
      • 無名関数とmapを組み合わせる
      • ビン分割
    • データの集約とグループ関数
  • 欠損データと異常値の取り扱い
    • リストワイズ削除
    • ペアワイズ削除
  • 時系列データの取り扱い
  • 所感

Pandas 基本的なデータ操作

階層型インデックス

データを複数軸で集計したいモチベーションがある場合に、階層型インデックスを設定すると幸せになれる。
階層的にインデックスを設定することで、各階層ごとに集計が可能となり、かなり便利になる。

階層型インデックスの作成例

hier_data_frame = DataFrame(np.arange(9).reshape((3,3))
                           ,index = [['a','a','b'],[1,2,2]]
                           ,columns = [['Osaka','Tokyo','Osaka']
                                      ,['Blue','Red','Red']]
                           )
hier_data_frame

f:id:taxa_program:20181209131845p:plain:w300
階層型インデックス例

また、上記で設定したインデックスやカラムには名前(ラベル)をつけることも可能です。

# indexに名前を付ける
hier_data_frame.index.names =['key1','key2']
# カラムに名前を付ける
hier_data_frame.columns.names =['city','color']
hier_data_frame

f:id:taxa_program:20181209132012p:plain:w300
インデックスに名前をつけた例

この状態で、例えばcity = Osakaのデータのみ参照したい場合は、下記のようにすれば良い。とても便利。

hier_data_frame['Osaka']

もちろん、行、列インデックスを軸にした集計も可能。

# 階層ごとの要約統計量:行合計
hier_data_frame.sum(level='key2')

f:id:taxa_program:20181209132359p:plain:w300
行インデックスを軸にした集計

# 列合計
hier_data_frame.sum(level='color',axis=1)

f:id:taxa_program:20181209132429p:plain:w300
列インデックスを軸にした集計

インデックスを削除したい場合などは、drop関数を使用する。

hier_data_frame.drop(['b'])

f:id:taxa_program:20181209132504p:plain:w300
インデックス[b]を削除

データの結合

まずはサンプルとして使用するデータを準備する

続きを読む

GCI 社会人向け Data Science Online Course 4週目の感想

f:id:taxa_program:20181111113255p:plain

第3期社会人向け Data Science Online Courseコースの4週目を終えました。

今週学んだことをアウトプットしていきます。


スケジュール
第1回(11/5): Numpy、Scipy、Pandas、Matplotlibの基礎
第2回(11/12):記述統計学と単回帰分析
第3回(11/19):確率と統計の基礎
第4回(11/26): Pythonによる科学計算の基礎(NumpyとScipy) ← Now!!
第5回(12/3): Pandasを使ったデータ加工処理
第6回(12/10): Matplotlibを使ったデータ可視化
第7回(12/17):データベースとSQLの基礎
第8回(12/24): データベースの応用(高度なSQL処理と高速化)
第9回(1/7):ドキュメント型DB(MongoDB)
第10回(1/14):機械学習の基礎(教師あり学習
第11回(1/21): 機械学習の基礎(教師なし学習
第12回(1/28): モデルの検証方法とチューニング方法
第13回(2/4): データサイエンスティスト中級者への道


Numpy

インデックス参照

下記のようなデータがあった場合

sample_array = np.arange(10)
print("sample_array:",sample_array)
#-> sample_array: [0 1 2 3 4 5 6 7 8 9]

スライスという操作により、先頭から○文字を抽出することができる。

# 前から数字を5つ取得して、sample_array_sliceに入れる(スライス)
sample_array_slice = sample_array[0:5]
print(sample_array_slice)
#-> [0 1 2 3 4]

この新しい変数sample_array_sliceの先頭から3つ(sample_array_slice[0]~sample_array_slice[2])を、10という値に置き換えることを考える。
この結果、sample_array_sliceは「10 10 10 3 4」となるのは明らかですが、このとき元の変数であるsample_arrayの値も変わってしまいます。

# sample_array_sliceの3文字目までは、10で置換
sample_array_slice[0:3] = 10
print(sample_array_slice)
#-> [10 10 10  3  4]

# スライスの変更はオリジナルのリストの要素も変更されていることに注意
print(sample_array)
#-> [10 10 10  3  4  5  6  7  8  9]

代入元の変数の値も変わってしまうのは、コピーではなくて参照が行われているからです。
すなわち、「sample_array_slice = sample_array[0:5]」という代入の構文は、sample_arrayの先頭から5つをsample_array_sliceにコピーしているように見えますが、そうではなくて、sample_array_sliceは、元のsample_arrayの先頭から5つを参照しているだけなのです。

そのため、値を変更すると、元の値も変わってしまいます。

参照ではなく、コピーを行う場合は、np.copy()を利用します。

# copyして別のobjectを作成
sample_array_copy = np.copy(sample_array)
print(sample_array_copy)
#-> [10 10 10  3  4  5  6  7  8  9]

sample_array_copy[0:3] = 20
print(sample_array_copy)
#-> [20 20 20  3  4  5  6  7  8  9]

# 元のリストの要素は変更されていない
print(sample_array)
#-> [10 10 10  3  4  5  6  7  8  9]

ブールインデックス

# データの準備
sample_names = np.array(['a','b','c','d','a'])
random.seed(0)
data = random.randn(5,5)

print(sample_names)
#-> ['a' 'b' 'c' 'd' 'a']

print(data)
#-> [[ 1.764  0.4    0.979  2.241  1.868]
#->  [-0.977  0.95  -0.151 -0.103  0.411]
#->  [ 0.144  1.454  0.761  0.122  0.444]
#->  [ 0.334  1.494 -0.205  0.313 -0.854]
#->  [-2.553  0.654  0.864 -0.742  2.27 ]]

data変数の[]のなかに条件として指定すると、Trueになっている箇所のデータだけを取り出せます。 この例では、先頭と末尾がTrueなので、そのデータのみが抽出される動作となります。これがブールインデックス参照です。

data[sample_names == 'a']
#-> array([[ 1.764,  0.4  ,  0.979,  2.241,  1.868],
#->       [-2.553,  0.654,  0.864, -0.742,  2.27 ]])

条件制御

np.whereを使うと、2つのデータXXとデータYYがあるとき、条件を満たすかどうかによって、XXの要素を取り出す、もしくはYYの要素を取り出すというように、取得するデータを切り分けられます。その書式は、次の通りです。

np.where(条件の配列, Xのデータ, Yのデータ)

# 条件制御のためのブールの配列
cond_data = np.array([True,True,False,False,True])

# 上記より、配列の1番目(1)、2番目(2)、5番目(5)の数字が出されます。
x_array= np.array([1,2,3,4,5])

# 上記より、配列の3番目(8)、4番目(9)の数字が出されます。
y_array= np.array([100,200,300,400,500])

# 条件制御実施
print(np.where(cond_data,x_array,y_array))
#-> [  1   2 300 400   5]

Numpyの演算処理

重複の削除

uniqueを用いることで、要素の重複を削除できる。

cond_data = np.array([True,True,False,False,True])

# 重複削除
print(np.unique(cond_data))

最小、最大、平均、合計の計算

Pandas同様、Numpyでも最小、最大などの計算ができます。axisを指定すると、行や列の指定も可能。

# 統計関数(PandasでやったがNumpyでもできる、列、行の指定なども)
sample_multi_array_data1 = np.arange(9).reshape(3,3)
print(sample_multi_array_data1)
print("最小値:",sample_multi_array_data1.min())
print("最大値:",sample_multi_array_data1.max())
print("平均:",sample_multi_array_data1.mean())
print("合計:",sample_multi_array_data1.sum())

# 行列の指定
print("行の合計:",sample_multi_array_data1.sum(axis=1))
print("列の合計:",sample_multi_array_data1.sum(axis=0))

配列操作とブロードキャスト

再形成

Numpyでは、行列の次元を増やすことを再形成と言います。

# データの準備
sample_array = np.arange(10)
sample_array

上記データを、例えばreshape(2,5)のようにすると、2行5列の行列に再形成できます。

# 再形成
sample_array2 = sample_array.reshape(2,5)
sample_array2
#-> array([[0, 1, 2, 3, 4],
#->       [5, 6, 7, 8, 9\]])

データの結合

concatenateを使うと、データを結合できます。axisで行方向か、縦方向を指定します。

# データの準備
sample_array3 = np.array([[1,2,3],[4,5,6]])
sample_array4 = np.array([[7,8,9],[10,11,12]])

# 行方向に結合
np.concatenate([sample_array3,sample_array4],axis=0)

配列の分割

splitを使うと配列を分割できます。

# データの準備
sample_array3 = np.array([[1,2,3],[4,5,6]])
sample_array4 = np.array([[7,8,9],[10,11,12]])
sample_array_vstack =  np.concatenate([sample_array3,sample_array4],axis=0)

# ~1の範囲と、1~3の範囲と、3~の範囲に分割
first,second,third=np.split(sample_array_vstack,[1,3])

ブロードキャスト

ブロードキャストとは、配列の大きさが異なっているときに、自動的に要素をコピーして、対象の大きさを揃える機能です。

sample_array = np.arange(10)

次のように「+3」をして、配列に3を加えようとしています。このとき、sample_array + 3は、片方は配列で、もう片方は配列ではないので、そのままでは計算できません。そこでNumpyでは暗黙的に、要素をコピーして大きさを揃えて、sample_array + np.array([3,3,3,3,3,3,3,3,3,3])のように計算します。これがブロードキャストです。

sample_array + 3

Scipy

積分微分方程式

積分

Scipyを使えば、たとえば、次の(数値)積分を求めることができます。

$$ \int_01 \frac{4}{1+x2} dx $$

# 積分計算
from scipy import integrate
import math

def calcPi(x):
    return 4/(1+x**2)
    
# 計算するためには`integrate.quad`を使います。`integrate.quad`には、定義した計算の関数を1つ目の引数に指定します。そして2つ目と3つ目の引数には、積分範囲を設定します。
integrate.quad(calcPi, 0, 1)
#-> 3.142

2次関数の最適化

次の2次関数について、$f(x)$が0になる$x$を考えてみましょう。もちろん、解の公式で解くことができますが、Scipyのoptimizeの使い方を覚えるために、optimizeを使って解いてみます。

$$ \ f(x) = 2x2 + 2x -10 $$

# 関数の定義
def f(x):
    y = 2 * x**2 + 2 * x - 10
    return y

# グラフ化
x = np.linspace(-4,4)
plt.plot(x,f(x))
plt.plot(x,np.zeros(len(x)))
plt.grid(True)

グラフから、解は1と-2付近にあることが分かるので、以下のような計算をさせると解を算出してくれます。

# x = 1 付近
x = fsolve(f,1)

# x = -2 付近
x = fsolve(f,-2)

exam(今週の提出課題)

提出課題については

「ある式を積分する」

というものでした。

所感

今週の講座に要した時間は、問題/課題も含め3時間〜4時間程度でした。

今までScipyはあまり使ってこなかったので、新しい知見を得ることができました。
Scipyのセクションでは、少々難しい数学の知識なども出てきており、完璧には理解できない箇所もあったため、特に下記は時間を見つけて復習できればと思います。

リーダブルコードを読了しました

f:id:taxa_program:20181201012041p:plain

おすすめ頂いたリーダブルコードを読了しました。 個人的に多くの知見を得ることができ、また、汎用的に利用できる知識が多くこれからのコーディングに少なからず影響を与えてくれる書籍でした。

今日はその中でも肝に命じておきたいこと、所感などまとめておきたいと思います。

名前に情報を詰め込む

プログラムに使用される変数名や関数名にはtmpなどハッキリしないものが多い。sizegetのように、一見問題なさそうな名前も、詳細な情報が含まれていないことがある。

本書では、名前を考える際に下記6点に注意することを推奨している。

  • 明確な単語を選ぶ
  • 汎用的な名前を避ける(あるいは、使う状況を選ぶ)
  • 抽象的な名前よりも、具体的な名前にする
  • 接尾辞や接頭辞を使って情報を追加する
  • 名前の長さを決める
  • 名前のフォーマットで情報を伝える

上記の中から、いくつか心当たりのある部分をピックアップしてみます。

汎用的な名前を避ける(あるいは、使う状況を選ぶ)

個人的に、関数の戻り値などにretなどの変数名をつけてしまう時があります。
この変数から読み取れる情報としては戻り値という当たり前の情報だけで、それ以外はないですよね。 例えば、2乗の合計を返す場合はsum_squaresなど、その変数(今回は戻り値)にどのような値が格納されているかを連想できるような名前を付けるべきですよね。 こうすれば変数の目的を事前に伝えることが可能となりますし、バグの発見確度もあがりそうです。

接尾辞や接頭辞を使って情報を追加する

例えば下記のようなコードがあった場合、変数startにはどのような値が格納されるか想像できますか?

var start = (new Date()).getTime()

時分?
秒?

正解はミリ秒です。

今回の場合は、下記のような変数名にするとわかりやすいですよね。

var start_ms = (new Date()).getTime()

このように、接尾辞や接頭辞に属性を追加するだけで、変数の意味の理解度が向上するはずです。

名前(変数名、引数名など)は短いコメントだと思い、命名することが大切なようです。

誤解されない名前

本書には、名前が「他の意味と間違えられることはないだろうか?」と何度も自問自答することが大切だと記載されています。

範囲を指定する場合はfirstlastを使う

よくコーディングしていて出くわすのが、範囲を絞ったコードですよね。 例えば、下記の例だとパッと見てどのように出力されるか分かり辛いと思いませんか?

print integer_range(start=3, stop=4) 

[2,3]?
あるいは[2,3,4]・・・?
コードを見ただけで判断するのはとても難しいと思います。

なので、範囲を指定する場合はfirstlastを使うと良いみたいです。
(この変数名が正しく聞こえるから)

包含/排他的範囲にはbeginendを使う

上記とは切り分けて、包含/排他的範囲を示す場合はbeginendを用いるのが良いみたい。

コメントすべきことを知る

コメントを書くことは良いことだと思いますが、何でもかんでもコメントとして残すべきではありませんよね。 コメントを読むとその分だけコードを読む時間も増えますし、画面を占領します。

よって、コメントには読むだけの、また、画面を占領させるだけの価値を持たせる必要があると思います。

本書では、この価値のあるコメントについても言及しています。

コードからすぐに分かることをコメントとして書かない

新しい情報を提供するわけでもなく、読み手がコードを理解しやすくなるわけでもないコメントは書かないべきです。

また、すぐに分かるという部分がとても重要です。
例えば下記のようなコードがあった場合、このコメントには価値があると思いますか?

# 2番目の`*`以降をすべて削除する
name = `*`.join(line.split('*')[:2])

上記コメントは「新しい情報」を提供できてはいませんよね。
また、コードを見ればどのように動くかは分かると思います。

しかし、コードを理解するよりも、コメントを読んだ方が早く理解できると感じたはずです。
よって、このコメントは価値のあるコメント(コメントとして記載した方が良いコメント)ということになりそうです。

また、通常は「補助的なコメント」(コードの読みにくさを補うコメント)が必要になるケースはあまりないようです。

このことを巷では「優れたコード > (ひどいコード + 優れたコメント)」と呼ぶそうです。

自分も業務の中で、「ここは補足的なコメントが必要だよな」と思い、良心からコメントを残していますが、そもそものコードがヒドいからコメントが必要だったんですね・・・。
こういった点も意識しながらコーディングすると、同じ量のコードを書いてもスキルの上達具合が全然違うんだろうと感じました。

本章の最後にとても簡潔なまとめが載っていたので、転記させていただきます。

「コメントはWHATではなく(あるいはHOWではなく)WHYを書こう」とうアドバイスを耳にしたことがあるかもしれない。 確かにキャッチーな言葉だけど、少し単純化しすぎていて、人によっては取り方が違うかもしれない。 ぼくたちからのアドバイスはこうだ。「コードを理解するのに役立つものなら何でもいいから書こう」 これなら、WHATでもHOWでもWHYでも(あるいは3つ全部でも)書ける。

制御フローを読みやすくする

条件やループなどの制御フローはできるだけ「自然」にする。コードの読み手が立ち止まって読み返したりしないように書く。

条件式の引数の並び順

例えばif文などの引数の並び順は、下記のような指針で決定すると良い。

左側 右側
「調査対象」の式。変化する。 「比較対象」の式。あまり変化しない。
if (10 <= length)

よりも

if (length >= 10)

の方が読みやすいですよね。
これは英語の用法と合っているようで、「もし君が18歳以上ならば」というのは自然ですが、「もし18年が君の年齢以下ならば」というのは少し不自然ですよね。
これと同じ原理なので覚えやすいです。

if/elseブロックの並び順

if/elseブロックは、下記を意識してコーディングする方が良い。

  • 条件は否定形よりも肯定系を使う。
  • 単純な条件を先に書く。ifとelseが同じ画面に表示されるので見やすい。
  • 関心を引く条件や目立つ条件を先に書く。

また、プログラムを書いていると、
より少ない行数でコーディングできた方が優れている

1行で書けたぜドヤ
という一種の俺すごいだろ錯覚に陥ることが少なくない。

行数を短くするより、他の人が理解するのにかかる時間を短くするのが一番大切だということを、改めて肝に銘じたい。

無関係の開問題を抽出する

エンジニアリングとは、大きな問題を小さな問題に分割して、それぞれの解決策を組み立てることに他ならない。 この原則をコードに当てはめれば、堅牢で読みやすいコードになる。 ここで大事なのは、無関係の下位問題を積極的に見つけて抽出することだと本書では述べている。

具体的には下記を念頭に置いてコーディングを行うと良い。

  1. 関数やコードブロックを見て、「このコードの高レベルの目標は何か?」と自問する。
  2. コードの各行に対して「高レベルの目標に直接的に効果があるのか?あるいは、無関係の下位問題を解決しているのか?」と自問する。
  3. 無関係の下位問題を解決しているコードが相当量あれば、それらの抽出して別の関数にする。

コードに思いを込める

コーディングする際に、プログラムのことを簡単な言葉で説明することで、コードがより自然になっていく。 この技法は思っているよりも簡単だが、非常に強力である。 説明で使う単語やフレーズをよく見れば、分割する下位問題がどこにあるかが分かる。

問題や設計をうまく言葉で説明できないのであれば、何かを見落としているか、詳細が明確になっていないということだ。 プログラム(あるいは自分の考え)を言葉にすることで明確な形にすることができる。

まとめ

  • 今後は1行ドヤコードは避ける。(いわゆる「頭の良い」コードには気をつける)
  • 他の誰か(数ヶ月後の自分を含め)に読みやすいコードを心がける。
  • コードだけで会話できることを目標とし、本書のタイトル通り読めるコードを書けるよう研鑽する。

冒頭でも述べましたが、コーディングに関わる方々は一読の価値ありです。
普遍的かつ不変的な内容なため、30歳になる手前の比較的若い年齢で本書と出会えたことは、とても幸せなことであり、今後のスキルアップ/キャリアアップに役立ってくれると感じました。

GCI 社会人向け Data Science Online Course 2週目の感想

f:id:taxa_program:20181111113255p:plain

第3期社会人向け Data Science Online Courseコースの2週目を終えました。

今週学んだことをアウトプットしていきます。


スケジュール
第1回(11/5): Numpy、Scipy、Pandas、Matplotlibの基礎
第2回(11/12):記述統計学と単回帰分析 ← Now!!
第3回(11/19):確率と統計の基礎
第4回(11/26): Pythonによる科学計算の基礎(NumpyとScipy)
第5回(12/3): Pandasを使ったデータ加工処理
第6回(12/10): Matplotlibを使ったデータ可視化
第7回(12/17):データベースとSQLの基礎
第8回(12/24): データベースの応用(高度なSQL処理と高速化)
第9回(1/7):ドキュメント型DB(MongoDB)
第10回(1/14):機械学習の基礎(教師あり学習
第11回(1/21): 機械学習の基礎(教師なし学習
第12回(1/28): モデルの検証方法とチューニング方法
第13回(2/4): データサイエンスティスト中級者への道


記述統計と推論統計

統計解析とは、データを客観的に分析し、そのデータに含まれる傾向を明らかにする方法。
その手法は、下記「記述統計」「推測統計」に大きく分かれる。

記述統計

集めたデータの特徴をつかんだり分かりやすく整理したり見やすくしたりする方法。

たとえば、平均や標準偏差などを計算してデータの特徴を計算したり、データを分類したり、図やグラフなどを用いて表現したりするのが記述統計。

推論統計

集めたデータから推論する方法。

たとえば、日本の全人口の年齢別の身長を調べたいとします。全員の身長を調べるのは困難です。そこでランダムな抽出した一部の人たちだけを対象に身長を調べ、そこから母集団である日本人の身長は、どのようなのかを推論します。

このように、部分的なデータしかないものから確率分布に基づいたモデルを用いて精密な解析をし、全体を推論して統計を求めるのが、推論統計の考え方。
推論統計は過去のデータから未来予測するときにも使われている。

量的データと質的データ

データは基本的に、量的データと質的データの2つに分けることができる。

  • 量的データ
    四則演算を適用可能な連続値で表現されるデータであり、比率に意味がある。例)人数や金額などのデータ。

  • 質的データ
    四則演算を適用不可能な不連続のデータであり、状態を表現するために利用される。例)順位やカテゴリなどのデータ。

記述統計

変動係数

例えば、株価(日経平均など)の標準偏差と為替(ドル円など)の標準偏差をそれぞれ計算するとします。この2つの標準偏差を直接比較するのはナンセンスですよね。なぜなら2万円前後で動いている日経平均と100円前後で動いている為替の標準偏差とでは、スケールが異なるからです。

そこで登場するのが変動係数なるもの。
変動係数は、標準偏差を平均値で割った値です。この値を使うとスケールに依存せず、比較できるようになります。

共分散

2つの変数の関係性を見るための値です。

共分散は、2組の対応するデータ間での平均からの偏差の積に関する平均値です。
2変数以上の分散を考えるときに使われます。Numpyには共分散の行列(共分散行列)を算出する機能があり、次のようにcov関数を使うと求められます。

# 共分散行列
np.cov(df['G1'], df['G3'])

共分散は偏差の積の期待値なので

  • 共分散が大きい(正)→XXが大きいときYYも大きい傾向がある
  • 共分散が00に近い→XXとYYにあまり関係はない
  • 共分散が小さい(負)→XXが大きいときYYは小さい傾向がある

という関連性がある。

相関係数

共分散はその定義式から、各変数のスケールや単位に依存してしまいます。そのスケールの影響を受けずに、2つの変数の関係を数値化するのが相関係数です。共分散をそれぞれの変数(ここではxxとyy)の標準偏差で割った数式が相関係数です。

相関係数は、-1から1までの値を取り、1に近ければ近いほど正の相関があるといい、-1に近ければ近いほど負の相関があるといいます。0に近い場合は、無相関であるといいます。

単回帰分析(推論統計)

線形単回帰分析

単回帰分析のうちでも、アウトプットとインプットが線形の関係に成り立つ(y=ax+b)ことを前提としものを線形単回帰という。 下記例のfit関数は、最小二乗法という手法で回帰係数aと切片bを計算してくれる。

from sklearn import linear_model

# 線形回帰のインスタンスを生成
lr = linear_model.LinearRegression()

# 説明変数
X = '説明変数を格納'

# 目的変数
Y = '目的変数を格納'
 
# 予測モデルを計算、ここでa,bを算出
lr.fit(X, Y)
 
# 回帰係数
print("回帰係数:", lr.coef_)
 
# 切片 
print("切片:", lr.intercept_)

決定係数

回帰係数と切片は分かったが、これが客観的にどうなのか判断するのは難しい。 これを数値化したものを決定係数(寄与率)といいます。

これは0から1までの値を取り、1に近ければ近いほど良いモデルになります。Pythonを使って決定係数を求めるには、scoreを使って以下のようにすることで求めることができる。

# 決定係数、寄与率とも呼ばれる
print("決定係数:", clf.score(X, Y))

exam(今週の提出課題)

提出課題については

「とあるデータを利用して単回帰分析を実施し、決定係数を求めてください。」

というものでした。

所感

今週の講座に要した時間は、問題/課題も含め2時間〜3時間程度でした。

今まで勉強してきたことを丁寧に復習できている感じがして、自分にとってとても有意義な講座になっています。

あと、中の人達ガンバレ!

GCI 社会人向け Data Science Online Course 1週目の感想

f:id:taxa_program:20181111113255p:plain

現在、11月5日より開講されました東京大学グローバル消費インテリジェンス寄附講座
第3期社会人向け Data Science Online Courseコースを受講しています。

そこでの所感や学びなどを書いてみようと思います。
現段階では1週間毎(課題が提出される頻度に合わせて)に記事としてまとめていければと思っていますが、
何が起きるか分からない御時世のため、更新頻度は変更される可能性が高いです。

東京大学グローバル消費インテリジェンス寄附講座って何?ってかたはこちらをご参照ください。

この記事が、この講座を気になっている方の意識決定などに少しでも役に立てば幸いです。


スケジュール
第1回(11/5): Numpy、Scipy、Pandas、Matplotlibの基礎 ← Now!!
第2回(11/12):記述統計学と単回帰分析
第3回(11/19):確率と統計の基礎
第4回(11/26): Pythonによる科学計算の基礎(NumpyとScipy)
第5回(12/3): Pandasを使ったデータ加工処理
第6回(12/10): Matplotlibを使ったデータ可視化
第7回(12/17):データベースとSQLの基礎
第8回(12/24): データベースの応用(高度なSQL処理と高速化)
第9回(1/7):ドキュメント型DB(MongoDB)
第10回(1/14):機械学習の基礎(教師あり学習
第11回(1/21): 機械学習の基礎(教師なし学習
第12回(1/28): モデルの検証方法とチューニング方法
第13回(2/4): データサイエンスティスト中級者への道


受講までの流れ

応募フォームから各種情報を入力し、応募するだけの簡単な作業です。
自分はこの講座の存在をTwitterで知りました。

今回は第3期生の募集ということで、この講座の存在もある程度周知されていた?のか
応募者数が受講可能人数を大幅に上回っていたようで、人数絞り込みのPythonテストが事前にありました。
(Numpyに関する知識を測るもので、決して難しい問題ではありませんでした)

上記抽選も無事通過し、受講する機会を獲得できました。

講座の歩み方

iLectというプラットフォーム上で一人一つインスタンスがセットアップされます。
このプラットホーム上で講義の資料や課題などが公開され、受講者はこの講義資料を参考に課題を解いていきながら知識を身につけていきます。
Webブラウザが動作する環境であれば受講可能だと思いますが、ローカルでjupyter環境を構築しておいた方がいろんなことが試せて良いと思います)

また、週に1度、1時間、運営側とのオンライン質問会が開催されます。
(今週は開催通知メールが届いていなく、参加することができませんでした・・・)

こちらに関しては、次回参加できたら雰囲気などお伝えできればと思います。

Chapter1

Chapter1では、本講座の概要とpython/jupyterの基礎知識などを学ぶことができました。

途中でクラスとインスタンスについて説明があるのですが、たい焼き機の例が出てきて
懐かしいなぁと思いました。

http://image.itmedia.co.jp/ait/articles/0803/12/r801.gif

講座を受ける前からpythonの勉強や、現職がSEということもあり、そこまで目新しい知識はありませんでしたが、初学者の方にとっても取り組みやすい内容だったのではないかと思います。

この章の総合問題に素数判定プログラムを作成してみる、というものがあり
pythonN ** 0.5とすると平方根が求められることを知りました。

Chapter2

Chapter2では、科学計算、データ加工、グラフ描画ライブラリの使い方を学ぶことができました。
主に各ライブラリについて、基本的な使い方を学習できます。

  • Numpy
  • Scipy
  • Pandas
  • Matplotlib

この章の総合問題は乱数を発生させる方法を使って、円周率を求めるプログラムを作成する(モンテカルロ法というものだったのですが、これがなかなか難しかった印象です。

また、Chapter1で出てくる問題の解答は配布されていますが、なぜかChapter2で出てくる問題の解答は配布されていません。
(運営さん、各章の解答を配布していただけると幸せになる人がたくさんいると思います)

exam(今週の提出課題)

提出課題については、

「ある行列について、これをインプットデータとして、その行列式を返り値とする関数を作成してください。」

というものでした。

解答は載せられませんが、Scipyを用いれば比較的簡単に解けるのではないかと思います。

所感

今週の講座に要した時間は、問題/課題も含め4時間〜5時間程度でした。
今の所は問題なくついていけそうです。