Python3.6.3チュートリアル写経20171111

4.7.6 ドキュメンテーション文字列~5.1.3 リストの内包表記 をやった。

以下メモ。

  • リストはappendとpopにより、スタック(LIFO)として使える
  • キュー(FIFO)としては、collectionsモジュールからdequeueをimportして以下のように使う
In [15]: from collections import deque

In [16]: queue = deque(["Eric", "John", "Michael"])

In [17]: queue
Out[17]: deque(['Eric', 'John', 'Michael'])

In [18]: queue.append("Terry")

In [19]: queue
Out[19]: deque(['Eric', 'John', 'Michael', 'Terry'])

In [20]: queue.append("Graham")

In [21]: queue
Out[21]: deque(['Eric', 'John', 'Michael', 'Terry', 'Graham'])

In [22]: queue.popleft()
Out[22]: 'Eric'

In [23]: queue
Out[23]: deque(['John', 'Michael', 'Terry', 'Graham'])

In [24]: queue.popleft()
Out[24]: 'John'

In [25]: queue
Out[25]: deque(['Michael', 'Terry', 'Graham'])
  • リスト内包表記では、mapやfilterが表現できる(mapは先頭の式で表し、filterはforの後ろのifで表す)
  • 数学的には、以下のIn [44]のように書けるとうれしいが、inの後ろに定義されていない変数を書くことはできない
In [42]: vec = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

In [43]: [num for elem in vec for num in elem]
Out[43]: [1, 2, 3, 4, 5, 6, 7, 8, 9]

In [44]: [num for num in elem for elem in vec]
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-44-805eb91a5d03> in <module>()
----> 1 [num for num in elem for elem in vec]

NameError: name 'elem' is not defined

Python3.6.3チュートリアル写経20171106

4.7.2 キーワード引数~4.7.5 ラムダ式をやった。

以下メモ

  • 下記のような関数が書ける(argumentsは可変長引数、keywordsは可変長キーワード引数)
def cheeseshop(kind, *arguments, **keywords):
    print("-- Do you have any", kind, "?")
    print("-- I'm sorry, we're all out of", kind)
    for arg in arguments:
        print(arg)
    print("-" * 40)
    for kw in keywords:
        print(kw, ":", keywords[kw])
  • リストをアンパックして関数に引数として渡せる(アンパックとは、リストの要素を前から順番に、仮引数に渡すこと)
def person(name, age):
    print(name, 'is', age, 'years old.')

p = ['taro', 20]
person(*p) # アンパック
  • 辞書をアンパックして関数に引数として渡せる(このときは、キーワードを指定して引数をに値を渡していると考えられる)
def person(name, age):
    print(name, 'is', age, 'years old.')

p = {'name': 'taro', 'age': 20}
person(**p) # アンパック
# タプルのリストをタプルの2番目でソート
a = [(1, 'kuma'), (2, 'neko'), (3, 'inu')]
a.sort(key=lambda pair: pair[1])
a
[(3, 'inu'), (1, 'kuma'), (2, 'neko')]

Python3.6.3チュートリアル写経20171104

Python チュートリアル — Python 3.6.3 ドキュメントを写経してる。 4.7.1 デフォルトの引数値までやった。

以下メモ。

  • PythonのREPLはpythonよりもipythonの方が便利
  • for文にelse節があり、breakするとelse節は実行されない
  • 文字列はイミュータブル
  • リスト、辞書はミュータブル
  • 文字列はシングルクォート'で囲むか、ダブルクォート"で囲むか、ダブルクォート3つで囲む
  • 文字列をシングルクォートで囲むときには、ダブルクォートをエスケープする必要がなくなり、ダブルクォートで囲むときには、シングルクォートをエスケープする必要がなくなる
  • 文字列をダブルクォート3つで囲むとき、文字列内の改行がそのまま改行になる。また、"""に隣接しなければ、ダブルクォートをエスケープしなくても大丈夫っぽい
  • for文内でリストを変更するときには、「for x in my_list[:]:」のようにしてリストをコピーする必要あり
  • デフォルト引数は1回しか評価されなくて、リストや辞書などのイミュータブルなデフォルト引数は、関数呼び出しごとに変化してしまう。

ベイジアンネットワーク

身の回りでベイジアンネットワークなどの言葉をよく聞くようになった。 ベイジアンネットワークは、ビッグデータを解析して、ある現象が発生したときに、何が原因かを確率的に抽出する手法のようだ。

僕としては、このような手法に対して、本当にうまくいくのかな、と少し懐疑的だ。 原因を抽出するときに、プログラムは、おそらく、原因A1、原因A2、…、原因ANに対して、確率分布を出力するのだろう。 ところが、これらの原因の集合そのものは、人間があらかじめ用意してあげる必要があるのではないか。

また、この手法では、原因をノードとするネットワークを作るらしいのだが、ネットワーク構造を決めるアルゴリズムがあるらしい。

懐疑的でありつつも、わからないことばかりで、興味がわいてくる。

Haskellで凸包を求めるGraham Scanアルゴリズムを実装する

夏休みなので、Haskellのリハビリのために、「Real World Haskell」を読んでいます。 3章の練習問題に、平面上の点の集合の凸包を求めるGraham scanアルゴリズムを求めよ、という問題があります。

Graham scan - Wikipedia

以下のように書きました。まだ、あまりテストしていません。 この本でQuick Checkを学んでテストしてみようと思います。

import Data.List

data Point2D = Point2D { x::Int, y::Int } deriving (Eq, Show)
data Direction = CounterClockWise | ClockWise | Collinier deriving (Eq, Show)

-- 線分abの延長線上に点cがあるならば、Collinier
-- 線分abの延長線の左側に点cがあるならば、CounterClockWise
-- 線分abの延長線の右側に点cがあるならば、ClockWise
-- ベクトルabとベクトルbcの外積のz座標の符号で上記を判定する
direction :: Point2D -> Point2D ->Point2D -> Direction
direction a b c
    | crossProductZ > 0 = CounterClockWise
    | crossProductZ < 0 = ClockWise
    | otherwise = Collinier
    where
        crossProductZ = abx * bcy - aby * bcx
            where
               abx = (x b) - (x a)
               aby = (y b) - (y a)
               bcx = (x c) - (x b)
               bcy = (y c) - (y b)

-- 平面上の点の集合の凸包をGraham Scanアルゴリズムで求める
convexHull :: [Point2D] -> [Point2D]
convexHull xs = convexHullSub ys
    where
        ys = [p] ++ sortForGrahamScan p pRemoved ++ [p]
            where
                p = startPoint xs
                pRemoved = filter (\x->x/=p) xs

convexHullSub :: [Point2D] -> [Point2D]
convexHullSub (a:b:c:xs)
    | direction a b c == CounterClockWise = a:(convexHullSub (b:c:xs))
    | otherwise = convexHullSub (a:c:xs)
convexHullSub xs = xs

-- 平面上の点をソートする
-- 点pとソートする点を通る直線とx軸の成す角度の昇順でソートする
sortForGrahamScan :: Point2D -> [Point2D] -> [Point2D]
sortForGrahamScan p xs = sortBy compareAngle xs
    where
        compareAngle a b
            | cosVal a < cosVal b = GT
            | otherwise = LT
            where
                cosVal point = (fromIntegral pointX) / sqrt (fromIntegral (pointX * pointX + pointY * pointY))
                    where
                        pointX = (x point) - (x p)
                        pointY = (y point) - (y p)

-- 点pを求める
-- 点pはy座標が最小の点の中で、x座標が最小の点である
startPoint :: [Point2D] -> Point2D
startPoint xs = head (sortByCoordinates xs)
    where
        sortByCoordinates = sortBy compareXY
            where
                compareXY a b
                    | (y a) < (y b) = LT
                    | (y a) > (y b) = GT
                    | (x a) < (x b) = LT
                    | otherwise = GT