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

PysimpleGUI 3分クッキング

はじめに Pythonで簡単なGUIアプリを作りたいけどどんなライブラリがあるんだろう、と思って調べた結果 PysimpleGUI という素晴らしいものに出会いました。 レイアウトが直感的でイベント処理も明解。公式のReadMeにある通り、コードを書いてて楽しくなるライブラリです。 公式クックブックがとても充実しているのも魅力なのですが、充実しすぎて全部読むのは躊躇するのと英語版しかないというハードルがあると思われます。 なので、ここでは3分くらいで読める量にまとめてみました。 シンプルなフォーム OKを押すと名前が出力される簡単な入力フォームは、以下のようなコードで実現します。 import PySimpleGUI as sg def main(): window = sg.Window("名前", layout=[ [sg.Text("名前を入力してください。")], [sg.Input("")], [sg.Button("OK"), ] ]) while True: event, values = window.read() if event == sg.WIN_CLOSED: break else: sg.popup(values[0]) if __name__ == '__main__': main() Windowのレイアウト 行ごとに配置する要素を決め、リスト配列で定義します。直感的に組めて分かりやすいです。 window = sg.Window("HogeHoge", layout=[ [sg.Text("以下を入力してください。")], [sg.Text("名前"), sg.Input("")], [sg.Text("メールアドレス"), sg.Input("")], [sg.Button("クリア"), sg.Button("OK")] ]) 画面内にさらに分割したレイアウトを組みたいときは「Frame」を使います frame = sg.Frame("入力", layout=[ [sg.Text("以下を入力してください。"), sg.Button("クリア")], [sg.Text("名前"), sg.Input("")], [sg.Text("メール"), sg.Input("")] ]) window = sg.Window("HogeHoge", layout=[ [sg.Text("登録してください")], [sg.Text("右にフレーム"), frame], # フレームを挿入 [sg.Button("OK")] ]) 後述のイベント管理も使えば、Frameを使って機能ごとにコンポーネントを分割することもできそうです。 盛り込める要素 ボタンやリストボックス、コンボボックス、チェックボックスなど、欲しいものは大体あります。 window = sg.Window("HogeHoge", layout=[ [sg.Input("文字の入力")], [sg.Listbox(["AAA", "BBB", "CCC"], size=(4, 3))], [sg.Combo(["A", "B", "C"])], [sg.Checkbox("チェックボックス")], [sg.Button("OK")] ]) イベントの管理 window.read()は、ウィンドウ内の各要素からイベントが発生するまで待機し、発生時はイベント名(eventで取得)と各要素の保持している値(valuesで取得)を返します。ループ内でwindow.read()を待機させ、発生したイベントに応じた処理を実行し、待機に戻ると言うのが基本になります。 eventには要素を定義する際に key= という引数に渡したものが返され、指定していない場合は0から順番に割り振られた番号になります。 valuesはInput等に入力した値、ListBoxで選択した値などが辞書形式で返されます。辞書のkeyは各要素のkeyとなっています。 window[keyの値]で各要素に直接触れるため、内容の変更を行ったりもできます。 window = sg.Window( "HogeHoge", layout=[ [sg.Text("以下を入力してください。")], # key= でイベント発生時のkeyを指定 [sg.Text("名前"), sg.Input("", key="name")], [sg.Text("メール"), sg.Input("", key="mail")], [sg.Button("クリア", key="clear"), sg.Button("OK", key="ok")] ]) while True: event, values = window.read() print(event, values) # OKボタンを押したとき # ok ,{'name': nameの入力値, 'mail': mailの入力値} # クリアボタンを押したとき: # clear, {'name': nameの入力値, 'mail': mailの入力値} if event == sg.WIN_CLOSED: break elif event == "ok": # ok ボタンを押したとき # ポップアップでインプットの値を表示 message = "name:" + values['name'] + "\nmail:" + values['mail'] sg.popup(message) elif event == 'clear': # クリアボタンを押したとき # 各入力欄を空にする。 window["name"].update("") window["mail"].update("") ボタン要素はクリック時にイベントを発生させますが、多くの要素はクリックだけではイベントを発生させません。enable_events=Trueとしてあげるとイベントが発生するようになります。 if-elifの繰り返しはイマイチ好きじゃない場合はイベントハンドラも設定できます。 KeyとFuncitonを辞書に入れて呼び出すだけですが。 # キーを事前に定義しておく NAME = 'name' OK = 'ok' MAIL = 'mail' CLEAR = 'clear' window = sg.Window( "HogeHoge", layout=[ [sg.Text("以下を入力してください。")], [sg.Text("名前"), sg.Input("", key=NAME)], [sg.Text("メール"), sg.Input("", key=MAIL)], [sg.Button("クリア", key=CLEAR), sg.Button("OK", key=OK)] ]) def clear_input(v): # 引数のとり方を他と同じように設定する window[NAME].update("") window[MAIL].update("") event_handler = { OK: lambda v: sg.popup(f"name:{v[NAME]}\nmail:{v[MAIL]}"), CLEAR: clear_input } while True: event, values = window.read() if event == sg.WIN_CLOSED: # ループをぬける場合は別に用意 break func = event_handler[event] func(values) 辞書形式で定義することで、子のコンポーネントで定義したハンドラーを親のハンドラーに引き渡して管理するということも可能だと思います。 参考 以下の記事を参考にしました。 https://qiita.com/KatsunoriNakamura/items/376da645e52f7ef7f9ef https://qiita.com/dario_okazaki/items/656de21cab5c81cabe59
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pylintオプション一覧_ja

Category Rule Default Description General ignore CVS 対象外にするファイルまたはディレクトリを指定。パスではなくファイル名またはディレクトリ名で指定する。 General ignore-patterns 対象外にするファイルまたはディレクトリのパターン(正規表現)指定。パスでなくファイル名またはディレクトリ名で指定する。 General persistent yes 後から比較するために収集したデータを保存する。 General load-plugins ロードするプラグインのリスト。通常は追加のチェッカーを登録する。 General fail-under 10 プログラムが正常であると判断されるスコアの閾値の設定。 General jobs 1 Pylintを実行するプロセッサ数。0を指定した場合、使用可能なプロセッサの数が自動で検出される。 General unsafe-load-any-extension 任意のC拡張のロードを許可する。拡張はアクティブなPythonインタプリタにインポートされ、任意のコードを実行できる。 General limit-inference-results 100 単一オブジェクトを推測する際の、推測数。これは大きな関数や、複雑でネストされた条件式などを処理する場合のパフォーマンス向上に役立つ。 General extension-pkg-allow-list C拡張をロードできるパッケージ名またはモジュール名のリスト。拡張はアクティブなPythonインタプリタにロードされ、任意のコードを実行できる。 General extension-pkg-whitelist C拡張をロードできるパッケージ名またはモジュール名のリスト。拡張はアクティブなPythonインタプリタにロードされ、任意のコードを実行できる。(extension-pkg-allow-listの下位互換性のための別名。) General suggestion-mode yes 有効のとき、pylintは一般的な設定ミスを推測し、誤検知のエラーメッセージではなく、ユーザーフレンドリーなヒントを出力する。 General exit-zero "静的解析エラーがあった場合でも""0""ステータスコードを返す。主に継続的インテグレーションのスクリプトで役出す。" General from-stdin stdinを、ファイル名をmodule_or_package引数として渡す必要があるpythonスクリプトとして解釈する。 Message control confidence 設定された信頼水準でのみ警告を表示する。すべてを表示するには、空のままにする。有効なレベル:HIGH、INFERENCE、INFERENCE_FAILURE、UNDEFINED。 Message control enable "メッセージ、レポート、カテゴリ、チェッカーをIDによって有効化する。複数指定するためには、"",""(カンマ)区切り、またはenableオプションを複数回使用する。(複数回使用による設定はコマンドラインでのみ。設定ファイルでは1回だけ使用すべき。)" Message control disable "メッセージ、レポート、カテゴリ、チェッカーをIDによって無効化する。複数指定するためには、"",""(カンマ)区切り、またはenableオプションを複数回使用する。(複数回使用による設定はコマンドラインでのみ。設定ファイルでは1回だけ使用すべき。)" Reports output-format text 出力フォーマットを設定する。利用可能なフォーマットはtext、parseable、colorized、json、msvs (visual studio)。レポータークラス(例:mypackage.mymodule.MyReporterClass) を提供することもできる。 Reports reports フルレポートを出力するかメッセージのみを出力するかを指定する。 Reports evaluation 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) "グローバル評価レポート(RP0004)で使用される評価式であり、10以下のスコアを返す必要がある。使用できる変数は、""error""(エラー指摘数)、""warning""(警告指摘数)、""refactor""(リファクタ指摘数)、""convension""(慣例指摘数)、""statement""(分析される文の総数)。" Reports score yes 評価スコアを有効化する。 Reports msg-template "メッセージ表示に使用されるテンプレート。python ""new-style"" format (str.format)で記述する。" Basic good-names "i,j,k,ex,Run,_" "常に受け入れる適切な変数名。"",""(カンマ)区切りで記述する。" Basic good-names-rgxs "適切な変数名の正規表現。"",""(カンマ)区切りで記述する。正規表現にマッチする変数名は受け入れる。" Basic bad-names "foo,bar,baz,toto,tutu,tata" "常に拒否する不適切な変数名。"",""(カンマ)区切りで記述する。" Basic bad-names-rgxs "不適切な変数名の正規表現。"",""(カンマ)区切りで記述する。正規表現にマッチする変数名は拒否する。" Basic name-group "名前(argument, attr, classなど)のグループを"":""(コロン)区切りで指定する。指定されたグループでは、同じ命名スタイルが使用される。" Basic include-naming-hint 無効な名前の警告に適切な名前フォーマットのヒントを含める。 Basic property-classes abc.abstractproperty プロパティを生成するデコレータのリスト。無効なデコレータ名が使用された時に、このリストが使用される。 Basic argument-naming-style snake_case 引数名に適用される命名スタイル。 Basic argument-rgx 引数名に適用される正規表現。argument-naming-styleのオーバーライド。 Basic attr-naming-style snake_case 属性名に適用される命名スタイル。 Basic attr-rgx 属性名に適用される正規表現。attr-naming-styleのオーバーライド。 Basic class-naming-style PascalCase クラス名に適用される命名スタイル。 Basic class-rgx クラス名に適用される正規表現。class-naming-styleのオーバーライド。 Basic class-attribute-naming-style any クラス属性名に適用される命名スタイル。 Basic class-attribute-rgx クラス属性名に適用される正規表現。class-attribute-naming-styleのオーバーライド。 Basic class-const-naming-style UPPER_CASE クラス定数名に適用される命名スタイル。 Basic class-const-rgx クラス定数名に適用される正規表現。class-const-naming-styleのオーバーライド。 Basic const-naming-style UPPER_CASE 定数名に適用される命名スタイル。 Basic const-rgx 定数名に適用される正規表現。const-naming-styleのオーバーライド。 Basic function-naming-style snake_case 関数名に適用される命名スタイル。 Basic function-rgx 関数名に適用される正規表現。function-naming-styleのオーバーライド。 Basic inlinevar-naming-style any ループ変数名に適用される命名スタイル。 Basic inlinevar-rgx ループ変数名に適用される正規表現。inlinevar-naming-styleのオーバーライド。 Basic method-naming-style snake_case メソッド名に適用される命名スタイル。 Basic method-rgx メソッド名に適用される正規表現。method-naming-styleのオーバーライド。 Basic module-naming-style snake_case モジュール名に適用される命名スタイル。 Basic module-rgx モジュール名に適用される正規表現。module-naming-styleのオーバーライド。 Basic variable-naming-style snake_case 変数名に適用される命名スタイル。 Basic variable-rgx 変数名に適用される正規表現。varialbe-naming-styleのオーバーライド。 Basic no-docstring-rgx ^_ docstringを記述しなくてよい関数名またはクラス名の正規表現。 Basic docstring-min-length -1 docstringを書く必要がある関数またはメソッドの行数の最小値。この値より短いものはdocstringを書く必要がない。 Classes defining-attr-methods "init,new,setUp,post_init" インスタンス属性の宣言に使用されるメソッド名のリスト。 Classes valid-classmethod-first-arg cls クラスメソッドにおける第一引数に有効な名前のリスト。 Classes valid-metaclass-classmethod-first-arg cls メタクラスのクラスメソッドにおける第一引数に有効な名前のリスト。 Classes exclude-protected "_asdict,_fields,_replace,_source,_make" protectedアクセス警告から除外するメンバ名のリスト。 Classes check-protected-access-in-special-methods 特殊メソッド内のprotected属性アクセスについての警告。 Design max-args 5 関数/メソッドの引数の最大数。 Design max-locals 15 関数/メソッド内のlocals()の最大数。 Design max-returns 6 関数/メソッド内のreturn/yieldの最大数。 Design max-branches 12 関数/メソッド内の分岐の最大数。 Design max-statements 50 関数/メソッド内の文の最大数。 Design max-parents 7 1クラスにおける親クラスの最大数。(R0901参照) Design max-attributes 7 1クラスおける属性の最大数。(R0902参照) Design min-public-methods 2 1クラスにおけるpublicメソッドの最小数。(R0903参照) Design max-public-methods 0 1クラスにおけるpublicメソッドの最大数。(R0904参照) Design max-bool-expr 5 if文におけるboolean式の最大数。(R0916参照) Exceptions overgeneral-exceptions "BaseException,Exception" cacheされたときに警告を出す例外。 Format max-line-length 100 1行の文字数の最大値。 Format ignore-long-lines ^\s*(# )?<?https?://\S+>?$ 1行の文字数の最大値を超えてもよい行の正規表現。 Format single-line-if-stmt else文がない時に、if文の中身を同じ行に記述することを許可する。 Format single-line-class-stmt クラスの中身が1行のとき、クラスの中身を宣言と同じ行に記述することを許可する。 Format max-module-lines 1000 モジュール内の行数の最大値。 Format indent-string ' ' "インデントとして扱う文字列。通常は、"" ""(4スペース)または""t""(1タブ)。" Format indent-after-paren 4 ぶら下がり文や継続行(文の複数行記述)に必要なインデントのスペース数。 Format expected-line-ending-format 改行コード。(例: empty(任意)、LF、CRLF) Imports deprecated-modules "optparse,tkinter.tix" "非推奨モジュール。"",""(カンマ)区切りで設定する。" Imports preferred-modules "モジュールと優先モジュールの組み。"",""(カンマ)区切りで設定する。" Imports import-graph 依存関係のグラフを指定されたファイルに出力する。(レポートRP0402を無効にしてはいけない。) Imports ext-import-graph 外部依存関係のグラフを指定されたファイルに出力する。(レポートR0402を無効にしてはいけない。) Imports int-import-graph 内部依存関係のグラフを指定されたファイルに出力する。(レポートRP0402を無効にしてはいけない。) Imports known-standard-library import記述順序において、指定したモジュールを標準ライブラリの部分に強制する。 Imports known-third-party enchant import記述順序において、指定したモジュールをサードパーティライブラリの部分に強制する。 Imports allow-any-import-level 任意のレベルにおいてインポート可能なモジュールのリスト。 Imports analyse-fallback-blocks "importのfallbackブロックを分析する。これはPython2, 3互換のコードをサポートするために使用される。Python2, 3互換のコードでは、Python2, 3どちらかのインターセプタにのみ存在するコードが存在し、それは分析時に偽陽性を招くためである。" Imports allow-wildcard-with-all allを定義するモジュールからのワイルドカードのインポートを許可する。 Logging logging-modules logging 文字列フォーマットの引数がロギング関数のパラメータフォーマットであることをチェックするためのロギングモジュール。 Logging logging-format-style old "ロギングメソッドのフォーマットスタイル。""old""の場合は%フォーマット。""new""の場合は、{}フォーマット。" Miscellaneous notes "FIXME,XXX,TODO" "警告に表示される注釈タグのリスト。 "",""(カンマ)区切りで設定する。" Miscellaneous notes-rgx 警告に表示される注釈タグの正規表現。 Refactoring max-nested-blocks 5 関数/メソッドのネストの深さの最大値。 Refactoring never-returning-functions "sys.exit,argparse.parse_error" "リターンしない関数の完全修飾名。ルール""inconsistent-return-statements""(R1710)をチェックする際、このリターンしない関数が呼び出された時にそれ自体が明示的なリターン文とみなされ、メッセージは出力されない。" Similarities min-similarity-lines 4 類似コード計算対象となるコードの行数の最小値。 Similarities ignore-comments yes 類似度計算においてコメントを無視する。 Similarities ignore-docstrings yes 類似度計算においてdocstringsを無視する。 Similarities ignore-imports 類似度計算においてインポートを無視する。 Spelling spelling-dict スペリング辞書名。利用可能な辞書:なし。利用するためには、python-enchantパッケージをインストールする必要がある。 Spelling spelling-ignore-words "スペルチェックしない単語のリスト。"",""(カンマ)区切りで設定する。" Spelling spelling-private-dict-file プライベート辞書を含むファイルへのパス。1行に1単語。 Spelling spelling-store-unknown-words メッセージを生成する代わりに、不明な単語をプライベート辞書(spelling-private-dict-fileオプション参照)に登録するかどうかを指定する。 Spelling max-spelling-suggestions 4 スペリングミスを示唆する数の上限。 Spelling spelling-ignore-comment-directives "fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy:" ディレクティブとみなす単語のリスト。コメントの先頭に現れた時にチェックされない。 String check-str-concat-over-line-jumps "複数行にまたがって定義された暗黙的な文字列連結に対して、""implicit-str-concat""が警告を生成するか否かを制御するフラグ。" String check-quote-consistency "区切り文字がモジュール内で一貫して使用されていない場合に、""inconsistent-quotes""が警告を生成するか否かを制御するフラグ。" Variables init-import initファイル内で使用されていないインポートをチェックするか否かを設定する。 Variables dummy-variables-rgx _+$ ([a-zA-Z0-9]*[a-zA-Z0-9]+?$) Variables additional-builtins 組み込み関数で定義されることになっている追加の名前のリスト。有効にする場合は、新しいビルトインを定義することは避ける必要がある。 Variables callbacks "cb_,_cb" コールバック関数を識別する文字列。指定された文字列で開始または終了する関数をコールバック関数とみなす。 Variables redefining-builtins-modules "six.moves,past.builtins,future.builtins,builtins,io" 組み込みを再定義できるオブジェクトを持つモジュールの修飾名のリスト。 Variables ignored-argument-names _.* ^ignored_ Variables allow-global-unused-variables yes 使用されていないグローバル変数を違反として扱うか否かの設定。 Variables allowed-redefined-builtins 組み込みの名前との被りを許可する名前のリスト。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pylintオプション一覧

Catecory Rule Default Description General ignore CVS Files or directories to be skipped. They should be base names, not paths. General ignore-patterns Files or directories matching the regex patterns are skipped. The regex matches against base names, not paths. General persistent yes Pickle collected data for later comparisons. General load-plugins List of plugins (as comma separated values of python module names) to load, usually to register additional checkers. General fail-under 10 Specify a score threshold to be exceeded before program exits with error. General jobs 1 Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the number of processors available to use. General unsafe-load-any-extension Allow loading of arbitrary C extensions. Extensions are imported into the active Python interpreter and may run arbitrary code. General limit-inference-results 100 Control the amount of potential inferred values when inferring a single object. This can help the performance when dealing with large functions or complex, nested conditions. General extension-pkg-allow-list A comma-separated list of package or module names from where C extensions may be loaded. Extensions are loading into the active Python interpreter and may run arbitrary code. General extension-pkg-whitelist A comma-separated list of package or module names from where C extensions may be loaded. Extensions are loading into the active Python interpreter and may run arbitrary code. (This is an alternative name to extension-pkg-allow-list for backward compatibility.) General suggestion-mode yes When enabled, pylint would attempt to guess common misconfiguration and emit user-friendly hints instead of false-positive error messages. General exit-zero Always return a 0 (non-error) status code, even if lint errors are found. This is primarily useful in continuous integration scripts. General from-stdin Interpret the stdin as a python script, whose filename needs to be passed as the module_or_package argument. Message control confidence Only show warnings with the listed confidence levels. Leave empty to show all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED. Message control enable Enable the message, report, category or checker with the given id(s). You can either give multiple identifier separated by comma (,) or put this option multiple time (only on the command line, not in the configuration file where it should appear only once). See also the "--disable" option for examples. Message control disable Disable the message, report, category or checker with the given id(s). You can either give multiple identifiers separated by comma (,) or put this option multiple times (only on the command line, not in the configuration file where it should appear only once). You can also use "--disable=all" to disable everything first and then reenable specific checks. For example, if you want to run only the similarities checker, you can use "--disable=all --enable=similarities". If you want to run only the classes checker, but have no Warning level messages displayed, use "--disable=all --enable=classes --disable=W". Reports output-format text Set the output format. Available formats are text, parseable, colorized, json and msvs (visual studio). You can also give a reporter class, e.g. mypackage.mymodule.MyReporterClass. Reports reports Tells whether to display a full report or only the messages. Reports evaluation 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) Python expression which should return a score less than or equal to 10. You have access to the variables 'error', 'warning', 'refactor', and 'convention' which contain the number of messages in each category, as well as 'statement' which is the total number of statements analyzed. This score is used by the global evaluation report (RP0004). Reports score yes Activate the evaluation score. Reports msg-template Template used to display messages. This is a python new-style format string used to format the message information. See doc for all details. Basic good-names i,j,k,ex,Run,_ Good variable names which should always be accepted, separated by a comma. Basic good-names-rgxs Good variable names regexes, separated by a comma. If names match any regex, they will always be accepted Basic bad-names foo,bar,baz,toto,tutu,tata Bad variable names which should always be refused, separated by a comma. Basic bad-names-rgxs Bad variable names regexes, separated by a comma. If names match any regex, they will always be refuse Basic name-group Colon-delimited sets of names that determine each other's naming style when the name regexes allow several styles. Basic include-naming-hint Include a hint for the correct naming format with invalid-name. Basic property-classes abc.abstractproperty List of decorators that produce properties, such as abc.abstractproperty. Add to this list to register other decorators that produce valid properties. These decorators are taken in consideration only for invalid-name. Basic argument-naming-style snake_case Naming style matching correct argument names. Basic argument-rgx Regular expression matching correct argument names. Overrides argument- naming-style. Basic attr-naming-style snake_case Naming style matching correct attribute names. Basic attr-rgx Regular expression matching correct attribute names. Overrides attr-naming- style. Basic class-naming-style PascalCase Naming style matching correct class names. Basic class-rgx Regular expression matching correct class names. Overrides class-naming- style. Basic class-attribute-naming-style any Naming style matching correct class attribute names. Basic class-attribute-rgx Regular expression matching correct class attribute names. Overrides class- attribute-naming-style. Basic class-const-naming-style UPPER_CASE Naming style matching correct class constant names. Basic class-const-rgx Regular expression matching correct class constant names. Overrides class- const-naming-style. Basic const-naming-style UPPER_CASE Naming style matching correct constant names. Basic const-rgx Regular expression matching correct constant names. Overrides const-naming- style. Basic function-naming-style snake_case Naming style matching correct function names. Basic function-rgx Regular expression matching correct function names. Overrides function- naming-style. Basic inlinevar-naming-style any Naming style matching correct inline iteration names. Basic inlinevar-rgx Regular expression matching correct inline iteration names. Overrides inlinevar-naming-style. Basic method-naming-style snake_case Naming style matching correct method names. Basic method-rgx Regular expression matching correct method names. Overrides method-naming- style. Basic module-naming-style snake_case Naming style matching correct module names. Basic module-rgx Regular expression matching correct module names. Overrides module-naming- style. Basic variable-naming-style snake_case Naming style matching correct variable names. Basic variable-rgx Regular expression matching correct variable names. Overrides variable- naming-style. Basic no-docstring-rgx ^_ Regular expression which should only match function or class names that do not require a docstring. Basic docstring-min-length -1 Minimum line length for functions/classes that require docstrings, shorter ones are exempt. Classes defining-attr-methods init,new,setUp,post_init List of method names used to declare (i.e. assign) instance attributes. Classes valid-classmethod-first-arg cls List of valid names for the first argument in a class method. Classes valid-metaclass-classmethod-first-arg cls List of valid names for the first argument in a metaclass class method. Classes exclude-protected _asdict,_fields,_replace,_source,_make List of member names, which should be excluded from the protected access warning. Classes check-protected-access-in-special-methods Warn about protected attribute access inside special methods Design max-args 5 Maximum number of arguments for function / method. Design max-locals 15 Maximum number of locals for function / method body. Design max-returns 6 Maximum number of return / yield for function / method body. Design max-branches 12 Maximum number of branch for function / method body Design max-statements 50 Maximum number of statements in function / method body. Design max-parents 7 Maximum number of parents for a class (see R0901). Design max-attributes 7 Maximum number of attributes for a class (see R0902). Design min-public-methods 2 Minimum number of public methods for a class (see R0903). Design max-public-methods 0 Maximum number of public methods for a class (see R0904). Design max-bool-expr 5 Maximum number of boolean expressions in an if statement (see R0916). Exceptions overgeneral-exceptions BaseException,Exception Exceptions that will emit a warning when being caught. Defaults to "BaseException, Exception". Format max-line-length 100 Maximum number of characters on a single line. Format ignore-long-lines ^\s*(# )?<?https?://\S+>?$ Regexp for a line that is allowed to be longer than the limit. Format single-line-if-stmt Allow the body of an if to be on the same line as the test if there is no else. Format single-line-class-stmt Allow the body of a class to be on the same line as the declaration if body contains single statement. Format max-module-lines 1000 Maximum number of lines in a module. Format indent-string ' ' String used as indentation unit. This is usually " " (4 spaces) or "t" (1 tab). Format indent-after-paren 4 Number of spaces of indent required inside a hanging or continued line. Format expected-line-ending-format Expected format of line ending, e.g. empty (any line ending), LF or CRLF. Imports deprecated-modules optparse,tkinter.tix Deprecated modules which should not be used, separated by a comma. Imports preferred-modules Couples of modules and preferred modules, separated by a comma. Imports import-graph Output a graph (.gv or any supported image format) of all (i.e. internal and external) dependencies to the given file (report RP0402 must not be disabled). Imports ext-import-graph Output a graph (.gv or any supported image format) of external dependencies to the given file (report RP0402 must not be disabled). Imports int-import-graph Output a graph (.gv or any supported image format) of internal dependencies to the given file (report RP0402 must not be disabled). Imports known-standard-library Force import order to recognize a module as part of the standard compatibility libraries. Imports known-third-party enchant Force import order to recognize a module as part of a third party library. Imports allow-any-import-level List of modules that can be imported at any level, not just the top level one. Imports analyse-fallback-blocks Analyse import fallback blocks. This can be used to support both Python 2 and 3 compatible code, which means that the block might have code that exists only in one or another interpreter, leading to false positives when analysed. Imports allow-wildcard-with-all Allow wildcard imports from modules that define all. Logging logging-modules logging Logging modules to check that the string format arguments are in logging function parameter format. Logging logging-format-style old The type of string formatting that logging methods do. old means using % formatting, new is for {} formatting. Miscellaneous notes FIXME,XXX,TODO List of note tags to take in consideration, separated by a comma. Miscellaneous notes-rgx Regular expression of note tags to take in consideration. Refactoring max-nested-blocks 5 Maximum number of nested blocks for function / method body Refactoring never-returning-functions sys.exit,argparse.parse_error Complete name of functions that never returns. When checking for inconsistent-return-statements if a never returning function is called then it will be considered as an explicit return statement and no message will be printed. Similarities min-similarity-lines 4 Minimum lines number of a similarity. Similarities ignore-comments yes Ignore comments when computing similarities. Similarities ignore-docstrings yes Ignore docstrings when computing similarities. Similarities ignore-imports Ignore imports when computing similarities. Spelling spelling-dict Spelling dictionary name. Available dictionaries: none. To make it work, install the 'python-enchant' package. Spelling spelling-ignore-words List of comma separated words that should not be checked. Spelling spelling-private-dict-file A path to a file that contains the private dictionary; one word per line. Spelling spelling-store-unknown-words Tells whether to store unknown words to the private dictionary (see the --spelling-private-dict-file option) instead of raising a message. Spelling max-spelling-suggestions 4 Limits count of emitted suggestions for spelling mistakes. Spelling spelling-ignore-comment-directives fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy: List of comma separated words that should be considered directives if they appear and the beginning of a comment and should not be checked. String check-str-concat-over-line-jumps This flag controls whether the implicit-str-concat should generate a warning on implicit string concatenation in sequences defined over several lines. String check-quote-consistency This flag controls whether inconsistent-quotes generates a warning when the character used as a quote delimiter is used inconsistently within a module. Variables init-import Tells whether we should check for unused import in init files. Variables dummy-variables-rgx _+$ ([a-zA-Z0-9]*[a-zA-Z0-9]+?$) Variables additional-builtins List of additional names supposed to be defined in builtins. Remember that you should avoid defining new builtins when possible. Variables callbacks cb_,_cb List of strings which can identify a callback function by name. A callback name must start or end with one of those strings. Variables redefining-builtins-modules six.moves,past.builtins,future.builtins,builtins,io List of qualified module names which can have objects that can redefine builtins. Variables ignored-argument-names _.* ^ignored_ Variables allow-global-unused-variables yes Tells whether unused global variables should be treated as a violation. Variables allowed-redefined-builtins List of names allowed to shadow builtins
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

学習の振り返り

はじめに 自己紹介:30代会社員 受講に至った経緯:AIに興味があったから アイデミーでの学習振り返り ・Python入門 ・Numpy ・Pandas ・Matplotlib ・データクレンジング ・機械学習概論 ・教師あり学習(回帰、分類) ・教師なし学習 ・自然言語処理 ・ディープラーニング基礎 ・ネガポジ分析 概要 目的は、ツイートを受け取って、そのツイートを「極めてネガティブ」、「ネガティブ」、「ニュートラル」、「ポジティブ」、「極めてポジティブ」のいずれかのセンチメントに分類する分類器を作成することです。 このKaggleデータセットを学習データとして使用すると、40,000以上のラベル付きCovid-19ベースのツイートが得られます。これを学習データとして使用し、フィードフォワードベースのニューラルネットワークを学習することができます。 プロセス 1)クリーンツイート 2)ユニークな単語辞書を作成する 3)トレーニングツイートを数値配列(機能)に変換 4)トレーニングデータセットのバランスをとる 5)ニューラルネットワークモデルを作成してトレーニングする 6)ニューラルネットワークモデルの使用 使用するコード NLTKのデータをダウンロードする必要があります。 import nltk nltk.download() 1) クリーンツイート機能 このプロセスの最初のステップは、ツイートをクリーニングする関数を作成することです。 from nltk.corpus import stopwords from nltk.stem import WordNetLemmatizer stop_words = set(stopwords.words('english')) tTokenizer = TweetTokenizer() lemmatizer = WordNetLemmatizer() def process_tweets(tweet): tweet_words = tTokenizer.tokenize(tweet) cleaned_tweet_words = [] for word in tweet_words: if 'https' in word or '#' in word or word in stop_words: pass else: punctuation_cleaned = word.translate(str.maketrans('', '', string.punctuation)).lower() lemmatized_word = lemmatizer.lemmatize(word) cleaned_tweet_words.append(lemmatized_word) return cleaned_tweet_words この関数は、各ツイートについて、「意味」を含む単語のリストを返します。 2) 固有語辞書の作成 for tweet, sentiment in tqdm(uncleaned_data): for word in process_tweets(tweet): all_words.append(word) all_words_counted = Counter(all_words) final_lexicon = [] LEXICON_MAX_WORDS = 1000 LEXICON_MIN_WORDS = 50 for word in all_words_counted: if LEXICON_MAX_WORDS > all_words_counted[word] > LEXICON_MIN_WORDS: final_lexicon.append(word) 3)学習用ツイートを数値配列(特徴量)に変換する 辞書を使って、各ツイートをNumPyの配列に変換します。 import numpy as np sentiment_index = {'Extremely Negative': 0, 'Negative': 1, 'Neutral': 2, 'Positive': 3, 'Extremely Positive': 4} def create_features_and_labels(uncleaned_data, final_lexicon): lexicon_len = len(final_lexicon) full_tweet_features = [] for tweet, sentiment in tqdm(uncleaned_data): tweet_array = np.zeros(lexicon_len) processed_tweet_words = process_tweets(tweet) if len(processed_tweet_words) >= 4: for word in process_tweets(tweet): if word.lower() in final_lexicon: np.put(tweet_array, final_lexicon.index(word.lower()), 1) full_tweet_features.append([tweet_array, sentiment_index[sentiment]]) x_train = [tweet_array for tweet_array, sentiment in full_tweet_features] y_train = [sentiment for tweet_array, sentiment in full_tweet_features] return x_train, y_train 4) トレーニングデータセットのバランス調整 トレーニングセットでは、各センティメントのサンプル数が同じになるようにする必要があります。 sentiment_lengths = Counter(y_train) lowest_sentiment = min(sentiment_lengths, key=sentiment_lengths.get) balanced_data = [] for sentiment in sentiment_index: setiment_count = 0 for indx, row in enumerate(y_train): if row == sentiment_index[sentiment]: balanced_data.append([x_train[indx], np.array(row)]) setiment_count += 1 if setiment_count >= sentiment_lengths[lowest_sentiment]: break random.shuffle(balanced_data) x_train = [tweet_array for tweet_array, sentiment in balanced_data] y_train = [sentiment for tweet_array, sentiment in balanced_data] NumPyファイルに保存することにより、ツイートを処理する時間が短縮されます。 np.save('x_training.npy', x_train) np.save('y_training.npy', y_train) np.save('final_lexicon.npy', final_lexicon) 5) ニューラルネットワークモデルの作成と学習 学習データが得られたので、シンプルなフィードフォワードのディープニューラルネットワークを使って分類器を作成します。 import tensorflow.keras as keras import tensorflow as tf import numpy as np x_train = np.load('x_training.npy', allow_pickle=True) y_train = np.load('y_training.npy', allow_pickle=True) また、x_trainセットの形状を変更して、ニューラルネットワークに適した形式にする必要があります。 x_train = x_train.reshape(len(x_train), len(x_train[0]), 1) model = tf.keras.models.Sequential() model.add(tf.keras.layers.Flatten()) model.add(tf.keras.layers.Dense(500, activation=tf.nn.relu)) model.add(tf.keras.layers.Dense(1000, activation=tf.nn.relu)) model.add(tf.keras.layers.Dense(500, activation=tf.nn.relu)) 最後のレイヤーは出力レイヤーになります。ここでは、5つのノードを持つ別の密なレイヤーを使用しています(5つの出力があるため)。 model.add(tf.keras.layers.Dense(5, activation=tf.nn.softmax)) モデルをコンパイルするために、「adam」オプティマイザー、損失関数のスパースカテゴリ相関、および10エポックを使用します。 エポックは、ネットワークがデータを実行する回数です。10エポックは、データセットを10回通過することを意味します。そのたびに、各ニューロンへの各入力の重みを調整し、損失を減らします(これにより精度が向上します)。 model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']) model.fit(x_train, y_train, epochs=10) ... Epoch 7/10 856/856 [==============================] - 4s 4ms/step - loss: 0.0780 - accuracy: 0.9755 Epoch 8/10 856/856 [==============================] - 3s 4ms/step - loss: 0.0627 - accuracy: 0.9795 Epoch 9/10 856/856 [==============================] - 3s 4ms/step - loss: 0.0568 - accuracy: 0.9815 Epoch 10/10 856/856 [==============================] - 3s 4ms/step - loss: 0.0671 - accuracy: 0.9774 最後に、モデルを保存して、使用できるようにします。 model.save('covid19_tweet_classifer.model') 6)ニューラルネットワークでツイートを分類する トレーニング済みのモデルを使用すると、ツイートを渡すことができ、感情が出力されます。 import csv import numpy as np with open('Corona_NLP_test.csv', newline='') as f: reader = csv.reader(f) uncleaned_test_data = list(reader)[1:] final_lexicon = list(np.load('final_lexicon.npy', allow_pickle=True)) model = tf.keras.models.load_model('covid19_tweet_classifer.model') x_test, testing_tweets = create_features_and_labels(uncleaned_test_data, final_lexicon) x_test = x_test.reshape(len(x_test), len(x_test[0]), 1) predictions = model.predict(x_test) for indx, prediction in enumerate(predictions[:10]): print(f"Original Tweet: {testing_tweets[indx][1]}") print(f"Actual Sentiment: {testing_tweets[indx][0]}") print(f"Predicted Sentiment: {sentiment_index[np.argmax(prediction)]}, \n") Original Tweet: "Find out how you can protect yourself and loved ones from #coronavirus?" Actual Sentiment: Extremely Positive Predicted Sentiment: Extremely Positive Original Tweet: "Do you remember the last time you paid $2.99 a gallon for regular gas in Los Angeles? Prices at the pump are going down. A look at how the #coronavirus is impacting prices." Actual Sentiment: Neutral Predicted Sentiment: Positive Original Tweet: "HI TWITTER! I am a pharmacist. I sell hand sanitizer for a living! Or I do when any exists. Like masks, it is sold the fuck out everywhere. SHOULD YOU BE WORRIED? No. Use soap. SHOULD YOU VISIT TWENTY PHARMACIES LOOKING FOR THE LAST BOTTLE? No. Pharmacies are full of sick people." Actual Sentiment: Extremely Negative Predicted Sentiment: Extremely Negative 5つの感情の出力例は、次のようになります。 [0.08312576 0.01809235 0.89360434 0.00205717 0.00312047] 今後の活用 仕事に活かしたい。 おわりに 機会があればその他のコースに挑戦したい。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CircleCI上でFlaskの疎通確認する方法

目的 タイトル通り CI上のコンテナでflask実行環境を作成し、curlコマンドを実行、疎通が取れること。 失敗例 config.yml # flaskの実行環境整備など(省略) - run: command: python server/app.py # background: trueにしないと次のstepに進まない。 background: true - run: curl http://127.0.0.1:5000/ 結果(失敗) 成功例 config.yml - run: command: python server/app.py background: true - run: sleep 10 - run: curl http://127.0.0.1:5000/ 結果(成功) 原因 Build was canceledが原因。 ただし、このメッセージで調べても有用な情報が見つからない(エラーの範囲が広すぎるので) 失敗例ではflaskのサーバーが立ち上がる前に次のコマンドが実施されているように見えたので、 遅延してみたところうまくいった。 本当のところの原因は不明だがとりあえず最低限動いたのでOK(滅茶苦茶ハマった) (これは実行回数が多いことで筆者の頭と同様におかしくなってしまったCIrcleCI)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ubuntu 20.10, 21.04にJupyter Notebookをインストールする(RとPower ShellやC#なども併せて)

(執筆 2021/5/9)  Jupyter Notebookを使うなら、UbuntuでもAnacondaでサクッと環境構築で楽したい。 Anacondaをインストール  https://www.anaconda.com へ行き、上部の Product にマウスカーソルを合わせると出てくるメニューから、Individual Edition Open Source Distribution を選択します。  Download をクリックすると、Anaconda Installersの選択ができますので、Linux 64-bit(x86) Installerを選択してダウンロードします。  ダウンロードされたファイルは、Anaconda3-2020.11-Linux-x86_64.sh のようになっているので、bashで実行します。(2020.11の部分は、適宜変わると思います) bash Anaconda3-2020.11-Linux-x86_64.sh  Enterを押せと出てくるので、Enterすると、ライセンス事項が表示されます。 スペースキーでページをめくっていくと、最後、ライセンス事項を承諾するか聞いてくるので、yesと入力してEnterを押します。(そのままEnterを押すと、再度yesかnoか聞いてきます)  最後、インストール場所を聞いてくるので、そのまま自分のホームディレクトリの下の anaconda3 でいいかと思います。  最後、yesと入力して終了させます。一度、terminalを閉じ、terminalを開き直すと、プロンプトの頭に (base) という文字が追加されます、自動的にconda環境が有効にされてしまう設定になるので、これが気持ち悪い場合は、 conda config --set auto_activate_base false  と入力することで、自動的に有効にならなくなります。逆に、自動的に有効にする設定は、 conda config --set auto_activate_base true  です。手動でcoda環境を有効にしたい場合は、 conda activate  無効にしたい場合は、 conda deactivate  と入力します。アップデートや、インストールなどのcondaで始まるコマンドは、仮想環境が有効になってる必要はありませんが、Jupyter Notebookを立ち上げるときは、有効にしておく必要があります。  pathは、.bashrcに追加されていますので、今のterminalを閉じて、再度terminalを開きなおせば、以下のコマンドでインストールが確認できます。 conda -V  最新バージョンにするために、以下のコマンドを入力します。 conda update conda  再度、conda -V でバージョンを確認すると、バージョンが上がっています。 Jupyter Notebook拡張機能のインストール  既に、Jupyter Notebookも使えるようになっているので、conda環境が有効になってる状態でterminalに以下のコマンドを入力して起動できます。 jupyter notebook  このままでも使えるのですが、便拡張機能をインストールしておきます。 conda install -c conda-forge jupyter_contrib_NbExtensions  これで、nbextensions他がインストールされるので、Jupyter Notebookを立ち上げてdisable何とかのチェックを外して、各拡張機能をenableしていきます。  個々の拡張機能は、@simonritchieさんの「[作業効率化] Jupyterの拡張機能を全部調べてみた」を参照してください。また、おすすめは、書川(カキカワ)さんの「【Python | Jupyter Notebook】Nbextensionsをインストールする方法!導入するべきオススメの拡張機能の5選【業務効率化】」を参照してください。 RとRStudioのインストール  condaからRやRStudioのインストールもできますが、公式からインストールします。  https://cran.r-project.org/ から、Download R for Linux -> ubuntu と進んでいくと、インストール方法が記載されたページにたどり着きます。以下のコマンドを1つずつ実行します。 sudo apt update -qq sudo apt install --no-install-recommends software-properties-common dirmngr sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E298A3A825C0D65DFD57CBB651716619E084DAB9 sudo add-apt-repository "deb https://cloud.r-project.org/bin/linux/ubuntu $(lsb_release -cs)-cran40/"  ここで追加したレポジトリは、ubuntu 20.10では問題ないのですが、21.04の場合はエラーが出てしまいます。21.04の場合は、 /etc/apt/source.list.d/archive_url-http_cloud_r-project_org_bin_linux_ubuntu-hirsute.listを開き、修正します。  Ubuntu 21.04の場合は、まだ21.04 hirsuteのreleaseレポジトリがないので、20.10のgroovyに書き換えます。そのうち、できると思いますので、元のはコメントアウトして残しておいた方がいいと思います。 ubuntu21.04 #deb https://cloud.r-project.org/bin/linux/ubuntu hirsute-cran40/ deb https://cloud.r-project.org/bin/linux/ubuntu groovy-cran40/  そのあと、update&upgradeをかけて、r-baseをインストールします。 sudo apt update sudo apt upgrade -y sudo apt install --no-install-recommends -y r-base  RStudioは、 https://www.rstudio.com/products/rstudio/download/#download からUbuntu 18用のdebファイルをダウンロードして、gdebiでインストールします。 sudo apt install gdebi sudo gdebi rstudio-1.4.1106-amd64.deb  rstudioの数字部分は、適宜変更しましょう。これで、RStudioはrstudioコマンドで起動できます。 Jupyter Notebook へ R を登録  コマンドプロンプトでconda環境を有効にした上で、Rを起動し、以下のコマンドを1行ずつ入れます。 install.packages('IRkernel') IRkernel::installspec()  これで、Jupyter NotebookでRを使うことができます。  もし、jupyter-clientがインストールされていないとエラーが出る場合は、conda環境が有効になっていないためと思われます。ctrl+zでいったん終了して、conda activateとした後で、Rを起動してIRkernel::installspec()を実行してみてください。 Power Shellの登録  https://docs.microsoft.com/ja-jp/dotnet/core/install/linux-ubuntu#2010- を見ながら、.NET 5.0 SDKをインストールします。 # 20.10 wget https://packages.microsoft.com/config/ubuntu/20.10/packages-microsoft-prod.deb -O packages-microsoft-prod.deb sudo dpkg -i packages-microsoft-prod.deb # SDK sudo apt-get update; \ sudo apt-get install -y apt-transport-https && \ sudo apt-get update && \ sudo apt-get install -y dotnet-sdk-5.0  次に、dotnet-interactive をインストールして、jupyter notebookに登録します。コマンドプロンプトから、以下のコマンドを入れます。 dotnet tool install --global Microsoft.dotnet-interactive  次のコマンドは、そのまま実行するとコマンドが見つからないと出てきますので、一度、ログアウトして再ログインしてから実行します。 dotnet interactive jupyter install  これで、UbuntuでもPower Shellが実行できるようになりました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ubuntu 20.10にJupyter Notebookをインストールする(RとPower ShellやC#なども併せて)

(執筆 2021/5/9)  Jupyter Notebookを使うなら、UbuntuでもAnacondaでサクッと環境構築で楽したい。 Anacondaをインストール  https://www.anaconda.com へ行き、上部の Product にマウスカーソルを合わせると出てくるメニューから、Individual Edition Open Source Distribution を選択します。  Download をクリックすると、Anaconda Installersの選択ができますので、Linux 64-bit(x86) Installerを選択してダウンロードします。  ダウンロードされたファイルは、Anaconda3-2020.11-Linux-x86_64.sh のようになっているので、bashで実行します。(2020.11の部分は、適宜変わると思います) bash Anaconda3-2020.11-Linux-x86_64.sh  Enterを押せと出てくるので、Enterすると、ライセンス事項が表示されます。 スペースキーでページをめくっていくと、最後、ライセンス事項を承諾するか聞いてくるので、yesと入力してEnterを押します。(そのままEnterを押すと、再度yesかnoか聞いてきます)  最後、インストール場所を聞いてくるので、そのまま自分のホームディレクトリの下の anaconda3 でいいかと思います。  最後、yesと入力して終了させます。一度、terminalを閉じ、terminalを開き直すと、プロンプトの頭に (base) という文字が追加されます、自動的にconda環境が有効にされてしまう設定になるので、これが気持ち悪い場合は、 conda config --set auto_activate_base false  と入力することで、自動的に有効にならなくなります。逆に、自動的に有効にする設定は、 conda config --set auto_activate_base true  です。手動でcoda環境を有効にしたい場合は、 conda activate  無効にしたい場合は、 conda deactivate  と入力します。アップデートや、インストールなどのcondaで始まるコマンドは、仮想環境が有効になってる必要はありませんが、Jupyter Notebookを立ち上げるときは、有効にしておく必要があります。  pathは、.bashrcに追加されていますので、今のterminalを閉じて、再度terminalを開きなおせば、以下のコマンドでインストールが確認できます。 conda -V  最新バージョンにするために、以下のコマンドを入力します。 conda update conda  再度、conda -V でバージョンを確認すると、バージョンが上がっています。 Jupyter Notebook拡張機能のインストール  既に、Jupyter Notebookも使えるようになっているので、conda環境が有効になってる状態でterminalに以下のコマンドを入力して起動できます。 jupyter notebook  このままでも使えるのですが、便拡張機能をインストールしておきます。 conda install -c conda-forge jupyter_contrib_NbExtensions  これで、nbextensions他がインストールされるので、Jupyter Notebookを立ち上げてdisable何とかのチェックを外して、各拡張機能をenableしていきます。  個々の拡張機能は、@simonritchieさんの「[作業効率化] Jupyterの拡張機能を全部調べてみた」を参照してください。また、おすすめは、書川(カキカワ)さんの「【Python | Jupyter Notebook】Nbextensionsをインストールする方法!導入するべきオススメの拡張機能の5選【業務効率化】」を参照してください。 RとRStudioのインストール  condaからRやRStudioのインストールもできますが、公式からインストールします。  https://cran.r-project.org/ から、Download R for Linux -> ubuntu と進んでいくと、インストール方法が記載されたページにたどり着きます。以下のコマンドを1つずつ実行します。 sudo apt update -qq sudo apt install --no-install-recommends software-properties-common dirmngr sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E298A3A825C0D65DFD57CBB651716619E084DAB9 sudo add-apt-repository "deb https://cloud.r-project.org/bin/linux/ubuntu $(lsb_release -cs)-cran40/" sudo apt install --no-install-recommends -y r-base  RStudioは、 https://www.rstudio.com/products/rstudio/download/#download からdebファイルをダウンロードして、gdebiでインストールします。一応、upgradeもしておきます。 sudo apt update sudo apt upgrade -y sudo apt install gdebi sudo gdebi rstudio-1.4.1106-amd64.deb  rstudioの数字部分は、適宜変更しましょう。これで、RStudioはrstudioコマンドで起動できます。 Jupyter Notebook へ R を登録  コマンドプロンプトでRを起動し、以下のコマンドを1行ずつ入れます。 install.packages('IRkernel') IRkernel::installspec()  これで、Jupyter NotebookでRを使うことができます。 Power Shellの登録  https://docs.microsoft.com/ja-jp/dotnet/core/install/linux-ubuntu#2010- を見ながら、.NET 5.0 をインストールします。 # 20.10 wget https://packages.microsoft.com/config/ubuntu/20.10/packages-microsoft-prod.deb -O packages-microsoft-prod.deb sudo dpkg -i packages-microsoft-prod.deb # SDK sudo apt-get update; \ sudo apt-get install -y apt-transport-https && \ sudo apt-get update && \ sudo apt-get install -y dotnet-sdk-5.0 # Runtime sudo apt-get update; \ sudo apt-get install -y apt-transport-https && \ sudo apt-get update && \ sudo apt-get install -y aspnetcore-runtime-5.0  次に、dotnet-interactive をインストールして、jupyter notebookに登録します。コマンドプロンプトから、以下のコマンドを入れます。 dotnet tool install --global Microsoft.dotnet-interactive  次のコマンドは、そのまま実行するとコマンドが見つからないと出てきますので、一度、Ubuntuを再起動させてから実行します。 dotnet interactive jupyter install  これで、UbuntuでもPower Shellが実行できるようになりました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

pythonのfor文は本当に遅い? (今日のPython Day9)

0. はじめに  「Pythonのforループは遅い」とよく(?)言われるそうですが、本当に遅いのか疑問に思いました。もちろん記事を書いている当人が初心者なので複雑なことをしてない(というかできない)だけかもしれません。今回は初心者でもfor文とその処理時間を出力することができる問題を作成しました。最後まで読んでいただけるとありがたいです。 1. 問題  1から10,000までの整数を1つずつ出力するプログラムを作成してください。また処理の最後に実行時間を出力するようにしてください。なお実行時間を出力する方法が分からない人はヒントを参考にしてください。 2. ヒント  【Python】処理にかかる時間を計測して表示という記事が分かりやすくよくまとまっているように感じました。この記事を参考に問題を解いてください。 3. 解答例 import time START_TIME = time.time() for i in range(1, 100001): print(i) i += 1 lag = time.time() - START_TIME print(f"実行時間は{round(lag, 3)}秒です。") 4. 解説  まず数の出力にはfor文を用いました。今回は1から10,000までの数を出力したかったのでrange()関数の中身(これを引数と言います) は1, 10001としました。range(10000)とすると0から9,999までの数が出力されてしまうからです。次に、先ほど紹介した記事に書かれていたように処理時間は「処理を終えた時間」から「処理を始めた時間」を引くことで求めました。今回の解答例ではそれに加えて処理時間の小数第3位以下を(個人的に)四捨五入したかったのでround()関数を用いました。これはなくても構いません。   肝心の処理時間ですが、なんと0.091秒。自分はとてもはやいと思いました。 5. まとめ ・自然数を1つずつ表示するにはfor i in range()を用いる。 (↑ただしwhileでも同じことはできます。) ・処理時間は「処理を終えた時間」から「処理を始めた時間」を引いて求める。 ・小数の四捨五入にはround()関数を用いる。 6. おまけトーク  PycharmというIDEを用いると簡単に外部モジュールをimportできるのですが、importする様子を見たいがためにわざわざシェルを使っています。あれってプログラムしている感じがあって個人的には好きなんですよね。私だけですかね?最後まで読んでいただき本当にありがとうございます。 参考文献 【Python】処理にかかる時間を計測して表示
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ROSでの通信遅延時間検証 その①

概要 ROS(melodic)での通信遅延時間について検証してみました。 最近ROSでの本格的な開発を始めたROS初心者です。 ROSはリアルタイム性が低い事が知られていますが、実際にどの程度のリアルタイム性が期待できるのか、ノード間通信の遅延時間という観点で検証してみました。 ここでは検証プログラムの基本的な動作とROSでの時間システムを基本から説明しています。適当なVM上で検証しているので詳細な性能検証は別途投稿します。 ROSでの処理時間計測 C/C++ではchrono関数等の時間計測用関数で処理時間計測を行っていると思います。 処理時間計測関数 ROSでも当然同じ関数を用いて時間計測が可能ですが、ROSを理解するためにも、ここではROSのログから処理時間を計測してみたいと思います。 検証用のコードと実行結果 では、ノード間通信の遅延時間を見ていきたいと思います。 ここでは、簡単な文字列を送信して、送信時と受信時のタイムスタンプを見る事で遅延時間を計測したいと思います。 検証では、下記のROS講座を参考にさせて頂きました。 ROS講座03 Pub & Sub 通信 検証用のpublisher(送信)のコードです。 詳細な動作説明は上記のROS講座に記載がありますので割愛しますが、ここで注目して頂きたいのは、ros::Rate loop_rate(100);です。 これは、publisher側のデータ送信レートです。つまり、このコードでは100Hz(10msに1回)でデータを送信する事になります。この時、送信されるデータは、msg.data = "Test msg";にあるように、'Test msg'という文字列になります。 test_publisher.cpp #include <ros/ros.h> #include <std_msgs/String.h> int main(int argc, char** argv) { ros::init(argc, argv, "test_publisher"); ros::NodeHandle nh; ros::Publisher chatter_pub = nh.advertise<std_msgs::String>("chatter", 10); ros::Rate loop_rate(100); while (ros::ok()) { std_msgs::String msg; msg.data = "Test msg"; ROS_INFO("publish: %s", msg.data.c_str()); chatter_pub.publish(msg); ros::spinOnce(); loop_rate.sleep(); } return 0; } これに対応するsubscriber(受信)が下記になります。 test_subscriber.cpp #include <ros/ros.h> #include <std_msgs/String.h> void chatterCallback(const std_msgs::String& msg) { ROS_INFO("subscribe: %s", msg.data.c_str()); } int main(int argc, char** argv) { ros::init(argc, argv, "test_subscriber"); ros::NodeHandle nh; ros::Subscriber sub = nh.subscribe("chatter", 10, chatterCallback); ros::spin(); return 0; } また、publisher, subscriberそれぞれにROS_INFOという関数が使用されていますが、これはターミナルに結果を出力するためのprintfのような物です。 下記がlaunchファイルになります。 test_pubsub.launch <launch> <node name="test_publisher" pkg="latency_test" type="test_publisher" output="screen"/> <node name="test_sybscriber" pkg="latency_test" type="test_subscriber" output="screen"/> </launch> これで、上記のlaunchファイルを実行すると、下記のように、ひたすら'Test msg'という文字列の送受信が行われます。 また、この時ROS_INFOの実行された時間も同時に表示されます。 ROSの時間フォーマットは、こちらの公式ドキュメントに記載がありますが小数点前はsec、小数点以降はnsecです。また、secはエポック秒です。 このターミナル出力をみると、publishは10msec程度の間隔で行われていて、publishからsubscribeの間隔は1msec以下である事がわかります。 送信レートと通信遅延時間の検証 ターミナルの表示結果をscriptでログをとって解析しても良いのですが、ROSの機能でこの結果は自動的にログとして残っています。デフォルトでは、ユーザフォルダ直下に/.ros/log/latestrosout.logとして保存されています。 このログファイルを下記のスクリプトで簡単に解析してみました。 check_time_stamp_pubsub.py import csv import numpy as np import matplotlib.pyplot as plt # Specify file name of log file file = 'rosout.log' log_file = open(file, "r", encoding="UTF-8") dataList = log_file.readlines() # Specify extract name extract_word1 = 'publish' extract_word2 = 'subscribe' published_time = [] subscribed_time = [] for row in dataList: if extract_word1 in row: published_time.append(float(row[:20])) if extract_word2 in row: subscribed_time.append(float(row[:20])) # Convert to numpy array published_time = np.array(published_time) subscribed_time = np.array(subscribed_time) diff_pub_time = [] for t in range(0,len(published_time)-1): diff_pub_time.append(published_time[t+1]-published_time[t]) # Remove surplus index diff_num = len(published_time) - len(subscribed_time) published_time = np.delete(published_time,slice(0,diff_num)) transmit_time = subscribed_time - published_time pub_time_ave = np.mean(diff_pub_time) pub_time_std = np.std(diff_pub_time) transmit_time_ave = np.mean(transmit_time) transmit_time_std = np.std(transmit_time) print('Pub time : Ave = {0}, STD = {1}'.format(pub_time_ave, pub_time_std)) print('Transmit time : Ave = {0}, STD = {1}'.format(transmit_time_ave, transmit_time_std)) plt.figure() plt.scatter(range(0,len(diff_pub_time)),diff_pub_time) plt.xlabel('Frame') plt.ylabel('Time [sec.]') plt.figure() plt.scatter(range(0,len(transmit_time)),transmit_time) plt.xlabel('Frame') plt.ylabel('Time [sec.]') plt.show() 下記が送信レートになります。送信した時間と1回前の送信時間との差分をプロットしています。100Hzで送信しているので、ここは10msecになるはずですが、最大で2msec程度のずれがありました。平均は10msec, 標準偏差は400usecとなったので、おおむね100Hzで送信されている事がわかります。 次に送信してから、受信されるまでの遅延を検証しました。 一番遅延が大きい時では3msec程度の遅延がありましたが、平均は300us, 標準偏差は90usecの遅延となりました。300usなら十分速いと思いますが、3msecとなると後段の処理によってはリアルタイム動作に影響を与える可能性がありそうですね。 また、この時publishの回数とsubscribeの回数があっておらず、publishのほうが先に動作を始めており11回送信後にsubscribeの動作が始まっていました。解析用のスクリプトでは、publish側が先に動作し始める事を前提にsubscribeの動作開始までのデータを捨てるようにしています。 まとめ pub&sub送信時の遅延時間を簡単に検証してみました。 ・送信レート、通信遅延ともにばらつき有り(それぞれ最大2msec,3msec) ・通信遅延は短い文字列であれば300us程度 ・ノードの動作開始タイミングに差分有り 今後は、下記を変えて遅延時間の検証を行っていく予定です。 ・送信データ容量 ・バッファサイズ ROS初心者ですので、記載内容に間違い、または、アドバイス等あればコメント頂けますと幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【個人開発】化合物の物性予測サービスをリリースした話

はじめに 化合物の物性を予測するサービス CHeMODEL(https://chemodel.herokuapp.com/) を個人開発によりリリースしてみた。 化合物データを対象とした機械学習については、様々な手法や実装が論文やgithubで公開されているものの、それらを用いてWEB上で手軽に予測できるサービスが少ないと感じていた。そもそもニーズがあまりないという可能性もあるが、化学分野の業務知識と開発ノウハウ(+それなりの時間)を持つ人間が少ないことも関係しているかもしれない。そういうわけで今回、自分の持つ知識と開発スキルを総動員し、WEB上での予測サービスを開発するに至った。 作ったもの 今回2つの物性の予測サービスを開発した。単に予測するだけでなく、予測根拠や予測の信頼性が分かるような機能にこだわってみた。以下、各画面と機能について説明する。 化合物入力 トップ画面である化合物入力 (URL : https://chemodel.herokuapp.com/) は以下の通りである。 予測したい化合物は以下4つのいずれかの方法で指定することができる。 SMILES文字列 SMILESファイル (1行1SMILESのファイル) SDFファイル 化学構造式(直接描画) 予測したい物性のモデルは、以下いずれかまたは両方を選択することができる。 Solubility Lipophilicity なお、Solubilityは、https://github.com/rdkit/rdkit/tree/master/Docs/Book/data/solubility.train.sdf 、 Lipophilicityは、https://deepchemdata.s3-us-west-1.amazonaws.com/datasets/Lipophilicity.csv のデータを用いた機械学習モデルである。 ※ Lipophilicity単独指定の場合、負荷の高いLipophilicityの適用領域の表示処理が行われ実質タイムアウトしてしまうため、必ずSolubilityを選択してほしい(笑)。 ※同様に、化合物を複数指定すると、かなりの確率でタイムアウトが発生するため、単独の指定をお奨めする(笑)。 予測結果一覧表示 化合物入力画面でsubmitボタンをクリックすると、以下の通り予測結果が表示される。 各情報の意味は次の通りである。 Predicted Value 物性の予測値である。 AD distance 予測モデルの学習データの重心からの距離である。どの程度、予測に信頼性を示しているかの指標として今回表示した。 なお、本来であればモデル構築時の説明変数で距離を求めるべきであるが、モデルの構築に用いたDeep Learningモデルから説明変数に相当するデータを取得するのが面倒だったため、今回 RDKit の記述子計算結果を利用している。 AD Knn5 学習データのうち最も近い距離にある5つの化合物との平均距離である。これも、予測の信頼性を示す指標である。 AD distance が学習データの分布の範囲内にあったとしても、AD Knn5が大きい場合(平均距離が大きい場合)、学習データの中に近いサンプルがないことになり、予測の信頼性が低いと考えられる。 explanatory visualization 化学構造中のどの原子が予測に寄与したかを示している。赤い程プラスに貢献しており、青い程マイナスに貢献している。画像をクリックすると2倍に拡大表示する(下図)。 予測モデルの適用領域の可視化 予測結果一覧表示のタブで「Applicability Domain」を選択すると、以下の通り、学習データおよび予測対象化合物が2次元に可視化される。2次元座標の生成は主成分分析を用いた。 予測対象のデータは赤でプロットされる。マウスカーソルをあてると対象サンプルの情報をホバーで表示する。後述する色モードが Normalの場合、クリックするとサンプルが大きな青色表示に変わり、そのサンプルの近傍の10個のサンプルがグレー表示される(下図)。 この状態で他のサンプルにマウスオーバすると、クリック中のサンプルとの距離が追加で表示される。これらの機能を用意した理由は、2次元で距離が近いからといって、必ずしも元の多次元における距離が近いとは限らないため、近傍との距離を正しく確認するためである。 また、グラフの色付け方法を指定する色モードは以下4種類を用意した。 Normal 色は全て同一色。この場合、先に説明したようにクリックしたサンプルと他のサンプルとの距離を確認できる。 AD Distance AD Distance の大きさに応じて色を表示する。学習データの重心からの距離の分布を視覚的に確認できる。 AD Knn5 AD Knn5 の大きさに応じて色を表示する。学習データの密度の分布を視覚的に確認できる。 Target value 実測値(予測対象の場合は予測値)に応じて色を表示する。実測値による分布がどうなっているかを視覚的に確認できる。 その他 予測結果や信頼性指標をCSVでダウンロードできるようにした。 実装方法の詳細 デプロイ環境 Herokuの無料プランを使った。またconda環境をデプロイしたかったため、Dockerによるデプロイを実施した( Docker によるデプロイ 参照)。 ちなみにDockerでデプロイする手順は以下の通りで、2回目以降は実質3分程度でリリースできる。"chemodel" は Heroku のアプリケーション名になるので適宜読み替えてほしい。 heroku login heroku container login heroku container:push web -a chemodel heroku container:release web -a chemodel ログは以下で参照可能である。 heroku logs --tail -a chemodel 言語/WEBアプリフレームワーク 言語はPython、WEBアプリフレームワークはDjango3を採用し、Visual Studio Codeで開発した。非常に快適であり、これを機にPyCharmからVisual Studio Codeに乗り換えるほどであった。 データベース データベースは今回使用しなかった。Herokuの無料プランではレコード数の制限があるため、ユーザの入力データや、予測結果は、1時ファイルやメモリ上で処理することとし、データベースに一切保存しないようにした。 フロントエンドフレームワーク BootStrap4を用いた。デザインはこれまで苦手な領域であったが、ファイルアップロードのフォームや、タブ切り替え等、このおかげで苦労なく違和感のないUIを実現できた。 予測モデル構築 PyTorchを使った自前のGCNライブラリ simple-GCN を用いて予測モデルの構築を行った。 化合物データ処理 化合物画像の生成や、主成分分析用の記述子計算などにRDKitに用いた。 化合物構造入力エディタ JSME を用いた。フリーのものは現状これ1択になる。 予測根拠表示 予測に寄与した原子への色付けはCaptum (https://captum.ai/) により実現した。モデルを解釈するアルゴリズムをまとめたライブラリであり、PyTorchに対応している。わがライブラリsimple-GCNで作成した予測モデルに適用し、原子に色付けを行った断片コードを以下に示す。今回はIntegratedGradientsという入力層の寄与度が分かる手法を利用した。 from captum.attr import Saliency, Integrated Gradients for i, (mol, batch) in enumerate(zip(mols, iters)): data = [] atom_features, bond_features, array_rep, labels = batch y = model(atom_features, bond_features, array_rep) #予測値 data.append(float(y.detach().numpy())) #予測確率 data.append(float(y.detach().numpy())) #根拠画像の生成 atom_features.requires_grad = True ig = IntegratedGradients(model) result = ig.attribute(atom_features, target=0, additional_forward_args=(bond_features, array_rep), internal_batch_size=atom_features.shape[0]) # 原子毎に寄与度を集約 total = torch.sum(result, dim=1) atom_hilights = {} bond_hilights = {} radii = {} max = 3 for value, ix in zip(total, array_rep["rdkit_ix"]): # 値に応じた色の選定 value = value.item() r = 0 b = 0 if value > 0: rate = value / max if rate > 1: rate = 1 color = get_color('AA', '55', 'AA', rate) else: rate = -value / max if rate > 1: rate = 1 color = get_color('55', '55', 'AA', rate) atom_hilights[int(ix)] = color radii[int(ix)] = 0.3 exp_image = generate_exp_image(mol, list(atom_hilights.keys()), list(bond_hilights.keys()), atom_hilights, bond_hilights, radii, (240, 240), type="image") data.append(exp_image) ret.append(data) 可視化処理 主成分分析はscikit-learnを用いた。 グラフ描画 Jupyterではmatplotlibを使うところであるが、WEB上であるため一時期流行ったD3.jsで実装した。D3.jsの取り扱いを含むJavaScriptでのグラフの描画が、今回苦戦したところであったが、非同期処理への対応 などでかなりの経験を積むことができた。 苦労したこと ローカルとDockerでの動作差異 ローカル(Windows10)で構築したcondaと同じ環境をDocker上に再現できなくて困った。これは今回採用したDockerのベースがLinuxベースであり、Windowsのローカルでインストールできたバージョンが、Docker経由だと見つからなかったためである。 また、グラフ可視化のために検討していたUMAPについて、ローカルで作成したモデルが、Dockerに登載すると動作しないことが判明した。これもOSの差が影響したとみている。condaを使う場合の注意点といえる。 Herokuアプリの起動に時間がかかり、タイムアウトが発生する。  Herokuの無料プランでは、30分アクセスがないとスリープする仕様である。スリープ後に起動する際にタイムアウトエラーがかなりの頻度で発生する。トップ画面を表示しているだけなのであるが、Dockerコンテナの起動に時間がかかっているのかもしれない。その場合以下の画面が表示される。この後再度アクセスすると運がよければ表示される(笑)。 ちなみにログはこんなエラーが表示されることが多い。 4-9030-4b31-b5f1-6610412427a7 fwd="XXX.XXX.XXX.XXX" dyno= connect= service= status=503 bytes= protocol=https 2021-05-08T04:57:26.885433+00:00 heroku[router]: at=error code=H20 desc="App boot timeout" method=GET path="/" host=chemodel.herokuapp.com request_id=772a517 まとめと今後の課題 今回は、一通りサービスの実現の技術的な目途を立てることができたので、次回は完成度の高いサービスを目指したい。 性能面でいえば、Lipophilicityのグラフ表示が異常に遅い。グラフ表示の際に、サンプル同士の総当たりの距離計算したファイルを読み込んでいるのだが、4200 x 4200の組み合わせ数となるため時間がかかっている。実用上学習データ同士の距離表示は除外してもよいだろう。 大量のデータをさばけるよう、Heroku以外のPaaSも検討したい。 対応モデルや予測手法を増やしてみたい。 参考文献 D3.js simple-GCN HerokuにConda環境で開発したアプリをデプロイする方法 Captum Captumを試す
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

gRPC Pythonのコード生成で、相対参照に近い意図したパッケージとして生成する

PythonでgRPCを使う場合には、grpcio-toolsパッケージを使いますが、この使い方で目的のパッケージの中にあるコードとして生成しようとした時に、ハマったので解説します。 実現したいこと 用意した定義ファイルはこちら proto/gisapp.proto syntax = "proto3"; package proto; service GISCalc { rpc RouteLength(RouteLengthRequest) returns (RouteLengthResponse) {} } message Point { double latitude = 1; double lognitude = 2; } message RouteLengthRequest { repeated Point route = 1; } message RouteLengthResponse { double length = 1; } ここから、以下のように使えるように proto パッケージの中に生成したコードを収めたいとします。 test.py import grpc from proto import gisapp_pb2_grpc, gisapp_pb2 channel = grpc.insecure_channel('localhost:50051') client = gisapp_pb2_grpc.GISCalcStub(channel) req = gisapp_pb2.RouteLengthRequest() res = client.RouteLength() つまり、以下のようなディレクトリ構成にします。 `- proto |- gisapp_pb2.py `- gisapp_pb2_grpc.py どうすればよいか パッケージにしたいディレクトリの中に、定義ファイルを置きます。 `- proto `- gisapp.proto ルートディレクトリにて、以下のように実行します。 python -m grpc_tools.protoc \ -I=. \ --python_out=. \ --grpc_python_out=. \ proto/gisapp.proto すると、以下のような、protoパッケージ下にあるプログラムとして生成されます。 proto/gisapp_pb_grpc.py import grpc from proto import gisapp_pb2 as proto_dot_gisapp__pb2 ... 解説 パッケージ構成は、-Iで指定したフォルダから、定義ファイル gisapp.proto までのディレクトリ構成になります。以下のような関係になります。 -I./proto proto/gisapp.proto →import gisapp_pb2 -I. proto/gisapp.proto →from proto import gisapp_pb2 次に、出力先に引数である --python_out、--grpc_python_out は、指定したパスをルートとするパッケージとして出力されます。 -I./proto proto/gisapp.protoかつ --python_out=./proto → proto/proto/gisapp_pb2.py に import gisapp_pb2 が作られる --python_out=. → proto/gisapp_pb2.py に import gisapp_pb2 -I. proto/gisapp.proto かつ --python_out=./proto → proto/proto/gisapp_pb2.py に from proto import gisapp_pb2 が作られる --python_out=. → proto/gisapp_pb2.py に from proto import gisapp_pb2 が作られる よって、前述のコマンドのとおりになります。 ところで betterproto というツールで生成したところ、どこのパッケージ下にもおける1ファイルが生成されるようになったので、上記のようなパッケージの問題は消失しました。 pip install betterproto[compiler]==2.0.0b3 python -m grpc_tools.protoc \ -I=. \ --python_betterproto_out=. \ proto/gisapp.proto proto/__init__.py # Generated by the protocol buffer compiler. DO NOT EDIT! # sources: proto/gisapp.proto # plugin: python-betterproto from dataclasses import dataclass from typing import Dict, List, Optional import betterproto from betterproto.grpc.grpclib_server import ServiceBase import grpclib @dataclass(eq=False, repr=False) class Point(betterproto.Message): latitude: float = betterproto.double_field(1) longitude: float = betterproto.double_field(2) @dataclass(eq=False, repr=False) class RouteLengthRequest(betterproto.Message): route: List["Point"] = betterproto.message_field(1) @dataclass(eq=False, repr=False) class RouteLengthResponse(betterproto.Message): length: float = betterproto.double_field(1) class GisCalcStub(betterproto.ServiceStub): async def route_length( self, *, route: Optional[List["Point"]] = None ) -> "RouteLengthResponse": ... class GisCalcBase(ServiceBase): async def route_length( self, route: Optional[List["Point"]] ) -> "RouteLengthResponse": ...
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

(備忘録)BERTの学習済みモデルを使って簡単に質問応答する方法を試みた結果^^;)

はじめに お休みのため時間あったので、初歩的な学習モデル(分類)で、以下のような質問応答ページを作っていました。うまくいかない点も多々あり、備忘禄用にやったことをアウトプットしておこうと思います。 この方法は、学習用モデルに以下のような教師データを与え、単語毎に分離してTF-IDFで文書をベクトル化してます。 学習モデルはほぼこちらを流用しております。 import pandas as pd df_study = pd.read_csv('ans_studyInput_qa.txt', names=['id', 'truth_val', 'ラベル(教師データ)', '入力']) df_study id truth_val ラベル(教師データ) 入力 0 1 T チャージ料金 1500円また、アルコール類を500円より提供しております。[こちら](htt... 料金はいくら? 1 2 T チャージ料金 1500円また,アルコール類を500円"より提供しております。[こちら](ht... 金額はどのくらいかかる? 2 3 T チャージ料金 1500円また、アルコール類を500円より提供しております。[こちら](htt... いくらあれば足りる? 3 x T チャージ料金 1500円また、アルコール類を500円より提供しております。[こちら](htt... 料金を教えてください 4 x T チャージ料金 1500円また、アルコール類を500円より提供しております。[こちら](htt... 料金について ... ... ... ... ... 134 x T どなたでもカラオケ感覚で歌って演奏できます。お店の楽器は自由に演奏できます。また、視聴のみで... 何ができる? 135 x T どなたでもカラオケ感覚で歌って演奏できます。お店の楽器は自由に演奏できます。また、視聴のみで... 楽しみ方は? 136 x T どなたでもカラオケ感覚で歌って演奏できます。お店の楽器は自由に演奏できます。また、視聴のみで... 楽しみ方法? 137 x T どなたでもカラオケ感覚で歌って演奏できます。お店の楽器は自由に演奏できます。また、視聴のみで... 他のお店との違いは? 138 x T どなたでもカラオケ感覚で歌って演奏できます。お店の楽器は自由に演奏できます。また、視聴のみで... 普通のお店との違いは? 139 rows × 4 columns この方法では、入力文書をTF-IDFでベクトル化しているため、単語の重要度(珍しさ)は分かるのですが、単語の並び順や意味的な近さを考慮できていません。そのため、学習モデルが分類ということもありますが、上図のGifのように「チャージ料金はいくらですか?」の問いに「チャージ料金 1500円また、アルコール類を500円より提供しております。」という回答をしています。 本当は、余計な部分はいらず「1500円です」と回答したいところです。 そこで、改善方法がないか探しました。調べた結果を記載します。 学習済みモデルについて 色々調べた所、自力で質問応答の学習済みモデルを作るのは自分のスキル、資源、時間的にも無理そうでした どうしようか悩んでいた所、こちらの記事でBERTを使った自然言語処理について分かりやすく解説頂いてましたので活用できないか試みました。 ファインチューニングという方法で実現可能なようでしたが、学習データ構造と質問応答への流用方法が理解できていないため、ファインチューニング済みの学習モデルを探すことにしました。 Hugging Faceが学習済みモデルを提供下さってました。 Hugging Faceについては、わかり易い記事ありましたので引用させて頂きます。 引用元:文章を理解するAIの開発を目指すHugging Face 情報を分類、理解、抽出、文章を生成するのにもすぐに活用できるのです。例えば、カスタマーサポートのメールや、TwitterやFacebookなどソーシャルメディア、新聞、書籍の投稿からも、特定のトピックについての情報抽出をしたい時にいつでもできるのです。 BERTの学習済みモデル(英語版)を使って結果確認 まずは、上記Hugging Faceの学習済みモデルを使ってどうなるか確認しました。 但し、Hugging Faceには日本語QAモデルが見当たらなかった(一つあったのですが、動かし方悪いのかエラーとなり動きませんでした)ので、英語版のモデルで無理やり試しました 試したモデルはdistilbert-base-uncased-distilled-squadです。 !pip install transformers from transformers import AutoModelForQuestionAnswering, AutoTokenizer, pipeline model_name = "distilbert-base-uncased-distilled-squad" # a) Get predictions nlp = pipeline('question-answering', model=model_name, tokenizer=model_name) # model = AutoModelForQuestionAnswering.from_pretrained(model_name) # tokenizer = AutoTokenizer.from_pretrained(model_name) お試し1 QA_input = { 'question': "チャージ料金はいくらですか?", 'context': 'チャージ料金 1500円また、アルコール類を500円より提供しております。' } res = nlp(QA_input) print(res) print('答え: ' + res['answer']) 実行結果1 {'score': 0.07764814049005508, 'start': 0, 'end': 11, 'answer': 'チャージ料金 1500'} 答え: チャージ料金 1500 お試し2(質問文を変更) QA_input = { 'question': "アルコール類はいくらですか?", 'context': 'チャージ料金 1500円また、アルコール類を500円より提供しております。' } res = nlp(QA_input) print(res) print('答え: ' + res['answer']) 実行結果2 {'score': 0.027067013084888458, 'start': 15, 'end': 28, 'answer': 'アルコール類を500円より'} 答え: アルコール類を500円より 料金以外の文章が残ってしまってます。 Bertの日本語QAモデルを使って結果確認 Hugging Faceには見当たりませんでしたが、日本語QAモデルの記事があり、既に学習済みモデルを作成して下さってました。 こちらの記事となります。大変勉強になりました 作成済みの学習モデルをダウンロードさせて頂き、結果を確認しました。 お試し3 context = """ チャージ料金 1500円また、アルコール類を500円より提供しております。 """ quesion = "チャージ料金はいくらですか?" prediction, score = predict(quesion, context) print('答え: ' + prediction) print(score) 実行結果3 答え: 1500円 13.75549030303955 チャージ料金のみとれています。 お試し4 context = """ チャージ料金 1500円また、アルコール類を500円より提供しております。 """ quesion = "アルコール類はいくらですか?" prediction, score = predict(quesion, context) print('答え: ' + prediction) print(score) 実行結果4 答え: 500円 7.591254949569702 参考文献 この記事を作るにあたって参考にさせて頂きました はじめての自然言語処理 文章を理解するAIの開発を目指すHugging Face BERTを使った汎用的な日本語QAモデルの作成 roberta-base for QA
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PythonでABCのCくらいまでをしばき倒す part1

注意 この記事はAtCoder及びAtCoder Beginner Contestのための記事です。 AtCoderって何?って方はこちらへ 初めての記事なのでどうか温かい目でよろしくお願いします。 多分正しくない記述がいっぱいです。 小技紹介なので厳密な説明をしません、説明がめんどくさい部分は省きます。 ミスってたらごめんなさい。 ターゲットとしてはB問題やC問題で苦戦しがち、時間がかかりがちな人あたりです。 正直あまり教育によろしい記事ではないと思います はじめに 競プロを始めて丁度1年くらいの緑Coder、くろま(Chroma7p)です。後輩に競プロ文化を広めるべく精進しております。 後輩たちの健闘を見ていると、ライブラリや言語の機能を使いこなしきれずC問題くらいで力尽きるパターンをよく見るので、そういった要素をある程度あらかじめ知っておくことで、灰~茶Diff前半くらいを反射でしばいてD問題以降に挑戦できるようになってほしいというのが狙いです。あとは初心者に教えたいことの備忘録的な物だったり初めての記事書く練習だったりします。 行き当たりばったりで書いているので順番等めちゃくちゃになるかもしれません。気づいたら加筆修正等はしていくつもりです。 今回は基本的な部分と、リスト、文字列の扱い、辞書型をまとめます。 便利な機能等を挙げていますが、行が少ないと速いというわけではなく当然それなりの処理があります。特にC問題では愚直に操作を行ったり、全探索をしてしまうと間に合わないケースが多いので気を付けたほうがいいと思います。そういった時のテクなどもいずれ紹介するつもりです。 なるべく色々なパターンを紹介しようとしていますがカバーしきれていないケースもあるので疑問に思った場合はその関数名で調べるなり自分で試すなりしていただければ理解が深まると思います。(関数や型の機能は調べてもらった方が早いし情報が多いです) あくまで紹介という体でよろしくお願いします。 なお、ここにあるコードは全てAtCoderの環境での動作を確認しているつもりです。 目次 項目 内容 基本 基本的な入出力やちょっとした演算 インデックスとスライス 文字列やリストを扱ううえで便利な機能 辞書型 文字列などで管理できる便利な配列 便利な関数 ABCで使える便利な関数 応用編 紹介した機能を用いてABCで使える小技を紹介 基本 入力を Hello world! として考えます。 s=input() print(s) #Hello world! 行を空白含めて文字列として読み取ります。(例:”Hello world!") s=input().split() print(s) #["Hello","world!"] 行を空白区切りのリストで取得します。 input()の返り値は上と同様"Hello world!"ですが、それをsplit()という関数で空白区切りで分割しています。 s,t=input().split() print(s,t) #Hello world! 入力の空白区切りの要素数と左辺の要素数が同じであれば直接代入もできます。 print()はスペース区切りで1行で出力してくれます。 s="Hello world!" for c in s:#sの文字列から1文字ずつcとして参照 print(c,end=" ") print()#ただの改行 #H e l l o w o r l d ! print()でendを指定してやると末尾に入る文字列を設定してやることが出来ます。デフォルトで改行が入っていますが、変更すれば改行をなくしたり、1文字ずつ間に挟んだりできます。 s="Hello" t="world" u=s+" "+t+"!"*5 print(u) #Hello world!!!!! v=(s+" "+t+"!")*5 print(v) #Hello world!Hello world!Hello world!Hello world!Hello world! 文字列同士の+は結合、*でその分繰り返すことが出来ます。記号の優先度は数字と同様*のほうが高いです。 また、数字と文字列でやろうとするともちろんエラーを吐きます。 print("ABC" in "ABCDE")#True print("AC" in "ABCDE")#False print("ABC" in ["ABC","ARC","AGC"])#True print("AB" in ["ABC","ARC","AGC"])#False 文字列A in 文字列B で文字列Bに文字列Aが含まれているかを判定します。判定するのは連続する部分文字列だけであり上の例で言うような飛び飛びの部分文字列は判定できません。 また、リスト内の検索にも使えますが、要素と完全に一致しないと判定できません。 a,b=3,4 print(a,b)#3 4 a,b=b,a print(a,b)#4,3 代入にこのような記法ができるので、変数の入れかえも一発でできます。 リストの基本 リストも、文字列同様リスト同士足したり定数を掛けたりできます。 また、リスト内包表記と呼ばれるfor文でリストを生成する方法もあります。 a=[7,6,5] b=[3,4,6] print(a+b)#[7, 6, 5, 3, 4, 6] print(b+a)#[3, 4, 6, 7, 6, 5] a.extend(b) print(a)#[7, 6, 5, 3, 4, 6] zeros=[0]*10 print(zeros)#[0, 0, 0, 0, 0, 0, 0, 0, 0, 0] nums=[3,6,4]*3 print(nums)#[3, 6, 4, 3, 6, 4, 3, 6, 4] print([i for i in range(10)])#[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] #↑ほとんど #↓同じ lis=[] for i in range(10): lis.append(i) print(lis)#[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] インデックスとスライス 文字列において、リストと同じようにn番目の文字を参照できます. インデックス print("Python"[0])#P print("Python"[1])#y print("Python"[5000])#エラー print("Python"[-1])#n print("Python"[-100])#エラー print([6,5,4,3,2,1][-4])#4 n文字の時それぞれの文字を0からn-1で参照します。 範囲外を選択するとエラーを吐きます また、一番最後の文字を-1番目としたマイナスの記法も存在します。(下参照) 実際マイナスで尻からたどれることと-1で最後尾が参照できることが分かれば大丈夫だと思います。 0 1 2 3 4 5 P y t h o n -6 -5 -4 -3 -2 -1 スライス スライスは文字列やリストで指定した範囲を取り出すことが出来る機能です。説明するより見たほうが早いです。 print("Python"[1:])#ython print("Python"[:2])#Py print("Python"[2:4])#th print("Python"[::2])#Pto print("Python"[::-1])#nohtyP print([10,9,8,7,6,5,4,3,2,1][-3:-8:-2])#[3,5,7] [start:stop:step]のようにコロンで区切って指定することで、自由に一定間隔の文字、要素を取り出すことが出来ます。 stepは省略可能で通常1になっています。また、start,stopの数字を省略すると端まで勝手にやってくれます。 そしてstepに負の値を入れると逆向きで行ってくれます print("Python"[33:4:264])#空文字列 スライスでは無茶な指定をしてもエラーを吐かずに空文字列を返してくれます。 基本的に、forとかでよく使うrange()と同じ文法のはずです。 辞書型 Pythonには辞書型(dict)という型があります。リストはインデックスで要素を参照しますが、辞書型ではkeyと呼ばれるもので参照します。(例:{key:要素}) keyは数字でも文字列でも割と何でも行けます(リストとかはダメ)。要素はリスト同様リストやら文字列やらもっと何でも行けます。 dic={"pen":1,"pineapple":2,"apple":"No",33:4} print(dic["pen"])#1 print(dic["pineapple"])#2 print(dic["apple"])#No print(dic[33])#4 print(dic[4])#エラー また、リスト同様辞書内の要素に直接アクセスして変更を加えることや、inでkeyの存在をチェックすることも可能です。 また新たなkeyと要素を追加したい場合dict[key]=xxで代入することで追加することが出来ます。 dict.keys()でdict内のkeyを列挙することが出来ます。 inp=["bass","bass","kick","kick","bass","kick","kick"] dic={} for s in inp: if s in dic:#sというkeyが存在するかを判定 dic[s]+=1 else:#ない場合新しいkeyを作る dic[s]=1 for key in dic.keys():#.keys()でkeyを参照 print(key+":"+str(dic[key])) #bass:3 #kick:4 文字列で与えられた要素などをカウントする際に使えます。 便利な関数 map() 実はリスト内包表記で事足りる イテラブルなもの(リストやタプルなど)のすべての要素に対して関数を適用します。細かい説明は省くので詳しくは"Python map"とかで調べてください。ここではリストの全ての要素に関数を適用する例を挙げます。 第一引数に関数を、第二引数にイテラブルなもの(ここではリスト)を入れます。第一引数の関数が引数を2つ、3つと要求する場合mapの第三、第四引数に同様にリストを入れておけばそれらがその関数の第二、第三引数として機能します。 map()の返り値はmap型のオブジェクトなのでそのまま出力する際はlist()に入れて変換してやる必要があります。 自作関数でも可能なのでリスト全体に対して一定の操作をしたい場合などに使えます。 lis=[1,-2,3,-4,5] print(map(abs,lis))#<map object at なんとかかんとか> print(list(map(abs,lis)))#[1, 2, 3, 4, 5] print([abs(i) for i in lis])#[1, 2, 3, 4, 5](やっていることは同じ) また、map()を用いて複数個の数字の入力もできます。 input().split()で文字列のリストを取得してintに変換しています。 前者の場合入力の要素数と左辺の変数の数が合わないとエラーになるので気を付けてください。 a,b=map(int,input().split()) lis=list(map(int,input().split())) count() その名の通り文字列内の文字やリスト内の要素をカウントしてくれる関数です。 print("aaa".count("a"))#3 print("aaa".count("aa"))#1 複数文字を指定する場合は重ならないように選ぶので後者は1となります。 print([1,1,1,4,4,5].count(1))#3 print(["ABC","ARC","AGC"].count("AHC"))#0 リストでも同様のことが出来ます。(完全一致) また、該当する要素が無い場合0を返します。 replace() 文字列のうち特定の部分文字列を置き換えます。 先頭から置き換えられるので重なっていてそれが置き換えられた場合重なっていた後ろの方は放置されます。 置き換えですが第二引数に空文字列を指定すれば削除できたり、二つの引数が同じ長さである必要はありません。 print("aaa".replace("a","x"))#xxx print("aaa".replace("aa","x"))#xa upper(),lower(),capitalize() それぞれ、文字列をupper(大文字)、lower(小文字)にする、先頭を大文字にする関数です print("AbCdEfG".upper())#ABCDEFG print("AbCdEfG".lower())#abcdefg print("AbCdEfG".capitalize())#Abcdefg print("なんだしなんだしagc".upper())#なんだしなんだしAGC print("ZENKAKU".lower())#zenkaku 大文字小文字の区別があるものなら変換可能です。また変換可能でなくてもエラーを吐くことはなく変換可能な物だけを変換してくれます。 isupper(),islower() 文字列が、大文字小文字の区別があるものが完全にupper(大文字)、lower(小文字)であるかを判別する関数です。 ただし、文字列のすべてが大文字小文字の区別が無いものである場合にはFalseになります。 print("ABC".isupper())#True print("ABC".islower())#False print("abc".isupper())#False print("abc".islower())#True print("aBc".isupper())#False print("aBc".isupper())#False print("なんだしなんだしAGC".isupper())#True print("なんだし".isupper())#False print("".isupper())#False join(),split() それぞれ、リストから文字列を、文字列からリストを作る関数です。 l=["霧","霧","奇","譚"] print("".join(l))#霧霧奇譚 s1=" ".join(l) print(s1)#霧 霧 奇 譚 s2="・".join(l) print(s2)#霧・霧・奇・譚 #s1をスペース区切りでリスト化 print(s1.split())#['霧', '霧', '奇', '譚'] #s2をスペース区切りでリスト化(スペースが無いのでそのまま文字列として入る) print(s2.split())#['霧・霧・奇・譚'] #s2を点で区切ってリスト化 print(s2.split("・"))#['霧', '霧', '奇', '譚'] #文字列をそのまま1文字ずつリスト化 print(list(s2))#['霧', '・', '霧', '・', '奇', '・', '譚'] "任意の文字列(空文字列でも可)".join(list)で、listの要素の間に任意の文字列を挟んで文字列にすることが出来ます。 また、文字列.split(任意の文字列(空の場合空白))で、文字列を任意の文字列で区切ってリスト化できます。 この辺は文字列系の問題で役立つことがあります。 ただし、数字のリストの場合文字列に変換してやらないと怒られるのでmapで変換してやってからjoinします。 これは特定の条件を満たす数列を出力しなさいみたいな問題で使えます。 lis=[1,2,3,4,5] print(" ".join(map(str,lis))) #1 2 3 4 5 sort(),sorted() リストをソートすることが出来ます。様々なオプションで調整することもできます。(ここではreverseを挙げます) また、sorted()はもとになるリストを変更せずにソートされたリストを返します。(非破壊的) .sort()はそのリストを書き換えてソートを行います。(破壊的) lis=[3,1,4,1,5,9,2] print(sorted(lis))#[1, 1, 2, 3, 4, 5, 9] print(lis)#[3,1,4,1,5,9,2] lis.sort() print(lis)#[1, 1, 2, 3, 4, 5, 9] lis.sort(reverse=True) print(lis)#[9, 5, 4, 3, 2, 1, 1] 実用編 ここからはこれまでに取り上げた機能を用いて実際に問題を解いていきます。 問題名がリンクになっているので自分で考えてみたい方はそこから飛んであまり下まで行かずに自分で解いてみてください。 ABC192-B uNrEaDaBlE sTrInG 先頭から奇数番目の文字が全て英小文字であり、かつ、先頭から偶数番目の文字が全て英大文字であるような文字列を読みにくい文字列と呼びます。 文字列Sが読みにくい文字列かどうか判定してください。 一撃です。 s="aA"+input() if s[::2].islower() and s[1::2].isupper(): print("Yes") else: print("No") このようにスライスとisupper(),islower()を駆使することで一瞬で書きあげることが出来ます。 Sの長さが1の場合に、s[1::2]が空文字列となり無条件に"No"を出力することを防ぐために、あらかじめSの頭に条件を満たした文字列を挿入しています。ちゃんとテストケースでチェックしていればこの想定外の挙動に気づくことが出来ます。 ABC173-B Judge Status Summary 高橋君は、プログラミングコンテスト AXC002 に参加しており、問題 A にコードを提出しました。 この問題にはN個のテストケースがあります。 各テストケースi(1≤i≤N) について、ジャッジ結果を表す文字列Siが与えられるので、ジャッジ結果が AC, WA, TLE, RE であったものの個数をそれぞれ求めてください。 辞書型を使えば楽勝です。 n=int(input()) dic={"AC":0,"WA":0,"TLE":0,"RE":0} for i in range(n): s=input() dic[s]+=1 for key in ["AC","WA","TLE","RE"]: print(key+" x "+str(dic[key])) 最後の出力に関してはdic.keys()を使ってもAtCoder上であればおそらく問題はないんですが、万が一のためにこの形にしています。 dict型のkeyの順序はPython3.7から保証されているそうです。 似た問題 ABC164-C Gacha ABC192-C Kaprekar Number 0以上の整数xに対して、g1(x),g2(x),f(x)を次のように定めます。 g1(x)=xを十進法で表した時の各桁の数字を大きい順に並び変えてできる整数 g2(x)=xを十進法で表した時の各桁の数字を小さい順に並び変えてできる整数 f(x)=g1(x)-g2(x) 整数N,Kが与えられるので、a0=N, ai+1=f(ai) (i≥0)で定まる数列のaKを求めてください。 ちなみに問題名はカプレカー数と読むらしいです。 問題文を読むと数字をリストとしてとらえてソートすればいいのがなんとなくわかります。 n,k=map(int,input().split()) for i in range(k): s=list(str(n))#nをリスト化 g1=int("".join(sorted(s,reverse=True)))#ソートして文字列として結合した後にintに変換 g2=int("".join(sorted(s))) n=g1-g2 print(n) nを文字列にしてリスト化(例:19419→['1','9','4','1,'9']) そのリストをソートして結合(例:['1','9','4','1,'9']→['1','1','4','9','9']→'11499'→11499) を行っています。 問題文に書かれていることをそのまま書いているだけです。難しそうですがちゃんと考えて組み合わせればシンプルに素早く書けるようになります。 最後に アレを書くならコレも書かなきゃという感じで結構な長さになってしまいました。 set型や諸ライブラリ等まだまだ紹介しきれていないのでいずれPart2を書くつもりです。 実用編書いてて思ったんですけどこれだけで楽々解ける問題ってそんなにないですね…… あくまで小技の紹介なのでこうした方が早いとかはちょっと許してください…… A~C問題は全部埋めるくらいの勢いで過去問巡回すると解くのがかなり早くなります。3完あたりは特に早さでパフォーマンスが開くと思うのでまずは早い3完で高いパフォーマンスを取るのを目標にしてみるといいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

IFCOpenshellとTrimeshを使ってIFCのデータを可視化した話と設定の落とし穴

これなんの話? BIMの標準データ交換フォーマットであるIFCのデータを可視化しようとした。 しかし、PythonのJupyter上で可視化しようとしたところ、IFCのデータを処理するためのライブラリ・IfcOpenShellに落とし穴があってドツボにはまったけど何とか解決したよっていうお話。 IFCのデータをPythonで可視化する まずやらないといけないこと IFCのデータのメッシュ化 IFCのデータは曲線やらなにやらのデータが入っていて、座標系は部屋や階ごとの相対座標系になっていたりする。 こいつを座標系展開して、形状をメッシュ化するのは大変。 ただ、IFCのデータを読み込んで、3Dメッシュ化する機能を持つライブラリは世の中に既に存在している。 それがIfcOpenshellである。他にもIFCEngineなんてものもあるが、こちらは研究目的なら無償だけどビジネスやらなにやらで使うならお金がかかる。 とりあえず、今回はpythonでコードを書くので使うのならばpythonのバインディングがあるIfcOpenshellでしょうと。 必要なもののインストール ifcopenshellをインストールするにはcondaが必要だけど、Anaconda入れればOK Anacondaでのcondaの使い方とか知らないっていう人は別途自分で調べてください() pythonのバージョンは3.8でcondaの仮想環境は構築しました。 そのうえで、とりあえず以下のコマンドを実行すれば必要なものは入る…はず conda install -c conda-forge -c oce -c dlr-sc -c ifcopenshell ifcopenshell conda install -c conda-forge -c dlr-sc -c pythonocc -c oce pythonocc-core pip install trimesh いざコード作成 jupyterを起動してコードを書きました。 サンプルはIfcOpenHouseを使いました。 内容は以下の通り import ifcopenshell from ifcopenshell import geom import trimesh ifc_file = ifcopenshell.open("IfcOpenHouse_IFC2x3.ifc") settings = geom.settings() scene = trimesh.Scene() for ifc_entity in ifc_file.by_type("IfcProduct"): if ifc_entity.Representation: shape = geom.create_shape(settings, ifc_entity) ios_vertices = shape.geometry.verts ios_faces = shape.geometry.faces vertices = [[ios_vertices[i], ios_vertices[i+1], ios_vertices[i+2]] for i in range(0, len(ios_vertices), 3)] faces = [[ios_faces[i], ios_faces[i+1], ios_faces[i+2]] for i in range(0, len(ios_faces), 3)] mesh = trimesh.Trimesh(vertices=vertices, faces=faces) scene.add_geometry(mesh) scene.show() これで可視化出来る…はずだった ところが出てきたのはこんなやつだった まあ、こうなってしまうのはIfcOpenshellの方のコードが色々とおかしいんでしょう…ってことで、色々調べてみた結果、どうやら座標系の設定の方に問題があることが分かった。 と、いうわけでその設定を行うようにしたコードだと以下の通りになる。 import ifcopenshell from ifcopenshell import geom import trimesh # 3Dオブジェクトのシーングラフを作成 scene = trimesh.Scene() def read_geom(ifc_path): # ファイル読み込み ifc_file = ifcopenshell.open(ifc_path) settings = geom.settings() # ワールド座標系を設定する(この設定がないとさっきみたいに変な三角形メッシュが出力される) settings.set(settings.USE_WORLD_COORDS, True) # IfcProductのサブクラスを全部取得する for ifc_entity in ifc_file.by_type("IfcProduct"): if ifc_entity.is_a("IfcOpeningElement"): continue if ifc_entity.Representation: # 設定に基づいてメッシュデータを作成 shape = geom.create_shape(settings, ifc_entity) ios_vertices = shape.geometry.verts ios_faces = shape.geometry.faces # 出力した頂点リストと頂点インデックスのリストを整形 # どちらも要素3の配列が並んでる2次元配列に vertices = [[ios_vertices[i], ios_vertices[i+1], ios_vertices[i+2]] for i in range(0, len(ios_vertices), 3)] faces = [[ios_faces[i], ios_faces[i+1], ios_faces[i+2]] for i in range(0, len(ios_faces), 3)] # trimeshを使って頂点インデックスと頂点リストからメッシュを生成 mesh = trimesh.Trimesh(vertices=vertices, faces=faces) # メッシュをシーングラフに追加 scene.add_geometry(mesh) read_geom("IfcOpenHouse_IFC2x3.ifc") # シーングラフを可視化 scene.show() これをjupyter上で実行して得られた画像がこちら 参考にしたところ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pythonで英語or日本語を自動判定するには?

英日自動判定をする 少し前にとある課題でbotを作った際、受け取った文章を翻訳させるのに英語か日本語かを自動判定する必要がありました。 「英語→日本語」のようにキーワードを付けるのは趣旨的に合わず(翻訳というより通訳のイメージに近かったため)、話す前にボタンを押して貰うのは他の機能に干渉するためできず・・・ 調べたところ、どうやらPython内で英語と日本語を判定する方法が存在したらしいので備忘録として残しておきます。 参考にさせて頂いたサイト様 Pythonで、文字列に日本語が含まれているか判定する ありがとうございます。助かりました。 コード import unicodedata def are_you_japanese(word): for char in word: wordtype = unicodedata.name(char) if "CJK UNIFIED" in wordtype or "HIRAGANA" in wordtype or "KATAKANA" in wordtype: return True return False 解説 unicodedata unicodedataはユニコードデータベースを利用するためのモジュールで、unicode文字列の検索や数値を行うことができる標準ライブラリです。 for char in word これはunicodedata.nameが1文字だけしか受け取ることができないために1文字ずつfor文で回すようにしているようです。 ちなみに文字を指定(word[0]のように)してしまうと、その1文字がスペースであった場合等に「SPACE」のような「どれでもないもの」が返却されてしまい、正しい判定ができなくなってしまいます。 話を戻して、unicodedata.nameに複数の文字を挿入するとこうなります↓ こんなエラーが返ってきていますね TypeError: name() argument 1 must be a unicode character, not str name()には1つのユニコード文字が受け取られている必要があり、str型ではないとのことです。 これは簡単に言うと複数の文字を持ったstr型は判定できないというメッセージです。 無いとは思いますが、int型を入れると似たようなエラーが返却されます。 unicodedata.name(char) これは、受け取った文字列についている名前(CJK UNIFIEDとか)を返却する関数です。 漢字ならCJK UNIFIED ~~~、ひらがなならHIRAGANA LETTER ~、カタカナならKATAKANA LETTER ~のような形で返却されます。。 英語の場合は大文字なら「LATIN SMALL LETTER ~」、小文字なら「LATIN CAPITAL LETTER ~」のような形で返却されます。 例としてはこんな感じです↓ if "CJK UNIFIED"・・・ これは、関数で受け取った文字列が漢字、ひらがな、カタカナのどれかであればTrueを返すという条件分岐です。 当然、それらでなければFalseが返却されます。 unicodedata.nameは文字がひらがなか返すようなものではない 実はunicodedata.nameの返り値はその単語によって変わります。 例えば末尾の「A」とか「IDEOGRAPH-4E9C」とか・・・ 例えばこんな感じで↓ 「な」なら「HIRAGANA LETTER NA」、カタカナの「ニ」なら「KATAKANA LETTER NI」が、肇という漢字なら「CJK UNIFIED IDEOGRAPH-8087」が返っていますね。 これはunicodedata.nameの機能は言語判定ではなくユニコードデータベースで当てられている文字の名前を返却するものであるからです。 if文の判定が"CJK UNIFIED" == wordtype・・・ではなく"CJK UNIFIED" in wordtype・・・となっているのは、返却されるデータはその文字固有のものであるため、完全一致せずにfalseとなってしまうためです。 欠点は「中国語や朝鮮語判定はできない」 これは参考元のブログに記載されていたものなのですが、この関数では中国語or日本語の判定は不可能であるようです。 理由を調べてみたところ、漢字は「CJK UNIFIED~~」の形で返却されますが、CJK UNIFIEDは「CJK統合漢字」と呼ばれ、中国語、朝鮮語、日本語の漢字をひとまとめにしたコードだそうです。 なので、日本で使われていない漢字(中国だけとか)でもCJK UNIFIED ~~が返却されるという特性上、これはできないようです。 ちなみに、CJKは「Chinese」「Japanese」「Korean」の頭文字だそうです。 まとめ 簡単な英or日語判定をするならunicodedataモジュールが使える unicodedata.name()はユニコード表での名前を返却するものである 中国語or日本語のように、漢字を使う言語同士の判定では利用できない。 お疲れ様でした。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【ESP32入門】ESP8266との比較と追跡カメラを制御する♪

昨夜は、やっとesp32もうまくMicroPythonがインストールできたので、ここではesp8266との違いをまとめると共に、追跡カメラを動かしてみました。 やったこと ・インストールの違い ・見かけの違いと利用できるPinについて ・追跡カメラのコード ・インストールの違い esp8266とesp32のイントールコマンドは参考から以下のとおりです。 まず、flashの消去は同一のコマンドで消せる。 【参考】 ①deploying-the-firmware@Getting started with MicroPython on the ESP8266 ②deploying-the-firmware@Getting started with MicroPython on the ESP32 binのversionはともかく、それぞれ以下のコマンドです。 $ esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect 0 esp8266-20170108-v1.8.7.bin または、 (e.g. some variants of a NodeMCU board) 以下を推奨しています $ esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect -fm dio 0 esp8266-20170108-v1.8.7.bin 一方、esp32では、 $ esptool.py --chip esp32 --port /dev/ttyUSB0 write_flash -z 0x1000 esp32-20180511-v1.9.4.bin 当初、esp32でインストールできなかったのは、このコマンドが異なっていたことが原因です。しかし、異なったコマンドでも、同じように書込みが正常に終了します。 ただし、Thonnyに接続したり、以下のコマンドでSerialを開くと、 $ sudo screen /dev/ttyUSB0 115200 error flash read error 1000 が出て、このエラーはいろいろな理由で出ているようです。 今回はflashへの書き込みができていなかったためとかんがえられます。 以下の参考に解説がありますが、何が原因で正常な書き込みが出来ないのかは不明です。 ※--chipの指定と -z 0x1000の指定が必要だったのかなと思っていますが不明です 【参考】 ③ESP32でesptool.pyの使い方 ・見かけの違いと利用できるPinについて これは、アマゾンの販売サイトのesp8266の画像やesp32サイトからpin配置から両者の比較をしてみます。 まず、esp8266は、DiyStudio ESP8266 NodeMCU ESP-12E;アマゾンを利用しています。 一般的なpin配置図は以下のとおり ESP8266 Pinout Reference: Which GPIO pins should you use?より アマゾンより そして、上記サイトより これらの情報から、以下のように接続しています。 esp8266 mpu6050 servo Led GND GND GND GND Pin(3.3v) 3.3v - - PILO(4.2v) - + - Pin(5) SCL - - Pin(4) SDA - - PWM(Pin(0)) - Servo1(yellow) PWM(Pin(12)) - Servo2(yellow) Pin(14, Pin.OUT) - - led(+) wayintopのesp32は以下のとおり;アマゾンです。 esp8266 mpu6050 servo Led GND GND GND GND Pin(3.3v) 3.3v - - PILO(4.2v) - + - Pin(22) SCL - - Pin(21) SDA - - PWM(Pin(0)) - Servo1(yellow) PWM(Pin(2)) - Servo2(yellow) Pin(15, Pin.OUT) - - led(+) ・追跡カメラのコード ということで、追跡カメラのコードは以下の通りほぼ同じコードで動きました。 esp32の追跡カメラのコード from machine import Pin from machine import I2C from machine import PWM import time import math as mt class mpu6050: def __init__(self, scl, sda): self.scl = scl self.sda = sda self.i2c = I2C(0,scl = self.scl, sda = self.sda, freq = 100000) slv = self.i2c.scan() #print(slv) self.slvAddr = 104 # レジスタをリセットする self.writeByte(0x6B,0x80) time.sleep(0.1) # PWR_MGMT_1をクリア self.writeByte(0x6B,0x00) time.sleep(0.1) def readXYZ(self): data = self.readByte(0x3B ,6) x = (2.0 / 0x8000) * u2s(data[0] << 8 | data[1]) y = (2.0 / 0x8000) * u2s(data[2] << 8 | data[3]) z = (2.0 / 0x8000) * u2s(data[4] << 8 | data[5]) return (x,y,z) def readTemp(self): data = self.readByte(0x41 ,2) raw = data[0] << 8 | data[1] # 上位ビットが先 temp= u2s(raw)/340 + 36.53 return temp def readGyro(self): data = self.readByte(0x43 ,6) x = (250 / 0x8000) * u2s(data[0] << 8 | data[1]) y = (250 / 0x8000) * u2s(data[2] << 8 | data[3]) z = (250 / 0x8000) * u2s(data[4] << 8 | data[5]) return (x,y,z) def writeByte(self, addr, data): d = bytearray([data]) self.i2c.writeto_mem(self.slvAddr, addr, d) def readByte(self, addr, num): s = self.i2c.readfrom_mem(self.slvAddr, addr, num) return s #unsignedを、signedに変換(16ビット限定) def u2s(unsigneddata): if unsigneddata & (0x01 << 15) : return -1 * ((unsigneddata ^ 0xffff) + 1) return unsigneddata def get_angle(rawX, rawY, rawZ): pitch = mt.degrees(mt.atan2(rawX, mt.sqrt(rawY*rawY+rawZ*rawZ))) roll = mt.degrees(mt.atan2(rawY, rawZ)) return pitch, roll if __name__ == "__main__": start = time.time() scl = Pin(22) sda = Pin(21) servo1 = PWM(Pin(0)) servo2 = PWM(Pin(2)) servo1.freq(100) servo2.freq(100) led_onboard = Pin(15, Pin.OUT) snsr = mpu6050(scl, sda) f = open('write1.txt', 'wb') f.write('t: pitch: zg_: ' + ' \n') xg_,yg_,zg_ = 0,0,0 x0,y0,z0 = snsr.readXYZ() z0 = z0 - 1 try: while True: t = time.time()- start #print(t) x1,y1,z1 = snsr.readXYZ() x, y, z = x1-x0,y1-y0,z1-z0 xg,yg,zg = snsr.readGyro() pitch, roll = get_angle(x,y,z) xg_ += xg yg_ += yg zg_ += zg #print('xg_,yg_,zg_=',xg_,yg_,zg_) print(zg,zg_,pitch) duty = int(150 - pitch) duty1 = int(150 - zg_) #int(roll) #print(duty, duty1) servo1.duty(duty1) servo2.duty(duty) led_onboard.on() f.write('{}'.format(t)+ ' ') f.write('{0:.2f} {1:.2f}'.format(pitch,zg_)+'\n') time.sleep(0.8) led_onboard.off() time.sleep(0.2) except KeyboardInterrupt: pass finally: f.close() pass 一方、ブレッドボードの様子は以下のとおり、ぎりぎりです。 GNDや電源供給は、外部電源のLIPOや外回りに逃がして確保しています。 まとめ ・esp8266とesp32のインストールの違いを明らかにし、安定してインストールしてRaspi4及びwindows上のThonnyにてMicroPythonで開発が出来るようになった ・結線のpinについて明らかにし、追跡カメラのコードを移植できた ・picoに比較して優位な機能である通信機能を利用して外部から制御したいと思う おまけ $ esptool.py -h usage: esptool [-h] [--chip {auto,esp8266,esp32,esp32s2,esp32s3beta2,esp32c3}] [--port PORT] [--baud BAUD] [--before {default_reset,no_reset,no_reset_no_sync}] [--after {hard_reset,soft_reset,no_reset}] [--no-stub] [--trace] [--override-vddsdio [{1.8V,1.9V,OFF}]] [--connect-attempts CONNECT_ATTEMPTS] {load_ram,dump_mem,read_mem,write_mem,write_flash,run,image_info,make_image,elf2image,read_mac,chip_id,flash_id,read_flash_status,write_flash_status,read_flash,verify_flash,erase_flash,erase_region,version,get_security_info} ... esptool.py v3.0 - ESP8266 ROM Bootloader Utility positional arguments: {load_ram,dump_mem,read_mem,write_mem,write_flash,run,image_info,make_image,elf2image,read_mac,chip_id,flash_id,read_flash_status,write_flash_status,read_flash,verify_flash,erase_flash,erase_region,version,get_security_info} Run esptool {command} -h for additional help load_ram Download an image to RAM and execute dump_mem Dump arbitrary memory to disk read_mem Read arbitrary memory location write_mem Read-modify-write to arbitrary memory location write_flash Write a binary blob to flash run Run application code in flash image_info Dump headers from an application image make_image Create an application image from binary files elf2image Create an application image from ELF file read_mac Read MAC address from OTP ROM chip_id Read Chip ID from OTP ROM flash_id Read SPI flash manufacturer and device ID read_flash_status Read SPI flash status register write_flash_status Write SPI flash status register read_flash Read SPI flash content verify_flash Verify a binary blob against flash erase_flash Perform Chip Erase on SPI flash erase_region Erase a region of the flash version Print esptool version get_security_info Get some security-related data optional arguments: -h, --help show this help message and exit --chip {auto,esp8266,esp32,esp32s2,esp32s3beta2,esp32c3}, -c {auto,esp8266,esp32,esp32s2,esp32s3beta2,esp32c3} Target chip type --port PORT, -p PORT Serial port device --baud BAUD, -b BAUD Serial port baud rate used when flashing/reading --before {default_reset,no_reset,no_reset_no_sync} What to do before connecting to the chip --after {hard_reset,soft_reset,no_reset}, -a {hard_reset,soft_reset,no_reset} What to do after esptool.py is finished --no-stub Disable launching the flasher stub, only talk to ROM bootloader. Some features will not be available. --trace, -t Enable trace-level output of esptool.py interactions. --override-vddsdio [{1.8V,1.9V,OFF}] Override ESP32 VDDSDIO internal voltage regulator (use with care) --connect-attempts CONNECT_ATTEMPTS Number of attempts to connect, negative or 0 for infinite. Default: 7.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【ESP32入門】ESP8266との比較と追跡カメラを制御する♪ ~flash read error 1000の解決~

昨夜は、やっとesp32もうまくMicroPythonがインストールできたので、ここではesp8266との違いをまとめると共に、追跡カメラを動かしてみました。 やったこと ・インストールの違い ・見かけの違いと利用できるPinについて ・追跡カメラのコード ・インストールの違い esp8266とesp32のイントールコマンドは参考から以下のとおりです。 まず、flashの消去は同一のコマンドで消せる。 【参考】 ①deploying-the-firmware@Getting started with MicroPython on the ESP8266 ②deploying-the-firmware@Getting started with MicroPython on the ESP32 binのversionはともかく、それぞれ以下のコマンドです。 $ esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect 0 esp8266-20170108-v1.8.7.bin または、 (e.g. some variants of a NodeMCU board) 以下を推奨しています $ esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect -fm dio 0 esp8266-20170108-v1.8.7.bin 一方、esp32では、 $ esptool.py --chip esp32 --port /dev/ttyUSB0 write_flash -z 0x1000 esp32-20180511-v1.9.4.bin 当初、esp32でインストールできなかったのは、このコマンドが異なっていたことが原因です。しかし、異なったコマンドでも、同じように書込みが正常に終了します。 ただし、Thonnyに接続したり、以下のコマンドでSerialを開くと、 $ sudo screen /dev/ttyUSB0 115200 error flash read error 1000 が出て、このエラーはいろいろな理由で出ているようですが、エラーの意味は、 Then it basicly tells you, it cant read from addres 0x1000, ということのようです。 ということで、write_flash -z 0x1000が効果があったと言えると思います。 例えば、以下の例 ③flash read err, 1000 (IDFGH-807) #113 つまり、今回はflashへの書き込みができていなかったためとかんがえられます。 以下の参考にesptool.pyの解説がありますが、この解説からは何が原因で正常な書き込みが出来ないのかは明確にはなりません。 ※上記と合わせると、--chipの指定と -z 0x1000の指定が必要だったのかなと思います 【参考】 ④ESP32でesptool.pyの使い方 ・見かけの違いと利用できるPinについて これは、アマゾンの販売サイトのesp8266の画像やesp32サイトからpin配置から両者の比較をしてみます。 まず、esp8266は、DiyStudio ESP8266 NodeMCU ESP-12E;アマゾンを利用しています。 一般的なpin配置図は以下のとおり ESP8266 Pinout Reference: Which GPIO pins should you use?より アマゾンより そして、上記サイトより これらの情報から、以下のように接続しています。 esp8266 mpu6050 servo Led GND GND GND GND Pin(3.3v) 3.3v - - PILO(4.2v) - + - Pin(5) SCL - - Pin(4) SDA - - PWM(Pin(0)) - Servo1(yellow) PWM(Pin(12)) - Servo2(yellow) Pin(14, Pin.OUT) - - led(+) wayintopのesp32は以下のとおり;アマゾンです。 esp32 mpu6050 servo Led GND GND GND GND Pin(3.3v) 3.3v - - PILO(4.2v) - + - Pin(22) SCL - - Pin(21) SDA - - PWM(Pin(0)) - Servo1(yellow) PWM(Pin(2)) - Servo2(yellow) Pin(15, Pin.OUT) - - led(+) ・追跡カメラのコード ということで、追跡カメラのコードは以下の通りほぼ同じコードで動きました。 esp32の追跡カメラのコード from machine import Pin from machine import I2C from machine import PWM import time import math as mt class mpu6050: def __init__(self, scl, sda): self.scl = scl self.sda = sda self.i2c = I2C(0,scl = self.scl, sda = self.sda, freq = 100000) slv = self.i2c.scan() #print(slv) self.slvAddr = 104 # レジスタをリセットする self.writeByte(0x6B,0x80) time.sleep(0.1) # PWR_MGMT_1をクリア self.writeByte(0x6B,0x00) time.sleep(0.1) def readXYZ(self): data = self.readByte(0x3B ,6) x = (2.0 / 0x8000) * u2s(data[0] << 8 | data[1]) y = (2.0 / 0x8000) * u2s(data[2] << 8 | data[3]) z = (2.0 / 0x8000) * u2s(data[4] << 8 | data[5]) return (x,y,z) def readTemp(self): data = self.readByte(0x41 ,2) raw = data[0] << 8 | data[1] # 上位ビットが先 temp= u2s(raw)/340 + 36.53 return temp def readGyro(self): data = self.readByte(0x43 ,6) x = (250 / 0x8000) * u2s(data[0] << 8 | data[1]) y = (250 / 0x8000) * u2s(data[2] << 8 | data[3]) z = (250 / 0x8000) * u2s(data[4] << 8 | data[5]) return (x,y,z) def writeByte(self, addr, data): d = bytearray([data]) self.i2c.writeto_mem(self.slvAddr, addr, d) def readByte(self, addr, num): s = self.i2c.readfrom_mem(self.slvAddr, addr, num) return s #unsignedを、signedに変換(16ビット限定) def u2s(unsigneddata): if unsigneddata & (0x01 << 15) : return -1 * ((unsigneddata ^ 0xffff) + 1) return unsigneddata def get_angle(rawX, rawY, rawZ): pitch = mt.degrees(mt.atan2(rawX, mt.sqrt(rawY*rawY+rawZ*rawZ))) roll = mt.degrees(mt.atan2(rawY, rawZ)) return pitch, roll if __name__ == "__main__": start = time.time() scl = Pin(22) sda = Pin(21) servo1 = PWM(Pin(0)) servo2 = PWM(Pin(2)) servo1.freq(100) servo2.freq(100) led_onboard = Pin(15, Pin.OUT) snsr = mpu6050(scl, sda) f = open('write1.txt', 'wb') f.write('t: pitch: zg_: ' + ' \n') xg_,yg_,zg_ = 0,0,0 x0,y0,z0 = snsr.readXYZ() z0 = z0 - 1 try: while True: t = time.time()- start #print(t) x1,y1,z1 = snsr.readXYZ() x, y, z = x1-x0,y1-y0,z1-z0 xg,yg,zg = snsr.readGyro() pitch, roll = get_angle(x,y,z) xg_ += xg yg_ += yg zg_ += zg #print('xg_,yg_,zg_=',xg_,yg_,zg_) print(zg,zg_,pitch) duty = int(150 - pitch) duty1 = int(150 - zg_) #int(roll) #print(duty, duty1) servo1.duty(duty1) servo2.duty(duty) led_onboard.on() f.write('{}'.format(t)+ ' ') f.write('{0:.2f} {1:.2f}'.format(pitch,zg_)+'\n') time.sleep(0.8) led_onboard.off() time.sleep(0.2) except KeyboardInterrupt: pass finally: f.close() pass 一方、ブレッドボードの様子は以下のとおり、ぎりぎりです。 GNDや電源供給は、外部電源のLIPOや外回りに逃がして確保しています。 まとめ ・esp8266とesp32のインストールの違いを明らかにし、安定してインストールしてRaspi4及びwindows上のThonnyにてMicroPythonで開発が出来るようになった ・結線のpinについて明らかにし、追跡カメラのコードを移植できた ・picoに比較して優位な機能である通信機能を利用して外部から制御したいと思う おまけ $ esptool.py -h usage: esptool [-h] [--chip {auto,esp8266,esp32,esp32s2,esp32s3beta2,esp32c3}] [--port PORT] [--baud BAUD] [--before {default_reset,no_reset,no_reset_no_sync}] [--after {hard_reset,soft_reset,no_reset}] [--no-stub] [--trace] [--override-vddsdio [{1.8V,1.9V,OFF}]] [--connect-attempts CONNECT_ATTEMPTS] {load_ram,dump_mem,read_mem,write_mem,write_flash,run,image_info,make_image,elf2image,read_mac,chip_id,flash_id,read_flash_status,write_flash_status,read_flash,verify_flash,erase_flash,erase_region,version,get_security_info} ... esptool.py v3.0 - ESP8266 ROM Bootloader Utility positional arguments: {load_ram,dump_mem,read_mem,write_mem,write_flash,run,image_info,make_image,elf2image,read_mac,chip_id,flash_id,read_flash_status,write_flash_status,read_flash,verify_flash,erase_flash,erase_region,version,get_security_info} Run esptool {command} -h for additional help load_ram Download an image to RAM and execute dump_mem Dump arbitrary memory to disk read_mem Read arbitrary memory location write_mem Read-modify-write to arbitrary memory location write_flash Write a binary blob to flash run Run application code in flash image_info Dump headers from an application image make_image Create an application image from binary files elf2image Create an application image from ELF file read_mac Read MAC address from OTP ROM chip_id Read Chip ID from OTP ROM flash_id Read SPI flash manufacturer and device ID read_flash_status Read SPI flash status register write_flash_status Write SPI flash status register read_flash Read SPI flash content verify_flash Verify a binary blob against flash erase_flash Perform Chip Erase on SPI flash erase_region Erase a region of the flash version Print esptool version get_security_info Get some security-related data optional arguments: -h, --help show this help message and exit --chip {auto,esp8266,esp32,esp32s2,esp32s3beta2,esp32c3}, -c {auto,esp8266,esp32,esp32s2,esp32s3beta2,esp32c3} Target chip type --port PORT, -p PORT Serial port device --baud BAUD, -b BAUD Serial port baud rate used when flashing/reading --before {default_reset,no_reset,no_reset_no_sync} What to do before connecting to the chip --after {hard_reset,soft_reset,no_reset}, -a {hard_reset,soft_reset,no_reset} What to do after esptool.py is finished --no-stub Disable launching the flasher stub, only talk to ROM bootloader. Some features will not be available. --trace, -t Enable trace-level output of esptool.py interactions. --override-vddsdio [{1.8V,1.9V,OFF}] Override ESP32 VDDSDIO internal voltage regulator (use with care) --connect-attempts CONNECT_ATTEMPTS Number of attempts to connect, negative or 0 for infinite. Default: 7.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PythonでbitDPを使い巡回セールスマン問題を解く

PythonでbitDPを使って巡回セールスマン問題を解く記事を探したところ、あまり見当たらなかったため備忘録がてら投稿します。また、重み付き有向グラフについては知っていることを前提としています。 注意点として、自分にとってわかりやすいかを基準にしているため、厳密でない、わかりにくい場合があります... 問題リンク AOJ Traveling Salesman Problem もしAtCoderにも同様の問題がありましたら教えていただけると幸いです... 問題の要点 最初に問題の要点だけ書いておきます。 まず、タイムリミットは1 sec, メモリの上限は131072 KBです。2 secではありません。 重み付きの有向グラフが与えられる。このとき、以下の二つを満たす経路のうち、通った辺の重みの総和が最小のものを求めよ(最小の重みを出力する)。ただし、そのような経路が存在しない場合は-1を出力せよ。 ・ある頂点から出発し、最後には戻ってくる経路である ・すべての頂点をちょうど1回通る経路である(すべての頂点を通る必要があるが、2回以上同じ頂点を通ってはいけない) 入力形式は V E s0 t0 d0 s1 t1 d1 : sE-1 tE-1 dE-1 となっており、Vは頂点の数、Eは辺の数、si, ti, diは頂点siから頂点tiに向かって重みがdiの辺が張られていることを表しています。 制約は 2 ≤ V ≤ 15 0 ≤ E ≤ V(V-1) 0 ≤ si, ti ≤ V-1 (si ≠ ti) 0 ≤ di ≤ 1000 与えられるグラフに多重辺はない となっています。Eの制約は明記されていませんが、与えられるグラフは多重辺を持たないと書いてあるので、V(V-1)(無向グラフの場合はV(V-1)/2だが、有向グラフなので、siとtiを入れ替えた辺が存在する可能性もあるため/2する必要がない)であると言えます。(実際、E > V(V-1)の場合exitする処理を追加したコードでもACが取れました。また、E = 0の場合も同様にexitするコードを提出した際WAになったため、この制約でおそらく間違いはないでしょう) bitDPって何? bitDPは、集合に対するDPと言われることがあります。少し具体的にいうと、N個の要素の順列の中で最も適切な順列を効率的に求めたい時に使うことが多いようです。N個の要素の順列を愚直に処理すると、順列はN!通りあるため、計算量はO(N×N!)となり、この問題はタイムリミットが1 secなので、PyPyではNが10のときが限界なってしまいます。しかし、例えばこの問題ではbitDPを用いると計算量をO(n^2×2^n)まで落とすことができ、Nが19まではギリギリ通すことができます。今回はN ≤ 15なので、余裕を持って通すことができます。 今回の問題では実際にどんなDPになるかというと、 DP[S][v] := 集合の全体のうちの部分集合Sの順列の中で、vが末項となるもののうち、最も最適なもののコスト(順列の評価方法は、その順列の通りの順番で頂点を通った時の重みの総和の低さで、最適な順列とは条件を満たすすべての順列の中で最も重みの総和が低いもの) となります。このとき、Sとはbitで表された集合です。集合をbitで表すのでbitDPと呼ばれているわけですね。ですので、Sの上限は2^V-1となります。また、末項で分ける理由として、例えば集合{1, 2, 5}の順列のうち末項が2であるものは{1, 5, 2}, {5, 1, 2}の2つですが、どちらとも状況としては「頂点1と5はすでに通っており、現在は頂点2にいる」と言えるため、このうち最もコストが低いものだけを考えることで効率化できるためです。 注意点 さて、プログラムに落とし込む前に1つ注意点があります。それはどの頂点から出発したかの判定の部分です。これは単純で、常に頂点0から出発したことにすればよいです。 例えば、上の図のような順番で頂点を通ったとき、出発地点が4であっても2であっても0であっても(勿論他の頂点であったとしても)、出発地点まで戻るまでのコストは変わりません。なので、出発地点を0で固定したとしても問題ありません。 実際のプログラム まず実際のプログラムにコメントを追加したものを載せておきます。今回は配るDPを使用しました。また、①〜⑤はそれぞれプログラムの下に少し詳しく説明を書いています。 V, E = map(int,input().split()) G = [[float('inf')]*V for i in range(V)] # 存在しないパスはinfになるように、最初にすべてinfにしておく for i in range(E): s,t,d = map(int,input().split()) G[s][t] = d # s,tは0以上V-1以下なので、デクリメントの必要はない dp = [[float('inf')]*V for i in range(2**V)] # dpの長さは2^V必要 dp[0][0] = 0 # 0から出発するのでdp[0][0]を0にしておく for S in range(2**V): # Sは集合をbitで表している for v in range(V): # vは配られる側の要素を表している for u in range(V): # uは配る側の要素を表している if not (S >> u) & 1 and S != 0: # ① continue if (S >> v) & 1 == 0: # ② if dp[S][u] + G[u][v] < dp[S | (1 << v)][v]: dp[S | (1 << v)][v] = dp[S][u] + G[u][v] # ③ # 全ての要素が含まれていて、末項が0のものの最小コストを出力する # infだった場合は到達できないということなので-1を出力する if dp[2**V-1][0] != float('inf'): print(dp[2**V-1][0]) else: print(-1) このプログラムでは、vは配られる側の要素を表し、uは配る側の要素を表しています。今回、要素とは頂点のことであるため、v,uには0〜V-1が入ります。 ①このプログラムではuが配る側の要素を表しているため、そもそもSのu番目のbitが立っていない、つまりu番目の頂点には到達していない場合、u番目の頂点から配ることはできません。しかし、今回は配るDPを使用しているため、sが0の時は例外的に処理をする必要があります。そうしないと、dp[0][0]以外全てinfのままになってしまいます。ですので、この部分は日本語で、「u番目の頂点に訪れている、あるいはどこの頂点にも訪れていない場合は続きの処理をし、そうでない場合は今回のループではこれ以上の処理をせず、次のループに移る」と表すことができます。 ②今回、vは配られる側であり、Sのv番目のbitが立っているということはすでにv番目の頂点には訪れているということであるため、出発地点を除いた頂点を2回以上訪れてはいけないという条件から、処理をする必要はありません。ですので、この部分ではSのv番目のbitが立っていない場合のみ続きの処理をするようにしています。 ③これは、dpを更新しているだけです。dp[S][v]にはbitで表された集合Sの順列のうち、末項がvであるものの最小コストが代入されているため、そのような順列のなかで、これまで記録されていた最小コストよりも少ないコストの順列を見つけることができた場合そのコストを記録しています。先にも説明しましたが、順列を保存する必要はなく、集合Sと末項vのみがわかればいいため、このようなdpリストになっています。 最後に 今回、初めての競プロ記事ということもありかなりゴチャゴチャした記事になってしまっています(極力スッキリはさせたつもりですが...)。ですが、もしどなたかの参考になったなら幸いです。 参考文献 今回の記事を書くにあたって、以下の二つの記事を参考にさせていただきました。ありがとうございます。 ビットDP(bit DP)の考え方 ~集合に対する動的計画法~ ビット演算 (bit 演算) の使い方を総特集! 〜 マスクビットから bit DP まで 〜
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LeetCodeWeekly240 C 1856. Maximum Subarray Min-Product ヒストグラム内の最大長方形の変形

題意 配列の連続した部分列の和 $ \times$ その区間の最小値 の最大値を求めよ 例: $[2,3,3,1,2]$の場合、[3,3]は和6 $times$ min3で18が答えとなる こう考えた ヒストグラムの最大長方形問題に帰着できます。次に図を示します。 上の絵が$[2,3,3]$を選択したとき。下の絵が$[3,3]$を選んだ時です。 ある要素$x$があった時、和がとられることを考えると、長さ$1$の長方形が$x$あると考えてよいです。 実装 さて、要素の数が十分に小さければ、図のようなヒストグラムを実際に配列としてつくって計算しても良いですが、大きい数だと配列が作れません。そのため、区間の和を$O(N)$で求められるように累積和を作ります。 ヒストグラムの最大化の面積を求める際、通常は ある部分の高さ $ \times $ 区間のindexの差 を取りますが、今回は、 ある部分の高さ $ \times $ 区間のindexの間の累積和 を使います。 ############################################ from collections import deque from typing import Deque from typing import List, Tuple from pprint import pprint class Rect: def __init__(self, height, pos): self.height = height self.pos = pos def solve(h: [int]): # 拾い物 の ヒストグラム最大化 ライブラリ stack: Deque[Rect] = deque() histogram = h + [0] max_area = 0 # ここに累積和を足す import itertools def createSDAT(l): return list(itertools.accumulate(itertools.chain([0], l))) sdat = createSDAT(h) squery = lambda a, b: sdat[b] - sdat[a] # query [a, b) for idx, height in enumerate(histogram): if not stack or stack[-1].height < height: stack.append(Rect(height=height, pos=idx)) elif stack[-1].height > height: top = Rect(height=0, pos=0) while stack and stack[-1].height > height: top = stack.pop() # ここは通常、今の位置 - heightのposだが、ここを、その間のブロックの和にする #max_area = max(max_area, (idx - top.pos) * top.height) max_area = max(max_area, squery(top.pos, idx) * top.height) stack.append(Rect(height=height, pos=top.pos)) return max_area ############################################ class Solution: def maxSumMinProduct(self, nums: List[int]) -> int: res = solve(nums) % (10**9+7) return (res)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Djangoでfirst commitするまでのメモ

たまに作る時用にメモ 前提事項 プロジェクト名:hogehoge プロジェクトのディレクトリを作成 $ mkdir hogehoge Pycharmでプロジェクト作成 [New Project]を選択 Pure Pythonでプロジェクトを作成 ※Djangoでプロジェクトを作成するとプロジェクトディレクトリ名をプロジェクト名が一緒になってしまうから  ディレクトリ名はhogehogeでプロジェクト名はconfigにしておきたい ・Locationはさっき作ったディレクトリを指定 ・create main.py welcome scriptのチェックボックスは外しておく Preferenceを開く(⌘,) Project:hogehoge > Python Interpreter から以下のパッケージをインストール ※インストール時にはSpecify Versionにチェックをいれて、バージョン固定をする(個人のお好きにどうぞ) django django-environ mysqlclient Pycharm内のタブからTerminalを開き、以下のコマンドを実行 (hogehoge) user ​hogehoge % django-admin startproject config . (hogehoge) user ​hogehoge % touch .env (hogehoge) user ​hogehoge % mkdir config/settings (hogehoge) user ​hogehoge % mv config/settings.py config/settings/_base.py (hogehoge) user ​hogehoge % touch config/settings/local.py config/settings/production.py (hogehoge) user ​hogehoge % touch .gitignore .envを更新 空白とシングルクォーテーションは必要ないことに注意 .env # Secret Key SECRET_KEY=django-insecure-hjgklfd..... # MySQL settings DATABASE_URL=mysql://[username]:[password]@127.0.0.1:3306/[databasename]?charset=utf8mb4&sql_mode=TRADITIONAL,NO_AUTO_VALUE_ON_ZERO コンフィグファイルを更新する 細かいところは自分のお好きに settings/_base.py import os ############### # Build paths # ############### BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) PROJECT_NAME = os.path.basename(BASE_DIR) # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'config.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [ os.path.join(BASE_DIR, 'templates'), ], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] WSGI_APPLICATION = 'config.wsgi.application' # Password validation # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/3.2/topics/i18n/ LANGUAGE_CODE = 'ja' TIME_ZONE = 'Asia/Tokyo' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.2/howto/static-files/ STATIC_URL = '/static/' STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')] STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') # Default primary key field type # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' settings/local.py from ._base import * import environ # Read .env if exists env = environ.Env() env.read_env(os.path.join(BASE_DIR, '.env')) ##################### # Security settings # ##################### SECRET_KEY = env('SECRET_KEY') DEBUG = True ALLOWED_HOSTS = [] ############ # Database # ############ DATABASES = { 'default': env.db() } ########### # Logging # ########### LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'filters': { 'require_debug_false': { '()': 'django.utils.log.RequireDebugFalse', }, 'require_debug_true': { '()': 'django.utils.log.RequireDebugTrue', }, }, 'formatters': { 'django.server': { '()': 'django.utils.log.ServerFormatter', 'format': '[%(server_time)s] %(message)s a', }, 'verbose': { 'format': '%(levelname)s %(asctime)s %(module)s ' '%(process)d %(thread)d %(message)s' }, # 開発用 'develop': { 'format': '%(asctime)s [%(levelname)s] %(pathname)s:%(lineno)d ' '%(message)s' }, }, 'handlers': { 'console': { 'level': 'INFO', 'filters': ['require_debug_true'], 'class': 'logging.StreamHandler', 'formatter': 'verbose', }, 'django.server': { 'level': 'INFO', 'class': 'logging.StreamHandler', 'formatter': 'django.server', }, 'mail_admins': { 'level': 'ERROR', 'filters': ['require_debug_false'], 'class': 'django.utils.log.AdminEmailHandler' } }, 'loggers': { 'django': { 'handlers': ['console', 'mail_admins'], 'level': 'INFO', }, 'django.server': { 'handlers': ['django.server'], 'level': 'INFO', 'propagate': False, }, } } settings/production.py from ._base import * import environ # Read .env if exists env = environ.Env() env.read_env(os.path.join(BASE_DIR, '.env')) ##################### # Security settings # ##################### SECRET_KEY = env('SECRET_KEY') DEBUG = False ALLOWED_HOSTS = ['*'] ############ # Database # ############ DATABASES = { 'default': env.db() } ########### # Logging # ########### LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'filters': { 'require_debug_false': { '()': 'django.utils.log.RequireDebugFalse', }, 'require_debug_true': { '()': 'django.utils.log.RequireDebugTrue', }, }, 'formatters': { 'django.server': { '()': 'django.utils.log.ServerFormatter', 'format': '[%(server_time)s] %(message)s a', }, 'verbose': { 'format': '%(levelname)s %(asctime)s %(module)s ' '%(process)d %(thread)d %(message)s' }, # 開発用 'develop': { 'format': '%(asctime)s [%(levelname)s] %(pathname)s:%(lineno)d ' '%(message)s' }, }, 'handlers': { 'console': { 'level': 'INFO', 'filters': ['require_debug_true'], 'class': 'logging.StreamHandler', 'formatter': 'verbose', }, 'django.server': { 'level': 'INFO', 'class': 'logging.StreamHandler', 'formatter': 'django.server', }, 'mail_admins': { 'level': 'ERROR', 'filters': ['require_debug_false'], 'class': 'django.utils.log.AdminEmailHandler' } }, 'loggers': { 'django': { 'handlers': ['console', 'mail_admins'], 'level': 'INFO', }, 'django.server': { 'handlers': ['django.server'], 'level': 'INFO', 'propagate': False, }, } } manage.pyを更新 manage.py - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.local') ローカルのMySQLにdatabaseを作成する .envのDATABASE_URLに記載したdatabasenameで作成すること .gitignoreを作成する gitignore.ioで作成 ワードは[Pycharm][Python][Django]など https://www.toptal.com/developers/gitignore 作成されたテキストを.gitignoreに貼り付ける 確認用の簡単なページを作成する staticファイルちゃんと使えるかとか最低限のとこは見とく URL追加 config/urls.py from django.contrib import admin from django.urls import path from django.views.generic import TemplateView urlpatterns = [ path('admin/', admin.site.urls), path('', TemplateView.as_view(template_name='home.html'), name='home'), ] template&staticファイルを作成 (hogehoge) user hogehoge % mkdir templates (hogehoge) user hogehoge % touch templates/_base.html (hogehoge) user hogehoge % touch templates/home.html (hogehoge) user hogehoge % mkdir -p static/css (hogehoge) user hogehoge % mkdir -p static/js (hogehoge) user hogehoge % touch static/css/home.css (hogehoge) user hogehoge % touch static/js/home.js templates/_base.html <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>{% block head_title %}{% endblock %}</title> {% block extra_css %}{% endblock %} {% block extra_js %}{% endblock %} </head> <body> {% block content %}{% endblock %} </body> </html> templates/home.html {% extends "_base.html" %} {% load static %} {% block head_title %}ホーム | hogehoge{% endblock %} {% block extra_css %} <link rel="stylesheet" href="{% static 'css/home.css' %}"> {% endblock %} {% block extra_js %} <script src="{% static 'js/home.js' %}"></script> {% endblock %} {% block content %} <h1 onclick="h1Click()">Hello World!</h1> {% endblock %} static/css/home.css h1 { color: blue; } static/js/home.js function h1Click(){ alert('h1 Click'); } ここでサーバー起動してみる (hogehoge) user hogehoge % python manage.py runserver 無事にサーバー起動ができて、css&jsがきちんと効いていることが確認できたらGitHubにプッシュする GitHubにプッシュ GitHub上にhogehogeプロジェクトを作成しておくこと (hogehoge) user hogehoge % git init (hogehoge) user hogehoge % git add . (hogehoge) user hogehoge % git commit -m "first commit" (hogehoge) user hogehoge % git branch -M main (hogehoge) user hogehoge % git remote add origin git@github.com:[project]/hogehoge.git (hogehoge) user hogehoge % git push -u origin main 後はいい感じに開発していく
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PyCharm&Djangoでfirst commitするまでのメモ

たまに作る時用にメモ DjangoはstartprojectしてそのままコミットするとSECRET_KEYも含まれてしまうので、その辺りも考慮して作成。 前提事項 プロジェクト名:hogehoge プロジェクトのディレクトリを作成 $ mkdir hogehoge PyCharmでプロジェクト作成 [New Project]を選択 Pure Pythonでプロジェクトを作成 ※Djangoでプロジェクトを作成するとベースディレクトリ名と設定ディレクトリ名が一緒になってしまうから  ベースディレクトリ名はhogehogeで設定ディレクトリ名はconfigにしておきたい ・Locationはさっき作ったディレクトリを指定 ・create main.py welcome scriptのチェックボックスは外しておく Preferenceを開く(⌘,) Project:hogehoge > Python Interpreter から以下のパッケージをインストール ※インストール時にはSpecify Versionにチェックをいれて、バージョン固定をする(個人のお好きにどうぞ) django django-environ mysqlclient 設定ファイルの構成を変更 PyCharm内のタブからTerminalを開き、以下のコマンドを実行 (hogehoge) user ​hogehoge % django-admin startproject config . (hogehoge) user ​hogehoge % touch .env (hogehoge) user ​hogehoge % mkdir config/settings (hogehoge) user ​hogehoge % mv config/settings.py config/settings/_base.py (hogehoge) user ​hogehoge % touch config/settings/local.py config/settings/production.py (hogehoge) user ​hogehoge % touch .gitignore .envを更新 変数定義の際、空白とシングルクォーテーションは必要ないことに注意 .env # Secret Key SECRET_KEY=django-insecure-hjgklfd..... # MySQL settings DATABASE_URL=mysql://[username]:[password]@127.0.0.1:3306/[databasename]?charset=utf8mb4&sql_mode=TRADITIONAL,NO_AUTO_VALUE_ON_ZERO コンフィグファイルを更新する 細かいところは自分のお好きに settings/_base.py import os ############### # Build paths # ############### BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) PROJECT_NAME = os.path.basename(BASE_DIR) # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'config.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [ os.path.join(BASE_DIR, 'templates'), ], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] WSGI_APPLICATION = 'config.wsgi.application' # Password validation # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/3.2/topics/i18n/ LANGUAGE_CODE = 'ja' TIME_ZONE = 'Asia/Tokyo' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.2/howto/static-files/ STATIC_URL = '/static/' STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')] STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') # Default primary key field type # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' settings/local.py from ._base import * import environ # Read .env if exists env = environ.Env() env.read_env(os.path.join(BASE_DIR, '.env')) ##################### # Security settings # ##################### SECRET_KEY = env('SECRET_KEY') DEBUG = True ALLOWED_HOSTS = [] ############ # Database # ############ DATABASES = { 'default': env.db() } settings/production.py from ._base import * import environ # Read .env if exists env = environ.Env() env.read_env(os.path.join(BASE_DIR, '.env')) ##################### # Security settings # ##################### SECRET_KEY = env('SECRET_KEY') DEBUG = False ALLOWED_HOSTS = ['*'] ############ # Database # ############ DATABASES = { 'default': env.db() } manage.pyを更新 manage.py - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.local') ローカルのMySQLにdatabaseを作成する .envのDATABASE_URLに記載したdatabasenameで作成すること $ mysql.server start $ mysql -u [username] -p mysql> create database [databasename]; .gitignoreを作成する gitignore.ioで作成 ワードは[PyCharm][Python][Django]など https://www.toptal.com/developers/gitignore 作成されたテキストを.gitignoreに貼り付ける 確認用の簡単なページを作成する staticファイルちゃんと使えるかとか最低限のとこは見とく URL追加 config/urls.py from django.contrib import admin from django.urls import path from django.views.generic import TemplateView urlpatterns = [ path('admin/', admin.site.urls), path('', TemplateView.as_view(template_name='home.html'), name='home'), ] template&staticファイルを作成 (hogehoge) user hogehoge % mkdir templates (hogehoge) user hogehoge % touch templates/_base.html (hogehoge) user hogehoge % touch templates/home.html (hogehoge) user hogehoge % mkdir -p static/css (hogehoge) user hogehoge % mkdir -p static/js (hogehoge) user hogehoge % touch static/css/home.css (hogehoge) user hogehoge % touch static/js/home.js templates/_base.html <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>{% block head_title %}{% endblock %}</title> {% block extra_css %}{% endblock %} {% block extra_js %}{% endblock %} </head> <body> {% block content %}{% endblock %} </body> </html> templates/home.html {% extends "_base.html" %} {% load static %} {% block head_title %}ホーム | hogehoge{% endblock %} {% block extra_css %} <link rel="stylesheet" href="{% static 'css/home.css' %}"> {% endblock %} {% block extra_js %} <script src="{% static 'js/home.js' %}"></script> {% endblock %} {% block content %} <h1 onclick="h1Click()">Hello World!</h1> {% endblock %} static/css/home.css h1 { color: blue; } static/js/home.js function h1Click(){ alert('h1 Click'); } ここでサーバー起動してみる (hogehoge) user hogehoge % python manage.py runserver ・無事にサーバー起動ができていること ・css&jsがきちんと効いていること が確認できたらGitHubにプッシュする GitHubにプッシュ GitHub上にhogehogeプロジェクトを作成しておくこと (hogehoge) user hogehoge % git init (hogehoge) user hogehoge % git add . (hogehoge) user hogehoge % git commit -m "first commit" (hogehoge) user hogehoge % git branch -M main (hogehoge) user hogehoge % git remote add origin git@github.com:[project]/hogehoge.git (hogehoge) user hogehoge % git push -u origin main 後はいい感じに開発していく
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

pandas.DataFrameのマルチラベルを簡単にバイナライズする方法

はじめに 機械学習をしていると、付与ラベルをone-hotベクトルに変換する必要がよく発生するのですが、pandasのDataFrameとscikit-learnのMultiLabelBinarizerを使えば簡単に変換できることを知りました。備忘録として記事にします。 変換対象のデータ 以下の表データが格納されたcsvファイル(sample.csv)をone-hotベクトルとしてバイナライズすることを目指します。ラベルデータは、セミコロンがデリミターとして格納されていることを想定します。 text labels あいうえお ひらがな カキクケコ カタカナ ドラえもん カタカナ;ひらがな バイナライズ後のデータは以下の通りです。labels列のデータはリスト形式になっているので、簡単に機械学習器のターゲット変数に入力することが可能になります。 text labels あいうえお [1, 0] カキクケコ [0, 1] ドラえもん [1, 1] 数行でマルチバイナライズされたone-hotベクトル列を作成することができました。 ラベルデータのリスト化 リスト化はPythonの標準機能であるsplitを使えば簡単にできます。 >>> df = pd.read_csv('sample.csv') >>> df text labels 0 あいうえお ひらがな 1 カキクケコ カタカナ 2 さしスセソ ひらがな;カタカナ >>> >>> df['labels'] = df['labels'].apply(lambda x: x.split(';')) >>> df text labels 0 あいうえお [ひらがな] 1 カキクケコ [カタカナ] 2 さしスセソ [ひらがな, カタカナ] この時点でlabels列に格納されているのは文字列ではなく配列になっています。 マルチバイナライズ化 マルチバイナライズは、scikit-learnのMultiLabelBinarizerというクラスを使って行います。ラベルのリストはmlb.classes_という変数で確認することができます。 >>> from sklearn.preprocessing import MultiLabelBinarizer >>> >>> mlb = MultiLabelBinarizer() >>> >>> mlb.fit_transform(df['labels']) array([[1, 0], [0, 1], [1, 1]]) >>> mlb.classes_ array(['ひらがな', 'カタカナ'], dtype=object) Pandasに再格納 zipとlistを使えば、pandas.DataFrameに再格納が可能です。 >>> df = pd.DataFrame(list(zip(df['text'], mlb.fit_transform(df['labels'])))) >>> df.columns = ['text', 'labels'] >>> df text labels 0 あいうえお [1, 0] 1 カキクケコ [0, 1] 2 さしスセソ [1, 1] 参考文献 sklearn.preprocessing.MultiLabelBinarizer
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PandasDataFrameのマルチラベルを簡単にバイナライズする方法

はじめに 機械学習をしていると、付与ラベルをone-hotベクトルに変換する必要がよく発生するのですが、pandasのDataFrameとscikit-learnのMultiLabelBinarizerを使えば簡単に変換できることを知りました。備忘録として記事にします。 変換対象のデータ 以下の表データが格納されたcsvファイル(sample.csv)をone-hotベクトルとしてバイナライズすることを目指します。ラベルデータは、セミコロンがデリミターとして格納されていることを想定します。 text labels あいうえお ひらがな カキクケコ カタカナ ドラえもん カタカナ;ひらがな バイナライズ後のデータは以下の通りです。labels列のデータはリスト形式になっているので、簡単に機械学習器のターゲット変数に入力することが可能になります。 text labels あいうえお [1, 0] カキクケコ [0, 1] ドラえもん [1, 1] 数行でマルチバイナライズされたone-hotベクトル列を作成することができました。 ラベルデータのリスト化 リスト化はPythonの標準機能であるsplitを使えば簡単にできます。 >>> df = pd.read_csv('sample.csv') >>> df text labels 0 あいうえお ひらがな 1 カキクケコ カタカナ 2 さしスセソ ひらがな;カタカナ >>> >>> df['labels'] = df['labels'].apply(lambda x: x.split(';')) >>> df text labels 0 あいうえお [ひらがな] 1 カキクケコ [カタカナ] 2 さしスセソ [ひらがな, カタカナ] この時点でlabels列に格納されているのは文字列ではなく配列になっています。 マルチバイナライズ化 マルチバイナライズは、scikit-learnのMultiLabelBinarizerというクラスを使って行います。ラベルのリストはmlb.classes_という変数で確認することができます。 >>> from sklearn.preprocessing import MultiLabelBinarizer >>> >>> mlb = MultiLabelBinarizer() >>> >>> mlb.fit_transform(df['labels']) array([[1, 0], [0, 1], [1, 1]]) >>> mlb.classes_ array(['ひらがな', 'カタカナ'], dtype=object) Pandasに再格納 zipとlistを使えば、pandas.DataFrameに再格納が可能です。 >>> df = pd.DataFrame(list(zip(df['text'], mlb.fit_transform(df['labels'])))) >>> df.columns = ['text', 'labels'] >>> df text labels 0 あいうえお [1, 0] 1 カキクケコ [0, 1] 2 さしスセソ [1, 1] 参考文献 sklearn.preprocessing.MultiLabelBinarizer
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

XenonPyをゼロから理解していく

はじめに XenonPyの概要とチュートリアルの一部(Sample dataとData access)について解説します。 ※マテリアルズインフォマティクス関係の内容を他にも投稿していますので、よろしければこちらの一覧から他の投稿も見て頂けますと幸いです。 XenonPyとは? 様々な化合物のデータベースかつMIに有用な予測モデルが含まれたツールで、MaterialsProjectで取得した記述子から新たに記述子を生成する際に使用することができます。 XenonPyには、低分子、高分子、無機材料の45種類の特性を対象に約14万個の機械学習の予測モデルが構築されています。マテリアルズインフォマティクスの様々なタスクを実行する機械学習アルゴリズムが実装されており、ユーザーはAPI経由でXenonPy.MDLの訓練済みモデルを再利用(転移学習)し、材料設計の様々なワークフローを構築可能です。 インストール方法 インストール方法はこちらに記載があります。XenonPyはPyTorch,pymatgen,rdkitの3つライブラリと依存関係にあるので、XenonPyインストール前にはこれら3つのインストールが必要となります。 使い方 公式チュートリアルに従って、XenonPyの使い方を解説していきます。 Sample data まずはサンプルデータを取得していきます。Materials Projectから1000個の無機化合物をランダムに選び出します。Materials Projectからデータを取得するにはAPIキーが必要となります。なお、Materials Projectに関してはこちらの投稿に概要を記載しています。 from xenonpy.datatools import preset preset.build('mp_samples', api_key='Your API') Data access データはDatasetオブジェクトとして容易に取り扱うことができます。(実例がないとどんな感じでデータを取り扱っていくのかいまいちイメージできませんでした…) Dataset set1にdata1.csv, data1.pd.xz, data1.pkl.zが存在し、set2にata2.csv, data2.pd.xz, data2.pkl.zが存在するとします。以下のコードでset1とset2の全てのファイルを含むDatasetオブジェクトが作成可能です。 from xenonpy.datatools import Dataset dataset = Dataset('/set1', '/set2') dataset 出力結果 <Dataset> includes: "data1": C:\set1\data1.pd.xz "data2": C:\set2\data2.pd.xz 公式ページでは以下のコードでデータの取り扱いが可能とのことですが、エラーが出て実行できずでした。 dataset.dataframe.data1 出力結果 --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-10-bdc1f28a8254> in <module> ----> 1 dataset.dataframe.data1 ~\AppData\Local\Continuum\anaconda3\lib\site-packages\xenonpy\datatools\dataset.py in __getattr__(self, name) 175 if name in self.__extension__: 176 return self.__class__(*self._paths, backend=name, prefix=self._prefix) --> 177 raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, name)) AttributeError: 'Dataset' object has no attribute 'dataframe' 以下のコードでdata1を読み込むことができました。 dataset.data1 pd, csv, xlsx(xls), pklのファイル形式を読み込むことが可能であり、backendのパラメータで以下のように指定します。 dataset = Dataset('set1', 'set2', backend='csv') dataset.data1 Preset XenonPyでは"elements"と"elements_completed"の2つの特性データが使用可能です。これらのデータはmendeleev,pymatgen,CRC Hand Book,Magpieから収集されています。 elements:118元素、74個の特徴量が含まれたデータ elements_completed:94元素(HからPu)、58個の特徴量が含まれたデータ 2021年5月現在、存在が確認されている元素の種類は118個であり、"elements"は欠損値や計算値もありながら全ての元素の情報を含んでいるデータと言えます。elementsやelements_completedの詳細やデータに含まれる特徴量についての詳細はこちらを参考にして下さい。 では、まずelementsについて見ていきます。 from xenonpy.datatools import preset preset.elements elementsデータに含まれる特徴量を確認します。 preset.elements.columns 出力結果 Index(['atomic_number', 'atomic_radius', 'atomic_radius_rahm', 'atomic_volume', 'atomic_weight', 'boiling_point', 'brinell_hardness', 'bulk_modulus', 'c6', 'c6_gb', 'covalent_radius_bragg', 'covalent_radius_cordero', 'covalent_radius_pyykko', 'covalent_radius_pyykko_double', 'covalent_radius_pyykko_triple', 'covalent_radius_slater', 'density', 'dipole_polarizability', 'electron_negativity', 'electron_affinity', 'en_allen', 'en_ghosh', 'en_pauling', 'first_ion_en', 'fusion_enthalpy', 'gs_bandgap', 'gs_energy', 'gs_est_bcc_latcnt', 'gs_est_fcc_latcnt', 'gs_mag_moment', 'gs_volume_per', 'hhi_p', 'hhi_r', 'heat_capacity_mass', 'heat_capacity_molar', 'icsd_volume', 'evaporation_heat', 'gas_basicity', 'heat_of_formation', 'lattice_constant', 'linear_expansion_coefficient', 'mendeleev_number', 'melting_point', 'metallic_radius', 'metallic_radius_c12', 'molar_volume', 'num_unfilled', 'num_valance', 'num_d_unfilled', 'num_d_valence', 'num_f_unfilled', 'num_f_valence', 'num_p_unfilled', 'num_p_valence', 'num_s_unfilled', 'num_s_valence', 'period', 'poissons_ratio', 'proton_affinity', 'specific_heat', 'thermal_conductivity', 'vdw_radius', 'vdw_radius_alvarez', 'vdw_radius_batsanov', 'vdw_radius_bondi', 'vdw_radius_dreiding', 'vdw_radius_mm3', 'vdw_radius_rt', 'vdw_radius_truhlar', 'vdw_radius_uff', 'sound_velocity', 'vickers_hardness', 'Polarizability', 'youngs_modulus'], dtype='object') 次に、elements_completedについて見ていきます。 preset.elements_completed elements_completedデータに含まれる元素を確認します。95番目のAm(アメリシウム)~118番目のOg(オガネソン)が含まれていないことが分かります。 preset.elements_completed.index Index(['H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', 'Na', 'Mg', 'Al', 'Si', 'P', 'S', 'Cl', 'Ar', 'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Co', 'Ni', 'Cu', 'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br', 'Kr', 'Rb', 'Sr', 'Y', 'Zr', 'Nb', 'Mo', 'Tc', 'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In', 'Sn', 'Sb', 'Te', 'I', 'Xe', 'Cs', 'Ba', 'La', 'Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm', 'Yb', 'Lu', 'Hf', 'Ta', 'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', 'Tl', 'Pb', 'Bi', 'Po', 'At', 'Rn', 'Fr', 'Ra', 'Ac', 'Th', 'Pa', 'U', 'Np', 'Pu'], dtype='object') elements_completedデータに含まれる元素を確認します。'brinell_hardness'や'covalent_radius_bragg'などのelementsには含まれていた特徴量がないことが分かります。 preset.elements_completed.columns Index(['atomic_number', 'atomic_radius', 'atomic_radius_rahm', 'atomic_volume', 'atomic_weight', 'boiling_point', 'bulk_modulus', 'c6_gb', 'covalent_radius_cordero', 'covalent_radius_pyykko', 'covalent_radius_pyykko_double', 'covalent_radius_pyykko_triple', 'covalent_radius_slater', 'density', 'dipole_polarizability', 'electron_negativity', 'electron_affinity', 'en_allen', 'en_ghosh', 'en_pauling', 'first_ion_en', 'fusion_enthalpy', 'gs_bandgap', 'gs_energy', 'gs_est_bcc_latcnt', 'gs_est_fcc_latcnt', 'gs_mag_moment', 'gs_volume_per', 'hhi_p', 'hhi_r', 'heat_capacity_mass', 'heat_capacity_molar', 'icsd_volume', 'evaporation_heat', 'heat_of_formation', 'lattice_constant', 'mendeleev_number', 'melting_point', 'molar_volume', 'num_unfilled', 'num_valance', 'num_d_unfilled', 'num_d_valence', 'num_f_unfilled', 'num_f_valence', 'num_p_unfilled', 'num_p_valence', 'num_s_unfilled', 'num_s_valence', 'period', 'specific_heat', 'thermal_conductivity', 'vdw_radius', 'vdw_radius_alvarez', 'vdw_radius_mm3', 'vdw_radius_uff', 'sound_velocity', 'Polarizability'], dtype='object') このように各元素に対する様々な特徴量を取得できることが分かりました。この特徴量をインプット情報として材料探索に活用できそうですね。 まとめ XenonPyの概要とチュートリアルの一部(Sample dataとData access)について解説しました。続編はまた投稿予定です。 参考 XenonPy公式ページ 国立研究開発法人 物質・材料研究機構(NIMS)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

超解像手法/VDSRの実装

概要 深層学習を用いた、単一画像における超解像手法であるVDSRの実装したので、それのまとめの記事です。 Python + Tensorflow(Keras)で実装を行いました。 なんでVDSRという名前なのかというと、VGG-netから着想を得たモデルだからということらしいです。 今回紹介するコードはGithubにも載せています。 1. 超解像のおさらい 超解像について簡単に説明をします。 超解像とは解像度の低い画像に対して、解像度を向上させる技術のことです。 ここでいう解像度が低いとは、画素数が少なかったり、高周波成分(輪郭などの鮮鋭な部分を表す)がないような画像のことです。 以下の図で例を示します。(図は[論文]より引用) これは、超解像の説明をする時によく使われる画像です。 (a)は原画像、(b)は画素数の少ない画像を見やすいように原画像と同じ大きさにした画像、(c)は高周波成分を含まない画像の例です。 (b)と(c)は、荒かったりぼやけていたりしていると思います。 このような状態を解像度が低い画像といいます。 そして、超解像はこのような解像度が低い画像に処理を行い、(a)のような精細な画像を出力することを目的としています。 2. VDSRの超解像アルゴリズム VDSRのアルゴリズムの概要図は以下の通りです。(図は論文から引用) Convolution層を多数重ねることで、学習をさせていますが、 最後に入力画像と畳み込み演算の結果を足し合わせるSkip Connnectionを導入していることが大きな特徴です。 これを行う意図としては、多数の畳み込み演算によって生じる勾配消失を防ぎ、画像の特徴を失わないようにするためです。 最後に入力画像を足し合わせることで、画像の特徴は残しつつ処理を行うことができる、というわけです。 今回実装したVDSRは、事前にbicubicで補間処理をした画像を入力するので、意味合いとしては、高周波成分の復元が近いと思います。 3. 実装したアルゴリズム 今回、実装したVDSRの構造のコマンドラインは以下の通りです。 __________________________________________________________________________________________________ Layer (type) Output Shape Param # Connected to ================================================================================================== input_1 (InputLayer) [(None, None, None, 0 __________________________________________________________________________________________________ conv2d (Conv2D) (None, None, None, 6 640 input_1[0][0] __________________________________________________________________________________________________ conv2d_1 (Conv2D) (None, None, None, 6 36928 conv2d[0][0] __________________________________________________________________________________________________ conv2d_2 (Conv2D) (None, None, None, 6 36928 conv2d_1[0][0] __________________________________________________________________________________________________ conv2d_3 (Conv2D) (None, None, None, 6 36928 conv2d_2[0][0] __________________________________________________________________________________________________ conv2d_4 (Conv2D) (None, None, None, 6 36928 conv2d_3[0][0] __________________________________________________________________________________________________ conv2d_5 (Conv2D) (None, None, None, 6 36928 conv2d_4[0][0] __________________________________________________________________________________________________ conv2d_6 (Conv2D) (None, None, None, 6 36928 conv2d_5[0][0] __________________________________________________________________________________________________ conv2d_7 (Conv2D) (None, None, None, 6 36928 conv2d_6[0][0] __________________________________________________________________________________________________ conv2d_8 (Conv2D) (None, None, None, 6 36928 conv2d_7[0][0] __________________________________________________________________________________________________ conv2d_9 (Conv2D) (None, None, None, 6 36928 conv2d_8[0][0] __________________________________________________________________________________________________ conv2d_10 (Conv2D) (None, None, None, 6 36928 conv2d_9[0][0] __________________________________________________________________________________________________ conv2d_11 (Conv2D) (None, None, None, 6 36928 conv2d_10[0][0] __________________________________________________________________________________________________ conv2d_12 (Conv2D) (None, None, None, 6 36928 conv2d_11[0][0] __________________________________________________________________________________________________ conv2d_13 (Conv2D) (None, None, None, 6 36928 conv2d_12[0][0] __________________________________________________________________________________________________ conv2d_14 (Conv2D) (None, None, None, 6 36928 conv2d_13[0][0] __________________________________________________________________________________________________ conv2d_15 (Conv2D) (None, None, None, 6 36928 conv2d_14[0][0] __________________________________________________________________________________________________ conv2d_16 (Conv2D) (None, None, None, 6 36928 conv2d_15[0][0] __________________________________________________________________________________________________ conv2d_17 (Conv2D) (None, None, None, 6 36928 conv2d_16[0][0] __________________________________________________________________________________________________ conv2d_18 (Conv2D) (None, None, None, 6 36928 conv2d_17[0][0] __________________________________________________________________________________________________ conv2d_19 (Conv2D) (None, None, None, 1 577 conv2d_18[0][0] __________________________________________________________________________________________________ add (Add) (None, None, None, 1 0 input_1[0][0] conv2d_19[0][0] ================================================================================================== Total params: 665,921 Trainable params: 665,921 Non-trainable params: 0 __________________________________________________________________________________________________ 今回は、Convolutionの数を20にしています。 また、最後にAddで、入力画像と畳み込み演算の結果を足し合わせて最終的な結果にしています。 4. 使用したデータセット 今回は、データセットにDIV2K datasetを使用しました。 このデータセットは、単一画像のデータセットで、学習用が800種、検証用とテスト用が100種類ずつのデータセットです。 今回は、学習用データと検証用データを使用しました。 パスの構造はこんな感じです。 train_sharp - 0001.png - 0002.png - ... - 0800.png val_sharp - 0801.png - 0802.png - ... - 0900.png このデータをBicubicで縮小したりしてデータセットを生成しました。 5. 画像評価指標PSNR 今回は、画像評価指標としてPSNRを使用しました。 PSNR とは Peak Signal-to-Noise Ratio(ピーク信号対雑音比) の略で、単位はデジベル (dB) で表せます。 PSNR は信号の理論ピーク値と誤差の2乗平均を用いて評価しており、8bit画像の場合、255(最大濃淡値)を誤差の標準偏差で割った値です。 今回は、8bit画像を使用しましたが、計算量を減らすため、全画素値を255で割って使用しました。 そのため、最小濃淡値が0で最大濃淡値が1です。 dB値が高いほど拡大した画像が元画像に近いことを表します。 PSNRの式は以下のとおりです。 PSNR = 10\log_{10} \frac{1^2 * w * h}{\sum_{x=0}^{w-1}\sum_{y=0}^{h-1}(p_1(x,y) - p_2(x,y))^2 } なお、$w$は画像の幅、$h$は画像の高さを表しており、$p_1$は元画像、$p_2$はPSNRを計測する画像を示しています。 6. コードの使用方法 このコード使用方法は、自分が執筆した別の実装記事とほとんど同じです。 ① 学習データ生成 まず、Githubからコードを一式ダウンロードして、カレントディレクトリにします。 Windowsのコマンドでいうとこんな感じ。 C:~/keras_VDSR> 次に、main.pyから生成するデータセットのサイズ・大きさ・切り取る枚数、ファイルのパスなどを指定します。 main.pyの15~26行目です。 使うPCのメモリ数などに応じで、画像サイズや学習データ数の調整が必要です。 main.py train_height = 64 #HR・LRのサイズ train_width = 64 test_height = 720 #HR・LRのサイズ test_width = 1280 train_dataset_num = 10000 #生成する学習データの数 test_dataset_num = 10 #生成するテストデータの数 train_cut_num = 10 #一組の動画から生成するデータの数 test_cut_num = 1 train_path = "../../dataset/DIV2K_train_HR" #画像が入っているパス test_path = "../../dataset/DIV2K_valid_HR"``` 指定したら、コマンドでデータセットの生成をします。 C:~/keras_VDSR>python main.py --mode train_datacreate `` これで、train_data_list.npz`というファイルのデータセットが生成されます。 ついでにテストデータも同じようにコマンドで生成します。コマンドはこれです。 C:~/keras_VDSR>python main.py --mode test_datacreate ② 学習 次に学習を行います。 設定するパラメータの箇所は、epoch数と学習率、今回のモデルの層の数です。 まずは、main.pyの28~31行目 main.py model_depth = 20 #モデルの層の数 BATCH_SIZE = 64 EPOCHS = 80 後は、学習のパラメータをあれこれ好きな値に設定します。81~95行目です。 今回は、モデルを使用するために、モデルの層の数を設定しないといけません。 また、20 epochごとに学習率を変更させる必要があるため、複数回に分けて学習をさせています。 main.py train_model = model.VDSR(model_depth) for i in range(EPOCHS // 20): optimizers = tf.keras.optimizers.SGD(lr=0.01 * (0.1 ** i), momentum=0.9, decay=1e-4, nesterov=False) train_model.compile(loss = "mean_squared_error", optimizer = optimizers, metrics = [psnr]) train_model.fit(train_x, train_y, epochs = 20, verbose = 2, batch_size = BATCH_SIZE) train_model.save("VDSR_model.h5") optimizerはmomentum、損失関数はmean_squared_errorを使用しています。 学習はデータ生成と同じようにコマンドで行います。 C:~/keras_VDSR>python main.py --mode train_model これで、学習が終わるとモデルが出力されます。 ③ 評価 最後にモデルを使用してテストデータで評価を行います。 これも同様にコマンドで行いますが、事前に①でテストデータも生成しておいてください。 C:~/keras_VDSR>python main.py --mode evaluate このコマンドで、画像を出力してくれます。 7. 結果 出力した画像はこのようになりました。 なお、今回は輝度値のみで学習を行っているため、カラー画像には対応していません。 対応させる場合は、modelのInputのchannel数を変えたり、データセット生成のchannel数を変える必要があります。 元画像 低解像度画像 生成画像 PSNR:27.22 画像の粗さが取れていることが分かります。 画素数は増えていないので、高周波成分の復元が意味合いとしては近いですね。 最後に元画像・低解像度画像・生成画像の一部を並べて表示してみます。 4倍なので、入力画像が歪んでいることもあり、なかなか綺麗にはなりません。 8. コードの全容 前述の通り、Githubに載せています。 pythonのファイルは主に3つあります。 各ファイルの役割は以下の通りです。 data_create.py : データ生成に関するコード。 model.py : 超解像のアルゴリズムに関するコード。 main.py : 主に使用するコード。 9. まとめ 今回は、最近読んだ論文のVDSRを元に実装してみました。 前述したとおり、VGG-netに着想を得たモデルとなっています。 記事が長くなってしまいましたが、最後まで読んでくださりありがとうございました。 参考文献 ・Accurate Image Super-Resolution Using Very Deep Convolutional Networks Jiwon  今回実装の参考にした論文。 ・画素数の壁を打ち破る 複数画像からの超解像技術  超解像の説明のために使用。 ・DIV2K dataset  今回使用したデータセット。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Python Streamlitで任意の書式を設定したい場合:write()関数でunsafe_allow_html引数をTrueとする

はじめに  SteamlitはPythonによるデータの分析結果を爆速で見える化・共有化するのに便利です。しかし、便利さゆえにかゆいところに手が届かない点が見えかくれする場合も少なくありません。 やりたいこと  例えば、わたしの場合、「エラーメッセージを表示させるために目立たせたないな」とか「ここの表示はインタラクティブに変わるので色を変えたいな」とかの贅沢な欲求が芽生えました。 方法  公式のAPIドキュメントをあさったのですがなかなか見つけれない中、とある英語のブログにて解決策を提示して下さっている方がいました。  結論は至って簡単です。  write() 関数に引数 unsafe_allow_html を追加し、True にしてあげるだけです。  これで、表示したい部分にHTMLタグを指定するとタグのプロパティで設定した表示方法がそのまま画面に反映されます。 コード例 任意の書式を設定したい場合の書き方 streamlit.write(<TAG style="hoge:bar">ホゲホゲ</TAG>, unsafe_allow_html=True)  Pandas?のDataframeの中身が無い場合のエラーメッセージを装飾する場合はこんな感じになります。 実装例 import streamlit as st import pandas as pd def check_df(df): if df.empty: st.write('<span style="color:red;background:pink">該当するデータがありません・・・・</span>', unsafe_allow_html=True) return False else: return True 結果 上記のコード実行した例を以下に示します。少し派手ですが、標準のStreamlitの画面には無いような文字色とか文字背景色を実現できています。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Djangoの開発サーバーが立ち上がるまで

今回やる事 おなじみコマンド「パイソンマナゲランサーバー」を追ってみる。 実装をひたすら追ってみる まず python manage.py runserverにより、直下のmanage.pyが動く。 1. manage.pyが動き出す manage.py def main(): os.environ.setdefault('DJANGO_SETTING_MODULE', 'アプリ名.settings') ... execute_from_command_line(sys.argv) if __name__ == '__main__': main() manage.pyでは、環境変数を設定した後、execute_from_commmand_lineというメソッドにコマンドラインで渡された引数をリストで渡し、メソッドを呼んでいる。 sys.argvとする事で、コマンドラインで入力したpython manage.py runserverのpython以降の ['manage.py', 'runserver'] がリスト形式で取得出来る 2. execute_from_command_lineメソッド django.core.management.__init__.py def execute_from_command_line(argv=None): utility = ManagementUtility(argv) utility.execute() execute_from_commmand_lineでは、ManagementUtilityクラスをインスタンス化し、ManagementUtilityクラスのexecuteメソッドを呼ぶ。 3. ManagementUtility.executeメソッド django.core.management.__init__.py class ManagementUtility: def __init__(self, argv=None): """ コマンドライン引数をセット self.argv = ['manage.py', 'runserver'] """ self.argv = argv or sys.argv[:] self.prog_name = os.path.basename(self.argv[0]) if self.prog_name == '__main__.py': self.prog_name = 'python -m django' self.settings_exception = None def execute(self): try: # subcommandはrunserverになる。 subcommand = self.argv[1] except IndexError: subcommand = 'help' # CommandParserでコマンドライン引数の詳細設定を行う。 # runserverだけだったらここは重要じゃない。 parser = CommandParser( prog=self.prog_name, usage='%(prog)s subcommand [options] [args]', add_help=False, allow_abbrev=False ) parser.add_argument('--settings') parser.add_argument('--pythonpath') parser.add_argument('args', nargs='*') try:        # runserverだけだったらindexは1までしかない。 options, args = parser.parse_known_args(self.argv[2:]) handle_default_options(options) except CommandError: pass ... # エラーチェックとか ... if subcommand == 'help': ... else: self.fetch_command(subcommand).run_from_argv(self.argv) runserverのコマンドをsubcommandという変数に持ったりエラーチェックなどをした後、fetch_commandで該当のコマンドのクラスを取得し、そのrun_from_argvメソッドを呼ぶ。 4. ManagementUtility.fetch_commandメソッド Commandクラスを返すメソッド。 コマンドが正しく入力されていなかったりしたら、見つからないよメッセージなどを出力する。 django.core.management.__init__.py def fetch_command(self, subcommand): # get_commandsメソッドは、django.core.management.commandsの中のコマンドクラス一覧を取得し、 # {コマンド名: アプリ名}という形式の辞書で返すメソッド。アプリ名はソース内で実装されているクラス。 # runserverだったら {'runserver', Commandクラス}になる。 commands = get_commands() try: app_name = commands[subcommand] except KeyError: ... if isinstance(app_name, BaseCommand): klass = app_name else: klass = load_command_class(app_name, subcommand) return klass feach_commandメソッドによってdjango.core.management.commands.runsercer.pyのCommandクラスが返され、そのクラスのrun_from_argvメソッドが呼ばれる。 5. Command.run_from_argvメソッド (runserver.py) django.core.management.commands.runserver.py # runserverのコマンドクラス class Command(BaseCommand): ... default_addr = '127.0.0.1' default_addr_ipv6 = '::1' default_port = '8000' protocol = 'http' server_cls = WSGIServer ... run_from_argvはこのクラスには実装されていないため、親クラスを見てみる。 BaseCommandクラスのrun_from_argメソッド django.core.management.base.py class BaseCommand: """ argv = ['manage.py', 'runserver'] """ def run_from_argv(self, argv): ... try: # executeメソッドを self.execute(*args, **cmp_options) except Exception as e: ... finally: try: connections.close_all() runserverのCommandクラスの親クラスのBaseCommandクラスでは、executeメソッドを呼び出している。 runserverのCommandクラスでexecuteメソッドは実装されているが、ほぼ中身は無く親クラスのexecuteを呼び出す形になっているためBaseCommandクラスのexecuteメソッドを見てみる。 6. BaseCommandクラスのexecuteメソッド django.core.management.base.py class BaseCommand: def execute(): # Djangoプロジェクトのエラーチェックなど ... output = self.handle(*args, **options) ... return output エラーチェックなどを行った後、handleメソッドを呼んでいる。handleメソッドはrunserver.pyのコマンドクラスに実装されている。 7. runserverのCommandクラスのhandle ~ innerrunメソッド django.core.management.commands.runserver.py class Command(BaseCommand): def handle(self, *args, **options): # エラーチェックなど。 # 「You must set settings.ALLOWED_HOSTS if DEBUG is False.」などのエラーはここで発生させたりしている。 ... # runメソッドを呼ぶ。 self.run(**options) def run(self, **options): # --noreloadなど指定しているかのチェック use_reloader = options['use_reloader'] if use_reloader: autoreload.run_with_reloader(self.inner_run, **options) else: # 今回はこっち self.inner_run(None, **options) def inner_run(self, *args, **options): # エラーチェックなど。 # マイグレーションしてない時ターミナルに出るエラーメッセージ、立ち上げた時のIP、ポートなどはここで出力している。 ... try: # get_handlerメソッドは、settings.pyにWSGI_APPLICATIONで指定しているWSGIHandlerが返される。 handler = self.get_handler(*args, **options) # runメソッドによってサーバーを立ち上げる。 run(self.addr, int(self.port), handler, ipv6=self.use_ipv6, ipv6, threading=threading., server_cls=self.server_cls) except: ... ここでも色々なエラーチェックなどをした後、runメソッドを呼ぶ。 8. runメソッドによりserve_foreverが呼ばれる django.core.servers.basehttp.py def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer): """ ip, portはrunserver.pyで定義されたデフォルトが入る。 addr = '127.0.0.1' port = '8000' wsgi_handler = WSGIHandler ipv6 = False (コマンドラインからuse_ipv6で指定したか) theading = False (コマンドラインからuse_threadingで指定したか) server_cls = WSGIServer """ server_address = (addr, port) if threading: httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {}) else: # 今回はこちら httpd_cls = server_cls # WSGIServerをインスタンス化する。 httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6) ... # WSGIServerにWSGIHandlerをセットする。 httpd.set_app(wsgi_handler) # serve_foreverを呼ぶ。 httpd.serve_forever() ここでserve_foreverを呼ぶことでサーバーを立ち上げてリクエスト待ち状態にしているみたい。 このserve_foreverというのはPython標準ライブラリのsocketserverのBaseServerクラスに実装されているメソッド。github上の該当ソース まとめ 標準ライブラリのサーバーを立ち上げるまでに、どのようなチェックをしているのかが大まかに理解出来た。立ち上げたサーバーにリクエストが来たらどのような動きをするのかもまとめたいと思った。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【M1必見】Docker を使ってデータ解析環境を構築する

なぜDocker を使うのか  結論から言うと、PCが汚れるのを防ぐため。HOSTコンピューター(自分が普段使うコンピュータ)に様々なパッケージを入れると、手間がかかるし、アンインストールしてもキャッシュが残ったりして、ストレージが少なくなってしまう。Dockerのコンテナを使い仮想環境を構築して、その中に様々なパッケージをインストールすることで、HOSTコンピュータに負荷をかけることなく、データ解析、分析が可能になる。さらに、インストールしたパッケージ同士がエラーを起こした際に、対応しやすいという利点もある。それに加えて、Dockerfileを共有することで、同じ環境が他の人でもコマンド一つで構築できてしまうという利点もある。 Dockerfile を作成する Dockerfileを作成する方法はいくらでもあるが、個人的には、https://code.visualstudio.com/ を使うことをお勧めする dockerfile # ubuntuをベースに docker image を作成する FROM ubuntu:latest # メンテナンスなどによく使われるコマンドをインストールする(-yはパッケージをインストールする際に必要なおまじない) RUN apt-get update && apt-get install -y wget vim sudo # WORKDIR でインストールする場所を決める WORKDIR <Anacondaをインストールする場所、推奨は「/opt」> RUN wget https://repo.continuum.io/archive/Anaconda3-2020.11-Linux-x86_64.sh <- インストールしたいAnacondaのバージョン Anacondaのバージョンなどについては、 https://repo.anaconda.com/archive/ を参照するといい。ubuntuに対応しているのは、「Anaconda3-2019.10-Linux-x86_64.sh」のように、「Linux-x86」が入っているもの dockerfile # anacondaインストーラーを起動し、anaconda3をインストールする # -b : バッチファイル的に動かすときに使用する(必須) # -p path :anacodna3をどこに置くかを指定する(デフォルトでは、root/anacodna3となる。メンテがめんどいので、optの下においた) RUN sh Anaconda3-2020.11-Linux-x86_64.sh -p /opt/anaconda3 -b # ENVで環境変数を設定する。以下は"python"のためのパス ENV PATH /opt/anaconda3/bin:$PATH # "jypyter", "lab" :jupyterlabをデフォルトで起動させるコマンド。 # "--ip=0.0.0.0" :ローカルでjupyterlabを使うときに必要なコマンド # "--LabApp.token=''" :本来ならjupyterlabを起動させた際にパスワードを入れる必要があるがこう書くことでそれを防ぐ CMD ["jupyter", "lab", "--ip=0.0.0.0", "--allow-root", "--LabApp.token=''"] Dockerfileを用いて、"docker image"を作成する terminal username@MacBook-Pro ~ % cd <Dockerfileを保存した場所> # Dockerfileがあるかどうかを確認する username@MacBook-Pro docker_file % ls >>> Dockerfile # "docker build"を使って構築する username@MacBook-Pro docker_file % docker build --platform linux/amd64 上記と同じコマンドを入力すれば、docker imageを作成できる。 【重要】M1Macを使用している方は、必ず「--platform linux/amd64」を付けて入力する 付けないとエラーになる ターミナルでDockerfileを起動させる terminal # "docker iamges" を使い、起動したい "docker image" があるかどうかを確認する username@MacBook-Pro ~ % docker iamges >>> REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> dge767nb2v62h 2 days ago 3.66GB # "docker run" を使い "docker image" を起動させる # "-p 8888:8888" はポートを設定するためのオプションなので必須。もし以前に8888を使用したことがあるのであれば、任意のもの(-p 1234:8888)を設定する。 username@MacBook-Pro ~ % docker run -p 8888:8888 dge767nb2v62h 起動させると勝手にJupyterLabが起動するので、Googleで「localhost:8888」と検索するとJupyterlabに入ることができる。入れることを確認できたら、完了。 さらにライブラリを追加したいとき 先ほど作成したDockerfileに以下のコマンドと追加したいライブラリを入力すればいい。追記する場所は、CMDの上あたりでいい。 RUN pip install --upgrade pip RUN pip install <ライブラリの名前> 【補足】AWSでdockerを使用する ここのセクションではAWSにdockerをインストールして、自分のPCにマウントさせることで、自分のPCのメモリなどを使わずデータ分析を行う方法を紹介する。あらかじめAWSアカウント作成後、AWSインスタンスを作成しておくこと! 詳しくは、こちら( https://aws.amazon.com/jp/register-flow/)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Python] 動的計画法 ABC200D

ABC200D 動的計画法の実装を工夫すると、時間計算量は$O(MN^2) (M=200)$となる。 dpの定義: $dp[r][s]=和の余りがrとなる正整数の集合がs$ サンプルコード M=200 n=int(input()) A=[*map(lambda x:int(x)%M,input().split())] # dpを 辞書型 { 余り:{正整数} } に初期化 from collections import * dp = defaultdict(set) dp[0] = set() for i in range(M): for d in dp.copy(): dd = dp[d] for j in range(n): # jがdp[d]にあればパス if j in dd: continue r = (d+A[j])%M s = dd | {j} # ddにjを追加 # dp[r]がdp[d]ならパス if s==dp[r]: continue # dp[r]がすでにあれば回答、なければsを登録 if dp[r]: print('Yes') B = [i+1 for i in dp[r]] C = [i+1 for i in s] print(len(B),*B) print(len(C),*C) exit() dp[r]=s print('No') 公式解説では鳩ノ巣原理を前提としたbit全探索が紹介されている。 個人的には、設計は出来たものの、DPなどの実装技術がまったく不足しており、技術力を鍛錬する必要がある。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Windows10にJupyter Notebookをインストールする(RとPower ShellやC#なども併せて)

(執筆 2021/5/9)  WindowsへのJupytere Notebookのインストールは、Anacondaを使うのが簡単です。ですが、RやRStudioは、パッケージをダウンロードしてきてインストールする方がよさそうな気がしたので、以下、手順を記載します。最小限のインストールです。 Anacondaをインストール  https://www.anaconda.com/ へ行き、上部 Products にマウスを合わせるとメニューが開くので、Individual Edtion Open Source Distribution を選択。 Download をクリックすると、ページのずっと下に飛ばされます。  環境に合わせて、Windows 64bit Graphic Installer を選択すると、ダウンロードが始まります。  ダウンロードしたファイルを開くと、Anacondaのインストールが始まります。  環境変数PATHへAnaconda3を追加するかどうかのオプションが、非推奨になってます。これは、ほかのソフトと競合する可能性があるためですが、使い勝手を考えると、私はチェックを入れたいと思います。判断に迷う場合は、このままチェックしないで進みましょう。チェックを入れると、赤字に変わって、ちょっとビビります。  インストールが開始され、少々待たされた後、「Next>」をクリックしていき、最後に「Finish」となりますが、最後の画面のチェックは、面倒なので外してから「Finish」しましょう。  インストールが終了したら、Anacondaを最新状態にします。WubdiwsのメニューにAnacondaの項目が増えていますので、Anaconda Promptを選択します。  以下のコマンドを入力します。 conda update conda  アップデートがあった場合、処理を進めるか聞いてきますので、yで進めます。  最後 Done と表示されれば、完了です。exitと入力して、画面を閉じます。(×で閉じてもOK) Jupyter Notebook の起動  WindowsのメニューにAnaconda3(64-bit)の項目が追加されていますので、Jupyter Notebookを選択すると、ブラウザが開きJupyter Notebookが起動します。右端のNewにはPython3が選択できるようになっています。  終了するときは、右上のQuitを押してからブラウザを閉じます。そのまま閉じてしまうと、下のようなコマンドライン画面が残ってしまいます。その場合は躊躇なく右上の×ボタンで閉じてください。  インストール時に選択した、PATHを通すにチェックを入れておくと、コマンドラインから jupyter notebook と入力しても起動できます。PATHの設定をしなかった場合、以下のようなメッセージが表示されます。  拡張機能が必要な場合は、Anaconda Promptからインストールを行います。 NbExtensionsの例 conda install -c conda-forge jupyter_contrib_NbExtensions Rのインストール  https://cran.r-project.org/ から、Download R for Windows -> base -> Download R 4.X.X for Windowsと進んで、Rをダウンロードします。  ダウンロードされた R-4.X.X-win.exe を開き、標準設定のままインストールします。インストールが完了すると、メニューにRの項目が増えています。 RStudioのインストール  RStudioもインストールしておきましょう。https://www.rstudio.com/products/rstudio/ から、DOWNLOAD RSTUDIO DESKTOP を選んで、ダウンロードします。  RStudio Desktop Free版で構いません。  ダウンロードしたファイルを開き、こちらも、そのまま進めてインストールします。インストールが完了すると WindowsのメニューにRStudioが追加されています。  起動すると、以下の画面が表示されます。クラッシュレポートの送信は、お好きな方をお選びください。 Jupyter Notebook へ R を登録  先ほどのRStudioのConsoleからか、Rを起動したコンソール画面に、以下のコマンドを順番に入力します。 install.packages('IRkernel') IRkernel::installspec()  これで、Jupyter Notebook を起動すると、Pythonの他にRが選択できるようになります。  簡単なグラフを試しに作ってみます。 install.packages について  他の記事で、install.packages(c('repr', 'IRdisplay', などなどのコマンドが必要となっていますが、Anacondaを使えば、これらのパッケージは既にインストールされてました。唯一、devtoolsは入ってないのですが、これを使うのはIRkernelをGithabから持ってこようとするためで、IRkernelはinstall.packagesでインストール可能なので必要ありませんでした。 Power Shellの登録  Jupyter NotebookでPower Shellを動かすために、.NET 5.0をインストールします。.NET 5.0の下のDownload .NET SDK x64をクリックして、インストーラーをダウンロードします。 https://dotnet.microsoft.com/download  インストールが完了すると、コマンドプロンプトからバージョンを確認します。 dotnet --list-sdks  次に、dotnet-interactive をインストールして、jupyter notebookに登録します。コマンドプロンプトから、以下のコマンドを順番に入れます。 dotnet tool install --global Microsoft.dotnet-interactive dotnet interactive jupyter install  これで、Jupyter Notebookを開くと、.NET(C#), .NET(F#), .NET(Power Shell)が選択できるようになります。  以上で最低限のインストールができたと思います。必要に応じ、パッケージや拡張機能のインストールを行ってください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む