[Kaggle]いろいろとTitanicしてみる:グリッドサーチ

ハイパーパラメータのチューニング

前回の続き
交差検証を調べていたら以下の記事に遭遇
scikit-learn を用いた交差検証(Cross-validation)とハイパーパラメータのチューニング(grid search) - Qiita
#はじめに 本記事は ( の 5 章(モデルの評価と改良)に記載されている内容を簡単にまとめたものになって...
これの後半にモデルに対するパラメータのチューニングの仕方が載っていたので、それを参考に今回は「ハイパーパラメータのチューニング」をやってみることにする。

ググる

Python: scikit-learn のハイパーパラメータを GridSearchCV で最適化する - CUBE SUGAR CONTAINER
機械学習のアルゴリズムにおいて、人が調整する必要のあるパラメータのことをハイパーパラメータと呼ぶ。 これは自動では決められないので、色々な値を試したりして汎化性能が高くなるものを選ばなきゃいけない。 今回はハイパーパラメータを決めるのに scikit-learn に実装されている GridSearchCV という機能を...

いくつかググってみたのだが、ここが自分には一番わかりやすかった。 つまるところ、それぞれのモデル?を作成する際のパラメータについて、
いっぱい試したいからそれを設定できるようにしたぜってことの様子。
なので、これだけ理解しても無駄だった。
それぞれのモデルに食わせたいパラメータを理解しないと意味がないと理解。

とりあえず決定木とSVMのパラメータを作ってみた

決定木
# GridSearchしてその結果最適なパラメータで設定
clf = DecisionTreeClassifier()
# 試行するパラメータを羅列する
params = {
        'max_depth': list(range(1, 10)),
        'min_samples_split' : list(range(3, 10)),
        'criterion': ['gini', 'entropy'],
    }
best_estimator = GridSearch(clf, params, 10, predictor_var, response_var)
SVM
clf = SVC(class_weight='balanced', random_state=0)
# 試行するパラメータを羅列する
params = {
        'C': [0.01, 0.1, 1.0],
        'gamma' : [0.01, 0.1, 1.0],
        'kernel': ['rbf', 'linear'],
    }
best_estimator = GridSearch(clf, params, 10, predictor_var, response_var)
GridSearchの中身そのものは一緒なので関数化してみた。
def GridSearch(clf, param_grid, cv_cnt, predictor_var, response_var):
    print(" --- grid_search ")
    # グリッドサーチにより最適値を求める
    # from sklearn import grid_search
    from sklearn.model_selection import GridSearchCV
    grid_search = GridSearchCV(estimator=clf, param_grid=param_grid, scoring='accuracy', cv=cv_cnt, n_jobs=-1)
    grid_search.fit(predictor_var, response_var)
    print(grid_search.best_score_)
    print(grid_search.best_params_)
    # print(gs.best_estimator_)

    # return grid_search.best_params_
    return grid_search.best_estimator_
best_estimatorを返却するよりはgrid_searchそのものを返却したほうが使いやすいのかな?
でも、スコアとかパラメタを返却されても使わないよな?
そしていずれのサイトにも書いてある「時間がかかる」という意味も理解。
ここら辺からPCのパワーが必要になってくるのかもしれない。 ついでに効果が高そうなRandomForestについてもGridSearchさせてみることにする
参考:http://blog.tatsushim.com/?p=63
clf = RandomForestClassifier()
params = {
        'n_estimators'      : [5, 10, 20, 30, 50, 100, 300],
        'max_features'      : [3, 5, 10, 15, 20],
        'random_state'      : [0],
        'n_jobs'            : [1],
        'min_samples_split' : [3, 5, 10, 15, 20, 25, 30, 40, 50, 100],
        'max_depth'         : [3, 5, 10, 15, 20, 25, 30, 40, 50, 100]
}
best_estimator = GridSearch(clf, params, 10, predictor_var, response_var)
return best_estimator
が、例外発生。
ValueError: max_features must be in (0, n_features] max_featuresで怒られているのでいったんデフォルトにさせてそれ以外のパラメータで試行。
で、得られたパラメータが以下。
{'max_depth': 15, 'min_samples_split': 15, 'n_estimators': 50, 'n_jobs': 1, 'random_state': 0}
スコアは0.836139169473 このパラメータ+max_featuresで再実施。
が、やっぱり ValueError: max_features must be in (0, n_features]
何かが違っているんだろうな。
よくわからないので先に進むことにする。

アップロードしてみる

ということで、DecisionTree、SVM、Random Forestに対してGridSearchしたうえでパラメータを再設定しての結果が以下。
                model_name     score
6            Random Forest  0.836176
0             DecisionTree  0.823866
1       LogisticRegression  0.798048
2  Support Vector Machines  0.785587
4     Gaussian Naive Bayes  0.782329
3                k近傍法(KNN)  0.714028
5               Perceptron  0.552625
前回と比べるとまあまあポイントがアップしている。
なので、これでテストもかましてアップロードしてみることにする。 2018-09-23_16h32_11.png だいぶ増えた。Rankingの方も真ん中ぐらいまで来た。 [参考]
Scikit learnより グリッドサーチによるパラメータ最適化 - Qiita
# Grid search とは scikit learnにはグリッドサーチなる機能がある。機械学習モデルのハイパーパラメータを自動的に最適化してくれるというありがたい機能。例えば、SVMならCや、kernelやgammaとか。[Sc...

ハイパーパラメータ自動調整いろいろ - Qiita
# Kerasでハイパーパラメータの自動調整いろいろ ディープラーニングを使う際の大きな課題の一つがハイパーパラメータのチューニングです。 ニューラルネットワークのニューロン数やドロップ率、ラーニング率といったパラメータを調整し、より...

ベイズ最適化とグリッドサーチの比較 - Qiita
## 概要 機械学習におけるパラメータチューニングには、グリッドサーチがよく使われる。 しかし、このような総当り的手法では計算に時間がかかる。 そこで、自動で効率よく最適なパラメータを選択する手法として、ベイズ最適化が考えられる。 今...

ハイパーパラメータの最適化と結果の見方【Pythonとscikit-learnで機械学習:第8回】
機械学習においてハイパーパラメータを最適化する手法について、実装・解説します。本シリーズでは、Pythonを使用して機械学習を実装する方法を解説します。各アルゴリズムの数式だけでなく、その心、意図を解説していきたいと考えています。...

GridSearchCVによるチューニング | 有意に無意味な話
Pythonの機械学習ライブラリscikit-learnにはモデルのパラメタをチューニングする仕組みとしてGridSearchCVが用意されています。ここではその使い方と実行例を紹介します。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

[Kaggle]いろいろとTitanicしてみる:過剰適合/過学習/交差検証

目的

交差検証について調べたりコード化してみる そもそもの発端としては
前回の訓練データだと90ぐらいのスコアになったのをアップロードしてみたらちょこっとしかUPしてなかったということである。
以下のようなろくでもない検証にしかしてなかったのでダメだろうとは思っていたが
ここまで差が出るとはちょっとびっくりであった。
evaluation_score = round(model.score(features , target) * 100, 2)

なので、調べてみることにした。

[過剰適合]
過剰適合 - Wikipedia
[交差検証]
交差検証 - Wikipedia
ググってみた。
「そのモデルの精度、高過ぎませんか?」過学習・汎化性能・交差検証のはなし - 六本木で働くデータサイエンティストのブログ
今年の1月にこんな話題を取り上げたわけですが。この記事の最後にちょろっと書いた通り、実際にはこういう"too good to be true"即ち「そのモデルの精度いくら何でも高過ぎるんじゃないの?」→「実は汎化性能見てませんでした」みたいなケースって、想像よりも遥かに多くこの世の中存在するみたいなんですね。ということ...
「モデルの説明変数は必要以上に増やせば増やすほど学習データのシグナルだけでなくノイズにまでフィットしてしまう」
訓練データに最適化しすぎると、訓練データ内のノイズについても何かしらのモデルから生成されたものなのではないかという推論モデルを構築してしまうということなわけだ。
これは仕事の世界でも割とありそうな話。
また、これは割と嫌な話ですが「交差検証したからと言って汎化性能が確保できるとは限らない」ケースもあるということ。特に学習データと(テストデータではない本当の)新規の未知データとで性質が全く違うようなケースでは、いかな汎化性能の高いモデルでも太刀打ちできません。時々Kaggleでその手のデータセットが出てきて物議を醸すことがありますが、実務でも同様のことは少なくないです。

そして実装へ

交差検証のロジックを調べて実装してみるかなーと思って捜索してたらびっくりした。
scikit learnより 交差検定で学習モデルの精度を評価 - Qiita
#やったこと - 手書き数字の画像データをSVMで分類 - Cross Validation でモデルの score を評価 - ハイパーパラメータ C を変えて、score がどう変わる確かめる - ハイパーパラメータ gamma ...

scikit-learnのモジュールの中にあるらしい。
・・・みなが扱うのだから、それもそうか。 ちなみに上記に記載してあるとおりに実装してみると何やらワーニングが出た。 C:\Program Files\Anaconda3\lib\site-packages\sklearn\cross_validation.py:44: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.
"This module will be removed in 0.20.", DeprecationWarning)
と思ったら、その上でcross_validationをimportしていたからっぽい。
from sklearn import cross_validation  # ←ここでワーニング
from sklearn.model_selection import cross_val_score
scores = cross_val_score(model, features, target)
# pprint.pprint(scores)
# 各分割におけるスコア
print('Cross-Validation scores: {}'.format(scores))
# スコアの平均値
# import numpy as np
evaluation_score = np.mean(scores)
print('Average score: {}'.format(evaluation_score))
cross_validationは使えなくなるのでmodel_selectionにしないといけないらしいのだが、そもそもまだ未使用なのでコメントアウトしておく
※参考:https://qiita.com/kasajei/items/e23929627d51aa1b09fe

ドキュメントも見てみる

3.1. Cross-validation: evaluating estimator performance — scikit-learn 0.21.3 documentation

cvの数を変えるとどうなるのか?

li = [i for i in range(4, 10)]
li.append(100)
for n in li:
    print('Average score {}: {}'.format(n, np.mean(cross_val_score(model, features, target, cv=n))))
Average score: 0.7833894500561166
Average score 4: 0.7991231041259068
Average score 5: 0.8047747932733926
Average score 6: 0.8036383699135378
Average score 7: 0.8060033232453085
Average score 8: 0.8071141555516557
Average score 9: 0.8035914702581368
Average score 100 : 0.8036111111111112
こんな感じだ。
100にしたからといってそこまで精度が上がるということでもなさそう。
というか、何をもって「精度が上がった」と言っているのかも自分ではよくわからない。
なので、とりあえず5ぐらいとして実施してみることにする。
この状態で各モデルに対して改めて検証してみる。
                model_name     score
0             DecisionTree  0.804775
6            Random Forest  0.804775
1       LogisticRegression  0.790168
4     Gaussian Naive Bayes  0.789031
3                k近傍法(KNN)  0.700442
2  Support Vector Machines  0.697160
5               Perceptron  0.627463
DecisionTreeがRandom Forestを逆転するという結果に。
また、Random Forestもsocreはよいが、前回ほどアホみたいな数値にはなっていない。
実際はこれよりも下がると考えると常識的な数値が出る検証となったと言えるかもしれない。 ただ、この検証スコアを信じるとDecisionTreeの方が高い結果になるはずなのだが、
前回アップロードした結果だとRandom Forestの方が若干高い。難しいな。

ハイパーパラメータのチューニング

交差検証を調べていたら以下の記事に遭遇
scikit-learn を用いた交差検証(Cross-validation)とハイパーパラメータのチューニング(grid search) - Qiita
#はじめに 本記事は ( の 5 章(モデルの評価と改良)に記載されている内容を簡単にまとめたものになって...
これの後半にモデルに対するパラメータのチューニングの仕方が載っていた。
※というか、本来は体系立てて学習していくことな気もしてきたがとりあえず気にしない。 なので、TODOとしてはモデルに対するパラメータチューニングもそのうち試してみるやることにする。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

メインヒロインが死んだり振られたり大変な話

ISLAND

アマプラにて

Amazon.co.jp: ISLANDを観る | Prime Video
本土から遠く離れた海に浮かぶ「浦島」 忘れられつつあるこの島に 「タイムトラベラー」を自称するひとりの青年が流れ着く。 青年は、3人の少女たちと出会い、 やがて島の未来を変えるべく奔走をはじめる。 数々の謎を秘めた浦島をめぐる 青年と少女たちの物語がひも解かれる--。(C)2015 Frontwing/PROTOTYP...

初回をテレビ放送時に偶然見かけ、なんかタイムリープものっぽいことが気になってたので、なんとなく一気に見てみた。

途中までの風呂敷広げている段階は面白かったんだけど、未来編の設定の乱雑さに急速にどうでもよくなってしまった。

尺の都合なら仕方ないのかもしれないけど、もう少しどうにかできなかったのかね?

そこまでも含めて、原作だともう少しいろいろとフォローがあるんだろうなというような雰囲気は感じれたので、アニメ化するにあたってこれでもいろいろ頑張ったんでしょうね。

最後に予想外の結果に。

と言ってもキャラの役回りについては割と初期から予想できてた感じ。むしろ全部おなじリンネかと思ってたぐらあか。

意外だったのは、あの話の流れからどうやって過去に帰るのかなと思っていたら、まさか「帰らない」もいう回答。

「過去に戻らないタイムリープもの」という珍しいジャンルにはなった気がする。

ただそのおかげで、ストーリーとしてはなんとなく大円団っぽく終わったけど、結局どこから来た「未来人」なのか?という話は完全にほっぽり投げ出しちゃってるし、過去において死んだ子たちは死んだままなんだよね。

全体的にもうちょいどうにかならんかったのかなぁという惜しさが残った。

それでも半日ダラダラと見続けるぐらいの訴求力はあったかな。

ガンゲイルはみてられなかった。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

[Kaggle]いろいろとTitanicしてみる

前回Kagglerになってみたが、それだとしっくりこなかったり、ほかのモデルを試してみてなかったりしたので
以下を参考にいろいろと試行錯誤してみた。 [Kaggle]0から本当に機械学習を理解するために学ぶべきこと~一流のデータサイエンティストを例に~
[part2]0から本当に機械学習を理解するために学ぶべきこと~一流のデータサイエンティストを例に~
[part3]0から本当に機械学習を理解するために学ぶべきこと~0からscikit-learnを使いこなす~ といっても、なんとなく思考をトレースしただけなので項目の追加などは特にせずに
今後使いまわしやすそうなコード構成に修正したぐらいだが。
全体的にやらないといけないことの流れはなんとなくわかった気がするので、次回別のデータセットで試してみるのもいいかもしれない。 で、いろいろなモデルをまとめて試してみた結果が以下。
image.png
こんな感じになったモデルから一番精度がよさそうなものをピックアップし、生成した予測データをアップロードしてみる。 image.png
こんな感じ。 image.png もうちょっと上がるのかと思ったけど、そうでもなかった。
これが訓練データに過剰適合してしまったということなのか? ちなみに修正後のソースはこんな感じ
何かを修正するとしたら、評価の部分だと思う。
交差検証にしたい。
あとは各モデルのパラメータとかもあるんだろうなと思うし、特徴量についてもある程度はチューニングできるようにしたい。
# -*- coding: utf-8 -*-
# ---------------------------------------------------------------------------
# Python3

import pprint
import datetime 

import pandas as pd
import numpy as np

# machine learning
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC, LinearSVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.linear_model import Perceptron
from sklearn.linear_model import SGDClassifier
from sklearn.tree import DecisionTreeClassifier


csv_train = r'C:\PJ\20180917_kaggle\kaggle_titanic\files\train.csv'
csv_test = r'C:\PJ\20180917_kaggle\kaggle_titanic\files\test.csv'


def read_dataset(df):

    # サイズ
    print("= size =")
    pprint.pprint(df.shape)

    # 統計量
    print("= describe =")
    pprint.pprint(df.describe())

    # 欠損データ
    print("= 欠損データ =")
    pprint.pprint(kesson_table(df))

    # 先頭データ
    print("= head =")
    pprint.pprint(df.head(10))

def read_datasets(df_train, df_test):
    print("---> train ---")
    read_dataset(df_train)
    print("---> test ---")
    read_dataset(df_test)
    print("------------------------")

def kesson_table(df): 
    null_val = df.isnull().sum()
    percent = 100 * df.isnull().sum()/len(df)
    kesson_table = pd.concat([null_val, percent], axis=1)
    kesson_table_ren_columns = kesson_table.rename(
    columns = {0 : '欠損数', 1 : '%'})
    return kesson_table_ren_columns

def distribution(df, column_name):
    #平均・標準偏差・null数を取得する
    Age_average = df[column_name].mean() #平均値
    Age_std = df[column_name].std()  #標準偏差
    Age_nullcount = df[column_name].isnull().sum() #null値の数=補完する数

    # 正規分布に従うとし、標準偏差の範囲内でランダムに数字を作る
    rand = np.random.randint(Age_average - Age_std, Age_average + Age_std , size = Age_nullcount)

    #Ageの欠損値
    df[column_name][np.isnan(df[column_name])] = rand
    pass

def pre_processing(df):
    # 欠損値の補完
    ## 中央値を設定:median()で中央値が取得できる
    df["Age"] = df["Age"].fillna(df["Age"].median())
    # distribution(df, "Age")
    ## 最頻値を設定:pandas.Seriesに対してmode()で最頻値のSeriesが取得できるのでそれの先頭を使用
    df["Embarked"] = df["Embarked"].fillna(df["Embarked"].mode()[0])
    # distribution(df, "Embarked")
    ## 最頻値を設定
    df["Fare"] = df["Fare"].fillna(df["Fare"].mode()[0])
    # distribution(df, "Fare")

    # 文字列→数字化
    df['Sex'] = df['Sex'].map({ 'male':0, 'female':1})
    df['Embarked'] = df['Embarked'].map({ 'S':0, 'C':1, 'Q':1})
    # df['Sex'] = df['Sex'].map({ 'male':1, 'female':0})
    # df['Embarked'] = df['Embarked'].map({ 'S':1, 'C':2, 'Q':0})

def output_file(prediction, df_test, filename):
    # PassengerIdを取得
    PassengerId = np.array(df_test["PassengerId"]).astype(int)
    # prediction(予測データ)とPassengerIdをデータフレームへ落とし込む
    df_solution_tree = pd.DataFrame(prediction, PassengerId, columns = ["Survived"])
    # csvファイルとして書き出し
    df_solution_tree.to_csv(filename, index_label = ["PassengerId"])
    pass

def get_data():
    # ファイル読み込み
    df_train = pd.read_csv(csv_train)
    df_test = pd.read_csv(csv_test)

    # データの確認
    # read_datasets(df_train, df_test)

    return df_train, df_test

def evaluation(model, features, target):
    """
    とりあえず結果を評価してみる
    """
    evaluation_score = round(model.score(features , target) * 100, 2)
    print(" -- evaluation : {}".format(evaluation_score))

    return evaluation_score

def create_model_DecisionTree(predictor_var, response_var):
    # 決定木の作成とアーギュメントの設定
    max_depth = 10
    min_samples_split = 5
    # model_DecisionTree = tree.DecisionTreeClassifier(max_depth = max_depth, min_samples_split = min_samples_split, random_state = 1)
    model_DecisionTree = DecisionTreeClassifier(max_depth = max_depth, min_samples_split = min_samples_split, random_state = 1)
    model_DecisionTree = model_DecisionTree.fit(predictor_var, response_var)

    return model_DecisionTree

def create_model_LogisticRegression(predictor_var, response_var):
    # ロジスティック回帰
    model_LogisticRegression = LogisticRegression()
    model_LogisticRegression.fit(predictor_var, response_var)
    # Y_pred = logreg.predict(X_test)
    return model_LogisticRegression

def create_model_SVM(predictor_var, response_var):
    # Support Vector Machines
    model_SVC = SVC()
    model_SVC.fit(predictor_var, response_var)

    return model_SVC

def create_model_KNeighbors(predictor_var, response_var):
    # k近傍法(KNN)
    model_KNeighbors = KNeighborsClassifier()
    model_KNeighbors.fit(predictor_var, response_var)

    return model_KNeighbors

def create_model_GaussianNB(predictor_var, response_var):
    # 単純ベイズ分類器またはナイーブベイズ分類器
    model_GaussianNB = GaussianNB()
    model_GaussianNB.fit(predictor_var, response_var)

    return model_GaussianNB

def create_model_Perceptron(predictor_var, response_var):
    # パーセプトロン
    model_Perceptron = Perceptron()
    model_Perceptron.fit(predictor_var, response_var)

    return model_Perceptron

def create_model_RandomForest(predictor_var, response_var):
    # Random Forest
    model_RandomForest = RandomForestClassifier(n_estimators=100)
    model_RandomForest.fit(predictor_var, response_var)

    return model_RandomForest

if __name__ == '__main__':

    print("start")

    # データ取得
    df_train, df_test = get_data()

    # 前処理:pre_processing
    # pd.options.mode.chained_assignment = None
    for df in [df_train, df_test]:
        pre_processing(df)
    # pd.options.mode.chained_assignment = 'warn'

    # 変換後データの確認
    # read_datasets(df_train, df_test)


    # 特徴量の対象とする項目を決定
    lst_params = ["Pclass", "Sex", "Age", "SibSp", "Parch", "Fare", "Embarked"]
    # lst_params = ["Pclass", "Sex", "Age", "Fare"]


    # 目的変数の値を取得
    response_var = df_train["Survived"].values

    # 説明変数の値を取得:追加となった項目も含めて予測モデルで使う値を抽出
    predictor_var = df_train[lst_params].values
    # テストからも説明変数の値を取得:実際の予測に使用するデータ
    test_predictor_var = df_test[lst_params].values

    # それぞれの結果格納用のDataFrameを用意する
    model_index = ["model_name","score","model"]
    df_models = pd.DataFrame(index=[], columns=model_index)

    # 確認するモデルリストを作成
    model_list = [  "DecisionTree", 
                    "LogisticRegression",
                    "Support Vector Machines",
                    "k近傍法(KNN)",
                    "Gaussian Naive Bayes",
                    "Perceptron","Random Forest"
                ]

    for index, name in enumerate(model_list):
        print(index, name)
        model = None
        # print(index)
        if(name == "DecisionTree"):
            # 決定木
            model = create_model_DecisionTree(predictor_var, response_var)
        elif(name == "LogisticRegression"):
            # ロジスティック回帰
            model = create_model_LogisticRegression(predictor_var, response_var)
        elif(name == "Support Vector Machines"):
            # Support Vector Machines
            model = create_model_SVM(predictor_var, response_var)
        elif(name == "k近傍法(KNN)"):
            # k近傍法(KNN)
            model = create_model_KNeighbors(predictor_var, response_var)
        elif(name == "Gaussian Naive Bayes"):
            # 単純ベイズ分類器またはナイーブベイズ分類器(Gaussian Naive Bayes)
            model = create_model_GaussianNB(predictor_var, response_var)
        elif(name == "Perceptron"):
            # パーセプトロン
            model = create_model_Perceptron(predictor_var, response_var)
        elif(name == "Random Forest"):
            model = create_model_RandomForest(predictor_var, response_var)
        else:
            print("Don't Exist Model")
            continue

        evaluation_score = evaluation(model, predictor_var, response_var)
        df_models = df_models.append(pd.Series([name, evaluation_score, model], index=model_index),ignore_index=True)

    # scoreでソート
    df_sorted_models = df_models.sort_values(by='score', ascending=False)
    pprint.pprint(df_sorted_models)

    # 一番精度が高そうなモデルを使って、テストデータに対して予測
    model = df_sorted_models.iloc[0]["model"]
    prediction = model.predict(test_predictor_var)

    # 予測結果をファイルに出力
    output_file(prediction ,df_test , "prediction_{0:%Y%m%d%H%M%S}.csv".format(datetime.datetime.now()))

    print("end")
githubの方も更新しておく。
RyoNakamae/kaggle_titanic
Contribute to RyoNakamae/kaggle_titanic development by creating an account on GitHub.

※これ、更新しちゃうと前回の記事の意味がわからなくなるな・・・

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

神戸にリージョ監督就任

ヴィッセル神戸、吉田孝行監督を事実上の解任!林健太郎氏が暫定監督に(関連まとめ)
【サッカー】神戸・吉田孝行監督を事実上の解任 林健太郎氏が暫定的に指揮
【速報】J1神戸、ペップ監督師匠のリージョ氏が新監督就任!吉田監督は事実上の解任(関連まとめ)
神戸 新監督にスペイン人のリージョ氏 マンC・グアルディオラ監督の“師匠”
神戸・三木谷会長、リージョ新監督就任に「まさか来てくれるとは思わなかった」監督「日本人の技術は高い」(関連まとめ)
【サッカー】<ヴィッセル神戸の新体制発表会見>三木谷会長「まさか来てくれるとは思っていなかった」新監督「日本人の技術は高い」
【小ネタ】徳島サポ、リージョ氏の神戸監督就任に安心する
【神戸】リージョ新監督が就任 会見にはイニエスタ、ポドルスキも出席

「事実上の解任」っていうと、クラブ寄りな監督にも対して退任を言わせるようにして違約金を払わないようなイメージがあるけど、今回の吉田さんはクラブには残るみたいだから、またちょっと違うケースになるんかな。どちらかというと、長期間の暫定監督だったとでも思えばいいのかな…

で、ポルディ、イニエスタを獲ったころからずっと「監督にも金を使えよ!」って言われてたが、まさかリージョを連れてくるとは。

監督としての実績や評判を考えると「理論な人」なイメージだがその「理論」を神戸で実現できるのか?そして実現まで三木谷さんは我慢できるのか。

サッカーの世界にはあまり無い概念だがオフェンスコーディネーターみたいな感じでお願いできると良かったりするのかなと思ったりもするけど。

「神戸をバルセロナ」にするのではなく、「神戸に合ったバルサ化」を見つけてくれるといろいろな指針にもなって面白くなるだろうなと期待。

三木谷さんにしてもリージョにしても、イニエスタにも相談してみたりしたのかな?

リージョ、ポルディ、イニエスタがいるようなチームになると、選手はオファーがあった時にスゲー悩むだろうな。

台風21号の猛威を可視化してみたかった話

目的

先日の台風21号関連の動画がTL上に流れてくるのを眺めていてふと思った。 「それぞれどこらへんの位置の動画なのだろう?」 わからなければ地図で可視化してみればいい。 ちょうど先日TwitterのAPIのストリーミングの仕様が変わったとかいうニュースもみかけていたので
久々にTwitterAPIも触ってみるかということで
Twitter上の台風関連の動画を地図上にポイント化してみる
ということを目的にスタートしてみる。
※いつものようにイメージはあるものの明確なゴールはない状態でスタート。

関連動画に対するTweetとその位置情報を集める

まずは[#台風21号]に動画がくっついているものを抽出してみる。
※おそらくニュースの動画とかが添付されていているものやパクツイとかもあるんだろうけどとりあえず何も考えずにピックアップしてみる。 仕様が変わってなければTwitterのSearchAPIは一週間ぐらい前までしか取得できないので、さっさと取得しておく必要があるので昔作った処理を流用するためにC#でやることにした。
public long GetTweet(long max_id)
{
    var API_Key = "xxxxxxxxxxxx";
    var API_Secret = "xxxxxxxxxxxx";
    var Access_Token = "xxxxxxxxxxxx";
    var Access_Token_Secret = "xxxxxxxxxxxx";

    var tokens = CoreTweet.Tokens.Create(API_Key, API_Secret, Access_Token, Access_Token_Secret);

    var parm = new Dictionary<string, object>();
    parm["count"] = 100;
    parm["q"] = "\"#台風21号\" -RT";
    parm["result_type"] = "mixed";
    parm["max_id"] = max_id;
    parm["f"] = "video";

    var tweets = tokens.Search.Tweets(parm);
    var setId = max_id;

    foreach (var tweet in tweets)
    {
        if (setId > tweet.Id) setId = tweet.Id;
        if (tweet.RetweetCount == 0) continue;
        if (tweet.Entities.Media != null && tweet.Entities.Media.Length != 0)
        {
            var tw_data = new TweetData();
            tw_data.CreatedAt_DateTime = tweet.CreatedAt.DateTime;
            tw_data.DisplayUrl = tweet.Entities.Media[0].ExpandedUrl;

            if (tweet.Place != null)
            {
                if (tweet.Place.Geometry != null)
                {
                    tw_data.Place_Geometry_Latitude = tweet.Place.Geometry.Latitude;
                    tw_data.Place_Geometry_Longitude = tweet.Place.Geometry.Longitude;
                }
                else
                {
                    tw_data.Place_FullName = tweet.Place.FullName;
                }
                list_tweet_data.Add(tw_data);
            }
            else
            {
                if (tw_data.DisplayUrl.Contains("photo"))
                {
                    list_tweet_data_no_geoinfo_photo.Add(tw_data);
                }
                else
                {
                    list_tweet_data_no_geoinfo_video.Add(tw_data);
                }
            }
        }
    }
    return setId;
}
※MaxIDを指定してそこから100件ずつ戻っていく形式になってます。 ※SearchAPIのオプション
Standard search API
結構な量になることは予想されたので、できるだけ取得対象を減らしたかった(APIのCALL回数の上限もあるため)ので以下のような条件にした。
parm["count"] = 100;
parm["q"] = "\"#台風21号\" -RT";
parm["result_type"] = "mixed";
parm["f"] = "video";
本当は近畿地方だけを取得しようと思い、
geocodeのオプションが使ってみたのだが、全く取得できなかったので止めた。
こんな感じのオプション:geocode:34.733165,-135.500214,100km
座標は新大阪駅(WGS1984)
※この時点で位置情報が付いているTweetはほぼないということを察するべきだったのかもしれない。 取得できた結果のうち、RetweetCountが0のものは別にいらないだろうという判断で取得後に除外。
※メディアがついていないものも取得後に除外。parm["f"] = "video"をつけているはずなのについてきてるものがあったため。画像も取得されていたのでこのオプションそのものが有効に働いてなかったのかもしれない。。

実行結果

15分に180Callしかできないのでここの取得処理に本当に時間がかかった。 で、なんやかんやで取得できたのが421件。
結論からいうと緯度経度が設定されていたTweetは一件もなかった。
みんなリテラシー高いな。 この段階で企画終了になりそうだったのだが、住所?的なものが設定されているのはいくつかあったのでせっかくなのでそれを可視化してみることにした。
ただ、緯度経度じゃないのでジオコーディングが必要。 ちなみに位置情報が未設定のものも含めた総数としては10000件弱。
せっかくなのでそれだけのページも作ってみたがこの作業が一番疲れた。
#台風21号 の画像/動画Tweet(位置情報)動画編(その1)
#台風21号 の画像/動画Tweet(位置情報)画像編(その1)
※動画はその5まで、画像に至ってはその13まである始末だ。 Tweetの系列順には並んでいるはずなので、備忘録としては割とありだなとは思ったが超めんどくさかった。
今回の企画でできあがるものよりも、こっちのサイトの方がたぶん見てて楽しいはずだ。

緯度経度取得

緯度経度をダイレクトに取得できたものは一件もなかった代わりにいくつか住所?っぽいものが取れたものがあるので
そこから緯度経度を取得してみる。
この辺のAPIを使うことにする。
findAddressCandidates—ArcGIS REST API: World Geocoding Service | ArcGIS for Developers
Use the World Geocoding Service to geocode by typing all address information into a single string.
ここでも厳密さは求めていないのでとりあえず最初に取れたものを信用してしまうことにする。
取れないものもあるが、その場合はとりあえずさっき調べた新大阪駅(34.733165,135.500214)にでもくっつけておく。 こんな感じでCSVにしてしまう
# ファイル読み込み
df = pd.read_table(r'tweet_data.tsv')

url = 'http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/findAddressCandidates?f=json&outFields=location&maxLocations=1&singleLine="{}"'
for index, row in df.iterrows():
    # 住所取得
    single_address = row['address']

    # 緯度経度取得
    res = requests.get(url.format(single_address)).json()

    if(len(res["candidates"])==0):
        # 取れなかった場合はとりあえず新大阪駅にでも紐づけておく
        df.at[index, 'x'] = 135.500214
        df.at[index, 'y'] = 34.733165
        continue 

    dic_location = res["candidates"][0]["location"]

    # 取得した値で元のDataFrameを更新
    df.at[index, 'x'] = dic_location["x"]
    df.at[index, 'y'] = dic_location["y"]

# CSVファイルとして出力する:indexはいらない。ヘッダーは必要
df.to_csv(r'tweet_data.csv', index=False)
簡単である。

TweetをGISへ

取得できた緯度経度を使って取得したTweetをGISへ流し込む。
CSVファイルをアップロードして前に作っていたArcGISへ。
今回はヘッダ付きのCSVでアップロードしているので特にややこしい各項目の設定は不要。 01_AGOL_01.PNG
01_AGOL_02.PNG
01_AGOL_03.PNG
01_AGOL_04.PNG
01_AGOL_05.PNG ということで出来上がりである。
なぜか変なところに設定されているものもいくつかある。
住所が日本語になっているものをURLエンコードしなかったからか? 01_AGOL_06.PNG 位置を直すのはたぶん結構めんどくさいので今回はやらない。
代わりにもう少しかっこよく表示できないかどうかを試してみる。
01_AGOL_07.PNG 実物はこんな感じ いろいろとやってみたかったがいくつか挫折。
以下は反省点や挫折点
  • Fav数やRT数も一緒にデータとして保持しておけばよかった。
    日時だけだと画像/動画を見に行くときの参考情報が少なすぎる

  • 可能であればその画面上でTweetのカード表示させたかったができなかった。

  • Cots&Configだけだと任意のJSは流せない?
    ポップアップ内にblockquoteは設定できるから
    <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
    を流せればカード化すると思うんだけどな。

  • 日時表記をなじみのある形式にしたかった

まとめ

  • とりあえずやりたかったことはできたので満足。
  • Twitterの新しいAPIはCoreTweetを使っている限りは意識しなくても問題なし?
  • もうちょっといろいろとやりたいこと/できそうなことはあるが、これ以上は自分のやる気が続かないのでおしまい。
  • Tweetの画像/動画を時系列で並べるということの方がちょっと面白かった。
  • ArcGIS Online上でTweetのカードが参照できればもうちょっと使いやすそうなものになるとは思うんだけどな。 ただ、Tweetする人がみな位置情報をくっつけてないので地図上で可視化する意味がほぼない。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

エンジニアリング組織論への招待のCh1だけ読んでみた

エンジニアリング組織論への招待
- Chapter1 思考のリファクタリング Chapter1を大雑把にまとめると「エンジニアリング」とはなんぞ?という話。
まだChapter1しか読み終わっていないが面白かったので自分用にピックアップ/整理してみた。
※もっといろいろと書いているけど書き出すとキリがないので結構適当だし、感想もところどころに混じってます。

工学とは、エンジニアリングとは

工学とは何かを「実現」していく学問。
ここでいう「実現」というのは、曖昧な状態からスタートし、具体的・明確さを増やす行為。
この曖昧さが「不確実さ」
この過程が「実現」 この曖昧さ/不確実さを減らしていくということが「エンジニアリング」の本質とも言える。
曖昧さ/不確実さというのは「わからないこと」のこと。
人間にとって、「わからないこと」というのは本質的には「未来」と「他人」ぐらいしかない。
つまりエンジニアリングというのはこの「未来」や「他人」という不確実性と向き合って、それらを減らしていく必要がある。
ただ、この「わからないもの」に向き合うということには「不安」が伴われる。 情報を生み出すことが不確実性を下げることにつながるが、
ソフトウェアを書く以外にも不確実性の削減はできるし、それもまた「エンジニアリング」の一部と言える。

論理的思考の盲点

論理的思考というのはつまり演繹的思考のこと。
論理的思考には2つの重大な前提がある
  • ルールと事象を正しく認知できること
  • 正しく演繹できること
この二つができないと論理的に考えることはできないが、そもそも正しく認知することはかなりむつかしい。
また、「論理的に考える」には、「非論理的に考えてしまう」瞬間を知ることが大事。 これはわかる。
たまに思考してるときに、「あ、今感情で判断したなー」って時があるし。

観測できないものは制御できない

観測できるのはあくまで結果であって能力などではない。でも「行動」は観測できる。
他人の「スキル」や「心境」は観測できるものではないけども、そこから生まれる行動は観測できる。
コントロールできるものを使って間接的に制御するしかない。

視野、視座、視点

「良い」プログラマには問題解決のための眼がある。
人間はそもそも完全な全体像を捉えることはできないので、それらを受け入れ視野視座視点を広く鋭く高く考えるように鍛えていくことが大事。

人間の不完全さを受け入れる

重要なのは自分の知性に対する絶え間ない疑いと、自分自身への洞察力。内省する力と言い換えることもできる。
自分自身がどのようなタイミングで間違った認知をし、間違った意思決定をしてしまうのかを知ることが重要。 よく言われる「失敗学」と同じような発想? 「自分は他人ではない」という当たり前の事実から立脚して、いかにコミュニケーションの不確実性を減らしていけるか?
これがエンジニアリングにとって重要な態度になる。
真に組織に求められるコミュニケーション能力というのは、コミュニケーションの不確実性を減少させる能力のことといえる。

勝手なまとめ

乱暴に簡単にざっくりとまとめてしまうと
何かをしようとした時のスタートはどうしたって曖昧さが多いし、それに対してやりたいことを実現していこうとするために情報を生み出していく必要がある。
ただ、その段階において思考や情報の非対称性、限定的な合理性によってカオスが生じてしまう。
って感じかな。
演繹法と仮説法は似てるけど全然違うというのは言われないと気がつかないかも。
仮説を立てるのはスキルではなくその仮説となる発想が出せるかどうかというのも面白い。
PDCAサイクルを回しているけど、その仮説/検証ってちゃんとわかってる?というのは意識しないといけないんだろうなとも思う。 書き散らしてから気が付いたけど、Qiitaに広木さんご当人が記事を書かれているのね。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

mockmock × AWS IoT Core × Lambda を試してみる

AWS IoTを使ってみたかった

ちょっとたしなんでみたいと思ったので[AWS IoT Core]を触ってみる。

構成案

手近に手軽なIoTのデバイスがなかったのでmockmockを使ってデバイス側についてはダミーとする。
IotCoreからの行先についてはノープラン。
とりあえずLambdaあたりにしておくことにする。
※Lambdaに飛ばせられればあとはどうとでもなるだろうという目算もあった。

mockmock:初期設定

最初にmockmockのアカウント作成。
SignUpからさくっと登録。簡単である。

AWS IoT Core

続いてAWS IoT側の設定。

証明書を作成する。

01.PNG 1-Click 証明書作成
02.PNG 作成した各ファイルをDL
03.PNG
※後々ハマった(※1)のだが、ここで「ルートCAのダウンロード」とあるリンク先にて証明書ファイルをDLしておく必要もある。
「ダウンロード」と書いてあるから、これを押すとDLが始まるのかと思ったが、そうではなかった。

ポリシー

ポリシーのアタッチを選択する
ポリシーがまだない場合はここから新規作成。
04_policy.PNG 05_policy.PNG
※これまた後々ハマる(※2)が、ここのリソースARNでこれを設定してしまうのはダメっぽい。 作成したポリシーは証明書にアタッチしておく。

Action?ルール?を設定

06_act.PNG 07_act.PNG 予定通りLambdaの関数を呼び出そうとするが、はたと気が付く。
呼び出し先の関数がない。
とりあえず動いていることがわかればいいので、前に作ったSlackへ飛ばすだけの関数を使いまわしてみることにする。 こんなやつ。
def lambda_handler(event, context):
    get_item_name = event['item']

    # 送信確認用にSlackへ飛ばす
    #送信先URL
    token = "xoxp-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    channel = "XXXXXXXXX"
    url = "https://slack.com/api/chat.postMessage?token={}&pretty=1&channel={}&text={}"
    import urllib.parse
    quote_item_name = urllib.parse.quote(get_item_name)
    url = url.format(token, channel, quote_item_name)

    #API実行
    import urllib.request
    urllib.request.urlopen(url)
    return "res:OK"
メッセージの条件はとりあえず適当に。
08_act.PNG これでAWS側の設定はOKなはずなのでmockmockへ戻って各設定を行う。
エンドポイントも忘れずに参照しておく。
09_act.PNG

mockmock側の設定

プロジェクトの作成

簡単かと思ったら認証でエラー。
上記で書いたRootCAのところでハマる(※1)。
どこからDLすりゃいいのかわからなかったが、よくよく読んでみると「ルートCAのダウンロード」の先のページのどれかでよさそうな感じなので、適当にDLして設定してみたところOK。[プロジェクトを作成しました]となった。
10_rootca.PNG
※ここから[RSA 2048 ビットキー: VeriSign クラス 3 Public Primary G5 ルート CA 証明書]のをDLして設定した。

データテンプレート、グループの作成

  • データ送信先パス:/topics/test/test
  • リクエストメソッド:POST
テンプレートについては「直接編集」すると戸惑うかもしれない。
「直接編集」といっても、送信できるデータを直接作成するということではなさそう。
KeyとValueにそれぞれ以下を設定してとりあえず一回試してみる。
"item": "from mockmock 01" 11_mockmock.PNG
12_mockmock_error.PNG エラーである。
mockステータスのところでテスト送信ができそうなのでここから送信してみるが、やはりエラー
よくわからない。かなり煮詰まった。

いろいろと試行錯誤してみた結果

ポリシーのリソースのところを*にしてみたら通った。(ハマった点※2)
要するに外からのアクセスを許容してなかったってことなのか?

上手くいった設定を以下に残しておく。

AWS IoT Core:証明書

ポリシードキュメント

{
"Version": "2012-10-17",
"Statement": [
    {
    "Effect": "Allow",
    "Action": "iot:*",
    "Resource": "*"
    }
]
}

モノ

無し

AWS IoT Core:Act(ルール)

〇ルールクエリステートメント
SELECT * FROM 'test/test' 〇アクション
Lambda関数を呼び出す

mockmock

プロジェクト

〇プロトコル
HTTPS 〇送信先ホスト
AWS IoT Core のエンドポイント 〇各証明書
DLしたもの

データテンプレート

〇HTTP Request Body / MQTT Payload
13_mockmock.PNG

mockグループ

〇mockステータス:データ送信先パス
/topics/test/test

こんな感じの結果になった

状態遷移を適当にいじると時間経過で次に呼び出されるものが確率で変更されるような感じ。
14_mockmock_result.PNG バリュージェネレータを使うとリストの中の値を指定した方法で抽出して設定してくれる。 15_mockmock_rundam.PNG 14_mockmock_rundam.PNG

まとめ

ということで、mockmock × AWS IoT Core × Lambdaの試しは終了。
Lambdaの関数そのものは何一ついじらずにAWS IoT Core と連携させてデバイス無しでそれの検証ができたというのは便利なんだろうなと思った。
この後、実際にデバイスを用意してどう送信するといいかまでわかると検証としては良かったのかもしれない。 AWS IoT Coreを試したのか、mockmock を試してみたのかよくわからないが、やってみたかったことはできたので良しとしておこう。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

Bitnami