フリーランチ食べたい

No Free Lunch in ML and Life. Pythonや機械学習のことを書きます。

読んだ本(Pythonによるベイズ統計モデリング、基礎からわかる時系列分析)

最近読んだ本のメモ。 本当は他にも感想を書きたい本が5冊以上あるのだが、全部書こうとすると、結局出来なくてまた放置してしまうので書けるうちに書いておく。

Pythonによるベイズ統計モデリング: PyMCでのデータ分析実践ガイド

Pythonによるベイズ統計モデリング: PyMCでのデータ分析実践ガイド

Pythonによるベイズ統計モデリング: PyMCでのデータ分析実践ガイド

この本は今年2018年6月に発売されたばかりの本だけど、内容がそれなりに網羅されてるし、非常に読みやすいので、Pythonを使った実践ベイズ統計学の決定版になりそうだと思った。ちなみにこれが出る前は下の「Pythonで体験するベイズ推論」をよく人に進めていたが、階層モデルやノンパラモデルMCMCの理論面についての説明があまりなく、取っ掛かりとしては良いが、全体を俯瞰して見た時にはこちらの方がオススメできる。

Pythonで体験するベイズ推論 PyMCによるMCMC入門

Pythonで体験するベイズ推論 PyMCによるMCMC入門

何点か良いと思った点を挙げておく。

翻訳の質が高い、訳者の方の愛が感じられる

全体を通して違和感のある翻訳や内容がなかった。これは訳者の金子さんが長年の統計の実務経験をお持ちで、かつ大学の教授で指導経験もあること、そして、あとがきにも書いてあるとおり、原書に対しての愛が強いことが理由かなと思った。ただ翻訳が良いだけでなく、おそらく原著で説明が簡潔すぎるような部分は、訳者の方による補足内容と補足コードがある。また脚注の書籍に関してはすべて日本語版のリンクも記載されている。非常に丁寧な仕事だと感じ安心して読めた。

訳があまり良くないと言われている最近のベイズ本だと下の「ベイズ統計モデリング」(通称犬4匹本)がある、どうやらこちらは大学のゼミで翻訳したものをベースにしているんじゃないか?ということがAmazonレビューに書いてあった。

ベイズ統計モデリング: R,JAGS, Stanによるチュートリアル 原著第2版

ベイズ統計モデリング: R,JAGS, Stanによるチュートリアル 原著第2版

実はこの本も買ったのだだけど、確かにあまり読みやすくなく、途中で挫折してしまっている。(内容は良いらしいのでちゃんと読みたい)。本著はスイスイ読めて1~2日で読み終えられるのも魅力だ。

階層モデルの図解がとてもわかりやすい

これは実際見てもらった方がわかりやすいと思うのだけど、階層モデルは全て下のように図示されている。 f:id:mergyi:20180820003841j:plain この表し方自体もわかりやすいし、1つ1つのモデルに対して丁寧に毎回、図示してくれるのもとてもわかりやすい。後半に出てくる混合モデルのZIP回帰や多次元分布のモデリングなどはこの図で非常に理解しやすかった。

「この本の次にどうやって勉強していけばいいか」が詳細に書いてある

本著の特徴として「他のベイズ本の名前がバンバン出てくる」ということを感じた。 それらはほとんど「この本を読み終わったら次はどう勉強すればよいか」という文脈で出てきており、本著は「ベイズ統計学を学ぶ上での羅針盤」になり得る本だと思った。 上に既に挙げた「Pythonで体験するベイズ推論」や「ベイズ統計モデリング」は何度も何度も参照されている。他には下の「異端の統計学ベイズ」という統計歴史小説、のような本も参照されている。

異端の統計学 ベイズ

異端の統計学 ベイズ

Pythonで体験するベイズ推論」や「異端の統計学ベイズ」など自分が既に読んで質が高かったものが多く参照されており、この本に対しての信頼度も高くなった。

コード例がわかりやすい

他にも簡潔なコードが全てのセクションで記載されていて、手元で再現することができる。コードは下のGithubに全てあがっている。

github.com

全体的にオススメ

まずベイズを概念的に理解でき、理論的にもある程度理解でき、コードの書き方もわかるのでかなりバランスが良いと思う。演習もかなり充実していたので、実践してみてBlogに書きたいと思っている。

基礎からわかる時系列分析

こちらの本も今年2018年3月に発売されたばかりであり、タイトルやシリーズから期待して読んだのだが、内容の網羅性に関しては良かった一方、説明は親切というわけではなく、自分の体験として、「もう理解している部分は言っていることはわかるが、まだ理解できていない内容に関しては結局わからない」というものだった。最近色々な種類の本を読んでいて気づいてきたのだが、「良い本」の重要なエッセンスは「正しい内容が書いてある」のではなく、「今まで超えられなかった壁を超えさせてくれる」ことなのではないかと感じている。ただ、この本も誠実な内容だと思うので、「壁を超えられたら」復習としてもう一回帰って来たい。

【Selenium】JavascriptのObjectの状態変化を待機する

TL;DR

  • Custom Wait Conditionsとdriver.execute_scriptを組み合わせる

Seleniumで「ある特定の動作を待つ」

最近はSPA的なサイトが増えてきたので「求めているDOMがブラウザにレンダリングされた」後に「ある特定の動作をさせたい」という気持ちになるときは多いのではないでしょうか。 そういう場合のために、Seleniumには、「待機する」用のClassが用意されています。例えば WebDriverWaitexpected_conditions です。 公式ドキュメントの例ですが、下記のように書くことができます。

5. Waits — Selenium Python Bindings 2 documentation

下記の例の場合、「idがmyDynamicElementの要素が出現するまで10秒ごと待機する」コードになります。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Firefox()
driver.get("http://somedomain/url_that_delays_loading")
try:
    element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "myDynamicElement"))
    )
finally:
    driver.quit()

様々な条件で待つ

presence_of_element_located 以外にも下記のようにメソッドが用意されており、様々な条件で待機することができます。

* title_is
* title_contains
* presence_of_element_located
* visibility_of_element_located
* visibility_of
* presence_of_all_elements_located
* text_to_be_present_in_element
* text_to_be_present_in_element_value
* frame_to_be_available_and_switch_to_it
* invisibility_of_element_located
* element_to_be_clickable
* staleness_of
* element_to_be_selected
* element_located_to_be_selected
* element_selection_state_to_be
* element_located_selection_state_to_be
* alert_is_present

JS Objectをチェックしたい

ただ問題としては全てHTMLの条件をチェックするということです。 待機する要素が多数に渡る場合は全ての要素をチェックするのはかなりしんどいので「一連の動作が終わったあとに、あるJS Objectの要素が書き換わる」ことをチェックしたいケースは少なからずあるのではないでしょうか。そんな場合は上記のメソッドは使えません。

Custom Wait Conditions

そんなときに使えるのがCustom Wait Conditionsで自分で特定の条件を書くことができます。 公式のも例がありますが、最もシンプルな例ではないので、もっとシンプルに書くと第二引数に driver を受け取る __call__ さえあればOKです。 __call__ は「ある特定の条件を満たしていなかったら False をそれ以外は受け取りたい要素を返す」ように実装します。

class CustomCondition:
  def __call__(self, driver):
    some_value = driver.some_method()
    if some_value == “some_condition":
        return some_value
    else:
        return False

wait = WebDriverWait(driver, 1)
some_condition = wait.until(CustomCondition())

この例だと「1秒ごとに状況をチェックしにいって、Falseでなかったら終了(値が帰ってくる)」コードになります。

driver.execute_script でJS Objectの状況取得

あとはこの条件にJS Objectの状況を入れられれば任務完了になります。SeleniumからJS Objectを取得するには driver.execute_script メソッドを使えば良いです。

7. WebDriver API — Selenium Python Bindings 2 documentation

例えばグローバルに以下のようなオブジェクトがあった時に

foo = {bar: ‘hoge'}

下記のようにして値を取得することが出来ます。

value = driver.driver.execute_script(‘return window.foo.bar’)
print(value) # => hoge

組み合わせる

これをCustom Wait Conditionsと組み合わせるとこのようになります。

class CustomCondition:
  def __call__(self, driver):
    some_value = driver.driver.execute_script(‘return window.foo.bar’)
    if some_value == “hoge":
        return some_value
    else:
        return False

wait = WebDriverWait(driver, 1)
some_value = wait.until(CustomCondition())

これで「 foo.bar == “hoge” になるまで動作を待機する」コードが書けました。めでたしめでた;。

(古典)統計学と機械学習の翻訳テーブル

(古典)統計学機械学習では使う名称が全然違う

土日は医学系研究室で客員研究員として粛々と研究しているのですが、医学系の研究というのはまだまだ古典統計学が主流です。古典統計学を扱う時の問題は色々あるのですが、その中でも大きいのは機械学習と同じ概念なのに名称が違うことです。 これはけっこう大変で、自分は普段「機械学習の用語」で考えているので、「(古典)統計学の用語」で考えている教授や学生さんと話すときに脳をフル回転させて同時翻訳する必要があります。もはやバイリンガルみたいな気持ちです。

まぁ大変なだけだったら良くないけど良いのですが、ときどき認識の齟齬が発生したりして、それは実質的な問題なので、とりあえず今後間違いを減らせるように「翻訳テーブル」を作ってみました。

モデルに対する翻訳テーブル

(古典)統計学 機械学習 備考
重回帰分析 一般線形回帰モデル 一般化線形回帰モデルを(古典)統計学でなんと呼ぶのだろうか
従属変数(dependent variable) 目的変数(response variable) 数式ではY
独立変数(independence variable) 説明変数(explanatory variable) 数式ではX
要因, 質的変数 離散の説明変数 (古典)統計学では名義尺度、順序尺度などさらに分かれている
共変量, 量的変数 連続の説明変数
偏回帰係数, 回帰係数 パラメータ、係数
尤度関数 目的関数, 損失関数(符号は逆)

適宜更新していきたい

とりあえず今思いついたものを書き出してみただけなのですが、普段から言語の壁を感じまくっているので気付いたら書き足していきたいと思ってます。「これもあるよ!」という方がいたら教えてください。

リモートワークの戦略とメリデメを整理する+弊社のリモートワーク事例の紹介

「リモートワークどうですか?」に対する回答を考える

今、自分が働いている会社はリモートワークを推進していて、自分自身も週3~4でリモートワークをしています。そういう状況なので、最近よく「リモートワークってどうですか?上手くいきますか?」と聞かれることが多いです。自分に関して言えば、リモートワークは「上手くいっていて最高!」なのですが、世の中では「リモートワークの失敗例」というものも表面化していて、一概に「リモートワークはイイ!」「リモートワークはワルイ!」で語ることに限界を感じていました。

ちょうど良い案件があった

そんなことを考えているところに、リモートワーク導入を考えている会社の友人から質問リストをもらったので、それに回答しながらリモートワークにおける戦略とメリットデメリットを整理してみました。 基本的にここに書いたことは自分の経験を元に仮説として考えたものでたたき台のイメージです。これを元にリモートワーク導入について誰かと議論できたらいいなと思っています。また、結果的に弊社のリモートワーク事例の紹介にもなりました。

質問リスト

それでは、下記の質問に答えていきたいと思います。

①リモートワークと会社出勤、両方選べるならどっち選ぶ?
②その理由はなんで?
③リモートワークで起きるいいこと
④リモートワークで起きる悪いこと
⑤生産性あがった?
⑥会社として生産性管理やモチベーション管理はどうしてる?
⑦MTGはどうしてる?
⑧今後リモートワークができる会社に有能な人は集まると思う?

①リモートワークと会社出勤、両方選べるならどっち選ぶ?②その理由はなんで?

タスクによって向き不向きがあると感じているので、ときと場合によって使い分けています。

分類してみる

具体的には下の図のように分類できるのではないかと、ふわふわ考えています。

まずタスクの分類です。色々な分け方があるかと思いますが、今回はタスクの難易度意思決定の頻度で見てみました。

f:id:mergyi:20180804020931p:plain

自分の場合は

  • A(タスク難, 連絡 少): 基本的にリモートワーク
  • B(タスク易, 連絡 少): どちらでも良い(都合の良い方)
  • C(タスク易, 連絡 多): どちらでも良い(都合の良い方)
  • D(タスク難, 連絡 多): 基本的に出社

するようにしています。こう見てみると、タスクが簡単であれば、リモートでも出社してもそんなに生産性に差がなく、タスクが難しく複雑なときは生産性に大きく影響するのではという仮説を立てることができます。リモートワークの生産性に関して語るのであれば、タスクを分類して生産性が下がりそうなタスクに対してどう対応していくかが大事だと思います。

割合は?

人によってバラバラだと思いますが、自分はざっくりと下のような感じです。 f:id:mergyi:20180806120909p:plain

A(タスク難, 連絡 少)の割合が多く、(Aに集中させてもらえてるのは貴重なことだと思うので感謝してます)リモートワークで生産性がかなり上がった、と感じています。

③リモートワークで起きる良いこと

「リモートワークできる」ということは単純に人生というRPGの自由度が上がるということなので良いことはたくさんあります。

仕事に集中できる

オフィスで働いているときはいろんなインターラプトがありました。 誰かに質問されたり、近くで気になる会話をしていて耳をそばだててしまったり。 これは良い刺激だし、楽しいのですが、やはりフロー状態に入る回数は少なかったと思います。 今はインターラプトは宅急便くらいしかないし、集中できる時間帯(自分は深夜が一番捗ります)にまとめて作業できるので捗ります。フロー状態に入る回数はかなり多くなったと思います。

土日が「真の休日」になる

これはリモートワークしていないと意外とわからないかも、と思いました。 以前も土日は休みだったんですが、平日にできない家事や荷物受け取り、市役所・病院に行く用事などをするのに毎週半日は使ってたと思います。今はこれらの作業は全て仕事をこなしながら平日に行ってます。なので土日は完全に自分の時間として使えます。

家族との時間が取れるようになる

僕は独り身なので実感は薄いのですが、チームのメンバーを見ていると「子どもの送り迎え」や「ご家族の看病」など家庭へのコミット度がハンパないなと感じます。お子さんを膝に載せながら働いているメンバーを見ると微笑ましすぎてとても幸せな気持ちになってしまいます。普通に「自分の父親もこういう働き方していたら母親はありがたかったろうな〜」と思うことが多いです。

健康になる

これは人による、と思いますが、自分は転職前は食事は基本的に外食、運動は時間が取れず出来てないという、まさに現代人、な状態だったのですが、今は、食事は自炊が8割、毎日2回ジョギング、週に3回トレーニングしている状態なので、激変したと思います。食事も野菜の量に気を使ったりできるようになりました。「それってリモートワーク関係なくない?」と思われるかもしれませんが、実際リモートワークして変わったのです。多分、時間と精神的な余裕のおかげかなと思ってます。

※福利厚生と書いてありますが、会社の福利厚生ではないです。笑

遊びの自由度が広がる

遊びたいときに遊び、働きたいときに働くスタイルになりました。 ふつうの平日の昼間に外で流しそうめんをするなんてリモートワークしなければ考えられなかったです。

④リモートワークで起きる悪いこと

上述させてもらった内容になりますが、「リモートワークできる」ということは単純に(自分も他のメンバーも)人生というRPGの自由度が上がる、ということなのでリモートワークすると絶対に起きる「悪いこと」というのは存在しないと思います。ただ、RPGと同じ(?)で自由度が上がれば難易度も上がります。では「何ができなかったら、どんな悪いことが起きるのか」を考えてみました。 f:id:mergyi:20180804033150p:plain

上記のように「組織としてカバーすべきこと」「個人がカバーすべきこと」のどちらかが達成されなかった時に悪影響が発生すると考えています。この図自体はリモートワーク関係ないのですが、リモートワークは非リモートワークに比べて「組織に求められるもの」も「個人に求められるもの」もレベルがかなりあがるイメージがあります。

⑤生産性あがった?

①に書いたAのタスクに関しては非常に生産性が上がったと感じてます。 入社して3ヶ月で月間MVP、上半期MVPもらえたのはこの生産性向上がなかったら(リモートでなかったら)絶対できなかったと思ってます。(MVPはちょっと自慢。笑)

ikedaosushi on Twitter: "全社MVPをもらって喜ぶ28歳。入社して3ヶ月、大変な事もあったけど、頑張ってきた事を評価してもらえて本当に嬉しい🙌🙌🙌… "

⑥会社として生産性管理やモチベーション管理はどうしてる?

OKRを使って目標管理を行っており、全社、部門、部署、PJとドリルダウンしていく仕組みになっています。 モチベーション管理というかわからないですが、働きやすい環境をつくる工夫はたくさんされていて、その一部はBlogでも紹介されています。

⑦MTはどうしてる?

Zoomを使って行ってます。通信状態が悪くてもかなり繋がりやすいし、画面シェア機能の細かい設定ができるので便利に使ってます。 また、リモートワークだから得られた面白い利点みたいなものがあったので書いておきます。

オフィスにいてもリモートMT

今の会社に来て面白いなと思ったのは、MTに出席者が2人以上オフィスにいても参加者の何人かがリモートだとZoomでリモートMTするということです。最初はえ?と思ったのですがやってみるとパラダイムシフトが起こりました。どんな状況でもZoomを使う(使える)、ということはMTする相手がどこにいるか、や、MTの場所を一切考えなくていいんです。 今はMTを開催するまで/されるまで、の精神的障壁がかなり低く「MTの内容に集中できている」と感じます。’

どんなMTにでも参加できる

会議室ごとにZoomのURLが設定されているので、会議室で行われるような「経営会議」などには自由に参加して話している内容を聞くことができます。オンボーディングの一貫で自分が参加しない部としての方向を決定するMTにZoomで参加して部としての現状を把握するのは、その後の仕事にとても役立ちました。

⑧今後リモートワークができる会社に有能な人は集まると思う?

これは一般論半分という感じですが、下の図のように「A(リモートしたい人の集合)」「B(リモートしてもしなくても良い人の集合)」を書いた時にそれぞれに一定の割合で「優秀な人」がいるはずなので「リモートOKな会社」の方が当然、優秀な人を雇うチャンスは大きいと思います。 f:id:mergyi:20180804030348p:plain

今後、という話だと図にも書いたとおり、時代に合った働き方をしたい、みんな考えていると思うのでA(リモートしたい人の集合)が増えてくると思います。 そうなると「リモートOKな会社」の方が優秀な人を雇うチャンスはどんどん大きくなってくるのではないでしょうか。

さいごに

以上で質問への回答は以上です。今更ですが、自分はリモートワークをしているし、リモートワークが好きなので完全にポジショントークです。また、本当はもっと細かく詰めたいところばかりなのですが、体力が尽きたのでまた誰かと議論してまとまってきたら追記していきたいと思ってます!

Linuxでadduserに-gecosを指定したら何ができるか。なぜ gecosという名前なのか。

あるソフトウェアのセットアップで adduser -gecos を設定するExampleがあって、何をしているか理解していなかったので調べてみました。

TLDR

  • -gecos optiongecos field を設定するときに使うもの
  • なぜ gecos というかは歴史的経緯があった
  • システムとしてのみ使う場合に便利
続きを読む

pipが v10->v18になってビビってメーリングリスト見たみたらリリースサイクルも変わってた

TLDR

急にv18が来たので(QVK)

pipが急にv18になってビビった。 https://github.com/pypa/pip/releases/tag/18.0

$ pip install -U pip
Collecting pip
  Downloading https://files.pythonhosted.org/packages/5f/25/e52d3f31441505a5f3af41213346e5b6c221c9e086a166f3703d2ddaf940/pip-18.0-py2.py3-none-any.whl (1.3MB)
    100% |████████████████████████████████| 1.3MB 4.8MB/s
Installing collected packages: pip
  Found existing installation: pip 10.0.1
    Uninstalling pip-10.0.1:
      Successfully uninstalled pip-10.0.1
Successfully installed pip-18.0

「アップデートね、おけおけ…...18!!?」みたいな感じになった。

CalVer

Twitterを眺めてみると「calver」というワードがチラホラ出ていて、これはCalendar Versioningのことらしい。 calver.org

つまり pip v18.0 の18は2018の18だったということ。 ubuntu18.04 のようにMinor Versionは月になっているが pipは 18.0 のようになっているので 18.0~3 のようになるのかな。

リリースサイクルも変わってた

詳細な情報を確認するためにメーリングリストを見たらちゃんとCalVerになることが書いてあった

Google グループ

This is the first pip release since adopting 3 month release cadence and 
a Calendar based versioning scheme (also known as CalVer). In simpler 
words, there will be a new pip release every 3 months unless there are 
no changes since the previous release. More details such as release 
months can be found in pip's development documentation. 

それとは別にリリースサイクルも変わっていることにも気付いた。今後はCommitが1つでもあれば3ヶ月おきにリリースしていくとのこと。 今までは結構リリースにムラがあったので(Releases · pypa/pip · GitHub) 安定した開発を続けていこうという意思なのかな。 (Releases見て気付いたけど、2017は全くリリースがなかったのにビックリ)

他にもちょいちょい変更あった

Google グループ 上記のメーリスより

- Python 3.3 is no longer supported - if you need pip on Python 3.3, 
  you should stay on pip 10, which is the last version to support Python 
  3.3. 
- Complete PEP 518 support - includes support for installation of build 
  dependencies from source and Unicode support on Python 2 and Windows 
- New --prefer-binary flag, to prefer older wheels over newer sdists 
- Many bug fixes and minor improvements 

大きなものだと↓がありそう。

  • Python3.3のサポート終了
  • PEP518(https://www.python.org/dev/peps/pep-0518/)のサポート完了
    • なんのPEPかと思ったらpackageをbuildするformatの仕様だったよう
    • もしかしてこれでinstallできなくなるpackageがあるのかも?

まとめ

  • 能動的にメーリングリストを見ることは少ないけど、受動的に情報を受け取っているだけでは知れないことがたくさんあるので、できるだけチェックした方がよい。
  • Software全体としてCalVerに移行していく流れがあるような気がする。

docker-compose run は portをmappingしない

dokcer-composeでちょっとハマったのでメモ

TLDR

  • 単純に docker-compose run service_name すると設定したportがmappingされない
  • docker-compose run --service-ports service_name すれば良い

詳細

↓のようなdocker-compose.ymlがあったときに

version: '3.5'
services:
    a:
        image: hoge
        ports:
            1234:1234

service_aだけ実行したかったので、 $ docker-compose run a /bin/bash とaだけrunした。

プロセスをチェックしてみると、portsをmapping されていない。

$ docker-compose ps 
          Name                         Command               State            Ports
--------------------------------------------------------------------------------------------
reponame_a_1     /bin/bash    Up

この問題に関してはGithubで質問されていたりして、詰まっている人は多いようだ。 Docker-compose run command doesnt map ports · Issue #1259 · docker/compose · GitHub

原因と解決策は、公式ドキュメントにしっかり書かれている。 run — Docker-docs-ja 17.06.Beta ドキュメント

使い方: run [オプション] [-e キー=バリュー...] サービス [コマンド] [引数...]

オプション:
-d                    デタッチド・モード: コンテナをバックグラウンドで実行し、新しいコンテナ名を表示
--name NAME           コンテナに名前を割り当て
--entrypoint CMD      イメージのエントリーポイントを上書き
-e KEY=VAL            環境変数を指定 (複数回指定できる)
-u, --user=""         実行時のユーザ名または uid を指定
--no-deps             リンクしたサービスを起動しない
--rm                  コンテナ実行後に削除。デタッチド・モードの場合は無視
-p, --publish=[]      コンテナのポートをホスト側に公開
--service-ports       サービス用のポートを有効化し、ホスト側に割り当て可能にする
-T                    疑似ターミナル (pseudo-tty) 割り当てを無効化。デフォルトの `docker-compose run` は TTY を割り当て
-w, --workdir=""      コンテナ内のワーキング・ディレクトリを指定

のうち、↓を使えばよい。

--service-ports       サービス用のポートを有効化し、ホスト側に割り当て可能にする

なので結論としては、

$ docker-compose run --service-ports service_name

とすればよい。

$ docker-compose ps 
          Name                         Command               State            Ports
--------------------------------------------------------------------------------------------
reponame_a_1     /bin/bash    Up    0.0.0.0:1234->1234/tcp

正しくmappingされた🎉

「なんでそういう仕様なの?」という声も聞こえてきそうだが(Githubで「直したほうが良くね?」って言ってる人もいた)

理由もしっかり公式ドキュメントに書いてある。 run — Docker-docs-ja 17.06.Beta ドキュメント

2つめの違いとして、 docker-compose run コマンドはサービス設定ファイルで指定したポートを作成しません。これは、既に開いているポートとの衝突を避けるためです。

確かに?ただ docker-compose up を2回すると衝突しそうだよな。と思って試したら新しくコンテナは作成されなかった。 公式ドキュメントにはその辺り明言されていないようにも見えるが雰囲気から、そういう仕様ということはわかる。

up — Docker-docs-ja 17.06.Beta ドキュメント もしサービス用のコンテナが存在している場合、かつ、コンテナを作成後にサービスの設定やイメージを変更している場合は、 docker-compose up -d を実行すると、 設定を反映するためにコンテナを停止・再作成します(マウントしているボリュームは、そのまま保持します)。Compose が設定を反映させないようにするには、 --no-recreate フラグを使います。

まとめ

公式ドキュメントをしっかり読むと色々わかるからしっかり読もう