oinume journal

Scratchpad of what I learned

gcloudコマンドを使わずにGoogle Cloud Storageにファイルをアップロードする

概要

gcloudコマンドを使わずにPythonとgoogle-cloudを使ってGoogle Cloud Storage(GCS)に頑張ってファイルをアップロードしてみる。google-cloudはPython向けのGoogle Cloud Platformの何かを操作するためのクライアントライブラリ。GCPの以下の機能の操作がサポートされている。

  • GA
    • Google Cloud Datastore
    • Google Cloud Storage
    • Google Cloud Translation
    • Stackdriver Logging
  • Beta
    • Google BigQuery
    • Google Cloud Natural Language
    • Google Cloud Speech
    • Google Cloud Video Intelligence
    • Google Cloud Vision
  • Alpha
    • Google Cloud Bigtable
    • Google Cloud Bigtable
    • Google Cloud DNS
    • Google Cloud Pub/Sub
    • Google Cloud Resource Manager
    • Google Cloud Runtime Configuration
    • Google Cloud Spanner
    • Stackdriver Error Reporting
    • Stackdriver Monitoring

gcloudコマンドはPython 2.7を必要とするんだけど、Python 2.7をどうしてもインストールできない環境で役立つ話だと思う。自分はHerokuでPython 3.6.x を使っていて、gcloudコマンドのためにPython 2.7をインストールできなくて困っていたのだけど、このgoogle-cloudライブラリを使うようにしてみた。

セットアップ

前提として

  • Python 3.4 以上
  • pip

がインストールされていること。

$ pip install google-cloud

でgoogle-cloudをインストールする。

認証

google-cloudのライブラリを使うにあたり、credentialが必要になる。おそらく一番ラクなのは

  • GCPのConsoleでService Accountを作って
  • そのcredential情報をJSONファイルとして取得し
  • GOOGLE_APPLICATION_CREDENTIALS 環境変数で指定する

ことだと思う。詳しい話は google-authのドキュメントに書いてある。その他の認証のやり方についても詳しく書いてある。

Pythonのスクリプトを実行する前に以下のコマンドで credential 情報のJSONファイルを指定すれば、Pythonのスクリプトでは特に何もしなくてOKだ。

$ export GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json

GCSにファイルをアップロードする

それでは本題。google-cloudのstorageモジュールを使ってGCSにファイルをアップロードしてみる。

  • get_bucketでバケットを取得して
  • blobオブジェクトを作ってアップロードする

感じ。

from google.cloud import storage
import sys


def upload(bucket_name, f):
    client = storage.Client()
    bucket = client.get_bucket(bucket_name)
    new_blob = bucket.blob(f)
    new_blob.upload_from_filename(f)


if __name__ == '__main__':
    if len(sys.argv) < 3:
        print('gcs.py <bucket> <file>', file=sys.stderr)
        sys.exit(1)
    upload(sys.argv[1], sys.argv[2])

まとめ

gcloudコマンドは早くPython3対応するかGoで書き直されて欲しい。

プログラマのためのGoogle Cloud Platform入門 サービスの全体像からクラウドネイティブアプリケーション構築まで

プログラマのためのGoogle Cloud Platform入門 サービスの全体像からクラウドネイティブアプリケーション構築まで

2017年の進捗

2017年の抱負 - oinume journal で書いた、今年の抱負の進捗。

機械学習を学ぶ

みんなのAI講座 ゼロからPythonで学ぶ人工知能と機械学習 | Udemy というものをやったけど、本当にまだまだわからないことが多い。あと、自分は機械学習よりもデータ分析の方が現時点ではオモシロイと感じている。numpyやpandasは少しわかってきたので、もう少し深掘りしていきたいところ。

Twitterの時間を制限する

うまくいった。唯一Twitterだけずっとやめられなかったけど、頻度は1日1回以下、時間は15分以下に抑えられてる。ひどい時は1日1時間ぐらい見ていたのでだいぶ改善したと思う。

辞められたのは、やっぱりスマホからアプリを削除したのが一番大きい。手癖のように暇さえあればTwitterのアプリを起動してしまっていたので、これが物理的にできなくなった。今はTwitter見たい時はブラウザで頑張って見てる。使いづらいけど、はまりたくないのでちょっと使いにくいぐらいが逆にちょうどいい。

去年より本を読む

Twitterをやめたことで、通勤時間に本を読む時間が増えた。とりあえずこの半年で読んだ本。

ルポ MOOC革命――無料オンライン授業の衝撃

ルポ MOOC革命――無料オンライン授業の衝撃

ルポ MOOC革命――無料オンライン授業の衝撃

2013年の本だけど、オンラインでの学習というものがここまで多様化していることに驚いた。感想は読書感想「ルポ MOOCS革命」 - oinume journal に書いてある。

新・所得倍増論

デービッド・アトキンソン 新・所得倍増論―潜在能力を活かせない「日本病」の正体と処方箋

デービッド・アトキンソン 新・所得倍増論―潜在能力を活かせない「日本病」の正体と処方箋

戦後の日本の高度経済成長の理由は単純に人口増加だったという説を説く本。グラフを見るとたしかにその通りだなぁと思う。この本を見て、安倍内閣のやっていることはまともなんだなとあらためて思った。

初めてのPHP

初めてのPHP

初めてのPHP

  • 作者: David Sklar,桑村潤,廣川類,木下哲也
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2017/03/18
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る

仕事でPHPを書かなくてはいけなくなったので仕方なく。特に新しい学びはなかった。中級者向けのPHPの本があったら教えて欲しい。

Google AdSense 成功の法則 57

Google AdSense 成功の法則 57

Google AdSense 成功の法則 57

自分で運営しているサイトのAdSenseの収益を上げたくて購入したけど、特に目新しいことは書いていなかった。

日本人の9割が知らない遺伝の真実 (SB新書)

日本人の9割が知らない遺伝の真実 (SB新書)

日本人の9割が知らない遺伝の真実 (SB新書)

橘玲の「言ってはいけない 残酷すぎる真実」よりかは信憑性がありそうだったので購入。IQや体重の遺伝の影響など、興味深いトピックが多かった。たまに「ほとんどすべてが遺伝で決まる」みたいなことを言う人がいるけど、決してそうではないと分かったので少し安心した。

徹底調査 子供の貧困が日本を滅ぼす 社会的損失40兆円の衝撃

徹底調査 子供の貧困が日本を滅ぼす 社会的損失40兆円の衝撃 (文春新書)

徹底調査 子供の貧困が日本を滅ぼす 社会的損失40兆円の衝撃 (文春新書)

日本の家庭の6分の1が相対的貧困にある日本の実体について、インタビューをまじえながら書かれている。貧困が連鎖することがどのぐらい日本の財政に影響をあたえるかなど面白かった。日本は教育については他の国と比べて国からの支援が弱いのでもっと頑張ってほしいな。最近流行りのGRIT(やり抜く力)は第3者が介入することで補完できる、など教育についても興味深いことがたくさん書いてあった。

プログラマのためのDocker教科書 インフラの基礎知識&コードによる環境構築の自動化

プログラマのためのDocker教科書 インフラの基礎知識&コードによる環境構築の自動化

まだ読み途中。Dockerの本はたくさん出ているけど、Dockerの仕組みがわかりやすく書いてある気がする。

英語

ショッキングなことに、昨年のTOEICからスコアが下がっていた。800点まではあと少しなので頑張りたいけど、非ネイティブの人とはだいたい意思疎通できるようになったので、自分的には今のレベルで満足している。

アルゴリズム勉強する

あんまりできてない。

VPSをやめる

これはやめられていない。とりあえずvultrの一番安い$2.5のプランにしてお金の節約はしてみた。

MySQLのデータをJupyter Notebook上でグラフにする

最近少しずつJupyter Notebookやpandas, matplotlibに慣れてきて、PythonによるData Scienceが面白くなってきたと感じてます。今日はMySQLのデータをSQLで持ってきて、Jupyter Notebook上でグラフにしてみる話。

セットアップ

Python3はインストールされていることを前提。jupyterなどの必要なソフトウェアを入れる環境を作って、pip でインストールする。

python3 -m venv jupyter
source jupyter/bin/activate
pip install jupyter pandas matplotlib pymysql

インストールが成功したら、こんな感じでJupyter Notebookを立ち上げる。

./jupyter/bin/jupyter notebook

立ち上がったらブラウザから適当にnotebookを作っておく。

MySQLに接続

今回はPure Pythonなpymysqlを使ってMySQLに接続する。接続先の情報は以下の例では環境変数から取っているけど、ここはpymysql.connectに直接渡すように変更してOK。connという変数に入っているのが、MySQLへのコネクションになる。

import os
import pymysql
import pandas as pd
import matplotlib.pyplot as plt

host = os.getenv('MYSQL_HOST')
port = os.getenv('MYSQL_PORT')
user = os.getenv('MYSQL_USER')
password = os.getenv('MYSQL_PASSWORD')
database = os.getenv('MYSQL_DATABASE')

conn = pymysql.connect(
    host=host,
    port=int(port),
    user=user,
    passwd=password,
    db=database,
    charset='utf8mb4')

pandas.read_sql_queryを使ってSQLを実行

df = pd.read_sql_query(
    "SELECT DATE(created_at) AS date, COUNT(*) AS count FROM user GROUP BY date HAVING date >= '2017-04-01' ",
    conn)

次にpandas.read_sql_queryを使って、MySQLからSQLで取得した結果をpandas.DataFrameにする。この関数には

  • 第1引数にSQL
  • 第2引数にMySQLのコネクション

を渡せばよい。これだけでMySQLから取得した結果がそのままDataFrameになるなんて簡単すぎる…

ちなみに今回は以下のuserテーブルから、日付ごとに登録したユーザー数を取得するSQLを発行している。

CREATE TABLE `user` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  `email` varchar(255) CHARACTER SET utf8mb4 NOT NULL,
  `followed_teacher_at` datetime DEFAULT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `email` (`email`)
);

read_sql_queryを実行した結果の df を表示してみるとこんな感じになっている。

f:id:oinume:20170601191237p:plain

DataFrameをグラフにする

最後に本題のグラフ化。DataFrameのindexに date カラムの値をセットして、DataFrameのplot.bar()を呼び出せば棒グラフが表示される。

%matplotlib inline はJupyter上にグラフを表示するためのおまじないっぽい。df.tail(10)しているのは直近の10件に絞って見やすくするため。

%matplotlib inline

df.index = df['date']
p = df.tail(10).plot.bar()

f:id:oinume:20170601211553p:plain

ちなみに plot.pie() とかやると円グラフが表示できる。描画できるグラフの種類についてはpandasのvisualizationというページに全部載っている。

まとめ

  • pandas.read_sql_query を使うと、SQLでSELECTした結果をそのままDataFrameにできる
  • DataFrameからグラフを表示するのは簡単
  • いろんな種類のグラフが描画できるよ

おまけ

gistに今回のnotebookを上げておいたのでよかったらどうぞ。

Udemyがなかなかいい感じ

最近は健康のために、六本木→渋谷まで歩いて帰っているのでPodcastをよく聴くようになった。1日30分以上歩いていて、その間は暇なのでPodcastを聞いていたのだけれどPodcastが在庫切れになってしまった。どうしようかと悩んでいたところ、以前Udemyでいくつかコースを購入したことを思い出して、Udemyのコースを垂れ流すようにしたところいい感じに技術的なものが勉強できるようになった。UdemyがPodcastよりいいなと思ったのは

  • (自分が聞いている)Podcastだと話している内容が薄いが、Udemyは学習サイトなのでPodcastよりは内容は濃い
  • 聞いていてどうしても画面を見なくてはいけない時は立ち止まって見れば良い。もしくは電車の中で再度見直す
  • 英語OKな人だったら本当に様々なコースがある(React, Machine Learning, Docker, etc…)
  • Udemyは定期的にキャンペーンをやっていて、普段だったら2万円かかるようなコースが1200円になっていたりする
    • 例えば今だとUdemy Learn Festという割引キャンペーンをやっている(5/27まで)
    • さらにiOS/Androidアプリ限定で常設的な割引キャンペーンもやっている

という点。1200円という値段なら書籍を買うより安くつく。特にアプリの使い方を学ぶような場合は動画の方が効率的に学習できると思う。というわけでUdemyオススメです。

go test in practice

This blog post describes basics and practical examples of go test. Go’s automated test mechanism is well designed and easy to use. I’ll show you some techniques of go test in this article.

What is go test

go test is a command to run automated tests of go packages.

  • Automated test must be defined in _test.go file
  • Automated test function must start with Test prefix

Example: stack

I implement a stack as real world example to explain go test. stack package provides stack.go. If you want to write tests for stack.go, create a file named stack_test.go. The source code is in GitHub repository.

go test [packages]

First of all, let’s test a simple function stack.NewIntStack.

package stack

import "testing"

func TestNewIntStack(t *testing.T) {
    istack := NewIntStack()
    if istack == nil {
        t.Error("NewIntStack() returns nil")
    }
}

The test checks NewIntStack returns non nil. To run the test, type go test ./stack. You’ll get following output. It means the test succeeded.

go test ./stack

ok      github.com/oinume/go-test-in-practice/stack       0.136s

go test -v

-v flag enables verbose mode. You can get a message TestNewIntStack finished by running with -v flag.

func TestNewIntStack(t *testing.T) {
    istack := NewIntStack()
    if istack == nil {
        t.Error("NewIntStack() returns nil")
    }
    t.Log("TestNewIntStack finished") // This message is output only in verbose mode
}
go test -v ./stack

=== RUN   TestNewIntStack
--- PASS: TestNewIntStack (0.00s)
        stack_test.go:10: TestNewIntStack finished
PASS
ok      github.com/oinume/go-test-in-practice/stack       0.132s

all outputs in STDOUT are printed in verbose mode. You can use t.Log or t.Logf if you want to print a message with line number.

If you want to do something only when verbose mode, You can use testing.Verbose() in your test code.

go test -short

You can use -short flag to skip long-running tests. You can refer the flag is on or off by testing.Short() in your test.

Example:

func TestIntStack_PushALot(t *testing.T) {
    if testing.Short() {
        t.Skip("Skip pushing a lot of numbers to a stack")
    }
    istack := NewIntStack()
    for i := 0; i < 10000000; i++ {
        istack.Push(i)
    }
}

go test -run

-run flag is used to specify tests to run. If you have test functions TestNewIntStack and TestIntStack_PushALot, you want to run only TestIntStack_PushALot. You’ll save time with -run flag in order to avoid running whole tests.

Example:

go test -run TestIntStack_PushALot ./stack

=== RUN   TestIntStack_PushALot
--- PASS: TestIntStack_PushALot (1.01s)
PASS
ok      github.com/oinume/go-test-in-practice/stack       1.156s

reflect.DeepEqual

You can use reflect.DeepEqual to compare two values of structs. Following example ensures istack1 and istack2 are the same.

func TestIntStack_Compare(t *testing.T) {
    istack1 := NewIntStack()
    istack2 := NewIntStack()
    for i := range []int{1, 2, 3} {
        istack1.Push(i)
        istack2.Push(i)
    }
    if !reflect.DeepEqual(istack1, istack2) {
        t.Errorf("Stacks must be the same: istack1.Size=%d, istack2.Size=%d", istack1.Size(), istack2.Size())
    }
}

TestMain

TestMain is a main function in automated tests. Sometimes it is necessary for a test program to do extra setup or teardown before or after testing. If func TestMain(m *testing.M) function exists in your package, the generated test will call TestMain(m) instead of running the tests directly. This is an example to set up and tear down with TestMain.

func TestMain(m *testing.M) {
    // Set up something for tests
    status := m.Run()
    // Tear down something for tests
    os.Exit(status)
}

And more

go test has much more features like benchmark, example test, etc. You’ll find them out in document of testing package. There are also good slides of testing like Advanced Testing with Go // Speaker Deck.