どこかに向かうらしい話

迷走エンジニアの放浪記

Python3におけるformat形式を自分のためにまとめてみた件

主なネタはココにある通り。
http://docs.python.jp/3.5/library/string.html#formatspec

自分がよく使うパターンに絞ってメモしてみる。

>>> printf("hoge")
hoge(改行あり)
>>> print("hoge", end="")
hoge(改行なし)

ポジション引数を使ったアクセス:

>>> '{0}, {1}, {2}'.format('a', 'b', 'c')
'a, b, c'
>>> '{2}, {1}, {0}'.format('a', 'b', 'c')
'c, b, a'
>>> '{0} {1} {0}'.format('abra', 'cad')   # 引数のインデクスは繰り返すことができます
'abra cad abra'

引数の要素へのアクセス:

>>> coord = (3, 5)
>>> 'X: {0[0]};  Y: {0[1]}'.format(coord)
'X: 3;  Y: 5'

テキストの幅を指定した整列:

>>> '{:<30}'.format('left aligned')
'left aligned                  '
>>> '{:>30}'.format('right aligned')
'                 right aligned'
>>> '{:^30}'.format('centered')
'           centered           '
>>> '{:*^30}'.format('centered')  # 詰め文字に '*' を使う
'***********centered***********'

%+f と %-f, % f の置換、そして符号の指定:

>>> '{:+f}; {:+f}'.format(3.14, -3.14)  # 常に表示する
'+3.140000; -3.140000'
>>> '{:f}; {:f}'.format(3.14, -3.14)  # 正の数にはスペースを表示
'3.140000; -3.140000'
>>> '{:-f}; {:-f}'.format(3.14, -3.14)  # マイナスだけを表示 -- '{:f}; {:f}' と同じ
'3.140000; -3.140000'

dによる指定:

>>> print("{0:d}".format(123))
123
>>> print("{0:+d}".format(123))
+123
>>> print("{0:04d}".format(123))
0123
>>> print("{0:+04d}".format(123))
+123
>>> print("{0:06d}".format(123))
000123
>>> print("{0:+06d}".format(123))
+00123

固定小数点の出力に関する指定:

標準では以下の通り。

>>> print("{0:f}".format(12.3456))
12.345600

小数点の位置に注目。

>>> print("{0:.1f}".format(12.3456))
12.3
>>> print("{0:.2f}".format(12.3456))
12.35
>>> print("{0:.3f}".format(12.3456))
12.346
>>> print("{0:.4f}".format(12.3456))
12.3456
>>> print("{0:.5f}".format(12.3456))
12.34560

小数点と表示させる桁数の比較。 x.yfは、小数点y桁だけ必ず表示しつつ、x文字分の表示領域に収めるように出力される。 (小数点も1文字としてカウントする)
ただし、出力対象がx文字分の表示領域に収まらない場合は、その分はオーバーして出力される。

>>> print("{0:3.1f}".format(12.3456))      # 小数点1桁必ず表示しつつ、3文字分の表示領域に収めるように出力されるが、表示領域に収まらないため、その分はオーバーして出力される。
12.3
>>> print("{0:4.1f}".format(12.3456))      # 小数点1桁必ず表示しつつ、4文字分の表示領域に収めるように出力される。
12.3
>>> print("{0:5.1f}".format(12.3456))      # 小数点1桁必ず表示しつつ、5文字分の表示領域に収めるように出力される。
 12.3
>>> print("{0:6.1f}".format(12.3456))      # 小数点1桁必ず表示しつつ、6文字分の表示領域に収めるように出力される。
  12.3
>>> print("{0:4.2f}".format(12.3456))      # 小数点2桁必ず表示しつつ、4文字分の表示領域に収めるように出力されるが、表示領域に収まらないため、その分はオーバーして出力される。
12.35
>>> print("{0:5.2f}".format(12.3456))      # 小数点2桁必ず表示しつつ、5文字分の表示領域に収めるように出力される。
12.35
>>> print("{0:6.2f}".format(12.3456))      # 小数点2桁必ず表示しつつ、6文字分の表示領域に収めるように出力される。
 12.35
>>> print("{0:7.2f}".format(12345.6789))   # 小数点2桁必ず表示しつつ、7文字分の表示領域に収めるように出力されるが、表示領域に収まらないため、その分はオーバーして出力される。
12345.68
>>> print("{0:8.2f}".format(12345.6789))   # 小数点2桁必ず表示しつつ、8文字分の表示領域に収めるように出力される。
12345.68
>>> print("{0:9.2f}".format(12345.6789))   # 小数点2桁必ず表示しつつ、9文字分の表示領域に収めるように出力される。
 12345.68

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でサーバをシャットダウンする。

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