プロクラシスト

今日の寄り道 明日の近道

【Day-10】Cross Validationとパラメータサーチでモデルの調整

f:id:imslotter:20171210183652p:plain

データ分析ガチ勉強アドベントカレンダー 10日目。

  • データを集め、前処理を行い、学習をする。
  • どういう学習器が良いのかの評価基準

の勉強までできた。でも、データがあって、評価基準がわかっていても、どうやって評価すればいいかについてはまだあまり触れていない。

もうちょっと具体的に言うと、データと学習器があって、どういう風に教師データとテストデータを分ければいいのか。この方法について、実はまだ何も言っていない。

そこで登場するのが、sklearn.model_selection

いよいよ最後の仕上げ。良い学習器、良いパラメータの探り方について学ぶ

Validationとは

モデルを作ってデータを分析する際、データをtrain data, validation data, test dataに分ける。 最終的なテストをする前に、訓練データの中を分割してテストを回すことで、パラメータ調整を行うために用いられる。

sklearnでは、originalデータをtrainとtestに分けるところをsklearn.model_selection.test_train_splitで行い、Validationデータに分けるところにもsklearn.model_selection.cross_val_scoreなどが用意されている。

また、それにしたがって学習器のパタメータを変えながら評価していく仕組みも用意されていて、sklearn.model_selection.GridSearchCVで実現される。(後述)

skleanのCross Validation

cross_val_score

sklearnで最も簡単にCross Validationをするには、cross_val_scoreという関数を用いる。

`cross_val_score(clf, data, target, cv=5, scoring="accuracy")`
変数 役割
clf 学習器
data データ
target ラベル
cv クロスバリデーションの回数
scoring 評価する指標(参照:metrics)

scoringには、下記の値を用いることができる。

['accuracy', 'adjusted_rand_score', 'average_precision', 
'f1', 'f1_macro', 'f1_micro', 'f1_samples', 'f1_weighted', 'neg_log_loss', 
'neg_mean_absolute_error', 'neg_mean_squared_error', 'neg_median_absolute_error', 
'precision', 'precision_macro', 'precision_micro', 'precision_samples', 'precision_weighted', 
'r2', 'recall', 'recall_macro', 'recall_micro', 'recall_samples', 'recall_weighted', 
'roc_auc']

各評価値が何なのかを詳しく知りたい方は、Day9を参照

出力は、cvの回数分の、評価値の配列となっている。例として、digitsデータをRandomForestで取り扱ってみる。

from sklearn.datasets import load_digits
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
digits = load_digits()
clf = RandomForestClassifier()
scoring = "f1_macro"
scores = cross_val_score(clf, digits.data, digits.target, cv=5, scoring=scoring)
print("{}:{:.3f}+/-{:.3f}".format(scoring, scores.mean(), scores.std()))

結果

f1_macro:0.901+/-0.031

pipline

cross validationを行う際に、sklearn.pipelineを使うと、処理が簡潔に書ける。(参考)

例 : 正規化した後の効果をcross_validationしたい

# 通常
from sklearn import preprocessing
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, train_size=0.8)
scaler = preprocessing.StandardScaler().fit(X_train)
X_train_transformed = scaler.transform(X_train)
clf = SVC(C=1).fit(X_train_transformed, y_train)
X_test_transformed = scaler.transform(X_test)
print(clf.score(X_test_transformed, y_test))
# pipeline
from sklearn.pipeline import make_pipeline
# 処理を流す順に関数を書いていく
scoring = "f1_macro"
clf = make_pipeline(preprocessing.StandardScaler(), SVC(kernel="linear",C=1))
scores = cross_val_score(clf, digits.data, digits.target, cv=5, scoring=scoring)
print("{}:{:.3f}+/-{:.3f}".format(scoring, scores.mean(), scores.std()))

pipelineを使うと、複数処理を一括でCVにかけられるので、とてもよい。

cross_validate 関数

sklearn 0.19.1から、cross_validateが用意された。

さっきまでのがcross_val_scores関数。ややこしいが少し違う

  • 評価に複数の指標を考慮できる
  • テストスコアに加えて、学習の時のスコア、学習時間、テストの時間などを算出してくれる。

つまり、より強力なcross validationを行える。

from sklearn.model_selection import cross_validate
from sklearn.metrics import recall_score
from sklearn.svm import SVC
scoring = ["f1_macro", "recall_macro"]
clf = SVC(C=1)
scores = cross_validate(clf, digits.data, digits.target, scoring=scoring, cv=5)
for key,value in scores.items():
    print("{}:{:.2f}+/-{:.2f}".format(key, value.mean(), value.std()))

結果はこちら

fit_time:0.51+/-0.01
score_time:0.12+/-0.00
test_f1_macro:0.50+/-0.04
train_f1_macro:1.00+/-0.00
test_recall_macro:0.45+/-0.04
train_recall_macro:1.00+/-0.00

Validation iterators

CrossValidationを行うときの、データセットの分け方にも、いろんなバリエーションがある。 sklearn.model_selection内には、いろんなCVの分け方の方法が載っている。

  • i.i.d data
    • K-fold
    • Repeated K-Fold
    • Leave One Out (LOO)
    • Leave P out (LPO)
    • Shuffle & Split
  • iterators with stratification based on class labels(サンプリングとか)
    • Stratified k-fold
    • Stratified Shuffle Split
  • Grouped data i.i.dデータと基本おなじ

代表的なのが、K-Fold法とLeave One Out法。両者を図にするとこんな感じ

今回は、K-Fold法でのCrossValidationを実装してみる

import numpy as np
from sklearn.model_selection import KFold
from sklearn.datasets import load_digits
from sklearn.metrics import accuracy_score
# K-Fold交差検定
iterater = KFold(n_splits=5)
results = []
for train_indexes, test_indexes in iterater.split(digits.data):
#     print(train_indexes, test_indexes)
    X = digits.data[train_indexes]
    y = digits.target[train_indexes]
    clf = RandomForestClassifier()
    clf.fit(X,y)
    pred_y = clf.predict(digits.data[test_indexes])
    ac = accuracy_score(digits.target[test_indexes], pred_y)
    results.append(ac)
results = np.array(results)
print("KFold accuracy: {:.2f}+/-{:.2f}".format(results.mean(),results.std()))

出力

KFold accuracy: 0.90+/-0.04

パラメータを調整する

機械学習は複雑なので、モデルの持つパラメータをどのように調節すべきか難しい。

sklearnでは、下記の方法でパラメータ探索が行えるようになっている(参考 : Tuning the hyper-parameters of an estimator)

  • グリッドサーチ : パラメータを総当り式で調べる
  • ランダム選択 : ランダムにパラメータをサンプリングして試す
  • モデルに合わせた賢いCV*1

他に、変数最適化の問題として、ある指標を評価関数にして解くというのもよさそう。Gaussian Process Optimizationなどがよさげ (参考)

今回は、グリッドサーチでの方法を載せる

パラメータ

SVCのパラメータである、C, kernel, その他変数について調整する。調整する パラメータは下記のように、キーとリストで保持する。

param_grid = [
    {'C': [1, 10, 100, 1000], 'kernel': ['linear']},
    {'C': [1, 10, 100, 1000], 'kernel': ['rbf'], 'gamma': [0.001, 0.0001]},
    {'C': [1, 10, 100, 1000], 'kernel': ['poly'], 'degree': [2, 3, 4], 'gamma': [0.001, 0.0001]},
    {'C': [1, 10, 100, 1000], 'kernel': ['sigmoid'], 'gamma': [0.001, 0.0001]}
    ]

関数にはsklearn.model_selection.GridSearchCVを用いる。引数は

  • 学習器のインスタンス(今回はSVC)
  • パラメータグリッド(上記param_grid)
  • cv : cross validationの回数
  • scoring : 評価する指標

実装

実装は下記の通り

from sklearn.model_selection import GridSearchCV
import pandas as pd
clf.get_params()
svc = SVC()
scoring = "f1_macro"
param_grid = [
    {'C': [1, 10, 100, 1000], 'kernel': ['linear']},
    {'C': [1, 10, 100, 1000], 'kernel': ['rbf'], 'gamma': [0.001, 0.0001]},
    {'C': [1, 10, 100, 1000], 'kernel': ['poly'], 'degree': [2, 3, 4], 'gamma': [0.001, 0.0001]},
    {'C': [1, 10, 100, 1000], 'kernel': ['sigmoid'], 'gamma': [0.001, 0.0001]}
    ]
clf = GridSearchCV(svc, param_grid,cv=4)
clf.fit(digits.data, digits.target)
df = pd.DataFrame(clf.cv_results_)
df_scored = df.sort_values(by=["rank_test_score"])[["params","mean_test_score","std_test_score","mean_fit_time"]]

結果を見る

結果は、pandasのデータフレームに保管可能になっていて、簡単に好きな値でソートができる。今回はテストスコアの良い順にソートを行ってみた。(pandasの扱いが苦手な人はDay4をご覧ください)

こんな風に、どういうパラメータがどういう結果だったかが保存されているので、より良いパラメータを選ぶことができる。

まとめ

今日は学習器の調整に重要なCross Validationとパラメータサーチの方法について触れた。 実際の業務の場では、パラメータを調整する機会もとても多いので、知っておくと良い。また、少し述べたが、もう少し効率的なパラメータ調整方法についても勉強しておきたい。

機械学習の一連の流れがコレでざっと洗えたと思う。明日はscikit-learnのチートシートについてでも触れようかな。明日もお楽しみに!

*1:ドキュメントによればあるらしい...?

【Day-9】機械学習で使う指標まとめ(実装編)

f:id:imslotter:20171209195625p:plain データ分析ガチ勉強アドベントカレンダー 9日目。

データを学習器に入れるところまではできた。後は学習させるだけ! だが、学習器といってもたくさんある。どういう学習器を選べばよいのだろうか。

そのためにはモデルをうまく評価するしくみを作らなければならない。 今回は、sklearn.metricsを見ながら、学習の評価をどのように行うかについて学ぶ

機械学習に使う指標総まとめ(教師あり学習編)

学習器の評価には、さまざまな指標が用意されている。 以前、教師あり学習については全力でまとめている。なので、そちらを見ていただければと思う。

www.procrasist.com

しかし、こちらの記事では、数式も多く、実感もわかないだろう。なので今回はこの中の指標の実装も行ってみる。

sklearn.metricsによる定量指標

sklearn.metricsには、たくさんの指標が用意されている

分類の定量指標

先ほどの分布を分類した結果を評価したい。参考にしたのはこちらの公式ページ。 用意するものは、下記のものである。カッコ内は私が実装で用いた変数

  • テストデータの正解ラベル(y_test )
  • 学習器が判定した結果(pred_y )
  • そのときの判定スコア(pred_y_score)※

※判定スコアは、必要な指標と必要でない指標がある。使わない指標は、ただ分類結果だけをみて判定するのでわかりやすい。一方で判定スコアを使う場合は、指標がすこしわかりにくくなる一方で、いわゆる分類器の自信を考慮しながらの算出となるので、より詳細に分類器を評価している。

ここで、sklearn.metricsに入っている主要な分類指標を見てみる

クラス 分類指標 判定スコアの
使用
備考
confusion matrix -- なし 実際と予測のずれ具合を見る
accuracy Accuracy なし どのくらいあたったか
classification_report f値, recall, precision なし よく使う指標をまとめてくれてて良い
hamming_loss hamming loss なし f:id:imslotter:20171209182300p:plain
jaccard_similarity jaccard類似度 なし f:id:imslotter:20171209182351p:plain
log_loss logarithm loss あり 使い方あんまり自信がない公式
precision_recall_curve precision-recall曲線 あり トレードオフ具合をみる
roc_auc ROC曲線 あり 閾値判定とか

よく使いそうだなと思ったのが、accuracy. classification_report. roc_auc。主要な指標がきれいにまとまっている

sklearn.datasets.load_breast_cancer()の学習を簡易的に行い、上記の3つの指標の入力の仕方と出力の仕方を学ぶ。

コードをみる
import matplotlib.pyplot as plt
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn import metrics
breast_cancer = load_breast_cancer()
clf = LogisticRegression()
X_train, X_test, y_train, y_test = train_test_split(breast_cancer.data, breast_cancer.target,train_size=0.8)
clf.fit(X_train,y_train)
# 結果を返す
pred_y = clf.predict(X_test)
# スコアを出すための関数。
# ref : [decision_functionとの違いは?](https://stackoverflow.com/questions/36543137/whats-the-difference-between-predict-proba-and-decision-function-in-sklearn-py)
pred_y_score = clf.predict_proba(X_test)[:,1]
print("accuracy\n", metrics.accuracy_score(y_test, pred_y))
print("classification report\n",metrics.classification_report(y_test,pred_y))
# Compute ROC curve and ROC area for each class
fpr, tpr, _ = metrics.roc_curve(y_test, pred_y_score,pos_label=1)
roc_auc = metrics.auc(fpr, tpr)
print("auc area", roc_auc)
# ROC
plt.figure(figsize=(5,5))
plt.plot(fpr, tpr, color='darkorange', lw=2, label='ROC curve')
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC curve: \nAUC={:.3f}'.format(roc_auc))
plt.show()

結果はこんな感じ

f:id:imslotter:20171209184215p:plain

回帰の定量指標

正解が数値で与えられる回帰にも、いくつか指標がある。これもsklearn.metrics内で実装されている。

sklearn.datasets,load_bostonデータセットを使って、試してみる

コードをみる
from sklearn.datasets import load_boston
from sklearn.linear_model import LinearRegression
from sklearn import model_selection, metrics
import numpy as np
boston = load_boston()
reg = LinearRegression()
X_train, X_test, y_train, y_test = model_selection.train_test_split(boston.data, boston.target,train_size=0.8)
reg.fit(X_train,y_train)
pred_y = reg.predict(X_test)
print("Variance score", metrics.explained_variance_score(y_test, pred_y))
print("MAE : Mean absolute error", metrics.mean_absolute_error(y_test, pred_y))
print("MSE : Mean squared error", metrics.mean_squared_error(y_test, pred_y))
print("RMSE: Root mean squared error", np.sqrt(metrics.mean_squared_error(y_test, pred_y)))
print("R2 score", metrics.r2_score(y_test, pred_y))

出力は

Variance score 0.637022922972
MAE : Mean absolute error 3.16480595297
MSE : Mean squared error 19.7557043856
RMSE: Root mean squared error 4.44473895584
R2 score 0.633791811542

クラスタリング定量指標

Evaluating the performance of a clustering algorithm is not as trivial as counting the number of errors or the precision and recall of a supervised classification algorithm. (clustering performance evaluation)

とあるように、クラスタリングこそ絶対的な定量指標が存在しない。分け方なので、用途や意味によって変わってくるから。 けれど、一応指針みたいなのはあって、クラスタ内の散らばりの少なさクラスタ間の距離の長さをうまく定式化することで、定量化する。

上記サイトにはクラスタリングの指標も多数実装されている。*1

デモ実装(分類学習器ごとの差)

最後にデモを作る。

この図は、三日月形に分布するデータを分類しようとした結果を分類器別に分けてみたものである。 *2

線形、非線形、アンサンブル学習など、学習器の性質によってかなり異なることが見て取れて面白い。

こうやって分離状況を可視化していくと、大体どういう雰囲気で学習器が分布しているかはわかる。 でも、それでは定量的な指標とはいえない。ので、先ほどまでの指標を見て、定量化してみた

詳細は例のごとくgithubにあげている。

github.com

結果1(表)

大きく結果の順位が変わるようなことはないが、精度だけじゃなく、precisionとrecallなどを見ると開きがあるもの、ないものなど違いがあったりして、分類器の個性を詳細に知ることができる。

Algorithm accuracy precision recall f1-score ham. loss jaccard sim AUC
LogisticRegression 0.83 0.82 0.83 0.82 0.17 0.83 0.92
Nearest Neighbors 0.95 0.91 1 0.95 0.05 0.95 0.95
Linear SVM 0.8 0.8 0.77 0.79 0.2 0.8 0.92
RBF SVM 0.94 0.89 1 0.94 0.06 0.94 0.98
Gaussian Process 0.95 0.91 1 0.95 0.05 0.95 0.98
Decision Tree 0.92 0.92 0.92 0.92 0.08 0.92 0.92
Random Forest 0.89 0.88 0.9 0.89 0.11 0.89 0.93
Neural Net 0.83 0.82 0.83 0.82 0.17 0.83 0.92
AdaBoost 0.86 0.84 0.88 0.86 0.14 0.86 0.92
Naive Bayes 0.82 0.81 0.81 0.81 0.18 0.82 0.92
QDA 0.83 0.82 0.83 0.82 0.17 0.83 0.92

結果2(図)

代表的な3種の分類器でROC曲線とPrecision-Recall曲線を引いた。 両者とも、トレードオフのグラフになっているので、覆われた領域の面積が大きいほど、いい分類器であるといえる。 今回のデータに対しては、非線形分類器に軍配が上がりそうだ。

まとめ

以前まとめていた指標、理論ではわかっていても実際に使って動きをみてみると、知識として定着する。 いろいろと指標はあるが、sklearn.metricsを用いれば簡単に実装が可能なので、勉強したい方は是非一度手を動かしてみてはいかがでしょうか。

ちょっと長くなりましたが、今日はこの辺で。 明日はモデル選択(Cross Validation)とパラメータサーチ!

*1:余裕があれば加筆します...w

*2:Classifier Comparisonを一部改変してつくった

【Day-8】絶望的なデータを前処理で何とかする。(pandas/sklearn)

f:id:imslotter:20171208163632p:plain データ分析ガチ勉強アドベントカレンダー 8日目。

Day-7の記事で、データを取り扱えるようになりました。 しかし、データがいつもきれいで美しいものだとは限りません。なかには絶望的なデータもたくさんあります。

機械学習等の学習器に投げ入れるには、もうひと工夫いることのほうが多いです。 pandassklearnで、できる工夫、前処理についてまとめて行きます

前処理とは

学習の流れを簡単な図にまとめてみる。

データ分析の労力の7~8割は、↑図の赤の部分、前処理といわれている。 適当に学習器に投げ入れたデータよりも、きちんと温かみをもって処理をすることが大事。*1

データをうまく整形することで精度が大きく変わってくるので、試行錯誤で調整を繰り返すことが多い。

ひとくちに前処理といってもデータの質、型(数値、カテゴリ変数、画像、自然言語)、仮定する分布などで大きく変わるので、一概には言えない。下記スライド(英語)は前処理について詳しく書かれていて、大変勉強になった。

絶望的なデータの入手

たとえば、avent-calendar-2017リポジトリにある、day8-sample.csvを読み込んでみる。

import pandas as pd
df = pd.read_csv("day8-sample.csv", index_col="name")
df

すると、絶望的なデータを手に入れることができる。

     height weight
name              
A     160cm   49kg
B     170cm   37kg
C     1.81m     80
D       NaN   50kg
E     1.90m     80
F     170cm    NaN
G     150cm     40

単位が違う、、単位がない、、、NaN。。。 実際、こんなデータがたくさん入っていたりする。本当はオペレーションのレベルで何とかしておけばこんなことは起こらないはずだが、データを集めているヒトが必ずしも情報技術者というわけではない。めんどくさいが、せむかたなし。

データを統一的な型(数値等)に変換(df.apply)

こういうデータを、学習器に投げるための形にもっていくのが、まず始めに行う前処理である。pandasを使えば、比較的楽に処理が可能。

【Day-4】都道府県のデータをいじりながら、pandasを学ぶにて、pandasについて触れた。 ここで、緯度経度を60度法から数値に変換するという処理をしたが、これも前処理のひとつである。 自分で関数を書いてpandasのapply関数を使うと、処理が簡単に行えるので良い。(詳しくはDay-4)

データを眺めると、単位で場合わけしながら、cmとkgに統一した数値データにするのがよさげ。なので、関数を作る。少し雑だが、cm,m,kgなどをうまく除去するように場合わけをする。

def height_to_num(height):
    if type(height)==float:
        return height
    if "cm" in height:
        height = float(height[:-2])
    if (type(height)!=float) and ("m" in height):
        height = float(height[:-1])
        height *= 100
    return height

def weight_to_num(weight):
    if type(weight)==float:
        return weight
    if  (type(weight)!=float) and ("kg" in weight):
        weight = weight[:-2]
    return float(weight)

この関数を全部のindexに適用するのが、apply関数である。次のようにすると、各カラムにさっき作った関数が実行される

df["height"] = df.height.apply(height_to_num)
df["weight"] = df.weight.apply(weight_to_num)
print(df)

出力

      height weight
name               
A      160.0     49
B      170.0     37
C      181.0     80
D        NaN     50
E      190.0     80
F      170.0    NaN
G      150.0     40

数字がきれいに扱えるようになった。

NaNの除去

これで全部統一的なデータ形式にできた。あと厄介なのがNaN(空白)の取り扱い。これをそのまま学習器に代入するとエラーが出る。sklearnでもpandasでも可能である。両方やってみる pandasの場合、下記の三種類がある

  • df.dropna() : NaNのある行を除去
  • df.fillna() : NaNをある値で埋める
  • df.interpolate() : NaNを前後の値から補間

df.dropna()

print(df.dropna(how="any"))

実行すると、

      height  weight
name                
A      160.0    49.0
B      170.0    37.0
C      181.0    80.0
E      190.0    80.0
G      150.0    40.0

このように、ひとつでもNaNが入っているindexは消える。 dropna()内の引数で、消し方を決められる。how="all"だと、すべてNaNのindexだけ消すといった具合になる。 詳しくはこちら

df.fillna()

値を埋める。0で埋めてもいいが、たとえばそのほかの値の統計値を使って埋める。なども可能。今回は平均(mean)で埋めてみる

df.height = df.height.fillna(df.height.mean())
df.weight = df.weight.fillna(df.weight.mean())
print(df)

出力は

name                    
A     160.000000    49.0
B     170.000000    37.0
C     181.000000    80.0
D     170.166667    50.0
E     190.000000    80.0
F     170.000000    56.0
G     150.000000    40.0

ふむふむ、無事平均値で埋まったようだ。ほかにも中央値で埋めるなど、無難な値で埋めることができる。

df.interpolate()

値を近似して補間してしまう方法。indexが意味を持つとき(たとえば時系列などにはよく用いられるが、名前のような、カテゴリカルなときは用いてもあまり意味を成さない。けど、練習のためやってみる。

print("orig\n",df.height.values)
print("interpolate\n",df.height.interpolate(method='linear').values)

interpolateを行った後は、

orig
 [ 160.  170.  181.   nan  190.  170.  150.]
interpolate
 [ 160.   170.   181.   185.5  190.   170.   150. ]

となり、method="linear"では線形補間が行われたことがわかる。

なお、methodには、いろんな補間形式がある。公式ページに補間の方法とまとめが載っているので、参考にするといいだろう。

また、sklearn.preprocessing.imputerでも、欠損値補間はできるようだ。(Imputer)

その他

そのほかにも、回帰代入法など、NaNを埋める方法はたくさんある。データの特徴をみながら、どういう埋め方が良いのかを判断すると良い。

スケーリング

これですべて数値で埋まった値が帰ってきたが、身長と体重で絶対値が違う。こういうデータの大きさ、形状を調節して同じような大きさにするほうが、うまくいく(ことが多い)。これをスケーリングという。

sklearn.preprpcessingには、スケーリングを行う関数が多く実装されている。 sklearn.preprocessing(公式ページ)

StandardScaler

各カラムの値を、平均0、標準偏差1の分布に変えてしまう。データが普通の分布(正規分布っぽい分布)をしているときなどはコレを用いることが多い。skelarn.preprocessing.StandardScalerを用いる。

# standard scaler
# スケールの取り出し(新しいデータが来たときに、固定された正規化定数で対応が可能)
scaler = preprocessing.StandardScaler().fit(df)
# スケールを出す
print("mean:{} std:{}".format(scaler.mean_,scaler.scale_))
# スケーリングを行う
df_scaled = scaler.transform(df)
print(df_scaled)

出力

mean:[ 170.16666667   56.        ] std:[ 12.07614729  16.27443218]
[[-0.84187998 -0.43012253]
 [-0.01380131 -1.16747545]
 [ 0.89708523  1.47470583]
 [ 0.         -0.36867646]
 [ 1.64235603  1.47470583]
 [-0.01380131  0.        ]
 [-1.66995865 -0.98313722]]

基本的には、

  • scaler = preprocessing.hogehoge().fit(df) で、それぞれのアルゴリズムによるデータのスケーリング定数を算出
  • scaler.hoge_で、スケーリング定数を取り出す
  • sceler.transform(df) で、スケーリングした配列を出力

という設計になっている。hogehoge,hogeは各アルゴリズムによって変わってくる

MinMaxScaler

これも良く使うスケーリング方法で、最低が0、最高が1にスケーリングする。StandardScalerとほとんど同じだが、係数が少し変わってくる

# min-max scaling
scaler = preprocessing.MinMaxScaler().fit(df)
print("max:{}, min:{}".format(scaler.data_max_, scaler.data_min_))
print("SCALED")
print(scaler.transform(df))

出力

max:[ 190.   80.], min:[ 150.   37.]
SCALED
[[ 0.25        0.27906977]
 [ 0.5         0.        ]
 [ 0.775       1.        ]
 [ 0.50416667  0.30232558]
 [ 1.          1.        ]
 [ 0.5         0.44186047]
 [ 0.          0.06976744]]

その他

preprocessingには、カーネル向けの前処理(KernelCenterer)や、多項式化(PolynomialFeatures)、バイナリ化(Binarizer)そのほかにもさまざまな前処理方法が用意されている。詳しくは公式ページを参照し、いろいろ試してみるのがいい。使い方は基本的に上記で示したとおり。

また、FunctionTransformerという関数を用いれば、sklearnの設計どおりに自分で特徴量変換関数を作ることができる。たとえば、データにlogをつけることも結構あったりするので、そういう変換関数を作る。

from sklearn.preprocessing import FunctionTransformer
# logを当てはめる
transformer = FunctionTransformer(np.log1p)
transformer.transform(df)

出力は

array([[ 5.08140436,  3.91202301],
       [ 5.14166356,  3.63758616],
       [ 5.20400669,  4.39444915],
       [ 5.14263774,  3.93182563],
       [ 5.25227343,  4.39444915],
       [ 5.14166356,  4.04305127],
       [ 5.01727984,  3.71357207]])

オレオレ特徴変換をしたいときは、こんなのもよさそう。

まとめ

手に入るデータがいつもきれいだとは限らない。というか、汚いぐちゃぐちゃなデータのほうが多い。 うまく変換する方法を知っておくことで、効率的に学習器にデータを投げることができる。

  • pandasのapply関数で、カラムごと一括処理
  • pandasのdropna, fillna, interpolateで、欠損値に対応
  • sklearn.preprocessingをうまく使って、データをいい具合に変換
  • 近年ではよく使うものは、前処理を済ませたデータを配ろうとする動きもあるみたいで、オープンソースとして提供しようとする試みもある。 このdataset.jpというところなどがそう。開発が滞っているっぽいので、活発になればうれしいな(面倒が減るな)とか思ってる。

    データ分析や機械学習に欠かせない「前処理」の共通化を目指したオープンソースが国内で発足|アイザック株式会社のプレスリリース

    以上、これで学習器に投げられるところまできた気がする。 明日は、良い学習器を選ぶためには?というお題で書きたい。

    *1:ディープラーニングの対等で、適当に投げてもかまわんという風潮もあるが、個人的には前処理は結果の説明のために必要だと思っている。

    【Day-7】sklearnで機械学習用データの作り方/使い方をまとめる(sklearn.datasets)

    f:id:imslotter:20171206182003p:plain データ分析ガチ勉強アドベントカレンダー7日目。 今日からはscikit-learnを取り扱う。

    機械学習の主要ライブラリであるscikit-learn(sklearn)。機械学習のイメージをつかみ練習するにはコレが一番よいのではないかと思われる。

    今日はデータを作って、(必要ならば)変形し、モデルに入力するまでをまとめる。

    • 既存データへのアクセスの仕方
    • ある程度狙ったランダムデータを作る方法
    • modelに入力する際、どういう構造でデータを入れるかについて。

    基本的にはDataset loading utilitiesを参考にしながら。 いくつかデータセットをピックアップして、実際に扱ってみる。

    なお、今回はsklearn.datasetsをふんだんに用いるので、はじめに下記コマンドを読み込んでおく。

    from sklearn import datasets
    

    Toy Dataset

    datasets.load_hogehoge()という関数により、データを使うことができる。

    感覚をつかむために用意されたデータセット。簡単に使えるが、デー多数は少なく、学習器の性能をテストするには完全な量ではない。

    スペック

    dataset どういうデータか データ数 次元 特徴量の型 正解ラベル
    load_boston ボストンの家賃 506 13 正の実数 実数
    load_iris アヤメの分類 50×3クラス 4 正の実数 3クラス
    load_diabetes 糖尿病患者の進行状況 442 10 -2<x<2 25~346の整数
    load_digits 8×8ピクセルの数字データ (約)180×10クラス 64 0~16の整数 0から9まで
    load_linnerud 男性の生理学的特徴と運動能力の関係 20 3 整数 整数
    load_wine ワインを3種類に分類 [59,71,48]=178 13 正の実数 3クラス
    load_breast_canser 乳がんの陰性/陽性判定 [212,357]=569 30 正の実数 2クラス

    データの形式

    正解ラベルが実数かクラスかによって、正解データの利用の仕方が回帰か分類かに分かれる。

    ざっくり回帰は、次の値を予測する、分類は、そのデータがどのクラスに属するかを判定する。正解ラベルが実数ならばその値自身に意味があるが、クラス(1,2,3など)ならば、その値自身には意味がない(カテゴリ変数とも呼ばれる)

    先ほどの表で、正解ラベル次第でデータの保持形式が変わる

    正解ラベルが実数

    下記データを保持している

    • data : データに入っているベクトルの値
    • feature_names : 各要素の名前
    • target : 実数値

    (例:boston)

    data =  datasets.load_boston()
    print("data shape:", data.data.shape)
    print("feature name:",data.feature_names)
    print("target value:", data.target)
    

    出力

    data shape: (506, 13)
    feature name: ['CRIM' 'ZN' 'INDUS' 'CHAS' 'NOX' 'RM' 'AGE' 'DIS' 'RAD' 'TAX' 'PTRATIO' 'B' 'LSTAT']
    target value: [ 24.   21.6  34.7  ...  22.   11.9]

    正解ラベルがクラス

    下記データを保持

    • data : データに入っているベクトルの値
    • feature_names : 各要素の名前
    • target : クラス(カテゴリ変数)
    • target_names : クラスの名前
    data = datasets.load_iris()
    print("data shape:",data.data.shape)
    print("feature name:",data.feature_names)
    print("target class", data.target)
    print("class name:",data.target_names)
    

    出力

    data shape: (150, 4)
    feature name: ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
    target class [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2]
    class name: ['setosa' 'versicolor' 'virginica']

    シャッフル

    ちなみにこのままだと、データが0,1,2ときれいに並びすぎている。逐次学習のアルゴリズムのときなどは影響を受けてしまうので、sklearn.util.shuffleを用いるとよい

    from sklearn.utils import shuffle
    X, y = shuffle(data.data,data.target, random_state=0)
    print("target class", y)
    

    出力

    target class: [2 1 0 2 0 2 0 1 1 1 2 1 1 1 1 0 1 1 0 0 2 1 0 0 2 0 0 1 1 0 2 1 0 2 2 1 0 1 1 1 2 0 2 0 0 1 2 2 2 2 1 2 1 1 2 2 2 2 1 2 1 0 2 1 1 1 1 2 0 0 2 1 0 0 1 0 2 1 0 1 2 1 0 2 2 2 2 0 0 2 2 0 2 0 2 2 0 0 2 0 0 0 1 2 2 0 0 0 1 1 0 0 1 0 2 1 2 1 0 2 0 2 0 0 2 0 2 1 1 1 2 2 1 1 0 1 2 2 0 1 1 1 1 0 0 0 2 1 2 0]

    狙ったランダムデータを生成する

    ラベル付データ生成

    make_hogeを使えば、簡単にデータを生成することができる。hogeで表内囲まれているところは、パラメータで調節できるところ。

    dataset どういうデータか データ数 次元 クラス数 データ分布の調整
    make_blobs ガウス分布のデータ生成
    (重ならない)
    n_samples n_features centers cluster_std
    center_box
    make_classification n-class分類用データ生成
    (詳細設計可能)
    n_samples n_features n_classes 結構複雑
    詳細
    make_gaussian_quantiles 同心円状の分布を生成 n_samples n_features n_classes mean
    cov
    make_hastie_10_2 Hastie Exampleで用いられた分布 n_samples 10 2 -
    make_circles 円の分布 n_samples 2 2 factor
    make_moons 三日月形の分布 n_samples 2 2 -

    その他

    • shuffle(bool) : サンプルをシャッフルするかどうか。

    それぞれのデータの分布(イメージ)はこんな感じ

    f:id:imslotter:20171206190749p:plain

    マルチラベルデータ生成

    さっきのが、正解ラベルがひとつのラベルのとき。正解ラベルを複数持つデータについてはmake_multilabel_classificationにて生成が可能(詳細)。重要なパラメータは下記

    • n_samples, n_features : ↑と一緒
    • n_classes : クラスの数
    • n_labels : ひとつのデータに対するラベル付けするクラスの平均

    ひとつのデータに対して出てくる出力は下記のようになる

    data, target = datasets.make_multilabel_classification(n_samples=100, n_features=10, n_classes=5, n_labels=3)
    print("data:",data[0])
    print("label:",target[0])
    

    出力

    data: [  4.   2.   9.   3.   4.   5.   3.   6.   1.  10.]
    label: [0 1 1 0 0]

    1がついているのがそのデータについているラベル。

    その他

    そのほかにもbiclustering用のデータや、metrics learning用のデータなどもある

    • make_biclustering
    • make_s_curvemake_swiss_roll(xz平面に射影)

    fetchしてくる

    datasets.fetch_hoghogeで、外部リポジトリにあるデータを保持することも可能。普通にダウンロードに時間がかかるので、必要なときだけ保存するようになっている。下記のようなものがある。

    関数 説明
    datasets.fetch_20newsgroups() 自然言語のデータ、20個のニュースカテゴリに分ける。データ数は11314
    datasets.fetch_20newsgroups_vectorized() 上記の文章を単語に分けてベクトル化(13万次元くらい)
    datasets.fetch_california_housing() カリフォルニアの家の評価(正解値は実数)
    datasets.fetch_kddcup99() KDD99の侵入検知のコンペで用いられたデータ。詳細
    datasets.fetch_lfw_pairs() labeld face in the wild の略。同じ人か違う人かの二値分類詳細
    datasets.fetch_lfw_people() 人の名前を当てる分類問題
    datasets.fetch_mldata("hoge") "hoge"を変えれば、ここにあるデータを良しなにとってこれる
    datasets.fetch_olivetti_faces() AT&Tが作った、CV用データセット
    datasets.fetch_rcv1() Reuters Corpus Volumeの略。80万のデータ、約5万のワードベクトル、13のカテゴリ。マルチラベル
    datasets.fetch_species_distributions() species distributionのデータセット参考

    これも基本的には

    • data : データに入っているベクトルの値
    • feature_names : 各要素の名前
    • target : クラス(カテゴリ変数の場合)
    • target_names : クラスの名前

    がデータとして入っている。自然言語ベクトル化する前とかだったら微妙に違うこともあるが、だいたいはこういう配列なんだと思っていればOK。そんなに難しい構造していないので、ちょっと自分が作った学習器を試したいときに、データだけ呼ぶってのもいいと思う。

    学習させる

    データを用意できたので、最後にデータを投げるところまでまとめて終わりにする。 処理の仕方とか、まあ種々のデータのいじり方は後に回すとして、どうやって入力するかだけ。

    1. データをシャッフルして分割する(sklearn.model_selection.train_test_split)
    2. 学習させる(sklearn.ensemble.RandomForestClassifier)
    3. テストして評価する(accuracy)(sklearn.metrics.accuracy_score)

    取ってきたデータを いろんな学習器があるけれど、sklearnは入出力の関数/型が決まっている

    • model.fit(X,y) : モデルを学習する(教師なしの場合は、ラベルはいらないので、model.fit(X))
    • model.predict(X) : モデルからテストを行う

    irisのデータを読み込んで学習を行うところまでをやってみる

    from sklearn.model_selection import train_test_split
    from sklearn.ensemble import RandomForestClassifier
    from sklearn.metrics import accuracy_score
    
    # データの読み込み
    iris = datasets.load_iris()
    data, target = iris.data, iris.target
    # 学習とテストに分ける
    data_train, data_test, target_train, target_test = train_test_split(data, target, train_size=0.8, random_state=1) 
    # RandomForestを使う
    model = RandomForestClassifier()
    # 学習
    model.fit(data_train, target_train)
    # テストと評価
    target_pred = model.predict(data_test)
    print(accuracy_score(target_test, target_pred))
    

    出力

    0.966666666667

    できた。ランダムフォレスト強い

    まとめ

    今日はデータについてと、一度学習するところまでをまとめてみた。 sklearnのデータセットの形を知り、をうまく使いこなせれば、いろいろと幅が広がりそう。

    今日のコードも、上げているので是非試してみてください。

    github.com

    明日もsklearnの話題!最後に取り扱った学習のところをもうちょっと詳しく書く予定です。お楽しみに~

    【Day-6】ゼロからJupyterの達人に!使い方の総まとめ。

    f:id:imslotter:20171205234021p:plain

    こんにちは、ほけきよです。

    データ分析ガチ勉強アドベントカレンダー6日目。

    当ブログもJupyterに関するメモをたくさん記してきました。 今回は保存版ということで、Jupyterの基礎事項から、ちょっとしたTipsなどを総まとめしておきます。この記事を読めばJupyterの使い心地もかなりUPするでしょう。

    事始

    インストール方法、実際に一通り実行してみるところまで行える。

    www.procrasist.com

    コレだけは知っておくべきチートシート

    以前自分のQiitaで書いたものを+αして再掲。最低限知っておくとよいもの。

    起動

    jupyter notebook

    実行

    shift+Enter

    補完

    然るべきところでtab。そこまで強力でもない

    ショートカット

    最低限覚えておくべきショートカット

    ショートカット 役割
    esc+M マークダウンモード
    esc+Y コードモード
    esc+L 行番号表示
    esc+A セルを上に挿入
    esc+B セルを下に挿入
    esc+DD セルを削除

    % : マジックコマンド

    Jupyterをpythonインタプリタとしてではなくシェルとして扱えるもの。詳しくは公式を。

    Built-in magic command

    マジックコマンドには二種類あって、下記の通り。

    • % : 一行を対象とする
    • %% : セル全体を対象とする

    たとえば、

    • %pdoc, %pdef. %psource, %pfile その後につづくもの(関数、クラスなど)の情報を表示
    • %timeit : 実行時間を表示
    • %run : 指定したpythonスクリプトを読み込んで実行
    • �bug : pdbデバッガを走らせる
    • %quickref : その他マジックコマンドのラインナップを表示

    あたりを覚えておけば便利だろう*1

    ? : イントロスペクション

    オブジェクトの前か後ろに?をつけると、jupyterがその説明をしてくれて、とても便利。(下図)

    なお、escを押せば、この情報は閉じられる。

    エディタとしてのJupyterをかっこよく

    Jupyter themesというライブラリによって、簡単にJupyterのテーマを変えられる。故にモチベがあがる。

    www.procrasist.com

    グラフのインタラクティブな操作

    もともとインタラクティブなJupyterをさらにインタラクティブにする。 パラメータをバーでいじればグラフが変わったりすると、素敵やん?

    下記二点を使えば、おしゃれなグラフの描画が可能!

    • Bokeh : オシャレなグラフ描画ライブラリ
    • ipywidget : インタラクティブにパラメータをぐりぐりする

    www.procrasist.com

    Jupyterでイケてるプレゼンをする

    ここまでくれば相当なJupyter使い。プレゼンもJupyterで作っちゃいましょう。 RISEというライブラリを紹介して、実際にプレゼン資料を作っています。

    www.procrasist.com

    種々のこと

    その他Jupyter界隈で気になることをさらっとまとめておく

    Colaboratory

    Colaboratory

    Googleが作ったクラウド型Jupyter - クラウド上でのJupyterの保管 - 複数人での編集

    を可能にする(参考: 日本語版最速!? jupyter notebookをgoogleが神改造 colaboratoryについてまとめてみた。 - Aidemy Tech Blog)

    Jupyterhub

    Jupyterhub documentation

    複数人でひとつのjupyter notebookを使うときに便利 (JupyterHubの構築 - Qiita)

    まとめ

    Jupyter、使いこなせばpythonの専用エディタとして大活躍できそう。 関数の情報や実行時間まで測れるし、かなり優秀だと思う。

    さて、明日からはscikit-klearnのお勉強。どこからやろうかな。考え中。。。

    *1:最悪最後のquickrefだけでも...w

    【Day-5】Jupyterでできる!イケてるプレゼンスライドの作り方

    f:id:imslotter:20171205031053p:plain

    こんにちは、ほけきよです。

    MSのツールの中でも、パワポだけは優れたツールだと思っているんですよ。 けれど、せっかく技術者ならば、そこら辺も新しいツールを使ってみたいものです。

    最近エンジニア界隈では、reveal.jsを使ってHTMLでプレゼン資料を作っているのをチラホラと見かけます。 あれ、かっこよい。。。

    なので、今回は、Jupyterでプレゼン資料を作る方法`をまとめておきます。

    jupyterをスライドにする(利用編)

    RISEをつかう。

    インストールと設定

    コマンド側はたったこれだけ。簡単、超簡単

    pip install RISE
    jupyter-nbextension install rise --py --sys-prefix
    jupyter-nbextension enable rise --py --sys-prefix

    Jupyterを起動して、 赤枠で囲んだ箇所が現れていれば成功

    使い方

    view->Cell Toolbar->slideshowを選択。スライドショー用の設定画面になる。

    下図のように、プルダウンメニューが出ていればOK、

    メニュー 用途
    Slide スライドで新しいページに切り替える
    Subslide サブスライドを作る(→のページ送りじゃなくて↓のページ送り)
    Flagment 同一スライドで、Enterを押してからスライド表示
    Skip スライドに反映しない
    Note スピーカーノート

    また、そのままではダサいので、体裁を整えたい。 %%HTML<style></style>とかでcssをべた書きがめんどくさいけど一番シンプル。その際は、図のように.rise-enabled .revealをつけておくと、スライドにのみ反映となる。つけないと、jupyter編集画面まで変わってしまう。

    実行

    実際にRISEでプレゼンするとこんな感じになる。題材は昨日のアドベントカレンダー

    出力

    htmlに出力 下記コマンドを入力すると、スライドの形式を保ったまま、htmlファイルが出来上がる

    jupyter nbconvert "day5-jupyter-slide.ipynb" --to slides --reveal-prefix "https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.1.0"

    出力されたhtmlファイルは、デフォルトのスライドデザインなので、jupyterの冒頭に書いたcssをコピーして、htmlのスライドが始まる直前の<style></style>の間にはめ込んでやる(はじめのスライドのタイトルなどで検索すると見つかりやすい)

    その際に、enable-riseセレクタは消去する。.revealは残す

    アップロード

    github.ioでは、htmlのスライドも見られるようにできる。 参考記事を見ながら、github pagesにあげてみる

    以下参考記事から抜粋した手順

    • reveal.jsを自分のgithubページにforkして、適当な名前に変更(settingで変更、そのままでもOK)
    • ローカルにforkしたreveal.jsページをcloneする
    • gh-pagesブランチを削除
    git branch -rd origin/gh-pages
    git push origin --delete gh-pages
    • 自分で新しくgh-pagesブランチを作成
    git checkout -b gh-pages
    • index.htmlというhtmlファイルを先ほど出力した自分のスライドに差し替える
    • 上記で作ったブランチにpush
    git push origin gh-pages

    ごり押しではあるが、スライドが作られている (demo page )

    ブログ等htmlで埋め込む

    最後、github.ioのページを何とかしてhtmlで埋め込みたい。

    こういうときは<iframe>タグを使う。

    <center>
    <iframe allowfullscreen="true" allowtransparency="true" frameborder="0" height="596"  mozallowfullscreen="true" src="https://hokekiyoo.github.io/jupyter-slide-demo/#" style="border:0; padding:0; margin:0; background:transparent;" webkitallowfullscreen="true" width="800"></iframe>
    </center>
    

    出力はこんな感じ

    まとめ

    いかがでしたか? Jupyter使いはぜひ使ってみてはいかがでしょうか

    試行錯誤を繰り返しながら色々と作ってみたので、改善点があれば教えていただければ幸いです。

    明日はJupyterネタがだいぶブログ内でまとまってきているので、それを踏まえてJupyterの総ざらいをします。ではでは!

    明日はjupyter!!

    【Day-4】都道府県のデータをいじりながら、pandasを学ぶ

    f:id:imslotter:20171204215003p:plain

    データ分析ガチ勉強アドベントカレンダー4日目。 今日はpandasを取り扱う。

    機械学習系の本にも、numpy、scipy, matplotlibの使い方は載っていても、pandasを載せている本って意外と少ない。 けれど、実際numpyの次くらいによく使う。データを取り扱ったり、計算したりするときにとても便利。一方で、癖があって慣れるまでに時間がかかる。なので、基礎的な事項をまとめておこうと思う。

    今回も、githubにコードや扱うデータを配置している。

    github.com

    都道府県の重心データを使いながら、pandasのお勉強をしようという試みである。

    pandasとは

    配列データの取扱が便利に行える

    • データの取り出し
    • データの操作
    • 統計計算
    • 時系列データの処理

    などを簡単に行えるため、重宝する。

    基礎事項は、公式ページの10 minutes to pandasを参考にすると良い。しかしこれ、確実に10分で終わらない内容となっている。その分濃いのでまあOKとする。

    また、リファレンスとしては下記の本も有用である。pandasの製作者が作っているので、信頼性は高い。

    Pythonによるデータ分析入門 ―NumPy、pandasを使ったデータ処理

    Pythonによるデータ分析入門 ―NumPy、pandasを使ったデータ処理

    基本事項

    データの読み込み/書き込み

    pandasの使い所としては、自分でデータ配列を作るよりかは、読み込んだcsv等のファイルを取り扱う時のほうが多いので、まずはソレ。pythonの組み込み関数であるcsvを使ってもいいが、pandasのほうがより手軽である。

    # 読み込み(csv)
    df = pd.read_csv("japan.csv", index_col="prefecrue")
    # 書き込み(csv)
    df.to_csv("japan2.csv")
    

    index_colは、インデックスにしたい列のこと。行の指定をするときに最もわかりやすいモノ(専門的に言えば主キーのようなもの?)を指定する。指定しなければ通し番号になる。

    Tips : データの文字コードがアレだと、下記のようなエラーが出るときもある。

    UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8e in position 0: invalid start byte

    そういうときは、

    df = pd.read_csv("japan.csv", encoding="shift-jis")
    

    とすると、解決する

    SeriesとDataFrameの作成

    読み込んでしまうと、そのまま表がDataFrameとして保管されるが、時には自ら作る場合もあるだろう。 pandasで用意されているデータ構造は下記のようなものがある。

    種類 特徴
    Series 1次元配列。要素をindexに保管
    DataFrame 2次元配列。行をindex、列をcolumnとして保存する
    Panel 3次元配列 参考

    正直、SeriesとDataFrameだけで良い。Panelは初めて知った。

    下記が、データフレームの作り方である

    # seriesが1次元配列、dataframeが多次元配列
    se = pd.Series([1,3,5,np.nan,6,8])
    print(se)
    # dataframe
    dates = pd.date_range("20130101",periods=6) 
    df = pd.DataFrame(np.random.randn(6,4), index=dates, columns=list('ABCD'))
    

    indexは指定しなければ、通し番号になる。datetimeなどで指定してやると後々時刻の範囲検索などもできるので便利である。

    データの基本的な情報をGetする

    (基本的にDataFrameの話を中心にすすめる)

    こうしてGETしたDataFrameの、基本的な情報は、下記のようにしてアクセスできる

    • df.head(3) # 初めの3つを見る
    • df.tail(3)) # 後の3つを見る
    • df.index # インデックスを確認
    • df.columns # カラムを表示
    • df.values # 中の値をarray形式で表示
    • df.describe() # 統計量(頻度、uniqueな値の個数、max,min,平均、25%点etc...)を表示

    df.valuesまでは、は中身を見るのにどれもよく使う。describeは初めて知った。便利そうだから今後使ってみる。

    データ内部へのアクセス

    DataFrame型へのアクセスは、様々用意されている。が、様々用意されているが故に、どれがどのようなアクセスの仕方だったのか、わかりにくくなっているのも事実である。ここで、どういうアクセスの仕方が可能なのか、まとめておく。

    • 基本
      • df["longtitude] # カラムの値(df.longtitudeでも可能)
      • df[0:3] # indexの指定
    • ラベルで指定 : df.loc
      • df.loc["東京都"] # indexの指定
      • df.loc[:,["longtitude","latitude"]] # columnのみ指定
      • df.loc["東京都",["longtitude","latitude"]] #両方指定
      • df.loc["東京都","longtitude"] # セル一つ分の指定
      • df.at["東京都","longtitude"] # セル一つ分の指定(より高速なアクセスが可能)
    • 位置による指定 ; df.iloc
      • df.iloc[3] # ilocによる行指定
      • df.iloc[3:5, 0:2] # ilocによる行列範囲指定
      • df.iat[1,1] # scalarの値(高速版)
    • 条件検索
      • df = df[(df.index!="沖縄県")&(df.index!="北海道")] # 沖縄と北海道は除外
      • 数値的な条件(>, == など)も可能

    新しいcolumnの追加、計算の適用。

    japanデータは、緯度経度が136:08:07のように、数値で入っていない。なので、この60度法で書かれたものをfloat型に変換し、新しいcolumnを追加したい。columnの追加は以下のような方法で出来る。辞書の追加のようなものだ。

    df["new_column"] = (新しい配列 or Series)
    

    変数の変換には、calc_numberという関数を用意した。

    def calc_number(d_num):
        """
        度であらわされてるのを、小数に変換
        """
        d = d_num.split(":")
        n = int(d[0])+float(d[1])/60+float(d[2])/3600
        return n
    

    さて、問題は、これをlongtitude,latitude関数の全てのindexに適用させるにはどうしたら良いかだ。 方法は2つある。

    • 一度配列を作り直して、新しいcolumnとして追加する
    • apply関数を適用する

    二番目の方法のほうが、シンプル。apply関数をつかうと、指定したcolumn全体に所与の関数を適用してくれる。 さっきのcalc_number関数を適用する

    df["latitude_num"]=df.latitude.apply(calc_number)
    df["longtitude_num"]=df.longtitude.apply(calc_number)
    print(df[df["latitude_num"]>135].index)
    

    出力

    Index(['山梨県', '静岡県', '長野県', '岐阜県', '富山県', '新潟県', '石川県', '栃木県', '群馬県', '埼玉県',
           '福島県', '北海道', '山形県', '福井県', '岩手県', '東京都', '奈良県', '宮城県', '秋田県', '三重県',
           '神奈川県', '青森県', '愛知県', '和歌山県', '滋賀県', '大阪府', '茨城県', '京都府', '千葉県'],

    ちゃんと西の方にある県が取り出せているよう。

    イテレーションを回す

    pandasはイテレーション用のメソッドを持っている。 が、なんかややこしいのでなかなか覚えられない。コチラのサイトを無限回見ている。何度もググって何度もこのページを開くのも流石にアレなので、ここにメモしておく。

    DataFrameなら、下記の3種類のイテレーション方法がある

    http://cdn-ak.f.st-hatena.com/images/fotolife/s/sinhrks/20150618/20150618222231.png
    (StatsFragmentsより引用)

    イテレーションの練習に、各都道府県の重心をプロットしてみる。*1

    plt.figure(figsize=(8,8))
    for key, row in df.loc[:,["longtitude_num","latitude_num"]].iterrows():
        plt.scatter(row["latitude_num"],row["longtitude_num"],
                    marker="x",color="blue")
    

    f:id:imslotter:20171204211523p:plain

    日本地図っぽい点群が出てきた。

    統計計算をしてみる

    今回の最後に、統計計算をpandasでしてみる。 pandasでは、簡単に統計計算を行うことが出来る。例えば以下の様なものが用意されている

    • df.mean() : 平均
    • df.std() : 標準偏差
    • df.var() : 分散
    • df.min() : 最小値
    • df.max() : 最大値

    全国の緯度と経度の平均を取ってみて、先程の都道府県重心プロットに重ね合わせる。どこになると思います?予想してみてください。

    longtitude_mean = df["longtitude_num"].mean()
    latitude_mean = df["latitude_num"].mean()
    print("latitude;{:.2f}, longtitude_mean:{:.2f}".format(latitude_mean, longtitude_mean))
    # >>> latitude;136.01, longtitude_mean:35.34
    

    さっきの日本地図に重ね合わせると

    f:id:imslotter:20171204212326p:plain

    こんな感じ。値をgooglemapで確認すると... f:id:imslotter:20171204212724p:plain

    滋賀県に!

    まとめ

    というわけで、よく使ったり調べたりする事柄を、まとめておいた。*2 しかし、ここに載せているのはpandasの機能のほんの一部分に過ぎない。 もともと金融データを取り扱う用に作られている*3ため、特に時系列データの取扱いは得意なようである*4。そのあたりもどこかでまとめられたらまとめる。

    明日はjupyter!!

    *1:pandasでもplotの関数はあるが、調べるのもめんどくさいので、matplotlibのものを使っている。

    *2:10 minutes to pythonは途中で飽きたので中座。。。

    *3:って書いていた気がする

    *4:rolling関数とか

    【Day-3】知らないコトがいっぱい...!『numpy 100 exercise』を全部やってみる (上級編)

    f:id:imslotter:20171203122846p:plain

    データ分析ガチ勉強アドベントカレンダー3日目。 今日も引き続き、100 numpy exercise をしていく。

    github.com

    今日は上級編。初級、中級でさえかなり難しかったので、不安ではあるが...とりあえずやっていく!

    また、問題の和訳と難易度も掲載しているので、自分の実力を試したい人はどうぞ。 自分が書いたコードともこちらに載せた(day3のやつ)

    github.com

    問題

    以下に、初級中級の問題を掲載する。長いので、ボタンを押すと見られるようにしている。

    • ○ : 模範解答どおり
    • △ : もっと効率的なやり方があった
    • ✕ : わからなかった
    実際の問題をみる
    番号 問題 難易度 結果
    64 2つのベクトルa,bがあって、aベクトルに、bで与えられたインデックスに箇所に1を加える ★★★
    65 aベクトルの値を用いて新しいベクトルを、bのインデックスに従って作る ★★★
    66 dtype=ubyte)の(w,h,3)画像全体を定義し、uniqueな値の数計算する(色はRGB256階調) ★★★
    67 4次元配列において、最後の2軸だけ一気に足す方法は? ★★★
    68 1次元ベクトルaを用意する。aと同じサイズで用意されたインデックスベクトル(min:0, max:9) s に従って構成されるsubsetベクトルの平均 ★★★
    69 内積の対角成分だけを取り出す ★★★
    70 [1,2,3,4,5]に対し、各値の間に3つの連続したゼロが挿入された新しいベクトルを作成する方法は? ★★★
    71 (5,5,3)の行列に対し、(5,5)の行列を、(5,5)の要素の箇所だけ掛け合わせる方法は? ★★★
    72 行列の特定の行を入れ替える ★★★
    73 三角形を記述する10個のtripletsがある。全ての三角形を作る線分の中で、uniqueなモノを書き出す。 ★★★
    74 bincountされた配列Cに対して、np.bincount(A)==CとなるようなAをどう作るか ★★★
    75 array上でsliding windowを使った平均算出法 ★★★
    76 一次元ベクトルaに対して一行目が(a[0],a[1],a[2])となって、以下の行はインデックスを1ずつずらした値が入るような行列をつくる ★★★
    77 配列のbooleanをひっくり返す、floatの記号をひっくり返す ★★★
    78 2つの点p0,p1がある。ある点pにおいて、p0,p1が作る直線と点pの距離を求めよ。 ★★★
    79 点群の集合P0,P1,Pがあって、Pの各要素の点からP0,P1が作る直線の距離を計算して配列にせよ。 ★★★
    80 配列Zに対し、与えられたpositionを配列の中心とし、与えられた形(shape)をくり抜いて新しい配列を作る(ないところは0で埋める) ★★★
    81 a=[1,2,3,4,5,...,14]とした時、R = [[1,2,3,4],[2.3.4.5].[3.4.5.6],...,[11,12,13,14]]を作る方法 ★★★
    82 行列のランクを計算する ★★★
    83 行列の中で最も使われている値を見つける ★★★
    84 (10,10)のランダム行列から全ての連続した(3,3)行列を取り出す ★★★
    85 Z[i,j]==Z[j,i]となるような、2次元配列のサブクラスを作る ★★★
    86 pセットの(n,n)の配列( size=(p,n,n) )と、pセットの(n,1)のベクトル( size = (p,n,1) )を用意する。p個の配列の掛け算を一度に実行する ★★★
    87 (16,16)の配列について、4×4のブロック和を求める ★★★
    88 ライフゲームをnuypyで実装する ★★★
    89 配列の中でn番目に大きな値を取る ★★★
    90 数値ベクトルについて、直積を取る。 ★★★
    91 普通の配列からrecord arrayを作る ★★★
    92 ベクトルaに対し、aの要素を3乗する計算方法を3つ答えよ ★★★
    93 A:(8,3)の配列、B:(2,2)の配列がある。Bの要素の順序は無視して、Bのそれぞれの行の要素を含むAの行を抜き出す ★★★
    94 (10,3)の行列に対し、全ての値が異なるrowとなるmatrix ★★★
    95 整数行列をバイナリ表現で表す ★★★
    96 2次元配列において、uniqueなrowを抽出 ★★★
    97 2つのベクトルa,bを考える。inner、outer、sum、mulの関数を求める ★★★
    98 2つのベクトル(x,y)によって作られるpathにおいて、等間隔サンプリングを用いてサンプリングする ★★★
    99 整数nと二次元配列Xがある。整数のみを含み、また和が4になる行を抜き出す ★★★
    100 1次元配列Xの平均のbootstrapped samplingにおける95%区間を計算する ★★★

    結果

    ★★★になると、題意がわからない問題も増えた。あと、普通に難しい、日本語が*1想像以上に解くのに時間がかかった。

    また、ゴリ押しでなんとかなる問題も結構あった*2。でも美しい回答を心がけたいところである。

    全問題
    37 15 7 15

    活躍したeinsum

    上級で印象に残ったのは、einsumを使う問題が結構多かった。 einsum()というのは、アインシュタインの縮約記号をpythonで使える、便利なやつ。以前記事にもしているので、そちらが詳しい。

    とにかく、**多次元配列や、複雑な配列演算に超絶威力を発揮する。

    下記の問題でeinsum()が使われている

    • (69). 内積の対角成分だけを取り出す
    • (71). (5,5,3)の行列に対し、(5,5)の行列を、(5,5)の要素の箇所だけ掛け合わせる方法は?
    • (84). pセットの(n,n)の配列( size=(p,n,n) )と、pセットの(n,1)のベクトル( size = (p,n,1) )を用意する。p個の配列の掛け算を一度に実行する
    • (90). 数値ベクトルについて、直積を取る。
    • (92). 大きなベクトルaに対し、aの要素を3乗する計算方法を3つ答えよ
    • (97). 2つのベクトルa,bを考える。inner、outer、sum、mulの関数を求める

    更に、実行時間が早くなるという恩恵も受けられる。92.の実行時間を確かめてみる

    x = np.random.rand(5e7)
    %timeit np.power(x,3)
    %timeit x*x*x
    %timeit np.einsum('i,i,i->i',x,x,x)
    

    計算結果

    2.42 s ± 79.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    762 ms ± 118 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    364 ms ± 15.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

    数倍早い。

    物理学徒以外の人は余り馴染みがないと思うので、初めは苦労するかもだが、慣れるととても良い。

    勉強になった問題(抜粋)

    例のごとく、勉強になった問題を抜粋する。

    全問題とちょっとした調べ物のリンクなどは、前と同様にgithubに残した。

    github.com

    81. a=[1,2,3,4,5,...,14]とした時、R = [[1,2,3,4],[2.3.4.5].[3.4.5.6],...,[11,12,13,14]]を作る方法

    普通にゴリ押しでも行けたが、関数を知っていると一発で終わりとても良いので、メモしておく。

    自分の回答

    a = np.arange(1,15,dtype=np.int32)
    b = np.zeros((11,4),dtype=np.int32)
    for i in range(11):
        b[i] = a[i:i+4]
    print(b)
    

    模範解答

    np.lib.stride_tricksを使う stride_trickの説明ページ

    Z = np.arange(1,15,dtype=np.uint32)
    R = np.lib.stride_tricks.as_strided(Z,(11,4),(4,4))
    print(R)
    

    共に出力は以下

    [[ 1  2  3  4]
     [ 2  3  4  5]
     [ 3  4  5  6]
     [ 4  5  6  7]
     [ 5  6  7  8]
     [ 6  7  8  9]
     [ 7  8  9 10]
     [ 8  9 10 11]
     [ 9 10 11 12]
     [10 11 12 13]
     [11 12 13 14]]

    82. 行列のランクを計算

    線形代数パッケージnp.linalgを使う。linalgの説明ページ

    linalgを使うと、例えば以下の様なことが出来る

    • 特異値分解 : np.linalg.svd(A)
    • ノルムを出す : np.linalg.norm(a)
    • 行列式を出す : np.linalg.det(A)
    • 方程式を解く : np.linalg.solve(a,b)
    • 逆行列を出す : np.linalg.inv(A)
    • 固有値を出す : np.linalg.eig(A)
    Z = np.random.uniform(0,1,(10,10))
    U, S, V = np.linalg.svd(Z) # Singular Value Decomposition
    #np.linalg.matrix_rank(Z) も可
    rank = np.sum(S > 1e-10)
    

    83. 行列の中で最も使われている値を見つける

    このbincount()というやつが結構便利。どの値が何個あるかを数えてくれる。 また、重複を避けた配列を返すものはnp.unique(a)というのが便利だったりする

    A = np.random.randint(0,5,10)
    print(A)
    print(np.bincount(A).argmax())
    #unique
    print(np.unique(A))
    

    出力

    [1 1 2 0 3 2 2 1 4 0]
    1
    [0 1 2 3 4]

    95. 整数行列をバイナリ表現で表す

    2進数に直す方法。ゴリ押しでもいけるが、模範解答がエレガントだったので、採用。

    &演算子がバイナリの演算子なのとreshap(-1,1)で縦ベクトルに出来るのを利用する。

    I = np.array([0, 1, 2, 3, 15, 16, 32, 64, 127])
    print(I)
    # print(I.reshape(-1,1))
    # print([3]&(2**np.arange(8))!=0)
    B = ((I.reshape(-1,1) & (2**np.arange(8))) != 0).astype(int)
    print(B[:,::-1])
    

    出力

    [  0   1   2   3  15  16  32  64 127]
    [[0 0 0 0 0 0 0 0]
     [0 0 0 0 0 0 0 1]
     [0 0 0 0 0 0 1 0]
     [0 0 0 0 0 0 1 1]
     [0 0 0 0 1 1 1 1]
     [0 0 0 1 0 0 0 0]
     [0 0 1 0 0 0 0 0]
     [0 1 0 0 0 0 0 0]
     [0 1 1 1 1 1 1 1]]

    まとめ

    2日に渡って、numpyの勉強をしてきた。 結構網羅的だったように思う。知らない関数もだいぶ多かったし、いい勉強になった。

    何よりも、数時間配列を作ってはいじり作ってはいじりを繰り返したお陰で、ささっと配列を作れるよぅになった気がする。これはもう訓練なので、一度こういう時間を儲けられたのはとても良かった。

    というわけでとりあえずnumpyの総ざらいは終わり。次回以降はpandasscikit-learnjupyterの復習・勉強をしていく。それではまた明日!

    *1:和訳が意味不明のものもあると思います、スミマセン。実行してみて何がいいたいか確かめてくださいw

    *2:88.ライフゲームとか

    【Day-2】numpyの勉強に『100 numpy exercise』を全部やってみる(初級・中級編)

    f:id:imslotter:20171202225708p:plain

    データ分析ガチ勉強アドベントカレンダー2日目。 数式を扱うことが多くなるので、numpyの復習をしたいと思う。使ったのは100 numpy exercise

    github.com

    numpyを用いるさまざまな問題が用意されていて、大変勉強になる。 今回は自分の実力を試すために、自分で解きつつ、よく使ったもの/新しく学んだことを列挙していく。

    また、問題の和訳と難易度も掲載しているので、自分の実力を試したい人はどうぞ。 自分が書いたコードともこちらに載せた

    github.com

    2日目は、初級・中級を掲載する。上級は明日挑戦して掲載予定。

    • ★☆☆ : 初級
    • ★★☆ : 中級
    • ★★★ : 上級

    問題

    以下に、初級中級の問題を掲載する。長いので、ボタンを押すと見られるようにしている。

    • ○ : 模範解答どおり
    • △ : もっと効率的なやり方があった
    • ✕ : わからなかった
    実際の問題をみる
    番号 問題 難易度 結果
    1 numpyを`np`という名前でimport ★☆☆
    2 numpyのバージョンとconfigを表示 ★☆☆
    3 サイズ10のnullベクトルを作成 ★☆☆
    4 作った配列のメモリサイズを確認 ★☆☆
    5 コマンドラインからnumpyのドキュメントを見る ★☆☆
    6 サイズが10で5番目の値だけ1の配列を作る ★☆☆
    7 値が10から49まで順に並んだ配列を作る ★☆☆
    8 配列の値をひっくり返す ★☆☆
    9 それぞれ0~8まで入った3×3の行列を作る ★☆☆
    10 [1,2,0,0,4,0]から0じゃない箇所を見つける ★☆☆
    11 3×3の単位行列をつくる ★☆☆
    12 3×3×3の乱数行列を作る ★☆☆
    13 10×10の乱数行列を作って、最大値と最小値を見つける ★☆☆
    14 サイズ30の乱数ベクトルを作って平均値を出す ★☆☆
    15 境界が1で、中身が0の2次元配列をつくる ★☆☆
    16 今ある配列に、0で埋めた境界を作る ★☆☆
    17 np.nanとnp.inf、小数の扱い ★☆☆
    18 5×5の行列を作って、対角成分の一つ下だけ1,2,3,4で埋める ★☆☆
    19 8×8の行列を作り、チェッカーボードパターンを作る ★☆☆
    20 (6,7,8)の配列で、インデックス(x,y,z)における100番目の要素は? ★☆☆
    21 ile functionを使って8×8のチェッカーボードパターンを作る ★☆☆
    22 5×5の乱数行列を正規化する ★☆☆
    23 8ビット整数を使って色を記述するdtypeを作る ★☆☆
    24 5×3の行列と3×2の行列を掛け合わせる(実数) ★☆☆
    25 1次元配列で、3以上8以下の値は負値にする ★☆☆
    26 numpy有無でのsum()の結果はわかる? ★☆☆
    27 整数ベクトルのなかでどの記述が間違っている? ★☆☆
    28 配列のゼロ除算 ★☆☆
    29 配列の小数点以下切り上げ ★☆☆
    30 2つの配列の中から同じ値を見つける ★☆☆
    31 numpyのwarningを無視する ★☆☆
    32 np.sqrtとnp.emath.sqrtの違い ★☆☆
    33 昨日、今日、明日の日付 ★☆☆
    34 2016年7月の日付配列 ★☆☆
    35 要素の計算( (A+B)*(-A/2) )をコピーなしで計算 ★★☆
    36 乱数行列の整数部分だけ取り出すやつ5種類 ★★☆
    37 行の値が[0,1,2,3,4]となる、5×5の行列 ★★☆
    38 ジェネレータを使って0から9までの配列を作る ★★☆
    39 0より大、1より小のサイズ10のrangingベクトルを作る ★★☆
    40 サイズ10のランダム配列を作ってsortする ★★☆
    41 小さい行列をnp.sumより早く計算する方法は? ★★☆
    42 2つのランダムベクトルが等しいかどうかを判定する ★★☆
    43 配列をimmutable(read-only)にする ★★☆
    44 直交座標の10×2の行列を極座標変換 ★★☆
    45 サイズ10のベクトルを作って最大値を0に変換 ★★☆
    46 x,y座標を[0,1]×[0,1]領域に変換したstructured arrayを作る ★★☆
    47 2つのベクトルを用いてコーシー配列(Cij =1/(xi - yj))を作れ ★★☆
    48 それぞれのnumpy scalar typeでの最小、最大値をprintする ★★☆
    49 配列の全ての値を省略せずにプリントする ★★☆
    50 ベクトル内の与えられたvalueの中で最も近い値を出力 ★★☆
    51 位置座標とcolorのRGBが保存されたstructured arrayを作る ★★☆
    52 10×2のランダム行列を作って、点同士の距離を求める ★★☆
    53 float32の行列をint32の行列に変換 ★★☆
    54 どうやってファイルを配列に変換する? ★★☆
    55 numpyの配列のenumerateと同等の表現は? ★★☆
    56 2DのGaussian-like arrayを生成する ★★☆
    57 2次元配列にランダムにp個、値を埋め込む ★★☆
    58 行列の各行に対し、その行の平均を引いていく ★★☆
    59 n列目のcolomunをソート ★★☆
    60 2D arrayにnullがあるかどうかを判定する ★★☆
    61 指定の値に最も近い値を見つける ★★☆
    62 イテレータを使って1×3行列と3×1行列のsumを計算 ★★☆
    63 名前の属性を付与したarrayクラスをつくる ★★☆

    結果

    なかなか厳しい結果となった。厳しい。 初級から結構知らないものが出てきたので、ほーんと思いながらといた。

    中級以降は、ダメ。自分がいかにプリミティブな操作しかできていないんだなというのを痛感した。

    難易度 問題数 正解 正答率
    ★☆☆ 34 23 67%
    ★★☆ 29 12 41%

    numpy配列の基本

    せっかくなので、よく使うnpの関数と、新しく知ったお得機能をメモしておきたい。このあたりを知っておけば、基本的な操作はできると思われる。

    配列を作る

    とりあえず配列を作れないとお話にならないので、作るときに便利な関数たちを列挙

    np.array([1,2,3,4,5])
    #>>>array([1, 2, 3, 4, 5])
    
    np.zeros((3,3))
    #>>>array([[ 0.,  0.,  0.],
    #        [ 0.,  0.,  0.],
    #        [ 0.,  0.,  0.]])
    
    np.ones((3,3))
    #>>>array([[ 1.,  1.,  1.],
    #       [ 1.,  1.,  1.],
    #       [ 1.,  1.,  1.]])
    
    np.random.random(5) #0から1までのランダム変数をサイズ5のベクトルで
    #>>>array([ 0.33732001,  0.73696762,  0.69890914,  0.46966465,  0.91019171])
    
    np.random.randint(0,5,10) #0から4までのランダム整数をサイズ10のベクトルで
    #>>>array([4, 3, 4, 1, 1, 4, 1, 3, 2, 0])
    
    np.random.uniform(0,1,5) #0から1までの一様実数をサイズ5のベクトルで
    #>>>array([ 0.72515655,  0.09389927,  0.49393525,  0.11564103,  0.31317932])
    
    np.random.normal(0,1,(3,3)) #平均0, 分散1の正規分布を3×3の行列で
    #>>>array([[ 0.64296467, -0.14865526, -0.24650383],
    #       [ 0.30479151, -1.61713417, -0.15371185],
    #       [ 0.92736104,  1.58778307, -1.86301156]])
    
    np.arange(10) #0から9まで順番に
    #>>>array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
    
    np.arange(1,10,2) #1から10を超える直前の数字まで2個飛ばしで
    #>>>array([1, 3, 5, 7, 9])
    
    np.linspace(0,10,10) #0から10までを5分割
    #>>>array([  0. ,   2.5,   5. ,   7.5,  10. ])
    
    # 5×5の配列の中にx,y座標を埋め込む
    A = np.zeros((5,5), [('x',float),('y',float)])
    A['x'], A['y'] = np.meshgrid(np.linspace(0,1,5),
                                 np.linspace(0,1,5))
    print(A)
    # >>> [[( 0.  ,  0.  ) ( 0.25,  0.  ) ( 0.5 ,  0.  ) ( 0.75,  0.  ) ( 1.  ,  0.  )]
    # [( 0.  ,  0.25) ( 0.25,  0.25) ( 0.5 ,  0.25) ( 0.75,  0.25) ( 1.  ,  0.25)]
    # [( 0.  ,  0.5 ) ( 0.25,  0.5 ) ( 0.5 ,  0.5 ) ( 0.75,  0.5 ) ( 1.  ,  0.5 )]
    # [( 0.  ,  0.75) ( 0.25,  0.75) ( 0.5 ,  0.75) ( 0.75,  0.75) ( 1.  ,  0.75)]
    # [( 0.  ,  1.  ) ( 0.25,  1.  ) ( 0.5 ,  1.  ) ( 0.75,  1.  ) ( 1.  ,  1.  )]]
    
    # イテレータを使って0から9までのサイズ10の配列
    def generate():
        for x in range(10):
            yield x
    a = np.fromiter(generate(),dtype=float,count=-1)
    print(a)
    #>>> [ 0.  1.  2.  3.  4.  5.  6.  7.  8.  9.]
    
    # チェッカーフラッグのように、4×4の行列に0,1を並べる
    np.tile(np.array([[0,1],[1,0]]),(2,2))
    #>>> array([[0, 1, 0, 1],
    #            [1, 0, 1, 0],
    #            [0, 1, 0, 1],
    #            [1, 0, 1, 0]])
    

    形を変える

    reshapeを使う

    a = np.arange(10)
    print(a)
    >>>
    a.reshape(2,5)
    >>>
    

    endpointの有無

    linspaceについて、指定した値を以下として扱うか未満として扱うか

    np.linspace(0,10,10)
    #>>> array([  0.        ,   1.11111111,   2.22222222,   3.33333333,
    #           4.44444444,   5.55555556,   6.66666667,   7.77777778,
    #           8.88888889,  10.        ])
    np.linspace(0,10,10,endpoint=False)
    #>>>array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9.])
    

    hstack, vstack, concatenate

    listのappendみたいなもの。ベクトル同士の結合

    a = np.arange(4)
    b = np.arange(4)[::-1]
    print(a,b)
    #>>> [0 1 2 3] [3 2 1 0]
    print(np.hstack((a,b)))
    #>>> [0 1 2 3 3 2 1 0]
    print(np.vstack((a,b)))
    #>>> [[0 1 2 3]
    #     [3 2 1 0]]
    

    スカラー値を足すとどうなる?

    全部に適用される

    a = np.arange(4)
    print(a)
    #>>> [0 1 2 3]
    print(a+1)
    #>>> [1 2 3 4]
    

    勉強になった問題(一部抜粋)

    多くの問題が学びのあるものだったが、個人的に勉強になった問題を抜粋する なお、全問題と回答はgithubにあげている。 とはいえ、中級はかなり勉強になったので、全部試してみると学びが大きいかもしれない。 githubには問題の和訳と回答をあげてみた。自分なりの回答をしているものもある。

    24. 5×3の行列と3×2の行列を掛け合わせる(実数)

    np.dotだけじゃなくて、@なる演算子があるらしい。

    A = np.arange(0,12).reshape(4,3)
    B = np.arange(0,6).reshape(3,2)
    print(A)
    print(B)
    print(A@B)

    出力

    [[ 0  1  2]
     [ 3  4  5]
     [ 6  7  8]
     [ 9 10 11]]
    [[0 1]
     [2 3]
     [4 5]]
    [[10 13]
     [28 40]
     [46 67]

    25. 1次元配列で、3以上8以下の値は負値にする

    条件文で検索をかけることができる

    a = np.arange(15)
    a[(a>3)&(a<=8)] *= -1
    print(a)
    

    出力

    [ 0  1  2  3 -4 -5 -6 -7 -8  9 10 11 12 13 14]

    36. 乱数行列の整数部分だけ取り出すやつを5種類

    //という演算子をはじめて知った。

    Z = np.random.uniform(0,10,10)
    print("36:")
    print(Z - Z%1)                      # 余りを引く
    print(np.floor(Z))                  # 切り捨ての関数
    print(np.ceil(Z)-1)                 # 切り上げて1を引く
    print(Z.astype(int).astype(float))  # 整数にしちゃう
    print(np.trunc(Z))                  # 整数部だけ取り出す
    print(Z//1)                         # 切り捨て演算子
    

    41. 小さい行列をnp.sum()より早く計算する方法は?

    add.reduce()を使うと良いらしい

    a = np.arange(100)
    print(np.add.reduce(a))
    

    43. 配列をimmutable(read-only)にする

    writeableをfalseの設定にして、書込み禁止にする。numpyはその設定ができる

    a43 = np.zeros(10)
    a43.flags.writeable = False
    # a43[0] = 1 エラーが出る
    

    49. 配列の全ての値を省略せずにプリントする

    printoptionsを利用することで、 省略されずに配列の全要素を見ることができる。

    np.set_printoptions(threshold=np.nan)
    x = np.zeros((16,16))
    

    55. numpyの配列のenumerateと同等の表現は?

    通常のenumerateのような、ndenumerate, ndindexというのがある。こっちのほうが早いのかな?あんまり違いがわかっていない。

    A = np.arange(9).reshape(3,3)
    for index, value in np.ndenumerate(A):
        print(index, value)
    for index in np.ndindex(A.shape):
        print(index, A[index])
    

    まとめ

    全然わからないものもたくさんあって、とても勉強になった。 明日は上級(★★★)にチャレンジ予定だが、0点なのではないかと危惧している。 でも、numpyはどういう場面でも使うので、基本をしっかり抑えておきたいなと思う。

    それではまた明日!

    【Day-1】データ分析/機械学習を行うために知っておきたいことを列挙する

    f:id:imslotter:20171201095130p:plain

    データ分析ガチ勉強アドベントカレンダー一日目。 まずは指針をということで、データ分析をはじめるにあたって勉強しておきたいことと、そのリソースをまとめる。言語はPythonを想定。

    • 興味領域が偏っている場合があるのであしからず
    • こんなの面白いよっていうのあれば教えてくださいな

    ※随時更新します

    Pythonライブラリ

    こんなの勉強しておけば良さそうリスト。抜け漏れご容赦。

    • ★★★ : 必須。空で使えるようになりたいトコロ。
    • ★★  : 周辺ツール、知っていればより便利になるよという感じ
    • ★   : あるアルゴリズムに特化しているようなもの。一歩先
    ライブラリ 必須度 用途
    numpy ★★★ 数値計算用のライブラリ。いろいろしてくれる
    scikit-learn ★★★ 機械学習用ライブラリ。たいていの基本的なことはここで出来る
    matplotlib ★★★ グラフ描画用ライブラリ。オシャレさはないけど使いやすい
    pandas ★★★ 表計算用ライブラリ。Excelなんて目じゃない。
    Jupyter ★★★ コード書きながら実験できるのが便利。詳しくはこちら
    scipy ★★ 統計処理の計算ライブラリ。numpyとsklearnで事足りる感は正直ある
    BeautifulSoup ★★ スクレイピング用ライブラリ。オリジナルデータ作成のときは役に立つ
    urllib ★★ クローリング,スクレイピング用ライブラリ
    re ★★ 正規表現ライブラリ。文字列の処理に使う
    json ★★★ jsonファイルの読み書き、パースを行うライブラリ、何かと使うことが多い
    deap 進化計算用ライブラリ。コチラのqiitaが詳しい
    statsmodels 時系列分析用ライブラリ
    prophet facebook謹製の時系列分析用ライブラリ
    opencv ★★ 画像を取り扱うときに使うライブラリ
    pyMC MCMC用ライブラリ、サンプリングがかんたんに出来る。亜種にPyStanもあり
    pycwt wavelet変換用ライブラリ。コチラのqiitaが詳しい
    mecab ★★ 日本語形態素解析用ライブラリ。自然言語処理をするなら
    gensim トピックモデル、word2vec, doc2vecなどを作るライブラリ

    深いアレたち

    Deeplearning用のやつ。最近乱立してて、キャッチアップし切れていない感もあるけど、気になる奴らをとりあえず拾ってみる

    ライブラリ 用途
    sonnet DeepMind社謹製深層学習ライブラリ。以前記事でも少し取り上げた
    chainer PFN社が作る国産ライブラリ、日本語ドキュメントが豊富
    tensorflow Google謹製OSS。とっつきづらいが圧倒的人口
    edward 確率的プログラミング用のライブラリ。tensorflowのラッパー
    keras thaanoやtensorflowのラッパー、簡単にネットワークを構成できる
    pytorch chainerをフォークして作られたライブラリ。ドキュメントやチュートリアルが充実している
    chainerMN 画像の学習で世界最速を実現した(記事 )並列分散学習パッケージ
    chainerRL 深層強化学習用ライブラリ

    参考記事 : 【PyTorch、Chainer、Keras、TensorFlow】ディープラーニングのフレームワークの利点・欠点【2017年10月更新】 - HELLO CYBERNETICS

    機械学習のお勉強

    論文

    arXiv

    日々更新されるarXivから興味のあるものを拾う。

    https://arxiv.org/list/{}/recent

    このURLの{}部分を変えると、いろんなジャンルの論文が読める。例えば↓

    • stat.ML : 機械学習全般
    • cs.CV : 画像処理系
    • cs.NE : 進化計算系

    尚、最近アーカイブのML系論文をHTML系形式で読めるArxiv Vanityなるものを知った。

    また、オープンソース型の最新論文情報共有サイト、arXivTimesなるものもあり、issueで論文のひとことメモを残していく形になっている。

    またまた、arxivの要旨とgithubソースコードがいっぺんにまとまったGitXivなるものもある。面白そうなものを素早く試せそうで良。

    カンファ

    e-learning

    Andrew Ng先生のMachine Learningチャンネルが勉強にはとても良さそう。

    www.coursera.org

    Deeplearningチャンネルも開設された。

    www.coursera.org

    読んだ本/積読本を載せたい。

    • 難易度とオススメ度は主観(3段階)
    • 統計、機械学習
    • これも随時更新
    難易度 オススメ度 内容 or 感想
    統計学が最強の学問である ★★★ 統計がどういう場面で使われているかわかりやすい一般書。まずイメージをつかむなら
    統計学入門 (基礎統計学?)
    自然科学の統計学 (基礎統計学)
    人文・社会科学の統計学 (基礎統計学)
    ★★ ★★★ 東大の統計の授業でも用いられている教科書。非常に網羅的でよい。数式もきちんと理解したいなら必読。ちなみにコレの後に続くシリーズで、自然科学の統計学人文・社会科学の統計学がある。難しいらしい。
    データ解析のための統計モデリング入門――一般化線形モデル・階層ベイズモデル・MCMC (確率と情報の科学) ★★★ 統計モデリングをコード実行例を含めて非常にわかりやすくまとめている。言語がRなのが(個人的に)玉に瑕だが、良書
    はじめてのパターン認識
    わかりやすいパターン認識
    続・わかりやすいパターン認識―教師なし学習入門―
    ★★★ 通称『はじパタ』機械学習の網羅的な入門だと、これがいいかもしれない。数式もきちんと記述されているので、どういう仕組みで動いているかのイメージが出来る。このシリーズにも続きがあって、『わかパタ』、『続わかパタ』があるが、続わかパタはかなり難しい*1
    深層学習 (機械学習プロフェッショナルシリーズ) ★★ ★★ ディープラーニングの理論的入門書として、網羅的でとてもよい。しかし、2年前の本なのでもう最先端のディープからはすこし違うところもある。けれど何やっているのかを把握するのにはオススメ
    パターン認識と機械学習 上
    パターン認識と機械学習 下 (ベイズ理論による統計的予測)
    ★★★ 通称『PRML』読むなら修行のつもりで。かなり数式が多い。この内容がわかるようになると、特にベイズ周りの扱いにはとても強くなると思われる。なお、副読本もある(パターン認識と機械学習の学習―ベイズ理論に挫折しないための数学)
    ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装 ★★★ ディープラーニングでCNNを実際に全部自分で実装しながら学ぶやつ。プログラミングの練習にもなり、またどういうデータが入力になってどう出力されるかも明確にわかるので理解が深まる。
    言語処理のための機械学習入門 (自然言語処理シリーズ) 積読 積読 自然言語の入門書として名高い。読みたい。
    異常検知と変化検知 (機械学習プロフェッショナルシリーズ) ★★ ★★ データ分析案件で結構な頻度出てくる異常検知。統計的な異常検知は割と網羅的。最近はディープラーニングを用いた異常検知もあるが、それは含まれていない
    時系列解析入門 ★★ ★★★ 時系列分析の教科書的存在。それなりに難しいが、それは時系列という存在が難しいのでやむなし。かなりわかりやすく書かれている。
    岩波データサイエンス Vol.6 積読 積読 最近出た時系列解析の本。各論的でレベルも高いが、かなり最先端の技術に触れられる。
    詳解 ディープラーニング ~TensorFlow・Kerasによる時系列データ処理~ 積読 積読 CNNを用いた画像分析はかなりいろいろと出回っているが、時系列データ処理に特化したディープラーニング本ってあまりないと思っている&興味分野なので、読みたい
    深層学習 Deep Learning 積読 積読 有名な本。プロフェッショナルシリーズよりは難しい。実際の研究事例がまとまっているようなものなので、ディープラーニングをもうちょっと深くしたくなったら読む予定。
    代数幾何と学習理論 (知能情報科学シリーズ) 積読 積読 ガチ理論。なぜか学習が起こるのか、とかそういうの(だと思っている)。これと情報幾何は趣味程度に読み進めたい。
    これからの強化学習 ★★★ ★★ 強化学習自体ややこしいので、結構読み進めるのは難しいが、基本が網羅的に学べ、またDeep Q-learning(DQN)についても和書で初めて触れた本。がんばって読み進めると、かなり詳しくなれる。

    まだあった気がするが、、、とりあえずこのくらい。。。

    • 数式に自信ある : 難易度関係なくオススメから
    • 数式はあまり... : 難易度低いの中心に

    自分の興味のある範囲のものを読んでみればいいと思います。

    twitter

    • 興味がある分野での有名な人のtwitterを抑えておいたら、やはり色々と捗る。

    データを集める

    • 最近の機械学習pythonライブラリ(chainer, tensorflow, sklearn, statsmodels, prophet, etc... )はdatasetクラスが用意されていて、予め有名なデータが保存されている。
    • オープンデータなら、とてもいいまとめ資料がこちらにある :
      beginning-ai.hatenablog.jp

    • 政府統計の総合窓口(e-Stat) : 日本人の統計データが色々とある。APIもあるので、データを扱いやすい。

    • 先も紹介したCVPaperに、CV用データセットが載っている
    • Kaggleデータ分析コンペ。上位入賞者は結構な賞金がもらえる。データも面白いものが多かったりする。最近ではメルカリデータとか?データ扱う練習 or 賞金狙い でやってみるのも良し。

    チートシート

    情報が散らばっているので、とりあえず集積してみた。が、あまりにも量が膨大なので、自分が何を勉強したいかを把握しながらすすめていくといいと思った。そこで役に立つのがチートシート

    下記サイトは、チートシートのまとめをしてくれている。結構網羅的。

    becominghuman.ai

    終わりに

    時代によって移り変わりが激しすぎるので、今後も定期的にアップデートしたいなと思う。

    あと、理解するために

    • タスクは何か
    • インプット、アウトプットは何か(実装レベルで)
    • 既存のものに比べてどう嬉しいのか
    • (できれば)なぜそういう恩恵があるのか、理論的考察

    をきちんと抑えながら理解をしていきたいなと思う。

    さて、明日はどうしようかな。

    *1:ノンパラメトリックベイズを扱っている

    『データ分析勉強アドベントカレンダー、全部俺』を、します。

    こんにちは、ほけきよです。

    明日から師走ですね。一年がたつのも早いものです。 ところで皆さんは「アドベントカレンダー」なるものを知っていますか?

    最近ブログをサボり気味だったこともあり、またデータ分析の勉強をしたいなとも思っていて、 一人データ分析ガチ勉強アドベントカレンダーを実施します!

    アドベントカレンダーとは

    アドベントカレンダー(Advent calendar)は、クリスマスまでの期間に日数を数えるために使用されるカレンダーである。アドベントの期間(イエス・キリストの降誕を待ち望む期間)に窓を毎日ひとつずつ開けていくカレンダーである。すべての窓を開け終わるとクリスマスを迎えたことになる。(Wikipediaより)

    もともとは、子供たちに対してクリスマスへの期待感を高めるために使われています。小窓をあけると、お菓子とか小物とかが各窓に入っている用です。なんだかオシャレですね!

    技術者界隈のアドベントカレンダー

    特に技術者界隈のアドベントカレンダーは少し様相が違います。 12/1から12/25までに、各テーマをひとつ掲げ、毎日1記事ずつ、記事をあげていきます。 一人でやるわけではなく、そのテーマに興味を持った人が集まりながら、わいわいとカレンダーを埋めていきます。

    カレンダーを作るプラットフォームの有名どころは二つあって、

    • Qiita HP
    • Adventar HP

    です。Qiitaは技術中心、Adventarはもっと広くいろんなジャンルのカレンダーっていう印象です。

    ほけきよのアドベントカレンダー

    本来わいわい集まりながらカレンダーを作るものですが、今回わたしは一人で実施します...!

    リンクはこちら

    adventar.org

    題の通り、一ヶ月間、復習もかねつつデータ分析のガチ勉強をしていこうと思います。 書きたい内容は以下の通り。

    • データ分析の話全般(論文/記事などを参考に)。特に↓のジャンル
    • pythonライブラリの勉強。ワンランク上の分析技術を身につけるために
      • numpy,pandas,scikit-learnについて総ざらい
      • 機械学習系ライブラリを使ってみる
        • keras, pytorch, prophet, statmodels, ...etc...
    • 実際にデータ分析
      • スクレイピング・クローリング周りの技術
      • ブログのデータを用いて
      • オープンデータを用いて

    上記の何割書けるかわかりませんが、できる限り書こうと思います。間違っているところなどあったら、コメントください。

    また、日によって出来にムラがあるかと思います *1。当日には埋められないことがあるかもしれません。でも、なんとか25日がんばって埋める所存ですので、どうか見てやってください。データ分析をしたことがある駆け出しの人なら、きっと役に立つはずです!

    ネタも募集中

    皆さんから、「データ分析でこんなことを知りたい」とか、「こんな話題を取り上げてほしい」、「このデータ面白そうじゃない?」って言うのも受け付けたいなと思います。オッ、これは、、、と思うものについてはがんばって記事にします。

    最近はやっているSarahah*2で、質問を気軽に受け付けます。 なんでも質問してください!!

    hokekiyoo.sarahah.com

    とりあえず完走する、、、ではではっ!

    ※なお、アドベントカレンダー関連の記事には【AC-#】という通し番号をつけておきます。普通の記事も投稿する予定ですので、データ分析に興味がない人もお楽しみに!

    *1:最終的には出来たものをリライトしてまとめたりもするかもしれないので、その辺もおいおい考えていきます。

    *2:匿名質問箱

    既成概念をぶち壊す!『レアンドロ展』のみどころは?

    こんにちは、ほけきよです。

    皆さんは『レアンドロ・エルリッヒ』をご存知ですか。 レアンドロ・エルリッヒを知らなくても、21世紀美術館なら知っているかもしれません。 21世紀美術館を知らなくても、この画像なら見たことがあるかも知れません。

    服を着ているのにまるで水中にいるかのようなプール。 彼の代表作とも言える作品で開館時時から大人気です。

    そんな気鋭の芸術家、レアンドロ・エルリッヒの展示会が、六本木の森美術館でスタートしました!

    レアンドロ・エルリッヒ展 観ることのリアル

    本展は、エルリッヒの四半世紀にわたる活動の全容を紹介する、世界でも過去最大規模の個展です。新作を含む44点の作品を紹介し、その8割が日本初公開となります。

    • 会期 2017.11.18(土)~ 2018.4.1(日) (会期中無休)
    • 開館時間 10:00~22:00(最終入館 21:30)
      • ※火曜日のみ、17:00まで(最終入館 16:30)
    • 会場 森美術館六本木ヒルズ森タワー53階)
    区分 料金
    一般 1,800円
    学生(高校・大学生) 1,200円
    子供(4歳~中学生) 600円
    シニア(65歳以上) 1,500円

    行ってみた、見所

    既成概念をぶち壊す

    エルリッヒ展の見所は、「リアリティ」のあり方。 エルリッヒの手にかかれば一見当たり前に見える景色に少しの非現実が混ぜ合わされ、不思議な空間が作り出されます。 21世紀美術館でのスイミングプールもそう。「水中では服は着られない」という固定観念を破壊し、新たな価値観を形成する。

    そんな作品がエルリッヒ点ではズラッと並びます。

    水に浮かんでいるかのようなボートの写真。水は反射するものだという既成概念を利用している。

    作品を通してわたしたちは、見るという行為の曖昧さを自覚し、惰性や習慣、既成概念や常識などを取り払い、曇りのない目で物事を「見る」ことで、新しい世界が立ち現われてくることを、身をもって体験することになるでしょう。

    インスタ映え?する鏡の錯覚

    個人的な今回のエルリッヒ展のみどころは、「鏡を使った錯覚」 普段見ている当たり前にみえる風景のはずが、鏡に寄って我々は混乱状態に陥る。

    この展示は一部が本当につながっていて一部が鏡の空間。一度その中に入ってしまうと、どう歩いていけばよいのかわからなくなる。


    (パンフレットより)

    特に今回の目玉作品でもある、"Building" こんな写真がとれます。インスタ映え?しそうじゃない?笑


    (パンフレットより)

    これも鏡を上手に使っていて、実際はこんな感じになっています。

    ネタバレ写真を見る

    一緒に行っていた友人は鏡か現実かわからず鏡に突進していってぶつかっていました。笑 それほど、大きなオトナすら混乱してしまう作品!

    まとめ

    いかがでしたか?参加型の個展、とても楽しく回ることが出来ました。

    友達、カップル、家族等、誰と行っても楽しめる良い展示だと思います。私も年齢を忘れて終始はしゃいでいました!笑

    興味を持った方は是非足を運んでみてください。超絶オススメです!ではではっ!

    PROCRASIST