圧倒的python:numpy データサイエンス受験用

かずまなぶです。

ランダムウォークを作ってみた 株式チャートっぽい

日々、独学で学び続けているデータサイエンスの分野ですが、体系的に学びたい思い、このたび

東京大学 工学系研究科 技術経営戦略学専攻


グローバル消費インテリジェンス寄附講座

【第三期社会人向けデータサイエンスコース】

というものに応募してみました。

しかし、応募者数が受講可能人数を上回ってしまい、とりあえずpythonスキルのテストを実施して人数を絞るとのことで、本日受験いたしました。

※会社休んでまで受験してますので、絶対に受かりたい~。(; ・`д・´)

テストの前に、今一度 numpyを復習してみましたので、貼っておきます。

ここには出てきませんが、np.split(A,2)とかnp.split(A,2,axis=1)とかスプリット系は絶対必須です。

そのほか 順序入れ替え系の参考サイト

参考書:Pythonによるデータ分析入門 第二版

# pythonによるデータ分析入門
import numpy as np
#アレイの作成
my_arr=np.arange(10) # array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
#リストの作成
my_list=list(range(10)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
my_arr=np.arange(1000000)
get_ipython().run_line_magic('time', 'for _ in range(10):my_arr2=my_arr*2 # Wall time: 20 ms')
my_list=list(range(1000000))
get_ipython().run_line_magic('time', 'for _ in range(10):my_list2=[x*2 for x in my_list] # Wall time: 660 ms')
# 乱数列を生成
data=np.random.rand(2,3)# 2行3列
print(data)
print(data*10)
data+data
data.shape # (2, 3)
data.dtype # dtype('float64')
type(data) # numpy.ndarray
#リストをアレイに変換
li=[1,2,3,4]
arr1=np.array(li) # array([1, 2, 3, 4])
#リストから2次元アレイを作る
li_1=[1,2,3.2,4]
li_2=[5,6,7,8]
data2=[li_1,li_2] # [[1, 2, 3, 4], [5, 6, 7, 8]]
arr2=np.array(data2)
"""
array([[1, 2, 3, 4],
[5, 6, 7, 8]])
"""
arr2.ndim # 2
arr2.shape #(2, 4)
arr1.dtype # dtype('int32')
arr2.dtype # dtype('float64')
# In[59]:
np.zeros(6) # array([0., 0., 0., 0., 0., 0.])
np.zeros(6).reshape(2,3)
"""
array([[0., 0., 0.],
[0., 0., 0.]])
"""
np.zeros((3,6)) #引数にタプルを与える
"""
array([[0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0.]])
"""
np.empty((3,6)) # ゼロとは限らないので注意
np.ones(6) # array([1., 1., 1., 1., 1., 1.])
np.eye(3) # 単位行列を生成 np.identity(3)も同じ
"""
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
"""
# dtypeを指定する
arr_1=np.array([1,2,3],dtype=np.float64)
arr_1.dtype # dtype('float64')
arr_2=np.array([1,2,3],dtype=np.float32)
arr_2.dtype # dtype('float32')
# dtypeを明示的にキャスト(型変換)する
arr=np.array([1,2,3,4,5])
arr.dtype # dtype('int32')
arr=arr.astype(np.float64) #アズタイプでキャストする
arr.dtype # dtype('float64')
# 数値が文字列として入っているデータを数値としてキャストする
arr=np.array(["1","2","3"],dtype=np.string_) # アンダーバーが付くことに注意
arr.dtype # dtype('S1')
arr=arr.astype(np.int8)
arr # array([1, 2, 3], dtype=int8)
# ベクトル演算 (numpyはデフォルトでにベクトル演算に対応している)
arr=np.array([[1,2,3],[4,5,6]])
print(arr*arr) # 要素同士を掛け算した
"""
array([[ 1, 4, 9],
[16, 25, 36]])
"""
print(arr**0.5) # 要素が平方根をとる
"""
[[1. 1.41421356 1.73205081]
[2. 2.23606798 2.44948974]]
"""
print(arr-arr) # 要素同士を引き算した
"""
array([[0, 0, 0],
[0, 0, 0]])
"""
print(1/arr) # 要素を逆数にする
"""
[[1. 0.5 0.33333333]
[0.25 0.2 0.16666667]]
"""
# 比較 bool配列で返す
arr_1=np.array([[1,2,3],[4,5,6]])
arr_2=np.array([[2,4,1],[4,3,7]])
arr_1>arr_2
"""
array([[False, False, True],
[False, True, False]])
"""
# ブロードキャストする
arr=np.arange(10)
arr[3:6]# array([3, 4, 5])
arr[3:6]=100 #ブロードにキャストする(一つの数値が、スライスされた配列全体に影響する)
arr # array([ 0, 1, 2, 100, 100, 100, 6, 7, 8, 9])
# 超注意事項:numpyのスライスはコピーではなくてビューとして機能する
arr_slice=arr[3:6]
arr_slice # array([100, 100, 100])
arr_slice[1] #100
arr_slice[1]=500 # スライスがコピーとして機能しているなら元データのarrには影響がないはず
arr # 戻データに影響あり。やはりスライスはコピーではなくビューとして機能している。
#array([ 0, 1, 2, 100, 500, 100, 6, 7, 8, 9])
# スライスをコピーにする場合
arr_copy=arr[3:6].copy() # 明示的にコピーする
arr_copy # array([100, 500, 100])
#これをいじっても 元データは影響しないはず
arr_copy[1]=800
arr# array([ 0, 1, 2, 100, 500, 100, 6, 7, 8, 9])
# 影響なし
# index指定
arr=np.array([[1,2,3],[4,5,6],[7,8,9]])
"""
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
"""
arr[0] # array([1, 2, 3])
arr[0][2] # 3
arr[0,2] # 3 これでも良い
# 三次元配列
arr=np.array([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]])
"""
array([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
"""
arr[0]=100 # ブロードキャスト
arr
"""
array([[[100, 100, 100],
[100, 100, 100]],
[[ 7, 8, 9],
[ 10, 11, 12]]])
"""
# スライス
arr=np.array([[1,2,3],[4,5,6],[7,8,9],])
"""
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
"""
arr[2] #特定の行 array([4, 5, 6])
a=arr[:,1:2] #特定の列 縦に抽出するためにはスライス指定が必要
print(a)
"""
[[2]
[5]
[8]]
"""
arr[:,1] #特定の列 だめな例 array([2, 5, 8])
#代入
arr[0:2,1:3]=0 #ブロードキャスト
arr
"""
array([[1, 0, 0],
[4, 0, 0],
[7, 8, 9]])
"""
# ブールインデックス
names=np.array(["a","b","c","d","b","f","g"],dtype="U4")
data=np.random.rand(7,4)
names.dtype
names=="b" # arrayに比較演算子を使うと bool配列が得られる
"""
array([False, True, False, False, True, False, False])
"""
data[names=="b"] # これをdataのインデックス指定として True行だけを抽出できる
"""
rray([[0.77152746, 0.54914732, 0.64225057, 0.44982208],
[0.2992621 , 0.81429222, 0.25126623, 0.0374134 ]])
"""
# インデックスの数と行の数が一致していること
data[names=="b",2:] # されに列指定もできる
#ひっくり返すこともできる
names=="b" # array([False, True, False, False, True, False, False])
names!="b" # array([ True, False, True, True, False, True, True])
#真偽を逆転してもいい
~(names=="b") # array([ True, False, True, True, False, True, True]) 同じこと
# 論理演算子 and ( & ) と or ( | ) を使ってみる
mask= (names=="b") | (names=="c") # and or は使用できない。論理演算子 & と | のみ対応
mask # array([False, True, True, False, True, False, False])
data[mask]
"""
array([[0.77152746, 0.54914732, 0.64225057, 0.44982208],
[0.44209134, 0.06026321, 0.26829479, 0.56929646],
[0.2992621 , 0.81429222, 0.25126623, 0.0374134 ]])
"""
# 重要:ブールインデックスのスライスは必ずコピーになる
data[data<0.5]=0 #抽出と代入
data
data=np.random.rand(7,4)
data[names!="b"]=100 # ブロードキャスト
data
#ファンシーインデックス インデックス参照に整数配列を使う方法
arr=np.empty((8,4)) # いったんメモリを確保して
"""
array([[ 1.20329383e-311, 1.04247851e-321, 0.00000000e+000,
0.00000000e+000],
[-9.42337042e+171, 1.16095484e-028, -3.11167853e-227,
-2.45684737e+181],
[ 2.08013637e-115, -1.45269431e-113, 8.99727468e-154,
-9.54229115e-295],
[-9.42337594e+171, -3.22060422e-253, 2.19422365e-153,
1.04630141e-013],
[ 7.87454533e+289, 1.10254634e-012, 4.02566411e-144,
6.96410748e+252],
[ 8.03408341e-095, 5.72974605e+194, 1.16589870e-028,
1.47763669e+248],
[ 4.78214477e+180, 1.16441574e-028, 5.38669143e+228,
7.79350126e-143],
[ 3.97084747e+246, 2.03789108e+180, 2.15799225e+243,
1.52881840e-110]])
"""
for i in range(8): #そして、書き換える。
arr[i]=i
"""
array([[0., 0., 0., 0.],
[1., 1., 1., 1.],
[2., 2., 2., 2.],
[3., 3., 3., 3.],
[4., 4., 4., 4.],
[5., 5., 5., 5.],
[6., 6., 6., 6.],
[7., 7., 7., 7.]])
"""
# インデックス参照を用意して、「任意の行」を、「特定の順番」で抽出する
arr[[4,3,0,6]]
"""
array([[4., 4., 4., 4.],
[3., 3., 3., 3.],
[0., 0., 0., 0.],
[6., 6., 6., 6.]])
"""
arr[[-3,-8,-7]] #マイナスも使える。最後尾の行から数える
"""
array([[5., 5., 5., 5.],
[0., 0., 0., 0.],
[1., 1., 1., 1.]])
"""
# 行と列を指定すると 一次元配列で返ってくる
arr=np.arange(32).reshape((8,4))
"""
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23],
[24, 25, 26, 27],
[28, 29, 30, 31]])
"""
arr[[1,5,7,2],[0,3,1,2]] # array([ 4, 23, 29, 10])
# ファンシーインデックスもブールインデックスと同じく、コピーを作ります
# コピーでなくビューを作るのはいまのところ スライシングのみです
# 転置行列 (行と列の入れ替え) transpose と T
#注意:これもコピーではなくてビューになる
arr=np.arange(15).reshape((3,5))
"""
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
"""
arr.T #転置
"""
array([[ 0, 5, 10],
[ 1, 6, 11],
[ 2, 7, 12],
[ 3, 8, 13],
[ 4, 9, 14]])
"""
# 内積計算で頻繁に使う np.dot()
np.dot(arr.T,arr)
"""
array([[125, 140, 155, 170, 185],
[140, 158, 176, 194, 212],
[155, 176, 197, 218, 239],
[170, 194, 218, 242, 266],
[185, 212, 239, 266, 293]])
"""
# 高次元の場合は transpose を使うと軸の順序指定ができる
arr=np.arange(16).reshape((2,2,4)) # 2層 2行 4列
"""
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]],
[[ 8, 9, 10, 11],
[12, 13, 14, 15]]])
"""
arr.transpose((1,0,2)) #引数=軸の順序 層と行を入れ替えて 列はそのまま
"""
array([[[ 0, 1, 2, 3],
    [ 8, 9, 10, 11]],
[[ 4, 5, 6, 7],
[12, 13, 14, 15]]])
"""
#swapaxes スワップアクシス は T を拡張して 軸の順序指定をできるようにした
arr.swapaxes(1,2) # 行と列を入れ替え 層はそのまま
"""
array([[[ 0, 4],[ 1, 5],[ 2, 6],[ 3, 7]], #1層目のなかで行列を転置
[[ 8, 12],[ 9, 13],[10, 14],[11, 15]]]) #2層目のなかで行列を転置
"""
#これもコピーでなくてビューを返す
#ユニバーサル関数 通称:ufunc ユーファンク。arrayにも普通の関数が使える
arr=np.arange(10) # array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# 単項ufunc
np.sqrt(arr) # 平方根
"""
array([0. , 1. , 1.41421356, 1.73205081, 2. ,
2.23606798, 2.44948974, 2.64575131, 2.82842712, 3. ])
"""
np.exp(arr) # ネピア数
"""
array([1.00000000e+00, 2.71828183e+00, 7.38905610e+00, 2.00855369e+01,
5.45981500e+01, 1.48413159e+02, 4.03428793e+02, 1.09663316e+03,
2.98095799e+03, 8.10308393e+03])
"""
# 2項ufunc 各列で大きいほうを採用
x=np.random.randn(3) # [ 1.1093276 -0.39888326 -0.28544499]
y=np.random.randn(3) # [ 0.51904861 0.35794352 -0.44136913
arr_max=np.maximum(x,y) # [ 1.1093276 0.35794352 -0.28544499]
#少数と整数に分ける modf
arr=np.random.rand(3)*5  # [1.61821754 2.93630856 3.38383168]
remainder,whole_part=np.modf(arr)
print(remainder,whole_part) # [0.61821754 0.93630856 0.38383168] [1. 2. 3.]
# 配列
points=np.arange(-5,5,0.01) #等間隔に配置された1000個の格子点
xs,ys=np.meshgrid(points,points) #x,y平面にmeshgridを打つ
z=(np.sqrt(xs**2+ys**2)) # meshgrid点における関数zを計算
np.shape(z) # サイズ(1000, 1000)
#可視化
get_ipython().run_line_magic('matplotlib', 'inline')
import matplotlib.pyplot as plt
plt.imshow(z,cmap=plt.cm.gray);plt.colorbar()
plt.title("Image plot of $\sqrt{x^2+y^2}$ for agrid of values")
#条件制御
xarr=np.array([1.1,1.2,1.3,1.4,1.5])
yarr=np.array([2.1,2.2,2.3,2.4,2.5])
cond=np.array([True,False,True,True,False])
result=np.where(cond,xarr,yarr) # (bool配列,Trueのとき選ばれる配列,Falseのとき選ばれる配列)
"""
array([1.1, 2.2, 1.3, 1.4, 2.5])
"""
# 選択される配列の部分をスカラーにすればブロードキャストされて置換できる。
arr=np.random.randn(3,3)
print(arr)
print(arr<0)
"""
[[-0.47165678 0.85528493 0.53105873]
[ 0.69874423 -0.78291097 0.30890445]
[-0.24354794 -0.00685989 0.10631391]]
[[ True False False]
[False True False]
[ True True False]]
"""
np.where(arr<0,2,arr)# マイナスの数 Trueは全部 スカラー2に置換する。Falseはオリジナルの数値を採用する
print(np.where(arr<0,2,arr))
"""
[[2. 0.85528493 0.53105873]
[0.69874423 2. 0.30890445]
[2. 2. 0.10631391]]
"""
# 数学関数 統計関数
arr=np.random.randn(5,4)
print(arr)
print(arr.mean())
print(np.mean(arr)) # 同じこと
print(arr.sum())
print(np.sum(arr)) #同じこと
print(arr.mean(axis=0)) # 行方向に入れていく→各列の平均が出る [ 0.37092639 0.78724106 0.31904456 -0.87450481]
print(arr.mean(axis=1)) # 列方向に入れていく→各行の平均が出る [-0.24614573 0.5018765 0.84322339 1.26942423 -0.23434149]
#累積和 cumsum 累積積 cumprod
arr=np.array([1,2,3,4,5])
print(arr.cumsum()) # [ 1 3 6 10 15]
print(arr.cumprod()) # [ 1 2 6 24 120]
# 真偽値 配列関数
arr=np.random.randn(5)
print(arr)
print(arr>0) # bool配列
print((arr>0).sum()) # Trueの個数を出力する
# any all
bools=np.array([False, False, True, True, False])
bools.any() # 配列の中に一つでもTrueがあったらTrue
bools.all() # 配列の中がすべてTrueだったらTrue
# 数値に対しても適用できる。 0 = False それ以外の数値は True 扱い
# ソート 直接置換する これはnp.ndary.sort関数というらしい。他にもnp.sort関数があるらしい
arr=np.random.randn(6)
print(arr)
print(arr.sort()) #小さい順に並べる 上書きされるので注意
print(arr)
#軸指定もできる
arr=np.random.randn(3,4)
print(arr)
print(arr.sort(0)) #行方向にソートする。結果、1行目が一番小さい数値の集まりになる
print(arr)
# 5%分位点を取る
arr=np.random.randn(1000)#これで順番になる
arr.sort()
print(arr)
len(arr) # 1000
arr[int(len(arr)*0.05)] # 下から5%の位置 -1.6530626609822332
# 集合関数 unique
names=np.array(["a","b","c","b","e"])
np.unique(names) #重複を削除して さらに ソートまでする。
#とある要素が配列内にあるか調べる np.in1d
arr=np.array([2,5,7,4,3,2])
np.in1d(arr,2) # array([ True, False, False, False, False, True])
np.in1d(arr,[2,3,7]) # array([ True, False, True, False, True, True])
# ファイルの入力 出力
arr=np.arange(10)
np.save("some_arr",arr) # 自動的に拡張子は .npyが付く
np.load("some_arr.npy") # 読みだす。 拡張しを忘れずに
# savezで複数個まとめる 拡張子は.npz
np.savez("some_arr.npz",a=arr,b=arr)
arr_npz=np.load("some_arr.npz") #いったんインスタンスにしたいとだめみたい
arr_npz["a"] # array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
arr_npz["b"] # array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# 圧縮して保存は savez_compressed 拡張子は.npz
np.savez_compressed("some_arr.npz",a=arr,b=arr)
arr_npc=np.load("some_arr.npz")
arr_npc["a"] # array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# 行列計算
#内積1 基本
x=np.array([[1,2,3],[4,5,6]])
y=np.array([[1,2],[3,4],[5,6]])
x.dot(y)
"""
array([[22, 28],
[49, 64]])
"""
np.dot(x,y) # これも同じ
# 内積2 転置しなくてもできる
x=np.array([[1,2,3],[4,5,6]])
y=np.ones(3) # array([1., 1., 1.])
x.dot(y) # array([ 6., 15.]) 数学的にはyは転置しないと計算できないが、自動的に転置してくれている。
x.dot(y.T) #array([ 6., 15.]) もちろん同じ結果。
#内積3 演算子 @ ができました
x@y # array([ 6., 15.])
# 転置 逆行列
from numpy.linalg import inv,qr #インポートしておこう リン・アルジ linalg=linear algebra
x=np.random.randn(5,5)
mat=x.T.dot(x) #行列x の転置行列x.T と 行列x との内積を計算してみた
inv(mat)
mat_unit=mat.dot(inv(mat)) # 正確な単位行列には戻らない
print(mat_unit)
mat_unit=np.round(mat_unit,decimals=5) #小数点5桁に丸めた
print(mat_unit)
# QR分解 正方行列 を [直行行列]・[上三角行列] に置き換える
q,r=qr(mat)
print(mat)
print(q)
print(r)
np.linalg.eig(mat) # 固有ベクトル と 固有値
b=np.array([1,2,3,4,5])
mat_solve=np.linalg.solve(mat,b) #Ax=bのxを求める
mat_lstsq=np.linalg.lstsq(mat,b)
print("solve: ",mat_solve)
print("lstsq : ",mat_lstsq)
# 疑似乱数を作る
mat=np.random.normal(size=(4,4)) #正規分布に基づいた乱数。完全な乱数ではないので疑似乱数と呼んでいる
"""
array([[ 0.03708459, -0.35050763, -0.49255684, 0.07165002],
[ 0.61679516, -0.34355482, 0.8140179 , 0.67186331],
[-1.41884249, 0.8826972 , 0.05766763, -0.70212211],
[-0.21402669, 1.44794685, -0.60866874, -1.16066817]])
"""
#乱数シードを設定できる 一度生成したら固定できる
rng=np.random.seed(1234) # rng=ランダム・ジェネレータ―
#グローバル参照を避けた乱数生成器 一度生成したら固定できる
rand=np.random.RandomState(12345)
rand.randn(5) # 乱数生成器rng から 乱数配列を作る
# ランダムウォークを作る
import random
position=0
walk=[position]
steps=1000
for i in range(steps):
step=1 if random.randint(0,1) else -1 # 1だったら何もおこらないでそのまま1。-1がはいったらstep=-1になる
position+=step
walk.append(position)
plt.plot(walk[:1000])
# ランダムウォークをnumpyで作る
import numpy as np
nsteps=1000
draws=np.random.randint(0,2,size=nsteps) # 最大値を1にするなら2を入れなくてはならないので注意
steps=np.where(draws>0,1,-1) # Trueなら1 False1なら-1
walk=steps.cumsum()
plt.plot(walk[:1000])
# 任意の値 n 離れたところまでの到達時間を得る ブールインデックスを使おう
n=10
(np.abs(walk)>n).argmax() # argmax() 配列の中で一番若いIndexの最大値(True)を得る
#多重ランダムウォーク 5000回 試行してみる
import numpy as np
import matplotlib.pyplot as plt
get_ipython().run_line_magic('matplotlib', 'inline')
nwalks=5000
nsteps=1000
draws=np.random.randint(0,2,size=(nwalks,nsteps)) #一気に5000回分の stepsを作成した。
draws.shape # (5000, 1000)
steps=np.where(draws>0,1,-1)
steps[0].shape# 1行が1回の試行
walks=steps.cumsum(1) #累積方向に注意
print(walks.max(),walks.min())
for i in range(100):
plt.plot(walks[i])
# ±30への到達時間を抽出する 真偽値配列関数 any
limit=30
hits=(np.abs(walks)>limit).any(1) # 配列の中に一つでもTrueがあったらTrue。列方向に見ていく
hits.shape # (5000,)
hits.sum() # limitに到達した試行回数 3216
# limitに到達した試行NOだけの行列をスライスして、その絶対値がlimitを超えたときの最速インデックスを返す
crossing_time=((np.abs(walks[hits]))>limit).argmax(1)
crossing_time.mean() #到達時間の平均値 515.5534339390206
# 降順ソート
arr=np.array([1,2,4,3,5,2,6,8,4,5,6])
np.sort(arr)
arr=arr[::-1]
arr