ながれとよどみ

自分が解いた問題の解法など

Dockerを使って競技プログラミングの環境構築をした際のメモ

C++Pythonが使えるように設定しました。

Dockerfile

FROM ubuntu:20.04

RUN apt-get update && apt-get install -y \
    build-essential python3-pip

RUN pip3 install --upgrade pip setuptools wheel
RUN pip3 install numpy networkx joblib cython scipy llvmlite numba matplotlib

WORKDIR /work

docker-compose.yml

version: '3'
services:
  app:
    build: .
    tty: true
    volumes:
      - type: bind
        source: ./work
        target: /work

データサイエンティスト養成講座5章の演習

5章ではNumpyやScipyを本格的に使っていく。

[:contents] 練習問題5-1から5-3

参照渡し、浅いコピーと深いコピーについては、こちらを参照

ドキュメント

numpy.copyの挙動

練習問題5-1から5-3

import numpy.random as random
#練習問題
sample_names = np.array(['a', 'b', 'c', 'd', 'e'])
random.seed(0)
data = random.randn(5, 5)
#sample_nameのbに該当する部分を抽出
data[sample_names=='b']
#sample_nameのc以外に該当する部分を抽出
data[sample_names!='c']

#print(data)
x = np.array([1, 2, 3, 4, 5])
y = np.array([6, 7, 8, 9, 10])
a = ['fuga','fuga', 'hoge', 'hoge', 'fuga']
print(np.where(a=='fuga', x, y))

練習問題5-4

  1. 配列についてすべての要素の平方根を計算
  2. 配列の最大値、最小値、合計値、平均値を計算
  3. 対角成分の和を計算
sample_multi_array_data2 = np.arange(16).reshape(4, 4)
print(np.exp(sample_multi_array_data2))

print(sample_multi_array_data2.min(), sample_multi_array_data2.max(), sample_multi_array_data2.sum(), sample_multi_array_data2.mean())
print(np.diag(sample_multi_array_data2))
ブロードキャストの説明はこちらを参照

演習問題5-7

配列を縦に結合

演習問題5-8

配列を横に結合

演習問題5-9

リストの各要素に3を加える

sample_array1 = np.arange(12).reshape(3, 4)
sample_array2 = np.arange(12).reshape(3, 4)
#縦に結合
np.concatenate([sample_array1, sample_array2], axis=0)
np.vstack((sample_array1, sample_array2))

#横に結合
np.concatenate([sample_array1, sample_array2], axis=1)
np.hstack((sample_array1, sample_array2))

sample_list = np.array([1, 2, 3, 4, 5])
print(sample_array + 3)

練習問題5-10, 11, 12

以下のデータについて、線形補間、2次のスプライン補間、3次のスプライン補間を行い、グラフを図示せよ。

x = np.linspace(0, 10, num=11, endpoint=True)
y = np.sin(x**2/5.0)
plt.plot(x, y, 'o')
plt.grid(True)

練習問題5-10から5-12

from scipy import interpolate

x = np.linspace(0, 10, num=11, endpoint=True)
y = np.sin(x**2/5.0)
plt.plot(x, y, 'o')
plt.grid(True)


f = interpolate.interp1d(x, y, 'linear')
plt.subplot(1, 3, 1)
plt.plot(x, f(x), '-')

xnew = np.linspace(0, 10, num=30, endpoint=True)


#スプライン2次補間を追加
f2 = interpolate.interp1d(x, y, 'quadratic')

plt.subplot(1, 3, 2)
plt.plot(x, y, 'o', xnew, f(xnew), '-',  xnew, f2(xnew), '--')
#スプライン3次補間を追加
f3 = interpolate.interp1d(x, y, 'cubic')
plt.subplot(1, 3, 3)
plt.plot(x, y, 'o', xnew, f(xnew), '-',  xnew, f2(xnew), '--', xnew, f3(xnew), 'x')P
特異値分解
import scipy as sp
#特異値分解
A = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])

U, s, Vs = sp.linalg.svd(A)
#print(U)
#print(s)
#print(Vs)
m, n = A.shape

S = sp.linalg.diagsvd(s,m,n)
print('U.S.V = \n', U@S@Vs)

LU分解とコレスキー分解は数値計算を勉強する際に

scipy integrateのドキュメント

Todo ローレンツ方程式

練習問題5-15、5-16

[tex: \int^{2}_{0} (x+1)2 dx]の値を求めよ

 \int^{\pi}_0 \cos(x) dxの値を求めよ

scipy optimizeのドキュメント

データサイエンティスト養成講座4章の演習

引き続きデータサイエンティスト養成講座を読む。

4章では、数理統計学の初歩的な部分とその実装について学ぶ。 数理統計について最低限の知識がないと理解がしづらいと思う。 自分は数理統計の初歩的な部分を勉強するためにクロスセクションシリーズの「数理統計学の基礎」を読んだ。

この本は数理統計学の入門書の中では比較的、厳密に書かれていると思う。

演習問題4-1

コイン投げの試行を1000回実行し、成功と失敗の確率を示せ

coin_data = np.array([0, 1])
steps = 1000
coin_rolls = np.random.choice(coin_data, steps)
for i in range(0, 2):
  p = len(coin_rolls[coin_rolls==i])/steps
  if(i == 0):
    print(f'表が出る確率は{p}')
  else:
    print(f'裏が出る確率は{p}')

演習問題4-2

1000本のくじの中に100本の当たりがある。AとBが順番にくじを引くときにともにあたりが出る確率を求めよ(くじは元に戻さない)

A、Bが当たりを引く確率をそれぞれ P(A) P(B)と書く。  P(A \cap B )  = P(A) \, P(B|A) = \frac{100}{1000} \times \frac{99}{999}  = \frac{11}{1110}

p.108のカーネル密度推定は他の本で勉強をする。

練習問題4-4

N(0, 1)からn=100の標本抽出を10000回繰り返して標本平均のヒストグラムを図示

sample_mean = np.array([])
for _ in range(0, 10000):
  #標本抽出して、標本平均を求める
  x = np.random.normal(0, 1, 100)
  sample_mean = np.append(sample_mean, x)

plt.hist(sample_mean)
plt.grid(True)

標本平均のヒストグラム

練習問題4-5 練習問題4-4の対数正規分布の場合

sample_mean = np.array([])
for _ in range(0, 10000):
  #標本抽出して、標本平均を求める
  x = np.random.lognormal(0, 1, 100)
  sample_mean = np.append(sample_mean, x)
#標本平均はほとんど0から15の範囲に分布しているので、ヒストグラムの範囲を調整する
plt.hist(sample_mean,range=(0, 15))
plt.grid(True)

練習問題4-6 student_data_mathの一期目の成績G1のヒストグラムカーネル密度推定

import pandas as pd
student_data_math = pd.read_csv('student-mat.csv', sep=';')

#カーネル密度推定
student_data_math.G1.plot(kind='kde', style='k--')

#ヒストグラム
student_data_math.G1.hist(density=True)
plt.grid(True)

カーネル密度推定とヒストグラム

p.111の二次元正規分布の図示

ライブラリの機能とかをまだ理解していないので、実装の意味が分からないところが結構ある pos = np.empty(x.shape + (2, ))pos[:, :, 0] = x pos[:, :, 1] = yとかよくわからん

#2次元正規分布
import scipy.stats as st
from scipy.stats import multivariate_normal
from mpl_toolkits.mplot3d import Axes3D

x, y = np.mgrid[10:100:2, 10:100:2]

#print(x)
#print(y)

pos = np.empty(x.shape + (2, ))
print(pos.shape)
pos[:, :, 0] = x
pos[:, :, 1] = y
print(pos[0])

rv = multivariate_normal([50,50], [[100, 0], [0, 100]])
z = rv.pdf(pos)
print(z)

fig = plt.figure(dpi=100)

ax = Axes3D(fig)
ax.plot_wireframe(x, y, z)
#x,y,zラベルの設定
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')

ax.ticklabel_format(style='sci', axis='z', scilimits=(0, 0))

大数の法則

大数の法則はiidな確率変数 X _ 1, X _ 2, \cdots X _ nについて \displaystyle \sum _ {k=1}^{n} \frac{x _ {k}}{n}  n \rightarrow \inftyとしたときにpに確率収束することを示している。

#大数の法則
calc_times = 1000
#サイコロ
sample_array = np.array([1,2,3,4,5,6])
number_cnt =  np.arange(1, calc_times+1)

#4つのパスを作成
for i in range(4):
  #1から6から一つ抽出する操作をcalc_times回繰り返してその累積和をとる
  p = np.random.choice(sample_array, calc_times).cumsum()
  #print(p)
  plt.plot(p/number_cnt)
  plt.grid(True)

パスが3.5に近づく様子

中心極限定理

#中心極限定理
def function_central_theory(N):

  sample_array = np.array([1, 2, 3, 4, 5, 6])
  number_cnt = np.arange(1, N+1) * 1.0
  
  mean_array = np.array([])

  for _ in range(1000):
    cum_variables = np.random.choice(sample_array, N).cumsum()*1.0
    print(cum_variables[N-1])
    mean_array = np.append(mean_array, cum_variables[N-1]/N)
  
  plt.hist(mean_array)
  plt.grid(True)

function_central_theory(100)
練習問題4-10は省略(どの教科書にも書いてあって、明らかなので)

練習問題4-11

Pythonで最尤推定の実装をする際に参考にする

練習問題4-14

本と同様にp値を計算するコードを書いたけど、計算できてない

#p値を計算
from scipy import stats
#G2での数学とポルトガル語の成績の平均の差の検定
t_2, p_2 = stats.ttest_rel(student_data_merge.G2_math, student_data_merge.G2_por)
print("p値は, ", p_2)

データサイエンティスト養成講座3章の演習

3章ではデータをダウンロードしてきて回帰分析をする。 データ

カレントディレクトリをchap3に移動し、そこでZIPファイルをダウンロードして展開するという本文のp.70からp.72の操作をするためには、作業にGoogle colabratoryを用いているために本文と若干異なるコードを書く必要が生じたので、自分が書いたコードをここに示しておく。 参考

!pwd
!mkdir chap3
%cd ./chap3 
#必要なライブラリ
import requests, zipfile
from io import StringIO
import io
#ZIPファイルをダウンロードして展開
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/00356/student.zip'
r = requests.get(url, stream=True)
z =zipfile.ZipFile(io.BytesIO(r.content))
z.extractall()

練習問題3-1 student-por.csvを読み込んで要約統計量を提示する。

data_por = pd.read_csv('student-por.csv', sep=";")
#要約統計量
data_por.describe()

練習問題3-2 数学のデータとポルトガル語のデータをマージ

#数学のデータとポーランド語のデータをマージして、要約統計量を求める
new_data = pd.merge(student_data_math, data_por, on=['school', 'sex', 'age', 'address', 'famsize', 'Pstatus', 'Medu', 'Fedu', 'Mjob', 'Fjob', 'reason', 'nursery', 'internet' ], suffixes=('_math', '_por'))
new_data.describe()

練習問題 3-3 Medu, Gedu, G3_mathを選んで散布図とヒストグラムを作成

Todo: ヒストグラムを作成
sns.pairplot(new_data[["Medu", "Fedu", "G3_math"]])

p.93 練習問題

練習問題

1, student-pr.csvのG3とG1を用いて回帰分析して、回帰係数、切片、決定係数を求める

2, 散布図と回帰直線を合わせてグラフ化

3, G3を目的変数、absencesを説明変数として回帰分析して、回帰係数、切片、決定係数を求める。散布図と回帰直線を合わせてグラフ化して結果を考察する。

por_data = pd.read_csv('student-por.csv', sep=";")
#print(por_data.head())

#各種要約統計量
#print(por_data.describe())
reg2 = linear_model.LinearRegression() 
X = por_data.loc[:, ['G3']].values
Y = por_data['G1'].values
reg2.fit(X, Y)

#回帰直線の図示
plt.plot(X, reg2.predict(X))

#回帰係数、切片、決定係数
print("回帰係数は", reg2.coef_)
print("切片は", reg2.intercept_)
print("決定係数は", reg2.score(X, Y))
#実際の散布図と回帰直線を合わせて図示
plt.plot(X, Y, 'o')
plt.plot(X, reg2.predict(X))
plt.grid(True)
#G3を目的変数、absencesを説明変数として回帰分析を行う
X = por_data.loc[:, ['absences']].values
Y = por_data['G3'].values

reg3 = linear_model.LinearRegression()
reg3.fit(X, Y)

#回帰直線と散布図を図示
plt.plot(X, Y, 'o')
plt.plot(X, reg3.predict(X))
plt.xlabel("欠席数")
plt.ylabel("G3")
plt.grid(True)

#回帰係数、切片、決定係数
print("回帰係数", reg3.coef_)
print("切片", reg3.intercept_)
print("決定係数", reg3.score(X, Y))
考察

決定係数は0.01以下であり、散布図と回帰直線を図示したグラフからも、回帰直線の当てはまりが非常に良くないことが分かる。

f:id:nqwerty:20210905125803p:plain

Todo 章末問題

データサイエンティスト養成講座2章の演習

引き続きこの本を読む

2章にはnumpy、matplotlibなどのデータ分析に用いるライブラリの基本的な説明が書かれている。

はてなブログに数式を打ち込む方法は、このブログを参考にした。

この本のサポートページはこちら

データのランダムな抽出

import numpy as np
import numpy.random as random

random.seed(3)
data = np.array([2, 4, 6, 8, 1, 3, 5, 7, 9])

print(random.choice(data, 5))

p.44 演習問題 1から50の和

#1から50までの和を求める
a = [x for x in range(1, 51)]
b = np.array(a)

ans = np.sum(b)
print("1から50の和は", ans)

p.44 演習問題 正規分布に従う乱数を10個発生させて、最小値、最大値、和を求める

random.seed(0)
rnd = random.randn(10)
print(np.min(rnd))
print(np.max(rnd))
print(np.sum(rnd))

p.44 演習問題 成分が3の5*5行列 Aを作って[tex: A2]を計算する。

import numpy as np
A = np.full(25, 3).reshape(5, 5)
#行列Aの二乗
print("行列Aの二乗は", np.dot(A, A))

[tex: f(x) = x2+ 3x + 1]について、 f(x) = 0の解と f(x)の最小値を求める

import scipy.linalg as linalg
from scipy.optimize import minimize_scalar
from scipy.optimize import newton
def my_func(x):
  return (x**2 + 3*x + 1)

#ニュートン法
print(newton(my_func, 0))
#最小値を求める
print(minimize_scalar(my_func, method="Brent"))

行列 Aについて、行列式の値、逆行列固有値固有ベクトルをそれぞれ求める

A = np.array([[1, 2, 3], [1, 3, 2], [3, 1, 2]])
#行列式を求める
print(linalg.det(A))
#逆行列を求める
print(linalg.inv(A))
#固有値、固有ベクトルを求める
eig_value, eig_vec = linalg.eig(A)
print("固有値は", eig_value)
print("固有ベクトルは", eig_vec)

関数[tex: f(x) = x3 + 2x + 1 = 0]の解をnewton法により求める。

def prob_func(x):
  return (x**3 + 2*x +  1)

print(newton(prob_func, 0))

Section2-5 pandas

p.53 pandas入門 IDが103以下の人を抽出

import pandas as pd
from pandas import Series, DataFrame

attri_data = {'ID': ['100', '101', '102', '103', '104'], 
              'City': ['Tokyo', 'Tokyo', 'Sendai', 'Sendai', 'Sendai'],
              'Birth_year': ['1990', '990','1490','1940','1991',],
              'Name': ['Hiroshi', 'Akiko', 'Yuki', 'Satoru', 'Steve']}

attri_data_frame = DataFrame(attri_data)
attri_data_frame_indexl = DataFrame(attri_data, index=['a', 'b', 'c', 'd', 'e'])

attri_data_frame_indexl

#IDが103以下の人を抽出
attri_data_frame_indexl[attri_data_frame_indexl['ID'] <= '103']

p.56 各都市ごとに誕生年の最大値と最小値を表示

#各都市ごとに誕生年の最大値と最小値を表示
print(attri_data_frame_indexl.groupby('City')['Birth_year'].max())
print(attri_data_frame_indexl.groupby('City')['Birth_year'].min())

練習問題2-7

1,Moneyが500以上の人を絞り込み 2,男女それぞれの平均Money 3,あらたにDataFrameオブジェクトを用意し、データをマージしてMoney, Math, Englishの平均を求める。

from pandas import Series, DataFrame
import pandas as pd

attri_data1 = {'ID':['1', '2', '3', '4', '5'],
              'Sex': ['F','F','M','M','F'],
              'Money': [1000, 2000, 500, 300, 700],
              'Name': ['Saito', 'Horie', 'Kondo', 'Kawada', 'Matduhara']}

attri_data_frame1 = DataFrame(attri_data1)
#Moneyが500以上の人のみ表示
print(attri_data_frame1[attri_data_frame1["Money"] >= 500])
#男女それぞれの平均Money
print(attri_data_frame1.groupby('Sex')['Money'].mean())

#あらたにDataFrameオブジェクトを用意して、IDをキーとしてマージする
attri_data_frame2 = DataFrame({'ID':['3', '4', '7'],
                         'Math': [60, 30, 40],
                         'English': [80, 20, 30]})

attri_new_frame = pd.merge(attri_data_frame1, attri_data_frame2)
print(attri_new_frame)
print("Moneyの平均点は", attri_new_frame['Money'].mean())
print("数学のの平均点は", attri_new_frame['Math'].mean())
print("英語の平均点は", attri_new_frame['English'].mean())

Section2-5 Matplotlib

p.65 演習問題2-10から2-12

 y = 5x + 3  (-10 \lt X \lt 10) を図示  y = sin(x) y = cos(x)のグラフを図示 一様乱数 X \sim U(0, 1)を1000個発生させて、ヒストグラムを図示

import numpy as np
import matplotlib as mlp
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline


def my_func(x):
  return 5*x + 3
x = np.linspace(-10, 10, 100)
plt.plot(x, my_func(x))
x = np.linspace(-10,10, 100)
plt.plot(x, np.sin(x))
plt.plot(x, np.cos(x))
import random
x = np.random.uniform(0.0, 1.0, 1000)
y = np.random.uniform(0.0, 1.0, 1000)
plt.subplot(2, 1, 1)
plt.hist(x, bins=60, range = (0, 1.5))

plt.subplot(2, 1, 2)
plt.hist(y, bins=60, range = (0, 1.5))

Todo:総合問題を解く(モンテカルロ法)

データサイエンティスト養成講座1章の演習

1章は基本的な文法事項の復習。高階関数とか思い出せてよかった。

p.24 フィボナッチ数列を求める方法の別解

#fibonattiをDPで求める
n = int(input())
dp = [0] * (n+1)
for i in range(1, n+1):
  if(i == 1 or i == 2):
     dp[i] = 1;
  else:
    dp[i] = dp[i-1] + dp[i-2]
print(f"{n}番目のフィボナッチ数は{dp[n]}")

p.26 高階関数reduce, filterについて調べて実装

参考

from functools import reduce
#高階関数 reduce, filter 
 
mul1 = reduce(lambda x, y: x*y, [2, 4, 6])
print(mul1)


val_3_div = filter(lambda x:x%3==0, [1, 2, 3, 4, 5, 6])
print(val_3_div)

練習問題 1から50までの和を計算

li = [x for x in range(1, 51)]

ans = reduce(lambda x, y: x+y, li)
print(f"1から50の和は{ans}")

p.29演習問題 クラス作成

 #四則演算クラス 
  class MyCalcclass:
    #初期化
    def __init__(self, x, y):
      self.x = x
      self.y = y

    def calc_add(self):
      return self.x + self.y

    def calc_sub(self):
      return self.x - self.y
    
    def calc_mul(self):
      return self.x * self.y
    
    def calc_div(self):
      if(self.y == 0):
        return "割り算はできない"
      else:
        return self.x / self.y

instance_1 = MyCalcclass(3, 0)
print(instance_1.calc_add())
print(instance_1.calc_sub())
print(instance_1.calc_mul())
print(instance_1.calc_div())

Todo: エラトステネスの篩