gepuro.net
gepulog

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

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をインストールしたら、無事に起動しました。

めでたし。めでたし。

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でデータを追加したり消したりするとゴミが溜まってくるそうで、それを削除出来るとのことです。

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

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倍も変わることが分かった。

Python3のFlaskをwsgiで動かす

自分の環境ではdocker上で動かしていましたが、本筋には影響を与えないので省略します。

Flaskのドキュメントであるmod_wsgi (Apache)に書いてあるし、Python2の頃は試したことあるから、余裕だろうと油断していた。

sudo apt-get install -y apache2 \
    apache2-mpm-prefork \
    apache2-utils \
    libexpat1 \
    ssl-cert \
    libapache2-mod-wsgi-py3

上のようにインストールした。 また、

/etc/apache2/sites-available/000-default.conf を

<VirtualHost *:80>
ServerName example.com
WSGIDaemonProcess app user=www-data group=www-data
WSGIScriptAlias / /app/app.wsgi
<Directory /app>
WSGIProcessGroup app
WSGIApplicationGRoup %{GLOBAL}
# Order deny,allow
# Allow from all
Require all granted
</Directory>
</VirtualHost>

にします。dockerで動かすだけなので、ファイルを直に編集しています。

ハマりポイント1

libapache2-mod-wsgi-py3をインストールする。

パッケージ名から想像できるが、wsgiはPython3とPython2系で異なる。

ハマりポイント2

apacheの設定では、 Require all grantedを使う。

Python2系では、 Order deny,allow Allow from all で良かった。

http://stackoverflow.com/questions/30642894/getting-flask-to-use-python3-apache-mod-wsgiに救われました。

ちなみにPyttho2系の時は、Flaskでhttpsを使うに書きましたので参考にどうぞ。

2つの画像を比較

Pythonで2つの画像の比較をしたい。

シェル上で実行するなら、

diff img1.png img2.png

で良い。

Pythonでは、

img1.tostring() == img2.tostring()

で比較出来る。

もっと綺麗な方法がある気がする。その時は加筆する。

python3による日付の扱い方メモ

twitterのAPIによるとタイムスタンプ

Wed Dec 24 11:34:28 +0000 2014

python3で処理する

from datetime import datetime, timezone, timedelta
time = "Wed Dec 24 11:34:28 +0000 2014"
d = datetime.strptime(time, '%a %b %d %H:%M:%S %z %Y')

とすると、dは

datetime.datetime(2014, 12, 24, 20, 34, 28, tzinfo=datetime.timezone(datetime.timedelta(0, 32400), 'JST'))

となる。

unixtimeを得る

d.timestamp()

とすればよく、結果は

1419420868.0
となる。

日本時間にする

JST = timezone(timedelta(hours=+9), 'JST')
d = datetime.fromtimestamp(d.timestamp(), JST)

とする。

文字列として出力

d.strftime("%Y/%m/%d %H:%M:%S")

で出力は

'2014/12/24 20:34:28'
となる。

この辺りの処理って、すぐに忘れるよね。汗

参考