20210419のPythonに関する記事は30件です。

スクショなどのファイル名のスペースやカッコなどをPythonで一括置換した

モチベーション macOSやLinuxでスクリーンショットを撮ると、スクリーンショット 20××-11-22 33.44.55.pngやScreenshot from 2021-04-19 14-19-39.pngなどのようにスペースが含まれてしまう。 また同じ名前のファイルをダウンロードすると、test (1).pngなどのようにスペースとかっこが含まれていて、コマンドでの操作が非常にやりにくい。 そこで、そのディレクトリにあるファイル名のスペースやかっこなどの記号を一括置換するプログラムをPythonで書きました。これを~/Downloadsやら~/Picturesやら~/Desktopのディレクトリに1個置いておくだけで、かなり便利になると思います。(updated) なおmacOSの場合の、スクリーンショット 20××-11-22 33.44.55.pngのスクリーンショットという日本語の部分は「Macのスクリーンショットの保存先と名前を変更する」でも排除できます。 コード import os import shutil def get_filenames(path): files_and_dir = os.listdir(path) # get a list of names of files and directories files = [i for i in files_and_dir if os.path.isfile(os.path.join(path, i))] # a list of names of only files return files def replace_a_with_b(path, a, b): files = get_filenames(path) for f in files: # For example, if f="test 1.pdf", we want to replace a=" " with b="_". if a in f: # g = f.replace(a, b) # g = "test_1.pdf" shutil.move(f, g) # mv 'test 1.pdf' test_1.pdf def main(): path = "." # current directory replace_a_with_b(path, " ", "_") replace_a_with_b(path, "(", "") replace_a_with_b(path, ")", "") # ここに追加したいものを書いてください if __name__ == "__main__": main() Ubuntuの~/Picturesで実行 Pictures $ ls total 360K -rw-rw-r-- 1 <user> <group> 158K Apr 18 22:17 'Screenshot from 2021-04-18 22-17-40.png' -rw-rw-r-- 1 <user> <group> 140K Apr 19 14:19 'Screenshot from 2021-04-19 14-19-39.png' -rw-r--r-- 1 <user> <group> 783 Apr 19 23:24 renamefiles.py Pictures $ python renamefiles.py Pictures $ ls total 360K -rw-rw-r-- 1 <user> <group> 158K Apr 18 22:17 Screenshot_from_2021-04-18_22-17-40.png -rw-rw-r-- 1 <user> <group> 140K Apr 19 14:19 Screenshot_from_2021-04-19_14-19-39.png -rw-r--r-- 1 <user> <group> 783 Apr 19 23:24 renamefiles.py 問題点 置換したい文字を追加すればするほどforの回数が多くなってしまって、あまり効率がよくない気がします。「もっとこうしたらいいよ」というのがありましたらぜひ教えてください。 改善 パス名を引数として渡すことで、コマンド的に使えるようにしました。 renamefiles.py import os import shutil import sys def get_filenames(path): files_and_dir = os.listdir(path) # get a list of names of files and directories files = [i for i in files_and_dir if os.path.isfile(os.path.join(path, i))] # a list of names of only files return files def replace_a_with_b(path, a, b): files = get_filenames(path) for f in files: # For example, if f="test 1.pdf", we want to replace a=" " with b="_". if a in f: # g = f.replace(a, b) # g = "test_1.pdf" shutil.move(f, g) # mv 'test 1.pdf' test_1.pdf def main(): if len(sys.argv)!=2: print("Usage: renamefiles <path_to_files>") sys.exit(1) else: # path = "." # current directory path = sys.argv[1] replace_a_with_b(path, " ", "_") replace_a_with_b(path, "(", "") replace_a_with_b(path, ")", "") if __name__ == "__main__": main() これをホームディレクトリなどに置いておき、~/.bashrcに以下を追加してください。 alias renamefiles="python ~/renamefiles.py" 終わったら source ~/.bashrc を実行すれば準備完了。 実行例は $ renamefiles /path/to/files $
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Colab環境でMeCabを使う

 Colab環境でMeCabを使いたい。手短にわかりたい。 やること word2vecをColab環境で使う。5行で使う。の続きです。 Colab環境でMeCabを使います。 MeCabを使えば日本語の文章を分かち書きすることができます。それを利用してword2vec用のコーパスを作ったりもできます。 参考 ColaboratoryでMeCabを使えようにする。 こちらの記事に答えが書いてありますが、若干補足します。 環境 Colaboratory環境 ブラウザはChrome推奨 colabを少し使ったことがある前提で進めていきます。 でもpythonを知らなくても実行できる説明にします。 やり方 colabで下記を実行していきます。簡単な解説もつけます。 ColabにMeCabをインストールする Colab ! apt install aptitude ! aptitude install mecab libmecab-dev mecab-ipadic-utf8 git make curl xz-utils file -y ! pip install mecab-python3==0.7 これだけでいけます。   MeCabを試す python3 import MeCab print(MeCab.Tagger("-chasen").parse("すもももももももものうち")) すもも 名詞,一般,,,,,すもも,スモモ,スモモ も 助詞,係助詞,,,,,も,モ,モ もも 名詞,一般,,,,,もも,モモ,モモ も 助詞,係助詞,,,,,も,モ,モ もも 名詞,一般,,,,,もも,モモ,モモ の 助詞,連体化,,,,,の,ノ,ノ うち 名詞,非自立,副詞可能,,,*,うち,ウチ,ウチ EOS と結果を出力します。 上記のプログラムでは、PythonにMeCabを導入し、 "すもももももももものうち"というフレーズをchasenという方式で品詞分解し、プリントしてます。 .Tagger() が分解方法の指定。 .parse() は解析する対象の文字列を指定しています。 もう少し他の使い方を見ていきます。 分かち書き .Tagger("-Owakati") python3 text = "プラレスとは、超LSIを組み込んだバトルマシン同士が、四角いジャングルで激突する現代最先端の格闘技だ。" tagger = MeCab.Tagger("-Owakati").parse(text) print(tagger) プラレス と は 、 超 LSI を 組み込ん だ バトル マシン 同士 が 、 四角い ジャングル で 激突 する 現代 最先端 の 格闘技 だ 。 品詞ごとに分割され、間に半角スペースが挿入された形のテキストが出力されます。 形態素解析 .Tagger("-chasen") python3 text = "プレイするたびに謎が深まる" tagger = MeCab.Tagger("-chasen").parse(text) print(tagger) プレイ 名詞,一般,,,,,* する 動詞,自立,,,サ変・スル,基本形,する,スル,スル たび 名詞,非自立,副詞可能,,,,たび,タビ,タビ に 助詞,格助詞,一般,,,,に,ニ,ニ 謎 名詞,一般,,,,,謎,ナゾ,ナゾ が 助詞,格助詞,一般,,,,が,ガ,ガ 深まる 動詞,自立,,*,五段・ラ行,基本形,深まる,フカマル,フカマル EOS 形態素解析2 .Tagger("-Ochasen") python3 text = "プレイするたびに謎が深まる" tagger = MeCab.Tagger("-Ochasen").parse(text) print(tagger) プレイ プレイ プレイ 名詞-一般 する スル する 動詞-自立 サ変・スル 基本形 たび タビ たび 名詞-非自立-副詞可能 に ニ に 助詞-格助詞-一般 謎 ナゾ 謎 名詞-一般 が ガ が 助詞-格助詞-一般 深まる フカマル 深まる 動詞-自立 五段・ラ行 基本形 EOS 前述の形式違い。 ヨミのみ .Tagger("-Oyomi") python3 text = "覇王翔吼拳を使わざるを得ない" tagger = MeCab.Tagger("-Oyomi").parse(text) print(tagger) ハオウショウ吼拳ヲツカワザルヲエナイ カタカナのヨミのみに変換。読めない漢字もある。 全情報 .Tagger("-Odump") python3 text = "知らぬが仏" tagger = MeCab.Tagger("-Odump").parse(text) print(tagger) 0 BOS BOS/EOS,,,,,,,, 0 0 0 0 0 0 2 1 0.000000 0.000000 0.000000 0 4 知ら 動詞,自立,,,五段・ラ行,未然形,知る,シラ,シラ 0 6 780 780 31 2 0 1 0.000000 0.000000 0.000000 7578 8 ぬ 助動詞,,,,特殊・ヌ,基本形,ぬ,ヌ,ヌ 6 9 484 484 25 6 0 1 0.000000 0.000000 0.000000 6300 14 が 助詞,接続助詞,,,,,が,ガ,ガ 9 12 299 299 18 6 0 1 0.000000 0.000000 0.000000 7165 15 仏 名詞,一般,,,,,仏,ホトケ,ホトケ 12 15 1285 1285 38 2 0 1 0.000000 0.000000 0.000000 14931 20 EOS BOS/EOS,,,,,,,,* 15 15 0 0 0 0 3 1 0.000000 0.000000 0.000000 14358 その他参考URL わかりやすくためになるサイトです。 - 【Python】形態素解析エンジン MeCabの使い方 - Python3からMeCabを使う
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GiNZA を HTTP Server 化する

目的 Objective OSやランタイムプラットフォームにできるだけ依存しない分散自然言語処理システムを作るためです。 Mecab, Cabocha の動作環境を用意するのが面倒だなと思ったのもきっかけです。 コード Code # coding: utf-8 from http.server import HTTPServer from http.server import BaseHTTPRequestHandler from urllib.parse import urlparse import urllib.parse from ginza import * import spacy import json from collections import defaultdict import traceback class class1(BaseHTTPRequestHandler): def __init__(self, request, client_address, server): self.nlp = spacy.load("ja_ginza") BaseHTTPRequestHandler.__init__(self,request,client_address,server) def do_GET(self): query = urlparse(self.path).query print(query) qs_d = urllib.parse.parse_qs(query) print(qs_d) text = qs_d["text"][0] print(text) text = urllib.parse.unquote(text) try: doc = self.nlp(text) res = [] for sent in doc.sents: resx = {} res.append(resx) pgps = {} resx["paragraphs"] = pgps stcs = {} pgps["raw"] = sent.text pgps["sentences"] = stcs tokens = [] stcs["tokens"] = tokens res.append(tokens) for token in sent: tk = {} tk["id"] = token.i tk["orth"] = token.orth_ tk["tag"] = token.tag_ tk["pos"] = token.pos_ tk["lemma"] = token.lemma_ tk["head"] = token.head.i tk["dep"] = token.dep_ tokens.append(tk) self.send_response(200) self.send_header("Content-type","application/json; charset=utf-8") self.end_headers() html = json.dumps(res) self.wfile.write(html.encode()) except: print(traceback.format_exc()) self.send_response(500) def main(): ip = '127.0.0.1' port = 8888 server = HTTPServer((ip,port),class1) server.serve_forever() if __name__ == '__main__': main() 呼び出し例 下記のURLにアクセスします。 http://localhost:8888/?text=今日はいい天気です。 呼び出し結果例 [{"paragraphs": {"raw": "\u4eca\u65e5\u306f\u3044\u3044\u5929\u6c17\u3067\u3059\u3002", "sentences": {"tokens": [{"id": 0, "orth": "\u4eca\u65e5", "tag": "\u540d\u8a5e-\u666e\u901a\u540d\u8a5e-\u526f\u8a5e\u53ef\u80fd", "pos": "NOUN", "lemma": "\u4eca\u65e5", "head": 3, "dep": "nsubj"}, {"id": 1, "orth": "\u306f", "tag": "\u52a9\u8a5e-\u4fc2\u52a9\u8a5e", "pos": "ADP", "lemma": "\u306f", "head": 0, "dep": "case"}, {"id": 2, "orth": "\u3044\u3044", "tag": "\u5f62\u5bb9\u8a5e-\u975e\u81ea\u7acb\u53ef\u80fd", "pos": "ADJ", "lemma": "\u3044\u3044", "head": 3, "dep": "acl"}, {"id": 3, "orth": "\u5929\u6c17", "tag": "\u540d\u8a5e-\u666e\u901a\u540d\u8a5e-\u4e00\u822c", "pos": "NOUN", "lemma": "\u5929\u6c17", "head": 3, "dep": "ROOT"}, {"id": 4, "orth": "\u3067\u3059", "tag": "\u52a9\u52d5\u8a5e", "pos": "AUX", "lemma": "\u3067\u3059", "head": 3, "dep": "cop"}, {"id": 5, "orth": "\u3002", "tag": "\u88dc\u52a9\u8a18\u53f7-\u53e5\u70b9", "pos": "PUNCT", "lemma": "\u3002", "head": 3, "dep": "punct"}]}}}, [{"id": 0, "orth": "\u4eca\u65e5", "tag": "\u540d\u8a5e-\u666e\u901a\u540d\u8a5e-\u526f\u8a5e\u53ef\u80fd", "pos": "NOUN", "lemma": "\u4eca\u65e5", "head": 3, "dep": "nsubj"}, {"id": 1, "orth": "\u306f", "tag": "\u52a9\u8a5e-\u4fc2\u52a9\u8a5e", "pos": "ADP", "lemma": "\u306f", "head": 0, "dep": "case"}, {"id": 2, "orth": "\u3044\u3044", "tag": "\u5f62\u5bb9\u8a5e-\u975e\u81ea\u7acb\u53ef\u80fd", "pos": "ADJ", "lemma": "\u3044\u3044", "head": 3, "dep": "acl"}, {"id": 3, "orth": "\u5929\u6c17", "tag": "\u540d\u8a5e-\u666e\u901a\u540d\u8a5e-\u4e00\u822c", "pos": "NOUN", "lemma": "\u5929\u6c17", "head": 3, "dep": "ROOT"}, {"id": 4, "orth": "\u3067\u3059", "tag": "\u52a9\u52d5\u8a5e", "pos": "AUX", "lemma": "\u3067\u3059", "head": 3, "dep": "cop"}, {"id": 5, "orth": "\u3002", "tag": "\u88dc\u52a9\u8a18\u53f7-\u53e5\u70b9", "pos": "PUNCT", "lemma": "\u3002", "head": 3, "dep": "punct"}]] ↑だとわかりにくいので見やすくしたのが以下のものです。 NLP4J NLP4J プロジェクトのコンポーネントとして利用する予定です。 NLP4J Index 参考 Reference GiNZA - Japanese NLP Library | Universal Dependenciesに基づくオープンソース日本語NLPライブラリ https://megagonlabs.github.io/ginza/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

socket通信とmultiprocessingのpipeを比較する

並行処理できて、なおかつ情報をまとめて受信したい時にパッと思いついたのがsocket通信でしたが、試行錯誤した結果、multiprocessingのPipeで実装を行いました。今回はsocketとPipeの比較をメモ程度に。 結論から言うと、送信内容をすぐに受信するのであれば両方とも変わりありませんが、受信内容をまとめて受け取る処理の場合はpipeの方が扱いやすかったです。 socket通信のテストコード ローカル通信を利用して、パソコン内のpyファイル同士で文字列の送受信を行います。 具体的にはサーバ側から文字列を送信し、クライアント側はまとめて受信するために受信処理を遅延させます。 server.py # -*- coding:utf-8 -*- #!/usr/bin/python import numpy as np import socket import sys #環境に応じて変更 HOST = '127.0.0.1' PORT = 50900 socket1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) socket1.bind((HOST, PORT)) socket1.listen(1) # コネクションとアドレスを取得 connection, address = socket1.accept() # 文字列を3回送る for i in range(3): txt = "abcd".encode('utf-8')# connection.send(txt) # サーバの処理終了防止 x = input() client.py # -*- coding:utf-8 -*- #!/usr/bin/python import socket import time import sys #IPアドレスとポート番号は環境に応じて変更 HOST = "127.0.0.1" PORT = 50900 sock1=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #タイムアウト防止 while True: try: sock1.connect((HOST,PORT)) except ConnectionRefusedError: continue break # 受信処理を遅延 time.sleep(5) # server.pyからの受信と表示 txt = sock1.recv(1024).decode() print(txt) 結果 クライアント→サーバの順に起動。 abcdabcdabcd 文字列が連なってしまって、扱うのが少々面倒くさいです。 Pipeのテストコード 処理条件はほぼ変わらず。 pipe.py # -*- coding:utf-8 -*- #!/usr/bin/python from multiprocessing import Pipe import time a, b = Pipe() # 文字列を3回送る for i in range(3): a.send("abcd") # 受信処理を遅延 time.sleep(5) # pipeの受信と表示 print(b.recv()) 結果 abcd 送信した文字列をそのまま受け取ることができましたが、実際はabcdの文字列が後ろに待機している状態となっています。そこで、受信内容を全て受け取れるよう、以下のように変更します。 pipe.py # -*- coding:utf-8 -*- #!/usr/bin/python from multiprocessing import Pipe import time a, b = Pipe() mai_list = [] # 文字列を3回送る for i in range(3): a.send("abcd") # 受信処理を遅延 time.sleep(5) # pipeの受信と表示(ない場合はpass) if b.poll() is True: while b.poll() is True: mai_list.append(b.recv()) print(mai_list) すると、受信内容が以下のようにlist型となって返ってきます。 ['abcd', 'abcd', 'abcd'] これで受信内容が扱いやすくなりました。 因みにPipeにおける並行処理については、multiprocessingモジュールのProcessを利用することで実装ができます。 pipe.py # -*- coding:utf-8 -*- #!/usr/bin/python from multiprocessing import Pipe from multiprocessing import Process import time a, b = Pipe() mai_list = [] def send(a): # 文字列を3回送る for i in range(3): a.send("abcd") if __name__ == "__main__": sends = Process(target=send, args=(a,)) sends.start() # 受信処理を遅延 time.sleep(5) # pipeの受信と表示(ない場合はpass) if b.poll() is True: while b.poll() is True: mai_list.append(b.recv()) print(mai_list)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Python IDE乗り換え

長年使いなれたIDEを乗り換えようと思う。 Spyderを愛用してきたが、最近性能を求めるライブラリを作り出そうとするとPythonでは限界があり、Cython -> C/C++ pythonAPI拡張にはまっている。 SpyderではC言語系はカバーしきれず、コマンドプロンプトとエディタを行ったり来たりなので統合開発環境が欲しいなと思った spyderの不満点 起動が重い 変数名の一括変更などできない。 アップデート後必ず何かが起きる。 あたりを我慢すると非常に満足だった。 Python IDEとしてまともに使えるもの探し Eclipse(重い、ダサい) Netbeans(Eclipseよりは軽いがデバッガが使いづらい,iteractiveWindowが使えない) Visual Studio Cominuty 2017(ダサい、マウス操作が多い、アウトライン表示できない) Vim拡張カスタムしまくり(自己満足に走りすぎて、逆にコーディングに集中できなくなる。Vimの設定修正の方が気になりだし本末転倒) PyCharm <- 軽い、Spyder以上に使いやすいがたまにクラッシュする、有料 結論 Visual Studio Code PyCharmを買おうかと思っていたが、 Microsoft製ということで食わず嫌いしてたが、VSCodeをインストールし1日環境設定に励んだところ、かなりイイ。 過去一番良いかも、、 めっちゃ軽い、思いの他、デバッガもまともに使える。 そしてSpyderやPycharmにはない利点、python, C/C++の融合 まだよくわかってないが、パフォーマンスプロファイラ機能が使えるのかがわからない。 拡張機能をインストールしろだと思うが、どれが良いのかまだわからない。 Visual Studio Cominutyとは完全に別物。。本家のVSは見習ってください。 VSCode設定備忘 setting.json { // "editor.renderLineHighlight": "all", // 選択中の行を強調する // "editor.fontFamily": "'Roboto Mono'", // フォント // "editor.fontSize": 20, // 文字サイズ // "editor.glyphMargin": false, // 行の左端に余白を作る // "editor.quickSuggestions": { // "comments": false, // コメント内では無効 // "strings": true, // 文字列内では有効 // "other": true // その他の場所で有効 // }, // 補完候補の自動表示 "editor.formatOnType": true, // コード整形 // "editor.rulers": [100], // 右端のルーラー位置 // "editor.folding": false, // コードの折りたたみを許可 // "editor.letterSpacing": -1, // 文字の間隔を詰める // "editor.lineNumbers": "false", // 行番号の表示 // "editor.minimap.enabled": false, // ミニマップの表示 "editor.minimap.maxColumn": 50, // ミニマップの幅 // "editor.scrollBeyondLastLine": false, // 最終行よりも下へのスクロールを許可 "editor.renderWhitespace": "boundary", // 連続した空白文字を可視化 "editor.insertSpaces": true, // Tabキーで半角スペースを入力 // "editor.renderIndentGuides": false, // インデントのガイドラインを表示 // "editor.minimap.renderCharacters": false, // ミニマップを簡略化 "editor.minimap.showSlider": "always", // ミニマップのハイライトを常に表示 // "editor.minimap.side": "right", // ミニマップを右に表示 "editor.autoIndent": "brackets", // オートインデント // "editor.cursorStyle": "line", // カーソルの形状 // "editor.cursorBlinking": "smooth", // カーソルの表示形式 // "editor.cursorWidth": 5, // カーソル幅 // "editor.emptySelectionClipboard": true, // 選択範囲無しでのコピーを許可 "editor.links": true, // リンクをクリック可能に "editor.matchBrackets": "near", // 対応する括弧の強調表示をオンに // "editor.mouseWheelScrollSensitivity": 0.7, // マウスホイール回転の移動係数 // "editor.mouseWheelZoom": false, // Ctrl+マウスホイールによるズームを無効化 // "editor.suggestFontSize": 16, // サジェストの文字サイズ // "editor.suggestLineHeight": 16, // サジェスト欄の行の高さ "editor.renderControlCharacters": true, // 制御コードの表示 // ターミナル "terminal.integrated.shell.windows": "cmd.exe", // PowerShell嫌い "terminal.integrated.profiles.windows": { "PowerShell": null, "Git Bash": null, "IPython": { "path": "${env:PYTHONPATH}/Scripts/ipython.exe", "args": [ "-i", "--no-banner" ] }, "base": { "path": "${env:APPROOT}/usr/bin/connbase.cmd" } }, // "terminal.integrated.fontFamily": "'Roboto Mono'", // フォント "terminal.integrated.fontSize": 16, // フォントサイズ "terminal.integrated.copyOnSelection": true, "terminal.integrated.cursorBlinking": true, // "terminal.integrated.detectLocale": "off", "terminal.integrated.scrollback": 10000, // ファイル設定 "files.autoSave": "off", //ダーティファイルの作成を無効 "files.eol": "\n", // 改行コードをLF(Linux/OSX)にする "files.insertFinalNewline": true, // ファイルの終端に空の行を追加 "files.autoGuessEncoding": true, // 文字コードを自動判別 // エクスプローラーから除外するファイルとフォルダ "files.exclude": { "**/__pycache__": true, "**/.DS_Store": true, "**/.egg": true, "**/.git": true, "**/.hg": true, "**/.history": true, "**/.pylint.d": true, "**/.pytest_cache": true, "**/.svn": true, "**/*.dll": true, "**/*.idb": true, "**/*.ilk": true, "**/*.o": true, "**/*.obj": true, "**/*.pdb": true, "**/*.pyd": true, "**/*.tlog": true, "**/*.vs": true, "**/CVS": true }, // ワークベンチ設定 "debug.terminal.clearBeforeReusing": true, "workbench.editorAssociations": [ { "viewType": "jupyter.notebook.ipynb", "filenamePattern": "*.ipynb" } ], "workbench.editor.enablePreview": false, // "workbench.editor.showTabs": true, // アクティビティバー(左端)を非表示に "workbench.editor.tabSizing": "shrink", // タブが多い場合,文字を非表示にしてもタブ表示を優先する // "workbench.statusBar.visible": true, // ステータスバー(下端)を表示 // "workbench.sideBar.location": "left", // サイドバーを左に // "workbench.colorTheme": "Breeze Dark Theme", // カラーテーマ // "workbench.iconTheme": "eq-material-theme-icons", // アイコンの適用 "workbench.colorCustomizations": { // カラーテーマに上書きする個別の設定 // "statusBar.background": "#000000", // ステータスバー背景色 // "statusBar.noFolderBackground": "#000000", // "statusBar.foreground": "#ffffff", // ステータスバー前景色 // "statusBar.noFolderForeground": "#ffffff", "statusBar.border": "#ffffff", // ステータスバーの境界線 // "sideBar.background": "#000000", // サイドバーの背景色 // "sideBar.foreground": "#ffffff", // サイドバーの前景色 // "sideBar.border": "#ffffff", // サイドバーの境界線 // "activityBar.background": "#000000", // アクティビティバーの背景色 // "activityBar.foreground": "#ffffff", // アクティビティバーの前景色 // "activityBar.border": "#ffffff", // アクティビティバーの境界線 // "editor.background": "#121817", // エディタ背景色 // "editor.lineHighlightBackground": "#002255", // 選択している行の強調色 // "editor.selectionBackground": "#660000", // 選択領域の強調色 "editorError.border": "#ff0000", // エラー部分の下線 // "editorLineNumber.foreground": "#0077ffbb", // "editorLineNumber.activeForeground": "#ffffff", // "scrollbarSlider.background": "#0077ff99", // スクロールバーの色 // "scrollbarSlider.hoverBackground": "#00ccffcc", // 移動中のスクロールバーの色 // "tab.activeBorder": "#ffffff", // アクティブタブの下線 // "tab.inactiveForeground": "#999999", // 非選択タブの文字色 // "editorBracketMatch.background": "#ffff0077", // 対応する括弧の背景色 // "editorSuggestWidget.selectedBackground": "#0044ff", // サジェスト欄,選択中項目の背景色 // "scrollbar.shadow": "#0077ff99", "editorLink.activeForeground": "#5555ce", }, // クラッシュレポートを送信する "telemetry.enableCrashReporter": false, "telemetry.enableTelemetry": false, // 拡張機能関連 "extensions.autoUpdate": true, // 自動更新 "extensions.ignoreRecommendations": false, // 推奨事項の通知をOFF // Git "git.path": "${env:APPROOT}/usr/libexec/git-core/git.exe", // markdown "markdown.preview.breaks": true, // 改行を反映 "markdown.preview.fontSize": 22, // 文字サイズ "markdown.preview.lineHeight": 1.1, // 行幅 // C/C++ "C_Cpp.updateChannel": "Insiders", "C_Cpp.clang_format_style": "{ BasedOnStyle: Chromium, BreakBeforeBraces: Attach, SpaceBeforeParens: Never, IndentWidth: 4 }", "C_Cpp.default.compilerPath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.28.29910\\bin\\HostX64\\x64\\cl.exe", //Python "python.pythonPath": "${env:PYTHONPATH}/python.exe", "python.terminal.launchArgs": [ "-c", "from IPython import start_ipython; start_ipython()", "-i", "--no-banner" ], "python.linting.enabled": true, "python.linting.pylintEnabled": false, "python.linting.flake8Enabled": true, "python.linting.lintOnSave": true, "python.linting.flake8Args": [ "--max-line-length=160", "--ignore=E302,W504,W391", "--exclude=test/*,.*", "max-complexity=10" ], "python.formatting.provider": "autopep8", "python.formatting.autopep8Args": [ "--max-line-length=160" //"--aggressive", "--aggressive", ], "code-runner.executorMap": { "javascript": "node", "java": "cd $dir && javac $fileName && java $fileNameWithoutExt", "c": "cd $dir && gcc $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", "cpp": "cd $dir && g++ $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", "objective-c": "cd $dir && gcc -framework Cocoa $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", "php": "php", "python": "%PYTHONPATH%/python.exe -u", "perl": "perl", "perl6": "perl6", "ruby": "ruby", "go": "go run", "lua": "lua", "groovy": "groovy", "powershell": "powershell -ExecutionPolicy ByPass -File", "bat": "cmd /c", "shellscript": "bash", "fsharp": "fsi", "csharp": "scriptcs", "vbscript": "cscript //Nologo", "typescript": "ts-node", "coffeescript": "coffee", "scala": "scala", "swift": "swift", "julia": "julia", "crystal": "crystal", "ocaml": "ocaml", "r": "Rscript", "applescript": "osascript", "clojure": "lein exec", "haxe": "haxe --cwd $dirWithoutTrailingSlash --run $fileNameWithoutExt", "rust": "cd $dir && rustc $fileName && $dir$fileNameWithoutExt", "racket": "racket", "scheme": "csi -script", "ahk": "autohotkey", "autoit": "autoit3", "dart": "dart", "pascal": "cd $dir && fpc $fileName && $dir$fileNameWithoutExt", "d": "cd $dir && dmd $fileName && $dir$fileNameWithoutExt", "haskell": "runhaskell", "nim": "nim compile --verbosity:0 --hints:off --run", "lisp": "sbcl --script", "kit": "kitc --run", "v": "v run", "sass": "sass --style expanded", "scss": "scss --style expanded", "less": "cd $dir && lessc $fileName $fileNameWithoutExt.css", "FortranFreeForm": "cd $dir && gfortran $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", "fortran-modern": "cd $dir && gfortran $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", "fortran_fixed-form": "cd $dir && gfortran $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", "fortran": "cd $dir && gfortran $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt" }, "code-runner.saveFileBeforeRun": true, "code-runner.runInTerminal": true, "code-runner.preserveFocus": true, "code-runner.clearPreviousOutput": true, // "[python]": { // "editor.defaultFormatter": "ms-python.python" // }, // "editor.defaultFormatter": "formulahendry.code-runner", // "[cpp]": { // "editor.defaultFormatter": "ms-vscode.cpptools" // }, "debug.openExplorerOnEnd": true, "debug.openDebug": "openOnDebugBreak" } c_cpp_properties.json { "configurations": [ { "name": "win64_d", "includePath": [ "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.28.29910\\ATLMFC\\include", "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.28.29910\\include", "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\ucrt", "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\shared", "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\um", "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\winrt", "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\cppwinrt", "${env:PYTHONPATH}\\include", "${workspaceFolder}/**" ], "defines": [ "_DEBUG", "UNICODE", "_UNICODE" ], "windowsSdkVersion": "10.0.18362.0", "compilerPath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.28.29910\\bin\\Hostx64\\x64\\cl.exe", "cStandard": "c11", "cppStandard": "c++14", "intelliSenseMode": "windows-msvc-x64" } ], "version": 4 } task.json { // Variable Example // ${workspaceFolder} /home/your-username/your-project // ${workspaceFolderBasename} your-project // ${file} /home/your-username/your-project/folder/file.ext // ${relativeFile} folder/file.ext // ${relativeFileDirname} folder // ${fileBasename} file.ext // ${fileBasenameNoExtension} file // ${fileDirname} /home/your-username/your-project/folder // ${fileExtname} .ext // ${lineNumber} VSCodeの編集画面で現在選択されている行番号 // ${selectedText} VSCodeの編集画面で現在選択されているテキスト // ${execPath} 実行中のVS Code実行可能ファイル「code.exe」のアドレス // ${env:xxxxxx} 環境変数 // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format "version": "2.0.0", "tasks": [ { "type": "process", "label": "clean", "command": "rm.exe", "args": [ "-rf", "build", "*.pyd", "*.egg-info", ], "problemMatcher": [ "$msCompile" ], }, { "type": "process", "label": "setup.py", "command": "${env:PYTHONPATH}\\python.exe", "args": [ "setup.py", "test" ], "group": "build", // { // "kind": "build", // "isDefault": true // }, "dependsOrder": "sequence", "dependsOn": [ "clean" ], "problemMatcher": [ "$msCompile" ], }, { "type": "cppbuild", "label": "prebuild", "command": "mkdir", "args": [ "build", ">nul", "2>&1", "&", "echo", ">nul" ], "presentation": { "echo": false, "reveal": "never", "focus": false, "panel": "shared", "showReuseMessage": false, "clear": true } }, { "type": "cppbuild", "label": "DebugBuildCpp", "command": "cmd.exe", "args": [ "/C", "chcp", "65001", "&&", "cl.exe", "/source-charset:utf-8", "/Zi", "/EHsc", "/nologo", "/Fe:", "build\\${fileBasenameNoExtension}.exe", "${file}", "/JMC", "/ifcOutput", "build\\", "/GS", "/W3", "/Zc:wchar_t", "/Zi", "/Gm-", "/Od", "/RTC1", "/sdl", "/Fd:build\\${fileBasenameNoExtension}.pdb", "/Zc:inline", "/fp:precise", "/D", "_DEBUG", "/D", "_CONSOLE", "/D", "_UNICODE", "/D", "UNICODE", "/errorReport:prompt", "/WX-", "/Zc:forScope", "/Gd", "/MDd", "/FC", "/Fabuild\\", "/EHsc", "/nologo", "/Fo:build\\${fileBasenameNoExtension}.obj", "/Fp:build\\${fileBasenameNoExtension}.pch", "/diagnostics:column", "/IC:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.28.29910\\ATLMFC\\include", "/IC:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.28.29910\\include", "/IC:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\ucrt", "/IC:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\shared", "/IC:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\um", "/IC:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\winrt", "/IC:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\cppwinrt", "/I${env:PYTHONPATH}\\include", "/I.\\", "/link", "/LIBPATH:C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.28.29910\\ATLMFC\\lib\\x64", "/LIBPATH:C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.28.29910\\lib\\x64", "/LIBPATH:C:\\Program Files (x86)\\Windows Kits\\10\\lib\\10.0.18362.0\\ucrt\\x64", "/LIBPATH:C:\\Program Files (x86)\\Windows Kits\\10\\lib\\10.0.18362.0\\um\\x64", "/LIBPATH:${env:PYTHONPATH}\\libs", "/LIBPATH:.\\", "/OUT:build\\${fileBasenameNoExtension}.exe", "/MANIFEST", "/PROFILE", "/NXCOMPAT", "/DYNAMICBASE", "/INCREMENTAL:NO", "kernel32.lib", "user32.lib", "gdi32.lib", "winspool.lib", "comdlg32.lib", "advapi32.lib", "shell32.lib", "ole32.lib", "oleaut32.lib", "uuid.lib", "odbc32.lib", "odbccp32.lib", "/SUBSYSTEM:CONSOLE", "/MANIFESTUAC:level='asInvoker' uiAccess='false'", "/ManifestFile:build\\${fileBasenameNoExtension}.exe.intermediate.manifest", "/ERRORREPORT:PROMPT" ], "options": { "cwd": "${workspaceFolder}" }, "problemMatcher": [ "$msCompile" ], "presentation": { "echo": true, "reveal": "never", "focus": false, "panel": "shared", "showReuseMessage": false, "clear": true }, "dependsOrder": "sequence", "dependsOn": [ "prebuild" ], "group": "build", "detail": "cl.exe" } ] } launch.json { "version": "0.2.0", "configurations": [ // for Python { "name": "Python: Debug Run", "type": "python", "request": "launch", "program": "${file}", "args": [], "console": "integratedTerminal", "preLaunchTask": "setup.py", }, // for C/C++ { "name": "C/C++: Debug Run File", "type": "cppvsdbg", "request": "launch", "program": "build/${fileBasenameNoExtension}.exe", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], "preLaunchTask": "DebugBuildCpp", // "console": "newExternalWindow", // "console": "integratedTerminal" "console": "internalConsole" }, ] }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Python および Keithley 2401 sourcemeter を用いて CV を作る(3)

はじめに (1)では必要なソフトのインストールを行った。 (2)では測定に用いるプログラムについて解説した。 いよいよ(3)では測定方法を述べる。また、理解を深めるための演習問題を課す。 測定 実験器具および装置 CVセル一式 ・電解液(1 mM K3[Fe(CN)6] および 100 mM KClを含む水溶液) 20 mL程度 ・作用電極 ・対極 ・参照電極 測定装置 Keithley 2400 ソースメータ ケーブル 4本(赤黒2本ずつ) 測定準備 ・CVセルの用意 通常は測定前に窒素バブリングを15分程度行うことで溶存酸素を追い出す必要がある。が、練習実験でとりあえず測ってみるためならそこまでしなくても良いと思う。 ・ケーブルの接続 ケースレーのアプリケーションノートを参考に、以下の通りケーブルを接続する。 Force HI(ソースメータ前面右上の赤)と作用電極、Force LO(右下の黒)と対極、 Sense HI(左上の赤) と作用電極、 Sense LO(左下の黒)と参照電極を接続する。 画像はケースレーのアプリケーションノートより引用。 このような接続にする理由を簡単に説明する(適宜、上の画像を参照すること)。 前提として、ポテンショスタットの機能は次の3つである(BASの資料を参照)。 1. 参照電極に対する作用電極の電位を制御する 2. 作用電極に流れる電流を測定する 3. 参照電極にはほとんど電流を流さない 設定した電圧を4 線式で印可するとき、ソースメータは Sense HI - Sense LO 間の電圧が設定電圧になるように電源電圧をフィードバックする。したがって、4 線式で Sense に参照電極-作用電極をそれぞれ接続することで、参照電極に対する作用電極の電位を任意に設定することができる(1)。測定用のプログラムにおいて電流を測定するよう設定している(keithley.measure_current)ので、作用電極に流れる電流を測定できる(2)。最後に、2400 ソースメータの入力インピーダンスは 10^10 Ω以上あることから、参照電極に電流はほとんど流れない(3)。以上より、今回のようにケーブルを接続することで、ソースメータをポテンショスタットのように用いることができる。 測定 任意の条件を入力して測定を行う。 演習問題 測定に関する考察課題 0.01~0.1 V/s のうちの任意の 5 種類の掃引速度について測定を行い、得られた結果について以下の点で考察せよ。1~3、すべて考えてみてほしい。 1. 最初の1セグメント目では酸化ピークが見られない。その理由を考察せよ。 2. ピーク電流値が Randles-Sevcik式に従う(ピーク電流値が掃引速度の平方根と線形の関係にある)ことを確認せよ。 3. 掃引速度によっては Randles-Sevcik式に従わない場合もあるかと思う。その原因を考察せよ。何が問題なのか。 プログラミング 次の機能を持つように、(2)で示されたコードを書き換えよ。1 は少なくとも考えてみてほしい。2 以降は、興味があれば。 1. 初期電位を出発して電位を掃引させる方向を掃引方向という。変数 direction に p を代入すると掃引方向が正に、n を代入すると掃引方向が負になるようにせよ。 2. 任意の電位を初期電位(start_V)として設定できるようにせよ。ただし(当然だが)設定できる電位は low_V 以上 high_V 以下の値であることを前提とする。 3. (2)のコードを参考に、一定時間ごとに開回路電圧を測定するプログラムを書け。開回路電圧とは、サンプルに外部から電流を印可していない(0 mA の電流を印可している)状態の電圧のことである。 https://www.toyo.co.jp/material/faq/detail/id=4713#:~:text=%E9%96%8B%E5%9B%9E%E8%B7%AF%E9%9B%BB%E5%9C%A7(Open%20Circuit,%E9%9B%BB%E4%BD%8D%E5%B7%AE%E3%82%92%E7%A4%BA%E3%81%97%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82&text=%E3%81%9F%E3%81%A8%E3%81%88%E3%81%B0%E3%80%81%E5%88%9D%E6%9C%9F%E9%9B%BB%E4%BD%8D%E3%82%92%2B100%20mV%20vs. おわりに 本シリーズでは電気化学の主要な測定手法の 1 つであるサイクリックボルタンメトリー(CV)を、ソースメータを用いて実行する方法について述べた。今回公開したコードでは(特に掃引速度に関して)市販の電気化学アナライザに匹敵する精度の測定は困難である。しかしながら、プログラミングによりソースメータを自ら制御してみることで、ポテンショスタットの役割をより深く理解できるようになるであろう。 参考文献 ケースレー製品による電気化学テストとアプリケーション https://jp.tek.com/-/media/files/jp-documents/5-1_echem-testmethods-application-1kz-60158-0.pdf 本シリーズはこれを参考に作成した。 2400 ソースメータ https://download.tek.com/datasheet/2400-jp.pdf この資料によるとセンス入力インピーダンスは 10^10 Ω 以上。センス入力インピーダンスが 4 線式使用時の電圧計(Sense側)の抵抗値だと解釈した。加えて、WE-CE 間の抵抗値はせいぜい kΩ オーダー(10^3~10^6 Ω)である。以上から、電圧計にほとんど電流は流れないと結論づけた。 BAS 電極ハンドブック https://www.bas.co.jp/ELH.html BAS の資料は測定方法も具体的でとてもわかりやすい。あまりメジャーではないかもしれないが、Youtube の動画もわかりやすいのでオススメ。 電気化学の基礎 https://www.bas.co.jp/xdata/2009_1st_seminar/watanabe.pdf 今回のようにケーブルを接続する理由について、この資料をもとに考察した。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Python および Keithley 2401 sourcemeter を用いて CV 測定を行う(3)

はじめに (1)では必要なソフトのインストールを行った。 (2)では測定に用いるプログラムについて解説した。 いよいよ(3)では測定方法を述べる。また、理解を深めるための演習問題を課す。 測定 実験器具および装置 CVセル一式 ・電解液(1 mM K3[Fe(CN)6] および 100 mM KClを含む水溶液) 20 mL程度 ・作用電極 ・対極 ・参照電極 測定装置 Keithley 2400 ソースメータ ケーブル 4本(赤黒2本ずつ) 測定準備 ・CVセルの用意 通常は測定前に窒素バブリングを15分程度行うことで溶存酸素を追い出す必要がある。が、練習実験でとりあえず測ってみるためならそこまでしなくても良いと思う。 ・ケーブルの接続 ケースレーのアプリケーションノートを参考に、以下の通りケーブルを接続する。 Force HI(ソースメータ前面右上の赤)と作用電極、Force LO(右下の黒)と対極、 Sense HI(左上の赤) と作用電極、 Sense LO(左下の黒)と参照電極を接続する。 画像はケースレーのアプリケーションノートより引用。 このような接続にする理由を簡単に説明する(適宜、上の画像を参照すること)。 前提として、ポテンショスタットの機能は次の3つである(BASの資料を参照)。 1. 参照電極に対する作用電極の電位を制御する 2. 作用電極に流れる電流を測定する 3. 参照電極にはほとんど電流を流さない 設定した電圧を4 線式で印可するとき、ソースメータは Sense HI - Sense LO 間の電圧が設定電圧になるように電源電圧をフィードバックする。したがって、4 線式で Sense に参照電極-作用電極をそれぞれ接続することで、参照電極に対する作用電極の電位を任意に設定することができる(1)。測定用のプログラムにおいて電流を測定するよう設定している(keithley.measure_current)ので、作用電極に流れる電流を測定できる(2)。最後に、2400 ソースメータの入力インピーダンスは 10^10 Ω以上あることから、参照電極に電流はほとんど流れない(3)。以上より、今回のようにケーブルを接続することで、ソースメータをポテンショスタットのように用いることができる。 測定 任意の条件を入力して測定を行う。 演習問題 測定に関する考察課題 0.01~0.1 V/s のうちの任意の 5 種類の掃引速度について測定を行い、得られた結果について以下の点で考察せよ。1~3、すべて考えてみてほしい。 1. 最初の1セグメント目では酸化ピークが見られない。その理由を考察せよ。 2. ピーク電流値が Randles-Sevcik式に従う(ピーク電流値が掃引速度の平方根と線形の関係にある)ことを確認せよ。 3. 掃引速度によっては Randles-Sevcik式に従わない場合もあるかと思う。その原因を考察せよ。何が問題なのか。 プログラミング 次の機能を持つように、(2)で示されたコードを書き換えよ。1 は少なくとも考えてみてほしい。2 以降は、興味があれば。 1. 初期電位を出発して電位を掃引させる方向を掃引方向という。変数 direction に p を代入すると掃引方向が正に、n を代入すると掃引方向が負になるようにせよ。 2. 任意の電位を初期電位(start_V)として設定できるようにせよ。ただし(当然だが)設定できる電位は low_V 以上 high_V 以下の値であることを前提とする。 3. (2)のコードを参考に、一定時間ごとに開回路電圧を測定するプログラムを書け。開回路電圧とは、サンプルに外部から電流を印可していない(0 mA の電流を印可している)状態の電圧のことである。 https://www.toyo.co.jp/material/faq/detail/id=4713#:~:text=%E9%96%8B%E5%9B%9E%E8%B7%AF%E9%9B%BB%E5%9C%A7(Open%20Circuit,%E9%9B%BB%E4%BD%8D%E5%B7%AE%E3%82%92%E7%A4%BA%E3%81%97%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82&text=%E3%81%9F%E3%81%A8%E3%81%88%E3%81%B0%E3%80%81%E5%88%9D%E6%9C%9F%E9%9B%BB%E4%BD%8D%E3%82%92%2B100%20mV%20vs. おわりに 本シリーズでは電気化学の主要な測定手法の 1 つであるサイクリックボルタンメトリー(CV)を、ソースメータを用いて実行する方法について述べた。今回公開したコードでは(特に掃引速度に関して)市販の電気化学アナライザに匹敵する精度の測定は困難である。しかしながら、プログラミングによりソースメータを自ら制御してみることで、ポテンショスタットの役割をより深く理解できるようになるであろう。 参考文献 ケースレー製品による電気化学テストとアプリケーション https://jp.tek.com/-/media/files/jp-documents/5-1_echem-testmethods-application-1kz-60158-0.pdf 本シリーズはこれを参考に作成した。 2400 ソースメータ https://download.tek.com/datasheet/2400-jp.pdf この資料によるとセンス入力インピーダンスは 10^10 Ω 以上。センス入力インピーダンスが 4 線式使用時の電圧計(Sense側)の抵抗値だと解釈した。加えて、WE-CE 間の抵抗値はせいぜい kΩ オーダー(10^3~10^6 Ω)である。以上から、電圧計にほとんど電流は流れないと結論づけた。 BAS 電極ハンドブック https://www.bas.co.jp/ELH.html BAS の資料は測定方法も具体的でとてもわかりやすい。あまりメジャーではないかもしれないが、Youtube の動画もわかりやすいのでオススメ。 電気化学の基礎 https://www.bas.co.jp/xdata/2009_1st_seminar/watanabe.pdf 今回のようにケーブルを接続する理由について、この資料をもとに考察した。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PythonからSQL Serverを動かそう!~接続編~

目次 0.この記事を書いた経緯 1.対象読者 2.環境 3.手順 4.苦労した点 5.まとめ 6.参考サイト 0-この記事を書いた経緯 PythonとSQL Serverの学習の備忘録として書きました。 この記事を読むと、SQL Serverに作成したDBの値をPythonで取り出して表示することができるようになります。 1-対象読者 Pythonを実行出来る環境がある方 (Jupyter Notebook、Visual Studio Code 等) pipでライブラリをインストールできる方 PythonとDBを一通り学習された初学者の方 DBをソースコードから動かしてみたい方 2-環境 Python 3.9.4 SQL Server 2019 (Express) SSMS(SQL Server Management Studio) 18.9(日本語版) pyodbc 4.0.30 ※すべてlocal環境(Windows10 64bit)で動作させています。 3-手順 (1)環境構築 ・「Python」,「SQL Server」,「SSMS(SQL Server Management Studio)」のインストール ※本記事ではインストールの手順については詳しく説明はしませんのでよく調べてダウンロードして下さい。下記に参考URLを置いておきます。 ・DBの準備 SSMSを立ち上げます。今回はWindows認証で接続します。 立ち上げたら「データベース」を右クリックして「新しいデータベース」を押下します。 押下すると以下のウィンドウが立ちあがるので任意の名前を入力します。入力したら「OK」を押します。 戻るとデータベースができているので今度は画面の階層までフォルダを展開して、「テーブル」を右クリックします。「新規作成」から「テーブル」を押下します。 以下の画像のようにテーブルを作成します(あくまで1例)。 ※id列のプロパティの「テーブルデザイナー」の「IDENTITY」の指定を「はい」にすると自動でidが追加されます。 保存するとテーブルの名前を要求されるので任意の名前を入力します。 オブジェクトエクスプローラーの画像の更新マークを押下します。 押下して「テーブル」まで展開するとテーブルが作成されているのがわかります。 データベースに任意の値を入力します。テーブルを右クリックして「上位200行の編集」を押下します。 適当な値を入力します。 ・TCP/IPの設定 スタートメニューから「SQL Server構成マネージャー」を開き「SQL Serverネットワークの構成」を展開し、「SQLEXPRESSのプロトコル」の「TCP/IP」を有効にします。 「IPアドレスタグ」を開き、一番下にある「IPALL」の「TCPポート」を「1433」に設定します。 ・pyodbcのインストール pyodbcとはMicrosoftが推奨しているPython 用の SQL ドライバーです。今回はpyodbcを使用するのでインストールをします。インストールについてはこちらを参考に行ってください。 以上で準備は完了です。 (2)コードの用意 main.py import pprint import pyodbc def login(): driver='{SQL Server}' server = '(1)SQLServerが稼働しているサーバー名' database = '(2)データベース名' trusted_connection='yes' connect= pyodbc.connect('DRIVER='+driver+';SERVER='+server+';DATABASE='+database+';PORT=1433;Trusted_Connection='+trusted_connection+';') cursor = connect.cursor() cursor.execute( "SELECT * FROM (3)Table_1" ) rows = cursor.fetchall() pprint.pprint( rows ) cursor.close() connect.close() if __name__ == '__main__':login() (3)コードの内容 コードの(1)、(2)、(3)には以下の画像の(1)、(2)、(3)の値を入力します。 コードを実行すると以下のようになり、値を取り出せました。 実行結果 [(1, 'a', 1000, '2021-03-01'), (2, 'b', 2000, '2021-04-01')] 4-苦労した点 別の環境で「SQL Server構成マネージャー」を探した際に、スタートメニューにありませんでした。結局場所についてはこちらを参考にしたら見つかりました。 5-まとめ DBをPythonから動かすことに成功しました。次はWebアプリケーションのGUIから値を操作することを目標に開発しようと思います。 6-参考サイト ・各種ソフトウェアのインストール Download Python | Python.org オンプレミスまたはクラウドで SQL Server をお試しください SQL Server Management Studio (SSMS) のダウンロード 手順 1:pyodbc Python 開発用に開発環境を構成する ・DBの環境構築 pyodbcでWindows認証でSQLServerにリモート接続する方法 Python環境にpyodbcをインストールしてSQLServerに接続する手順 Configure the Windows Firewall to Allow SQL Server Access
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Python 少ない点に対する近似曲線 2

続き この記事は前回の記事の続きです。 今回は2つのランダム点間の分割に加えて、近似曲線も分割してみます。 例) ランダム点が30個の場合 ランダム点30個、次数30 極大ランダム点で極小となっていたり、その逆になったりしています。曲線の右側もおかしな極値を取っています。 ランダム点30個、次数60 次数を倍にしてみました。曲線の右側のおかしな挙動は改善されましたが、それでもグラフ中央付近は改善が見られません。 近似曲線の分割 近似曲線を分割するため、中間ランダム点を格納したndarrayを分割します。 sample6.py import matplotlib.pyplot as plt import random import numpy as np import math SIZE = 30 SEED = 2 DEGREE = 30 SPLIT_DISTANCE = 0.1 # 2点のランダム点の距離を0.1の長さに分割する SPLIT_ARRAY = 3 # 中間ランダム点の分割数 def plot_split(x_val1, x_val2, y_val1, y_val2, x_medium_points, y_medium_points): """ 各ランダム点の中間点を生成するメソッド (x_val1, y_val1), (x_val2, y_val2): 2点のランダム点 x_medium_points: 中間点のx座標をすべて格納する配列 y_medium_points: 中間点のy座標をすべて格納する配列 """ # 2点のランダム点の距離を計算 distance = math.sqrt(math.pow(x_val2 - x_val1, 2) + math.pow(y_val2 - y_val1, 2)) # 必要な中間点の数を計算 spl_num = math.floor(distance / SPLIT_DISTANCE) # 2点のランダム点を分割する. (x, y)が中間点の座標 x_ = np.linspace(x_val1 ,x_val2, spl_num) y_ = np.linspace(y_val1 ,y_val2, spl_num) # 中間点を追加する x_medium_points = np.append(x_medium_points, x_) y_medium_points = np.append(y_medium_points, y_) return x_medium_points, y_medium_points def plot_split_curve(x_medium_points, y_medium_points, DEGREE, n): """ 分割した中間ランダム点を描画するメソッド """ coeff = np.polyfit(x_medium_points, y_medium_points, DEGREE) y_polyfit = np.poly1d(coeff)(x_medium_points) plt.plot(x_medium_points, y_medium_points, marker='o') if n == 0: plt.plot(x_medium_points, y_polyfit, label='approximate curve', color='red') else: plt.plot(x_medium_points, y_polyfit, color='red') def plot_curve(): """ 近似曲線を描画するメソッド """ np.random.seed(seed=SEED) plt.figure(figsize=(8.0, 6.0)) x = np.array(range(SIZE)) y = np.random.rand(SIZE) x_medium_points = np.empty(0) # すべての中間点のx座標を格納するndarray y_medium_points = np.empty(0) # すべての中間点のy座標を格納するndarray # すべてのランダム点間を分割するループ for i in range(SIZE - 1): x_medium_points, y_medium_points = plot_split( x[i], x[i + 1], y[i], y[i + 1], x_medium_points, y_medium_points ) # ndarrayの分割 for n, x_split_array, y_split_array in zip( range(SPLIT_ARRAY), np.array_split(x_medium_points, SPLIT_ARRAY), np.array_split(y_medium_points, SPLIT_ARRAY) ): plot_split_curve(x_split_array, y_split_array, DEGREE, n) plt.legend() plt.show() plot_curve() ランダム点30個、次数30、中間ランダム点の分割数3 ランダム点30個、次数30、中間ランダム点の分割数6 参考記事
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python tips】htmlタグの削除の方法

1.はじめに 今回はテキストデータからHTMLタグを削除する方法を紹介します。 htmlタグは文章の意味を学習させる際にノイズとなるデータです。 なので、削除してあげることが重要になります。 2.環境 MacOS Catalina10.15.5 Miniconda Python3.7.5 3.例題 はまってしまう!楽しい!! ついついやってしまいます。<br />簡単なものから難しいものまで<br />子供と一緒に楽しく遊べて考えながら<br />出来るので面白いです。 Amazon Reviewのデータセットからタグが付いている文章を抽出しました。 ここからタグを抜き出しましょう。 4.方法 4.1.beautiful Soupのインストール まずはPythonライブラリであるbeautiful soupをMiniconda環境にインストールします。 >conda install beautiful Soup 4.2.変数htmlに文字列を代入 >>>html = ""はまってしまう!楽しい!! ついついやってしまいます。<br />簡単なものから難しいものまで<br />子供と一緒に楽しく遊べて考えながら<br />出来るので面白いです。"" 4.3.HTMLタグを除去する関数を定義 from bs4 import BeautifulSoup def clean_html(html, strip=False): soup = BeautifulSoup(html, 'html.parser')     text = soup.get_text(strip=strip) return text 4.4.出力する clean_html(html) 他にも正規表現を使った方法などもあるので追々紹介できたらと思います!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

モダンFortran向けドキュメント自動生成ツールFORDの使い方

概要 FORDはFORtran Documenterの略で,モダンFortranプログラム向けのドキュメント自動生成ツールです.Fortranプログラムのドキュメント生成において,Doxygenでは不十分であり,かつ代替ツールが無いことが,FORD開発のきっかけだったようです. FORDは,ソースコードから変数,派生型定義,手続き(関数およびサブルーチン),モジュールの情報を抽出し,ドキュメントを生成します.それらの情報に,コメントで追加の情報を付加することができます.コメントには,MarkdownやLaTeX記法を利用できます.また,関数の呼出し関係やモジュールの参照関係,派生型の継承関係を図示することができます. FORDは多機能ですが,わかりにくい部分や落とし穴もあります. FORDがドキュメントと称しているのは,プログラミングインタフェース情報です. プログラミング言語におけるリファレンスに相当 インストール方法や背景理論,サンプルなど,いわゆるアプリケーションにおけるドキュメントは,ページと呼ばれています. ドキュメントの出力ディレクトリの中身は,FORDでドキュメントを生成する際に何の断りもなく削除されます. 本記事では,FORDの用語に沿って,FORDが生成するプログラミングインタフェース情報をドキュメント,それ以外をページと称します. 環境 Windows Windows 10 Pro 20H2 Python 3.8.5 (Anaconda Individual Edition 4.10.1) FORD 6.0.0 python-graphviz 0.16 graphviz 2.38.0 Linux Ubuntu 18.04 (on WSL) Python 3.6.9 FORD 6.0.0 graphviz 2.40.1 FORDのインストール FORD本体のインストール FORDのインストールには,pipを利用します. Windowsの場合は,Anaconda Promptを管理者権限で起動して, pip install FORD を実行します. Ubuntuの場合は,sudoを付けて実行します. sudo pip install FORD 日本語を含むファイルを処理する場合,日本語のエンコードに起因してFORDがエラーになる場合があります.Windowsで日本語エンコードにUTF-8を用いる場合,環境変数PYTHONUTF8の値を1に設定してください. graphvizのインストール(Windowsのみ) FORDは,関数の呼出し関係やモジュールの参照関係,派生型の継承関係の関係図の生成にgraphvizを利用します.pipでFORDをインストールすると,graphviz1もまとめてインストールしてくれるのですが,Windowsの場合は,Windows上で動くgraphvizのバイナリもインストールする必要があります. バイナリのインストールには,condaを利用します. conda install graphviz その後,graphvizのバイナリがインストールされたディレクトリをパスに追加します. 著者の場合は,Anacondaを全ユーザが利用できる設定でインストールしているので,AnacondaはC:\ProgramData\Anaconda3にインストールされています.condaでインストールしたgraphvizは,Anacondaのインストールディレクトリ以下のLibrary\bin\graphvizにインストールされるので,C:\ProgramData\Anaconda3\Library\bin\graphvizを環境変数PATHに追加します. その後,コマンドプロンプトを起動して,dot -Vを実行します. >dot -V dot - graphviz version 2.38.0 (20140413.2041) などといった表示が現れれば,インストールは成功です. graphvizには,正式なWindows版も存在します2が,代用できるかは確認していません. FORDによるドキュメント生成 サンプルソースファイル サンプルとして,エラトステネスのふるいのソースを用います. main.f90 main.f90 program main use, intrinsic :: iso_fortran_env implicit none integer(int32), allocatable :: primes(:) call generate_primes_up_to(100, result=primes) print *, "number of primes", size(primes) print *, "generated primes", primes(:) contains subroutine generate_primes_up_to(num, result) use, intrinsic :: iso_fortran_env implicit none integer(int32), intent(in) :: num integer(int32), allocatable, intent(inout) :: result(:) integer(int32), allocatable :: number(:) if (num >= 2) then call initialize(number, num) call sieve(number) call extract_primes(number, result) deallocate (number) else allocate (primes(0)) end if end subroutine generate_primes_up_to subroutine initialize(number, num) use, intrinsic :: iso_fortran_env implicit none integer(int32), allocatable, intent(inout) :: number(:) integer(int32), intent(in) :: num integer(int32) :: i allocate (number(2:num), source=[(i, i=2, num)]) end subroutine initialize subroutine sieve(number) use, intrinsic :: iso_fortran_env implicit none integer(int32), intent(inout) :: number(2:) integer(int32) :: i, num num = maxval(number) do i = 2, int(num**0.5) if (number(i) /= 0) then number(i+i::i) = 0 !& end if end do end subroutine sieve subroutine extract_primes(number, result) use, intrinsic :: iso_fortran_env implicit none integer(int32), intent(in) :: number(2:) integer(int32), allocatable, intent(inout) :: result(:) result = pack(array=number, mask=(number /= 0)) end subroutine extract_primes end program main FORDの実行 FORDを用いてドキュメントを生成するには,FORD用の設定ファイルを作成し,それをコマンドライン引数としてFORDを実行します. ford 設定ファイル.md 設定ファイルは生成されるドキュメントのトップページも兼ねるので,設定ファイルには2種類の情報を書く必要があります. FORDの設定 トップページに書くべき内容 FORDの設定 設定ファイルに記述できる内容は非常に多いので,詳細は公式ページに任せて,必須と思われる内容を挙げていきます. 設定は全て 設定名: 値で指定します. なお,FORDは設定の途中に空行など設定以外の情報が入っていると,その時点で設定の読み込みを止める(以降はトップページの内容として扱う)ので,絶対に空行など設定以外の情報を入れないでください. プロジェクト情報 project プロジェクトの名前. summary プロジェクトの概要. license ドキュメントのライセンス.以下から選択 by, by-nd, by-sa, by-nc, by-nc-nd, by-nc-sa, gfdl, opl, pdl, bsd その他,必要があれば,githubやbitbucket, sourceforgeなどのURL,プロジェクトのWebサイトやロゴ(アイコン)などを指定できます. 著者情報 author 著者名 その他,著者の簡単な紹介,e-mailアドレスや各種SNSアカウントを指定できます. ディレクトリ情報 src_dir ソースファイルのディレクトリ(標準は設定ファイルのあるディレクトリをカレントとして./src) output_dir 生成されたドキュメントの出力ディレクトリ(標準は設定ファイルのあるディレクトリをカレントとして./doc) ディレクトリの指定には注意が必要です. 概要でも述べたとおり,FORDが生成するドキュメントは,プログラミングインタフェース情報です.インストール方法や背景理論,サンプルなど,いわゆるアプリケーションにおけるドキュメントを./docに置くことが多いでしょうが,output_dirを指定しないと,./docに置かれているファイルが全て消去されてしまいます. いくつかのプロジェクトでは,いわゆるアプリケーションにおけるドキュメントを./docに置き,FORDが生成するドキュメントを./api-docなど./docとは異なるディレクトリに出力し,FORDが生成するドキュメントはリポジトリに登録しないようにしています. 本記事もこれにならい,FORDが生成するドキュメントは./api-docに出力することにします. 設定ファイルの例 上記で挙げた設定を記述して,Fordでドキュメントを生成してみます.設定ファイル名はapi-doc-ford-settings.mdとしました. api-doc-ford-settings.md src_dir: ./src output_dir: ./api-doc project: エラトステネスのふるい summary: エラトステネスのふるいを用いて素数を生成する author: implicit none license: by-nc ファイルの配置は下記のようになっています. . ├── src │ └── main.f90 └── api-doc-ford-settings.md FORDの設定ファイルがあるディレクトリで,FORDを実行します. >ford api-doc-ford-settings.md Reading file src\main.f90 Processing documentation comments... Correlating information from different parts of your project... Creating HTML documentation... Creating search index... 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 6/6 [00:00<00:00, 22.70/s] Writing resulting documentation. カレントディレクトリにapi-docフォルダが出力されます. api-doc\index.htmlを開くと,下図のようなドキュメントが生成されたことが確認できます. Source Filesはソースファイルの一覧,Proceduresには手続き(関数およびサブルーチン)の一覧が現れています. Source Filesにあるmain.f90のリンクをクリックすると,シンタックスハイライト付きでソースファイルを確認できます. Proceduresのリンク,例えばgenerate_primes_up_toをクリックすると,インタフェース情報を確認できます. 設定ファイルにgraph: trueを追加して再度FORDでドキュメントを生成すると,他のモジュールや関数との関係が図示されます.何度も書きますが,設定を書く際は空行などを入れないようにしてください. 注釈による情報の追加 FORDでは,ソースファイルに注釈を付けることで,生成するドキュメントに情報を追加することができます.Documentation Markerとよばれる記号をコメントに続けて付けることで,注釈を記述できます. FORDでは,4種類のDocumentation Markerを定めています. FORDの設定名 Documentation Marker(標準,変更可能) docmark ! docmark_alt * predocmark > predocmark_alt |3 Documentation Markerは設定で変更可能ですが,#は注釈にMarkdownを使うときに混乱しますし,@は後述するFORDの拡張機能と重複するので,これといった代替記号を選定するのは難しいように思います. 変数,手続きに対する注釈 docmarkは,コメント記号に続けてDocumentation Markerを書くことで,以降のコメントが上の行に書かれた項目の注釈であることを意味します.コメントのインデントは必須ではありません.読みやすさのためにインデントしています. integer(int32), intent(in) :: num !! 素数の上限値 と書くと,素数の上限値がnumの注釈として扱われます.この状態でFORDによって処理すると,ドキュメントの引数に注釈が追加されます. docmarkによって注釈の対象となるのは1行のみです.複数行にわたる注釈を記述したい場合は,複数行にわたってdocmarkを付ける必要があります. integer(int32), intent(in) :: num !! 素数の上限値<br> !! 0以上の整数.負の数は受け付けない 行数が長くなると,docmarkを付けるのも大変になるので,複数行にわたる注釈を付けやすくするためにdocmark_altを利用します. integer(int32), allocatable, intent(inout) :: result(:) !* 生成された素数<br> ! 要素数は素数の個数に等しく,小さい素数から順番に格納される docmarkやdocmark_altとは逆に,注釈を付けたい項目の上に注釈を書きたい場合もあります.その場合は,predocmarkかpredocmark_altを用います. !> 素数の上限値<br> !> 0以上の整数.負の数は受け付けない integer(int32), intent(in) :: num !| 生成された素数<br> ! 要素数は素数の個数に等しく,小さい素数から順番に格納される integer(int32), allocatable, intent(inout) :: result(:) それ以外の注釈 変数や手続きのように,注釈を付ける項目がある場合は,docmarkやpredocmarkの挙動の違いは重要です.TODOや既知のバグ,あるいは関数の使用例を書く場合は,どれを使っても問題ありません. 下の例では,predocmark_altを利用しています.関数の中ほどに書いた注釈には,近くに関連付ける項目(関数や手続き)がありません.これらは,ドキュメント中に本文として表示されます.@todoは,FORDの機能です.詳しくは後述します. !|第1引数で指定された数を上限として,その数までの素数を生成する. ! 第2引数は,生成された素数を格納する. ! 素数生成のアルゴリズムにはエラトステネスのふるいを用いる. subroutine generate_primes_up_to(num, result) use, intrinsic :: iso_fortran_env implicit none integer(int32), intent(in) :: num !! 素数の上限値 <br> !! 0以上の整数.負の数は受け付けない integer(int32), allocatable, intent(inout) :: result(:) !! 生成された素数<br> !! 要素数は素数の個数に等しく,小さい素数から順番に格納される integer(int32), allocatable :: number(:) ! 2からnumまでの数表 !|##例 !```Fortran !program main ! integer(int32),allocatable :: primes(:) ! call generate_primes_up_to(num=10, result=primes) ! ! primes = [2, 3, 5, 7] !end program main !``` if (num >= 2) then call initialize(number, num) call sieve(number) call extract_primes(number, result) deallocate (number) else ! numが1以下であれば,素数は0個 !!@todo `num<0`の場合に警告を出す allocate (primes(0)) end if end subroutine generate_primes_up_to FORDで利用できる記法 FORDで注釈を付ける際,Markdown,LaTeXおよびFORD独自の拡張記法が利用できます. LaTeX記法を用いる場合,$...$は対応しておらず,\(...\)を利用するように指示されています. FORD独自の拡張記法には,@note, @warning, @todo, @bug環境があります.これらの使い方は全て同じで,この環境を用いると,FORDで処理された際に,強調表示されます. @todo num<0の場合に警告を出すのように1行で書くこともできます.複数行にわたって記述したい場合は@環境名~@end環境名で囲みます. @todo - リファクタリング - コマンドライン引数への対応 @endtodo その他,ドキュメント内の要素にリンクを張るための[[]]という記法も利用できます.それ以外にも多くの記法・機能があるので,詳しくは公式ページを確認してください. トップページの作成 さて,FORDの設定ファイルはトップページを兼ねていることを既に説明しました.トップページに何も情報がないのも見栄えが悪いので,FORDの記法を利用してトップページに情報を追記してみます. src_dir: ./src output_dir: ./api-doc project: エラトステネスのふるい summary: エラトステネスのふるいを用いて素数を生成する author: implicit none license: by-nc graph: true エラトステネスのふるいを用いて素数を生成する. @warning Work in progress @endwarning ## 素数生成の手順 エラトステネスのふるいでは,ある数\(n\)が与えられた時に,\(2\)から\(n\)までの数表を用意し,まず\(2\)の倍数を数表から取り除く. この作業をふるい落としと呼ぶ.数字を\(3, 4, 5...\lfloor\sqrt{n}\rfloor\)と順次変えて, その数の倍数を数表からふるい落とし,最後までふるい落とされなかった数を素数として扱う. @note このプロジェクトでは, - 数表を用意することを初期化(対応する手続きは[[initialize(procedure)]]) - 倍数を数表から取り除くことをふるい落とし(対応する手続きは[[sieve(procedure)]]) - ふるい落とされなかった数を取り出すことを素数の抽出(対応する手続きは[[extract_primes(procedure)]]) と呼ぶ. @endnote @todo - リファクタリング - コマンドライン引数への対応 - 他 @endtodo @bug 現在の所バグは見つかっていない. @endbug [[initialize(procedure)]]はFORDの独自拡張記述で,ドキュメント内のintializeという名前の手続きのページにリンクを張ります. ページの生成 FORDがドキュメントと称しているのはプログラミングインタフェース情報で,インストール方法や背景理論,サンプルなど,いわゆるアプリケーションにおけるドキュメントは,ページと呼ばれているのでした. FORDでは,ページも生成できます.ページを生成するには,設定でpage_dirを指定し,page_dirにMarkdown(およびFORDがサポートする記法)で内容を記述します. ページの生成では制約が二つあります. ページの基となる.mdファイルには,メタデータを記述する必要がある. page_dirおよびサブディレクトリには,index.mdという名前のファイルが必要 メタデータは3種類あります. - title: ページタイトル(必須) - author: ページの生成者(オプション) - date: ページの生成日(オプション) page_dirおよびサブディレクトリには,index.mdという名前のファイルが必要ですが,そのtitle:はファイル名と一致させる必要はありません. ページを生成する際,FORDの拡張機能の一つである,Markdown-include拡張を利用すると,いくつかのページを生成する手間が省けます.Markdown-include拡張では,{!ファイル名.md!}とすることで,指定したファイルの中身で当該行を置き換える事ができます. Markdown-include拡張でincludeされるファイルは,標準で設定ファイルと同じディレクトリから探されます.ディレクトリを変えたい場合は,md_base_dir:で設定ファイルからの相対パスを指定することができます. リポジトリのREADME.mdやLICENSEをページに含める場合に,この拡張記法を用いると,同じ内容を2カ所に記述する必要がなくなります. 下記のように,LICENSEとREADME.mdを追加し,docにページの基となるファイルを用意しました. . ├── src │ └── main.f90 ├── doc │ ├── index.md │ └── license.md ├── api-doc-ford-settings.md ├── LICENSE └── README.md README.md # Sieve of Eratosthenes ## Goals and Motivations ## Scope ## Install ## Usage ## Contributions ## Links LICENSE Copyright (c) 2021 implicit_none Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ./doc/index.md --- title: Read Me --- {!README.md!} ./doc/license.md --- title: license --- {!LICENSE!} 設定の部分に,page_dir: ./docを追記してFORDでドキュメントを生成してみると,ページ上部のメニューにRead Meが追加されていることが確認できます. Read Meのリンクをクリックすると,ページのトップ(index.mdから生成されたapi-doc/page/index.html)に移動します.README.mdの内容が挿入されていることが確認できます. licenseのリンクをクリックした移動先ページでも同様に,LICENSEの内容が挿入されています. VSCodeのTask コマンドをいちいち入力するのも億劫なので,VSCodeのtasks.jsonにタスクとして登録します.FORDの実行ファイルと設定ファイルの名前があればよいので,設定自体は非常に簡単です."command"の部分は著者の環境です. { "label": "generate document", "type": "shell", "options": { "cwd": "${workspaceRoot}" }, "command": "C:\\ProgramData\\Anaconda3\\Scripts\\ford.exe", "args": [ "api-doc-ford-settings.md" ], "presentation": { "echo": true, "reveal": "always", "focus": true, "panel": "shared", "showReuseMessage": true, "clear": false }, "problemMatcher": [], } このようにタスクとして登録するのであれば,FORDの設定ファイルは名前を固定するようにルールを定めた方がよいでしょう. おわりに FORDの使い方を,一通り簡単に紹介しました.これだけでもFORDを使ってドキュメントを生成できますが,FORDは他にも多くの機能を持っています.色々と試して,FORDのベストプラクティスを見つけたいと思います. FORDの注意点まとめ FORDの生成するドキュメントは,プログラミングインタフェース情報である アプリケーションのドキュメントは,FORDではページとよばれる 標準の出力ディレクトリは./docであり,生成のタイミングで中身を全て消す アプリケーションのドキュメントを./docに作成している場合は,設定ファイルで出力ディレクトリを指定する FORDの設定ファイルは,設定と生成されるドキュメントのトップページを兼ねる 設定を記述する部分で,途中に空行などの設定以外の情報が入っていると,その時点で設定の読み込みを止めるので,絶対に空行など設定以外の情報を入れない ソースファイルに日本語が含まれる場合は,OS標準の日本語エンコーディングとファイルの日本語エンコーディングの違いに注意し,必要があればPythonの環境変数を設定する FORDの設定ファイル名は,出力ディレクトリ名-ford-settings.mdなど名前を固定すると楽 conda上では,python-graphvizと表示されます. ↩ 公式ページを確認してください ↩ 縦棒がMarkdownだと表の区切りと重なるので,&#124;を使って記述しています. ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Djangoでよく使うコマンド操作一覧

Djangoでよく使うコマンド操作一覧 概要 WEBアプリケーションを作るときにDjangoを使うのですが、よく使うコマンドをよく忘れてしまうのでまとめてみました!! プロジェクト作成 django-admin startproject プロジェクト名 アプリケーションの作成 python3 manage.py startapp アプリ名 サーバーの起動 python3 manage.py runserver マイグレーションファイルを作成 python3 manage.py makemigrations モデルのあるアプリ名 マイグレーションファイルをデータベースに適用 python3 manage.py migrate
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

wsl環境構築について

初めに 初めて記事を投稿する。 Qiita記事作成に当たり、このサイトとこのサイトを参考にした。 wslの環境構築について、別の大学にある同じ研究室の後輩に教えるために作成した。 ちょくちょく内容を追加していくと思う。 そのため、本筋からずれることが多々ある。 ワタシハリナックスチョットデキナイので、嘘をつくことも多々ある。 指摘してくださると助かる。 後輩へ。分からないことがあればググれ。 君の分からない問題は、世界の誰かがすでに突破している問題だ。ググれば出る。 それと、ここで質問するとき本名は言わないでくれ。 目次 wslについて wslのインストール pythonのhello world wslについて wsl(Windows Subsystem for Linux)は、文字通り、windowsマシン上で、linuxを動かすためのシステム。 windowsマシンから見て、別のマシン(仮想マシン)扱いになっている。 ROSなども普通に動く。 かなり便利。 不便な点 wsl2(2021/04/19現在wsl最新)では、GUI関連がサポートされていない。そのため、自分でxserverなどを介して、GUIを動かせるように設定しなければならない。 ipアドレスの扱いに癖があり、TCP/IPなどで、windowsとwsl_linuxで通信させたいとき、wsl_linux側からでは、"localhost"でwindows側にアクセスできない。 色々詰んだ時、ファイアウォール関連が原因だったことが結構多い。ファイアウォールの注意喚起が起きたときは、脳死でokを連打しないようによく読む癖をつけたほうが良い。 linuxについて linux(linux系OS)は、windowsOSやmacOSと同じOSの一種である。 様々な種類(ディストリビューション)があり、ubuntuなどが代表的である。 linuxは、その名から分かるように、Linus氏が作成したunix系OSである。(macOSもunix系。) オープンソースなものが多く、開発ガチ勢が良く使用している(気がする)。 windows派 vs mac派 の宗教戦争をしている間に、「僕はlinux派~」と割り込むと、双方から嫌われる可能性があるので注意しよう。 ROS(Robot Operating System)は、基本的にlinux系OS上でしか動作しないので、ロボットの開発・制御をしたいなら、linux一択みたいな風潮はある(気がする)。 macユーザーの後輩へ macOSは、先に述べた通り、linux同様、unix系OSである。したがって、これから言うことは嘘であるが、macを使用しているのなら、とりあえず、以下に示すwslを用いたlinux環境の構築は、もうできているものとして考えてもよい。(pythonのhelloworldらへんから試してみてくれ。) しかし、細かいところで仕様が違うところがあるので、問題が発生したら、その都度調べてくれ。僕はmacを使ってないからわからん。 ただ、macユーザーはかなりの数がいるので、もし問題にぶつかっても、同じ問題を解決している人がネット上にきっと存在する。安心していい。 もし、macだけどどうしてもlinuxで開発したいというのなら、"仮想マシン"や"デュアルブート"で検索してみたらよい。 wslのインストール 基本的に、windows公式のここに従えばよい。 上記サイトを読むことを強く推奨するが、めんどくさい場合は、以下のコマンドを、powershell(管理者権限)で実行すればよい。 powershell(管理者権限)で実行するとは、スタートボタン左クリックで出てくる"Windows PowerShell(管理者)"をクリックすると出てくる青い画面上で、コマンドを実行する、という意味である。 wslを有効にする dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart 仮想マシンの機能を有効にする dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart 上記コマンド実行後windowsマシン(パソコン本体)を再起動 その後、Microsoft StoreでLinux ディストリビューション(ubuntuのことと理解してよい。)をインストールする。   自分は、"ubuntu"を使用する。     Microsoft Storeの、"Ubuntu 20.04 LTS"(2021/04/19現在最新版)にした。 最後に、以下のコマンドを、同様にpowershell(管理者権限)で実行 wsl2をwslの規定のバージョンとして設定する wsl --set-default-version 2 wslのインストールはここで終わり。 以下確認 確認用コマンド wsl -l -v で 確認用出力 NAME STATE VERSION * Ubuntu Running 2 のようになっていればよい。(stateは、別にRunningじゃなくてもよい。) これで、windows上のターミナル(コマンドプロンプトでも、power shellでもどっちでもいい)で、"wsl"と入力すれば、ubuntuが動く。 最初にwslを起動するときは、起動に少し時間がかかり、また、ubuntuアカウントを作成する必要がある(とても簡単)。このサイトを参考に行うとよい。 以降の環境構築において、windows上の作業なのか、ubuntu上の作業なのかを、意識して作業するべき。 便利ツール 以下のツールのインストールを強く勧める。 windows terminal Microsoft Storeで、"windows terminal"と検索すれば出る。 超便利なターミナル。 Visual Studio Code (vsc) エディタ。エディタは、各宗教にお任せするが、wsl+vscは良い。 公式サイトでインストールできる。 vscをubuntu上で使うときは、リモートでwslにつないでいる扱いになっており、windowsアプデの後などに、参照パスが切れて開けなくなることがある。その時は、一回、windows側でvscを開き、そこから、wsl上のファイルを開けば、参照パスが通り、以降、wsl上でも開くようになる。 pythonのhello world "hello world"とは、プログラミング界隈におけるの"チュートリアル"の意味。 python(python3)をwsl上にインストールして、実際にコードを書いてみるところまでする。 この作業は、すべて、wsl上(ubuntu上)で行う。windows上ではないことを意識して行うように。 他の作業は、wslとwindowsの両方で作業が必要になることが多い。 作業場所は、自分で"workspace"などの名前のディレクトリを作成して、その中で行うのがマナーがいい。 ディレクトリの作成方法などの、linuxコマンドは、自分で調べて、使えるようになっておくべき。 以下のコマンドをwsl上で実行する。(コマンドは1行ずつね。) コマンド間の日本語は、読まんでもいい。 おまじない sudo apt update sudo apt upgrade "sudo"で始まるコマンドは、"管理者権限で実行"みたいな意味。 "ほんとに実行しますか?"と聞かれるので、"y"(yesの意味)と打てばよい。 プログラムの世界では、祈ることが非常に重要視される。このおまじないも、祈りの1つ。 この2つのコマンドは、定期的に行っていいと思う。 python本体のインストール sudo apt install -y python3 sudo apt install -y python3-pip sudo apt install -y python3-dev "-y"は、毎回、"y"って手打ちするのがだるいからつけただけ。 これから、色々なpythonパッケージをインストールすることになると思う。 その時、"pip"でインストールしたら、python内部の"site-package"内部に、 それ以外の方法でインストールしたら、"dist-package"内部に格納されるらしい。 NumPyのインストール sudo apt install -y python3-numpy NumPyは、pythonを超すごい電卓にしてくれるライブラリ。 pythonが人気な理由の1つが、NumPyを使用できるから。 なくても動くが、np(NumPyのこと)がないpythonって、正直、意味わからんから、最初に入れておく。 pylintのインストール pip install pylint pylintは、pythonの文法をチェックしてくれるやつ。 なくても動くけど、なかったら、vscに怒られるので、最初から入れておく。 以上で、pythonの環境構築終わり。 以下、"hello world"を出力するプログラムを作成し、動作確認。 適当な場所で、以下のコマンドを実行。 helloworld.pyファイルの作成と編集 code helloworld.py "code"コマンドは、vscで編集するときに使用する 以下vsc内部でhelloworld.pyを以下のように編集 helloworld.py print("hello world") 保存後、wsl上で、以下のコマンドを実行 helloworld.pyの実行 python3 helloworld.py 以下のような出力になれば、動作確認成功。 hello world また、pythonには対話モードというものも存在している。 調べることをおすすめする。 以上で、pythonのことを完全に理解したと思う。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

KerasによるMNISTの手書き文字の分類

KerasによるMNISTの手書き文字の分類 概要 今回はkerasを用いてmnistという手書き文字がたくさん入ったimageデータセットから1~9の文字を分類します 必要なライブラリのimport import os,re import matplotlib.pyplot as plt import numpy as np from sklearn.model_selection import train_test_split import keras from keras.datasets import mnist mnistダウンロード データを学習用とテスト用に分割 次に学習用のデータを学習用と検証用に8:2の割合で分割 from keras.datasets import mnist from sklearn.model_selection import train_test_split (train_data, train_labels), (test_data, test_labels) = mnist.load_data() x_train, x_valid, y_train, y_valid = train_test_split(train_data, train_labels, test_size=0.2) 画像データと正解ラベルのリサイズ ①x_train,x_validは現在(4800,28,28),(1200,28,28)になっているのでkerasのモデルの学習に使える形にするために(4800,28,28,1),(1200,28,28,1)の形に変換 ②画像データのデータ型をfloat型に変換 ③画像の画素値は0~255までで数値が大きいので0~1の間に変換 ④正解ラベルをone-hot-encodhingにする from keras.utils import to_categorical #① x_train = x_train.reshape(x_train.shape[0], 28, 28, 1) x_valid = x_valid.reshape(x_valid.shape[0], 28, 28, 1) #② x_train = x_train.astype('float32') x_valid = x_valid.astype('float32') #③ x_train /= 255 x_valid /= 255 #④ y_train = keras.utils.to_categorical(y_train, 10) y_valid = keras.utils.to_categorical(y_valid, 10) モデルの作成 from keras.models import Sequential from keras.layers import Dense, Dropout, Flatten from keras.layers import Conv2D, MaxPooling2D model = Sequential() model.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=(28, 28, 1))) model.add(Conv2D(64, (3, 3), activation='relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) model.add(Flatten()) model.add(Dense(128, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(10, activation='softmax')) model.summary() Model: "sequential_1" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d_2 (Conv2D) (None, 26, 26, 32) 320 _________________________________________________________________ conv2d_3 (Conv2D) (None, 24, 24, 64) 18496 _________________________________________________________________ max_pooling2d_1 (MaxPooling2 (None, 12, 12, 64) 0 _________________________________________________________________ dropout_2 (Dropout) (None, 12, 12, 64) 0 _________________________________________________________________ flatten_1 (Flatten) (None, 9216) 0 _________________________________________________________________ dense_2 (Dense) (None, 128) 1179776 _________________________________________________________________ dropout_3 (Dropout) (None, 128) 0 _________________________________________________________________ dense_3 (Dense) (None, 10) 1290 ================================================================= Total params: 1,199,882 Trainable params: 1,199,882 Non-trainable params: 0 _________________________________________________________________ モデルのコンパイル from keras.optimizers import RMSprop model.compile(loss='categorical_crossentropy', optimizer=RMSprop(), metrics=['accuracy']) 画像の水増しと学習 datagen = ImageDataGenerator( featurewise_center=False, # データセット全体で,入力の平均を0に調整 samplewise_center=False, # 各サンプルの平均を0に調整 featurewise_std_normalization=False, # 入力をデータセットの標準偏差で正規化 samplewise_std_normalization=False, # 各入力をその標準偏差で正規化 zca_whitening=False, # ZCA白色化のイプシロン rotation_range=50, # 回転角度(-50~50度) width_shift_range=0.3, # 左右のスライド幅 height_shift_range=0.2, # 上下のスライド幅 zoom_range=[1.0,1.5], # 拡大・縮小率 horizontal_flip=False, # 水平反転しない vertical_flip=False) hist = model.fit_generator(datagen.flow(x_train, y_train, batch_size=32), steps_per_epoch=len(x_train)/32, epochs=10, validation_data=(x_valid, y_valid)).history 精度の表示 # 精度のplot plt.plot(hist['accuracy'], marker='.', label='acc') plt.plot(hist['val_accuracy'], marker='.', label='val_acc') plt.title('model accuracy') plt.grid() plt.xlabel('epoch') plt.ylabel('accuracy') plt.legend(loc='best') plt.show() # 損失のplot plt.plot(hist['loss'], marker='.', label='loss') plt.plot(hist['val_loss'], marker='.', label='val_loss') plt.title('model loss') plt.grid() plt.xlabel('epoch') plt.ylabel('loss') plt.legend(loc='best') plt.show() テストデータで精度の評価 test_data = test_data.reshape(test_data.shape[0], 28, 28, 1) test_data = test_data.astype('float32') test_data /= 255 test_labels = keras.utils.to_categorical(test_labels, 10) score = model.evaluate(test_data, test_labels, verbose=0) print('Test loss:', score[0]) print('Test accuracy:', score[1])
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python】すべてのシートの印刷設定を行う。

pythonを使用してExcelファイルの操作を勉強しています。 本日の気づき(復習)は、印刷設定に関してです。 pythonでExcelを操作するため、openpyxlというパッケージを使用しています。 何気に、印刷設定を行うのって苦痛ではないですか? ヘッダーだったり、フッターだったり・・・。 印刷を行う属性一覧 調べてみると、印刷の設定を行う属性が沢山ありました。 主要と思われる所を以下にまとめています。 print_area:印刷範囲 print_title_cols:常に印刷する列 print_title_rows:常に印刷する行 oddHeader.center.text:ヘッダー中央部 oddFooter.center.text:フッター中央部 page_setup.orientation:印刷の向き(横:ORIENTATION_PORTRAIT)(縦:ORIENTATION_LANDSCAPE) page_setup.fitToWidth:ページ数に合わせて印刷する設定(横)1ページなら、「1」自動なら、「0」 page_setup.fitToHeight:ページ数に合わせて印刷する設定(縦)1ページなら、「1」自動なら、「0」 sheet_properties.pageSetUpPr.fitToPage:fitToWidth属性、fitToHeight属性を有効にする page_setup.paperSize:用紙サイズ たぶん、これぐらいだと思います。 最終的なコード from openpyxl import load_workbook print_area = 'A1:D50' print_title_rows = '1:5' header_text = '&F' footer_text = '&P / &Nページ' wb = load_workbook('サンプル.xlsx') for ws in wb.worksheets: # プリントエリアを設定 ws.print_area = print_area # 常に印刷する行を指定 ws.print_title_rows = print_title_rows # ヘッダーを指定 ws.oddHeader.center.text = header_text # フッターを設定 ws.oddFooter.center.text = footer_text wps = ws.page_setup # 印刷の向きを設定 wps.orientation = ws.ORIENTATION_LANDSCAPE # 横を1ページ wps.fitToWidth = 1 # 縦を自動 wps.fitToHeight = 0 # fitTo属性を有効にする ws.sheet_properties.pageSetUpPr.fitToPage = True # 用紙サイズを設定 wps.paperSize = ws.PAPERSIZE_A4 wb.save('サンプル_印刷設定.xlsx') 気を付けたポイントは worksheets属性で全シートを取得して繰り返し処理をする。 ヘッダー、フッターには ブック名を表す'&F'、ページ番号を表す'&P'、総ページ数を表す'&N' を、それぞれ設定した。 page_setup.fitToWidth属性、page_setup.fitToHeight属性を使用した場合は sheet_properties.pageSetUpPr.fitToPage属性を「True」にしないと有効にならない。 と言うところでしょうか。 比較的簡単に、前ページ変更できるのでお勧めです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

スマホを使ってRaspberryPiのWifi設定を外部から変更する(ESP8266使用)

プロトタイプあるある ぼく『ラズパイとセンサ繋いでIoT機器のプロトタイプ出来た!ケースもぴったり!』 ??『じゃあ今から、うちの会社の会議室でデモしてくれない?』 ぼく『…デモ前にケース開けてモニタとマウスとキーボード繋いで、現場のWifiに再設定が必要です。』 ぼく&??『とほほ・・・』 なんとか設置を簡便に出来ないものか? (誰でも/特別な機器やケーブル、アプリ等を用いずに!) 私的解決法:ESP8266+スマホで設定を行い、その情報をラズパイに送る ESP8266(ESP-WROOM-02モジュール)を搭載した基板を製作して、ラズパイとシリアル通信が出来るようにしました。 回路 使用したピンは3.3v、GND、Tx、Rxの4本です。5VやI2Cを使用する場合も多そうなので、 ピン配置そのままで10ピン分岐してあります。 スケッチ main.cpp #include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino //needed for library #include <DNSServer.h> #include <ESP8266WebServer.h> #include <WiFiManager.h> //https://github.com/tzapu/WiFiManager String ssid; String pass; int incomingByte = 0; // 受信データ用 void setup() { // put your setup code here, to run once: IPAddress ip; Serial.begin(115200); //Serial.println("Start"); delay(3000); //WiFiManager //Local intialization. Once its business is done, there is no need to keep it around WiFiManager wifiManager; wifiManager.setDebugOutput(false); //Serial.println("RESET"); wifiManager.resetSettings(); //set custom ip for portal //wifiManager.setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0)); //fetches ssid and pass from eeprom and tries to connect //if it does not connect it starts an access point with the specified name //here "AutoConnectAP" //and goes into a blocking loop awaiting configuration wifiManager.autoConnect("WifiFix_SETUP"); //or use this for auto generated name ESP + ChipID //wifiManager.autoConnect(); //if you get here you have connected to the WiFi // Serial.println("connected!!"); ssid = wifiManager.getSSID(); pass = wifiManager.getPassword(); } void loop() { // put your main code here, to run repeatedly: if (Serial.available() > 0) { incomingByte = Serial.read(); Serial.print(ssid); Serial.print(","); Serial.println(pass); } } WiFiManager ESP8266/ESP32向けのArduinoライブラリで、WiFiManagerがあります。(Qiitaで探してみよう)作成したスケッチを書き込むとアクセスポイントとして動作するのでスマートフォン等でアクセスポイントを探すと [WifiFix_SETUP]が現れます。 接続すると自動的に192.168.4.1にアクセスし、この様な画面が出ます。 "Configure Wifi"をタップするとアクセスポイントのスキャンを行い、SSID一覧から選んでパスワード入力が可能です。 正しく設定されるとESP8266は指定したアクセスポイントに接続します。 接続に成功すると電源投入中はSSIDとパスワードを保持するので、この情報をRaspberryPiに反映させる事が出来れば目的達成です。(電源投入時にSSID/PASSは初期化します) RaspberryPiとの接続 pythonスクリプトを作成しました。 wifi_fixer.py import os import time import serial def ESP_check(): ser = serial.Serial('/dev/serial0', 115200, timeout=3) time.sleep(1) ser.write(11) dummy = ser.readline().decode() rim = dummy.split(',') if len(rim) > 1: # print("SSID:", rim[0], " PASS:", rim[1]) return rim else: # print("No data") rim = [] return rim def CreateWifiConfig(SSID, password): config = ( '\nnetwork={{\n' + '\tssid="{}"\n' + '\tpsk="{}"\n' + '}}').format(SSID, password) print(config) with open("wpa_supplicant.conf.edit", "a+") as wifi: wifi.write(config) wifi.close() print("Wifi config added") def CheckWPAfile(SSID, PASS): check = 0 ssid_txt = "" pass_txt = "" with open("/home/pi/wpa_supplicant.conf.edit") as wifi: while True: line = wifi.readline() if not line: break if 'ssid' in line: ul = line.split('"') ssid_txt = ul[1] if 'psk' in line: ul = line.split('"') pass_txt = ul[1] if ssid_txt == SSID and pass_txt == PASS: check = 1 return check response = os.system("sudo ping -c 1 google.com") if response != 0: print 'system is not connected!' response = os.system("sudo ifconfig wlan0 down") response = os.system("sudo cp /etc/wpa_supplicant/wpa_supplicant.conf /home/pi/wpa_supplicant.conf.edit") esp = ESP_check() if len(esp) != 0: print(esp[0].strip(), esp[1].strip()) if CheckWPAfile(esp[0].strip(), esp[1].strip()): print("find") else: print("diff!") CreateWifiConfig(esp[0].strip(), esp[1].strip()) response = os.system("sudo cp /home/pi/wpa_supplicant.conf.edit /etc/wpa_supplicant/wpa_supplicant.conf") response = os.system("sudo reboot") response = os.system("sudo ifconfig wlan0 up") while True: res2 = os.system("sudo ping -c 1 google.com") time.sleep(1) if res2 == 0: print 'Connected' break 動作 ラズパイのWifiが外部に繋がっているかpingで確認 ESP8266にシリアルで問い合わせ、もしSSID/PASSが登録されていたら/etc/wpa_supplicant/wpa_supplicant.confに追記してリブート wifiが正常に設定されている、またはESP8266が何も返さない(設定されていない)ならスクリプトを終了 上記のようなスクリプトをcronに設定し一定周期で走らせます。ラズパイは知らない場所で起動してもWifiが繋がらず手も足も出ませんが、スマホから設定されればスクリプトが動作した際にWifiの設定が更新され、再起動が行われます。 本来の目的アプリを自動起動にしておけば、次回からは再設定されたWifiに自動接続されて無事動作するという目論見です。 問題点&検討中の課題 IEEE 802.11 b/g/n (2.4GHz帯)しか対応していない 電波強度が強いアクセスポイントが複数ある場所では目的のアクセスポイントが見つけにくい(直接入力は可能) ラズパイのシリアルピンを占有してしまう セキュリティ上の懸念(ESP内部にデータを保持している) 現在改良中です! あと、この基板を某所に置いてもらえないか画策中
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

OpenCVを用いた画像処理の基礎【まとめ】Python

opencvをimportして使えるようにする import cv2 import numpy as np from matplotlib import pyplot as plt ・Opencvによる画像の読み込み opencvによる画像の読み込み img = cv2.imread('apple-picuture.jpg') ・OpenCVによって扱われる画像はnumpyアレーで(高さ、横幅、カラー)の順に格納されている img = cv2.imread('apple-picuture.jpg') img.shape >>>(320,320,3) ・OpenCVによって扱われる画像はBGRの順番で画素値が格納されている img = cv2.imread('apple-picuture.jpg') img[0][0] >>>(121,23,56) (Blue,Green,Red)の順番 ・OpenCVによる画像の表示 画像が表示されたらその画像をクリックしてどこかのキーボードを入力するとウィンドウが閉じます # 画像を表示する img = cv2.imread('apple-picuture.jpg') cv2.imshow('image',img) # キーボード入力を待つ cv2.waitKey(0) # すべてウィンドウを閉じる cv2.destroyAllWindows() ・OpenCVによる画像の保存 今回はtest.jpgという名前で同じ階層に画像を保存 うまくいくとTrueと出力される img = cv2.imread('apple-picuture.jpg') # osをimport import os #画像の保存 cv2.imwrite('test.jpg',img) >>>True ・OpenCVによるリサイズ img = cv2.imread('apple-picuture.jpg') img_resize = cv2.resize(img,(160,200)) img_resize.shape >>>(200, 160, 3) (高さ,横幅,チャンネル数) ・OpenCVによるリサイズの引数について cv2.resize()の引数は以下のようになっています cv2.resize(src, dsize, fx, fy, interpolation) fx,fyは画像を何倍にするのかを表します 例えば縦を1.5倍、横幅を2倍にするならば①のようになります interpolationはデフォルトでINTER_LINEARになっていますが他にも ・INTER_NEAREST – 最近傍補間 ・INTER_AREA – ピクセル領域の関係を利用したリサンプリング。画像を大幅に縮小する場合、モアレを避けることができる手法 などがあります② リサイズの引数について img = cv2.imread('apple-picuture.jpg') #① img_resize = cv2.resize(img,(img.shape[0],img.shape[1]),1.5,2) >>>(480,640,3) 元は(320,320,3) #② サイズは元のまま img_area = cv2.resize(img,(320,320),interpolation=cv2.INTER_AREA) ・グレースケールへの変換 通常画像は3チャンネルのRGBで表されますが、グレースケールでは1チャンネルで表されます。 メリットとしては演算が3分の1になることや、2値化がやりやすいということです ちなみにグレースケールは以下のような計算式になっています Gray = 0.2989R + 0.5870G + 0.1140B グレースケールへの変換 #1つ目 img = cv2.imread('apple-picuture.jpg') img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #補足(HSVへの変換) img_hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV) #2つ目(画像を読み込むときに2つ目の引数に0を入れるだけ) img = cv2.imread('apple-picuture.jpg',0) ・ヒストグラム均一化 ヒストグラム均一化によって画像をより明暗をはっきりとした画像に変換できます 今回はグレースケールで表された画像に対してヒストグラム均一化を行っています cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]]) channnels : グレースケールの場合は0 histSize : ビンの数を表していて、全画素値を対象とするのであれば [256] を指定します. ranges : ヒストグラムを計測したい画素値の範囲を表す RANGE です.通常は [0,256] を指定します ヒストグラム均一化 img = cv2.imread('apple-picuture.jpg',0) hist = cv2.calcHist([img],[0],None,[256],[0,256]) ・γ(ガンマ)変換 γ変換とは画像の明るさの変換方法のこと Y = 255 x ( Y ÷ 255)( 1 / γ) これがγ変換の式になっており γが1の時は Y=x となり直線(下記の画像の1) γが大きくなれば明るい画像、小さくなれば暗い画像になります ヒストグラム均一化 img = cv2.imread('apple-picuture.jpg',0) def create_gamma_img(gamma, img): gamma_cvt = np.zeros((256,1), dtype=np.uint8) for i in range(256): gamma_cvt[i][0] = 255*(float(i)/255)**(1.0/gamma) return cv2.LUT(img, gamma_cvt) ・2値化 2値化とはある閾値を越えると255,小さいと0という風にして画像をモノクロにする手法です。 1つ目は通常使われる2値化の方法で、retには閾値が格納されています 2つ目は相対的に明るいか暗いかを判断して2値化してくれる方法です 2値化 img = cv2.imread('apple-picuture.jpg',0) #1つ目 ret , img_0 = cv2.threshold(img,0,255,cv2.THRESH_OTSU) #2つ目 img_ada = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,3,1)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

継承

継承 継承とは、あるクラスを元に新たなクラスを作ることをいいます。 「class 新しいクラス名(元となるクラス名)」と記述することで他のクラスを継承して、新しいクラスを定義することができます。この時、新しいクラスを子クラス、元となるクラスを親クラスと呼ばれます。 継承により、親クラスのインスタンスメソッドをそのまま子クラスでも使うことができます。 しかし、子クラスで定義したメソッドは親クラスでは使えないので注意が必要です。 script.py from fruit import Fruit fruit1 = Fruit('りんご', 200) print(fruit1.info()) fruit_price.py class FruitPrice: def __init__(self, name, price): self.name = name self.price = price def info(self): return self.name + 'は' + str(self.price) + '円です' fruit.py from fruit_price import FruitPrice class Fruit(FruitPrice): pass 出力結果 りんごは200円です 上記のように、継承させることで親クラスのインスタンスメソッドであるinfoメソッドを子クラスで使うことができました。 まず、script.pyでFruitクラスを呼び出すことで、fruit.py内のFruitクラスを呼び出します。この時、Fruitクラス(子クラス)はfruit_price内のFruitPriceクラス(親クラス)を継承させているため、 親クラス内のinfoメソッドを使うことができるので、Fruitの引数である'りんご'と200を用いて出力結果を得ることができました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

第2回 今更だけどしっかり基礎から強化学習を勉強する ディープラーニング編(Q学習、方策勾配法、A3C/A2C)

今回は基本的にモデルフリーの環境が前提となります。 モデルベースについてはいつかやるかも? 第1回 基礎編(動的計画法、Q学習、SARSA、Actor Critic) 第3回:そのうち ディープラーニングに使うライブラリですが、Tensowflow2.0(+Keras)を使います。 Tensowflow2.0から公式でKerasが取り入れられたようでそちらを使っていきます。 コード全体 本記事で作成したコードは以下です。 GoogleColaboratory 環境 OpenAI gym で提供されている CartPole-v0 を使用します。 台座を右か左に動かして棒を立たせ続けるゲームです。 棒がある一定以上傾いたり、画面外に行くと終了します。 報酬は常に1手に入り、早く終了する=累計報酬が少なくなるという学習です。 200stepまで実行されるので最大報酬は200となります。 状態は[台座の位置,台座の速度,棒の角度,棒の速度]を返します。 アクションは台座を左に移動させる、右に移動させるの2つです。 GoogleColaboratoryによる Gym の描画 昔に書いた記事を参考にしています。 コメントにもある通り以下の部分が不要になったようです。(コメントありがとうございます) import os os.environ["DISPLAY"] = ":" + str(display.display) + "." + str(display.screen) 一応コードを書いておきます。(同じものがコード全体にもあります) おまじない部分です。 #installing dependencies !apt-get -qq -y install libcusparse8.0 libnvrtc8.0 libnvtoolsext1 > /dev/null !ln -snf /usr/lib/x86_64-linux-gnu/libnvrtc-builtins.so.8.0 /usr/lib/x86_64-linux-gnu/libnvrtc-builtins.so !apt-get -qq -y install xvfb freeglut3-dev ffmpeg> /dev/null !pip -q install gym !pip -q install pyglet !pip -q install pyopengl !pip -q install pyvirtualdisplay # Start virtual display from pyvirtualdisplay import Display display = Display(visible=0, size=(1024, 768)) display.start() 今回はkera-rlは使わないので、表示部分を関数化しました。 import gym from tensorflow import keras import matplotlib.pyplot as plt import matplotlib.animation import time from IPython.display import HTML def GymView(rgb_array_frames, interval=20, start_frame=0, end_frame=0): assert start_frame<len(frames) if end_frame == 0: end_frame = len(frames) elif end_frame > len(frames): end_frame = len(frames) start_frame = start_frame t0 = time.time() # 表示サイズをここで指定しています。 plt.figure(figsize=(2.5,2.5), dpi = 200) patch = plt.imshow(frames[0]) plt.axis('off') def plot(frame): if frame != 0 and frame % 200 == 0: print("{}f {:.2f}m".format(frame, (time.time()-t0)/60)) patch.set_data(frames[frame + start_frame]) ani = matplotlib.animation.FuncAnimation(plt.gcf(), plot, frames=end_frame - start_frame, interval=interval) return ani.to_jshtml() 以下のような使い方を想定 env = gym.make('CartPole-v0') state = env.reset() # ゲームの初期化 frame = env.render('rgb_array') # ゲームの描画 done = False total_reward = 0 step = 0 frames = [frame] while not done: action = env.action_space.sample() state, reward, done, _ = env.step(action) total_reward += reward step += 1 frame = env.render('rgb_array') frames.append(frame) print("step: {}, reward: {}".format(step, total_reward)) HTML(GymView(frames)) # 必ずセルの最後に記載 価値関数の学習(Q学習) Q学習の行動価値関数をニューラルネットワークで拡張してみます。 更新式 Q学習の更新式は以下でした。 ($\alpha$ は学習率、$\gamma$は割引率) $$ Q(s_t,a_t) \leftarrow Q(s_t,a_t) + \alpha ( r_{t+1} + \gamma \max_a (Q(s_{t+1}, a)) - Q(s_t,a_t) ) $$ しかし、差分の計算はディープラーニング内で計算されるので以下の式だけが必要になります。 $$ r_{t+1} + \gamma \max_a (Q(s_{t+1}, a))$$ また、エピソード終了時は次の状態がないため以下となり、報酬だけになります。 $$ r_{t+1}$$ 価値関数モデルの定義 モデルは状態を入力とし、各アクションでの価値を出力します。 from tensorflow.python import keras from tensorflow.keras.optimizers import Adam # 環境の状態の形式(shape) obs_shape = env.observation_space.shape # 環境の取りうるアクション数 nb_actions = env.action_space.n lr = 0.001 # 学習率 c = input_ = keras.layers.Input(shape=obs_shape) c = keras.layers.Dense(10, activation="relu")(c) c = keras.layers.Dense(10, activation="relu")(c) c = keras.layers.Dense(nb_actions, activation="linear")(c) model = keras.Model(input_, c) model.compile(optimizer=Adam(lr=lr), loss='mse', metrics=["mae"]) model.summary() 拡張性を優先してSequentialモデルではなくFunctionalAPIでモデルを作っています。 Dense層を2つ結合したシンプルなモデルです。 optimizerはAdamを使い、損失関数には平均二乗誤差(mse)を使っています。 メトリクスは確認用なので学習には関係ありません。 行動の決定 Epsilon-Greedy法を使います。 Tensorflow2.0での値の取り出し方の説明がメインです。 Tensorflowを使う場合はshape(次元数)を意識することが重要な気がします。 def EGreedyPolicy(model, state, nb_actions, epsilon): if np.random.random() < epsilon: # epsilonより低いならランダムに移動 return np.random.randint(nb_actions) else: # Q値が最大のアクションを実行 q = model(state.reshape(1,-1))[0].numpy() return np.argmax(q) モデルからの値の取り出しは model(入力) で行います。 入力ですが、複数の結果も1回で取り出すことができるので次元数を1増やして与える必要があります。 今回ですと state は (4,) 次元([位置,加速度,角度,速度])なので reshape して (1,4) 次元([[位置,加速度,角度,速度]])に増やしています。 (1,4) で入力すると出力は (1, 出力結果) で返ってきます。 今回ですとアクション数が出力になるので(1,2)です。 ですので、[0] で0番目の結果を取得し、q には(2,)次元([左アクションの価値,右アクションの価値])が入ります。 また、model()で返ってくる値はTensor型なので numpy() で numpy 型に変換しています。 最後に、qから価値の高いほうのアクションをargmax関数で取得しています。 経験の収集(Experience Replay)と学習ループのコード 強化学習によるディープラーニングは基本オンライン学習になります。(反対はバッチ学習) (いつかオンライン強化学習とオフライン強化学習まで触れられればいいなー) オンライン学習は1データ毎にパラメータを更新するため学習が安定しにくいといった欠点があります。 それを補う手法としてミニバッチ学習という複数のデータでパラメータを更新する手法があります。 モデルフリーの強化学習ではデータ収集の仕方上どうしてもデータが時系列となり、データに偏りが生じてしまいます。 これでは学習が安定しないため、Experience Replay と呼ばれる手法を用いてバラバラの複数のデータからミニバッチ学習を実施しています。 データ(経験)を収集するコードは以下です。 import numpy as np from collections import deque epsilon = 0.1 batch_size = 32 buffer_size = 1024 # 収集する経験は上限を決め、古いものから削除する experiences = deque(maxlen=buffer_size) # 学習ループ env = gym.make("CartPole-v0") for episode in range(300): state = np.asarray(env.reset()) done = False total_reward = 0 # 1episode while not done: # アクションを決定 action = EGreedyPolicy(model, state, nb_actions, epsilon) # 1step進める n_state, reward, done, _ = env.step(action) n_state = np.asarray(n_state) total_reward += reward # 経験を保存する experiences.append({ "state": state, "action": action, "reward": reward, "n_state": n_state, "done": done, }) state = n_state # 学習(中身は後述) train(model, experiences, batch_size, buffer_size) 学習 学習はまずある程度経験が貯まるまでまってから実行します。 コードはバッファサイズ分(1024)貯まるまで待っています。 貯まったらまず経験をランダムにバッチサイズ分取得します。 その後、更新式の通り計算して教師用のデータを作りモデルを学習させます。 import random def train(model, experiences, batch_size, buffer_size): # 経験が貯まるまで学習しない if len(experiences) < buffer_size: return gamma = 0.9 # 割引率 # ランダムに経験を取得してバッチを作成 batchs = random.sample(experiences, batch_size) # データ形式を変形 state_batch = np.asarray([e["state"] for e in batchs]) n_state_batch = np.asarray([e["n_state"] for e in batchs]) # 現在の状態のQ値と次の状態のQ値を求める # (batch_size, nb_actions) ← (batch_size, state) # (32, 2) ← (32, 4) q = model(state_batch).numpy() n_q = model(n_state_batch).numpy() # 各バッチでQ値を計算 for i, batch in enumerate(batchs): action = batch["action"] reward = batch["reward"] if batch["done"]: q[i][action] = reward else: q[i][action] = reward + gamma * np.max(n_q[i]) # モデルをミニバッチ学習する model.train_on_batch(state_batch, q) 評価と結果の出力 強化学習では機械学習で使われる一般的なメトリクスの他に、1エピソードで取得できた合計報酬が重要となります。 報酬を基準に評価していいのですが、学習用に使ってるデータは探索用の行動が含まれているので少し正確ではない点に注意が必要です。(下振れします) 評価用のコードは以下です。 # 探索をやめてQ値が最高の行動のみにする # 0 でもいいが、序盤に局所解に陥ってるとつまらないので少し乱数を混ぜて何回か見てみる epsilon = 0.0001 # 5回テストする for episode in range(5): tate = np.asarray(env.reset()) env.render() done = False total_reward = 0 # 1episode while not done: action = EGreedyPolicy(model, state, nb_actions, epsilon) n_state, reward, done, _ = env.step(action) state = np.asarray(n_state) env.render() step += 1 total_reward += reward print("{} step, reward: {}".format(step, total_reward)) 学習中の様子 メトリクスは1エピソードの平均値で表示しています。 学習は80エピソードあたりから始まっていますね。 テスト結果 200 step, reward: 200.0 200 step, reward: 200.0 200 step, reward: 200.0 195 step, reward: 195.0 199 step, reward: 199.0 戦略関数の学習(Policy Gradient) パラメータを持った戦略関数の更新 価値関数はそのまま実際の価値を教師データとして入力すればよかったですが、戦略関数はそうはいきません。 戦略関数から出力される行動確率は簡単には求められないからです。 ではどうするかというと期待値を計算し、それが最大化されるように戦略関数を学習します。 期待値 $J(\theta)$ は「(戦略に従い)状態に遷移する確率」×「行動確率」×「行動価値」から計算されます。 $$ J(\theta) \propto \sum_{s \in S} d^{\pi_\theta}(s) \sum_{a \in A} \pi_{\theta}(a|s) Q^{\pi_\theta}(s,a) $$ $d^{\pi_\theta}(s)$ は戦略 $\pi_{\theta}$に従い状態$s$へ遷移する確率、$\pi_{\theta}(a|s)$ はそこで行動$a$をとる確率、$Q^{\pi_\theta}(s,a)$ は行動価値です。 また、$\propto$(propotional to)は比例関係を表す記号で期待値がエピソード長に比例することを表しています。 この式については導出が複雑らしく、詳細はググってください(え この期待値 $J(\theta)$ を最大化する方法を考えます。 直感的には高い報酬が見込まれる行動には高い確率を、その逆には低い確率を割り当てる感じです。 これを最大化する手法として方策勾配法(Policy Gradient)があります。 方策勾配法(Policy Gradient) 期待値 $J(\theta)$ の勾配は以下になるようです。 $$ \nabla J(θ) \propto \sum_{s \in S} d^{\pi_\theta}(s) \sum_{a \in A} \pi_{\theta}(a|s) \nabla log \pi_{\theta}(a|s) Q^{\pi_\theta}(s,a) $$ この計算も結構複雑らしいので割愛します。 ここで、$d^{\pi_\theta}(s)$と$\pi_{\theta}(a|s)$が確率、$\nabla log \pi_{\theta}(a|s) Q^{\pi_\theta}(s,a)$が値と見ることができます。 なのでこれを期待値E[値]という形式で書くと以下となります。 $$ \nabla J(θ) \propto E_{\pi_\theta} [ log \pi_{\theta}(a|s) Q^{\pi_\theta}(s,a) ] $$ 戦略モデルの定義 モデルは状態を入力とし、各アクションを選択する確率(戦略)を出力します。 from tensorflow.python import keras from tensorflow.keras.optimizers import Adam # 環境の状態の形式(shape) obs_shape = env.observation_space.shape # 環境の取りうるアクション数 nb_actions = env.action_space.n lr = 0.01 # 学習率 c = input_ = keras.layers.Input(shape=obs_shape) c = keras.layers.Dense(10, activation="relu")(c) c = keras.layers.Dense(10, activation="relu")(c) c = keras.layers.Dense(nb_actions, activation="softmax")(c) model = keras.Model(input_, c) model.compile(optimizer=Adam(lr=lr)) model.summary() 出力層をsoftmaxにすることで各アクションの確率を出力するようにしています。 また損失関数は自作するので指定していません。 行動の決定 モデルが各アクションの選択確率を出力するのでそのまま確率に従って選ぶだけです。 def SoftmaxPolicy(model, state, nb_actions): action_probs = model(state.reshape((1,-1)))[0].numpy() return np.random.choice(nb_actions, 1, p=action_probs)[0] 経験の収集と学習ループのコード 経験の収集ですが、収集した時に使われていた戦略と学習する時の戦略が一致している必要があります。(On-policyのため) ですのでモデルを更新すると過去の経験が使えなくなります。 これは Experience Replay と相性が悪く、今回の実装では Experience Replay は使わずにモンテカルロ法で実装しています。 また、経験と学習の戦略が一致していない場合は Off-policy となり、この差異を何かしら調整して学習する手法もあったります。 (今回は触れません) 経験収集と学習のループのコードは以下です。 # 学習ループ env = gym.make("CartPole-v0") for episode in range(300): state = np.asarray(env.reset()) done = False total_reward = 0 experiences = [] # 1episode while not done: # アクションを決定 action = SoftmaxPolicy(model, state, nb_actions) # 1step進める n_state, reward, done, _ = env.step(action) n_state = np.asarray(n_state) total_reward += reward # 経験を保存する experiences.append({ "state": state, "action": action, "reward": reward, "n_state": n_state, "done": done, }) state = n_state # 現在からエピソード最後までの報酬を計算 for i,exp in enumerate(experiences): G = 0 t = 0 for j in range(i, len(experiences)): G += (gamma ** t) * experiences[j]["reward"] t += 1 exp["G"] = G # 1エピソード毎に学習(中身は後述) train(model, experiences) 学習 更新式の通りに勾配を計算して更新する必要があるので損失関数は自作したものを用意する必要があります。 Tensorflow2.0 では GradientTape を用いると勾配を計算できるようです。(参考の公式チュートリアルが参考になりました) from sklearn.preprocessing import StandardScaler def train(model, experiences): # データ形式を変形 state_batch = np.asarray([e["state"] for e in experiences]) action_batch = np.asarray([e["action"] for e in experiences]) reward_batch = np.asarray([e["G"] for e in experiences]) # アクションは one_hot ベクトルにする one_hot_actions = tf.one_hot(action_batch, nb_actions) # 報酬は正規化する # (正規化しないと学習が安定しませんでした) # (softmax層と相性が悪いから?) reward_batch = StandardScaler().fit_transform(reward_batch.reshape((-1, 1))).flatten() # 勾配を計算する with tf.GradientTape() as tape: # 現在の戦略を取得 action_probs = model(state_batch, training=True) # Forward pass # (1) 選択されたアクションの確率を取得 selected_action_probs = tf.reduce_sum(one_hot_actions * action_probs, axis=1) # log(0) 回避用 clipped = tf.clip_by_value(selected_action_probs, 1e-10, 1.0) # (2) 期待値「log( π(a|s) ) × Q」を計算 loss = tf.math.log(clipped) * reward_batch # (3) experiences すべての期待値の合計が最大となるように損失を設定 # 最大値がほしいので負の値にしています loss = -tf.reduce_sum(loss) # 勾配を元にoptimizerでモデルを更新 gradients = tape.gradient(loss, model.trainable_variables) model.optimizer.apply_gradients(zip(gradients, model.trainable_variables)) return loss # 確認用 (1)で $\pi_{\theta}(a|s)$ を計算しています。 (2)で $log \pi_{\theta}(a|s) Q^{\pi_\theta}(s,a)$ を計算しています。 (3)で計算した期待値を合計しています。 評価と結果の出力 戦略を学習しているのでテスト用に何かする必要はありません。 そのまま実行できます。 # 5回テストする for episode in range(5): tate = np.asarray(env.reset()) env.render() done = False total_reward = 0 # 1episode while not done: action = SoftmaxPolicy(model, state) n_state, reward, done, _ = env.step(action) state = np.asarray(n_state) env.render() step += 1 total_reward += reward print("{} step, reward: {}".format(step, total_reward)) 学習中の様子 テスト結果 200 step, reward: 200.0 200 step, reward: 200.0 200 step, reward: 200.0 200 step, reward: 200.0 200 step, reward: 200.0 A3C/A2C Actor CriticのディープラーニングアルゴリズムとしてA2C(Advantage Actor Critic)を取り上げます。 A2Cの前にA3C(Asynchronous Advantage Actor Critic)があり、A3Cでは分散学習+Asynchronous(非同期)で学習する手法でした。 しかし、非同期がなくても同等以上の精度がでるといわれて提案された手法がA2Cらしいです。 ただ、今回の実装において分散学習は本質ではないのでそれを除外した実装を行います。 そうなるとA3CとA2Cで大きく実装の差異はないようです。 モデルの定義 A2Cのモデルでは状態の入力に対してActor側とCritic側の2つの出力を持ちます。 Dueling Networkに似てますね(もしかしたらこれが元ネタかも知れません) from tensorflow.python import keras from tensorflow.keras.optimizers import Adam # 環境の状態の形式(shape) obs_shape = env.observation_space.shape # 環境の取りうるアクション数 nb_actions = env.action_space.n lr = 0.01 # 学習率 c = input_ = keras.layers.Input(shape=obs_shape) c = keras.layers.Dense(10, activation="relu")(c) c = keras.layers.Dense(10, activation="relu")(c) actor_layer = keras.layers.Dense(nb_actions, activation="linear")(c) critic_layer = keras.layers.Dense(1, activation="linear")(c) model = keras.Model(input_, [actor_layer, critic_layer]) model.compile(optimizer=Adam(lr=lr)) model.summary() 今回も損失関数は自作するので指定していません。 行動の決定 方策勾配法の時と同じですが出力が線形なのでsoftmax関数を経由して確率的に選ぶようにしています。 def LinearSoftmaxPolicy(model, state, nb_actions): action_eval, _ = model(state.reshape((1,-1))) probs = tf.nn.softmax(action_eval) return np.random.choice(nb_actions, 1, p=probs[0].numpy())[0] モデルの出力が2つあるのでその処理も行っています。 経験の収集と学習ループのコード 経験の収集は方策勾配法の時と同じく同じ戦略の経験を集める必要があります。 なのでモンテカルロ法で実装しますが、Criticにより価値を見積もることもできるのでエピソード終了まで待つ必要はありません。 バッチサイズ分経験が貯まったらその都度計算していきます。 経験収集と学習のループのコードは以下です。 batch_size = 32 experiences = [] # 学習ループ env = gym.make("CartPole-v0") for episode in range(300): state = np.asarray(env.reset()) done = False total_reward = 0 # 1episode while not done: # アクションを決定 action = LinearSoftmaxPolicy(model, state, nb_actions) # 1step進める n_state, reward, done, _ = env.step(action) n_state = np.asarray(n_state) total_reward += reward # 経験を保存する experiences.append({ "state": state, "action": action, "reward": reward, "n_state": n_state, "done": done, }) state = n_state # batch_size貯まるごとに学習する if len(experiences) == batch_size: train(model, experiences) experiences = [] 勾配の計算 A2Cでは1つのネットワークで戦略と価値を出力しているのでロス関数も1つとなります。 更新式は以下に分けられます。 Total loss = -アドバンテージ方策勾配 + α Value loss - β 方策エントロピー アドバンテージ方策勾配と方策エントロピーは最大値を求めたいのでマイナスをかけています。 αとβは割合を決めるハイパーパラメーターです。 アドバンテージ方策勾配 方策勾配で求める勾配は上記でも書いた通り以下になります。 $$ log \pi_{\theta}(a|s) Q^{\pi_\theta}(s,a) $$ アドバンテージ方策勾配は以下になります。 $$ log \pi_{\theta}(a|s) A^{\pi_\theta}(s,a) $$ QがAに変わっただけですね、Aは以下になります。 $$ A(s_t,a_t) = Q(s_t,a_t) - V(s_t) = r_{t+1} + V(s_{t+1}) - V(s_t) $$ 方策勾配の重みづけに状態行動価値をそのまま使わずに現在の状態価値を引くことで分散が小さくなり学習が安定するそうです。 上記式では1stepのみ引いていますが、数ステップ先まで引く方法もあるようです。 Value loss Q学習と変わらず次の状態の価値と今の状態の価値の差分です。 平均二乗誤差で損失を出します。 $$ \frac{ \sum(r + V(s_{t+1}) - V(s_t) )^2}{n} $$ 方策エントロピー 方策エントロピーとはエントロピーが大きいほうが良い状態を指します。 例えばアクションが[50%,50%]と[70%,30%]の方策があった場合、後者のほうがエントロピーが大きい(乱雑である)といいます。 方策エントロピーが大きいほうが、学習が進んでおりいい方策になっていると考えられるため、これにボーナスを与える項がこの方策エントロピーになります。 数式は以下です。 $$ \sum_a \pi(a_t|s_t) log \pi(a_t|s_t) $$ 方策エントロピー項の追加は、方策関数の正則化効果が期待できるようです。 学習 各経験に関して、状態価値関数が予測できるので、分かる部分に関しては実測値から、不明な部分は状態価値関数から予測して状態価値を計算しています。 def train(model, experiences): gamma = 0.9 # 割引率 # 現在からエピソード最後までの報酬を計算(後ろから計算) if experiences[-1]["done"]: # 最後が終わりの場合は全部使える G = 0 else: # 最後が終わりじゃない場合は予測値vで補完する n_state = np.atleast_2d(experiences[-1]["n_state"]) _, n_v = model(n_state) G = n_v[0][0].numpy() # 割引報酬を後ろから計算 discounted_rewards = [] for exp in reversed(experiences): if exp["done"]: G = 0 G = exp["reward"] + gamma * G discounted_rewards.append(G) discounted_rewards.reverse() discounted_rewards = np.asarray(discounted_rewards) # データ形式を変形 state_batch = np.asarray([e["state"] for e in experiences]) action_batch = np.asarray([e["action"] for e in experiences]) # アクションをonehotベクトルの形に変形 onehot_actions = tf.one_hot(action_batch, nb_actions) # 勾配を計算する with tf.GradientTape() as tape: action_eval, v = model(state_batch, training=True) # Forward pass # π(a|s)を計算 action_probs = tf.nn.softmax(action_eval) selected_action_probs = tf.reduce_sum(onehot_actions * action_probs, axis=1) #--- アドバンテージを計算 # アドバンテージ方策勾配で使うvは値として使うので、 # 勾配で計算されないように tf.stop_gradient を使う advantage = discounted_rewards - tf.stop_gradient(v) # log(π(a|s)) * A(s,a) を計算 selected_action_probs = tf.clip_by_value(selected_action_probs, 1e-10, 1.0) # 0にならないようにclip policy_loss = tf.math.log(selected_action_probs) * advantage # 合計 policy_loss = tf.reduce_sum(policy_loss) #--- Value loss # 平均二乗誤差で損失を計算 value_loss = tf.keras.losses.MeanSquaredError()(discounted_rewards, v) #--- 方策エントロピー entropy = tf.reduce_sum(tf.math.log(selected_action_probs) * selected_action_probs) #--- total loss value_loss_weight = 1.0 entropy_weight = 0.1 loss = -policy_loss + value_loss_weight * value_loss - entropy_weight * entropy # 勾配を元にoptimizerでモデルを更新 gradients = tape.gradient(loss, model.trainable_variables) model.optimizer.apply_gradients(zip(gradients, model.trainable_variables)) 評価と結果の出力 方策勾配法と同じで戦略を学習しているのでテスト用に何かする必要はありません。 そのまま実行できます。 # 5回テストする for episode in range(5): tate = np.asarray(env.reset()) env.render() done = False total_reward = 0 # 1episode while not done: action = LinearSoftmaxPolicy(model, state) n_state, reward, done, _ = env.step(action) state = np.asarray(n_state) env.render() step += 1 total_reward += reward print("{} step, reward: {}".format(step, total_reward)) 学習中の様子 テスト結果 200 step, reward: 200.0 200 step, reward: 200.0 200 step, reward: 200.0 200 step, reward: 200.0 200 step, reward: 200.0 あとがき ニューラルネットワークに反映するうえで重要なのは勾配の出し方ですね。 価値関数は簡単ですが、戦略関数の更新は計算が難しいですね…(まあ、計算結果だけを使えば問題ないですけど) 次は強化学習の学習効率を上げる手法について取り上げたいと思います。 参考 TensorFlow > 学ぶ > TensorFlow Core > ガイド基本的なトレーニングループ TensorFlow > 学ぶ > TensorFlow Core > ガイド > トレーニングループを最初から作成する 機械学習スタートアップシリーズ Pythonで学ぶ強化学習 [改訂第2版] 入門から実践まで(amazonリンク) A3CでCartPole (強化学習) Policy Gradient Algorithms A3C(論文) A2C(論文) Advantage Actor Critic Tutorial: minA2C 【強化学習】実装しながら学ぶA3C【CartPoleで棒立て:1ファイルで完結】
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ADX2ロボットでブロックの長さを得る

はじめに ブロックの長さを知りたい時がよくあるので、 キューを選択して実行すると長さが得られるような ADX2ロボット機能のスクリプトを書いてみた。 やっていること 選択キューを取得 キューの中にあるブロックを取得 ブロックの長さ(BlockEndPositionMs)を得る 少し整形してログに表示 出力結果 ログに出力される。 何か最後に長いブロックが入っている・・・ これはいらないブロックかもしれない。 なんてことに気が付けたりする。 あと、長さが一定だった場合は、ここでも同じ値になっていれば心配ないなど安心できる。 スクリプト # --Description:[tatmos][Analyze]選択したキューのブロックの長さをログに表示 import cri.atomcraft.debug as acdebug import cri.atomcraft.project as acproject # 選択しているCueを得る selected_Cues = acproject.get_selected_objects("Cue")["data"] if not selected_Cues : acdebug.warning("Please select at least a Cue.") sys.exit() for cue in selected_Cues: # パス表示 acdebug.log("Target Path:\"{0}\"".format(acproject.get_object_path(cue)["data"] )) Blocks = acproject.get_child_objects (cue, "Block")["data"] for block in Blocks: blockEndPositionMs = acproject.get_value(block, "BlockEndPositionMs") if blockEndPositionMs["succeed"]: length = "{:,.3f}".format(float(blockEndPositionMs["data"])) acdebug.log(" {0}\t {1}".format( "{:>12}".format(length) ,acproject.get_value(block, "Name")["data"])) おわりに ブロックの長さ、ビートに合わせていたりした場合などに、半端なタイミングだとうまくループにならなかったりといろいろあるので、そういうチェックを入れても良いかもしれない。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Flaskを使用したFacebook ログイン 連携用API作成 メモ

Flask を使用してFacebookログイン連携するためのAPI作成方法についてメモする。 Google連携用APIを試した時と同様に、Docker起動できる形で過去に作成したFacebook検証コードを部分的にAPI化した。 作成するAPI 認可リクエスト作成API Facebookへの認可エンドポイントへアクセスするためのURLをパラメータをつけて生成・返却する。 stateはAPI呼び出し時に生成し、レスポンスとして返却する。 client_idなど固定の属性値は環境変数から取得する。 リクエスト例 POST /api/facebook/auth_request/create HTTP/1.1 Host: localhost:5000 レスポンス例 { "authorization_request_url": "https://www.facebook.com/v10.0/dialog/oauth?client_id=AAABBBBCCC&scope=email&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2Fcallback&state=ABCDE12345&response_type=code", "state": "ABCDE12345" } トークンリクエスト+ユーザー情報取得API 認可レスポンスとして受け取った認可コード(code)を指定して、トークンリクエスト+ユーザー情報取得を行う。 今回は簡略化のため認可リクエストパラメータのDB保存まで実装しておらず、検証処理は行っていないが、stateパラメータの検証は必ず行うこと。 リクエスト POST /api/facebook/auth_request/complete HTTP/1.1 Host: localhost:5000 Content-Type: application/json Content-Length: 363 { "code":"XXX" } レスポンス例 { "id": "1234567890", "name": "山田太郎" } プロジェクト構成 facebook_oidc └─ docker-compose.yml └─ facebook.env │ └─ be └─ Dockerfile └─ requirements.txt │ └─app └─ app.py │ └─ api └─ __init__.py │ └─views └─ facebook.py 実装 docker-compose.yml ※起動時に環境変数ファイルfacebook.envを読み込む。 version: "3" services: be: container_name: be build: ./be env_file: facebook.env volumes: - ./be/app:/app ports: - "5000:5000" command: flask run --host 0.0.0.0 --port 5000 tty: true facebook.env 環境変数ファイル。アプリケーション登録時に発行・設定した値を指定する。 FACEBOOK_CLIENT_ID=YOUR_CLIENT_ID FACEBOOK_CLIENT_SECRET=YOUR_CLIENT_SECRET FACEBOOK_SCOPE_LIST=YOUR_SCOPE_LIST FACEBOOK_REDIRECT_URI=YOUR_REDIRECT_URI FACEBOOK_AUTHORIZATION_ENDPOINT=https://www.facebook.com/v10.0/dialog/oauth FACEBOOK_TOKEN_ENDPOINT=https://graph.facebook.com/v10.0/oauth/access_token FACEBOOK_APP_TOKEN_ENDPOINT=https://graph.facebook.com/oauth/access_token FACEBOOK_TOKEN_VALIDATION_ENDPOINT=https://graph.facebook.com/debug_token FACEBOOK_USER_INFO_ENDPOINT=https://graph.facebook.com/v10.0/ be/requirements.txt Pythonライブラリ一式 Flask Flask-Cors be/Dockerfile FROM python:3.8 RUN mkdir /app ADD requirements.txt /app ENV PYTHONUNBUFFERED 1 EXPOSE 5000 WORKDIR /app RUN pip3 install -r requirements.txt be/app/app.py from api import app if __name__ == '__main__': app.run() be/api/__init__.py from flask import Flask from .views.facebook import facebook_router from flask_cors import CORS def create_app(): app = Flask(__name__) CORS(app, supports_credentials=True) app.register_blueprint(facebook_router, url_prefix='/api') return app app = create_app() be/api/views/facebook.py コントローラー ※エラーハンドリング皆無 import hashlib from flask import Flask, Blueprint, request import urllib.parse as parse import urllib.request as req import urllib.error as error import json import os from pprint import pprint # Routing Settings facebook_router = Blueprint('facebook_router', __name__) # Client Param client_id = os.getenv('FACEBOOK_CLIENT_ID') client_secret = os.getenv('FACEBOOK_CLIENT_SECRET') redirect_uri = os.getenv('FACEBOOK_REDIRECT_URI') scope_list = os.getenv('FACEBOOK_SCOPE_LIST') # Facebook Endpoint authorization_endpoint = os.getenv('FACEBOOK_AUTHORIZATION_ENDPOINT') token_endpoint = os.getenv('FACEBOOK_TOKEN_ENDPOINT') app_token_endpoint = os.getenv('FACEBOOK_APP_TOKEN_ENDPOINT') token_validation_endpoint = os.getenv('FACEBOOK_TOKEN_VALIDATION_ENDPOINT') user_info_endpoint = os.getenv('FACEBOOK_USER_INFO_ENDPOINT') app = Flask(__name__) # Create Authorization Request Endpoint @facebook_router.route("/facebook/auth_request/create", methods=['POST']) def create(): # Generate state state = hashlib.sha256(os.urandom(32)).hexdigest() # Create Authz Request URL auth_request_url = authorization_endpoint+'?{}'.format(parse.urlencode({ 'client_id': client_id, 'scope': scope_list, 'redirect_uri': redirect_uri, 'state': state, 'response_type': 'code' })) res_body = { "authorization_request_url": auth_request_url, "state": state } return json.loads(json.dumps(res_body)) # Token Request And Get User Info Endpoint @facebook_router.route("/facebook/auth_request/complete", methods=['POST']) def complete(): # Parse Req Body jsonData = json.dumps(request.json) req_body = json.loads(jsonData) # Exchange Authorization code for Access Token token_req_url = token_endpoint+'?{}'.format(parse.urlencode({ 'client_id': client_id, 'client_secret': client_secret, 'redirect_uri': redirect_uri, 'code': req_body["code"] })) try: token_req = req.Request(token_req_url, method='GET') with req.urlopen(token_req) as token_res: token_res_body = token_res.read() except error.HTTPError as err: err_str = str(err.code) + ':' + err.reason + ':' + str(err.read()) pprint(err_str) except error.URLError as err: err_str = err.reason pprint(err_str) access_token = json.loads(token_res_body)['access_token'] # Generate App Access Token # https://developers.facebook.com/docs/facebook-login/access-tokens/#apptokens app_token_req_url = app_token_endpoint+'?{}'.format(parse.urlencode({ 'client_id': client_id, 'client_secret': client_secret, 'grant_type': 'client_credentials' })) try: app_token_req = req.Request(app_token_req_url, method='GET') with req.urlopen(app_token_req) as app_token_res: app_token_res_body = app_token_res.read() except error.HTTPError as err: err_str = str(err.code) + ':' + err.reason + ':' + str(err.read()) except error.URLError as err: err_str = err.reason app_token = json.loads(app_token_res_body)['access_token'] # Validate Access Token token_validation_req_url = token_validation_endpoint+'?{}'.format(parse.urlencode({ 'input_token': access_token, 'access_token': app_token })) try: token_validation_req = req.Request( token_validation_req_url, method='GET') with req.urlopen(token_validation_req) as token_validation_res: token_validation_res_body = token_validation_res.read() except error.HTTPError as err: err_str = str(err.code) + ':' + err.reason + ':' + str(err.read()) pprint(err_str) except error.URLError as err: err_str = err.reason pprint(err_str) # Get User Info # https://developers.facebook.com/docs/graph-api/reference/user user_request_url = user_info_endpoint+'/' + \ json.loads(token_validation_res_body)['data']['user_id']+'/' headers = { 'Authorization': 'Bearer ' + access_token } user_req = req.Request(user_request_url, headers=headers, method='GET') with req.urlopen(user_req) as user_res: user_res_body = user_res.read() return json.loads(user_res_body) 起動 docker-compose up -d 参考情報 ログインフローを手動で構築する アクセストークン
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python演算処理】単位トーラス(Unit Torus)を巡る数理①平坦トーラス(Flat Torus)との往復

以下の投稿では複素平面(Complex Plane)上における円周群の概念と等速円運動(Constant Velocity Circular Motion)に共通する数理について調べました。 等速円運動についての物理学と数学の立場の違い? 今度は座標系全体に目を向けてみましょう。 トーラス座標系(Torus coordinate system)なる概念の登場。 この投稿は主に以下を参照しています。 【超わかる】オイラーの公式を見て!聞いて!感じるンゴ! ①まずは両側無限実数列(Both-sides Real Sequence)$Z_n$とその指数写像(Exponential Map)たる片側無限実数列(One-side Real Sequence)$e^n$の関係から出発する。自明の場合として$Z_n$は$e^n$の対数写像(Logarithm Map)となる。 リー環の指数写像 - Wikipedia 解析学の通常の指数関数はリー群Gが正の実数の乗法群(そのリー環は実数全体のなす加法群)のときの指数写像という特別な場合である。リー群の指数写像は通常の指数関数の性質と類似の多くの性質を満たすが、しかしながら、多くの重要な面において異なりもする。 行列指数関数(Matrix Exponential=行列乗) - Wikipedia 行列の対数(Logarithm of a Matrix) - Wikipedia 対数を持つ正方行列(Square Matrix,行要素数と列要素数が一致する正方行列)はいずれかのリー群に属し、かつ、その対数はそのリー群に付随するリー代数の元に対応するため、行列の対数函数の研究はリー理論につながる。指数写像は行列の指数関数で与えられるが、その逆写像は一般に多価となる。対数写像はリー群Gを付随するリー代数gへ写す。 【数理考古学】常用対数表(Table of Common Logarithms)を使った計算 実軸(Real Axis)における乗除算はその対数写像において加減算に置き換えられる。 それぞれの関数の定義域(関数y=f(x)における独立変数xの値)と値域(関数y=f(x)における従属変数yの値)の関係は以下。 Z_n(n=-\infty→-1→0→1→+\infty)=(-\infty,…,-1,…,0,…,1,…,+\infty)\\ e^n(n=-\infty→-1→0→1→+\infty)=(0,…,e^{-1},…,1,…,e^1,…,\infty) 【数理考古学】とある実数列(Real Sequance)の規定例②等比数列から乗法群へ -\infty→0\\ -1→e^{-1}(0.3678794)\\ 0→1\\ 1→e^1(2.718282)\\ +\infty→\infty これを「正の実軸上の半直線上に写る元の定義域」は実数直線の任意の点αと考える。 ②すると「負の実軸上の半直線上に写る元の定義域」は$α+iπ$とイメージされる。オイラーの等式(Eulerian Identity)$e^{πi}=-1$の世界。 ③「正の虚軸上の半直線上に写る元の定義域」は$α+i\frac{π}{2}$ないしは$α-3i\frac{π}{2}$とイメージされる。分枝点切断を行わない座標系では両者が同値となる。 ④「正の虚軸上の半直線上に写る元の定義域」は$α+3i\frac{π}{2}$ないしは$α-i\frac{π}{2}$とイメージされる。分枝点切断を行わない座標系では両者が同値となる。 これはまさに複素平面をトーラス座標系として捉える発想に他なりません。 【Python演算処理】単位球面を巡る数理②そして単位トーラスへ 確かにトーラス構造を平たく伸ばして「(上下左右の端同士がつながってるコンピューターRPGのワールドマップの様な)平面トーラス」に変換するとこうした座標演算が可能となるのです。こうして展開された平面トーラスは、大半径/小半径それぞれを単位1と置いた場合、それぞれ2π倍の広がりを持つ方形となります。 【ドラクエ1】ワールドマップ(世界地図)とマップ一覧 一般の円座標系との共通点。 この投稿も主に以下を参照しています。 【超わかる】オイラーの公式を見て!聞いて!感じるンゴ! トーラス座標系も円座標同様に写像元に加えられるスカラー加減算の影響を受ける訳ですが、こちらはむしろ頭を切り替えて円座標が極座標系(Polar Coordinates System)では半径(Radius)rθ(2次元)、rφθ(3次元)と表される数理に拠って考える方がイメージしやすいかもしれません。 ①元写像が実数軸の原点で交わる場合、単位スケールそのまま。 ②元写像が実数軸の原点より左(すなわちマイナス方向の位置)で交わる場合、縮小。 ③元写像が実数軸の原点より右(すなわち+方向の位置)で交わる場合、拡大。 さらに与えられる演算が傾き(Slope)の要素を含む場合、円ではなく螺旋を描きます。これについては円描画関数$-1^n=±i^{2x}$を中心と考える方式に頭を切り替えた方が遥かにイメージしやすいでしょう。 【数理考古学】とある実数列(Real Sequance)の規定例②等比数列から乗法群へ 0>公比>-1の等比数列の場合…どんどん振幅の幅が狭まっていく。 公比<-1の等比数列の場合…どんどん振幅の幅が広がっていく。 どうやらこの辺りの数理はトーラス座標系の拡張形たる円筒座標系(Cylindrical coordinate system)をさらに円錐座標系(Conical Coordinate System)に発展させる際に鍵となってきそうです。 そんな感じで以下続報…
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Python dictを一定量に分割して取り出す

listを一定区間、または一定数になるよう分割することは日常的にされているかと思いますが、辞書(dict)を一定量に区切る機会はあまりないかもしれません。 そんなニッチな辞書分割にも、いろいろな方法があります。ここでは、一番直感的でかんたんな方法(主観)をメモしておきます。 itertools.islice()を使います。 isliceで辞書を分割する実装 dict_slice.py data = { i:i**2 for i in range(10) } pprint.pprint(data, width=40, indent=4) # { # 0: 0, # 1: 1, # 2: 4, # 3: 9, # 4: 16, # 5: 25, # 6: 36, # 7: 49, # 8: 64, # 9: 81 # } from pprint import pprint from itertools import islice def dict_chunks(data, size): it = iter(data) for i in range(0, len(data), size): yield {k:data[k] for k in islice(it, size)} chunks = dict_chunks(data, size=3) count = 0 for c in chunks: print(f"chunk {count}: {c.keys()}") count += 1 # chunk 0: dict_keys([0, 1, 2]) # chunk 1: dict_keys([3, 4, 5]) # chunk 2: dict_keys([6, 7, 8]) # chunk 3: dict_keys([9]) より突っ込んだことを書くと長くなるので記事にまとめています。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

データサイエンス〜独学ダッシュボード〜

■前提 〜データサイエンティストを目指すことを決意したエンジニアの独学メモ〜 これまで独学をしようと試行錯誤してきましたが、あまり上手くいかなった。 とあるYouTubeを観て、目からウロコ。 独学が手段ではなく目的になっていた。 ■きっかけ 以下のYouTubeを観て感銘を受けました。 【前半】初心者向け!データサイエンスの独学ロードマップ 【後半】初心者向け!データサイエンスの独学ロードマップ このYouTubeをきっかけにデータサイエンティストを目指すこととしました。 動画の中で紹介されていた書籍を早速購入しました。 まだ半分しか読めていませんが、素晴らしい書籍だと思います。 技術評論社 AI・データ分析プロジェクトのすべて[ビジネス力×技術力=価値創出] ■前提 私の状態 年齢:40代 職業:金融系エンジニア(要件定義・外部設計などの上流工程) スキル:SQLは好物 ■最後に 私がデータサイエンティストへのスキルチェンジする様子を このダッシュボードをとおして、記録していければと思っています。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

pythonでgnuradio

概要 pythonでgnuradioやってみた。 1khzのサイン波を聞く。 環境 windows 7 64bit GNU Radio Companion 3.7.10.1 Python 2.7.10 サンプルコード from gnuradio import analog, audio, blocks, gr class my_block(gr.top_block): def __init__(self): gr.top_block.__init__(self, "top0") self.samp_rate = samp_rate = 32000 self.audio_sink_0 = audio.sink(samp_rate, '', True) self.analog_sig_source_x_0 = analog.sig_source_f(samp_rate, analog.GR_COS_WAVE, 1000, 1, 0) self.connect((self.analog_sig_source_x_0, 0), (self.audio_sink_0, 0)) if __name__ == '__main__': try: my_block().run() except KeyboardInterrupt: pass 以上。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python】Nestしたdictで特定の文字列を含むValueを見つける

TL;TD dictで特定の文字列を含むValueを見つけて、文字列加工を行いたかった 結果はそのValueまでの文字列が格納されたlistが出力される dict-keyの場合はkey名、listの場合はindexが文字列に含まれる このままでは実際にValueにアクセスはできないので、実際にはdpathのモジュールを使用して値は取得する https://pypi.org/project/dpath/ こんな感じで指定の条件を満たすValueどこにあるか探す list / str になるまで再帰的に処理を行う list内にdictが含まれる場合が考慮されてないので、そこは要改良 def __get_dict_path_by_match_str_pattern(self, my_dict, pattern, path="", result=None): if result is None: result = [] for key, value in my_dict.items(): if isinstance(value, dict): self.__get_dict_path_by_match_str_pattern(value, pattern, "{}/{}".format(path, key), result) elif isinstance(value, (list, tuple)): result += ["{}/{}/{}".format(path, key, i) for i, v in enumerate(value) if pattern in v] elif isinstance(value, (str, int)): if pattern in value: result.append("{}/{}".format(path, key)) else: raise ValueError("Not support type {}. Value is {}".format(type(value), value)) return result Ex. Valueに"l" を含む文字列を持つものを探す input { "attr": { "types": { "tag": { "name": "Tom", "gender": "male" }, "category": "employee" } } } output ["/attr/types/tag/gender", "/attr/types/category/0"] 感想 yieldとか使うともっと効率よく処理できそう。今度試そう
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS lambdaでS3オブジェクトの自動ウイルススキャンをやろうとしてハマった話

やりたかったこと S3にファイルがアップされたら自動でウイルススキャンを行いたい 調べてみると以下がいい感じだったので実施したが思いの外ハマったのでメモ https://github.com/upsidetravel/bucket-antivirus-function 手順 権限周りは以下を参考にしてください https://dev.classmethod.jp/articles/s3-bucket-antivirus-lambda/ git clone https://github.com/upsidetravel/bucket-antivirus-function.git cd bucket-antivirus-function/ sudo make all ./build/lambda.zipが作成されるのでS3にアップする 以下のCfnテンプレートで3時間ごとに実行されるlambda関数作成 Resources: ScheduledRule: Type: AWS::Events::Rule Properties: ScheduleExpression: 'cron(00 0-23/3 * * ? *)' State: ENABLED Targets: - Arn: !GetAtt Lambda.Arn Id: bucket-antivirus-update PermissionForEventsToInvokeLambda: Type: AWS::Lambda::Permission Properties: FunctionName: !Ref Lambda Action: lambda:InvokeFunction Principal: events.amazonaws.com SourceArn: !GetAtt ScheduledRule.Arn Lambda: Type: AWS::Lambda::Function Properties: Code: S3Bucket: lambda-function-bucket S3Key: lambda.zip Environment: Variables: AV_DEFINITION_S3_BUCKET: antivirus-definition-bucket FunctionName: bucket-antivirus-update Handler: update.lambda_handler MemorySize: 1024 Role: antivirus-update-role-arn Runtime: python3.7 Timeout: 300 エラー発生 とりあえずここまでの工程でS3にウイルス定義ファイルをアップする部分はできたはずなので試しに実行してみると以下のエラー発生 START RequestId: xxxxxxxxxxxxxxxxxxxxxxxx Version: $LATEST Script starting at 2021/04/19 04:37:41 UTC Attempting to create directory /tmp/clamav_defs. Starting freshclam with defs in /tmp/clamav_defs. freshclam output: b'./bin/freshclam: error while loading shared libraries: libprelude.so.28: cannot open shared object file: No such file or directory\n' Unexpected exit code from freshclam: 127. File does not exist: main.cld File does not exist: main.cvd File does not exist: daily.cld File does not exist: daily.cvd File does not exist: bytecode.cld File does not exist: bytecode.cvd Script finished at 2021/04/19 04:37:42 UTC END RequestId: xxxxxxxxxxxxxxxxxxxxxxxx REPORT RequestId: xxxxxxxxxxxxxxxxxxxxxxxx Duration: 2604.36 ms Billed Duration: 2605 ms Memory Size: 128 MB Max Memory Used: 85 MB Init Duration: 334.40 ms あれこれ調べてみると https://github.com/upsidetravel/bucket-antivirus-function/issues/125 こちらのissueに遭遇。どうやらlambda側がライブラリを見つけられないことが原因のよう Dockerfileを以下のように書き換えてmakeし直したところエラーが解消しました。 FROM amazonlinux:2 # Set up working directories RUN mkdir -p /opt/app RUN mkdir -p /opt/app/build RUN mkdir -p /opt/app/bin/ # Copy in the lambda source WORKDIR /opt/app COPY ./*.py /opt/app/ COPY requirements.txt /opt/app/requirements.txt # Install packages RUN yum update -y RUN yum install -y cpio python3-pip yum-utils zip unzip less RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm # This had --no-cache-dir, tracing through multiple tickets led to a problem in wheel RUN pip3 install -r requirements.txt RUN rm -rf /root/.cache/pip # Download libraries we need to run in lambda WORKDIR /tmp RUN yumdownloader -x \*i686 --archlist=x86_64 clamav clamav-lib clamav-update json-c pcre2 libprelude gnutls libtasn1 lib64nettle nettle RUN rpm2cpio clamav-0*.rpm | cpio -idmv RUN rpm2cpio clamav-lib*.rpm | cpio -idmv RUN rpm2cpio clamav-update*.rpm | cpio -idmv RUN rpm2cpio json-c*.rpm | cpio -idmv RUN rpm2cpio pcre*.rpm | cpio -idmv RUN rpm2cpio gnutls* | cpio -idmv RUN rpm2cpio nettle* | cpio -idmv RUN rpm2cpio lib* | cpio -idmv RUN rpm2cpio *.rpm | cpio -idmv RUN rpm2cpio libtasn1* | cpio -idmv # Copy over the binaries and libraries RUN cp /tmp/usr/bin/clamscan /tmp/usr/bin/freshclam /tmp/usr/lib64/* /opt/app/bin/ # Fix the freshclam.conf settings RUN echo "DatabaseMirror database.clamav.net" > /opt/app/bin/freshclam.conf RUN echo "CompressLocalDatabase yes" >> /opt/app/bin/freshclam.conf # Create the zip file WORKDIR /opt/app RUN zip -r9 --exclude="*test*" /opt/app/build/lambda.zip *.py bin WORKDIR /usr/local/lib/python3.7/site-packages RUN zip -r9 /opt/app/build/lambda.zip * WORKDIR /opt/app
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pythonによる各種画像処理ライブラリを用いたデータの入出力方法とライブラリ間の連携方法(OpenCV, Scikit-image, Pillow)

概要 Python を用いて画像処理を行う第一歩として,画像処理用の各種ライブラリによるデータの入出力方法と,ライブラリ間の連携方法について記載する. Python ではいくつかの画像処理ライブラリが活用できる.そのため,ひとつのコードの中で複数のライブラリを用いた処理を行う際には,互換性の確認が必要である. ここでは,各ライブラリを用いて実装する際の画像データ構造の扱い方の違いと複数ライブラリをまたいで使用する際の方法について記述する. Python で活用できる画像処理ライブラリの種類と事前準備 ここでは画像処理ライブラリとして,OpenCV, Scikit-image, Pillow について扱う. OpenCV:Open Source Computer Vision Library Intel が開発した画像処理のためのオープンソースライブラリ.C/C++, Java, MATLAB でも公開されており,インターネット上にも OpenCV を用いたサンプルコードが多く見受けられる. 【インストール方法】 コマンドプロンプト上で,OpenCV を pip3 コマンドによりインストールする. pip3 install opencv-python pip3 install opencv-contrib-python ※OpenCV では,画像データを numpy 配列 ndarray で扱うため,numpy モジュールがインストールされていない場合には numpy インストールしておく. pip3 install numpy 【インポート方法】 Python プログラム上で cv2 を import する. import cv2 Scikit-image Python向けの画像処理ライブラリ. 【インストール方法】 コマンドプロンプト上で,Scikit-image を pip3 コマンドによりインストールする. pip3 install scikit-image ※Scikit-image も OpenCV 同様,画像データを numpy 配列 ndarray で扱うため,numpy モジュールがインストールされていない場合には numpy インストールしておく. pip3 install numpy 【インポート方法】 Python プログラム上で skimage を import する. from skimage.io Pillow 2011 年で開発を停止した PIL (Python Image Library) のリポジトリをフォークし,Python3 のサポートを追加した画像処理ライブラリ. 【インストール方法】 コマンドプロンプト上で,Scikit-image を pip3 コマンドによりインストールする. pip3 install Pillow 【インポート方法】 Python プログラム上で PIL を import する. from PIL import Image 各画像処理ライブラリの入出力 OpenCV ・入力 img = cv2.imread(Inputfilename) ※ Inputfilename には画像のあるディレクトリからファイル名を記載するが,日本語を含む path は読み込まないため注意. ・画像の可視化 cv2.imshow('imgCV', img) cv2.waitKey(0) cv2.destroyAllWindows() ・出力 cv2.imwrite(Outputfilename, img) 【データの構造】 画像データを読み込むと,( 行(画像の縦のサイズ), 列(画像の横のサイズ), 色の次元数(白黒だと 1 カラーだと 3) ) の構造になっている.色の順番は,BGR(青、緑、赤)の順で保存されている. print(type(img)) <class 'numpy.ndarray'> print(img.shape) (行, 列, 色) print(im.dtype) uint8 Scikit-image ・入力 img = skimage.io.imread(Inputfilename) ・画像の可視化 io.imshow(img) ・出力 io.imsave(Outputfilename, img) 【データの構造】 画像データを読み込むと,( 画像の縦のサイズ, 画像の横のサイズ, 色の次元数(白黒だと 1 カラーだと 3) ) の構造になっている.色の順番は,RGB(赤、緑、青)の順で保存されている. print(type(img)) <class 'numpy.ndarray'> print(img.shape) (縦, 列, 色) print(im.dtype) uint8 Pillow ・入力 img = Image.open(Inputfilename) ・画像の可視化 img.show() ・出力 img.save(Outputfilename) 【データの構造】 画像データを読み込むと,画像オブジェクトとして読み込まれている. print(img) <PIL."ファイル形式"ImagePlugin.BmpImageFile image mode="色情報" size="横"x"縦" at 0xXXXXXXXXXXX> 各ライブラリで読み込んだデータの扱い方 1. Pillow で読み込んだデータを numpy により画像処理を行う Pillow で読み込んだデータはオブジェクト型になっているため,numpy による画像処理を行う場合には,ndarray 型に変更する. imgRGB = np.asarray(img) ※img:Pillow で読み込んだデータ,img2:ndarray 型に変更したデータ(RGB) ここで img2 のデータは,色の順番が RGB の順になっている.そのため,Scikit-image で扱う場合と OpenCV で扱う場合には,この後の処理が少し異なることに注意が必要. 1.1. Scikit-image で扱う場合 Scikit-image で扱う場合には,色の順番が同じであるため,処理は不要. 1.2. OpenCV で扱う場合 OpenCV で扱う場合には,色の順番を変える次の処理が必要になる. imgCV = cv2.cvtColor(imgPIL, cv2.COLOR_RGB2BGR) 2. OpenCV と Sckit-image の連携 OpenCV と Sckit-image では色の保存されている順番が異なるため,お互いのライブラリを扱う際には,色の順番の変換が必要になる. 2.1. OpenCV で読み込んだデータを Sckit-image により画像処理を行う OpenCV で読み込んだデータを Sckit-image で扱う際には,BGR から RGB への変換が必要. imgSK = cv2.cvtColor(imgCV, cv2.COLOR_BGR2RGB) ※imgCV:OpenCV で読み込んだデータ(BGR),imgSK:Sckit-image で読み込んだデータ(RGB) 2.2. Sckit-image で読み込んだデータを OpenCV により画像処理を行う Sckit-image で読み込んだデータを OpenCV で扱う際には,RGB から BGR への変換が必要. imgCV = cv2.cvtColor(imgSK, cv2.COLOR_BGR2RGB) ※imgCV:OpenCV で読み込んだデータ(BGR),imgSK:Sckit-image で読み込んだデータ(RGB)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pythonによる各種画像処理ライブラリを用いた画像データの入出力方法とライブラリ間の連携方法(OpenCV, Scikit-image, Pillow)

概要 Python を用いて画像処理を行う第一歩として,画像処理用の各種ライブラリによるデータの入出力方法と,ライブラリ間の連携方法について記載する. Python ではいくつかの画像処理ライブラリが活用できる.そのため,ひとつのコードの中で複数のライブラリを用いた処理を行う際には,互換性の確認が必要である. ここでは,各ライブラリを用いて実装する際の画像データ構造の扱い方の違いと複数ライブラリをまたいで使用する際の方法について記述する. Python で活用できる画像処理ライブラリの種類と事前準備 ここでは画像処理ライブラリとして,OpenCV, Scikit-image, Pillow について扱う. OpenCV:Open Source Computer Vision Library Intel が開発した画像処理のためのオープンソースライブラリ.C/C++, Java, MATLAB でも公開されており,インターネット上にも OpenCV を用いたサンプルコードが多く見受けられる. 【インストール方法】 コマンドプロンプト上で,OpenCV を pip3 コマンドによりインストールする. pip3 install opencv-python pip3 install opencv-contrib-python ※OpenCV では,画像データを numpy 配列 ndarray で扱うため,numpy モジュールがインストールされていない場合には numpy インストールしておく. pip3 install numpy 【インポート方法】 Python プログラム上で cv2 を import する. import cv2 Scikit-image Python向けの画像処理ライブラリ. 【インストール方法】 コマンドプロンプト上で,Scikit-image を pip3 コマンドによりインストールする. pip3 install scikit-image ※Scikit-image も OpenCV 同様,画像データを numpy 配列 ndarray で扱うため,numpy モジュールがインストールされていない場合には numpy インストールしておく. pip3 install numpy 【インポート方法】 Python プログラム上で skimage を import する. from skimage.io Pillow 2011 年で開発を停止した PIL (Python Image Library) のリポジトリをフォークし,Python3 のサポートを追加した画像処理ライブラリ. 【インストール方法】 コマンドプロンプト上で,Scikit-image を pip3 コマンドによりインストールする. pip3 install Pillow 【インポート方法】 Python プログラム上で PIL を import する. from PIL import Image 各画像処理ライブラリの入出力 OpenCV ・入力 img = cv2.imread(Inputfilename) ※ Inputfilename には画像のあるディレクトリからファイル名を記載するが,日本語を含む path は読み込まないため注意. ・画像の可視化 cv2.imshow('imgCV', img) cv2.waitKey(0) cv2.destroyAllWindows() ・出力 cv2.imwrite(Outputfilename, img) 【データの構造】 画像データを読み込むと,( 行(画像の縦のサイズ), 列(画像の横のサイズ), 色の次元数(白黒だと 1 カラーだと 3) ) の構造になっている.色の順番は,BGR(青、緑、赤)の順で保存されている. print(type(img)) <class 'numpy.ndarray'> print(img.shape) (行, 列, 色) print(im.dtype) uint8 Scikit-image ・入力 img = skimage.io.imread(Inputfilename) ・画像の可視化 io.imshow(img) ・出力 io.imsave(Outputfilename, img) 【データの構造】 画像データを読み込むと,( 画像の縦のサイズ, 画像の横のサイズ, 色の次元数(白黒だと 1 カラーだと 3) ) の構造になっている.色の順番は,RGB(赤、緑、青)の順で保存されている. print(type(img)) <class 'numpy.ndarray'> print(img.shape) (縦, 列, 色) print(im.dtype) uint8 Pillow ・入力 img = Image.open(Inputfilename) ・画像の可視化 img.show() ・出力 img.save(Outputfilename) 【データの構造】 画像データを読み込むと,画像オブジェクトとして読み込まれている. print(img) <PIL."ファイル形式"ImagePlugin."ファイル形式"ImageFile image mode="色情報" size="横"x"縦" at 0xXXXXXXXXXXX> 各ライブラリで読み込んだデータの扱い方 1. Pillow で読み込んだデータを numpy により画像処理を行う Pillow で読み込んだデータはオブジェクト型になっているため,numpy による画像処理を行う場合には,ndarray 型に変更する. imgRGB = np.asarray(img) ※img:Pillow で読み込んだデータ,img2:ndarray 型に変更したデータ(RGB) ここで img2 のデータは,色の順番が RGB の順になっている.そのため,Scikit-image で扱う場合と OpenCV で扱う場合には,この後の処理が少し異なることに注意が必要. 1.1. Scikit-image で扱う場合 Scikit-image で扱う場合には,色の順番が同じであるため,処理は不要. 1.2. OpenCV で扱う場合 OpenCV で扱う場合には,色の順番を変える次の処理が必要になる. imgCV = cv2.cvtColor(imgPIL, cv2.COLOR_RGB2BGR) 2. OpenCV と Sckit-image の連携 OpenCV と Sckit-image では色の保存されている順番が異なるため,お互いのライブラリを扱う際には,色の順番の変換が必要になる. 2.1. OpenCV で読み込んだデータを Sckit-image により画像処理を行う OpenCV で読み込んだデータを Sckit-image で扱う際には,BGR から RGB への変換が必要. imgSK = cv2.cvtColor(imgCV, cv2.COLOR_BGR2RGB) ※imgCV:OpenCV で読み込んだデータ(BGR),imgSK:Sckit-image で読み込んだデータ(RGB) 2.2. Sckit-image で読み込んだデータを OpenCV により画像処理を行う Sckit-image で読み込んだデータを OpenCV で扱う際には,RGB から BGR への変換が必要. imgCV = cv2.cvtColor(imgSK, cv2.COLOR_BGR2RGB) ※imgCV:OpenCV で読み込んだデータ(BGR),imgSK:Sckit-image で読み込んだデータ(RGB)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

備忘録 cpython Unicodeデータの入出力方法

訳あってPython CAPIを使い始めたが、C言語、C++初心者のため悪戦苦闘中。 ただし初心者でもわかるぐらいpython3系のUnicodeAPIは、 とっ散らかっている。おそらく過渡期なんだとCpythonのソースから感じた。 単にUnicodeオブジェクトの読み書きをしたいだけなのだが、 どうもExampleが見当たらない。備忘録として残しておく。 Cへの入力(PyObjectを読込む) python2系 PyObject* o = xxxx; if (PyUnicode_Check(o)) return NULL; Py_UNICODE* u = PyUnicode_AsUnicode(o); // uはC言語で扱えるデータ ここまでは分かりやすかったのだが、3分の2は廃止予定の関数、、 python3系 どんだけ2系と違うんだよ。。 パターン1 きっツ PyObject* o = xxxxx; if (PyUnicode_READY(o) == -1) return NULL; void *data = PyUnicode_DATA(o); int kind = PyUnicode_KIND(o); Py_ssize_t len = PyUnicode_GET_LENGTH(o); Py_UCS4* u = new Py_UCS4[len+1]; // C++ならこうか? // Py_UCS4* u = (Py_UCS4*)calloc((len+1)*sizeof(Py_UCS4)); // Cならこうか? for (Py_ssize_t i = 0; i < len; i++) { u[i] = PyUnicode_READ(kind, data, i); } //メモリ開放忘れるととんでもないことに delete[] u; // free(u); パターン2 ソースを見る限りこういう技もあるようだがやってよいのか? PyObject* o = xxxxx; if (PyUnicode_READY(o) == -1) return NULL; int kind = PyUnicode_KIND(o); void *data = PyUnicode_DATA(o); if (kind == PyUnicode_1BYTE_KIND) Py_UCS1 *s = (Py_UCS1 *)data; elif (kind == PyUnicode_2BYTE_KIND) Py_UCS2 *s = (Py_UCS2 *)data; else Py_UCS4 *s = (Py_UCS4 *)data; Py_UCS4* u = (Py_UCS4 *)s; // uはC言語で扱えるデータ うーん // さらに枝狩りして以下と同じかと PyObject* o = xxxxx; if (PyUnicode_READY(o) == -1) return NULL; void *data = PyUnicode_DATA(o); Py_UCS4* u = (Py_UCS4 *)data; うーん直感的に何やってるのかわからない。 パターン3 これに落ち着いた。 PyObject *orgpy;//<-インプット Py_ssize_t len =PyObject_Length(orgpy); Py_UCS4 u; for (Py_ssize_t i = 0; i < len; i++) { u = PyUnicode_READ_CHAR(orgpy, i); //何か処理 } 迷走の理由 https://docs.python.org/ja/3/c-api/unicode.html この説明だけ見て使える人ってどれだけいるの? 使い方を知りたいだけなのに例がないため、中途半端な説明のおかげで大混乱。 ソースを読み、デバッグしながらでようやく理解できたレベルで腹立たしい。 pyへの出力(PyObjectを書き出す) マルチバイト系の取り扱い方法がまだ全く分かってない。 python2系 const char *ascii = "hoge"; PyObject* o = PyUnicode_FromString(ascii); // oはpythonから見えるオブジェクト const Py_UNICODE *u; //<-マルチバイトだとする Py_ssize_t size = 1; //<- たぶん文字数?未確認 PyObject* o = PyUnicode_FromUnicode(u, size) python3系 uだけあっても書き込めない!? 謎過ぎてあってるのかどうかすらわかない。 PyObject *py; Py_UCS1 *data = PyUnicode_1BYTE_DATA(orgpy); //<-これ1byte大事 int kind = PyUnicode_KIND(orgpy); //<-でもKINDは1とは限らない //kind情報がわかってないといけないということは元となるPyObjectがないとはっきりとわからないのでは? Py_ssize_t len = zz; //あらかじめdataの長さがわかってないといけない。 // uの長さってどうやったら調べられるの? for (Py_ssize_t i = 0; i < len; i++) { py = PyUnicode_FromKindAndData(kind, data + (i * kind), 1); // 何か処理!っていうか1文字単位でしかPyObject作れないんだけど、、 }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む