Remrinのpython攻略日記

python3に入門しました。python3についてあれこれとサンプルコードとか。

map(), filter()

pythonのmap(), filter()の使い方について。
 

map()

Definition : map(func, *iterables)
リストなどの全要素に関数を適用し、イテレータを作る。
もとのリストは保存され、非破壊的。
mapオブジェクトを生成するので、中身を見たければlist化など。

list1 = [1.7, 5.9, -3.68]
m = map(int, list1)
print(m)            # <map object at 0x...>
print(list(m))      # [1, 5, -3]

 
mapのかわりに内包表記でも書ける

list1 = [1.7, 5.9, -3.68]
print([int(i) for i in list1])  # [1, 5, -3]

 
mapオブジェクトはイテレータ

list1 = [1.7, 5.9, -3.68]
m = map(int, list1)
print(next(m))     #  1 
print(next(m))     #  5
print(next(m))     # -3

 
lambda関数も使える

m = map(lambda x:x**2, range(4))
print(list(m))        # [0, 1, 4, 9]

 
map()を使って相関係数を計算する
公式:
f:id:rare_Remrin:20170505165448p:plain

# correlation coefficient
def corr(x, y):
    if len(x) != len(y):
        return "different length"
    sx = sum(x)
    sy = sum(y)
    sx2 = sum(map(lambda x:x**2, x))
    sy2 = sum(map(lambda x:x**2, y))
    sxy = sum(map((lambda x, y:x*y), x, y))
    n = len(x)
    try:
        return (n*sxy-sx*sy)/((n*sx2-sx**2)*(n*sy2-sy**2))**0.5
    except:
        return 0
    
x = [1, 2, 3]
y = [5, 5, 6]
print("相関係数:", corr(x, y)) # 相関係数: 0.8660254037844387

 

filter()

Definition : filter(function or None, iterable)
リストなどの全要素に関数を適用し、Trueのものだけのイテレータを作る。
もとのリストは保存され、非破壊的。
filterオブジェクトを生成するので、中身を見たければlist化など。
 
正の要素だけ選ぶ

list1 = [1.7, 5.9, -3.68]
f = filter(lambda x:x>0, list1)
print(list(f))   # [1.7, 5.9]

 
内包表記でも書ける

list1 = [1.7, 5.9, -3.68]
f = filter(lambda x:x>0, list1)
print(list(f))   # [1.7, 5.9]

 
関数をNoneにすると、Trueのものだけを選ぶ。

f = filter(None, range(4))
print(f)        # <filter object at 0x...>
print(list(f))  # [1, 2, 3]

 
filter()とは逆に偽の要素を選ぶ関数としてitertools.filterfalse()がある。

バーンスレイのシダ

○バーンスレイのシダ
 
4種類の変換をそれぞれ、85%、7%、7%、1%の確率で選んでいきます。

# -*- coding: utf-8 -*-

import numpy as np
import matplotlib.pyplot as plt

def transform1(p):
    x, y = p[0], p[1]
    x1 = 0.85*x + 0.04*y
    y1 = -0.04*x + 0.85*y + 1.6
    return x1, y1

def transform2(p):
    x, y = p[0], p[1]
    x1 = 0.2*x - 0.26*y
    y1 = 0.23*x + 0.22*y + 1.6
    return x1, y1
    
def transform3(p):
    x, y = p[0], p[1]
    x1 = -0.15*x + 0.28*y
    y1 = 0.26*x + 0.24*y + 0.44
    return x1, y1

def transform4(p):
    y = p[1]
    x1 = 0
    y1 = 0.16*y
    return x1, y1    

def transform(p):
    transforms =[transform1, transform2, transform3, transform4]
    # 0~3の中から、85%, 7%, 7%, 1%の重みでインデックスを選ぶ
    index = np.random.choice([0, 1, 2, 3], p=probability)
    t = transforms[index]
    x, y = t(p)
    return x, y

def draw(n):
    x, y = [0], [0]    # x、yはn個の要素を持つリストになる
    x1, y1 = 0, 0      # 現在の座標
    for i in range(n):
        x1, y1 = transform((x1, y1))
        x.append(x1)
        y.append(y1)
    return x, y

n = 1000  # 点の数
# 85%, 7%, 7%, 1%
probability = [0.85, 0.07, 0.07, 0.01] # 合計が1.00
x, y = draw(n)
plt.plot(x, y, "o", c="g", markeredgecolor="darkgreen")
plt.title("Fern with {} points".format(n))
plt.show()

 
n=1000として、1000個の点で描いたシダ
f:id:rare_Remrin:20170506224334p:plain
 
n=8000として、8000個の点で描いたシダ
f:id:rare_Remrin:20170506224421p:plain
 
参考:
Pythonからはじめる数学入門 Amit Saha

matplotlibでアニメーション

matplotlibでアニメーションを作ります。
  

# -*- coding: utf-8 -*-

import matplotlib.pyplot as plt
import matplotlib.animation as ani

def create_circle():
    c1 = plt.Circle((0, 0), 0.5)
    return c1

def update_radius(i, c1):  # i:フレーム番号
    plt.cla()
    c1.radius = i*0.5      # 最大半径15
    return c1,

def create_animation():
    fig = plt.gcf()
    ax = plt.axes(xlim=(-10, 10), ylim=(-10, 10))
    ax.set_aspect("equal")
    c1 = create_circle()
    ax.add_patch(c1)
    anim = ani.FuncAnimation(fig, update_radius, 
                        fargs=(c1,), frames=30, interval=50)
    anim.save("circle.gif", writer = 'imagemagick')
create_animation()

 
円が徐々に大きくなるアニメーションになるはずが、
ValueError: Cannot save animation: no writers are available. Please install ffmpeg to save animations.
というエラーが出てうまくいきませんでした。
imagemagickをダウンロードして、matplotlibrcのanimation convert pathを
#animation.convert_path: C:\py3531\pytemp\ImageMagick-7.0.5-5-portable-Q16-x86\magick.exeとしましたが認識せず。
また時間のある時にでも調べてみます。
  
 

matplotlibで図形

matplotlibで図形を描く方法。
 
plot()関数が呼ばれると背後でfigure()が呼ばれ、続いてaxes()が呼ばれてfigureの中に軸をつくる。
plot()関数を呼ばずにfigure()やaxes()で図、軸を設定できる。
 

import matplotlib.pyplot as plt

c1 = plt.Circle((0, 0), radius=1, fc="yellow", ec="r")
ax = plt.gca()
ax.add_patch(c1)
plt.axis("scaled")
plt.show()

 
f:id:rare_Remrin:20170506162014p:plain
 
○figure()関数
Figureオブジェクトを作る。
Definition :

figure(num=None,           # autoincrement if None, else integer from 1-N 
       figsize=None,       # defaults to rc figure.figsize 
       dpi=None,           # defaults to rc figure.dpi 
       facecolor=None,     # defaults to rc figure.facecolor 
       edgecolor=None,     # defaults to rc figure.edgecolor 
       frameon=True, 
       FigureClass=Figure, 
       **kwargs)

 

num figure番号。整数または文字列のオプション引数でデフォルトはNone。もしnumが与えられなければ、新しいfigureを作り、figure番号を1増やす。figureオブジェクトはこの番号をnumber属性として保持する。もしnumが与えられ、すでに存在しているfigure番号だった場合は、そのfigureオブジェクトをアクティブにし、参照を返す。存在しないfigure番号のときは、新規のfigureオブジェクトを作成し、その参照を返す。numが文字列のときはウィンドウのタイトルがnumになる。
figsize (幅, 高さ)の整数のタプルで単位はインチ。デフォルトはrc figure.figsize
dpi figureの解像度。整数で、デフォルトははrc figure.dpi
facecolor 背景色。デフォルトはrc figure.facecolor
edgecolor 枠の色。デフォルトはrc figure.edgecolor

 

返り値 figureオブジェクト

 
○axes()関数
 Figureオブジェクトに座標軸を付け加える

parameter 内容
facecolor color 軸の背景色
frameon True or False 枠を表示するか
sharex otherax 他の軸とxaxis属性を共有するか
sharey otherax 他の軸とyaxis属性を共有するか
polar True, False 極座標を使うか
aspect "equal", "auto", num アスペクト比x/y。"equal"は1:1

 
○axis()メソッド
素数4のタプルを引数としてaxis()メソッドを呼ぶと、座標軸の範囲を変更できる。

引数 内容
なし 現在の座標軸の範囲を(xmin, xmax, ymin, ymax)のタプルで返す。
"off" 座標軸を表示しない
"equal" 円が円に見える。
"scaled" 座上軸の両端の自動調整
"tight" 余白を小さく?
"image" データの範囲に合わせる
"auto" 非推奨
"normal" 非推奨
"square" x軸の範囲(xmax-xmin)とy軸の範囲を等しくする

 

fig = plt.figure()
ax =plt.axes()
print(plt.axis())   # (0.0, 1.0, 0.0, 1.0)

v = (0, 2, 0, 3)
plt.axis(v)
plt.show()

 
x軸の範囲が0~2、y軸の範囲が0~3になっている。
f:id:rare_Remrin:20170506155223p:plain

gcf()関数:現在のFifureへの参照。オブジェクトがない場合は作成する。
gca()関数:現在のAxesへの参照。オブジェクトがない場合は作成する。
 
○ax.set_aspect()関数
 グラフのアスペクト比を設定する。

○円plt.Circle以外にもいろいろな図形が書ける。
 Ellipse, Polygon, Rectangleなどなど
 
参考:
patches — Matplotlib 2.0.1 documentation

csvライブラリ

csvモジュールの使い方について。
 
以下の内容のtest.csvを準備しました。

1,20
2,30
3,40
4,50

 
csvファイルの読み取り
(1)各行はリストとして読み込まれる。

import csv

with open("test.csv", "r") as f:
    data = csv.reader(f)
    print(data)  <_csv.reader object at 0x...>
    for i in data:  # 各行がリストになっている
        print(i)
# ['1', '20']
# ['2', '30']
# ['3', '40']
# ['4', '50']

 
(2)joinで見やすく。

with open("test.csv", "r") as f:
    data = csv.reader(f)
    print(data)
    for i in data:
        print(", ".join(i))
# 1, 20
# 2, 30
# 3, 40
# 4, 50

csv.reader()の引数になるのは、ファイルオブジェクトまたはリスト
 
(3)読み飛ばしたい行があるときはnext()する。

with open("test.csv", "r") as f:
    data = csv.reader(f)
    next(data)                    # 1行読み飛ばす
    for i in data:
        print(", ".join(i))       # 2, 30
                                  # 3, 40
                                  # 4, 50  

 
(4)読み飛ばす行をヘッダーなどとして使用するときは代入をしておく。

with open("test.csv", "r") as f:
    data = csv.reader(f)
    header = next(data)        # 1行読み飛ばし、headerに代入
    print(header)              # ['1', '20']
    for i in data:
        print(", ".join(i))    # 2, 30
                               # 3, 40
                               # 4, 50  

 
csvファイルの書き込み
newline=""とオプションを入れないと、空白行が追加されてしまう。
(1)

import csv
with open('test.csv', 'w', newline="") as f:
    writer = csv.writer(f)
    writer.writerow([1] + [20])
    writer.writerow([2, 30])
    for i in range(3, 5):
        writer.writerow([i, (i + 1) * 10])

 
(2)

data =[[1, 20], 
       [2, 30], 
       [3, 40],
       [4, 50]]
with open('test.csv', 'w', newline="") as f:
    writer = csv.writer(f)
    writer.writerows(data)

 
参考:
14.1. csv — CSV ファイルの読み書き — Python 3.6.1 ドキュメント

matplotlibの色名一覧

matplotlibの色名一覧
 
f:id:rare_Remrin:20170505171728p:plain
 

この色名一覧はpythonで書かれていて、同じページにコードも載っています。
あとでゆっくりコードを読んでみようと思います。
 

# coding: utf-8

from __future__ import division

import matplotlib.pyplot as plt
from matplotlib import colors as mcolors

colors = dict(mcolors.BASE_COLORS, **mcolors.CSS4_COLORS)

# (HSV形式,色名)というタプルに直し、Hをキーにしてソートしたリストにする
by_hsv = sorted((tuple(mcolors.rgb_to_hsv(mcolors.to_rgba(color)[:3])), name)
                for name, color in colors.items())
# sortしたタプルのリストから、色名だけを抜き出したリストを作る
sorted_names = [name for hsv, name in by_hsv]


n = len(sorted_names)   # 8色 + 148色 = 全156色
ncols = 4               # 列数を4にする。他の数でもよい
nrows = n // ncols + 1  # 行数を計算

fig, ax = plt.subplots(figsize=(8, 5)) # 横8インチ、縦5インチ

# Get height and width
X, Y = fig.get_dpi() * fig.get_size_inches()
h = Y / (nrows + 1)   # 1マスの縦のドット数
w = X / ncols         # 1マスの横のドット数

for i, name in enumerate(sorted_names):
    col = i % ncols            # 0番 1番 2番 3番
    row = i // ncols           # 4番 5番 6番 7番 ...のように割り振る
    y = Y - (row * h) - h      # 表示するy座標

    xi_line = w * (col + 0.05) # 長方形の左端のx座標
    xf_line = w * (col + 0.25) # 長方形の右端のx座標
    xi_text = w * (col + 0.3)  # 色名の文字列を表示するx座標

    # 左よせで文字を表示
    ax.text(xi_text, y, name, fontsize=(h * 0.8),
            horizontalalignment='left',
            verticalalignment='center')
    # hlines(横向きの直線)として色つきの長方形を表示
    ax.hlines(y + h * 0.1, xi_line, xf_line,
              color=colors[name], linewidth=(h * 0.6))

ax.set_xlim(0, X)
ax.set_ylim(0, Y)
ax.set_axis_off()

fig.subplots_adjust(left=0, right=1,
                    top=1, bottom=0,
                    hspace=0, wspace=0)
plt.show()

わからないことが多すぎるので、いろいろ確認してみた。
・mcolors.BASE_COLORS : 
 8つの基本色。アルファベット1文字で表す。
 色名:RGBの辞書型になっている。 

print(mcolors.BASE_COLORS)
# {'y': (0.75, 0.75, 0), 'm': (0.75, 0, 0.75), 'r': (1, 0, 0), 
#  'c': (0, 0.75, 0.75), 'k': (0, 0, 0), 'g': (0, 0.5, 0), 
#  'w': (1, 1, 1), 'b': (0, 0, 1)}

 
・mcolors.CSS4_COLORS
 148色の(色名:16進コード)の辞書型

print(len(mcolors.CSS4_COLORS))
# 148

print(mcolors.CSS4_COLORS)
# {'oldlace': '#FDF5E6', 'limegreen': '#32CD32', 'palevioletred': '#DB7093',
# 'mintcream': '#F5FFFA', 'rosybrown': '#BC8F8F', 'blueviolet': '#8A2BE2', 
# 'lime': '#00FF00', 'orange': '#FFA500', 'mediumorchid': '#BA55D3', ...

 
参考:
color example code: named_colors.py — Matplotlib 2.0.1 documentation

matplotlibで散布図

matplotlibで散布図を描く方法について。
 
Definition :

plt.scatter(
        x, y,                 # x座標, y座標の配列
        s=None,               # マーカーのサイズ
        c=None,               # マーカーの色
        marker=None,          # マーカーの形
        cmap=None,            # cがfloat型のときのカラーマップ
        norm=None,            # cをfloat型配列にした時の規格化インスタンス指定
        vmin=None, vmax=None, # 最大・最小
        alpha=None,           # 透明度
        linewidths=None,      # 線の太さ
        verts=None, 
        edgecolors=None,      # 線の色
        hold=None, 
        data=None, 
        **kwargs)

色名一覧はここ
 
 
・乱数で100個の点を描く

import numpy as np
import matplotlib.pyplot as plt

x = np.random.rand(100)
y = np.random.rand(100)
plt.scatter(x, y)
plt.show()

 
f:id:rare_Remrin:20170505153640p:plain
  
・マーカーをひし形にして、色を付ける。

x = np.random.rand(100)
y = np.random.rand(100)
plt.scatter(x, y, s=100, c="orange", edgecolor="red")
plt.show()

 
f:id:rare_Remrin:20170505153737p:plain 
 
・直線、軸、タイトルつき。

import numpy as np
import matplotlib.pyplot as plt
#日本語を使う場合は以下の2行でフォントを準備
from matplotlib.font_manager import FontProperties
fp = FontProperties(fname='C:\WINDOWS\Fonts\msgothic.ttc', size=14)

x = np.arange(20)
y = x + np.random.rand(20)*4 
plt.scatter(x, y, s=50, marker="x", c="red", linewidth=1)
plt.plot([0, 19], [2, 21], c="blue")  #直線の描画
plt.title("散布図", fontproperties=fp)
plt.xlabel("x軸", fontproperties=fp)
plt.ylabel("y軸", fontproperties=fp)
plt.show()

 
f:id:rare_Remrin:20170505153934p:plain 
 

chars = "^<>vo+d"
x = np.random.rand(100)
y = np.random.rand(100)
markers = [chars[i%7] for i in range(100)]
for i in range(100):
    plt.scatter(x[i], y[i], marker=markers[i])
plt.show()

f:id:rare_Remrin:20170526175130p:plain
 

x = np.random.rand(10000)
y = np.random.randn(10000)
plt.scatter(x, y, alpha=0.2)
plt.show()

f:id:rare_Remrin:20170526175210p:plain
 

x = np.random.randn(10000)
y = np.random.randn(10000)
plt.scatter(x, y, alpha=0.2)
plt.show()

f:id:rare_Remrin:20170526175252p:plain
 

カラーマップを使う。

x = np.random.rand(100)
y = np.random.rand(100)
col = np.linspace(0, 1, 100)
plt.scatter(x, y, c=col, cmap="spring")
plt.colorbar()  #カラーバーの表示
plt.show()

 
f:id:rare_Remrin:20170505154033p:plain 
 
カラーマップの一覧はここに。
 
参考:

Python でデータサイエンス