Cucco’s Compute Hack

コンピュータ関係の記事を書いていきます。

Visual Stuido Code & Anaconda環境構築(その2)

vscodeでanacondaを使うと出るエラーの対策。a以下のコマンドを実行すると、対処できるかも。

conda init
エラーの内容
PS C:\dev> C:/Users/<ユーザー名>/Anaconda3/Scripts/activate
PS C:\dev> conda activate base
conda : 用語 'conda' は、コマンドレット、関数、スクリプト ファイル、または操作可能なプログラムの名前として認識されません。
名前が正しく記述されていることを確認し、パスが含まれている場合はそのパスが正しいことを確認してから、再試行してください。
発生場所 行:1 文字:1
+ conda activate base
+ ~~~~~
    + CategoryInfo          : ObjectNotFound: (conda:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

移動平均(numpy.convolve利用)1次元

関連記事に乗せている2次元よりは1次元のほうが使い勝手がよさそうなので書き換え。

起点からwindowsizeの範囲で合計するだけではなくて、起点側を,ignoresize個を無視して合計するような形にしている。

np.convolveの2つ目の引数の割当たりかたが想像の逆なので、v=np.flip(v) で反転している。

ソースコード

import numpy as np

def np_moving_sum(data_1d,windowsize=3,ignoresize=0):
    '''
    1次元のリスト or np.array
    '''
    if  data_1d is None:
        data_1d = [1,2,3,5,8,13,21,34,55,89]

    if type(data_1d) == np.ndarray:
        np_data_1d=data_1d
    elif  type(data_1d) == list:
        np_data_1d=np.array(data_1d)

    # np_data_1d.shape は、(10,)
    answer = np.zeros(np_data_1d.shape)
    answer[:] = np.nan
    # vの長さが3の時
    # v[0]=0 3番目にマッピングされる
    # v[1]=1 2番目にマッピングされる
    # v[2]=0 1番目にマッピングされる

    v = np.ones(windowsize)
    v[0:ignoresize]=0
    v=np.flip(v)

    answer[: np_data_1d.shape[0] - windowsize + 1 ]=np.convolve(np_data_1d, v, mode = "valid")

    return answer

def np_moving_average(data_1d,windowsize=3,ignoresize=0):
    return np_moving_sum(data_1d,windowsize,ignoresize)/(windowsize-ignoresize)

if __name__ == "__main__":
    data_1d = [1,2,3,5,8,13,21,34,55,89]
    print(data_1d,'\n')
    print(np_moving_sum(data_1d=data_1d,windowsize=3,ignoresize=2))
    print(np_moving_sum(data_1d=data_1d,windowsize=3,ignoresize=1))
    print(np_moving_sum(data_1d=data_1d,windowsize=3,ignoresize=0))
    print('\n')
    print(np_moving_sum(data_1d=data_1d,windowsize=4,ignoresize=3))
    print(np_moving_sum(data_1d=data_1d,windowsize=4,ignoresize=2))
    print(np_moving_sum(data_1d=data_1d,windowsize=4,ignoresize=1))
    print(np_moving_sum(data_1d=data_1d,windowsize=4,ignoresize=0))
    print('\n')
    print(np_moving_average(data_1d=data_1d,windowsize=3,ignoresize=2))
    print(np_moving_average(data_1d=data_1d,windowsize=3,ignoresize=1))
    print(np_moving_average(data_1d=data_1d,windowsize=3,ignoresize=0))
    print('\n')
    print(np_moving_average(data_1d=data_1d,windowsize=4,ignoresize=3))
    print(np_moving_average(data_1d=data_1d,windowsize=4,ignoresize=2))
    print(np_moving_average(data_1d=data_1d,windowsize=4,ignoresize=1))
    print(np_moving_average(data_1d=data_1d,windowsize=4,ignoresize=0))

実行結果

(base) C:\>python lib_moving_calcs_np.py
[1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

[ 3.  5.  8. 13. 21. 34. 55. 89. nan nan]
[  5.   8.  13.  21.  34.  55.  89. 144.  nan  nan]
[  6.  10.  16.  26.  42.  68. 110. 178.  nan  nan]


[ 5.  8. 13. 21. 34. 55. 89. nan nan nan]
[  8.  13.  21.  34.  55.  89. 144.  nan  nan  nan]
[ 10.  16.  26.  42.  68. 110. 178.  nan  nan  nan]
[ 11.  18.  29.  47.  76. 123. 199.  nan  nan  nan]


[ 3.  5.  8. 13. 21. 34. 55. 89. nan nan]
[ 2.5  4.   6.5 10.5 17.  27.5 44.5 72.   nan  nan]
[ 2.          3.33333333  5.33333333  8.66666667 14.         22.66666667
 36.66666667 59.33333333         nan         nan]


[ 5.  8. 13. 21. 34. 55. 89. nan nan nan]
[ 4.   6.5 10.5 17.  27.5 44.5 72.   nan  nan  nan]
[ 3.33333333  5.33333333  8.66666667 14.         22.66666667 36.66666667
 59.33333333         nan         nan         nan]
[ 2.75  4.5   7.25 11.75 19.   30.75 49.75   nan   nan   nan]

DBのテーブルから列データをリストで取得する

DBのテーブルから列データをリストで取得する。fetch()で取得すると、行ごとのタプルのリストになっていて、処理しづらいので、ほしい列の値だけをリストにする関数get_one_column_data_list()を作成。
リストのメモリ確保のため、件数確認のget_countも作成。

get_one_column_data_list()は、リスト化したときの順番をソート済みで取得することも可能。

プログラム
import sqlite3
import random
from faker import Faker

def get_count(database, table_name):
    cur = database.cursor()
    sql_count = "SELECT COUNT (*) FROM {0}".format(table_name)
    d = cur.execute(sql_count).fetchone()
    # dは、(100,)のような形になっている
    cur.close()
    return d[0]

def get_one_column_data_list(database, table_name, column_name, target_column_index=0, column_orderby=None):
    data_size = get_count(database, "data")
    data_list = [None]*data_size

    if column_orderby == None:
        sql_select = "SELECT {0} FROM {1}".format(column_name, table_name)
    else:
        sql_select = "SELECT {0} FROM {1} ORDER BY {2} asc".format(
            column_name, table_name, column_orderby)

    cur = database.cursor()
    d = cur.execute(sql_select)

    for index, row in enumerate(d):
        data_list[index] = row[target_column_index]

    cur.close()

    return data_list

if __name__ == "__main__":

    con = sqlite3.connect(":memory:")
    con.isolation_level = None  # None で自動コミットモード
    cur = con.cursor()
    cur.execute('PRAGMA temp_store=MEMORY;')
    cur.execute('PRAGMA journal_mode=MEMORY;')

    sql_create_table = "CREATE TABLE data(number INTEGER UNIQUE, name TEXT, score REAL)"
    sql_instert_data = "INSERT INTO data VALUES(?,?,?)"

    fake = Faker()
    listsize = 8
    list_data = [None] * listsize

    print("データ準備 開始")
    for i in range(listsize):
        list_data[i] = [i, fake.name(), random.random()]
        print(list_data[i])
    print("データ準備 完了")

    cur.execute(sql_create_table)
    cur.executemany(sql_instert_data, list_data)

    table_name = "data"
    column_name = "score"
    column_orderby = "name"

    data_list = get_one_column_data_list(
        con, table_name, column_name, target_column_index=0, column_orderby=column_orderby)

    print(data_list)
実行結果
>python C:\dev\SampleCodes\hello_sqlite\select_one_col.py
データ準備 開始
[0, 'Taylor Smith', 0.6560666934413109]
[1, 'Jesse Carrillo', 0.9199740526758551]
[2, 'Tina Gonzalez', 0.8344908595983038]
[3, 'Richard Mckinney', 0.1240783472168423]
[4, 'Victoria Pace', 0.25291942565400816]
[5, 'Steven Craig', 0.0703249952634678]
[6, 'Valerie Mitchell', 0.0015255246599048533]
[7, 'Victoria Hill', 0.9645617001034171]
データ準備 完了
[0.9199740526758551, 0.1240783472168423, 0.0703249952634678, 0.6560666934413109, 0.8344908595983038, 0.0015255246599048533, 0.9645617001034171, 0.25291942565400816]

分割してCSVに書く、分割されたCSVを読む

1年前のプログラムの一部改良。
複数ファイルを連続して読むプログラム - Cucco’s Compute Hack

ディレクトリのパスと、ファイル名(拡張子ナシ、連番ナシ)を与えて、
決まった行数を書いたファイルを保存する、それらのファイルを開いて読む、というプログラム。

読む場合は以前から継続で、イテレータを利用できるようにした。
読むファイルをすべてリストで指定していたが、pathlibで一覧を取得している。

プログラム
import csv
from pathlib import Path
import os

from faker import Faker
import random


class split_csv_writer:
    '''
    渡された値をファイルに書き落としていく
    max_linesを超えたら、別のファイルに変更する。
    '''

    def __init__(self, dirctory_path, filename_wo_extension, header_data=None, max_lines=100000):
        self.max_lines = max_lines
        if header_data == None:
            self.max_lines = max_lines-1
        self.currnet_lines = self.max_lines+1  # 初回にOpenを実行してもらうため。

        self.currnet_file_post_index = 0
        self.filename = filename_wo_extension
        self.f = None
        self.dirctory_path = dirctory_path
        self.header_data = header_data

        self.delete_existing_files()

    def close(self):
        # デストラクタでも呼んでいる
        self.currnet_file_post_index = self.currnet_file_post_index+1
        if self.f != None:
            self.f.flush()  # 実際には、ファイルに書き込みしてくれないことがあったので追加。
            self.f.close()
        self.f = None

    def delete_existing_files(self):
        p = Path(self.dirctory_path)
        r = self.filename+"*.csv"
        for existing_file_path in p.glob(r):
            print("削除します ", existing_file_path)
            os.remove(existing_file_path)

    def __del__(self):
        self.close()

    def open(self):
        if self.f == None:
            pass
        else:
            self.close()

        real_filename = self.dirctory_path + self.filename + \
            "_{0:08d}.csv".format(self.currnet_file_post_index)

        os.makedirs(self.dirctory_path, exist_ok=True)

        self.f = open(real_filename, 'w', encoding='utf-8')
        self.csv_writer = csv.writer(
            self.f, delimiter=',', quotechar='"', lineterminator='\n')
        self.currnet_lines = 0
        print("新規作成 ", real_filename)

    def writerow(self, input_data):
        '''
        input_dataには、リストかタプルでデータを与える。
        '''
        if self.currnet_lines > self.max_lines:
            self.open()
            if self.header_data != None:
                self.writerow(self.header_data)

        self.csv_writer.writerow(input_data)
        self.currnet_lines = self.currnet_lines+1


class split_csv_reader:
    def __init__(self, dirctory_path, readfilename_wo_extention, skipHeader=False):
        self.filename = readfilename_wo_extention
        self.currentFileIndex = -1
        self.fp = None
        self.csv_reader = None
        self.skipHeader = skipHeader
        self.dirctory_path = dirctory_path
        self.set_readFileNames()

    def set_readFileNames(self):
        self.readFileNames = []
        p = Path(self.dirctory_path)
        r = self.filename+"*.csv"
        for existing_file_path in p.glob(r):
            self.readFileNames.append(existing_file_path)

        # ⃣print(self.readFileNames)

    def __iter__(self):
        # next()はselfが実装してるのでそのままselfを返す
        return self

    def __next__(self):

        if self.csv_reader is None:
            # 1個目のファイルを開く
            self.nextfile()

        try:
            value = next(self.csv_reader)
            return value
        except StopIteration:
            # 終端まで来たら、このStopIterationが投げられる。
            try:
                self.nextfile()
                value = next(self.csv_reader)
                return value
            except StopIteration:
                # 次のファイルがなかったので、例外を投げてイテレータを終わる。
                # ファイルがロックされている場合もここに来るので、問題になる可能性あり。
                raise (StopIteration)
        except:
            # ここには来ない。
            raise (StopIteration)

    def nextfile(self):
        self.currentFileIndex = self.currentFileIndex + 1
        if self.fp is not None:
            self.fp.close()
        if self.currentFileIndex > len(self.readFileNames)-1:
            # 次のファイルはないので例外を投げる
            raise(StopIteration)
        else:
            self.fp = open(
                self.readFileNames[self.currentFileIndex], mode='r', newline='\n')
            self.csv_reader = csv.reader(self.fp, delimiter=',', quotechar='"')

            if self.skipHeader is True:
                next(self.csv_reader)
                # ⃣print(value)

# 動作確認用プログラム
if __name__ == "__main__":
    dirname = r"C:/lib_split_test/"  # 最後はos.sepで終わるように指定する
    filename = r"lib_split_test"

    print("#書き込みのテスト")
    headerdata = ("#", "Name", "score")
    writer = split_csv_writer(
        dirname, filename, header_data=headerdata, max_lines=3)

    fake = Faker()
    for i in range(1, 10+1):  # 最後の値は実行されないrange(1,10+1)で、1~10
        data = [i, fake.name(), random.random()]
        writer.writerow(data)
        print(data)
    writer.close()

    print("#読み込みのテスト")

    reader = split_csv_reader(dirname, filename, skipHeader=True)

    for item in reader:
        print(item)
実行結果
(base) C:\dev\ > python C:\dev\lib_sprit_csv_reader_writer.py
#書き込みのテスト
削除します  C:\lib_split_test\lib_split_test_00000000.csv
削除します  C:\lib_split_test\lib_split_test_00000001.csv
削除します  C:\lib_split_test\lib_split_test_00000002.csv
削除します  C:\lib_split_test\lib_split_test_00000003.csv
新規作成  C:/lib_split_test/lib_split_test_00000000.csv
[1, 'Carol Martinez', 0.2993282973465532]
[2, 'Monica Skinner', 0.47771227744058886]
[3, 'Stephanie Zimmerman', 0.30639552562401595]
新規作成  C:/lib_split_test/lib_split_test_00000001.csv
[4, 'Terry Williams', 0.2800113471343493]
[5, 'Scott Grant', 0.8271274374443526]
[6, 'Jose Daniels', 0.4170927481515181]
新規作成  C:/lib_split_test/lib_split_test_00000002.csv
[7, 'Adam Austin', 0.2850528257749132]
[8, 'Krista Williams', 0.9258438865231986]
[9, 'Jared Adkins', 0.6205699038539508]
新規作成  C:/lib_split_test/lib_split_test_00000003.csv
[10, 'Ryan Morales', 0.9635161039757013]
#読み込みのテスト
['1', 'Carol Martinez', '0.2993282973465532']
['2', 'Monica Skinner', '0.47771227744058886']
['3', 'Stephanie Zimmerman', '0.30639552562401595']
['4', 'Terry Williams', '0.2800113471343493']
['5', 'Scott Grant', '0.8271274374443526']
['6', 'Jose Daniels', '0.4170927481515181']
['7', 'Adam Austin', '0.2850528257749132']
['8', 'Krista Williams', '0.9258438865231986']
['9', 'Jared Adkins', '0.6205699038539508']
['10', 'Ryan Morales', '0.9635161039757013']

pythonの引数ライブラリargparse

argparseのサンプルコード。-から始まる名前にしてOptional引数にして、
action="store_true"をつけておけば、フラグとして利用できそう。

プログラム
import argparse

if __name__ == "__main__":

    parser = argparse.ArgumentParser()

    # 必須引数(=位置引数)を追加
    # type=intがない場合は文字列
    parser.add_argument(
        "square", help="display a square of a given number", type=int)
    parser.add_argument(
        "base", help="display a square of a given number", type=int)

    # Optional引数
    # 引数に -v があれば、args.verbosityはTrueになる
    parser.add_argument("-v", "--verbosity",
                        help="increase output verbosity", action="store_true")

    # Optional引数
    # とれる値の指定のある引数
    parser.add_argument("-c", "--choices", type=int,
                        choices=[0, 1, 2], help="increase output verbosity")

    args = parser.parse_args()

    # 引数の参照方法/値確認
    print(args.square**2)
    print(args.base)

    if args.verbosity:
        print("verbosity turned on ", args.verbosity)
    else:
        print("verbosity turned off ", args.verbosity)

    print("choices:", args.choices)
-h の結果
(base) c:\dev>python a00_main.py -h
usage: a00_main.py [-h] [-v] [-c {0,1,2}] square base

positional arguments:
  square                display a square of a given number
  base                  display a square of a given number

optional arguments:
  -h, --help            show this help message and exit
  -v, --verbosity       increase output verbosity
  -c {0,1,2}, --choices {0,1,2}
                        increase output verbosity
実行結果
(base) c:\dev>python a00_main.py -v -c 2 5 6
25
6
verbosity turned on  True
choices: 2

複数の2クラス分類の一括学習

タイトルでは、わけがわからないと思うが、
1種類のデータに対して、2クラス分類問題が複数ある場合の学習。
整数dに対して、2の倍数かどうかと、3の倍数かどうか、・・・を例に学習してみた。

訓練データ形式

x : 8桁のビット整数。アンダーバー2つは、xベクトルの中での次元の番号。
y0:2の倍数かどうか。
y1:3の倍数かどうか。以降5,7,11の倍数かどうか。

x__0,x__1,x__2,x__3,x__4,x__5,x__6,x__7,y0,y1,y2,y3,y4
0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,1,0,0,0,0,0
0,0,0,0,0,0,1,0,1,0,0,0,0
0,0,0,0,0,0,1,1,0,1,0,0,0
0,0,0,0,0,1,0,0,1,0,0,0,0
0,0,0,0,0,1,0,1,0,0,1,0,0
0,0,0,0,0,1,1,0,1,1,0,0,0
0,0,0,0,0,1,1,1,0,0,0,1,0
0,0,0,0,1,0,0,0,1,0,0,0,0
0,0,0,0,1,0,0,1,0,1,0,0,0
0,0,0,0,1,0,1,0,1,0,1,0,0
0,0,0,0,1,0,1,1,0,0,0,0,1

f:id:Cucco:20190530231038p:plain
学習結果
f:id:Cucco:20190530231110p:plain
ネットワーク設計
f:id:Cucco:20190530231354p:plain
学習結果

所見
  • BatchNormalization はあったほうが収束が早い。
  • ReLUは収束早い。(Sigmoidに比べて)
  • ノード数を減らして、段数を増やすより、ノード数を増やしたほうが精度が高い(今回はノイズなしだから??)
  • 分岐前のノード数は、分岐数の2倍以上あったほうが良い(?)