Cucco’s Compute Hack

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

LEFT OUTER JOINの評価

LEFT OUTER JOINの評価

一瞬で終わる。メモリも食わない。
UNIQUE属性付けておくとさらに早い。

実施内容

データのテーブルと、クラス分け結果のテーブルのJoin。
クラス分け結果は適当に%演算で作った。

ソースコード
import sqlite3
from faker import Faker
import random
from datetime import datetime

tic0 = datetime.now()

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

listsize = 100000
classsize= 128

sql_create_data = "CREATE TABLE data(number INTEGER UNIQUE, name TEXT, score REAL)"
sql_create_class = "CREATE TABLE class(number INTEGER UNIQUE, label INTEGER)"
sql_instert_data = "INSERT INTO data VALUES(?,?,?)"
sql_instert_class = "INSERT INTO class VALUES(?,?)"

sql_select_join = "SELECT data.number, data.name, data.score, class.label FROM data LEFT OUTER JOIN class ON data.number = class.number"
sql_select_join_cl1 = "SELECT data.number, data.name, data.score, class.label FROM data LEFT OUTER JOIN class ON data.number = class.number WHERE class.label = 1 "
#list_data = [[None] for i in range(listsize)]
list_data = [None] * listsize
list_class = [None] * listsize
fake = Faker()


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

cur.execute(sql_create_data)
cur.execute(sql_create_class)
print("テーブルの定義を表示")
table_defs = cur.execute("SELECT * FROM sqlite_master WHERE type='table'")
for item in table_defs:
    print(item)

print("データの挿入")
cur.executemany(sql_instert_data, list_data)
cur.executemany(sql_instert_class, list_class)

# ここからjoin時間計測
tic = datetime.now()

cur.execute(sql_select_join)

toc = datetime.now()

print("テーブルの中身を表示")
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())

print("classが1のテーブルの中身を表示")
cur.execute(sql_select_join_cl1)
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())

print("join {0}件 処理時間 {1}".format(listsize, toc-tic))
print("全体処理時間 {0}件 処理時間 {1}".format(listsize, datetime.now()-tic0))
con.close()
結果
(base) C:\dev\SampleCodes\hello_sqlite>python outerjoin.py
データ準備 開始
データ準備 完了
テーブルの定義を表示
('table', 'data', 'data', 2, 'CREATE TABLE data(number INTEGER UNIQUE, name TEXT, score REAL)')
('table', 'class', 'class', 4, 'CREATE TABLE class(number INTEGER UNIQUE, label INTEGER)')
データの挿入
テーブルの中身を表示
(0, 'Troy Wagner', 0.44436625795068907, 0)
(1, 'Lee Robertson', 0.8527352596455694, 1)
(2, 'Mark Franco', 0.9942993187450221, 2)
(3, 'Joel Sandoval', 0.9462360044917911, 3)
(4, 'Katherine Ho', 0.6177953257612685, 4)
(5, 'Shannon Adams', 0.6044842942129696, 5)
(6, 'Jacob Wong', 0.4513990366427033, 6)
(7, 'Howard Bennett', 0.6643356684420646, 7)
(8, 'Scott Mitchell', 0.5792325135939987, 8)
(9, 'Joshua Tyler', 0.4882390253804837, 9)
(10, 'Steven Day', 0.03463822764171387, 10)
(11, 'Heather Hughes', 0.888992343863056, 11)
(12, 'Margaret Thomas DDS', 0.402020535579534, 12)
(13, 'David Rosario', 0.8354810420435498, 13)
classが1のテーブルの中身を表示
(1, 'Lee Robertson', 0.8527352596455694, 1)
(129, 'April Pittman', 0.48442848761646606, 1)
(257, 'Mercedes Gallagher', 0.9811398290695581, 1)
(385, 'Xavier Harvey', 0.39333389385880146, 1)
(513, 'Laura Powell', 0.11691465694144565, 1)
(641, 'Mrs. Lori Gibbs MD', 0.13424141037411286, 1)
(769, 'Christina Jacobson', 0.7144345369983663, 1)
(897, 'Gregory Lowe', 0.2939644032693347, 1)
(1025, 'Michael Santos', 0.9319930754332403, 1)
(1153, 'Olivia Montgomery', 0.3756360549631732, 1)
(1281, 'Joseph Eaton', 0.7451317465818261, 1)
(1409, 'Julia Adams', 0.5858535015316725, 1)
(1537, 'George Kelley', 0.12250922691704258, 1)
(1665, 'Patricia Johnson DVM', 0.09949616494939173, 1)
join 100000件 処理時間 0:00:00
全体処理時間 100000件 処理時間 0:00:14.371519

Neural Network ConsoleのCrossEntropy損失関数(ロス関数)の使い方

Neural Network Consoleの損失関数(ロス関数)の使い方の記録。
画像処理系はSquareErrorでもいいが、カテゴリ系はそんなわけにもいかないので。

入力データ次第で、ある程度決まった形になるので、記録として残しておく。

CategoricalCrossEntropyを使う場合

ラベルは、複数値のカテゴリインデックス。1列。
affineで適当な列数に変換した後、softmax -> CategoricalCrossEntropy

f:id:Cucco:20190526165910p:plain
CategoricalCrossEntropy

BinaryCrossEntropyを使う場合

ラベルは1か0の2値。
OneHot形式の2列の場合、affineで2列に変換した後、softmax -> BinaryCrossEntropy
1列の0/1の場合、affineで1列に変換した後、sigmoid(softmaxからsigmoidに訂正) -> BinaryCrossEntropy

f:id:Cucco:20190526165832p:plain
BinaryCrossEntropy

sqlite3のexecutemanyの動作確認

1回で10万件を挿入するのに、0.35秒。
別実行した1件ソートの繰り返しでは0.42秒。大した差ではないが、ループを組まなくていいメリットあり。

値を埋めたいところは、"INSERT INTO users VALUES(?,?,?)" のようにハテナにしておく。
リストのリストや、タプルのリストにしておけば、全件Insertしてくれるようす。

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

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

listsize = 100000

sql_create = "CREATE TABLE users(number INTEGER, name TEXT, score REAL)"
sql_instert = "INSERT INTO users VALUES(?,?,?)"
sql_select = "SELECT number,name,score FROM users ORDER BY number LIMIT 3"
sql_select_last = "SELECT number,name,score FROM users ORDER BY number LIMIT 3 OFFSET {0}".format(listsize-3)

list1 = [None] * listsize
fake = Faker()

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

cur.execute(sql_create)
print("テーブルの定義を表示")
tmp = cur.execute("SELECT * FROM sqlite_master WHERE type='table'").fetchall()
print(tmp)

# ここからexecutemany時間計測
tic = datetime.now()

print("データの挿入")
cur.executemany(sql_instert, list1)

# executemany時間計測終わり
toc = datetime.now()

cur.execute(sql_select)
print("テーブルの中身を表示")
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print()
cur.execute(sql_select_last)
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())

print()
print("executemany {0}件 処理時間 {1}".format(listsize, toc-tic))

con.close()
実行結果
(base) C:\dev\SampleCodes\hello_sqlite>python execmeny.py
データ準備 開始
データ準備 完了
テーブルの定義を表示
[('table', 'users', 'users', 2, 'CREATE TABLE users(number INTEGER, name TEXT, score REAL)')]
データの挿入
テーブルの中身を表示
(0, 'Dawn West', 0.5244752623689407)
(1, 'Marvin Chambers', 0.8354440852719125)
(2, 'Clinton Lowe', 0.4116042084368037)

(99997, 'Aaron Conley', 0.795391969430207)
(99998, 'Alyssa Brooks', 0.17316654138026266)
(99999, 'Marisa Peterson', 0.018786705346994004)

executemany 100000件 処理時間 0:00:00.350097

sqlite3とpandasの連動確認

やっていること

0. sqliteのDB(インメモリ)の用意
1. データ準備
2. sqliteのDB(インメモリ)に書き込み
3. sqliteのDB(インメモリ)のテーブル定義を確認
4. sqliteのDB(インメモリ)のテーブルの内容を確認 ORDER BY numberでソート。
5. fillnaでNaN値を補完
6. ソートしなおして、NaNを補完した値で、sqliteに書き込み&内容確認

ソースコード
import sqlite3
import pandas as pd

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

list1 = [[1, 'alpha', 10.0], [2, 'Bravo', None], [3, 'Charlie', 8.5], [5, 'Echo', 9.8], [4, 'Delta', 3.6]]
#list1 = [[1,'alpha', 10],[2,'Bravo', None],[3,'Charlie', 8], [5,'Foxtrot', 9],[None,'Echo', 3]]
#list1 = [[1,'alpha', 10],[2,'Bravo', 7],[3,'Charlie', 8], [5,'Foxtrot', 9],[4,'Echo', 3]]
df1 = pd.DataFrame(list1, columns=['number', 'name', 'score'])
print(df1)
print(df1.dtypes)

# sqliteに書き込み
df1.to_sql(name='users', con=con, index=False,
           schema='number INTEGER, name TEXT, score REAL')
tmp = cur.execute("SELECT * FROM users").fetchall()

print(tmp)

# schemaに'number TEXT, name TEXT, score REAL'を指定しても、
# 'number TEXT, name TEXT, score REAL'になるので、dataframeの設定が優先される様子。
# 値にNoneがあると、INTEGERではなくREALになる。
tmp = cur.execute("SELECT * FROM sqlite_master WHERE type='table'").fetchall()

print(tmp)

# read_sql_table only supported for SQLAlchemy connectable.
df2 = pd.read_sql(sql='SELECT * FROM users ORDER BY number', con=con)

# df3.to_sql(・・・,if_exists="replace")を実行したとき、
# pandas.io.sql.DatabaseError: Execution failed on sql 'DROP TABLE "users"': database table is locked
# になることがある。再実行するか、curを閉じるとよい。

print(df2)
print(df2.dtypes)

df3 = df2.fillna(method="ffill")
print(df3)

df3.to_sql(name='users', con=con, index=False,
           schema='number INTEGER, name TEXT, score REAL', if_exists="replace")
tmp = cur.execute("SELECT * FROM users").fetchall()
cur.close()
print(tmp)

con.close()
実行結果
   number     name  score
0       1    alpha   10.0
1       2    Bravo    NaN
2       3  Charlie    8.5
3       5     Echo    9.8
4       4    Delta    3.6
number      int64
name       object
score     float64
dtype: object
[(1, 'alpha', 10.0), (2, 'Bravo', None), (3, 'Charlie', 8.5), (5, 'Echo', 9.8), (4, 'Delta', 3.6)]
[('table', 'users', 'users', 2, 'CREATE TABLE "users" (\n"number" INTEGER,\n  "name" TEXT,\n  "score" REAL\n)')]
   number     name  score
0       1    alpha   10.0
1       2    Bravo    NaN
2       3  Charlie    8.5
3       4    Delta    3.6
4       5     Echo    9.8
number      int64
name       object
score     float64
dtype: object
   number     name  score
0       1    alpha   10.0
1       2    Bravo   10.0
2       3  Charlie    8.5
3       4    Delta    3.6
4       5     Echo    9.8
[(1, 'alpha', 10.0), (2, 'Bravo', 10.0), (3, 'Charlie', 8.5), (4, 'Delta', 3.6), (5, 'Echo', 9.8)]

可変引数のテスト**kwargs

可変引数のテスト

プログラム
def func1(**kwargs):
    print(kwargs)
    # キーに一致する値の取得。キーがない場合はNoneになる。
    print(kwargs.get("a"))
    print(kwargs.get("b"))
    print(kwargs.get("c"))
    print(kwargs.get("key1"))
    print(kwargs.get("key2"))
    print(kwargs.get("key3"))


print("func1(key1=1, key2=2)の場合")
func1(key1=1, key2=2)

# 辞書を引数として渡せる
print("func1(**dict1)の場合")
dict1 = {"a": 1, "b": "bb"}
func1(**dict1)
実行結果
func1(key1=1, key2=2)の場合
{'key1': 1, 'key2': 2}
None
None
None
1
2
None
func1(**dict1)の場合
{'a': 1, 'b': 'bb'}
1
bb
None
None
None
None

pythonでyamlファイルの読み込み(コンフィグファイルとして)

yamlに書いた内容が、文字列や数値がその型で取得できる。

辞書型と、リストにはいった辞書のyamlの書き方を追記。

ソースコード

import yaml
import os
import pprint

# yamlファイルは、このhello_yaml.pyと同じディレクトリにある想定
default_yaml_filename = "config.yaml"


class config():
    def __init__(self):
        self.foo = None
        self.bar = None
        self.hoge = None
        self.piyo = None
        
        self.dics = None
        self.dics_list=None
        self.default_yaml_fullpath = os.path.dirname(
            os.path.abspath(__file__)) + os.sep + default_yaml_filename

        self.load()

    def load(self):
        try:
            # 念のため絶対パスでアクセス
            with open(self.default_yaml_fullpath,"r",encoding="utf-8") as f:
                y = yaml.load(stream=f, Loader=yaml.SafeLoader)
                self.foo = y.get("foo")
                self.bar = y.get("bar")
                self.hoge = y.get("hoge")
                self.piyo = y.get("piyo")
                self.dics = y.get("dics")
                self.dics_list = y.get("dics_list")
                
        except:
            print("error", self.default_yaml_fullpath)
            raise


config = config()

print("config.foo: {0} {1}".format(config.foo, type(config.foo)))
print("config.bar: {0} {1}".format(config.bar, type(config.bar)))
print("config.hoge: {0} {1}".format(config.hoge, type(config.hoge)))
print("config.piyo: {0} {1}".format(config.piyo, type(config.piyo)))
print("config.dics: {0} {1}".format(config.dics, type(config.dics)))
pprint.pprint(config.dics)
print("config.dics_list: {0} {1}".format(config.dics_list, type(config.dics_list)))
pprint.pprint(config.dics_list)

config.yamlファイル(ソースコードと同じディレクトリ)

foo: foo1
bar: 100
hoge: 3.14
piyo: 
  - piyo1
  - piyo2
  - 100
  - 3.14
dics:
  x: 100
  y: 200
dics_list:
  - a: 1111
    b: 2222
  - c: 3333
    d: 4444

実行結果

> >python hello_yaml.py
config.foo: foo1 <class 'str'>
config.bar: 100 <class 'int'>
config.hoge: 3.14 <class 'float'>
config.piyo: ['piyo1', 'piyo2', 100, 3.14] <class 'list'>
config.dics: {'x': 100, 'y': 200} <class 'dict'>
{'x': 100, 'y': 200}
config.dics_list: [{'a': 1111, 'b': 2222}, {'c': 3333, 'd': 4444}] <class 'list'>
[{'a': 1111, 'b': 2222}, {'c': 3333, 'd': 4444}]

補足
Loader指定のないyaml.load(f)は推奨されない。y = yaml.load(stream=f, Loader=yaml.SafeLoader)に変更。

C:\dev\SampleCodes\hello_yaml\hello_yaml.py:20: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.
  y = yaml.load(f)

Visual Studio Code & Anaconda環境構築

最近、VSCodePython環境を作るとデバッグ実行がうまくいかないことがあるので、試行錯誤のメモ。

path(ユーザーの環境変数)に以下を追加

C:\Users\<ユーザー名>\Anaconda3\Scripts
C:\Users\<ユーザー名>\Anaconda3\

anacondaの初期設定

「CommandNotFoundError: Your shell has not been properly configured to use 'conda activate'.」と言われたときは、「conda init」を実行してみるとよい。

(base) C:\Users\<ユーザー名>>conda init
no change C:\Users\<ユーザー名>\Anaconda3\Scripts\conda.exe
no change C:\Users\<ユーザー名>\Anaconda3\Scripts\conda-env.exe
no change C:\Users\<ユーザー名>\Anaconda3\Scripts\conda-script.py
no change C:\Users\<ユーザー名>\Anaconda3\Scripts\conda-env-script.py
no change C:\Users\<ユーザー名>\Anaconda3\condabin\conda.bat
no change C:\Users\<ユーザー名>\Anaconda3\Library\bin\conda.bat
no change C:\Users\<ユーザー名>\Anaconda3\condabin\_conda_activate.bat
no change C:\Users\<ユーザー名>\Anaconda3\condabin\rename_tmp.bat
no change C:\Users\<ユーザー名>\Anaconda3\condabin\conda_auto_activate.bat
no change C:\Users\<ユーザー名>\Anaconda3\condabin\conda_hook.bat
no change C:\Users\<ユーザー名>\Anaconda3\Scripts\activate.bat
no change C:\Users\<ユーザー名>\Anaconda3\condabin\activate.bat
no change C:\Users\<ユーザー名>\Anaconda3\condabin\deactivate.bat
modified C:\Users\<ユーザー名>\Anaconda3\Scripts\activate
modified C:\Users\<ユーザー名>\Anaconda3\Scripts\deactivate
modified C:\Users\<ユーザー名>\Anaconda3\etc\profile.d\conda.sh
modified C:\Users\<ユーザー名>\Anaconda3\etc\fish\conf.d\conda.fish
no change C:\Users\<ユーザー名>\Anaconda3\shell\condabin\Conda.psm1
modified C:\Users\<ユーザー名>\Anaconda3\shell\condabin\conda-hook.ps1
modified C:\Users\<ユーザー名>\Anaconda3\Lib\site-packages\xonsh\conda.xsh
modified C:\Users\<ユーザー名>\Anaconda3\etc\profile.d\conda.csh
modified C:\Users\<ユーザー名>\Documents\WindowsPowerShell\profile.ps1
modified HKEY_CURRENT_USER\Software\Microsoft\Command Processor\AutoRun

「Missing required dependencies ['numpy']」と言われたら以下。
ファイルのありか Python Extension Packages for Windows - Christoph Gohlke
参考サイトscipyが突然読み込まれなくなった話 - Qiita

pip install C:\Users\<ユーザー名>\Downloads\numpy-1.16.2+mkl-cp37-cp37m-win_amd64.whl

PowerShellを管理者として実行

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned