はじめに
こんにちは清水です!
この記事は、Xonsh Advent Calendar 2018 – Qiitaの6日目の記事です。
AWSの話題を中心に、日々の業務やプログラミングの徒然を綴るエンジニアブログです。
HANDS LAB ENGINEERS BLOG
ハンズラボエンジニアブログ
こんにちは!新卒の清水です。
最近、勉強または趣味でやっていたPyQの機械学習・初級をやり終えたので自分でもやってみました。
以前Kaggleのチュートリアルはやったことはありますが、用意されているデータの説明がやはり英語だったのでそれなりにハードルがありました。
なので今回はネットを放浪中にポケモンのcsvデータがあったので、これを使用して行きたいと思います。
個人的にみずタイプのポケモンが好みなのでステータスからみずタイプかどうか判定しようと思います。
OS: macOS High Sierra 10.13.5
Python: 3.6.5
scikit-learn : 0.19.1
jupyter notebook
pandasを使用してcsvデータを読み込みます。
1 2 |
pip3 install pandas |
1 2 3 4 |
import pandas as pd df = pd.read_csv('pokemon_status.csv') df.head(10) |
1 2 |
df.info() |
ポケモンが909体(メガ進化も含む)なのでどうやら第七世代(サン・ムーン)までのデータのようです。
ポケモンの各ステータス(HP, こうげき, ぼうぎょ, とくこう, とくぼう, すばやさ)を説明変数X、タイプを目的変数yとして学習させていこうと思います。
みずタイプであるのか、そうでないのかで判断したいのでみずタイプのポケモンには1をそうでないものには0を付与します。
関数を用意
1 2 3 4 5 6 7 8 9 |
def type_to_num(type): if type == 'みず': return 1 else: return 0 # type_numの列を作成 df['type_num'] = df['タイプ1'].apply(type_to_num) |
applyメソッドを使用すると指定した列データ全てに関数を実行してくれます。
データをみてみましょう。
1 2 |
df.iloc[9:15] |
みずタイプが含まれている行を出してみました。みずタイプには1が振られています。
もちろんscikit-learnを使用して学習させます。
今回は目的変数が2値なのでロジスティック回帰で行います。
トレーニングデータとテストデータの割合は7:3で分割します。
1 2 |
pip install scikit-learn |
C = 1000としていますがこのCはハイパーパラメータと呼び、Cの値が大きすぎるほど過学習しやすくなり、小さすぎると学習にならない問題があります。
今回はCの値を0.01, 0.1, 1, 10, 100, 1000とパラメータを変えて影響があるか確認し、特に影響がなかったので1000のまま放置してます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
X = df.iloc[:,7:12] y = df['type_num'] # トレーニングデータとテストデータに分ける from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3) # ロジスティック回帰の呼び出し from sklearn.linear_model import LogisticRegression lr = LogisticRegression(C=1000) # データを学習させる lr.fit(X_train, y_train) # スコアを表示 lr.score(X_test, y_test) |
およそ87%の割合で判定することができました。
ほぼ自分一人の力で機械学習をしたのは初めてなのでまぁまぁいいのではないかと思います。
判定に失敗した例としてオーダイルをみずタイプではないと判定しました。
そんなにポケモンを知らなくても、見れば多くの人はみずタイプだろうと判断するでしょう。
しかし、オーダイルの進化前のアリゲイツはみずタイプと判定しました
改善案としてはステータスの族ごとに学習をさせることで改善することはできると思います。
ですが、より高い精度を求めるならポケモンの画像データを使用するのがいいと思いました(全体的に青っぽいとか)。
ポケモンの知識がないと難しいところがあるのでやはりデータのリサーチは必要だということを感じました。
全体的な機械学習の流れは覚えられてきたのでこれから色々と試していきたいと思います。
こんにちは2018年度新卒の清水です!
新人研修でHTML, CSS, JavaScriptを使いwebアプリを作っています。
私はフロントをあまり書いてこなかったので心機一転して学習しています。
ちなみに、学生のときサーバサイドをやってました(JavaとPythonはよく書いてました)。
バージョンは3.6.5です
flaskをインストールします
1 2 |
pip3 install flask |
MySQLからデータを取得するところは省きます
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# coding: UTF-8 from flask import Flask, make_response import json import db_conect api = Flask(__name__) @api.route('/', methods=['GET']) def get_user(): row = db_conect.get_task() res_json = { 'title' : row[2], 'details': row[3], 'limit': str(row[4]), 'insert': str(row[5]), } return make_response(json.dumps(res_json, ensure_ascii=False)) if __name__ == '__main__': api.run(host='localhost', port=8080) |
とりあえず curlコマンドでjsonが取得できるかテストします
1 2 |
curl http://localhost:8080/ | jq . |
1 2 3 4 5 6 7 |
{ "title": "リスト作成", "details": "html, css, jsを使う", "limit": "2018-05-05 00:00:00", "insert": "2018-04-29 00:41:17" } |
ちゃんと取れました
HTML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <h1>Ajax練習</h1> <p>アクセス先 : http://localhost:8080/ </p> <p>リクエストメソッド : GET</p> <input type="text" class="input"> <button class='get-btn'>ボタン</button> <div class="info"></div> <script src="http://code.jquery.com/jquery-3.3.1.js"></script> <script src="test.js"></script> </body> </html> |
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$(function() { $('.get-btn').on('click', () => { //http通信開始 $.ajax({ url: "http://localhost:8080/", dataType: "json", type: "GET", }).done(function(res) { console.log(res) }).fail(function(res) { console.log(res) }); }); }); |
ボタンが押されたらajax通信をしてjsonを取得します
見た目はこのように
Chromeのデベロッパーツールを使用してテストを見ていきます
おや?エラーを吐きました
翻訳すると
1 2 3 |
要求されたリソースに「Access-Control-Allow-Origin」ヘッダーが存在しません。 したがって、原点「ヌル」はアクセスが許可されません。 |
なんだかよくわかりませんね
Access-Control-Allow-Origin + flask でググっていると以下のサイトを見つけました
Javascript – No ‘Access-Control-Allow-Origin’ header is present on the requested resource
どうやらPython3系以降は pip install flask-cors
でflask-corsを使用して解決するそうです。
私はpip3 install flask-cors
で入れました。
1 2 3 4 5 6 7 8 9 10 11 12 |
# coding: UTF-8 from flask import Flask, make_response from flask_cors import CORS #追加 import json import db_conect api = Flask(__name__) CORS(api) #追加 # 以下同文 |
解決していない…なぜだ
前記したサイトにはPython2系の解決法も記載されていたのでこちらもテスト
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# coding: UTF-8 from flask import Flask, make_response import json import db_conect api = Flask(__name__) # 追加 @api.after_request def after_request(response): response.headers.add('Access-Control-Allow-Origin', '*') response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization') response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS') return response # 以下同文 |
ついに成功!
なぜPython2系の解決法で成功したのかは不明
Access-Control-Allow-Origin', '*'
を設定することにより、任意のドメインがサイト間でアクセスできるようになるだんだん調べて行くとSame-Origin Policy(同一生成元ポリシー)やCORS(Cross-Origin Resource Sharing)制限などのネットワーク用語が出てきたので理解できるよう努力していきたいと思っています。
こんにちは。百木田です。
CI、回してますか?
CodePipelineで実行するステージの進行状況を手軽に見たいと思い、Slackに流れるようにしたので共有します。
ポイントとしては、CodePipelineからLambda functionを呼ぶのではなく、CloudWatchイベントでCodePipelineステージのステータスの変化を検知してLambda functionを呼び出します。
今回はできるだけシンプルにするために、すでにCodePipelineは作成済みの想定で、すべてのステージにおけるSUCCEEDEDとFAILEDのステータスを通知します。なのでCodePipelineに変更は必要ありません。
また、Slack Botを作成しトークンを発行して使っていますがIncomming Webhookでも同じようなことはできるかと思います。
Serverless Frameworkを使ってCloudWatchイベントの設定と、slackに通知するためのLambda functionをデプロイします。
1 2 3 |
$ serverless version 1.22.0 |
1 2 3 4 5 |
- functions/ - status_notification.py - serverless.yml - serverless.env.yml |
コードは記事の下の方に書いときます。上記のディレクトリ構成のように配置したらデプロイします。
1 2 |
$ serverless deploy |
デプロイできたらCodePipelineを動かしてみます。そうするとslackにこのような通知が来るかと思います。
いつの実行結果なのかをトレースできるようにCodePipelineの実行IDの前半7桁を表示しています。この辺はお好きにカスタマイズしてみてください。
CloudWatchイベントの検知がリアルタイムじゃないので、CodePipelineの進行と通知にラグがあったり、前のステージの実行完了と次のステージの実行開始の通知が前後することなどもありますが、実行結果がわかればいいかなくらいの感じなので気にしないことにしてます。
ありがとうございました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# -*- coding:utf-8 -*- """CloudWatch Eventから送られてきたCodePipelineのステージステータスの変更をSlackに通知する""" import os import boto3 import urllib.request, urllib.parse URL = 'https://slack.com/api/chat.postMessage' SLACK_BOT_TOKEN = os.environ['SLACK_BOT_TOKEN'] CHANNEL = os.environ['CHANNEL'] client = boto3.client('codepipeline') def handler(event, context): stage_name = event['detail']['stage'] state = event['detail']['state'] pipeline_execution_id = event['detail']['execution-id'] post_message = '[' + pipeline_execution_id[:7] + '] ' + ' ' + state.ljust(10) + ': ' + stage_name post_data = {} post_data['text'] = post_message post_data['token'] = SLACK_BOT_TOKEN post_data['channel'] = CHANNEL data_encoded = urllib.parse.urlencode(post_data).encode("utf-8") req = urllib.request.Request(URL, data_encoded) with urllib.request.urlopen(req) as response: response.read().decode('utf-8') return |
1 2 3 4 |
slack: BOT_TOKEN: xoxb-xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxx CHANNEL: XXXXXXXXX |
※ detailのセクションを消すと、すべてのステータスが検知対象になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
service: slack-notification-sample frameworkVersion: ">=1.18.0 <2.0.0" provider: name: aws runtime: python3.6 region: ap-northeast-1 stage: dev environment: TZ: Asia/Tokyo package: include: - functions/** exclude: - serverless.yml - serverless.env.yml functions: statusNotification: handler: functions/status_notification.handler events: - cloudwatchEvent: event: source: - aws.codepipeline detail-type: - CodePipeline Stage Execution State Change detail: state: - SUCCEEDED - FAILED environment: CHANNEL: ${file(./serverless.env.yml):slack.CHANNEL} SLACK_BOT_TOKEN: ${file(./serverless.env.yml):slack.BOT_TOKEN} |
皆々様、お久しぶりのブログ更新です。
Kinesis FirehoseがS3に出力したファイルをPythonでモニャモニャしたいと思っていたところ以下のことでつまづいてしまいました。
1つのファイルに複数レコード出力されている場合、改行(区切り文字)がなく1レコードずつ読み込めない!
改行とか入っていて、1行ずつ読み込むんだろう・・・みたいな想像を勝手にしていたのでちょっとつまずいてしまいました。
AWSのデモデータをKinesisFirehoseに流すと実際のファイルはの中身は下記のようになります。
1 |
{"ticker_symbol":"TGH","sector":"FINANCIAL","change":-0.6,"price":65.43}{"ticker_symbol":"JYB","sector":"HEALTHCARE","change":-2.27,"price":42.95}{"ticker_symbol":"WAS","sector":"RETAIL","change":0.53,"price":13.04}{"ticker_symbol":"NGC","sector":"HEALTHCARE","change":0.32,"price":5.41} |
こういったJsonストリームデータをPythonで処理する時ってどうしたらいいんだろうと調べていたらjsonライブラリにJSONDecoderというのがあるのを見つけました。
下記サンプルです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import json import boto3 s3 = boto3.resource('s3') bucket = s3.Bucket('backet name') obj = bucket.Object('key name') obj = obj.get() json_stream = obj['Body'].read() decoder = json.JSONDecoder() while len(json_stream) > 0: record, index = decoder.raw_decode(json_stream) json_stream = json_stream[index:] print record |
これを実行すると下記のように出力されました〜。
1 2 3 4 |
{"ticker_symbol":"TGH","sector":"FINANCIAL","change":-0.6,"price":65.43} {"ticker_symbol":"JYB","sector":"HEALTHCARE","change":-2.27,"price":42.95} {"ticker_symbol":"WAS","sector":"RETAIL","change":0.53,"price":13.04} {"ticker_symbol":"NGC","sector":"HEALTHCARE","change":0.32,"price":5.41} |
そうです、この記事・・・単にストリームデータの読み込み方についての記事です!KinesisFirehoseは完全に引きです!
でもストリームデータを扱うことは個人的には今後も増えそうなので今回調べておいてよかったです!
ではでは〜。
エンジニア募集中!
人気記事
最新記事
カテゴリー