どこかに向かうらしい話

迷走エンジニアの放浪記

split()とsplit(" ")で出力が異なる件について

掲題の通り。
split()split(" ")では、微妙に出力結果が違うことに注意。

>>> space1 = "a b"

>>> space2 = "a  b"

>>> space3 = "a   b"

>>> [i for i in space1.split()]
['a', 'b']

>>> [i for i in space1.split(" ")]
['a', 'b']

>>> [i for i in space2.split()]
['a', 'b']

>>> [i for i in space2.split(" ")]
['a', '', 'b']

>>> [i for i in space3.split()]
['a', 'b']

>>> [i for i in space3.split(" ")]
['a', '', '', 'b']

Pythonでの多次元配列の定義方法

Pythonで多次元配列の定義についてのメモ。
基本的にはリスト内包表記で次のように配列を作ります。

例えば、要素数1が3、要素数2が4の2次元配列arr2は、

>>> arr2 = [[0 for i2 in range(4)] for i1 in range(3)]

にて作成可能。
例えば、要素数1が3、要素数2が4、要素数3が5の3次元配列arr3は、

>>> arr3 = [[[0 for i3 in range(5)] for i2 in range(4)] for i1 in range(3)]

にて作成可能。 arr3[i1][i2][i3]の値の操作は、

>>> arr3[1][2][3] = 1

>>> arr3
[[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]],
 [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 0]],
 [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]]

と言った感じで扱える。

Python3におけるmap/filterの使い方

はじめに

map()/filter()の使いどころがよくわからないので、自分なりに調査をしてみた。
この2つの関数は、Python2系とPython3系では挙動が異なるので、まずはその話から。

まずは、具体的に実行内容を見てみたい。

python2系での実行結果

>>> print(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> print(map(lambda x: x*2, range(10)))
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>> print(filter(lambda x: x % 2, range(10)))
[1, 3, 5, 7, 9]

python3系での実行結果

>>> print(range(10))
range(0, 10)
>>> print(map(lambda x: x*2, range(10)))
<map object at 0xb7bdd74c>
>>> print(filter(lambda x: x % 2, range(10)))
<filter object at 0xb7bdd74c>

Python2系では,上に挙げたそれぞれの関数、メソッドはそれぞれリストを返している。
しかし,Python3系ではリストではなく、iterator objectを返すように挙動が変更された。
iteratorを返すことで、一度に全要素を計算せず、要素が必要とされる時に計算するようになり、使用するメモリ量を低く抑えているとのこと。

2系のように、iteratorをリスト化したい場合はiteratorをlist関数に渡してリストを生成すればよい。

>>> print(list(map(lambda x: x*2, range(10))))
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

>>> print(list(filter(lambda x: x % 2, range(10))))
[1, 3, 5, 7, 9]

set関数に渡せば、iteratorより集合も生成可能。

>>> print(set(map(lambda x: x*2, range(10))))
{0, 2, 4, 6, 8, 10, 12, 14, 16, 18}

>>> print(set(filter(lambda x: x % 2, range(10))))
{1, 9, 3, 5, 7}

map()

map()とは、リストの要素に演算を適用してくれる関数。

map(func, iterable, ...)

第2引数以降のiterableを順にfuncに渡した結果をyieldで返す(generator)。
引数iteratbleは第1引数の関数の引数に順に渡される。

基本的な使い方としては、以下のように各要素の2乗されたリストを生成などがある。

>>> def square(x):
...     return x * x
...

>>> map(square, range(1, 10))
<map at 0x7f474ad63e80>

>>> list(map(square, range(1, 10)))
[1, 4, 9, 16, 25, 36, 49, 64, 81]

ラムダ式を用いれば、1行で同様の結果を得ることができる。

>>> map(lambda x: x*x, range(1, 10))
<map at 0x7f474ad67128>

>>> list(map(lambda x: x*x, range(1, 10)))
[1, 4, 9, 16, 25, 36, 49, 64, 81]

内包記法を使えば、直接リストを生成することができる。

>>> [x*x for x in range(1, 10)]
[1, 4, 9, 16, 25, 36, 49, 64, 81]

filter()

filter()とは、リストの要素を抽出してくれる関数。

filter(func, iterable)

iterableのオブジェクトを順にfuncに渡し、funcがTrueで返したオブジェクトをieldで返す(generator)。

>>> def is_mod(x):
...     return x % 3 == 1
...

基本的な使い方としては、以下のように各要素の3で割ったときに1余る要素のリストを生成などがある。

>>> filter(is_mod, range(1 ,10))
<filter at 0x7f474ad77f28>

>>> list(filter(is_mod, range(1 ,10)))
[1, 4, 7]

ラムダ式を用いれば、1行で同様の結果を得ることができる。

>>> filter(lambda x:x % 3 == 1, range(1, 10))
<filter at 0x7f474ad7d400>

>>> list(filter(lambda x:x % 3 == 1, range(1, 10)))
[1, 4, 7]

内包記法を使えば、直接リストを生成することができる。

>>> [x for x in range(1 ,10) if x % 3 == 1]
[1, 4, 7]

filter() と map()の組み合わせ

リストの要素を抽出して演算を適用する。
例えば、3で割ったとき余りが1になる要素を取得して、取得した各要素を2倍するとする。
通常の通りにやろうとすると、以下の通りになる。

>>> result = []

>>> for x in range(1, 10):
...     if x % 3 == 1:
...         result += [x * 2]
... print(result)
...
[2, 8, 14]

filter()、map()を用いて書くと、以下のようになる。

>>> map(lambda x: x * 2, filter(lambda x: x % 3 == 1, range(1, 10)))
 <map at 0x7f474ad772e8>

>>> list(map(lambda x: x * 2, filter(lambda x: x % 3 == 1, range(1, 10))))
[2, 8, 14]

内包記法を使ってのリスト生成は以下の通り。

>>> [x * 2 for x in range(1, 10) if x % 3 == 1]
[2, 8, 14]

最後に

今回のネタは以下のサイトを参考にしました。

特に「何気にPythonでつかっていた関数型プログラミング技法いろいろ」の情報は2系ではよくまとまっていると思う。
reduce()についてもどっかのタイミングで調べておきたいなと思った。

Pythonでの日付の扱い

自分用に忘れないためのメモを残す。

基本パターン1

>>> import datetime
# 日付の格納
>>> day = datetime.date(2016, 2, 22)
# 1日進める
>>> print(day + datetime.timedelta(days=1))
2016-02-23
# 1日戻す
>>> print(day - datetime.timedelta(days=1))
2016-02-21

基本パターン2

>>> now = datetime.datetime.now()

>>> print(now)
2016-02-22 23:36:57.814567
# 1時間戻す
>>> print(now - datetime.timedelta(hours = 1))
2016-02-22 22:36:57.814567
# 1分戻す
>>> print(now - datetime.timedelta(minutes = 1))
2016-02-22 23:35:57.814567
# 1秒戻す
>>> print(now - datetime.timedelta(seconds = 1))
2016-02-22 23:36:56.814567

宿題

月単位での操作、年単位での操作をする方法がわからないので、追って調査する。

Python3で文字列リストの変換をmapでしようとしたらハマった件について

したいこと

文字列

a1 = ['0', '12.2','23']

[0.0, 12.2, 23.0]

と、リストの要素を文字列からfloatへ変換して出力させたい。

Python2.X系だと、以下で求めたいListが出力される。

>>> a1_str = map(float,a)

しかし、Python3.4.3で実行するとmapオブジェクトが返される。
よって、以下のようにリスト化すればよい…とはいかない。1回イテレートすると消えてしまう仕様のため、2回目にイテレートすると空になってしまう。

>>> a1_list = list(a1_str)
>>> print(a1_list)
[]

それを回避する方法として、内包表記を用いて一発でリスト化する方法を用いる。

>>> a1_list = [float(i) for i in a1]

もうちょい

では逆は?

リストの要素をintから文字列に変換したいとする。

>>> a2 = [1, 2, 3]
>>> [str(i) for i in a2]
['1', '2', '3']

ちょっとした応用

以下の文字列

a3 = '10 20 30'

から、以下のint型のリスト

[10, 20, 30]

を生成したい。
これは、

[int(i) for i in a3.split(' ')]

により生成可能。

IPython notebookのリモート接続に関する件について

はじめに

IPython notebookは便利っぽい。
なので、CentOSサーバにいれて、みんなでつつけるように出来たらもっと便利だろうと。
デフォルトだとリモート接続できるように設定せにゃあかんいうことで、その設定について備忘録を簡単に残す。

目標

簡単にするため、ログインパスワードを知っている人間がつつければOKってコトにする。
細かい設定を行いたい場合は、以下を参照。

http://jupyter-notebook.readthedocs.org/en/latest/public_server.html

導入前提

  • CentOS7
  • Python3.4
  • pip3で以下が導入済みであること
    • numpy
    • scipy
    • pandas
    • matplotlib
    • scikit-learn
    • IPython notebook

導入

設定

IPythonを起動して、IPython notebookにログインするときのパスワードを設定する。
ハッシュ化されたパスワードが表示されるのでコピーしておく。

# ipython

In [1]: from notebook.auth import passwd

In [2]: passwd()
Enter password:【ログインパスワード】
Verify password:【ログインパスワード】
Out[2]: 'sha1:【ハッシュ化されたログインパスワード】'

IPythonを終了して、jupyter_notebook_config.pyを編集する。

# vi ~/.jupyter/jupyter_notebook_config.py

jupyter_notebook_config.pyの内容は以下の通り。

c = get_config()

# matplotlibで描画したものがnotebook上で表示できるようにする
c.IPKernelApp.pylab = 'inline'
# 全てのIPから接続を許可
c.NotebookApp.ip = '*'
# IPython notebookのログインパスワード
c.NotebookApp.password = 'sha1:【ハッシュ化されたログインパスワード】'
# 起動時にブラウザを起動させるかの設定(デフォルトは起動させる)
c.NotebookApp.open_browser = False
# ポート指定(デフォルトは8888)
c.NotebookApp.port = 【接続ポート】

接続検証

IPython notebookを起動させる。

# ipython notebook

そして、外部の端末のブラウザよりhttp://【リモートサーバ】:【接続ポート】/treeで接続する。
するとパスワードを聞かれるので、【ログインパスワード】を入力して、ログインする。

これで、リモートからIPython notebookを使うことが出来るようになる。

new -> Notebooks Python 3をクリックし、新規ノートブックを開き、以下の通りに入力を進める。

In [1]: pylab inline --no-import-all
        Populating the interactive namespace from numpy and matplotlib
In [2]: x = np.arange(-10, 10, 0.1)
In [3]: y = np.sin(x)
In [4]: plt.plot(x, y)
Out[4]: [<matplotlib.lines.Line2D at 0x7fef3e2e2d68>]

入力したら、以下の画像のようなsin(x)の絵が出力されることを確認する。

f:id:hiroto1979:20160201011812p:plain

コンソールより、Ctrl-Cでサーバをシャットダウンする。

これでたぶん一通りの基本的なものは使えるようになるだろう。

VirtualBoxが正常に動作しなかった件について

MacTypeをインストールしていると、上手に使えないときがあるの備忘録。
そのときはMacTypeを起動し、「プロセスマネージャー」より、以下のプロセスを右クリックから『このプロセスを除外する』を選択する。

これでOK。