Python test入門 その2

はじめに

前回の記事Python test入門 その1に引き続き、Pythonのテストについて、標準ライブラリであるunittestを使って学んでいきます。

今回も公式リファレンスのコードを引用しながら、解説をしていきます。

解説

テストディスカバリ

複数のファイルに対してテストを実行したい場合があります。

その場合は下記のようにコマンドを実行します。

1
python -m unittest discover

カレントディレクトリにある、testから始まるテストスクリプトを実行します。

前処理と後処理

テストにあたり、前処理や後処理を実行したい場合があります。

そういった場合は、setUptearDownを用います。

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
import unittest

class TestStringMethods(unittest.TestCase):

def setUp(self):
print ('setUp')

def tearDown(self):
print ('tearDown')

def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')

def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())

def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)

if __name__ == '__main__':
unittest.main()

(改行が入らず分かりにくいですが)前処理と後処理が実行されていることが確認できます。

各処理はそれぞれのテストケースに対して実施されます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
test_isupper (__main__.TestStringMethods) ... setUp
tearDown
ok
test_split (__main__.TestStringMethods) ... setUp
tearDown
ok
test_upper (__main__.TestStringMethods) ... setUp
tearDown
ok

----------------------------------------------------------------------
Ran 3 tests in 0.001s

OK

クラス単位で前処理、後処理を行いたい場合はクラスメソッドを利用して、下記のように実装します。

1
2
3
4
5
6
7
@classmethod
def setUpClass(self):
print ('setUpClass')

@classmethod
def tearDownClass(self):
print ('tearDownClass')

メソッド

以下に示した12のメソッドが用意されています

1
2
3
4
5
6
7
8
9
10
11
12
assertEqual(a, b)
assertNotEqual(a, b)
assertTrue(x)
assertFalse(x)
assertIs(a, b)
assertIsNot(a, b)
assertIsNone(x)
assertIsNotNone(x)
assertIn(a, b)
assertNotIn(a, b)
assertIsInstance(a, b)
assertNotIsInstance(a, b)

一部、コードを載せておきます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import unittest

class TestMethods(unittest.TestCase):
def test_assert_equal(self):
self.assertEqual(1, 1)

def test_assert_not_equal(self):
self.assertNotEqual(1, 2)

def test_assert_true(self):
self.assertTrue(True)

def test_assert_false(self):
self.assertFalse(False)

if __name__ == '__main__':
unittest.main()

次回に続きます!

Python test入門 その3

記事情報

  • 投稿日:2020年4月9日
  • 最終更新日:2020年4月10日

Python test入門 その1

はじめに

この記事ではPythonのテストについて、標準ライブラリであるunittestを使って学んでいきます。

公式リファレンスのコードを引用しながら、解説をしていきます。

解説

基本

test_modlue.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import unittest

class TestStringMethods(unittest.TestCase):

def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')

def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())

def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)


if __name__ == '__main__':
unittest.main()

細かくみていきましょう。

1
import unittest

unittestは標準ライブラリであるためインストールの必要はなく、ただインポートすればOKです。

次に、クラスの定義をしています。またこのクラスはunittest.TestCaseを継承しています。

1
class TestStringMethods(unittest.TestCase):

クラス内で3つのメソッドを定義しています。これらがテストケースに相当します。

1
2
def test_upper(self):
...

最後にメイン関数でunittest.main()を実行します。ここでテストが実行されることになります。

1
2
if __name__ == '__main__':
unittest.main()

さて、先ほどのスクリプトを実行してみましょう。

1
python3 test_modlue.py
1
2
3
4
5
...
----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

上記のように出力されれば成功です。
3件のテスト全てに成功したことがわかります。

コマンドライン実行

-mオプションを使うことでモジュールを実行することができるため、下記のようにテストすることもできます。

Python -mオプションの仕組みも参照)

この場合、スクリプト内でメイン関数を実行する必要はありません。

1
python3 -m unittest test_module
1
python3 -m unittest test_module.py

テストに失敗した場合

コードを書き換えてテストを失敗させてみましょう。

1
2
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOOO')

テストを実行しましょう。

1
2
3
4
5
6
7
8
9
10
AssertionError: 'FOO' != 'FOOO'
- FOO
+ FOOO
? +


----------------------------------------------------------------------
Ran 3 tests in 0.001s

FAILED (failures=1)

1件で失敗したことがわかります。わかります。

詳細の表示

-vオプションをつけることで詳細を表示することができます

1
python3 -m unittest test_module -v
1
python3 test_module.py -v

のように実行します。

1
2
3
4
5
6
test_isupper (__main__.TestStringMethods) ... ok
test_split (__main__.TestStringMethods) ... ok
test_upper (__main__.TestStringMethods) ... ok

----------------------------------------------------------------------
Ran 3 tests in 0.001s

このように詳細に結果を得られます。

失敗時

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
test_isupper (__main__.TestStringMethods) ... ok
test_split (__main__.TestStringMethods) ... ok
test_upper (__main__.TestStringMethods) ... FAIL

======================================================================
FAIL: test_upper (__main__.TestStringMethods)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_module.py", line 6, in test_upper
self.assertEqual('foo'.upper(), 'FOOO')
AssertionError: 'FOO' != 'FOOO'
- FOO
+ FOOO
? +


----------------------------------------------------------------------
Ran 3 tests in 0.001s

FAILED (failures=1)

どのケースが成功したかが表示される分、やはりわかりやすいですね。

長くなりそうなので、続きは次回!

Python test入門 その2

記事情報

  • 投稿日:2020年4月8日
  • 最終更新日:2020年4月10日

主成分分析(PCA)を実装する

はじめに

この記事ではPythonで主成分分析(PCA)の実装を行います。

まずはじめにscikit-learnを用いて実装した後に、

NumPyのみを利用して、自前での実装を試みます。

実装

scikit-learn

まずはscikit-learnを使ってみます。

データにはフィッシャーのアヤメを用います

1
2
3
4
5
6
7
8
9
10
11
12
from sklearn.datasets import load_iris
import numpy as np
iris = load_iris()
X = iris.data
from sklearn.decomposition import PCA
pca = PCA()
X_ = (X - X.mean(axis=0))/X.std(axis=0) # 標準化
X_new = pca.fit_transform(X_)
print (pca.explained_variance_)
print (pca.explained_variance_ratio_) # 寄与率
print (pca.components_)
print (X_new[0]) # 変換後データの先頭レコード

pca.explained_variance_ratio_は、変換後の各主成分の寄与率を表しています。
pca.explained_variance_pca.components_が何者なのかは今後わかります。

固有値分解

次に固有値分解を用いた実装を行います。

主成分分析は、データの分散共分散行列の固有値分解に帰着できます。確認してみましょう。

1
2
3
4
5
6
7
8
9
10
11
class MyPCA:
def __init__(self):
pass
def fit_transform_eig(self, X):
X = (X - X.mean(axis=0))/X.std(axis=0)
cov = np.cov(X.T)
l, v = np.linalg.eig(cov)
self.explained_variance_ = l # 固有値
self.explained_variance_ratio_ = self.explained_variance_ / self.explained_variance_.sum()
self.components_ = v # 固有ベクトル
return X.dot(v)
1
2
3
4
5
6
pca = MyPCA()
X_new = pca.fit_transform_eig(X)
print (pca.explained_variance_) # 固有値に相当
print (pca.explained_variance_ratio_) # 寄与率
print (pca.components_) # 固有ベクトルに相当
print (X_new[0])

先ほどと全く同じ結果が得られたはずです。

さて、ここでpca.explained_variance_が固有値に相当することが分かります。そして、その和が1になるように規格化したのがpca.explained_variance_ratio_となります。

また、pca.components_が固有ベクトルに相当することが分かります。

特異値分解

次に特異値分解を用いて実装することもできます。実際、scikit-learnの主成分分析は特異値分解で実装されています。

これは対称行列の特異値と固有値が等しく、かつ分散共分散行列は対称行列であるためです。

1
2
3
4
5
6
7
8
9
10
11
class MyPCA:
def __init__(self):
pass
def fit_transform_svd(self, X):
X = (X - X.mean(axis=0))/X.std(axis=0)
cov = np.cov(X.T)
U, s, V = np.linalg.svd(cov)
self.explained_variance_ = s # 特異値
self.explained_variance_ratio_ = self.explained_variance_ / self.explained_variance_.sum()
self.components_ = U # 左特異ベクトル(この場合V.Tも同じ)
return X.dot(V.T)
1
2
3
4
5
6
pca = MyPCA()
X_new = pca.fit_transform_svd(X)
print (pca.explained_variance_) # 特異値に相当
print (pca.explained_variance_ratio_) # 寄与率
print (pca.components_) # 左特異ベクトルに相当
print (X_new[0])

分散共分散行列が対称行列であるため、固有値と特異値、固有ベクトルと特異ベクトルが等しくなっていることも確認できます。

まとめ

NumPyの固有値分解や特異値分解を使って、scikit-learnPCAを再現することができました。

記事情報

  • 投稿日:2020年4月7日
  • 最終更新日:2020年4月7日

asyncioについて

はじめに

asyncioはasync/await構文を使い、並行処理のコードを書くためのライブラリです。

基本的な概念

  • イベントループ

    イベント(何らかのアクション)を待機するためのメカニズムです。

  • コルーチン

    途中で実行を止めることができる関数のようなものだと理解してください。

実践

コルーチンの実行

まずは、基本であるコルーチンを動かしてみましょう。

コルーチンの実行方法は3つありますが、Python3.6で書くと以下のようになります。
3.7以降では、asyncio.run()asyncio.create_task()ができる)

コルーチンの宣言は簡単で、通常の関数のように宣言を行えば良いです。

ただし、defの前にasyncを付けます。

コード

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import asyncio
async def f(n):
print (n, "start")
await asyncio.sleep(1)
print (n, "end")

async def g(n):
await f(n)

async def h(n):
loop = asyncio.get_event_loop()
task = loop.create_task(f(n))
await task

loop = asyncio.get_event_loop() # イベントループの生成
loop.run_until_complete(f(1)) # コルーチンをイベントループに直接渡す
loop.run_until_complete(g(2)) # コルーチンの内部でawaitコルーチンとしてイベントループに渡す
loop.run_until_complete(h(3)) # タスクとしてイベントループに渡す

startと出力し、1秒待ったのちendと出力するコルーチンfを定義し、3つの方法で実行しました。

タスク

さて、これだと通常の関数と比較した際のメリットが全く見えませんね。

そこでタスクを複数使って、非同期な処理を実装してみましょう。

コード

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import asyncio
async def f(n):
print (n, "start")
await asyncio.sleep(1)
print (n, "end")

async def g():
loop = asyncio.get_event_loop()
task1 = loop.create_task(f(1))
task2 = loop.create_task(f(2))
await task1
await task2

loop = asyncio.get_event_loop() # イベントループの生成
loop.run_until_complete(g()) # コルーチンの内部でawaitコルーチンとしてイベントループに渡す

実行結果を見るとわかるのですが、task1の終了を待たずしてtask2の実行が始まっていることが確認できます。

awaitとは

ここでawaitが何者なのか考えましょう。

先ほどのコルーチンgを書き換えます。

コード

1
2
3
4
5
6
async def g():
loop = asyncio.get_event_loop()
task1 = loop.create_task(f(1))
await task1
task2 = loop.create_task(f(2))
await task2

今度は期待するような非同期処理が行われなかったはずです。

これはtask1を作成した直後にawaitしてしまったためです。

awaitは処理が完了するまで、コルーチンやタスクをブロックします。つまり、完了するまでプログラムが進まないということになります。

ただし、何でもかんでもawaitをつけられるわけではなく、awaitableなオブジェクトにのみ付与が可能なので注意が必要です。

記事情報

  • 投稿日:2020年4月6日
  • 最終更新日:2020年5月4日

ABC161D Lunlun Number

問題

https://atcoder.jp/contests/abc161/tasks/abc161_d

方針

  • ルンルン数を、1番目から順に作成していきK番目のルンルン数を作成する

    ポイント

  • 1桁の自然数(1~9)は全てルンルン数である。
  • あるルンルン数Xが与えられた時、文字列Xの末尾に特定の文字を書き足すことで新たなルンルン数Yを作成することができる。
    • 書き足す文字の候補は、Xの末尾の文字をsとしてs-1, s, s+1である。
      • s=0の場合: s, s+1
      • s=9の場合: s-1, s
      • それ以外の場合: s-1, s, s+1
    • この時、明らかにX < Yである
    • 逆に、n>2として、あるn桁のルンルン数Yがある時、Yの先頭からn-1桁をスライスした数Xもまたルンルン数である。
      • Yに対してXはただ一つのみ存在する

アルゴリズム

上記の性質を使うと、

  1. 1~9が格納されたキューを用意する
  2. デキューする。その数から新たなルンルン数を2または3個作成、エンキューする。このステップを繰り返す。

ことで、K番目のルンルン数を得ることができる。

コード

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import queue
q = queue.Queue()
for i in range(1,10):
q.put(i)
K = int(input())
for k in range(K):
x =q.get()
last = x % 10
if last != 0:
q.put(10*x + last - 1)
q.put(10*x + last)
if last != 9:
q.put(10*x + last + 1)
print (x)

記事情報

  • 投稿日:2020年4月5日
  • 最終更新日:2020年4月5日

ABC161C Replacing Integer

問題

https://atcoder.jp/contests/abc161/tasks/abc161_c

方針

シミュレーションを考える。

  1. 操作を繰り返しxとKの値を近づける。
  2. 最終的にはxはK以下となり、下記のどちらかパターンになる。
    • xは一定となる
    • xは周期2で振動する

ポイント

  • 「操作の繰り返し」は剰余の計算に対応する。

コード

1
2
3
N,K = map(int,input().split())
N = N % K
print (min(N,K-N))

記事情報

  • 投稿日:2020年4月4日
  • 最終更新日:2020年4月4日

PySimpleGUIでマインスイーパ

PySimpleGUIとは

Pythonで簡単にGUIを作成するためのライブラリです。
https://pysimplegui.readthedocs.io/en/latest/

PythonでGUIを作成する際は、tkinter、Qt、Remi、WxPythonなどを使いますが、簡単な実装でもコード量が多くなりがちです。

それを解決するのがPySimpleGUIで、上記の軽量なラッパーとして機能します。

標準ライブラリではないので、各自インストールしてください。

1
2
3
pip install pysimplegui
or
pip3 install pysimplegui

基本的な使い方

sg.popup

1
2
3
4
5
6
7
8
sg.popup('popup')  # Shows OK button
sg.popup_ok('popup_ok') # Shows OK button
sg.popup_yes_no('popup_yes_no') # Shows Yes and No buttons
sg.popup_cancel('popup_cancel') # Shows Cancelled button
sg.popup_ok_cancel('popup_ok_cancel') # Shows OK and Cancel buttons
sg.popup_error('popup_error') # Shows red error button
sg.popup_timed('popup_timed') # Automatically closes
sg.popup_auto_close('popup_auto_close') # Same as PopupTimed

ボタンのメッセージやポップアップのタイトルを変えることもできます。

1
sg.popup('マスに対する操作を選択してください',custom_text=('open', 'flag'),title='')

sg.Button

例えば二つのボタンを並べて表示しする場合は以下のように使います。

1
layout =  [[sg.Button('0'),sg.Button('1')]]

マインスイーパ

公式のサンプルコードとしてマインスイーパがあるのですが、GUIを提供するのみでゲームロジックが組まれていませんでした。

そこでシンプルなルールのみで実装しました。

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
32
33
34
35
36
37
38
39
40
import PySimpleGUI as sg
from random import randint
import numpy as np
from scipy import signal
MAX_ROWS = MAX_COL = 10
board = [[randint(0,1) for j in range(MAX_COL)] for i in range(MAX_ROWS)]
board = np.zeros(MAX_ROWS*MAX_COL).astype(np.int)
idx = np.random.choice(len(board), 3, replace=False) # 爆弾をランダムに3箇所設置
board[idx] = 1
board = board.reshape(MAX_ROWS, MAX_COL).tolist()
filter = np.array([ # 二次元畳み込みで爆弾の数をカウント
[1,1,1],
[1,0,1],
[1,1,1]
])
counter = signal.convolve2d(board, filter, 'full') # 畳み込みとサイズが大きくなるので、
board = counter[1:-1,1:-1] - board # スライスする。ここでboardを引くことで、爆弾マスは-1になる
print (board)
board = board.tolist()
layout = [[sg.Button('?', size=(4, 2), key=(i,j), pad=(0,0)) for j in range(MAX_COL)] for i in range(MAX_ROWS)]
window = sg.Window('Minesweeper', layout)
while True:
event, values = window.read()
print (event,values)
if event in (None, 'Exit'):
break
select = sg.popup('マスに対する操作を選択してください',custom_text=('open', 'flag'),title='')
print('select', select)
if select is 'open':
window[event].update(board[event[0]][event[1]], button_color=('white','black'))
if board[event[0]][event[1]]==-1:
sg.popup("You Lose")
break
elif select is 'flag':
state = window[event].GetText()
if state == '?':
window[event].update('F', button_color=('red',None))
elif state == 'F':
window[event].update('?', button_color=('white',None))
window.close()

ポイント

爆弾のカウント

フィルタを用意して畳み込みを行うことで周囲の爆弾をカウントしています。

1
2
3
[1,1,1],
[1,0,1],
[1,1,1]

フラグ機能

マスをクリックするとポップアップが開き、「マスを開く」か「フラグをON/OFFする」か選択ができます。
GetTextで格納されている値が取得できるので、これを用いてF(フラグON)?(デフォルト、フラグOFF)を切り替えます。

1
2
3
4
5
state = window[event].GetText()
if state == '?':
window[event].update('F', button_color=('red',None))
elif state == 'F':
window[event].update('?', button_color=('white',None))

日本語版コマンドクリックリファレンス

日本語版のコマンドクイックリファレンスをKindleで購入できます。Kindle Unlimitedでも読むことができます。
ただし、kindleで販売されているものは内容は分割版(抜粋)となっています。内容が良さそうでしたら、フルのpdfを購入されると良いと思います。
購入方法も記載されています。

宣伝

機械学習エンジニアを目指している方向けに、書籍を出しました。
サクッと読める内容ですので是非お手に取ってみてください。

記事情報

  • 投稿日:2020年4月3日
  • 最終更新日:2020年8月28日

Pythonで並行/並列処理 concurrent.futuresの紹介

concurrent.futures

Pythonで非同期実行を行うためのモジュールです。

標準ライブラリに含まれているのでインストールの必要はありません。

なお、concurrentパッケージに含まれるモジュールは現時点でfuturesのみです。

実装

マルチスレッドの場合、ThreadPoolExecutorを用います。

1秒かかる処理funcを8回実行したいとしましょう。

1
2
3
4
5
6
7
8
9
from concurrent.futures import ThreadPoolExecutor
import time
def func():
time.sleep(1)
start = time.time()
with ThreadPoolExecutor(max_workers=4) as e:
for i in range(8):
e.submit(func)
print (time.time()-start)

ThreadPoolExecutor(max_workers=4)としてワーカーを4つ作成しています。
そのため処理が8/4=2で約2秒で終わります。

では、ワーカーを6つに増やすとどうでしょうか。考えてから実行してみてください。

マルチプロセスの場合、ProcessPoolExecutorを用います。

1
2
3
4
5
6
7
8
9
from concurrent.futures import ProcessPoolExecutor
import time
def func():
time.sleep(1)
start = time.time()
with ProcessPoolExecutor(max_workers=4) as e:
for i in range(8):
e.submit(func)
print (time.time()-start)

マルチプロセスでも同様の高速化ができましたね。

今回のケースでは、速度面では違いはありません。

解説

funcと呼ばれるI/Oバウンドな処理を模擬した関数を実装しています。

I/Oバウンドとは、I/Oに負荷がかかることを意味しており、
ディスクの読み書きが遅い場合や通信の遅延が大きい場合に当たります。

I/Oバウンドに対しては、マルチスレッドとマルチプロセスはいずれも有効です。
(サンプルコードの通り)

一方、CPUバウンドな処理については、マルチスレッドによる高速化は期待できませんので使い分けに注意してください。

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
from concurrent.futures import ThreadPoolExecutor
import time
def func():
s = 0
for i in range(10000000):
s += 1
# 逐次処理
start = time.time()
for i in range(8):
func()
print (time.time()-start)

# マルチスレッド
start = time.time()
with ThreadPoolExecutor(max_workers=4) as e:
for i in range(8):
e.submit(func)
print (time.time()-start)

# マルチプロセス
start = time.time()
with ProcessPoolExecutor(max_workers=4) as e:
for i in range(8):
e.submit(func)
print (time.time()-start)

逐次処理とマルチスレッドの違いはあまりなく、マルチプロセスが最も速いはずです。

記事情報

  • 投稿日:2020年4月2日
  • 最終更新日:2020年5月4日

PyQを3ヶ月毎日やってみた感想

はじめに

私は業務でPythonを少し触るエンジニアです。

Pythonの復習をかねて、PyQを3ヶ月間毎日解いてみました。

この記事はその個人的な感想です。

PyQとは

Pythonが学習できるオンラインのサービスです。

コンテンツ

クエストと呼ばれる問題のセットを解いていきます。

PyQ上にJupyte Notebook形式でコーディングしていきます。

  • 左側に問題が表示
  • 右側にノートブックが表示

されます。

そして判定ボダんをクリックするとテストが走る仕組みです。

私が感じたメリット・デメリット

メリット

  1. 扱っている分野が広い
    Pythonは非常に多くの用途で使われている言語です。

    PyQでは

    • 基本文法

    • 標準ライブラリ

    • Webアプリ

    • 統計

    • 機械学習

      など広く学ぶことができます。

      そして、とにかくクエストが多いので3ヶ月毎日30分取り組んだ程度では20%くらいしか終わりませんでした。それくらい、ボリュームがあります。そして、どんどんクエストが追加されます

  2. 草が生えるのでモチベーションが上がる
    GitHubのように草が生えます。

    とても単純ですが毎日続けていると、

    「今日も草を絶やさないようにしよう!」

    と継続する動機になります。

  3. コーディングがメインの教材である
    PyQでは、コードテストが通るかが全てです。

    ですので内容を理解していれば、説明半分に実装に移ればよくサクサク進みます。

    (一方、タイポがあれば全然進まないので、変なところで詰まる場合もあります。)

    あたり前ですが、プログラミングの勉強をしているのでコードを書かないと話になりません。

    そういう意味でいうと、とにかくコードを書かせるスタイルのPyQで学べば、毎日コードを読み、書く習慣ができるので良いと思います。

デメリット

  1. 復習が難しい
    「あの操作はどこで勉強したのかな?」となることがあるのですが、
    教材(問題と回答)がクエストに紐づいているため、探すことが難しいです。

    学習ノートと呼ばれるメモ書きを残す機能があるのですが、
    こちらについては、後でどう参照するかがわかりませんでした。

    そのため、「ここはメモをとりたい!」という場面では、
    PyQ以外のツールで、どのクエストでどういうポイントがあったかを記録すると良いと思います。

  2. 形骸化してしまう
    メリットにあげた「草が生えるのでモチベーションが上がる」の裏返しですが、逆に草を絶やさないように学習が形骸化してしまう恐れがあります。

    特にPyQでは簡単な脳死でできてしまうクエストもあるので、きちんと学習負荷がかかっていることを意識すると良いと思います。

  3. 難易度が低いものもある
    これもメリットの裏返しで「扱っている分野が広い」分、掘り下げて学びたいところで講座が終わってしまったりします。

    PyQで想定しているレベルは初心者〜中級者だと思うので、Python経験者の場合

    • 専門分野以外の知識もつけたい
      という動機であればOKですが
    • 専門分野を掘り下げたい
      という動機だと、別の教材を使うのが良いのかなと思います。

まとめ

PyQはとても素晴らしい教材でした。

ただし、難易度の話など自分にあった教材かを見極めて使うのが良いと思います。

(レベル的にはprogate卒業してから使って見るのが良いです)

記事情報

  • 投稿日:2020年4月1日
  • 最終更新日:2020年4月1日

ゼロから始める機械学習 第6回「scikit-learnの活用」

はじめに

この記事は、連載「ゼロから始める機械学習」 6本目のラスト記事となります。

前回「学習データとテストデータ」 では、データを分割する必要性について理解し、train_test_splitを実装しました。

これで基本的な機械学習の流れを理解できたのではないでしょうか。

実はこれまでに実装してきた

  • ロジスティック回帰
  • train_test_split

scikit-learnライブラリに実装されています。

勉強のためにNumPyを用いてきましたが、実際のシーンではscikit-learnを使うことも多いでしょう。そこで、次回はこれらの内容をscikit-learnを用いて実装し直してみます。

実装

実は説明すべき箇所はほとんどありません。

これまでの実装のインターフェイスはscikit-learnに合わせていたためです。

1
2
3
4
5
6
7
8
9
from sklearn.datasets import load_iris
import numpy as np
iris = load_iris()
X_org = iris.data
y_org = iris.target
# 問題の簡単化(前回記事を参照)
idx = [y_org != 2]
X = X_org[idx][:,:2]
y = y_org[idx]
1
2
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.2)
1
2
3
4
5
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression()
lr.fit(X_train, y_train) # 学習
pred = lr.predict(X_test) # 予測と評価
print (np.mean(pred == y_test)) # 平均正解率

インターフェイスを合わせたと言いましたが、厳密には私たちが実装したpredictは確率を返します一方、scikit-learnpredict0または1を返す点が異なるので注意してください。

前回のコードと比較すると一目瞭然、かなり簡単に実装できました!

まとめ

お疲れ様でした。

連載のゴールであった簡単な機械学習プログラムの実装ができるレベルに達したでしょうか。

ここまで着いてこれた方であれば、きっとプログラムが実装できる!

さて、原理を理解しながらNumPyで実装する方法を学んだので、今度はscikit-learnを使いこなせるようにステップアップしましょう。

連載「scikit-learnで学ぶ機械学習」を始めます)

では、scikit-learnを用いて機械学習について学んでいきます。

データ分析とは何か?機械学習との関係について

では、データ分析と機械学習の関係についてまとめています。

記事情報

  • 投稿日:2020年3月31日
  • 最終更新日:2020年3月31日