gepuro.net
gepulog

データ分析エンジニアによる備忘録的ブログ

awscliを使おうとしたら"get_environ_proxies() missing 1 required positional argument: 'no_proxy'"と怒られた話

ある日、いつも通りに

$ aws s3 ls

と実行したら、

get_environ_proxies() missing 1 required positional argument: 'no_proxy'

と怒られました。

手元の環境は、Ubuntu16.04で、 awscliのバージョンは aws-cli/1.11.13 Python/3.5.2 Linux/4.4.0-75-generic botocore/1.4.70 です。

エラーメッセージでググッても何も出てこないので、再起動をしてみたり、awscliをダウングレードしたりしましたが、結果は変わらず。

最終的には、

$ sudo pip3 install --upgrade boto3

と実行して、boto3のバージョンを最新にあげたら直りました。

めでたし、めでたし。

AWS AthenaでPartitionの設定をする

AWS re:Invent 2016で発表されたAthenaというサービスを試してみました。このサービスはS3上にあるデータに対してSQLでデータを取得することが出来ます。一言で言えば、AWS版のBigQueryです。 gzで圧縮されたままのデータに対してもクエリを投げることができ、データをスキャンした量に応じて課金されます。2017年2月15日現在では、1TB あたり5USDと非常に安いです。

BigQuery同様に巨大なデータをうっかりスキャンしてしまうとお金が飛んでいくので注意です。参考: BigQueryで150万円溶かした人の顔

というわけで、日付毎にPartitionを切りましょうという話です。 Englishが得意な皆さんは、https://docs.aws.amazon.com/athena/latest/ug/partitions.html見てもらえば一発ですが、備忘録のために書き残します。

データの準備

下にあるデータを仮定します。

$ cat 20170101.tsv 
a    1
a    2
a    3

$ cat 20170102.tsv 
b    1
b    2
b    3

$ cat 20170103.tsv 
c    1
c    2
c    3

S3に保存する

こんな感じです。年月日ごとにログを保存してあるような、よく見る形式です。

$ aws s3 ls athenatest.aws.gepuro.net --recursive
2017-02-15 19:27:10          0 20170101/
2017-02-15 19:27:28         12 20170101/20170101.tsv
2017-02-15 19:27:15          0 20170102/
2017-02-15 19:27:42         12 20170102/20170102.tsv
2017-02-15 19:27:18          0 20170103/
2017-02-15 19:27:53         12 20170103/20170103.tsv

テーブルを作る

GUIでの設定方法は見れば分かると思いますが、 次の通りです。

  • データベース名: mytest
  • テーブル名: ymdtest
  • TSV形式
  • データノカラムをvar1, var2という名前に
  • Partitionのカラムをdtに
  • S3のパス: s3://athenatest.aws.gepuro.net/

すると、次のようなクエリが生成されます。

CREATE EXTERNAL TABLE IF NOT EXISTS mytest.ymdtest (
  `var1` string,
  `var2` string 
) PARTITIONED BY (
  dt string 
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'
WITH SERDEPROPERTIES (
  'serialization.format' = '    ',
  'field.delim' = '    '
) LOCATION "s3://athenatest.aws.gepuro.net/"

このクエリを実行すれば、テーブルが作られます。

パーティション毎にデータを突っ込む

ALTER TABLE mytest.ymdtest add partition (dt="20170101")
LOCATION "s3://athenatest.aws.gepuro.net/20170101/"

とすると、20170101のデータをテーブルに突っ込めます。

これをパーティションだけ繰り返します。 つまり、

ALTER TABLE mytest.ymdtest add partition (dt="20170102")
LOCATION "s3://athenatest.aws.gepuro.net/20170102/"
ALTER TABLE mytest.ymdtest add partition (dt="20170103")
LOCATION "s3://athenatest.aws.gepuro.net/20170103/"

とすれば、データが入ります。

クエリの実行

全データスキャンするなら、

SELECT * FROM mytest.ymdtest

20170101のみスキャンするなら、

SELECT * FROM mytest.ymdtest
WHERE dt='20170101'

20170101~20170102で範囲指定するなら、

SELECT * FROM mytest.ymdtest
WHERE
dt>='20170101'
AND dt<='20170102'

とします。

念押ししておくと、データスキャン量に応じて課金するので、

WHERE var1='a'

のように条件をつけただけでは、全データをスキャンしてしまいます。注意!!! Athena画面上にスキャンした量が表示されるので、気にしておくと良いです。

また、クエリの出力結果はS3に保存されています。このバケットに対しては、ライフサイクルを設定しておいた方が良さそうです。

Enjoy Athena!!

jupyter notebookをubuntu 16.04にインストールするときにハマった罠

手元の端末にjupyter notebookをインストールしていなかったので、機嫌良くpip3 install jupyterでインストールしてjupyter notebookで起動したところ、

Native kernel (python3) is not available

というメッセージが表示された。ブラウザから「New」を見てもPython3の文字は表示されていない。

改めてjupyterを次のようにしてインストールした

$ pip3 install --upgrade jupyter

すると、

Exception:
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/pip/req/req_install.py", line 1006, in check_if_exists
    self.satisfied_by = pkg_resources.get_distribution(str(no_marker))
  File "/usr/share/python-wheels/pkg_resources-0.0.0-py2.py3-none-any.whl/pkg_resources/__init__.py", line 535, in get_distribution
    dist = get_provider(dist)
  File "/usr/share/python-wheels/pkg_resources-0.0.0-py2.py3-none-any.whl/pkg_resources/__init__.py", line 415, in get_provider
    return working_set.find(moduleOrReq) or require(str(moduleOrReq))[0]
  File "/usr/share/python-wheels/pkg_resources-0.0.0-py2.py3-none-any.whl/pkg_resources/__init__.py", line 695, in find
    raise VersionConflict(dist, req)
pkg_resources.VersionConflict: (ipython 2.4.1 (/usr/lib/python3/dist-packages), Requirement.parse('ipython>=4.0.0'))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/pip/basecommand.py", line 209, in main
    status = self.run(options, args)
  File "/usr/lib/python3/dist-packages/pip/commands/install.py", line 317, in run
    requirement_set.prepare_files(finder)
  File "/usr/lib/python3/dist-packages/pip/req/req_set.py", line 360, in prepare_files
    ignore_dependencies=self.ignore_dependencies))
  File "/usr/lib/python3/dist-packages/pip/req/req_set.py", line 448, in _prepare_file
    req_to_install, finder)
  File "/usr/lib/python3/dist-packages/pip/req/req_set.py", line 387, in _check_skip_installed
    req_to_install.check_if_exists()
  File "/usr/lib/python3/dist-packages/pip/req/req_install.py", line 1011, in check_if_exists
    self.req.project_name
AttributeError: 'Requirement' object has no attribute 'project_name'

というエラーが出ていることに気づいた。 どうやら、ipythonのバージョンが低いようなので、

pip3 install --upgrade ipython

をしてみたが変化なし。

どうやら原因はapt-getからインストールしたipythonのバージョンが低いようです。 手元の環境をよく見なおしてみると、pipからインストールしたipythonとapt-getからインストールしたipythonの両方が入っていました。

apt-getからインストールした古いipythonを削除して、再度jupyterをインストールしたら、無事に起動しました。

めでたし。めでたし。

データサイエンスLT祭り 2夜目で発表してきました

久しぶりにLTをした気がします。少しだけ便利になると思うので、使ってもらえると嬉しいです。

Rstudio上でのパッケージインストールを便利にするaddin4githubinstall from gepuro

SQLite3をPythonから使っていたら「sqlite3.OperationalError: database or disk is full」というエラーが出た

タイトルの通りで頭を抱えていました。

Bashで

$ df -h

を実行してもディスクは溢れていなかったのです。

ググってみるとSQLITE3 VACUUM, “database or disk is full”という人がいたので覗いたら解決しました。

conn = sqlite3.connect("data.db")
cur = self.conn.cursor()
cur.execute("""
    pragma temp_store_directory='/tmp'
    """)
conn.commit()

のようにして、一時ディレクトリを指定したら動くようになりました。 デフォルトでは、どこに持ってるのだろうか?そこまでは調べていません。

また、

vacuum;

というのも覚えました。

SQLite3でデータを追加したり消したりするとゴミが溜まってくるそうで、それを削除出来るとのことです。

データベースが大きくなった時に活躍しそうなので、ついでにメモしておきます。

統計的学習の基礎4.4~を読みました

統計的学習の基礎読書会で発表してきました。以下がその時の資料です。

統計的学習の基礎 4.4~ from gepuro

ATOMで数式を改行する方法

動作環境は、mathjax-warapperを入れて、markdown-preview-plusでプレビューを確認している。

下の方法で改行出来た。

\[
\begin{align}
y &= x + x + x \\
&= 3 x
\end{align}
\]

Python3で「if a in b」をするときはsetを使うべし

タイトルの通りです。下のコードで確認しました。 データが増えてくると1万倍は変わるようです。

Python 3.5.1 |Anaconda 2.4.1 (64-bit)| (default, Dec  7 2015, 15:00:12) [MSC v.1900 64 bit (AMD64)]
Type "copyright", "credits" or "license" for more information.

IPython 4.0.1 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: %cpaste
Pasting code; enter '--' alone on the line to stop or use Ctrl-D.
:import time
:
:a = [i for i in range(10000)]
:b = [i for i in range(5000,100000)]
:start = time.time()
:[i for i in a if i not in b]
:elapsed_time = time.time() - start
:print(elapsed_time)
:
:a = [i for i in range(10000)]
:b = set([i for i in range(5000,100000)])
:start = time.time()
:[i for i in a if i not in b]
:elapsed_time = time.time() - start
:print(elapsed_time)
:<EOF>
7.634490013122559
0.0005004405975341797

numpy上で平均を求める v.s. Pandasで平均を求める

計算の待ち時間が長く感じることが増えたので調べる 結論は、numpyのみで計算した方が早い。 以下で確認した。

Python 3.5.1+ (default, Mar 30 2016, 22:46:26) 
Type "copyright", "credits" or "license" for more information.

IPython 2.4.1 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: %cpaste
Pasting code; enter '--' alone on the line to stop or use Ctrl-D.
:import numpy as np
:import time
:
:start = time.time()
:dt = np.array([0 for i in range(100)], dtype=float)
:for i in range(100):
:    dt += dt
:dt = dt/100
:elapsed_time = time.time() - start
:print(elapsed_time)
:
:import pandas as pd
:start = time.time()
:dt = np.array([0 for i in range(100)], dtype=float)
:dt_list = [dt for i in range(100)]
:pd.DataFrame(dt_list).mean()
:elapsed_time = time.time() - start
:print(elapsed_time)
:<EOF>
0.00039386749267578125
0.00755763053894043

Pandasのappendが遅くて萎えた話

あまりにも処理に時間がかかるので、下のコードで確認した。

gepruo@ubuntu$ ipython3
Python 3.5.1+ (default, Mar 30 2016, 22:46:26) 
Type "copyright", "credits" or "license" for more information.

IPython 2.4.1 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: %cpaste
Pasting code; enter '--' alone on the line to stop or use Ctrl-D.
:import pandas as pd
:import time
:start = time.time()
:df = pd.DataFrame()
:for i in range(100):
:    df.append(pd.DataFrame([1,2,3]))
:elapsed_time = time.time() - start
:print(elapsed_time)
:
:
:start = time.time()
:def gen_data():
:    for i in range(100):
:        yield [1,2,3]
:df = pd.DataFrame([i for i in gen_data()])
:elapsed_time = time.time() - start
:print(elapsed_time)
:
:<EOF>
0.21839094161987305
0.0008673667907714844

たった100回のappendであっても約251倍も変わることが分かった。