プログラミング

概要

  • つらいけどpython3の勉強
  • 最近流行ってるので習得しなければならない…
  • pythonは言語を作る気で行かないと死ぬ

下位ページ

目次

まとめるべきこと

collection系 https://docs.python.org/2/library/datatypes.html 調べたいもの:heap, bisect, setsとsetのちがい、ordered set, queueとstack, priority_queue, repr, Pythonのordered dict まんまOrderedDict?という名前のcollectionがある http://azunobu.hatenablog.com/entry/2015/05/01/115413 お手軽構造体namedTuple http://sucrose.hatenablog.com/entry/2014/04/21/000909 dequeがある

pythonには亀グラフィクスという2Dグラフィクスが備わっている http://www.ic.daito.ac.jp/~mizutani/python/using_turtle.html

pythonの二分木 http://www.ic.daito.ac.jp/~mizutani/python/binary_tree.html

type hinting(タイポ) IFは書いた方がいいですね C++以外ですが、私はint,string,list,map,setの関数内変数についてはあまり書かないです PythonのIFにtype hitingするのもありかなって思います(書かない人多いですが) assert isinstance祭りしましょう

pythonの@はデコレータ 処理の前後に、処理を追加する あと数年するといろんな分野の統計で、「AIの予測に従った場合と、プロが独自の判断でAIを無視した場合、前者の方が成績が良い」という結果が出始める。で、プロが「数値で見えない価値」とか「長期的な視点」を主張し出す。広告のアドテクで起きたことが、全業界で起こると思えば想像しやすい

疑問

  • 一般にPythonで変数を出力・ロードする方法ってどうすればいいの?

参考

環境構築

  • 鬼門
sudo apt-get -y install python3-dev
python -V
python3 -V #バージョンを確認。3.5だとする。
sudo apt-get install python3.5-dev #ここのバージョンとして3.5を入れる
sudo apt-get install python3-setuptools
sudo easy_install3 pip
pip -V # pipの場所がpython3になっていることを確認

sudo pip install virtualenv

開発を始める時

  • はじめて
    virtualenv envname
    pip3 install numpy
  • 二回目以降
    . envname/bin/activate
    pip list # envname環境でのパッケージ
  • 開発を終える時
    deactivate

基本は使ってはならないがpip3について

  • グローバルに入れるには、必ず使うバージョンまで指定しないといけない
sudo python3.5 -m pip install numpy

参考

文法

    • セミコロンなし,インデントが文法.
    • 配列はmatlab式.[10, [20, 16], [32, u"太郎"], 18]など.スライス使える(a[1:2], a[:3], a[2:])が、スライス自体がリストにはならない.長さはlen(list),追記はlist.append(hoge).
    • 数値配列の作成はrange(1, 5)など([1, 2, 3, 4])
    • 文字列では、シングルとダブルクオートの区別がない
    • ifに括弧なし.if, elif, elseはすべて行末に:
    • forはmatlab式+行末に:.forのinに文字列は一文字ずつ取得.for, whileのあとにelseを入れることができる
    • コメントは#comment, """comment"""
    • 数字->文字はstr(num).文字→整数はint(str),文字→浮動はfloat(str),数値判定はstr.isdigit()
    • 論理演算子はor, and, not.真偽はTrue, False
    • 関数はdef function_name(arg1, ...):.行末に:が必要
      • *でargs, **でパラメータを渡せる(参照
    • intも含め配列の関数渡しも、「すべて」参照渡し
    • a={}でc++でいうmapになる
      • pythonのdictは存在しないキーを出力しようとするとデフォルトエラーなので、そうじゃなくしたいならgetを使う。
    • printf
      • print aでprintf("%d\n",a);
      • print a,でprintf("%d",a);
    • for-else構文は、break「しなかったとき」に入るスペシャルステージ
    • if 3>a>1<b<5: print(a, b)ができる!
  • ☆☆
    • 空オブジェクトはNone(Noneは予約語)
    • 空白文字削除はstr.strip()
    • Pythonは日本語がクソ
      • 以下を一行目に入れる
        # coding: UTF-8
  • 可変長引数
>>> def func(*a):
...   print a
...
>>> func("a","b","c")
('a', 'b', 'c')
  • pythonのis operator
    • ポインタの一致
    • Immutableなら==と同じだが、リストとかmutableなものではポインタの一致を見るようになる

Pythonの難しさ

  • 結局型を意識しなければいけないなら、型を全て省略する意味は一体どこにあるのだろう
    • 理由: めんどいので(一方コードリーディングつらくない?)
    • データオペレションのみに注力できるから、って思ったけど、少なくともいろい型やなんやらは考えてるので、見た目的に何もないだけで意識は、型から解放されてない

バブルソート

def bubblesort(a):
    for i in range(len(a)-2):
        for j in range(len(a)-1-i):
            if a[j] < a[j+1]:
                tmp = a[j]
                a[j] = a[j+1]
                a[j+1] = tmp



a=[2,4,5,1,2]
bubblesort(a)
for i in range(len(a)):
    print a[i]

代表的なデータ型の操作

型の大まかな特徴

  • pythonでは型が暗黙の了解となっている
    • int, float
    • iterativeな型:list, set(, str)。これらの間は自由に行き来できる(strはちょっと怪しい)
      • strは静的!
    • tuple
      • tupleは静的!(1, 3, 4)[2]などのアクセスが可能。
    • dict
    • ndarray
      • listしか突っ込めない
    • map object
      • このままでは使えないので、list, setに渡してやる必要がある(strはダメ)
  • 変換

型の相互変換

intfloatstrlistsetdictndarray
int=float(n)str(n)[n]{n}{n: m}np.array([n])
floatint(x)=str(x)[x]{x}{f: x}np.array([x])
strint(s), 失敗でRE, int('0.1')はRE。ord(s)でもOKで、ordは1文字以外だとREfloat(s), 失敗でRE=list(s)set(s)xnp.array(list(s))
lista[i]a[i]str(a)は、listのデバッグ出力が文字列として得られる。a: [char]なら"".join(a)、a: [int]なら"".join(list(map(lambda x: chr(x+ord('0')), [0, 3])))=set(a)ts = [(1, 2), (3, 4), (5, 6)]; dict(ts)。同じようにdict(zip(a, b))などが可能(zipはzip objectでlistを返すわけではないが、list(zip(a,b))で同様になる)。キーだけ指定する場合は、marks = {}.fromkeys(['Math','English','Science'], 0)np.array(a)
setfor x in s: print(x)for x in s: print(x)str(s)、setのデバッグ出力が文字列として得られるlist(s)=xnp.array(list(s))
dictd[x], xがなければREd[x], xがなければREstr(d)、dictのデバッグ出力が文字列として得られるlist(d)はdのkeys list。dd.keys()は実はdict_keysという型!ペアで欲しいならlist(zip(d.keys(), d.values()))set(d)はdのkeys set。d.keys()は実はdict_keysという型!=np.array(list(d))
ndarrayv[i]v[i]str(a)でデバッグ出力らしきもの(違う)が出るlist(a)かa.tolist()set(a)x=

二次元配列

  • 変な作り方をすると、参照になって代入が独立じゃなくなる。毎回リスト内包で作成すること!

型ごとに可能な操作

  • str以外全部に対してビルトイン関数: all(), any(), enumerate(), len(), max(), min(), sorted(), sum()などが使える
  • sequence(list, string)には、reversedが使える。
  • sortedはstrを突っ込んでもリストが帰ってくる
サイズ要素追加要素削除反復差分検索ソート逆順
listlen(a)push_backがa.append(x), a.insert(i, x)はiの次にxを挿入するpush_backがa.pop()。a.pop(i)は#iを返して#iを消す。del a[i]で#iを消す。a.remove('a')でaを先頭1個削除(削除できないとRE)[1] * 100なし+, これは.extend(b)と同等なしa.index('x'): xのfirst occurenceを取得a.sort()a.reverse()が可能。reversed(a)でもまあ良い
setlen(s)s.add(x)a.discard(x)がエラー無し。remove(x)はxがないとRE。s.pop()はなんか一個削除して値を返す(順序がない、ハッシュなので)。なしandor。論理排他和は^。包含関係はa <= bs-tx in s, x not in ssetはハッシュなのでソートしてくれない!sorted(s)なし
dictlen(d)d[i] = xd.pop(i)でkeyがiの要素削除して値を返す。d.popitem()で何か一つ削除して値を返す。なしd = {x:d1[x] for x in d1 if x in d2}なしなしd[i]はiがなければRE。d.get(i)はなければNoneを返す。sorted(d)だが、これはキーしかソートしてくれないのでsorted(list(zip(d.keys(), d.values())))なし
strlen(s)s + t, O(len(s)+len(t))不可能s*3なしなしなし'ab' in s''.join(sorted(s))''.list(reversed(s))

list

  • listには.countという出現回数を取得する関数がある

str

  • 静的データ構造!!途中で#iの変更をしたくなっても無理。変更にO(n)かかり、基本的に遅い。Javaみたいな感じ。
  • 対策:動的文字列は、strではなくlistで管理する
  • 'a'+1みたいなことをしたい場合は?めんどいが 
chr(ord(s)+1)
  • したがって+演算子は毎回新たなオブジェクトを生成するので、あまり行儀が良くない
s = s + "新たな文字列1"
s = s + "新たな文字列2"
. . .
とせずに、配列を使って、
L = []
L.append("新たな文字列1")
L.append("新たな文字列2")
. . .
s = ''.join(L)

とするのが定石イディオム
  • split
    • これは便利
    • 複数文字delimiterもできる
>>> 'I have a pen'.split()
['I', 'have', 'a', 'pen']
>>> 'aabbababbabbbb'.split('a')
['', '', 'bb', 'b', 'bb', 'bbbb']
>>> 'aabbababbabbbb'.split('aa')
['', 'bbababbabbbb']
  • 文字列にはupper, lowerという関数がある
  • 小文字リスト
import string
string.ascii_lowercase
‘abcdefghijklmnopqrstuvwxyz’

その他のデータ構造

  • Counter
    • 便利
from collections import Counter
Counter([‘apple’,‘red’,‘apple’,‘red’,‘red’,‘pear’])
Counter({‘red’: 3, ‘apple’: 2, ‘pear’: 1})

ファイル

for line in open("test.txt", "r")
    line.strip()
    print line

正規表現

import re
a = re.search(r'^[a-z]', line)

numpy

Numpy Transposeに同値な Tというメンバ変数らしきものがあるhttps://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.T.html pythonできれいな2次元グラフを書く http://qiita.com/kenmatsu4/items/d282054ddedbd68fecb0 パラメータ分布を{coda}パッケージを使ってプロットするとこんな感じです。

ndarray

  • スライスアクセス
  • ファンシーアクセス
  • 要素アクセス
    import numpy as np
    ndarr = np.array([[1., 2., 3.], [4., 5., 6.], [7., 8., 9.]])
    indices = [1,1]   # row,col
    ndarr[tuple(indices)]

逆引き

  • countしたい場合
np.count_nonzero(v==-1)
  • npでmapしたい場合
np.vecorize(func)(v)
  • 0配列を作る
np.zeros(n)。
  • max, min
max(v), min(v)
  • 条件を満たすインデックス列挙
np.where(a>1)

コーディングイディオム

not a

  • C++のa.empty()はnot aで可能

隠れビルトイン関数

  • pow(x, y[, z])
    • x^y%zの高速実装
    • 競プロのために作られたとしか思えないがRSA暗号で使う
  • sorted(d.items(), reverse=True)
    • 逆順ソートする。
  • all, any
    • iterableの全てTrue、もしくはどれかがTrueでTrue
  • bin(int)
    • 二進数表記する
  • ascii(obj), repr(obj)
    • printで出力される文字列と同じものを返す
  • complex(re, [im])
    • 複素数。文字列を突っ込むことができる。
  • divmod(a, b)
    • 商と余りのtuple。divmod(10.2, 3)=(3.0, 1.1999999999999)
  • int(str, [base=10])
    • a = int('1000', base=3)で81になる
  • 普通のint型n
    • 普通にC++と同じようなbit操作が可能。n & (1 << 4)
    • n.bit_length()は二進数桁数。log2と同じ。
  • 普通のfloat型x
    • x.is_integer()は整数かを雑に判定する。if abs(x - int(x)) < 1e-6:とかしなくて良くなる
  • str
    • countという部分文字列のカウントがある。 'abcabcbcbc'.count('bc') # 4
    • findは、最初の出現位置を返す。なければ-1 'abcabcbcbc'.find('bc') # 1
    • replaceは全出現の置換 'abcabcbcbc'.replace('bc', '')
    • stripは前後の空白文字を消去する。

C++より実装速度が早いアルゴリズム

  • 気軽にsplitとかを前提にしたアルゴリズムを組めるのはいい
  • setの|や&
  • reversed(range(10))はrange(10)[::-1]でもできる。

内包表記

  • 内包表記には後置if条件を複数つけることができる。
    • [x for x in range(100) if x % 2 if x % 3]
  • if-elseもできる。前置になる
    • [ i if i%2==0 else str(i) for i in range(10)]
  • 速度的にも3倍程度早い
  • gotoモジュールはデフォルトではなく、頑張ってインストールしなければならないので残念。多重ループ抜け出しは基本for-elseかフラグしか方法がなさそう。あとは関数化

一括比較・一括処理

  • swap
    a, b = b, a
  • 一括等価チェック
    • 複数のオブジェクトの比較はつなげて一度に行う
# long
# 最初の文字と最後の文字両方が一致する
a[1] == b[1] and a[-1] == b[-1]

# short
a[1] + a[-1] == b[1] + b[-1]
  • リストで場合分け
    • これはC++でもできそう
# long
t = a % 3
if t == 0:
    a = a * 2
elif t == 1:
    a = 0
elif t == 2:
    a = t * 2

# short
a = [a * 2, 0, t * 2][a % 3]
  • if-elseの代わりにand orを使うワンライナー
条件 and True時 or False時
  • forのワンライナー。:は一行一個だが、それ以内のものはセミコロンでくっつけられる。
for x in[None]*10:print(a);a+=1
  • forでループ変数は絶対に参照しないぞという気構え(range書くより短い)
for _ in [1]*10:

mapオブジェクト、filterオブジェクトなど

  • ジェネレータと呼ばれるらしい
    • リストなどの遅延評価
  • 評価するには、for文なのでgenerateするか、明示的にlist(map_object)などとする([map_object]はだめ)

参照・ポインタ

概要

  • pythonの変数は全て参照!
    • 変数に新たなオブジェクトそのものが代入されるときには、これまでの参照先から変わって新たなオブジェクトが作られた場所を参照するようになる。

まず

  • とりあえずこれ動かしてなんかヤバイことを察して
  • 1つめ
>>> a = [1,2,3]
>>> b=a
>>> b[0]=3
>>> a
[3, 2, 3]
>>> b
[3, 2, 3]
>>> b += [4]
>>> a
[3, 2, 3, 4]
>>> b
[3, 2, 3, 4]
  • 2つめ
>>> L = [1,2,3,4]
>>> def func(ll):
...   ll = [5,6,7,7]
...
>>> func(L)
>>> L
[1, 2, 3, 4]
  • 3つめ
>>> def func(ll):
...   ll[0] = 5
...
>>> func(L)
>>> L
[5, 2, 3, 4]

注意すべき挙動

  • listを関数に渡して、
    • リスト全体を変えた場合は副作用がないが、
    • リストの一部を変えると副作用が起きる
    • 対策:func(a[:])とコピーを渡す。もしくは、関数内部始めに必ずdeep copyしてから使う。
  • 二次元配列を[[0]*m]*nで実装するとダメ
    • 超有名なのでググッて
    • 対策:リスト内包表記を使う

pythonの変数と実体は独立

  • 変数は全部ポインタ
    • 変数はラベルでしかなく、実体と独立にふわふわ浮いている
  • 代入
    • 変数にオブジェクトを代入すると、
      • 変数にオブジェクトの参照が代入される
    • 変数に変数を代入すると、
      • 変数に、変数が持つオブジェクトの参照が代入される
  • 関数呼び出し
    • 関数内部の変数に、入れた変数の参照が代入される
  • 例:以下は、4行出力するうち、3番目のみ相違となる。
def func(x):
  print(id(x))
  x = 3
  print(id(x))
    
a = 1
print(id(a))
func(a)
print(id(a))
  • これはC++に例えると、こうなる(thx to hakuyume君)

なぜimmutableとmutableで説明がつくと思っているのか

  • なんか皆immutableだからかーふーんと言っているが、なぜあの理解で理解できていると思っているのか理解できない
  • listはおそらく、listオブジェクトの中にいっぱいintの参照が詰まっている
    • list[0]を変更しようとした場合、listオブジェクトの0番目のintの参照を張り替える必要がある
      • mutableというのは、おそらくこれが可能というだけであって、listだからという話ではないと思う
    • 実際に、listそのものを完全に代入しなおした場合、listオブジェクトが変わるのでmutableだがidが変わる
    • したがって、mutableオブジェクトの場合、mutableオブジェクトのメンバ変数を実行可能だというだけで、それが関数渡しのidの話とは直接関係ないのでは?と感じている

pythonのポインタのようなもの

  • idというものでポインタが取れる
a = 1
id(a)

リストのdeep copy

  • a[:]とするとdeep copyができる
>>> a = [1,2,3] 
>>> b = a[:] # b = list(a)とか、b = copy.copy(a)でも大丈夫
>>> a
[1, 2, 3]
>>> b
[3, 2, 3]

関数わたし

  • 重要:list, dict, set, bytearrayは、自身を変更できるので、参照渡しであることを強く意識せねばならない
  • 関数に渡された値を変更した際に元の値自体も変更できるどうかは,オブジェクトの型に依存
    • 変更不可(Immutable)な型
      • int, float, str, tuple, bytes, frozenset 等
    • 変更可能(Mutable)な型
      • list, dict, set, bytearray 等
  • int型を参照わたししたいときは?
    • int型に変更できる余地がないので無理です

bitwise op.

  • bytearrayをつかう?

その他

  • sqrt(n)
    • n**0.5ができる
  • 数学変数
    • pi, e, infなどは、math.pi, math.e, math.infなどでアクセスす
  • pythonのfor内部で添字をいじっても意味ないので注意!!!
    • C++ではたまにfor内部でiを加速するが、pythonは毎回代入される。
  • 2**100000くらいならまあ余裕で計算できる

注意

  • {}はどっち?
    • dictであり、setではない
    • s = set()とする

闇魔法

  • 無理やりapplicableっぽくするやつがある

入出力

  • 改行なし
import sys
sys.stdout.write(str)

開発用

デバッグ

  • assert 条件式, ‘エラーメッセージ’
  • そもそもコンパイルレベルで発覚するミスをどうやって未然に検出するんだろう?
  • loggerという、デバッグレベルを設定できるパッケージがある

引数の扱い

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('processes', type=int)
parser.add_argument('--env', type=str, default='CartPole-v0')
parser.add_argument('--arch', type=str, default='FFSoftmax',

Pythonでの高階関数

クラス

  • Pythonのコンストラクタは__self__
    • classでは全てのメンバ関数に第一引数selfを入れる必要
    • メンバ変数も全てself.を付ける
    • デフォルト変数定義ない。動的に決まる。コンストラクタで初期化する。

メモ

Pandas

  • https://openbook4.me/projects/183/sections/777
  • https://qiita.com/hi34/items/43c366dea18b46faf49d
  • チートシート
  • SeriesとDataFrame?の2つがある
    • ベクトルや、行列の行と列に名前が付いている感じ
    • 縦の名前がindex, 横の名前がcolumns
  • API
    • s = pd.Series([1,2,3], index=['a','b','c'])
    • DF作成
      • df = pd.DataFrame?([[1,4,7],[2,5,8],[3,6,9]], index = ['i1','i2','i3'], columns = list("abc"))
      • foo = pd.DataFrame?({'bar': [0, 1, 2],'baz': [3, 4, 5]}, index=['a', 'b', 'c'])のようにしてcolumnsを指定することもできる。
      • 後でつけることもできる。df.column = ['a', 'x', 'c']とか、df.index = ['i1','i2','i3']とか
      • dict<T, array<S>>を食わせても初期化する。
    • 要素取得
      • df.ix[[1,2],['b','c']]でDataFrame?が、df.ix[:, 2]でSeriesが、df.ix[1,1]でスカラが帰ってくる。名前でも番号でもOK
      • df['a']はdf.ix[:, 'a']であって、混乱する。。
    • df[df>1]などで、条件を満たさないものをNaNにする感じ。df[df>1]=INFのようにできる。
    • 追加
      • foo['new_column'] = [6, 7, 8] # 横に追加
      • foo.append(pd.DataFrame?({'bar': [6, 7], 'baz': [8, 9}, index=['d', 'e'])) # 縦に追加
      • pd.concat([df1, df2]) # 縦に追加
      • df.append(df2, ignore_index=True) # 縦に追加
      • df1.join(df2) # 横に追加
    • 削除
      • foo.drop('e') # 行を削除する
      • foo.drop('bar', axis=1) # 列を削除する
    • 変なindexing
      • day_no
      • df_sample.query("day_no == 'day1'|day_no == 'day2'")
      • select_condition = "day1"; df_sample.query("day_no == @select_condition")
      • df_sample.query("index == 11 ")
      • df_sample.query("index in [11,12] ")
    • 読み出し
      • pd.read_csv('foo.csv', header=0)
      • df.to_csv('bar.csv', index=False)
    • データのチラ見
      • df.head(), df.tail()
    • 基本情報
      • df.shape # 縦横の形
    • 転置
      • df.T
    • numpy
      • df.valuesでnumpy配列や行列になる

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS