akiyoko blog

akiyoko の IT技術系ブログです

まだ CSV の文字化けで消耗してるの?(Excel で直接開いても文字化けしない CSVファイルを Python3 で作成するスマートな方法)

この投稿は 「python Advent Calendar 2017 - Qiita」 の 9日目の記事です。

こんにちは、akiyoko です。
「Python Advent Calendar」は 4年連続 4度目の参加になります。 *1, *2, *3



はじめに

皆さん、CSV は好きですよね? Excel も大好きですね?
じゃあ当然、CSVファイルは Excel で開きますよね。

文字化けは? ・・もちろん嫌いですよね。
でも CSVファイルを Excel で開こうとしたときに、こんな文字化け地獄を経験したことはありませんでしたか? *4


f:id:akiyoko:20171205230423p:plain:w400


ということで今回は、Excel で直接開いたときに文字化けしない CSV ファイルを Python3 で作成する方法 を紹介したいと思います。(おまけで Python2 でのやり方も書いておきますが、今時 Python2 で消耗している人なんていないですよね? *5



 

結論

結論を先に書くと、

  • Unicode の文字符号化方式は 「UTF-16(正確には、BOMありの UTF-16 LE)」
  • タブ区切り

で CSVファイルを作成すれば、Excel で直接開いても文字化けせず、それぞれの値がセルごとに分かれて表示されます。


(参考)Which encoding opens CSV files correctly with Excel on both Mac and Windows? - Stack Overflow



Windowsでは、リトルエンディアンのUTF-16符号化スキームが使われている。内部表現では16ビット符号なし整数を符号単位とするUTF-16符号化形式(CEFなのでBOMはなし)として扱い、ファイルなどではBOMありのUTF-16符号化スキーム(リトルエンディアン)が主である。


UTF-16 - Wikipedia

Note Microsoft uses UTF-16, little endian byte order.


Using Byte Order Marks | Microsoft Docs

とあるように、Microsoft Excel が 「BOMありの UTF-16 LE」を扱っているため、この方法がベストと言えそうです。


なお、「CSV(Comma-Separated Values)」と言いながらも区切り文字がタブなので、厳密には「TSV(Tab-Separated Values)」と呼ぶべきでしょうか。議論の余地はあるものの(*6)、拡張子を「.csv」としておくことでダブルクリック時に自動的に Excel が起動してくれるので(アプリケーションが関連付けられているので)、拡張子は「.csv」とした方がよいでしょう。



 

検証(Python 3)

ファイルオープン時に「encoding='utf-16'」と指定することで、符号化方式が「UTF-16 LE with BOM」となります。
「encoding='utf-8-sig'」(UTF-8 with BOM)だと、環境によっては(Mac + Excel 2011 とか?)文字化けすることがあるので推奨しません。

import csv


def main():
    rows = [['髙﨑 將'], ['あああ', 'いいい', 'ううう'], ['Ⅰ・Ⅱ・Ⅲ', '①②③']]

    # OK
    with open('utf_16_excel_tab.csv', 'w', newline='', encoding='utf-16') as f:
        w = csv.writer(f, dialect='excel-tab', quoting=csv.QUOTE_ALL)
        w.writerows(rows)

    # これでもOK
    with open('utf_16_excel_tab_2.csv', 'w', newline='', encoding='utf-16') as f:
        w = csv.writer(f, dialect='excel', delimiter='\t', quoting=csv.QUOTE_ALL)
        w.writerows(rows)

    # 文字化けしないが、セルごとに分かれないのでNG
    with open('utf_16.csv', 'w', newline='', encoding='utf-16') as f:
        w = csv.writer(f, quoting=csv.QUOTE_ALL)
        w.writerows(rows)

    # 文字化け (しない場合もある)
    with open('utf_8_sig.csv', 'w', newline='', encoding='utf-8-sig') as f:
        w = csv.writer(f, quoting=csv.QUOTE_ALL)
        w.writerows(rows)

    # 文字化け (しない場合もあるが、セルごとに分かれないのでNG)
    with open('utf_8_sig_excel_tab.csv', 'w', newline='', encoding='utf-8-sig') as f:
        w = csv.writer(f, dialect='excel-tab', quoting=csv.QUOTE_ALL)
        w.writerows(rows)

    # 文字化け
    with open('utf_8.csv', 'w', newline='', encoding='utf-8') as f:
        w = csv.writer(f, quoting=csv.QUOTE_ALL)
        w.writerows(rows)

    # 文字化け
    with open('utf_8_excel_tab.csv', 'w', newline='', encoding='utf-8') as f:
        w = csv.writer(f, dialect='excel-tab', quoting=csv.QUOTE_ALL)
        w.writerows(rows)


if __name__ == '__main__':
    main()


OK

f:id:akiyoko:20171205231119p:plain:w500

セルごとに分かれない

f:id:akiyoko:20171205231145p:plain:w500

文字化け

f:id:akiyoko:20171205231136p:plain:w500


なお、確認した環境は、

  • macOS 10.12.16 + Microsoft Office 365 & Excel for Mac 2011
  • Windows 10 + Microsoft Office 2010

です。



ちなみに、open 時に「newline=''」を指定している理由は、Windows 対策のためです。


(参考)

 

おまけ(Python 2)

# -*- coding: utf-8 -*-
import cStringIO

import codecs
import unicodecsv as csv


class UnicodeWriter:
    """
    A CSV writer which will write rows to CSV file "f",
    which is encoded in the given encoding.
    """

    def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
        # Redirect output to a queue
        self.queue = cStringIO.StringIO()
        self.writer = csv.writer(self.queue, dialect=dialect, **kwds)
        self.stream = f
        self.encoder = codecs.getincrementalencoder(encoding)()

    def writerow(self, row):
        self.writer.writerow([s.encode("utf-8") for s in row])
        # Fetch UTF-8 output from the queue ...
        data = self.queue.getvalue()
        data = data.decode("utf-8")
        # ... and reencode it into the target encoding
        data = self.encoder.encode(data)
        # write to the target stream
        self.stream.write(data)
        # empty queue
        self.queue.truncate(0)

    def writerows(self, rows):
        for row in rows:
            self.writerow(row)


def main():
    rows = [[u'髙﨑 將'], [u'あああ', u'いいい', u'ううう'], [u'Ⅰ・Ⅱ・Ⅲ', u'①②③']]

    with open('test_unicode_writer.csv', 'w') as f:
        w = UnicodeWriter(f, dialect=csv.excel_tab, encoding='utf-16')
        w.writerows(rows)


if __name__ == '__main__':
    main()

https://docs.python.org/2/library/csv.html#examples の UnicodeWriter をそのまま使えばいいよという話ですが、それにしても面倒臭いですよね。いっそ滅んでしまえばいいのに、Python2。



 

まとめ

Excel で直接開いても文字化けしない CSVファイルを Python3 で作成するには、

  • ファイルオープン時に「encoding='utf-16'」と指定
  • csv.writer の引数に「dialect='excel-tab'」と指定

とするのがスマートで確実です。

今回はちょっとレガシーな話題でした。



明日は、driller さんの「python Advent Calendar 2017 - Qiita」 10日目の記事です。
よろしくお願いします。




 

おまけ

文字コードに詳しくなりたい人は、こちらをどうぞ。

*1:《過去記事》akiyoko.hatenablog.jp

*2:《過去記事》akiyoko.hatenablog.jp

*3:《過去記事》akiyoko.hatenablog.jp

*4:ネタが古いですね。図は、「悪循環画像ジェネレータ」を利用させていただきました。

*5:・・はい、私です。

*6:「タブ区切りは CSV じゃなくて TSV だろ」問題がついに解決した - 頭ん中

「あなたの趣味は?」のアンケート結果を R で因子分析してみた

この投稿は 「R Advent Calendar 2017 - Qiita」 の 4日目の記事です。

こんにちは、akiyoko です。
「R Advent Calendar 2017」は 3年ぶり 2回目の参加になります。 *1

何をしたのか?

「あなたの趣味は?」というアンケート結果に対して「因子分析」を実施 することで回答の奥に潜む共通要因を探り、どんな趣味趣向を持った人たちがアンケートに回答してくれていたのか? を分析してみました。


具体的にはこんなシチュエーションです。

現在、アンケートの回収に Google Forms を使っていて、回答項目の一つに「あなたの趣味は何ですか?」(*2)という項目が含まれています。例えばこんな感じです(実際には他にも項目があります)。


f:id:akiyoko:20171202235107p:plain:w300

趣味アンケート

Q1.あなたの趣味は何ですか? 当てはまるものを次の中から全てお答えください


【選択肢】特に無い/将棋/囲碁/チェス/ポーカー/麻雀/その他のボードゲーム・テーブルゲーム/TVゲーム・PCゲーム(携帯用を含む)/映画鑑賞/音楽鑑賞/楽器演奏/演芸・演劇鑑賞/美術鑑賞/スポーツ観覧/ダンス/料理・お菓子作り/ガーデニング/読書/ネットサーフィン/パチンコ・パチスロ/競馬・競輪・競艇/カラオケ/その他(自由回答)


回答結果をグラフにすると、以下のようになりました。

f:id:akiyoko:20171203003721p:plain:w500

しかしながら、このままでは面白くない。何か新しい視点で分析できないものか? *3

ということで、このアンケート回答者の趣味の傾向から、どんなクラスタの人たちがアンケートに回答してくれているのか?ということを趣味の背後に潜んでいる共通因子から推測してみよう、と思い立ったわけです。


 

そもそも因子分析とは?

こちらの説明が非常に分かりやすいです。

  • 因子分析は,複数の変数間の関係性を探る際によく用いられる手法である(ただし正確には潜在的な変数を仮定するのだが,以下に説明する)。
  • 因子分析をする目的は,「因子」を見つけることである。
  • 因子とは,実際に測定されるものではなく,測定された変数間の相関関係をもとに導き出される「潜在的な変数」(観測されない,仮定された変数)である。
  • 言い換えると,因子分析とは「ある観測された変数(たとえば質問項目)が,どのような潜在的な因子から影響を受けているか」を探る手法といえる。


心理データ解析第8回(1)」より


よく「主成分分析」と混同しやすい「因子分析」ですが、

  • 因子分析をする目的は「共通因子を見つけること」である
  • その一方で,主成分分析の目的は「情報を縮約すること」である。

心理データ解析補足01」より

といった違いがあります。上記サイトの図が特に分かりやすいです。

私の感覚では、主成分分析は、主成分を1つに縮約して観測された変数に重み付けをして各データ行の「合計得点」を求めたいときや、主成分を2つに次元圧縮して特徴量を一つの散布図にまとめて表示するときに使うもの、と考えています。



 

なぜ R?

普段は Excel や Python でデータ分析をしていて R は使わないのですが、私の知る限りでは、因子分析に関しては Excel 単体ではできず、Python でも簡単にできるようなものがありません(scikit-learn には sklearn.decomposition.FactorAnalysis というクラスがあるのですがそれを使ったサンプルが何故かあまりありません。主成分分析をするサンプルならいつくもあるのですが・・)。
その点、R なら超簡単に出来てしまうことが分かってからは、因子分析には R を利用するようにしています。

実践

ここからが本番です。

Google Forms のアンケート結果をクレンジングしてファイルを CSV形式で保存し、R に読み込ませて分析します。

データクレンジング

Google Forms からアンケート結果を xlsx形式でエクスポートすると、こんな感じになっています。

f:id:akiyoko:20171202163927p:plain


Excel関数を使ってチェックボックス形式のデータを整形します。
具体的には、別の Excelファイルを新規作成し、(選択肢として不要なので)「特に無い」「その他」の列を削除した後、以下のようにして「0」「1」のデータに変換します。

f:id:akiyoko:20171203003640p:plain


[ファイル]>[名前を付けて保存]から、ファイルを CSV 形式で保存します。
ファイル名は、例えば「factor_analysis.csv」など、日本語を使わない方が無難です(RStudio から読み込めない可能性があります)。

将棋,囲碁,チェス,ポーカー,麻雀,その他のボードゲーム・テーブルゲーム,TVゲーム・PCゲーム(携帯用を含む),映画鑑賞,音楽鑑賞,楽器演奏,演芸・演劇鑑賞,美術鑑賞,スポーツ観覧,ダンス,料理・お菓子作り,ガーデニング,読書,ネットサーフィン,パチンコ・パチスロ,競馬・競輪・競艇,カラオケ
0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0
0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0
1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0
(以下略)

 

RStudio にデータ投入

インストールしていない場合は、公式ダウンロードページ から RStudio をダウンロードしてインストールします。
私が使ったバージョンは、RStudio for Mac(Version 1.0.153)です。


作成した CSVファイルを読み込みます。

> data <- read.csv(file="~/Downloads/factor_analysis.csv", header=T, fileEncoding="Shift-JIS")
> head(data)
  将棋 囲碁 チェス ポーカー 麻雀 その他のボードゲーム.テーブルゲーム TVゲーム.PCゲーム.携帯用を含む. 映画鑑賞 音楽鑑賞 楽器演奏 演芸.演劇鑑賞 美術鑑賞 スポーツ観覧 ダンス 料理.お菓子作り
1    0    0      0        0    0                                   1                               0        0        0        0             0        0            0      0               0
2    0    1      0        0    0                                   0                               0        0        0        0             0        0            0      0               0
3    1    0      0        0    0                                   0                               0        0        0        0             0        0            1      0               0
4    1    1      0        0    1                                   1                               0        0        0        0             0        0            0      0               0
5    0    0      0        1    0                                   0                               0        0        0        1             0        0            0      0               0
6    0    0      0        0    0                                   0                               0        1        1        0             0        1            0      0               0
  ガーデニング 読書 ネットサーフィン パチンコ.パチスロ 競馬.競輪.競艇 カラオケ
1            0    0                1                 0              0        0
2            0    0                0                 0              1        0
3            0    1                1                 0              0        0
4            0    0                1                 0              0        0
5            0    0                0                 0              0        0
6            0    1                0                 0              0        0

上記は CSV ファイルのエンコード形式が「Shift-JIS」の場合の記述ですが、もし「UTF-8」にした場合は「fileEncoding="UTF-8"」とすれば OK です。


 

RStudio で因子分析

以降は、ほぼ「Rで因子分析やってみた」のままです。

まずは、因子数を決定します。

> c <- cor(data)
> e <- eigen(c)$values
> e
 [1] 2.7796088 2.6282309 1.7220938 1.6669475 1.4724370 1.3176913 1.2386144 1.0709480 0.9855064 0.8927945 0.7569210 0.6899642 0.6341069 0.6018854 0.5724795 0.4168670 0.3761065 0.3551432 0.3143882
[20] 0.2790165 0.2282491

固有値のグラフをスクリープロットとして出力します。

> plot(e, type="b", main="Scree Plot", xlab="Number", ylab="Eigenvalue")

f:id:akiyoko:20171203004038p:plain:w500


固有値の減少がなだらかになる直前までの固有値の数を因子数とする(スクリー基準)、および、因子数の基準となる固有値の最小値を「1」とする(カイザーガットマン基準)を考慮して、因子数を「6」としました。 *4, *5


最後に、因子数を 6 として因子分析をおこないます。

> factanal(x=data, factors=6, rotation="promax")

「rotation」の引数は、"none", "varimax", "promax" などがありますが、今回は、因子間の相関を仮定しないする(2017.12.26 訂正)プロマックス回転「 promax」を選択しました。 *6


f:id:akiyoko:20171203004437p:plain
f:id:akiyoko:20171203004450p:plain


この結果を因子負荷量の大小で色付けすると、以下の表のようになります。

f:id:akiyoko:20171203004907p:plain:w500


上記の表から、以下のように共通因子(趣味趣向クラスタ)を分類してみました。あくまでも仮説ですが。

  • 因子1:「麻雀」「囲碁」「将棋」の因子負荷量が大きい ・・・ 囲碁将棋系
  • 因子2:「美術鑑賞」「演芸・演劇鑑賞」の因子負荷量が大きい ・・・ アート系?
  • 因子3:「楽器演奏」「料理・お菓子作り」「ダンス」の因子負荷量が大きい ・・・ 音楽系?
  • 因子4:「競馬・競輪・競艇」「パチンコ・パチスロ」の因子負荷量が大きい ・・・ ギャンブル系
  • 因子5:「その他のボードゲーム・テーブルゲーム」「チェス」の因子負荷量が大きい ・・・ その他のボードゲーム系
  • 因子6:「映画鑑賞」「音楽鑑賞」の因子負荷量が大きい ・・・ オーソドックスな趣味系?


一部強引なところもあるかもしれませんが、アンケートに回答した人が「ああ、私はこの趣味趣向クラスタだな」と分かりやすいような分類になっているのではないかと思います。




 

まとめ

  • 因子分析は R でやれば超簡単
  • 数行で書けるよ

これを言うためだけに 8000字オーバーの記事を書いてしまいました。。



明日は、yamano357 さんの「R Advent Calendar 2017 - Qiita」 5日目の記事です。
よろしくお願いします。


 

おまけ

因子分析の結果表示でそれぞれの出力行がガタついて項目がズレてしまう場合は、
[Preferences]>[Appearance]から、Editor font に「Osaka-Mono」を選択すれば解決します(Mac の場合)。


f:id:akiyoko:20171203182418p:plain:w350



今回の場合はグラフ描画時に日本語を出力していませんが、RStudio でグラフを描画する際に文字化けしてしまう場合は、

par(family="HiraKakuProN-W3")

と事前に実行しておけばよいです。 *7

*1:《過去記事》akiyoko.hatenablog.jp

*2:今回はインドア系の趣味についてのみアンケートしました。

*3:選択肢に挙げた15種類の趣味は、総務省統計局が5年ごとに実施している「社会生活基本調査」(出典:平成28年 社会生活基本調査結果(総務省統計局))の「趣味・娯楽」の34種類の区分のうちの15種類と一致させているので、やろうと思えば、その種類別行動者数(≒趣味にしている人の割合)と照らし合わせることで世間一般の平均的な趣味趣向と比較することもできます。

*4:http://cogpsy.educ.kyoto-u.ac.jp/personal/Kusumi/datasem06/minemoto.pdf

*5:実際には「5」から「7」を順次選んで計算したところ、「6」が結論を導きやすかったという理由もあります。

*6:因子分析における因子軸の回転法について | Sunny side up!

*7:Rとウェブ解析:MACでグラフの日本語文字化けを防ぐ簡単な方法

「bitFlyer Drink Meetup! #9」に参加してきました

主催

bitFlyer

会場

株式会社bitFlyer 本社
東京都港区赤坂 9‐7‐1 ミッドタウン・タワー 8F



 

全体の感想など

11/28 から 11/30 までの直近3日間だけで

  • POSレジでの決済サービス開始 *1
  • 米国進出(bitFlyer USA Inc.) *2
  • FX 初のサーキットブレイク発動 *3

と(良くも悪くも)話題に事欠かない日本最大の仮想通貨取引所を運営する bitFlyer の勉強会に参加してきました。


bitFlyer ビットコインを始めるなら安心・安全な取引所で


国内シェアが8割、テレビCM を大量投入するなど、ビットコイン・仮想通貨の取引所としてはノリにノッている bitFlyer ですが、全銀協が推薦する実証実験プラットフォームベンダーに選出されたとの発表もあったことから、取引所以外にブロックチェーン自体にも注力していこうという方向性が窺えます。 *4


現在は「miyabi」という自社製ブロックチェーンをゼロから作っているとのことです。開発言語は C# で、チームがまだ小さいということもあってかお披露目はまだ当分先のようです。 *5



あと、会場はこんな感じで(私の写真ではありません)、六本木ミッドタウンの新オフィスに引っ越して 1ヶ月とのことでフロアも雰囲気もピカピカなオフィスでした。社員も90名に急増したとのことで、さすがノリノリですね(よく見ると床に刻み海苔らしきものが散らばってましたが、前日のイベントでピザでも食べたのでしょうか。まさにノリノリ)。




bitFlyer ビットコインを始めるなら安心・安全な取引所で



さて、LT の内容ですが、Hyperledger Sawtooth は今回初めて聞きました。PoET(Proof of Elapsed Time)も初耳です。

公式ドキュメント によると、Intel SGX のチップを使った Intel サーバ群を TEE(Trusted Execution Environments:信頼済み実行環境?)としたブロックチェーン上で、待ち時間をランダムに割り当てられたノードペアがブロックの承認をおこなうという仕様になっているようです(間違っていたらすいません)。

ただし PoET が動作するのは、Intel の分散台帳プラットフォーム「Sawtooth Lake」など限定的なブロックチェーン上のみのようで、実質 PoET はパブリックチェーンとしては利用できないということでしょうかね。
しかも、

実験用途にしか利用を推奨していない。
独自のコンセンサスアルゴリズムPoETを持つが、これは本来intelが提供するハードウェアを利用して行われるため完全版ではなく、オープンソース版ではシミュレータが用意されている。


開発は続けられているが、正式なプロダクトへの採用を勧めていない為、選択肢にはならない。


さまざまなブロックチェーン技術」より

とあるように、メインは実験用途とか。登壇者も「実務では使っていない」と言っていましたので、miyabi 開発のために他製品を調査してみたということなのかもしれません(実際、他の方も「社内勉強会の資料を外に出せるように手を入れた」と言っていました)。なお今回のデモは Docker のシミュレータ上で動作させるため、Intel SGX の TEE は利用しておらず、Mac でも問題なく動かせるというカラクリのようです。

また、(サンプルの ○✕ゲームの実装がそうなっているだけかもしれませんが、)Ether の Gas のようなトランザクション手数料の仕組みがないため、ノードのマイニングの報酬がなく、ノードを立てる経済インセンティブをどう設計するかについてはシステム上の懸念が残ります。というかそもそも、 Hyperledger 系プロダクトは分散台帳と暗号技術で守られた P2Pネットワーク、コンセンサスアルゴリズムを使いやすいように提供しているだけで、ブロックチェーン経済圏は範疇外ということなのかもしれません。

ブロックチェーンプラットフォームとしてメジャーなのはBitcoinとEthereumですが、それらとHyperledgerとの大きな違いは、bitcoinにとっての「bitcoin」、ethereumにとっての「ether」のような仮想通貨の単位がHyperledger には存在しないことです。Hyperledgerでは、純粋にブロックチェーンの持つ分散型台帳という特性を仮想通貨に限らず社会の様々なソリューションの技術基盤として汎用的に活用できるように開発されています。


Hyperledger入門 : Hyperledger(ハイパーレッジャー)って何? | BlockChain Online ブロックチェーンオンライン」より


Hyperledger プロジェクトの立ち位置については、http://doublehash.me/tag/hyper-ledger/ の図が分かりやすかったです。しかしながら Hyperledger Sawtooth はどちらかと言えば、Transaction and data は「Public」、Mining/Consensus は「Trusted(consensus)」(つまり図の左下のエリア)なんじゃないかな?と思いました。




まあそれはさておいて、(私が長年 Python を使ってきたということもあって)Python で任意のスクリプトを書けるのは面白いな、と思いました。
Python 製のブロックチェーンとしては他にも、

  • HydraChain
    • Ethereum の拡張版で、コンソーシアム型またはプライベート型のブロックチェーンを構築可能。Python でコントラクトを書けるのが特徴。
  • BigchainDB
  • DragonChain

などがありますが、Python で自由にコントラクトを記述できる有名どころとしては HydraChain が挙げられるでしょうか。ただし、HydraChain はノードが最低限 6台必要ということで検証用途としては Hyperledger Sawtooth に軍配が上がるということなのかもしれません(実際試してみましたが、Docker 上でデモを動かすのは非常に簡単でした)。



 

WindowsのDocker環境でブロックチェーンを動かしてみる

越智 佳景 氏(ブロックチェーンエンジニア 株式会社 bitFlyer)

  • Hyperledger
    • ビジネスのためのブロックチェーン技術 *6
    • Linux Foundationで開発
    • オープンソース
    • Sawtooth (ソウトゥース)は Hyperledger プロジェクトの一つで Intel が開発を主導 *7
  • PoW は参加者が限定されていない場合に有効
  • Sawtooth トランザクション
    • アプリ開発者が任意に設計できる
    • Validator が Transaction Processor(ビットコインのスクリプトに相当)に問い合わせ
    • ステートを変更する
  • Sawtooth ブロック
    • 代表ノードがブロックを作る
      • Intel SGX のチップ、Intel のサーバを信用する??
    • PoET(Proof of Elapsed Time:時間に応じてブロックを作れる可能性が高まる)
  • Docker
    • 3月あたりにEE(Enterprise)とCE(Community)に分かれた
    • 実行方法は二つ
      • Dockerfile(docker build . で Imageを作って docker run)
      • 複数コンテナをまとめて起動する場合は docker-compose.yaml(docker compose up でコンテナを起動)

なおブロックについては、チェーン内部にタイマーがあり、一定時間ごとに自動的にブロックが作られるようになっているとのこと。また State は、トランザクション外(メモリ上?)で管理されるそうです。




 

macOS の Docker環境で Hyperledger Sawtooth を動かす

ここから、私の macOS の Docker 上で Hyperledger Sawtooth のデモを動かしてみます。

環境は以下の通りです。

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.12.6
BuildVersion:   16G1036

$ docker --version
Docker version 17.09.1-ce, build 19e2cf6


Sawtooth Enterprise Blockchain に事例が紹介されていますが、その他に ○✕ゲームがデモ用に実装されているので、それを Docker 上で動作させてみます。と言っても、発表の内容をなぞるだけですが。


まず、Hyperledger の sawtooth-core の GitHub から、以下の手順で sawtooth-core-1.0.0rc3.zip をダウンロードします。なお現時点での最新版は「v1.0.0rc3」。

f:id:akiyoko:20171201024521p:plain

f:id:akiyoko:20171201024759p:plain


docker/compose/sawtooth-default.yaml を開いて、以下のように shell をコピペして shell1, shell2 に書き換えます。

  ...

  shell1:
    image: hyperledger/sawtooth-all:1.0
    container_name: sawtooth-shell-default1
    expose:
      - 8008
      - 4004
    depends_on:
      - rest-api
    entrypoint: "bash -c \"\
        sawtooth keygen && \
        tail -f /dev/null \
        \""

  shell2:
    image: hyperledger/sawtooth-all:1.0
    container_name: sawtooth-shell-default2
    expose:
      - 8008
      - 4004
    depends_on:
      - rest-api
    entrypoint: "bash -c \"\
        sawtooth keygen && \
        tail -f /dev/null \
        \""

 
以下のコマンドを実行して、コンテナを起動します。

$ docker-compose -f ~/Downloads/sawtooth-core-1.0.0rc3/docker/compose/sawtooth-default.yaml up

しばらくすると、各種コンテナが起動します。

$ docker ps
CONTAINER ID        IMAGE                                       COMMAND                  CREATED             STATUS              PORTS                              NAMES
2efe61c116df        hyperledger/sawtooth-all:1.0                "bash -c 'sawtooth..."   16 minutes ago      Up 15 minutes       4004/tcp, 8008/tcp                 sawtooth-shell-default1
9d14523518bb        hyperledger/sawtooth-all:1.0                "bash -c 'sawtooth..."   16 minutes ago      Up 15 minutes       4004/tcp, 8008/tcp                 sawtooth-shell-default2
59f216a70497        hyperledger/sawtooth-settings-tp:1.0        "settings-tp -vv -..."   16 minutes ago      Up 15 minutes       4004/tcp                           sawtooth-settings-tp-default
0f0d651f61b3        hyperledger/sawtooth-rest-api:1.0           "sawtooth-rest-api..."   16 minutes ago      Up 16 minutes       4004/tcp, 0.0.0.0:8008->8008/tcp   sawtooth-rest-api-default
f17d965f771b        hyperledger/sawtooth-xo-tp-python:1.0       "xo-tp-python -vv ..."   16 minutes ago      Up 16 minutes       4004/tcp                           sawtooth-xo-tp-python-default
2ae2e16405f2        hyperledger/sawtooth-intkey-tp-python:1.0   "intkey-tp-python ..."   16 minutes ago      Up 15 minutes       4004/tcp                           sawtooth-intkey-tp-python-default
25803f8bec59        hyperledger/sawtooth-validator:1.0          "bash -c 'sawadm k..."   16 minutes ago      Up 16 minutes       0.0.0.0:4004->4004/tcp             sawtooth-validator-default


次に、別々のターミナル上で

《ターミナル 1》

$ docker exec -it sawtooth-shell-default1 bash

《ターミナル 2》

$ docker exec -it sawtooth-shell-default2 bash

を実行し、起動した 2つの shell クライアントのコンテナにそれぞれログインします。


xo の遊び方、コマンドなどの仕様については、以下を参照。


《ターミナル 1》

### user1 用の鍵を作成
# sawtooth keygen user1
writing file: /root/.sawtooth/keys/user1.priv
writing file: /root/.sawtooth/keys/user1.pub

### ゲームを新規作成
# xo create --url http://rest-api:8008 --username user1 game1
Response: {
  "link": "http://rest-api:8008/batch_statuses?id=5ebd578b0c6800460bcf2e53cd8275f2e8266fee9e9fd421f94f7b92d0b785fe28debe5c0a986fb44c784df7a1e35cf678d8f3fe3e3255fcc1fe0b710420cbd8"
}

### ゲームが作成されたか確認
# xo list --url http://rest-api:8008
GAME            PLAYER 1        PLAYER 2        BOARD     STATE
game1                                           --------- P1-NEXT

### user1 が一手目を打つ
# xo take --url http://rest-api:8008 --username user1 game1 1
Response: {
  "link": "http://rest-api:8008/batch_statuses?id=19189296519d8ced6d94902203004607532bb59b5dd8b75fcc5ff99022dc02fb54e26c6618dec172d27e09cb7808d3f2b14aac7cdece01960a321b532673afe7"
}

### ゲームの状況を確認
# xo show --url http://rest-api:8008 game1
GAME:     : game1
PLAYER 1  : 03a8de
PLAYER 2  :
STATE     : P2-NEXT

  X |   |
 ---|---|---
    |   |
 ---|---|---
    |   |


《ターミナル 2》

### user2 用の鍵を作成
# sawtooth keygen user2
writing file: /root/.sawtooth/keys/user2.priv
writing file: /root/.sawtooth/keys/user2.pub

### ゲームの一覧を確認
# xo list --url http://rest-api:8008
GAME            PLAYER 1        PLAYER 2        BOARD     STATE
game1           03a8de                          X-------- P2-NEXT

### user2 が 2手目を打つ
# xo take --url http://rest-api:8008 --username user2 game1 3
Response: {
  "link": "http://rest-api:8008/batch_statuses?id=1d33ab7613cb9cffc5813502b1a47b1f9ea78d291fe2ce69187bd6128034593f0889eba850cf7e92e32db0f702cbc55e61508d1e743dd3fad19c2a47cd574792"
}

### 試合のステータスを確認
# xo show --url http://rest-api:8008 game1
GAME:     : game1
PLAYER 1  : 03a8de
PLAYER 2  : 039346
STATE     : P1-NEXT

  X |   | O
 ---|---|---
    |   |
 ---|---|---
    |   |

という感じで、xo-tp-python がトランザクションを処理しています。
もちろん鍵が合わないユーザーは、間違った順番で take できないように検証がおこなわれます。

なおブロックは、チェーン内部にタイマーがあり、一定時間ごとに自動的にブロックが作られるようになっているとのこと。ちなみに、State はトランザクション外(メモリ上?)で管理されるということです。

「BPStudy#123 〜技術書籍執筆の実際、ノウハウ」に参加してきました

主催

BPStudy

会場

国際英語学校代々木教会ビル会場 大会議室6F
東京都渋谷区代々木1-29-5 (教会ビル)

Twitter

twitter.com



 

全体の感想など

最近、何か技術本を書きたいなぁ、と思い始めていました。
というのも、
techbookfest.org

というのを少し前に知ったからです。
こういうアウトプットのし方もあるのね、と。

あと、ちょうど最近、

というのもホットエントリーになっていたり。


ちなみに結城浩さんは、過去に自身のブログでこういったことも書いています。

本を出版するのは、一冊目が一番たいへんだ。 ほんとうに、ほんとうに一冊目はたいへん。 二冊目以降は(一冊目に比べれば)夢のように楽だ。 何が楽になるかというと、自分の中に生じる不安を吹き飛ばすのが楽になる。 「こんなに大変で、自分はやりとげられるだろうか」という不安に対しては、 「うん、大丈夫。こういう大変さはいつもと同じだ」 と答えられるようになる。 「こんなに一冊の本に時間をかけても大丈夫なのだろうか」という不安に対しては 「気持ちが前向きになっているから大丈夫。この時間は品質向上に必要な時間なのだ」 と自分に対して答えられるようになる。 いつも、祈りは必要だ。いつも、呼吸が必要なように。 それはそれとして、 二冊目以降、 自分の不安な気持ちをなだめるためのエネルギーを、 具体的な仕事に向けることができるのはとても楽なことだ。


一冊の本の7分目ほどで、何か大切なものがキラキラッと見えることがある。 本を書き始める前には知らなかった何か、 ささやかではあるけれど本質的な何かを見つかる瞬間だ。 それは著者にとって大きな報酬の1つだ。 物語をつかむ瞬間。 大きな喜びの瞬間。


でも、一番大きな喜びは、出版後にやってくる。 それは、読者から送られてくる「なるほど、わかりました!」というフィードバックだ。


本を書くということ


私自身はこれまで本を書いたことはありませんが、この一年ほど某会報誌に毎月10ページほど寄稿していたこともあり、書くことの辛さ、難しさは多少は理解しているつもりです。でもどうせ書くなら、多くの人に届けられるものを書きたい。そんなことを悶々と思っていたときに偶然見つけたこの勉強会。これは行くしかないでしょうと。


そして今回感じたこと。本を書く人は、人に何かを伝えるのが上手い。
というか、話の「構成」がうまいのかなあ、と感じました。きちんと伝えられるような構成をまず考えているというか、伝えたいことを中心に話を作っているというか。技術書とは言えど、本を買った人に何かを残す、という使命をきちんと意識しているように思いました。



 

まず、共著からやってみよう 〜 Pythonエンジニアファーストブックで学んだノウハウの共有

鈴木 たかのり 氏(株式会社ビープラウド)

Slide:Pythonエンジニアファーストブックの紹介


  • 6章を5人で書いた。
  • ターゲットは、これからPythonを仕事で使うエンジニア
  • Pythonエンジニア養成読本を改訂
    • Pythonのバージョンを3系に
    • Bottle → Djangoに変更
    • ライブラリ、ツールを最新に
  • スケジュール
    • 2016年12月に改訂を打診
    • 3月にキックオフの飲み会
    • 6月に Web以外脱稿
    • 7月に Web脱稿
    • 9月9日発刊
  • 打ち合わせでストーリー作成
  • LEGOのデータを使おう!
    • 実際に Scrapy で LEGO のデータをクローリングしている人がいる *1

 
Pythonエンジニアファーストブックで学んだノウハウの共有
清原 弘貴 氏(株式会社ビープラウド)

Slide:共著からやってみよう 〜Pythonエンジニアファーストブックで学んだノウハウの共有

  • 初めてなら共著をオススメ
    • 今まで他の本をやってきた人の執筆ノウハウが使える
    • 執筆の流れが理解できる
  • 執筆ノウハウ
    • Sphinx で書く
    • term-validator でビルドのたびに漢字や表記の揺れを自動でチェックしてくれる
    • TODOや指摘をプルリクでやり取り(GitLab?)
    • Dropbox で PDFファイルを直接レビュー(すごい!!オススメ!)
      • PDFにコメントを付けられる
      • Dropbox と Adobe が提携してるから実現してる??
  • Slack でやりとり
  • コードは GitHub で公開している
  • 執筆の流れ
    • 意外と時間が掛かるし、流れや見積もり感覚が開発と少し違う
  • 良かったところ
    • 知識を補完し合える(得意・不得意)
    • よく知ってる人としてのレビュー、知らない観点からのレビュー
    • 著者みんなで告知できる
      • Twitter、POP行脚、イベント発表、打ち上げ
  • 積極的にレビューするのが大事
  • 共著に参加するには?
    • 声が掛かりそうな人と仲良くなる
    • 私できますよ的な雰囲気をアピール
    • 信頼貯金を貯めよう
  • 「意見は率直に」
    • by「ピクサー流 創造するちから」



 

技術書を書くということ。商業誌を書くということ 〜 Jupyter 実践入門執筆プロジェクトを終えて

池内 孝啓 氏(株式会社 slideship)


  • 技術書を書くということ
  • 動機
    • 利己的
      • 自己や自社のブランディング
      • 経験
      • 印税
    • 利己的
      • 世に広める
      • 後世に記録を残す
  • ブランディング
    • キャリアの方向性と書籍の領域がマッチしていればブランディングになる
    • 実績として分かりやすい
  • 技術の輪を広げる
    • コミュニティに還元(Pay it forward)
  • 印税?
    • 300頁/1時間あたり1.5頁=200時間
    • 一冊 120万円とすると、割に合わない?
  • 納本制度
    • Jupyter本も納本済み
    • 知識や技術が陳腐化しても、当時の考えや歴史は覆らない
  • 商業誌を書くということ
  • 利益を出す必要がある
  • 良い本かどうかはマーケットが判断
  • Jupyter本は、2016年2月頃に技術評論社へ企画を持ち込む
    • 紆余曲折を経て2017年に企画スタート
  • テーマ選択の理由は「行ける!」と思ったから
  • ベネフィットを届ける
  • 読者は高度な専門知識に対してお金を払っている
    • 正確な情報
    • 妥当な方法
  • 読者がどれだけ利益を得たかが全て
    • 知らなかったことが知れる。分からなかったことが分かる
    • 学習のきっかけ
  • 売上の向上のために
    • ニーズに答える
    • ベネフィットを提供
    • マーケットの大きなところを狙う
  • 利益率を上げるために
    • 執筆コストを下げる
    • 執筆ノウハウを共有
  • 執筆プロジェクトは、ステークホルダーの利益をどう最大化させるかという視点をもっと持つ
  • O'Reillyのアトラス?どうなったか不明
  • テキストからコンバート?
  • GitBook?(Sphinx の代替として)
    • Markdown を束ねるツール


 

はじめての執筆でわかった技術書ができるまでの流れ

岩崎 圭 氏(株式会社 SQUEEZE)

docs.google.com


  • スケジュール
    • 2016年10月キックオフ
    • 2017年6月が本来の〆切 → 8月に完成
  • 形式は Markdown
  • GitLab の git で管理
  • やり取りは Slack
  • pyhack の常連 + ブログも書いていたので? 声をかけてもらったのかな?
  • まずは企画を通す
  • 最初のキックオフMTGでアウトラインを出す
  • ツールは、Sphinx, Re:VIEW
  • 執筆が上手くいかない問題
    • 書く時間を上手く確保できない
      • 平日仕事が終わったら必ず「コワーキングスペースに行く」を習慣化
    • 筆が進まない問題
      • 各章で最初にアウトラインを書くようにした
    • 執筆のアクティビティを Slack に流す
      • 執筆が死んでる感を出さないように
  • 1章あたりどんなに短くとも2週間は掛かった
  • 原稿消滅事件
  • レビューはDropboxコメント機能を利用
  • 修正は時間と体力との戦い
  • もう少し上手くやりたかったこと
    • 日本語力不足の解消
    • 最低限の校正の自動化(textlint x CI など)
    • 原稿の自動ビルド(テンションが違う)
    • 原稿の時点である程度レビューしたかった
    • 素のMarkdownがつらい
      • コラム、Note、Point など書籍ならではのブロックの表現
  • とんでもない量の時間と体力を費やして本当に疲れた
  • 技術的な内容を日本語に変換するのが難しい

gitlab.com の原稿消失事件は、2月のコレらしい。
結局大丈夫だったとのこと。




 

LT

 

技術書は Jupyter Notebook で書けばいいんじゃない?

driller / どりらん 氏

  • Jupyter Notebook とドキュメントビルダーだけで OK!
  • nbconvert で変換
  • Shpinx, Pelican
  • nbsphinx
  • PDF や ePub を作成するなら ⇒ Sphinx
  • HTML形式だけでよいなら ⇒ Miyadaiku
  • ただし、テキスト校正ツールが使えない、コーディング規約のチェックが使えないなどの問題も

 

技術書査読・校正の現場から

Hayao Suzuki 氏


 

一流のエンジニア/経営者になるため基礎力を磨け!

高崎健太郎

  • 一流になるためには学びが重要
  • 自習、経験、環境
  • ぶれない軸
  • 一緒に学び合える仲間
  • 学びを与えてくれるもの
    • 歴史、スポーツ
      • 同じテーマで議論できる
      • 葛藤、挫折、新たな挑戦。組織論、戦術論


 

技術書の原稿はWordで書いちゃダメゼッタイという話

生形 可奈子 氏(アシアル株式会社)

  • スラスラわかるJavaScript は単著
  • 増刷で修正する場合は、軽微な修正であっても原稿データと同期を取る
  • Amazonレビューの「違反を報告」はヤバイ

「fin-pyもくもく会 #10」に参加してきました

主催

fin-py

会場

株式会社インタートレード
東京都中央区新川一丁目17番21号 茅場町ファーストビル3階

Twitter

twitter.com



 

全体の感想など

fin-py は今回で 3回目の参加となりました。

Python は業務で7年ほど&プライベートでもちょくちょく触っているのでそこそこ使いこなせますが、これまで金融業界の経験もないし、個人的にほとんど投資をしたことがないので、Finance の部分は素人同然。発表のときに「約定」を「やくてい」と読んでしまうほどのレベルです。。


まあ、金融業界にいなくても独学で十分という話もありますが。。


あと今回は参加者が多くてビックリしました。特に初参加の方が多かったようです。Quantopian 関連の人が多かったのでしょうか、詳しくはよく分かりません。



《過去記事》
akiyoko.hatenablog.jp

akiyoko.hatenablog.jp



 

やりたかったこと

bitFlyer の BTC-FX API を使ってトリガー検知

bitFlyer Lightning FX(ビットコイン FX) では、預入証拠金に対して最大15倍の取引ができるのが特徴です。最低取引金額が 0.001 BTC になっているため、1BTC=100万円として 1,000 円(レバレッジ15倍なら預入証拠金は約67円)から取引ができることになります。


bitFlyer ビットコインを始めるなら安心・安全な取引所で
bitFlyer ビットコインを始めるなら安心・安全な取引所で


背景としては、この一年の仮想通貨のトレンドとして、

Ripple(3月上旬)
アルトコイン(〜6月中旬)
草コイン(〜7月?)
ICO(〜9月中旬)
ハードフォーク(〜11月?)
チャイナショック(9月初旬) ⇒ アルトコインが焼かれる
CME先物発表(10月下旬) ⇒ アルトコインが焦土に
取引所増加
BTC-FX ⇐ 今ココ!?


みたいな流れがあったりするので、ちょっと触ってみようかと(まだ触ったことはありません)。


 

やったこと

  • FX 戦士たちの戦略調査
  • bitFlyer Lightning(FX取引所)を眺めてみる
    • いろんな音が鳴ってた ♪
  • pybitflyer 触ってみた
  • ccxt で書いてみた
  • テクニカル指標を扱うライブラリ「TA-Lib」を使ってグラフ書いてみた

 

環境
$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.12.6
BuildVersion:   16G1036

$ python --version
Python 3.5.2 :: Anaconda 4.2.0 (x86_64)


 

TA-Lib のインストール

テクニカル指標を扱うライブラリ。
GitHub - mrjbq7/ta-lib: Python wrapper for TA-Lib (http://ta-lib.org/).

$ brew install ta-lib
$ pip install TA-lib

TA-Lib (0.4.10)

「error: command '/usr/bin/clang' failed with exit status 1」とのエラーが出るので、まず先に「brew install ta-lib」が必要。

(参考)python - /usr/bin/clang command failing trying to pip install TA-lib on MacOS - Stack Overflow


 

pybitflyer のインストール

id:yag_ays さん作の bitFlyer REST API のラッパーライブラリ。
bitFlyer LightningのAPIをPythonから使えるパッケージ「pybitflyer」を作りました - おおかみ山

$ pip install pybitflyer

pybitflyer (0.1.7)


使ってみる。

import pybitflyer

exec(open('env.py', 'rb').read())

api = pybitflyer.API(
    api_key=BITFLYER_KEY,
    api_secret=BITFLYER_SECRET,
)
api.board(product_code='FX_BTC_JPY')

こんな感じで、板情報が取れます(それぞれ100件くらい)。

{'asks': [{'price': 942400.0, 'size': 0.00310928},
  {'price': 942497.0, 'size': 0.60458056},
  {'price': 942498.0, 'size': 0.04},
  ...],
 'bids': [{'price': 942212.0, 'size': 0.0521},
  {'price': 942152.0, 'size': 0.3},
  {'price': 942151.0, 'size': 0.22},
  ...],
 'mid_price': 942306.0}


 

ccxt で書いてみた

pybitflyer とほぼ同じことが書けます。

import ccxt
from pprint import pprint

exec(open('env.py', 'rb').read())

ex = ccxt.bitflyer({
    'apiKey': BITFLYER_KEY,
    'secret': BITFLYER_SECRET,
})

pprint(ex.fetch_ticker('FX_BTC_JPY'))
print('-' * 50)
pprint(ex.fetch_order_book('FX_BTC_JPY'))
{'ask': 1019470.0,
 'average': None,
 'baseVolume': 234473.73139995,
 'bid': 1019144.0,
 'change': None,
 'close': None,
 'datetime': '2017-11-26T12:56:20.000Z',
 'first': None,
 'high': None,
 'info': {'best_ask': 1019470.0,
          'best_ask_size': 0.0152,
          'best_bid': 1019144.0,
          'best_bid_size': 1.4489,
          'ltp': 1019144.0,
          'product_code': 'FX_BTC_JPY',
          'tick_id': 10554736,
          'timestamp': '2017-11-26T12:56:20.9',
          'total_ask_depth': 8018.9239892,
          'total_bid_depth': 11740.4605367,
          'volume': 249894.26662009,
          'volume_by_product': 234473.73139995},
 'last': 1019144.0,
 'low': None,
 'open': None,
 'percentage': None,
 'quoteVolume': 249894.26662009,
 'symbol': 'FX_BTC_JPY',
 'timestamp': 1511700980000,
 'vwap': None}
--------------------------------------------------
{'asks': [[1019470.0, 0.0152],
          [1019475.0, 0.0152],
          [1019494.0, 0.2008],
          ...,
          [1735257.0, 0.79804842]],
 'bids': [[1019144.0, 1.4489],
          [1019143.0, 2.331],
          [1019140.0, 0.01],
          ...,
          [95000.0, 2.0]],
 'datetime': '2017-11-26T12:56:22.000Z',
 'timestamp': 1511700981575}


しかしながら、pybitflyer と同じく 100件ほどしか板情報が取れないため、例えばボリンジャーバンドを計算するための ticker の情報はどうやって収集すればいいの?というのが懸念点。



 

TA-Lib を使ってグラフ書いてみた

とりあえず、さくらのクラウドサーバ上の MongoDB に格納している ticker データからグラフ作ってみました。

前回の反省を活かし、Jupyter Notebook で。

% matplotlib inline

from datetime import datetime, timedelta

import matplotlib.pyplot as plt
import pandas as pd
import talib
from pymongo import MongoClient, ASCENDING
from sshtunnel import SSHTunnelForwarder

plt.style.use('ggplot')
pd.options.display.max_rows = 20

now = datetime.now()
df = None

with SSHTunnelForwarder(
    '153.xxx.xxx.xxx',
    ssh_username='ubuntu',
    ssh_pkey='/Users/akiyoko/.ssh/sakura.pem',
    remote_bind_address=('127.0.0.1', 27017)
) as server:
    # server.start()
    print(server.local_bind_port)

    client = MongoClient('127.0.0.1', server.local_bind_port)
    db = client['bittrex']
    collection = db['tickers']

    records = list(collection.find(
        {
            'symbol': 'BTC',
            'timestamp': {'$gte': now - timedelta(minutes=60 * 24)},
        },
        {'_id': False},
    ).sort('timestamp', ASCENDING))

    df = pd.DataFrame(records)
    # Need?
    # https://stackoverflow.com/a/17328858/8426544
    #df = df.set_index(pd.DatetimeIndex(df['timestamp']))

print(df.dtypes)

df['sma'] = talib.SMA(df['last'].values, timeperiod=12)
print(df)

ax = df.plot(x='timestamp', y='last')
df.plot(ax=ax, x='timestamp', y='sma', secondary_y=True)


f:id:akiyoko:20171126220525p:plain





 

LT

pandas はデータをリサンプリングできる。例えば、1分足から5分足へ。

例えば、こんな感じ。

% matplotlib inline

import matplotlib.pyplot as plt
import pandas as pd
import talib

plt.style.use('ggplot')
pd.options.display.max_rows = 20

df = pd.read_csv('DAT_ASCII_EURUSD_M1_2015.csv', sep=';',
                 names=('Time', 'Open', 'High', 'Low', 'Close', ''),
                 index_col='Time', parse_dates=True)
df.index += pd.offsets.Hour(7)

# cf. https://stackoverflow.com/a/36223274/8426544
# cf. http://nekopuni.holy.jp/2015/01/pythonnysol%E7%82%BA%E6%9B%BF%E9%AB%98%E9%A0%BB%E5%BA%A6%E3%83%87%E3%83%BC%E3%82%BF%E3%81%8B%E3%82%89%E4%BB%BB%E6%84%8F%E3%81%AE%E3%83%AD%E3%82%A6%E3%82%BD%E3%82%AF%E8%B6%B3%E3%83%81%E3%83%A3/
df = df.resample('1H').agg({
    'Open': 'first',
    'High': 'max',
    'Low': 'min',
    'Close': 'last',
}).ffill()
df['FastMA'] = talib.SMA(df['Close'].values, timeperiod=10)
df['SlowMA'] = talib.SMA(df['Close'].values, timeperiod=30)

df.plot(y=['Close', 'FastMA', 'SlowMA'])

from pandas_highcharts.display import display_charts
df = pd.DataFrame({'Close': df['Close'], 'FastMA': df['FastMA'], 'SlowMA': df['SlowMA']})
display_charts(df, chart_type="stock", title="MA cross", figsize=(640, 480), grid=True)

(参考)PythonでFXシストレのバックテスト(1)


resample() メソッドを使用することで時系列データの頻度を変換できます。日次のデータを週次や月次などのデータに変換できます。


どりらんさん共著の Jupyter 本に載ってる!(P.128 あたり)


Jupyter 上で動かせるチャートを書くなら、pandas-highcharts が良さげ。
python-highcharts もあるよ。


 

「fin-pyもくもく会 #9」に参加してきました

主催

fin-py

会場

株式会社インタートレード
東京都中央区新川一丁目17番21号 茅場町ファーストビル3階

Twitter

twitter.com



 

全体の感想など

前回の初参加からおよそ3ヶ月、3回ぶりの参加となりました。


《過去記事》
akiyoko.hatenablog.jp



前回は、Poloniex という仮想通貨取引所の API を使ってロボアドを作ろう、ということで API を初めて触ってみたのですが、その後の成果は全く奮わず。。

今回はそれを一歩進めて、API を使って仮想通貨の売買のテストをしてみることにしました。




最近は「インベスターZ」を読んで投資のノウハウを勉強中のど素人ですが、fin-py 常連の方々に「おっ!」と思ってもらえるような爪痕を残せるようになるまで頑張ってみたいと考えています。




そして、fin-py 主催者からのつぶやき。

爪痕残せた!(違)


実行環境

  • macOS Sierra 10.12.6
  • Python 3.5.2(Anaconda 4.2.0)


 

やったこと

ccxt というライブラリのコードを読みながら、実際に触ってみました。


まず、Exchange クラスは

def load_markets(self, reload=False):
def fetch_markets(self):
def fetch_tickers(self, symbols=None, params={}):
def fetch_order_status(self, id, market=None):
def fetch_order(self, id, symbol=None, params={}):
def fetch_orders(self, symbol=None, params={}):
def fetch_open_orders(self, symbol=None, params={}):
def fetch_closed_orders(self, symbol=None, params={}):

あたりのメソッドが使えそう。

また、取引所ごとに

def fetch_ticker(self, symbol, params={}):
def fetch_trades(self, symbol, params={}):
def create_order(self, symbol, type, side, amount, price=None, params={}):
def cancel_order(self, id, symbol=None, params={}):
def withdraw(self, currency, amount, address, params={}):

が用意されている。

しかしながら create_order() は、直接使うのではなく、指値注文なら

def create_limit_buy_order(self, symbol, *args):
def create_limit_sell_order(self, symbol, *args):

create_limit_xxx_order 系のメソッドを使うっぽい。たぶん。

def create_market_buy_order(self, symbol, amount, params={}):
def create_market_sell_order(self, symbol, amount, params={}):

create_market_xxx_order 系は成行注文かな。
見たところ、対応している取引所は少なそうな雰囲気ではあるが。

# sell one ฿ for market price and receive $ right now
print(exmo.id, exmo.create_market_sell_order('BTC/USD', 1))

# limit buy BTC/EUR, you pay €2500 and receive ฿1  when the order is closed
print(exmo.id, exmo.create_limit_buy_order('BTC/EUR', 1, 2500.00))

こんな感じで使えと。
https://github.com/ccxt/ccxt#python-1


以下、実際に試してみた。


 

fetch_balance

バランスを取得する。


(使用例)

import ccxt
from pprint import pprint

ex = ccxt.bittrex({
    'apiKey': BITTREX_KEY,
    'secret': BITTREX_SECRET,
})

ret = ex.fetch_balance()
pprint(ret)


(出力例)

{'BTC': {'free': 0.33, 'total': 0.33, 'used': 0.0},
 'LTC': {'free': 0.0, 'total': 2.22, 'used': 2.22},
 'XRP': {'free': 1000.0, 'total': 1000.0, 'used': 0.0},
 ...
 'free': {...,
          'BTC': 0.33,
          'LTC': 0.0,
          'XRP': 1000.0,
          ...},
 'info': [...,
          {'Available': 0.33,
           'Balance': 0.33,
           'CryptoAddress': '1Mxxxxxxxx',
           'Currency': 'BTC',
           'Pending': 0.0},
          {'Available': 1000.0,
           'Balance': 1000.0,
           'CryptoAddress': None,
           'Currency': 'XRP',
           'Pending': 0.0},
          ...],
 'total': {...,
           'BTC': 0.33,
           'LTC': 2.22,
           'XRP': 1000.0,
           ...},
 'used': {...,
           'LTC': 2.22,
           ...}}

ルート直下は、

- info: 全通貨の情報(作成済みのアドレスやバランスなどの量)
- free: ポジションフリーになっている量を全通貨分まとめて表示
- total: 保持している総量を全通貨分まとめて表示
- used: ポジションを取っている量を全通貨分まとめて表示

各通貨の下は、

- free: ポジションフリーになっている量
- total: 総量
- used: ポジションを取っている量

という形で出力されている。



 

fetch_order_book

注文板を取得する。
Bittrex でいうところの「ORDER BOOK」の板。


(使用例)

ret = ex.fetch_order_book('LTC/BTC')
pprint(ret)


(出力例)

{'asks': [[0.00724399, 162.062],
          [0.007244, 68.0758],
          [0.00724498, 12.119],
          ...,
          [0.01287905, 0.27054]],
 'bids': [[0.00721213, 4.87597329],
          [0.0072, 112.42175327],
          [0.007194, 54.9071],
          ...,
          [1e-08, 9874677.64]],
 'datetime': '2017-10-28T06:57:05.000Z',
 'timestamp': 1509173824684}

'asks' は売り出し価格、'bids' は買いたい値段。
成立した金額に近いものから順に(すなわち 'asks' は値段の低い順、'bids' は値段の高い順に)並んでいる。

'asks' および 'bids' のそれぞれのリストは、0番目が BTC換算の価格、1番目がそれぞれの売買ボリューム(アルトコインベースで BTC建てではない)。


 

fetch_trades

他人のものを含めて過去に成立した取引を抽出する。
Bittrex で言うところの「MARKET HISTORY」の板。


(使用例)

ret = ex.fetch_trades('LTC/BTC')
pprint(ret)


(出力例)

[{'amount': 3.63704229,
  'datetime': '2017-11-05T14:21:40.000Z',
  'id': '91373876',
  'info': {'FillType': 'PARTIAL_FILL',
           'Id': 91373876,
           'OrderType': 'SELL',
           'Price': 0.00720401,
           'Quantity': 3.63704229,
           'TimeStamp': '2017-11-05T14:21:40.993',
           'Total': 0.02620128},
  'price': 0.00720401,
  'side': 'sell',
  'symbol': 'LTC/BTC',
  'timestamp': 1509891700000,
  'type': 'limit'},
  ...]


 

create_limit_buy_order

指値で買い注文を出す。


(使用例)

ret = ex.create_limit_buy_order('LTC/BTC', 2, 0.0005)
pprint(ret)

の例だと、
「0.00050000 BTC / 1 LTC」の指値で、2 LTC の注文を出している。
第三引数は、合計金額ではなく、アルトコイン1単位あたりの値段なので要注意。


なお Bittrex では、合計金額が 50K satoshi 以下のゴミ注文を出すと「DUST_TRADE_DISALLOWED_MIN_VALUE_50K_SAT」というエラーが出るようなので、これも要注意。*1


(出力例)

{'id': 'd60c914b-9ba1-4e27-b055-deb7c6549f7f',
 'info': {'message': '',
          'result': {'uuid': 'd60c914b-9ba1-4e27-b055-deb7c6549f7f'},
          'success': True}}


 

fetch_order

自分が出したオーダーを抽出する。


オーダー時の 'id' を指定します。
売買成立後のオーダーを見ることも可能。


約定前のオーダーでは、'status' が 'open' になっています。
(部分的に売れている場合はどうなるのか?については要調査。)


(使用例)

ret = ex.fetch_order('d60c914b-9ba1-4e27-b055-deb7c6549f7f', 'LTC/BTC')
pprint(ret)


(出力例)

{'amount': 2.0,
 'average': None,
 'cost': 0.001,
 'datetime': '2017-11-05T14:36:54.000Z',
 'fee': {'cost': 0.0, 'currency': 'BTC'},
 'filled': 0.0,
 'id': 'd60c914b-9ba1-4e27-b055-deb7c6549f7f',
 'info': {'AccountId': None,
          'CancelInitiated': False,
          'Closed': None,
          'CommissionPaid': 0.0,
          'CommissionReserveRemaining': 2.5e-06,
          'CommissionReserved': 2.5e-06,
          'Condition': 'NONE',
          'ConditionTarget': None,
          'Exchange': 'BTC-LTC',
          'ImmediateOrCancel': False,
          'IsConditional': False,
          'IsOpen': True,
          'Limit': 0.0005,
          'Opened': '2017-11-05T14:36:54.987',
          'OrderUuid': 'd60c914b-9ba1-4e27-b055-deb7c6549f7f',
          'Price': 0.0,
          'PricePerUnit': None,
          'Quantity': 2.0,
          'QuantityRemaining': 2.0,
          'ReserveRemaining': 0.001,
          'Reserved': 0.001,
          'Sentinel': '4f9809dd-a8d5-4225-a7cf-1feebfcea9f6',
          'Type': 'LIMIT_BUY'},
 'price': 0.0005,
 'remaining': 2.0,
 'side': 'buy',
 'status': 'open',
 'symbol': 'LTC/BTC',
 'timestamp': 1509892614000,
 'type': 'limit'}

売買成立後のオーダーを見ると、'status' が 'closed' になっていました。ちなみに、キャンセル済みの場合でも 'status' は 'closed' でした。


 

fetch_open_orders

自分が出している約定前のオーダーの一覧を抽出する。
「OPEN ORDERS」の板。


(使用例)

ret = ex.fetch_open_orders('LTC/BTC')
pprint(ret)


(出力例)

[{'amount': 2.0,
  'average': None,
  'cost': 0.001,
  'datetime': '2017-11-05T14:36:54.000Z',
  'fee': {'cost': 0.0, 'currency': 'BTC'},
  'filled': 0.0,
  'id': 'd60c914b-9ba1-4e27-b055-deb7c6549f7f',
  'info': {'CancelInitiated': False,
           'Closed': None,
           'CommissionPaid': 0.0,
           'Condition': 'NONE',
           'ConditionTarget': None,
           'Exchange': 'BTC-LTC',
           'ImmediateOrCancel': False,
           'IsConditional': False,
           'Limit': 0.0005,
           'Opened': '2017-11-05T14:36:54.987',
           'OrderType': 'LIMIT_BUY',
           'OrderUuid': 'd60c914b-9ba1-4e27-b055-deb7c6549f7f',
           'Price': 0.0,
           'PricePerUnit': None,
           'Quantity': 2.0,
           'QuantityRemaining': 2.0,
           'Uuid': None},
  'price': 0.0005,
  'remaining': 2.0,
  'side': 'buy',
  'status': 'open',
  'symbol': 'LTC/BTC',
  'timestamp': 1509892614000,
  'type': 'limit'}]

 

cancel_order

約定前のオーダーをキャンセルする。

オーダー時の戻り値から取得した 'id' の値を第一引数に使います。


(使用例)

ret = ex.cancel_order('d60c914b-9ba1-4e27-b055-deb7c6549f7f', 'LTC/BTC')
pprint(ret)


(出力例)

{'message': '', 'result': None, 'success': True}

なお、すでにキャンセル済みのオーダーに cancel_order() すると、

ccxt.base.errors.InvalidOrder: bittrex cancelOrder() error: {"success":false,"message":"ORDER_NOT_OPEN","result":null}

という例外が発生します。


 

fetch_orders

自分の過去の取引履歴を抽出する。

キャンセルを除いた、過去に売買が成立した取引だけが抽出できるはず。
新しい順に出力されます。

(使用例)

ret = ex.fetch_orders('LTC/BTC')
pprint(ret)

(出力例)

[{'amount': 1.1,
  'average': 0.00689999,
  'cost': 0.00758999,
  'datetime': '2017-11-02T11:09:40.000Z',
  'fee': {'cost': 0.00001897, 'currency': 'BTC'},
  'filled': 1.1,
  'id': 'dc7bfda3-d170-4e30-8461-771d8f690c73',
  'info': {'Closed': '2017-11-02T11:09:41.203',
           'Commission': 0.00001897,
           'Condition': 'NONE',
           'ConditionTarget': None,
           'Exchange': 'BTC-LTC',
           'ImmediateOrCancel': False,
           'IsConditional': False,
           'Limit': 0.0069,
           'OrderType': 'LIMIT_SELL',
           'OrderUuid': 'dc7bfda3-d170-4e30-8461-771d8f690c73',
           'Price': 0.00758999,
           'PricePerUnit': 0.00689999,
           'Quantity': 1.1,
           'QuantityRemaining': 0.0,
           'TimeStamp': '2017-11-02T11:09:40.91'},
  'price': 0.0069,
  'remaining': 0.0,
  'side': 'sell',
  'status': 'closed',
  'symbol': 'LTC/BTC',
  'timestamp': 1509620980000,
  'type': 'limit'},
...]

「PyCon JP 2017」に初参加してきました

タイトル

PyCon JP 2017 - connpass (2017.9.8-9)
pyconjp.connpass.com

会場

早稲田大学西早稲田キャンパス63号館
東京都新宿区大久保3-4-1

Twitter

twitter.com


 

全体の感想など

PyConJP、今回が初参加でした。
会場は隅々まで活気があって、参加した人しか分からないパワーや刺激をたくさん受けて過ごした二日間でした。

スケジュールはこちら。
pycon.jp

動画やスライドもこのページに揃っているので、参加できなかった人、見逃したセッションはここでフォローを。



一日目は昼前から参加したのですが、会場まで向かう人がまばらで、会場が大学敷地のかなり奥の方だったので「あれ?合ってんのかな?」とちょっと迷子になりかけました。。

f:id:akiyoko:20170908115140j:plain:w400


そして、初っ端からのお弁当タイム(笑)。
お弁当がタダ(チケット代に含まれている)なのは、会場で初めて知りました。ラッキー!

結構豪華です。

f:id:akiyoko:20170908115758j:plain:w400


それどころか、飲み物(コーヒー、ジュース)も無料で飲めるし、おやつタイムになったら(セルフですが)おやつがもらえるんですね。これも知らなかった。

f:id:akiyoko:20170909152925j:plain:w300
(写真は二日目の「PyConJP 最中」とアメ?)


二日目もお昼から。
脇目も振らず食堂に向かい、颯爽とお弁当を手にします。
わ〜い、選びたい放題や〜(違)

f:id:akiyoko:20170909134227j:plain:w400


休み時間が短くて(人気のセッションの前にはちょっとした席取り?なんかもあって)日頃不摂生している体にはしんどいイベントでしたが、出来たてホヤホヤ(9月9日発刊)の「PythonユーザのためのJupyter[実践]入門」が並んでいたのを休憩中に見かけたので早速購入してみました。

パラパラと立ち読みしたところ、他で見られないような細かい説明が多々あって、一瞬で「これは買い」だと感じました。一部で「鈍器」と言われている(笑)ほど分厚い本に仕上がっていますが、著者曰くどこから読んでもいいらしいので、気軽に読めそうです。しばらくしたら感想をブログに載せようかと考え中です。それにしても 400ページで 3,500円は安い!!



f:id:akiyoko:20170909144253j:plain:w400



PyCon JP とは全然関係ないですが、この翌日から夏休みで屋久杉を見に行ってきたのですが、往復12時間のトレッキングに体力の限界を感じました。。

f:id:akiyoko:20171106030010g:plain

Animated GIF editor and GIF maker で作成)





 

Day 1(9月8日)

メディア会議

  • 7割売れたら合格点
  • 最初の部数が売れたら「売れた」と言っていい
  • Pythonスタートブックが入門本で一番売れてる。1万部?
  • 5万部?売れるとビルが立つ?
  • ディープラーニング本
  • 本を書いたら人生変わる?
    • 出たばっかりなのであんまり。近しい人が声をかけてくれるくらい
    • 達成感はある。承認欲求が満たされる
    • 履歴書に書くとインパクトあるアピールになる
  • Amazonの著者ページは、編集社に権限がある場合も。だから勝手に作られてることも?
  • 本を書くためにすること
    • 公式ドキュメントを一番読んだ。下手なことは書けないので
    • 結城先生の文章の書き方、を読んだ
  • Markdown で一章1ページずつ
    • GitLab でプライベートリポジトリを創った
    • 製品版に近い状態に出力(HTML?)できるような独自のツールがある
  • e-Pub形式にするかしないか?は、飾りの多さによる?
  • Dropboxレビューの機能を使った
    • ページごとに指摘ができる??
  • 定時に帰ってから、3〜4ヶ月間コワーキングスペースに篭って執筆した
  • 〆切は1〜2ヶ月くらい遅れがち
  • 海外の公式に近いドキュメントをボランティアが無料で翻訳しているものは、出版社からするとちょっと脅威に感じる
  • Pytyon本の企画は、「Pythonこれから来るぞ!」というイチ編集者の意気込みから!?


 

Kivy


Kivy はつらそう、という感想が多かった。
PyQt はどうなの?

  • キヴィー
  • Kivy Showcase にサンプルが並んでる
  • Kv Language というUI用のメタ言語がある
    • Widget(UI)を簡単に記述できる。CSSとBootstrap(グリッド)に近い
    • 全部Pythonで書くこともできるが、KVと合わせることもできる
  • MITライセンス
  • 2017年現在も開発が盛んに行われている
  • GUI部門で一位!
  • 公式Androidアプリを試してみるのが一番わかり易い
  • Garden
    • 拡張機能。個別にインストール
  • Androidアプリの作成方法は二つ
    • Kivy Launcher
      • Pythnon 2系のみ。Kivy 1.9.1 のみ(最新版ではない)
    • Buildozer(UbuntuVM)
      • Python2/3両対応
  • クロスプラットフォームの検討
    • 2019年目処で全てのデバイスで Python3 対応予定
  • 4つの壁
    • 1. 情報が少ない(特に日本語)
    • 2. インストール
      • 非公式パッケージのインストールがオススメ
    • 3. Kv Language
      • kviewer (デバッガ?)を使うのがオススメ
    • 4. 日本語入力(IME)に問題あり
  • 簡単なアプリならすぐに作れる


 

PythonとRを行ったり来たり

https://github.com/toshiukii/rpy-talk/blob/master/rpy_pyconjp17.ipynb

  • 関西大学での教育系データの分析
  • Python と R の比較
    • 読みやすさ、書きやすさ、言語の総合力 ⇔ 知見の蓄積
    • 機械学習ライブラリ ⇔ 統計パッケージ
    • 実務家ユーザー ⇔ 研究者
    • Jupyter Notebook ⇔ RStudio
    • Rより速いことが多い ⇔ RMarkdownによる文書作成
  • Python, pandas は欠損値の扱いが雑なのがデメリット
  • Jupyter Notebook で Rkernel を使うこともできる
  • feather はカラム志向のデータストア?高速、欠損値の扱いがウリ
  • RPy2
    • Python 2.7, 3.3> で動作
    • Pythonから Rを呼び出す
  • iPythonでセルマジックを使う
    • 「%%R」でセル全体に適用させると、Rのコードをペタッと貼れる
  • Pythonでデータを綺麗にして送り込む?
  • Pandasでは、obuject型ではなくなるべくint/float型に変換しておくと間違いがない
  • WesとHadleyが組んだように、PythonとRも仲良くしようぜ!

 

PythonでOAuth『サーバ』を構築した話


仮想通貨取引所 Zaif の人。
暗号通貨のAPIを使うときの OAuthサーバの話。

  • OAuth 2.0 の話
  • 「OAuth2 規約」
    • パラメータや戻り値が規約で決まっている
  • scopeは「%20(空白)」で区切るという決まりに
  • マスタデータ登録時にリダイレクトURLを登録しておけば、リクエストのパラメータとして redirect_uri は不要
  • state はなりすまし対策。規約では必須ではないが、入れたほうがよい
  • URLのバリデートには「cornice(コーニス)」を使った
    • Pyramidと相性がよい
  • expires_in(利用期限)は3600秒がデフォルトらしい


 

プロダクト開発して分かったDjangoの深~いパーミッション管理の話

hirokiky Slides


PyQ の人。

  • Djangoの権限管理の定石
  • Lv1 View で if文
  • Lv1 User にプロパティ is_premium
  • Lv2 デコレータを作る @premium_required
  • Lv2 凝ったデコレータ @subscription_required(STANDARD_PLAN, PREMIUM_PLAN)
  • リクエストのユーザ情報とプランとが密結合。。
  • パーミッションを作る!
    • @user_permission_required("view_premium_articles")
  • Lv3 許可設定
  • パーミッションを採用すると、仕様の変更に強くなった
  • 複雑になっちゃう。。→ライブラリ!
    • Django 自体の Permission
      • DBで管理。User <-> Model のパーミッションだけ
    • django-guardian
      • 一番人気らしい。イケてる版 Djnago の Permission
    • django-rules
      • DB使わずにできる
      • デコレータやテンプレートも使える
  • django-keeper というライブラリ作った!
    • ACLを設定する

 

Day 2(9月9日)

Pythonの本気!RaspberryPiやEdisonを使ったIoTシステムの構築

https://www.slideshare.net/yutakitagami/pycon-jp-2017yuta-kitagami



を書いた人。

  • IoT時代において、「Python 最強だから」
  • Pythonでハードウェアを扱える。ハードウェア用のラブラリがあるから
    • C言語で書かれたライブラリのPythonラッパー
  • Python用のCソースが用意されている
    • py_xxx.c
  • akilib は自作ライブラリ(秋葉原の部品を扱えるライブラリ!)
  • Bottle(イイ!), tynyDB(ちょっと重い), requests
  • OpenCV も C のPythonライブラリ
  • http://elpisapi.net/TestAPI/
    • Bottle で Websocket で通信してる
  • ラズパイもPythonで動かせるが、長時間動かしていると不安定?(勝手にOS落ちてたりする?)
    • 結局Cがよいのでは???
    • Micro Python(組み込み用Python)に期待?
  • ほかの多数のライブラリとの組み合わせだと、Cでは飽和してしまうので無理
    • Cはひとつのことだけに集中するならよい

 

Pythonをとりまく並行/非同期の話

https://tell-k.github.io/pyconjp2017/

  • 並行/並列処理とは?
    • 本当に複数の処理を同時に実行するのが -> 並列処理
    • 複数処理を効率良く切り替えながらあたかも同時に実行するのが -> 並行処理
  • concurrent.futures
    • Python3.2 から追加された並行/並列処理用のライブラリ
  • Pythonのコードを実行できるスレッドは 常に一つのみ という制限
    • CPython がスレッドセーフではない Cライブラリに依存しているから
  • ちなみに、I/O処理や、一部のC拡張モジュールなどでは GILが解放される らしいです
  • CPUバウンドな処理を並列にするには?
    • マルチプロセス で 並列 に実行する
  • 非同期I/O
  • イベントを監視するためのループが イベントループ
  • コルーチン
    • 処理を任意のタイミングで中断/再開できる機能
    • Pythonではジェネレータの拡張構文として実装されている
    • ジェネレータベースのコルーチン
  • Python公式で非同期I/O のための共通のコンポーネント群
    • Python3.5 からは asyn/await構文 (ネイティブコルーチン) が使える

まとめ

  • 並行は並列を包含する概念
  • マルチスレッドはI/Oバウンドには効果あり
  • マルチスレッドはGILがあるのでCPUバウンドには効果なし
  • 並列処理をしたいのであればマルチプロセスが良い
  • C10K問題くらいからシングルスレッドでも非同期処理が必要になった
  • シングルスレッドで非同期処理
  • イベントループ/IO多重化/コルーチンという技術要素で実現
  • Pythonの非同期ライブラリ
  • asyncioの誕生の背景と概要
  • 今後は各種ライブラリがもっとasyncioに対応していくでしょう

 

SREエンジニアがJupyter+BigQueryでデータ分析基盤をDev&Opsする話

  • アプリならPython一択、インフラはBigQuery一択
  • Jupyterなら、主要BIツールにたいてい繋がる
  • 「俺の考えた最強のデータ基盤」は使われない。。
    • 重要なのは、イテレーションを回すこと。やりたいことが日々変わること
    • 事前の十全な準備は無理
  • p.118「タスクの優先順位」おもしろい!