Cucco’s Compute Hack

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

記述のカテゴリ分け

もとの詳細な記述を分析して、下位のカテゴリに分類し、下位のカテゴリをさらに上位カテゴリに再分類する。
2階層のブレイクダウンの逆。

ルールは辞書で作成。keyにあたる部分がカテゴリ名、valueにはlistを設定する。
そのリストにある記述が、もとの詳細な記述の中にあれば、そのカテゴリであると判断する。

下位カテゴリが複数のカテゴリに該当する場合、もとの詳細な記述の最初に書いてあるカテゴリとする。

結果の見方は、「もとの詳細な記述 下位カテゴリ 上位カテゴリ」

結果

AA123 A1 A
AA123B22 A1 A
B22AA123 B2 B
asdf None None
asC12df C1 None

ソース

def classify_category(source_descripton,rule_dic):
    category_found = False
    found_key= ""
    find_pos=100 # 十分な長さ

    for category_key in rule_dic.keys():
        for category_value in rule_dic[category_key]:
            if category_value in source_descripton:
                category_found = True
                tmp_pos=source_descripton.find(category_value)
                if tmp_pos < find_pos:
                    found_key = category_key
                    find_pos=tmp_pos

    if category_found is False:
        found_key="None"

    return found_key

if __name__ == '__main__':
    top_category={}
    second_category={}

    top_category["A"]=["A1","A2"]
    top_category["B"]=["B1","B2"]

    second_category["A1"]=["A11","A12"]
    second_category["A2"]=["A21","A22"]
    second_category["B1"]=["B11","B12"]
    second_category["B2"]=["B21","B22"]
    second_category["C1"]=["C11","C12"]

    source_descripton="AA123"
    second_category_description = classify_category(source_descripton,second_category)
    top_category_description = classify_category(second_category_description,top_category)
    print(source_descripton,second_category_description,top_category_description)

    source_descripton="AA123B22"
    second_category_description = classify_category(source_descripton,second_category)
    top_category_description = classify_category(second_category_description,top_category)
    print(source_descripton,second_category_description,top_category_description)
    
    source_descripton="B22AA123"
    second_category_description = classify_category(source_descripton,second_category)
    top_category_description = classify_category(second_category_description,top_category)
    print(source_descripton,second_category_description,top_category_description)

    source_descripton="asdf"
    second_category_description = classify_category(source_descripton,second_category)
    top_category_description = classify_category(second_category_description,top_category)
    print(source_descripton,second_category_description,top_category_description)

    source_descripton="asC12df"
    second_category_description = classify_category(source_descripton,second_category)
    top_category_description = classify_category(second_category_description,top_category)
    print(source_descripton,second_category_description,top_category_description)

3次元の表

多次元(3次元)の配列が必要になったので、初期化と参照の方法を確認。
2次元表の中の1枠をcellとみなして、cellの中にも1次元の配列があるイメージ。

コード

import itertools

print("3次元の配列")
dim_row =2 # row
dim_col =3 # col
dim_cell =4 # cell

# ゼロ初期化
list_3d =[[[0 for z in range(dim_cell)] for y in range(dim_col)] for x in range(dim_row)]

print("\nlist_3d[0][1][2]=1")
list_3d[0][1][2]=1

print("\n単純にprint")
print(list_3d)

print("\n行を取り出してprint")
for i in list_3d:
    print(i)
    
print("\n行を、フラットな配列に変換")
for i in list_3d:
    print(list(itertools.chain.from_iterable(i)))

実行結果

3次元の配列

list_3d[0][1][2]=1

単純にprint
[[[0, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]]

行を取り出してprint
[[0, 0, 0, 0], [0, 0, 1, 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, 0, 0, 0, 0, 0, 0]

コンソールの同じ行にprint

コンソールで、表示を更新したいけど、行は増やしたくないときに使うもの。

消してもよい情報をprintするときは、printt.printt("hoge","piyo1",over_write=True) のように、"over_write=True” とする。

実行結果

('hoge', 'piyo0')
('hoge', 'piyo3')    
('hoge', 'piyo4')
('hoge', 'piyo7')    
('hoge', 'piyo9')   

コード

import time
class printt():
    # クラス変数
    last_over_write_status = False
    @classmethod
    def printt(cls, *args, over_write=False):

        if __class__.last_over_write_status is True:
            print("\r",end="")
        else:
            pass

        if over_write is False:
            if __class__.last_over_write_status is True:
                # 1行前の表示残りを上書きするため、後半に空白を追加
                print(args,"   ")
            else:
                print(args)
            __class__.last_over_write_status = False
        else:
            print(args,end="")
            __class__.last_over_write_status = True

if __name__ =="__main__":
    printt.printt("hoge","piyo0")
    time.sleep(1)
    printt.printt("hoge","piyo1",over_write=True)
    time.sleep(1)
    printt.printt("hoge","piyo2",over_write=True)
    time.sleep(1)
    printt.printt("hoge","piyo3")
    time.sleep(1)
    printt.printt("hoge","piyo4")
    time.sleep(1)
    printt.printt("hoge","piyo5",over_write=True)
    time.sleep(1) 
    printt.printt("hoge","piyo6",over_write=True)
    time.sleep(1)
    printt.printt("hoge","piyo7")
    time.sleep(1) 
    printt.printt("hoge","piyo8",over_write=True)
    time.sleep(1)
    printt.printt("hoge","piyo9")

pythonでの環境変数操作

pythonでの環境変数の参照、設定、削除。

クラスにしたもの

1つの環境変数ごとに1つのインスタンスが必要。

import os

class myosenv():
    def __init__(self,new_key:str, value_str=None):
        self.new_key=new_key
        
        key_value=os.getenv(self.new_key)

        if key_value is not None:
            print(f"{new_key} already exists.")
            print(f"{new_key}={key_value}")
            raise Exception

        if value_str is not None:
            self.set_value(value_str)

    def set_value(self, value_str:str):
        # __init__でその名前の環境変数が存在していないことは確認済み
        os.environ[self.new_key] = value_str

    def get_value(self):
        return os.getenv(self.new_key)

    def __del__(self):
        del os.environ[self.new_key]

if __name__ == '__main__':

    #env = myosenv("os")
    env = myosenv("hoge")
    env.set_value("hoge1")

    print(env.get_value())
    print(os.environ["hoge"])
    
    # コンストラクタでkeyとvalueを両方定義
    env_piyo = myosenv("piyo","piyo20")
    print(env_piyo.get_value())
    print(os.environ["piyo"])

基本の動作確認

コード
import os

print("\n1. 実在する環境変数")#----------------------------------
new_key="OS"
key_value=os.getenv(new_key)

if key_value is None:
    print(f"存在しない。{new_key} is {key_value}")
else:
    print(f"{new_key} is {key_value}")

print("\n2. 実在しない環境変数")#----------------------------------

new_key="hoge"
key_value=os.getenv(new_key)

if key_value is None:
    print(f"存在しない。{new_key} is {key_value}")
else:
    print(f"{new_key} is {key_value}")

print("\n3. 実在しない環境変数を新たに作る")#----------------------------------
#new_key="hoge"
#key_value=os.getenv(new_key)

if key_value is None:
    print(f"存在しない。{new_key} is {key_value}")
    new_key_value="hoge2000"
    os.environ[new_key] = new_key_value
    print(f"set {new_key} = {new_key_value}")
else:
    print(f"{new_key} is {key_value}")

print("\n4. 環境変数を新たに作った")#----------------------------------
#new_key="hoge"
key_value=os.getenv(new_key)

if key_value is None:
    print(f"存在しない。{new_key} is {key_value}")
else:
    print(f"{new_key} is {key_value}")

print("\n5. 作った環境変数を消す")#----------------------------------
del os.environ[new_key]
print(f"del os.environ[{new_key}]")

print(f"\n6. 環境変数を消した後")#----------------------------------
#new_key="hoge"
key_value=os.getenv(new_key)

if key_value is None:
    print(f"存在しない。{new_key} is {key_value}")
else:
    print(f"{new_key} is {key_value}")
実行結果
1. 実在する環境変数
OS is Windows_NT

2. 実在しない環境変数
存在しない。hoge is None

3. 実在しない環境変数を新たに作る
存在しない。hoge is None
set hoge = hoge2000

4. 環境変数を新たに作った
hoge is hoge2000

5. 作った環境変数を消す
del os.environ[hoge]

6. 環境変数を消した後
存在しない。hoge is None

classmethodとクラス変数

クラスのインスタンスを作らずにクラスの関数を実行したい場合のメモ

クラス変数であればclassmethod内で参照できる。インスタンスを作ればクラス変数も変更できる。
classmethod内では、インスタンス変数は一切参照できない。(作ったインスタンスでclassmethodを実行しても)

classmethod を使う場合、第一引数を cls とすることが慣習らしいですが、以下のコードではselfとなっています。(検証コードとして、インスタンス変数を参照できる可能性を残すため)

コード
class myclass():
    # クラス変数
    val_class=1

    def __init__(self):
        # インスタンス変数
        self.val_inst=10

        # インスタンス生成時に、クラス変数を書き換え。
        __class__.val_class=100
    
    # 通常関数
    def print_inst(self):
        print(self.val_inst)
        print(__class__.val_class)
        print("\n")
    
    # classmethod
    # classmethodは、__init__以下で宣言したインスタンス変数にはアクセスできない。
    # インスタンスを作れば、クラス変数も変更できる。
    @classmethod
    def print_class(self):
        print(__class__.val_class)
        try:
            # val_instが初期化されていない可能性がある。
            print(self.val_inst)
        except Exception as e:
            print(e)
        print("\n")
        
if __name__ == "__main__":
    print("インスタンスを作らずに、classmethiodをコール")
    myclass.print_class()

    print("インスタンスを作る")
    x=myclass()

    print("インスタンスを作った後に、classmethiodをコール")
    myclass.print_class()

    print("インスタンスのなかのclassmethiodをコール")
    x.print_class()

    print("インスタンスのなかの通常関数をコール")
    x.print_inst()
実行結果
インスタンスを作らずに、classmethiodをコール
1
type object 'myclass' has no attribute 'val_inst'


インスタンスを作る
インスタンスを作った後に、classmethiodをコール
100
type object 'myclass' has no attribute 'val_inst'


インスタンスのなかのclassmethiodをコール
100
type object 'myclass' has no attribute 'val_inst'


インスタンスのなかの通常関数をコール
10
100

markdownの箇条書きにチェックボックスをつける

markdownの箇条書きの先頭にチェックボックス”[ ]”を付与するスクリプト
引数でmdファイルを指定する。_addcheck.md にリネームして保存する。

markdown-pdfでhtmlにすれば、チェックボックスとして動作するところまで確認。(チェックの変更は保存できない)

プログラム
import re
import sys

if len(sys.argv) != 2:
    print("this script add [ ] box, save new md file")
    print("usage: python md_addcheck.py mdfilepath")
    exit()

if sys.argv[1][-3:] != ".md":
    print("usage: python md_addcheck.py mdfilepath")
    print("mdfilepath seems not md file.",sys.argv[1])
    exit()

file_original = sys.argv[1]
file_addcheck = file_original.replace(".md", "_addcheck.md")

with open(file_original, "r", encoding="utf8") as f:
    lines = f.readlines()

with open(file_addcheck, "w", encoding="utf8") as fw:

    rc1 = re.compile(r"^( )*\d\. \w")
    rc2 = re.compile(r"^( )*- \w")

    for line in lines:
        mt1 = re.match(rc1, line)
        mt2 = re.match(rc2, line)
        if mt1 is not None:
            pos = mt1.end() -1 
            new_line = line[:pos] + "[ ] " + line[pos:]
        elif mt2 is not None:
            pos = mt2.end() -1 
            new_line = line[:pos] + "[ ] " + line[pos:]
        else:
            new_line = line
        
        fw.write(new_line)

print("done")
print(f"please find {file_addcheck}")
データ
# foo
- foo
- bar
    - barfoo
    - barfoo
# bar
1. hoge
1. bar
    1. barfoo
    1. barfoo
# foo
1. foo
1. bar
    - barfoo
    - barfoo
# bar
- hoge
- bar
    1. barfoo
    1. barfoo
# bar
- 感じ
- 漢字
    1. 漢字1
    1. 漢字 2  

# hoge
asdf
qwer
1.sadf
-asdf
実行結果(markdown)
# foo
- [ ] foo
- [ ] bar
    - [ ] barfoo
    - [ ] barfoo
# bar
1. [ ] hoge
1. [ ] bar
    1. [ ] barfoo
    1. [ ] barfoo
# foo
1. [ ] foo
1. [ ] bar
    - [ ] barfoo
    - [ ] barfoo
# bar
- [ ] hoge
- [ ] bar
    1. [ ] barfoo
    1. [ ] barfoo
# bar
- [ ] 感じ
- [ ] 漢字
    1. [ ] 漢字1
    1. [ ] 漢字 2  

# hoge
asdf
qwer
1.sadf
-asdf
実行結果(ブラウザ)
f:id:Cucco:20201214190901p:plain
チェック前
f:id:Cucco:20201214190937p:plain
チェック後

sklearnでクラスタリング(その3)

学習済みのクラスタ識別機は、pickleで保存する模様。

プログラム
import numpy as np
from sklearn.cluster import KMeans

import pickle
import os

X = np.array([[0, 0],[0, 1],[1, 0],[1, 1], [0, 10], [0, 9], [0, 8], [10, 10], [10, 9],[9,10]])
Y = np.array([[0, 0], [0, 1], [1, 0], [1, 1], [0, 10], [0, 9], [0, 8], [10, 10], [10, 9], [9, 10]])

# クラスタ識別機の学習
kmeans = KMeans(n_clusters=3, random_state=0).fit(X)

# 学習結果を表示
print("オリジナルのクラスタ識別機を利用した結果")
print(kmeans.labels_)
print(kmeans.cluster_centers_)
print(kmeans.predict(Y))
print(kmeans.transform(Y))

# 学習済みクラスタ識別機を保存
traind_kmeans_file = os.path.dirname(os.path.abspath(__file__)) + os.sep + 'traind_kmeans_model.pickle'
with open(traind_kmeans_file, mode='wb') as fp:
    pickle.dump(kmeans, fp)

# 学習済みクラスタ識別機をファイルから呼び出し
with open(traind_kmeans_file , mode='rb') as fp:
    kmeans_new = pickle.load(fp)

# 学習結果を表示
print("読み出したクラスタ識別機を利用した結果")
print(kmeans_new.labels_)
print(kmeans_new.cluster_centers_)
print(kmeans_new.predict(Y))
print(kmeans_new.transform(Y))
結果
オリジナルのクラスタ識別機を利用した結果
[0 0 0 0 2 2 2 1 1 1]
[[0.5        0.5       ]
 [9.66666667 9.66666667]
 [0.         9.        ]]
[0 0 0 0 2 2 2 1 1 1]
[[ 0.70710678 13.6707311   9.        ]
 [ 0.70710678 12.98289473  8.        ]
 [ 0.70710678 12.98289473  9.05538514]
 [ 0.70710678 12.25651754  8.06225775]
 [ 9.5131488   9.67241209  1.        ]
 [ 8.51469318  9.6896279   0.        ]
 [ 7.51664819  9.80929265  1.        ]
 [13.43502884  0.47140452 10.04987562]
 [12.74754878  0.74535599 10.        ]
 [12.74754878  0.74535599  9.05538514]]
読み出したクラスタ識別機を利用した結果
[0 0 0 0 2 2 2 1 1 1]
[[0.5        0.5       ]
 [9.66666667 9.66666667]
 [0.         9.        ]]
[0 0 0 0 2 2 2 1 1 1]
[[ 0.70710678 13.6707311   9.        ]
 [ 0.70710678 12.98289473  8.        ]
 [ 0.70710678 12.98289473  9.05538514]
 [ 0.70710678 12.25651754  8.06225775]
 [ 9.5131488   9.67241209  1.        ]
 [ 8.51469318  9.6896279   0.        ]
 [ 7.51664819  9.80929265  1.        ]
 [13.43502884  0.47140452 10.04987562]
 [12.74754878  0.74535599 10.        ]
 [12.74754878  0.74535599  9.05538514]]
set_params()は学習結果は含んでいない

get_params()の結果をset_params(**get_params()の結果)でセットしただけでは、以下といわれる。

sklearn.exceptions.NotFittedError: This KMeans instance is not fitted yet. Call 'fit' with appropriate arguments before using this estimator.