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

データ分析コンペに参加してみよう

 1.はじめに  データ分析コンペティションに参加しよう!と意気込んでkaggleを見てもなんのこっちゃ。  ハードルを下げてSIGNATEに参加しようと思ってもなんのこっちゃ。一応コードを丸パクリして提出までは行けても何がどうなっているのかがよくわからない。結局、SIGNATEから離れてしまった。そんな方達にもわかりやすいように一連の流れを図を用いて表現しています。一部、厳密にいえば正しくない点もありますが今回はわかりやすさを優先します。  図で説明した部分について以下のようにPythonコードを付属させている場合があります。図で行っている作業をPython上で実装したい場合はコードを参照してください。(初学者はPythonコードは参照しないことをお勧めします)  今回扱うのはテーブルデータに関してです。 sample.py この部分に対応するpythonコードを記述します  2.簡単な全体の流れ  SIGNATEからダウンロードできるのは上記3つであることがほとんどです。(拡張子がtsvの場合もあります)  ここでごちゃごちゃ説明されてもわからないと思うので、少し例を見てみましょう。  今みなさんは高校3年生です。  1月にはセンター試験がありますね。そこに向けて問題集やら参考集やらで勉強します。問題を問いて答え合わせをして間違い直しをします。  時は早いものでもうセンター試験当日です。  さて、みなさんの手元には数学の問題用紙と回答用紙が存在します。今までの知識を総動員して問題を解きました。回収されるのは回答用紙だけです。途中がどうであれ、僕たちの点数はこの紙一枚に集約されました。  2ヶ月後くらいには点数がなんだか細長い紙にプリントされて返ってきました。  何を言ってるんだ、となっている方もいると思いますが大丈夫です。では見ていきましょう。  上の例で「問題集やら参考集やら」としたのが訓練データです。  次に「数学の問題用紙」としたのが評価用データです。  最後に「数学の回答用紙」としたのが応募用サンプルファイルです。  つまり、評価用データで学習をしてその解法を評価用データに適応しそこから得た自分なりの答えを応募用サンプルファイルに入れてSIGNATEに提出をします。そうすると、結果が返ってきます。これが簡単な流れになります。  ここまで理解できた方はわかるかと思いますが、僕たちがパソコンをカタカタして色々するのはほとんどが「訓練データ」に関してです。つまり、これからはずっと訓練データに関して触れていきます。  が、最初にこれらのファイルをPythonで動かせるようにしなきゃいけないのでそこからいきましょう!!  3.データをPython上で動かせるようにしよう  さて、図示をする前にpythonでデータを読み込めなくてwebで調べると「パスがどうこう」「階層がどうこう」って言われます。  でもパスとは何かを知らん!わからないものをわからない言葉で説明されてわかるわけがない。はい、無理ってなりません?僕はなりました(笑)  ってことでできるだけ難しい言葉は使わずに説明していきます。  上みたいな状況を考えます。これもグダグダ書いてもわかるものじゃないので例を見ていきましょう。  3階建てのアウトレットに来てます。アウトレットは「A」「B」「C」の3つのゾーンに分かれています。  あなたは「A」ゾーンの3階にいます。  さて、「A」ゾーンでの買い物は終わり「B」ゾーンの3階にあるお店を目指しましょう。しかし3階では「A」ゾーンと「B」ゾーンは繋がっていません。一度2階に降りて「A」ゾーンから「B」ゾーンに移動をしてから3階に上がってお店を目指します。  上の例で示した、「あなた」としたのが実行したいPythonファイルです。  次に「ゾーン」としたのは各フォルダです。  最後に「お店」としてのはデータのファイルです。  上記の図を例を用いて理解をしてもらえればと思いますが、一階には一つのゾーン(フォルダ)しかありません。二階には2つのゾーン(「データ分析」・「アルゴリズム」)と一つの店舗(データ3)が存在します。そして、「データ分析」というゾーンの3階にはあなた(pythonファイル)と一つの店舗(データ1)があります。「アルゴリズム」というゾーンの3階には一つの店舗(データ2)が存在します。  あなたが、「データ1」の店舗に入るには歩けば良いだけです。しかし「データ3」を得るためには2階に降りる必要が、「データ2」を得るには2階に降りてゾーンを移動して3階に移動する必要があります。Python君は勝手に歩いてはくれますが、勝手に階段を降りたり、別のゾーンに移動してはくれません。(そんなことしたら大変ですよね笑)  なので、別の階・ゾーンにあるデータをもらうときはPython君に「階段を降りて」・「ゾーンを移動して」という命令を出してあげなければなりません。 以下でここまでの作業をPythonコードで書いていきます。(今回データを入れているファイル名は上にある図示と一致させます(例:データ1→data1.csv)) sample.py import pandas as pd #ライブラリのインポート df = pd.read_csv('data1.csv') #同じ階・ゾーンにデータが存在する場合(データ1) df = pd.read_csv('../data3.csv')#一つ下の階にデータが存在する場合(データ3) df = pd.read_csv('../アルゴリズム/data2.csv')#別のゾーンにデータが存在する場合(データ2) #階段を一個降りる命令 '../' #階段を降りて「アルゴリズム」というゾーンへ移動する命令 '../アルゴリズム' #階段を一個上る命令 '/' #2階に降りて「アルゴリズム」というゾーンへ移動し3階へ上がってdata2.csvというお店に入る '../アルゴリズム/data2.csv'  4.訓練データを利用しよう  話が若干前後しますが、訓練データは「問題集やら参考集やら」だったことは覚えていますかね。  それを覚えていてくれればこの章の話は全く難しくありません  では見てきましょう!  いきなり、図が出てきて知らない言葉の羅列に驚いたかもしれませんが難しいことはありません。  何度も繰り返しますが、訓練データは「問題集やら参考集やら」のことです。これらは「問題」と「解答」が分かれていますよね。解答が後ろの方にまとめて記述されていたり、別冊になっていたり。。  SIGNATEの訓練データも似たような作りになっています。単に「問題」部分を「説明変数」、「解答」部分を「目的変数」と名前をつけているだけです。こういうなんだか難しそうな言葉を使うと初学者は離れていくと思うのですけど、、まあそんな話は置いといて訓練データのどこが説明変数になってどこが目的変数になるのでしょうか。  ここで、SIGNATEの画面を見ていきます。一応何かあったら怖いので必要ない部分は全て隠しています。この画面は自分が参加したいコンペをクリックしてもらって「データ」タブをクリックして下にスクロールすると同じような画面が出てきます。まあ、参考までに。  てことで重要なのは黄色く塗られた部分です。ここが「解答」部分(目的変数)で、他のは全て「問題」部分(説明変数)になります。  お気づきの方もいると思いますが、与えられたままの状況では問題文と一緒に答えが乗っちゃってます。イメージで言えば問題文があって下にある解答欄に全部答えが記入されてるイメージです。それだと答えがわかっちゃってるので解く意味がなくなりますよね。というより答えを見ながら解いても意味ないですよね。ってことで面倒ではあるんですけど、図の形で訓練データの中にある説明変数(「問題」部分)と目的変数(「解答」部分)を別個に分けます。分けた時に、説明変数部分から目的変数を消すのを忘れないでくださいね。分けたら上の図みたいになるわけです。 ここまでをPythonコード使ってみていきましょう。 sample.py import pandas as pd #ライブラリのインポート #訓練データをPython上に入れる df = pd.read_csv('train.csv') #問題文とは別個に解答がまとまった冊子を作ります(ヘッダ名称とは上記写真内にある「ヘッダ名称」と同じです) target = df['(解答部分にあたるヘッダ名称)'] #問題文内から回答を消します(axis=1は列を消すよってことを言ってます) df = df.drop(['(解答部分にあたるヘッダ名称)'],axis=1) 5.分類器を作成しよう  またなんのこっちゃわからん言葉が出てきたと思われると思いますが、心配いりません。また難しくないことを難しそーうに書いているだけです。  さっきまでで、訓練データを説明変数(「問題」部分)と目的変数(「解答」部分)に分離しましたよね。次は問題と解答を交互に見ながら解法を作っていこうというお話です。で、この解法部分が「分類器」と呼ばれ、解法を作成することを「分類器の作成」と言います。  数学の問題と一緒で解法は幾つでもあります。ですが、数学の解法と同じで正解率が高くなる解法は存在します。つまり、正解の解法は存在しないけれども限りなく正しいと呼べる解法は確かに存在します。  データコンペティションはこの限りなく正しい解法を生み出す作業なのです。  しかし、一から解法を作り出すのは難しいためすでに用意されているものがいくつも存在します。が、今回ここはスルーします。  また具体的な分類器の使用もしないことからPythonコードもありません。  ここは今はイメージの中で大丈夫です。実際にデータ分析をする際に「Python 分類器」で調べると優秀な方々が記事をたくさん書いてくださっています。また、最初から問題を解けないのと一緒で最初から分類器の作成なんてできません。最初はコピペをしながらどんな風に問題を解いているのか、どのような問題に威力を発揮するのかを体験するところから始めてみましょう。   6.分類器を評価データに当てはめよう  ここまでくればもう難しいことはありません。最初の方に説明しましたが、評価データは「センター試験」のようなものです。さらに5章で解法についても学びました。  評価用データは「センター試験」です。当たり前ですが、答えが最初から書いてあるわけじゃないですし、自分で解答を別冊にうつすなんで操作も必要になりません。(もし必要なら大問題ですよね笑)  ここで僕たちがやらなきゃいけないのは今まで学んできた解法を全く同じように生かすことだけです。センター試験とは違い、人間ではなく機械(Python)が回答を記入していくので緊張で解けなかった、、なんてこともありません。  ここではなんの祈りも通用しません。もっと問題を解いておけばよかった、なんて考えてももう遅いです。自分がやってきたものそのものをテストにぶつけることしかできません。  何を言いたいのかというと、ここで何か特別な作業は必要になりません。今まで訓練データを使って作ってきた分類器(解法)をあくまで全く同じように評価データに使います。  そうすると、Pythonが答えを返してくれます。ここまでで答えを出すことに成功しました。最後にその答えを回答用紙に記述する過程が残っています。では、最後にそこをみて終わりましょう。  今回も具体的な操作がないため、Pythonコードは省略します。  7.答えを応募用サンプルファイルに入れよう  さて、長かったこの記事も終わりが見えてきましたね。あとひと踏ん張りです!    では、つい先ほど得た答えを回答用紙に記入していきましょう。SIGNATEの中では応募用サンプルファイルが解答用紙に当たるんでしたよね。応募用サンプルファイルはセンター試験の解答用紙とほぼ同じです。問題番号が振られており、それに対応する答えを記入していきます。  つまり、応募用サンプルファイルの一行目はいわば「問題番号」が振られています。なので二行目に解答を記入していきます。  二行目にこれまでで得た解答を記入すればもう終わりです。と言いたいところですがそうは問屋がおろしません。笑  何が問題なのかというと、手元に答えが入った解答用紙があるのは良いのですが黙っていたままでは試験官が解答用紙を取りに来てはくれません。というより、解答用紙は自分から試験官に出しに行かなきゃ行けません。なので解答用紙を自分のパソコン上に落として、そのファイルをSIGNATEという試験官に提出します。そこまですれば本当に終わりです。  最後に7章で触れた操作についてPythonコードでみていきましょう。(結構難しいので一旦スルーでも大丈夫です) sample.py import numpy as np #6章で得た解答をy_predに入れる(行列にする必要がある) y_pred = np.array(['予測された値']) #応募用サンプルファイルのインポート(ヘッダーがふられているのでheader = Noneで削除) df_sample = pd.read_csv('sample_submit.csv',header = None) #応募用サンプルファイルの2列目を選択してそこにy_predを入れる df_sample.iloc[:,1] = y_pred #df_sampleを自分のパソコン上に落とす(ここでもヘッダー・フッダーを落とす必要あり) df_sample.to_csv('(自分の好きな名前).csv',header=None,index=None)  8.さいごに  最後まで読んでくださりありがとうございました。また、お疲れ様でした。    最初にも述べましたが厳密に言えば間違っている部分も存在しますが重要な部分はできるだけ簡単に、できるだけ厳密性を欠かないように配慮しています。また、初学者の方は流れを掴んでいただくだけで良いと思います。最初からPythonコードに手を出してもわからないものにわからないものが積み重なって嫌になってしまうものです。できないことは決して恥ずべきことではなく、できないことに挑戦しようとしている今の姿勢ほどかっこいい姿勢はないと思います!  今回の記事がほんの少しでもためになっていれば幸いです。    
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【VScode】pytestによる単体テスト実行 & カバレッジ可視化方法

はじめに VScode上でのpytestを利用した単体テスト実行とカバレッジ可視化の方法に関する個人的な備忘録です。 主に以下のことを記載。 poetryを利用した単体テスト実行可能なプロジェクト雛形作成 VScodeのテストエクスプローラー上での単体テスト(pytest)実行方法 VScode拡張機能を利用したテストカバレッジ(pytest-cov)計測結果のVScode上での可視化設定 python=v3.8、VScode=v1.6.1で動作を確認 単体テストプロジェクト作成 下記コマンドでプロジェクト雛形(pytestdemo)を作成する。 poetryによるプロジェクト雛形作成 # プロジェクト雛形作成コマンド(src layout) poetry new pytestdemo --src cd pytestdemo # pytestとpytest-covを開発環境用ライブラリとしてインストール poetry add pytest pytest-cov --dev # プロジェクトのパッケージへのPYTHONPATH設定を追加するために実行 # このコマンドを実行しない場合、単体テスト実行時に「Module not found error」が発生するため注意 poetry install # rstよりmdのほうが好みなので変更 mv README.rst README.md 下記の単体テストデモ用のコードを追加したプロジェクトで以降の単体テスト実行の説明を進める。 src/pytestdemo/calc.py 単純な加算(add)・減算(sub)・乗算(multiply)・除算(divide)の関数を実装 tests/test_calc.py calc.pyの単体テストを実行 プロジェクト構成 . ├── README.md ├── poetry.lock ├── pyproject.toml ├── src │   └── pytestdemo │   ├── __init__.py │   └── calc.py └── tests ├── __init__.py └── test_calc.py src/pytestdemo/calc.py def add(val1: int, val2: int) -> int: return val1 + val2 def sub(val1: int, val2: int) -> int: return val1 - val2 def multiply(val1: int, val2: int) -> int: return val1 * val2 def divide(val1: int, val2: int) -> float: if val2 == 0: raise ZeroDivisionError() return val1 / val2 tests/test_calc.py import pytest from pytestdemo.calc import add, divide, multiply, sub def test_add(): assert add(6, 3) == 9 def test_sub(): assert sub(6, 3) == 3 def test_multiply(): assert multiply(6, 3) == 18 def test_divide_ok(): assert divide(6,3) == 2 # 「カバレッジ = 100%」にしない場合の確認のためコメントアウト # def test_divide_zero_division_error(): # with pytest.raises(ZeroDivisionError): # assert divide(6, 0) 作成したプロジェクトは自分のGitHubレポジトリにも置いているので、興味があれば参照してください。 VScode上での単体テスト実行 VScode標準のPython拡張機能はインストール済であることを想定。 単体テスト実行設定 pytestをpythonの単体テストツールとして有効化するための設定を記述する。 .vscode/settings.json(またはユーザー用のsettings.json) { // 単体テストツールとしてpytestを有効化 "python.testing.pytestEnabled": true, // ファイル保存時にテスト対象コードを自動的に探索 "python.testing.autoTestDiscoverOnSaveEnabled": true, } テストエクスプローラーでの単体テスト実行 正しく設定がされていれば、以下のようにVScode上で単体テストを実行できるようになる。 VScode上でのカバレッジ可視化実行 カバレッジ可視化はVScode拡張機能のCoverage Guttersを利用することで可能となる。事前にインストールしておく。 カバレッジ可視化実行設定 .vscode/settings.json(またはユーザー用のsettings.json) { // 単体テストツールとしてpytestを有効化 "python.testing.pytestEnabled": true, // ファイル保存時にテスト対象を自動的に探索 "python.testing.autoTestDiscoverOnSaveEnabled": true, // pytest実行時の引数設定を追加 // --cov: カバレッジ計測の有効化 // --cov-report xml: カバレッジ計測レポートをxml形式(coverage.xml)で出力 "python.testing.pytestArgs": ["--cov=src", "--cov-report", "xml"], // エディタ上のカバレッジ表示設定 // ガター(ブレークポイント等が表示される場所)でのカバレッジ表示有無(default: true) "coverage-gutters.showGutterCoverage": true, // エディタ行でのカバレッジ表示有無(default: false) "coverage-gutters.showLineCoverage": true, // ルーラーでのカバレッジ表示有無(default: false) "coverage-gutters.showRulerCoverage": true } pytest実行時の引数設定はpyproject.tomlからも設定が可能 (参考リンク) カバレッジ可視化実行 VScode上のテストエクスプローラーから単体テストを実行後、下記のようにフッターの◯ Watchをクリックすることでカバレッジをエディタ上に表示ができる。 カバレッジ計測データは、pytestが単体テスト実行時に出力・更新するcoverage.xmlより取得をしている。 単体テストが実施された「テストカバレッジ=90%」分のコードが緑色で可視化され、 残りの単体テスト未実施の0除算関連のコードは赤色で可視化されている。 デバッグ設定との競合解決方法 VScodeではpytestによるカバレッジ取得設定(--cov)時に、そのままでは単体テストでのデバッグが出来ない仕様となっている。 以下、VScode公式サイトのカバレッジ取得設定とデバッグ設定の競合に関する記載です。 Note If you have the pytest-cov coverage module installed, VS Code doesn't stop at breakpoints while debugging because pytest-cov is using the same technique to access the source code being run. To prevent this behavior, include --no-cov in pytestArgs when debugging tests, for example by adding "env": {"PYTEST_ADDOPTS": "--no-cov"} to your debug configuration. (See Debug Tests above about how to set up that launch configuration.) (For more information, see Debuggers and PyCharm in the pytest-cov documentation.) 要約すると、カバレッジ取得とデバッグで同一の技術を利用しているため、カバレッジ取得設定がされている場合にデバッグ時にブレークポイントで正常に止まらなくなるらしい。 下記のようにデバッグ用の設定ファイルに記述を加え、単体テストデバッグ時のカバレッジ取得設定をオフ(--no-cov)にすることで、正常にデバッグを実行できるようになる。 .vscode/launch.json { // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "Python: Current File", "type": "python", "request": "launch", "program": "${file}", + "purpose": ["debug-test"], "console": "integratedTerminal", + "env": { "PYTEST_ADDOPTS": "--no-cov" } } ] } 上記の設定により、カバレッジ取得設定時でもデバッグが可能となったことが確認できる。 参考 Python testing in Visual Studio Code pythonのカバレッジをpytest-covで調べる VSCodeでカバレッジを表示する(pytest-cov)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【python】モンティホール問題

モンティホール問題とは プレーヤーの前に閉じた3つのドアがあって、1つのドアの後ろには景品の新車が、2つのドアの後ろには、はずれを意味するヤギがいる。プレーヤーは新車のドアを当てると新車がもらえる。プレーヤーが1つのドアを選択した後、司会のモンティが残りのドアのうちヤギがいるドアを開けてヤギを見せる。 ここでプレーヤーは、最初に選んだドアを、残っている開けられていないドアに変更してもよいと言われる。 ここでプレーヤーはドアを変更すべきだろうか? wikipediaより引用 https://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%B3%E3%83%86%E3%82%A3%E3%83%BB%E3%83%9B%E3%83%BC%E3%83%AB%E5%95%8F%E9%A1%8C pythonによるシミュレーション monty_hall.py import random def monty_hall(n_trial=1000, change_door=True): n_wins = 0 for i in range(n_trial): doors = [0, 0, 0] win_place = random.randint(0, 2) doors[win_place] = 1 choice = random.randint(0, 2) # ハズレドアの1つを公開 if doors[choice] == 0: revealed = 3 - choice - win_place else: revealed = (choice + random.randint(1, 2)) % len(doors) # ドアを変えたければ変える if change_door: choice = 3 - revealed - choice if doors[choice] == 1: n_wins += 1 return n_wins n = 1000 print("ドアを変えた場合 : {} 回中勝ち {} 回。".format(n, monty_hall(n_trial=n, change_door=True))) print("ドアを変えない場合 : {} 回中勝ち {} 回。".format(n, monty_hall(n_trial=n, change_door=False))) ドアが3つしかないのでドアインデックスの和を利用することで少し簡潔に書くことができる。 結果 ドアを変えた場合 : 1000 回中勝ち 668 回。 ドアを変えない場合 : 1000 回中勝ち 354 回。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC159 C - Maximum Volume を解いた

確証はないが、サンプルが三等分してるので、 マネしてみた。 abc159c.py L = int(input()) print("{:.6f}".format( (L/3)**3 ))
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Blenderのコマンドサンプル

目的 Blender2.93でPythonを実行するコマンドのサンプルを紹介します。 macOSの例ですが、適宜読み替えればWindowsでも動くはずです。 作成するコマンドの内容 コマンドの引数にテキストを指定すると、Blenderでテキストオブジェクト、カメラ、ライトを作成しBlenderファイルとして保存したり、レンダリングしてPNGファイルを作成したりします。 コード 機能は、Scriptingの「テンプレート → Python → Background Job」のコードをベースに下記の2点を修正しました。 argparseでなくFireを使うように修正。Fireについては「Python-Fireについて」を参照されたし。 ライトの明るさを1000Wに修正。 background_job.py import sys import bpy import fire def example_function(text, render_path=None, save_path=None): # Clear existing objects. bpy.ops.wm.read_factory_settings(use_empty=True) scene = bpy.context.scene txt_data = bpy.data.curves.new(name="MyText", type="FONT") # Text Object txt_ob = bpy.data.objects.new(name="MyText", object_data=txt_data) scene.collection.objects.link(txt_ob) # add the data to the scene as an object txt_data.body = text # the body text to the command line arg given txt_data.align_x = "CENTER" # center text # Camera cam_data = bpy.data.cameras.new("MyCam") cam_ob = bpy.data.objects.new(name="MyCam", object_data=cam_data) scene.collection.objects.link(cam_ob) # instance the camera object in the scene scene.camera = cam_ob # set the active camera cam_ob.location = 0.0, 0.0, 10.0 # Light light_data = bpy.data.lights.new("MyLight", "POINT") light_ob = bpy.data.objects.new(name="MyLight", object_data=light_data) scene.collection.objects.link(light_ob) light_ob.location = 2.0, 2.0, 5.0 light_data.energy = 1000 bpy.context.view_layer.update() if save_path: bpy.ops.wm.save_as_mainfile(filepath=save_path) if render_path: render = scene.render render.use_file_extension = True render.filepath = render_path bpy.ops.render.render(write_still=True) if __name__ == "__main__": sys.argv = sys.argv[:1] + sys.argv[(sys.argv + ["--"]).index("--") + 1 :] fire.Fire(example_function) background_job.pyとして作成してください。 準備 コマンドをシンプルに記述するために、シェルで下記を設定しているとします。 alias blender=/Applications/Blender.app/Contents/MacOS/Blender alias blender_pip="/Applications/Blender.app/Contents/Resources/2.93/python/bin/python3.9 -m pip" 下記のようにしてfireをインストールします。 blender_pip install -U fire 実行 下記のようにしてシェルで実行します。 blender -b -P background_job.py -- 'Hello Blender!' img -bは、バックグラウンド実行の指定です。 -P Pythonファイルで、Pythonファイルを実行します。 --以降に、Pythonファイル用のオプションを指定します。 下記のようにimg.pngが作成されます。 また、コマンドの最後にファイル名を指定すると、Blenderファイルとして保存できます。 以上
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC158 C - Tax Increase から学んだ

油断したつもりはなかったが WA abc158c_ng.py A,B = map(int,input().split()) from math import floor for x in range(1,101): #<= ここ if floor(x*0.08) == A and floor(x*0.1) == B: print(x) exit() print(-1) 敗因はコメントにあるここ。 A,B は max 100 .つまり 答えの数値を 1/100 して 100 なわけだから 100 の 100 倍は最低でも覚悟しないとダメ。 一応、多めに for は回してみた。 abc158c_ok.py A,B = map(int,input().split()) from math import floor for x in range(1,10**5+1): if floor(x*0.08) == A and floor(x*0.1) == B: print(x) exit() print(-1)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[AWS]IAM認証をかけたAPIGatewayを別アカウントのLambdaから呼び出す構成をSAMで作成してみた

記事のタイトルが長くなってしまったのですが、主要な構成は以下です。 アカウントA - APIGateway(IAM認証付き) - Lambda アカウントB - Lambda フロー アカウントB.Lambda ⇒ アカウントA.APIGateway ⇒ アカウントA.Lambda 細かく見ていきましょう。 Githubリポジトリ 今回記事で解説している構成を作成した際のソースをgithubにプッシュしました。 もし同じような構成を作っていて困っている方がいたら、ソースをいじってデプロイしてみてください! ※使う際はいくつかのパラメータをご自身の環境に合わせて設定していただく必要があります。 注意 こちらの記事はPython, AWS SAMを利用しています。 Pythonではさらに、Boto3, aws_requests_auth のライブラリを利用しています。 動くところまでどうにか作ったものなので、もっと良い構成や実装、間違っている点があればご指摘頂けると勉強になります。 本記事の対象者 コアなケースですので、あまり対象者はいないかもしれません。それ故に情報が無かったので、記事にすることにしました。 AWSのAPIGateway, Lambda, IAMロールが分かる人 「APIGatewayにIAM認証をかける」が分かる人 SAM、又はCloudFormationを利用してAWSリソースをデプロイした経験がある人 他アカウントのLambdaからIAM認証をかけたAPIGatewayを呼び出したい人 構成について 今回実装した構成は、APIGatewayのアカウントとAPIGatewayを呼び出すLambdaのアカウントが別であり、APIGatewayにはIAM認証が必要という構成図です。 以下構成図です。 構成の詳細: APIGateway Account まず、こちらの構成の詳細を解説します。 APIGateway Accoutでは、IAM認証のかかったAPIGateway、呼び出し先のLambdaが基本の構成です。 こちらのAPIGatewayが別アカウントから呼び出され、最終的にLambda関数の結果が戻されます。 このアカウントでポイントとなるのが、IAMロールの存在です。 こちらのIAMロールのSAMテンプレートを見てみましょう。すべて見る必要は全くないです。ポイント1,ポイント2だけ見てください。 template.yaml APIGatewayRole: Type: "AWS::IAM::Role" Properties: RoleName: !Ref RoleName Path: "/" ManagedPolicyArns: - "arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs" Policies: - PolicyName: "authorizerLambdaInvokeAccess" PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: #...............ポイント1:Lambda周りの権限も必要 - lambda:InvokeAsync - lambda:InvokeFunction - execute-api:Invoke Resource: "*" #...............ポイント2:このIAMロールを他で使えるようにAssumeRolePolicyを規定する AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Sid: "AllowApiGatewayServiceToAssumeRole" Effect: "Allow" Action: - "sts:AssumeRole" Principal: AWS: - !Sub "arn:aws:iam::${AnotherAccountID}:role/FromLambdaRole" ポイント1: Lambda周りの権限も必要 ポイント2: このIAMロールを他で使えるようにAssumeRolePolicyを設定する Lambda周りの権限も必要 今回の構成では、APIGatewayに渡ってきた認証情報を、APIGatewayのロールとして利用します。 詳しくは、以下の記事に書いた情報を確認ください。 そのため、APIGatewayがLambdaを実行できる権限も必要なため、その権限を付けています。 AssumeRolePolicyを設定する AssumeRolePolicyとは、STS(Security Token Serivce )にてAssumeRoleする際に利用するPolicyです。 では、STSのAssumeRoleとはなんでしょう? それは、IAMロールが持っている権限を一時的に別のユーザーやロールに付与する動作のことです。 今回はAPIGateway Accountで作成したIAMロールによってAPIGatewayのIAM認証を行うので、こちらのIAMロールの権限をLambda AccountのIAMロールに付与する必要があります。 そこで、AssumeRolePolicyに権限を付与する対象を記載しているのです。 以下を見てみましょう。 Principal: AWS: - !Sub "arn:aws:iam::${AnotherAccountID}:role/FromLambdaRole" 他アカウントのIAMロールであるFromLambdaRoleに「AssumeRoleをしてもよい」という許可を出しています。 構成の詳細: Lambda Account 次に、Lambdaアカウントの構成を解説します。 ポイントとなるのは、「APIGateway AccountのIAMロール」から権限をもらうことが許可されている、IAMロールです。 こちらのIAMロールをLambdaにアタッチすることで、Lambdaにて「APIGateway AccountのIAMロール」を利用することができます。そして、「APIGateway AccountのIAMロール」を使ってLambdaからAPIGatewayを呼び出すことができます。 呼び出し時のソースを見てみましょう。 app.py credentials = get_credentials() # ...............ポイント1: IAMの認証情報を取得する auth = AWSRequestsAuth( aws_access_key=credentials['AccessKeyId'], aws_secret_access_key=credentials['SecretAccessKey'], aws_host=aws_host, aws_region=REGION_NAME, aws_service='execute-api' ) headers = {'x-amz-security-token': credentials['SessionToken']} # ............... ポイント2: IAMの認証情報を送る response = requests.post( url, json={"foo": "bar"}, auth=auth, headers=headers) def get_credentials(): client = boto3.client('sts') IAM_ROLE_ARN = os.environ['IAM_ROLE_ARN'] IAM_ROLE_SESSION_NAME = 'other_account_session' response = client.assume_role( RoleArn=IAM_ROLE_ARN, RoleSessionName=IAM_ROLE_SESSION_NAME ) return response['Credentials'] ポイント1: IAMの認証情報を取得する ポイント2: IAMの認証情報を送る STSを利用し、IAMの認証情報を取得する 先ほどAPIGateway Accountの解説の際に出てきたSTSのAssumeRoleを利用し、IAMロールの認証情報を取得しています。 こちらをAPIGatewayを呼び出す際にヘッダーに渡してあげることで、IAM認証のかかったAPIGatewayを呼び出すことが出来ます。 IAMの認証情報を送る requests.postの中で、IAMロールの認証情報を一緒に送信して上げましょう。 response = requests.post( url, json={"foo": "bar"}, auth=auth, headers=headers) 以上のようにすることで、別アカウントからのAPI呼び出しが可能になります。 感想 1番辛かった作業は、SAMの書き方を調べながら書くことです。 SAMは使っている人が少ないせいもあり、なかなか情報が少ないです。 また、公式ドキュメントも最低限の情報しか書いてないので中々苦労します。日本語訳が割と雑なのはまだ良いのですが、英語で読んでも欲しい情報に中々辿り着けません。 今度IaCするときは、terraformとかを使ってみようかなと思いました。 参考記事
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC156 C - Rally を解いた

文章通り入れてみた。別に sort しなくても 良いと思うけど。。。 abc156c.py N = int(input()) X = list(map(int,input().split())) X.sort() ans = float("inf") for i in range(1,101): score = 0 for j in range(N): score += (X[j]-i)**2 ans = min(score,ans) print(ans)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

M1 Macでのpython環境の構築(pyenv + miniforge)

はじめに これまでなんとなく利用してきた Mac での python 環境を見直し、pyenv + miniforge で環境構築し、気象ライブラリであるMetpyとJupiter Labを利用可能にしたため、その過程を記録する。 python環境見直しの一つのきっかけは、これまで利用していたpythonのpipを使ってMetPyがインストールできなかったことであった。 目標 pyenv + miniforge で python 環境を構築する MetPyを Jupyter Lab で利用できるようにする 環境 PC: Makbook Pro (13-inch, M1, 2020) OS: MacOS Big Sur (Version 11.5.2) 方針 pyenv でpythonの実行環境を管理する miniconda のフォークである miniforge (3-4.10.1-5)を用いる miniforgeとはさまざまなCPUアーキテクチャ(intelのx86_64やppc64le、Apple M1を含むaarch64)のサポートに重点を置いたMiniconda。 M1チップでは、pyenvを用いてpython(3.10.0や3.9.7)やanaconda3-2021.05がインストールできなかった。このため、M1チップで利用可能なminiforgeを用いることにした。 パッケージ管理は conda で行う miniforgeはconda 系のパッケージ管理ツールであるため 参考HP 上記HPでは以下の3つの方法が記述されており、今回は2を選択した。 1. Homebrewで直接pythonをインストールする 2. Anaconda環境(miniforge)を使う 3. Dockerを使う M1 Macの罠が詳しく書かれている インストール pyenv のインストール git を利用して、ホームディレクトリ以下にpyenvをインストールした。 $ git clone https://github.com/pyenv/pyenv.git ~/.pyenv .bashrcの設定と読み込み $ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc $ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc $ echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n eval "$(pyenv init -)"\nfi' >> ~/.bashrc $ source .bashrc pyenv の利用法 python や miniconda などのインストール可能なパッケージの表示 $ pyenv install --list pyenv-virtualenvのインストール 現状まだ利用していないが、インストールしておく。 $ git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv $ echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bashrc miniforgeのインストール インストール $ pyenv install miniforge3-4.10.1-5 利用するパッケージ(miniforge)を指定する。 $ pyenv global miniforge3-4.10.1-5 global は自分がいるディレクトリに関わらず適用される設定。 (特定のディレクトリ以下に適用させるには global ではなく local とする。) 今現在インストールされているPythonやminiforgeのバージョンを確認 $ pyenv versions system * miniforge3-4.10.1-5 (set by /Users/katon/.pyenv/version) ~/.pyenv 以下にインストールされた miniforgeが利用されていることを確認できる。 ここで、system というのはpyenvではなく、OS側で用意されているpythonになる。 condaコマンドを利用可能にする $ conda activate コマンドラインが以下の表示になる (base) (miniforge3-4.10.1-5) katon@kyudai ~ % conda コマンドは以下を参照。 metpyのインストール $ conda install -c conda-forge metpy jupyterのインストール Jupyter Notebookの後継であるJupyterLabを利用するためには、jupyterをインストールすればよい。 インストール $ conda install jupyter 以下のコマンドで jupiter lab が起動できた。 $ jupyter lab MetPyの以下のサンプルコードがjupiter lab上で動くことが確認できた。 scikit image のインストール conda install scikit-image
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC154 C - Distinct or Not を解いた

うん。できた。 abc154c.py N = int(input()) A = list(map(int,input().split())) print("YES" if len(list(set(A))) == len(A) else "NO" )
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【図解】seq2seqによる機械翻訳 サンプルコード

seq2seqによる機械翻訳の仕組みについて理解を深めるため、Kerasを用いたseq2seqのサンプルコードについて調査しました。私がこれまで学んできた一般的なディープニューラルネットワーク(DNN)やCNNと比べると、モデル定義や推定処理等の実現方法が色々異なっており初見では取っ付きにくかったので、調査結果を備忘録として本記事に残すことにしました。 はじめに この記事のゴール seq2seqのサンプルコードで使用されているモデル構造や処理フローの全体像について把握することで、seq2seqの仕組みについて理解する この記事の対象者 深層学習や機械翻訳の初学者 パッケージ化されたseq2seqのAPIではなく、KerasのLSTM等を用いたseq2seqの実現方法について興味がある方 ※サンプルコードの動かし方については本記事では扱いません。  サンプルコード中のコメント文の説明で動かし方が記載されていますので、興味のある方はそちらをご参照下さい。 参考元のソースコード 下記のGitHubで掲載されているサンプルコードを参照し、本記事で解説させて頂いています。 https://github.com/awslabs/keras-apache-mxnet/blob/master/examples/lstm_seq2seq.py ※上記のコードは下記URLのkeras-team様のコードからforkしたものであるようですが、keras-team様のGitHubコードはその後更新されており、現時点では所々差分がありますのでご留意ください。(見比べたところモデルの構成や処理フローに大きな変更はありません) https://github.com/keras-team/keras-io/blob/master/examples/nlp/lstm_seq2seq.py seq2seqとは エンコーダとデコーダで構成される、機械翻訳で使用される深層学習アルゴリズムです。 エンコーダは翻訳対象の単語を受け取ると、その単語の意味情報が圧縮された「状態」を出力してデコーダに受け渡し、それを基にデコーダが別言語の単語に翻訳するというものです。デコーダでは全文字を一発で出力するのではなく先頭から1文字ずつ出力し、出力した文字を用いてさらに次の文字を出力していくという流れで単語を翻訳します。 ソースコード解説 各処理の概要を順番に説明します。 学習データの用意 ソースコードのコメント文に記載されているURLから英語とフランス語の単語表のテキストファイルを入手し、それを1行ずつ読み取って下記の学習データセットを用意します。 エンコーダの入力データ: 各行の英単語をOneHot表現に置きかえたもの デコーダの入力データ: 各行のフランス語の単語の先頭と終端にそれぞれSOS(\t)とEOS(\n)を付与し、OneHot表現に置きかえたもの デコーダの出力データの正解ラベル: デコーダの入力データを1文字ずつ手前にずらしたもの ちなみに上記の各入出力データは、各単語の文字をOneHotベクトル化したことで下図のような3次元データになっています。seq2seqでは各単語を文字が順番に並んだ時系列データとして扱ってLSTMで処理しているので、このような前準備が必要になるのですね。 モデルの定義 モデルは主にエンコーダとデコーダで構成され、それぞれKerasのLSTMレイヤと、デコーダについては翻訳後の文字を推定するためのDenseレイヤ(全結合層)が使用されています。 また、一般的なDNNやCNN等では一旦モデルを定義したらそれを学習と推定の両方で使用するかと思いますが、seq2seqでは学習完了後にモデルを再定義して推定に使用しています。 学習時: エンコーダとデコーダを1つのモデルインスタンスにパッキングして定義 推定時: エンコーダとデコーダを別々のモデルインスタンスとして定義 なお、推定時にモデルを再定義する際には、学習で使用したLSTMやDenseレイヤのインスタンスを流用して推定用モデルを定義します。これによって、学習した各レイヤのパラメータを保持しつつも、学習時とは異なったモデル構造で推定処理を行うことが可能になります。(個人的にはこの発想が斬新でした) 学習処理 上記で用意したエンコーダとデコーダの入力データ、およびデコーダの出力データの正解ラベルを引数として、学習用モデルのfitメソッドを実行するだけです。fitメソッドの第一引数にエンコーダとデコーダの入力データをリスト化して与えている点以外は、特に変わった点はありません。 推定処理 推定処理は若干複雑です。通常のDNN等ではpredictメソッドを1回実行するだけで各サンプルの推定処理が行われますが、このseq2seqではエンコーダとデコーダで個別にpredictを実行し、さらにデコーダの方では1文字ずつpredictを行い、その出力をさらに次のpredictの入力に手動で渡している点が特徴です。 具体的には、以下の処理を各英単語ごとに実行し、フランス語の各単語を出力していきます。 ① 英単語をOneHotベクトル化したデータを入力として、エンコーダモデルのpredictメソッドを実行  ⇒ 英単語の意味情報が圧縮された状態変数(h,c)が出力される。 ② エンコーダモデルから出力された状態変数と、デコーダの入力データの初期値(\t)を入力として、デコーダモデルのpredictメソッドを実行  ⇒ 状態変数とフランス語の1番目の文字が何であるかを示す確率が出力されるので、    np.argmaxやインデックス⇒フランス語文字への変換テーブルを用いて    フランス語文字へ変換する。 ③ ②で出力された状態変数と、②で推定したフランス語の文字をOneHotベクトル化したものを入力として、デコーダのpredictメソッドを実行  ⇒ 再度状態変数と次のフランス語の文字の推定値が出力されるので、②と同様にして    フランス語の文字に変換する。以降、EOS(\n) or フランス語単語の最大長に    達するまでこれを繰り返す。 さいごに 以上、Kerasを用いたseq2seqのサンプルコードの解説でした。 実際に機械翻訳を実装する際にはパッケージ化されたライブラリ(TensorFlowのAddonプロジェクト等)や翻訳サイト等が公開しているWebAPIを使用することが多いかと思いますが、seq2seqの仕組みの理解の際にご参考にして頂ければ幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【解説】seq2seqによる機械翻訳 サンプルコード

seq2seqによる機械翻訳の仕組みについて理解を深めるため、Kerasを用いたseq2seqのサンプルコードについて調査しました。私がこれまで学んできた一般的なディープニューラルネットワーク(DNN)やCNNと比べると、モデル定義や推定処理等の実現方法が色々異なっており初見では取っ付きにくかったので、調査結果を備忘録として本記事に残すことにしました。 はじめに この記事のゴール seq2seqのサンプルコードで使用されているモデル構造や処理フローの全体像について把握することで、seq2seqの仕組みについて理解する この記事の対象者 深層学習や機械翻訳の初学者 パッケージ化されたseq2seqのAPIではなく、KerasのLSTM等を用いたseq2seqの実現方法について興味がある方 ※初学者の方もある程度イメージが持てるよう、図を活用して説明します。 ※サンプルコードの動かし方については本記事では扱いません。  サンプルコード中のコメント文の説明で動かし方が記載されていますので、興味のある方はそちらをご参照下さい。 参考元のソースコード 下記のGitHubで掲載されているサンプルコードを参照し、本記事で解説させて頂いています。 https://github.com/awslabs/keras-apache-mxnet/blob/master/examples/lstm_seq2seq.py ※上記のコードは下記URLのkeras-team様のコードからforkしたものであるようですが、keras-team様のGitHubコードはその後更新されており、現時点では所々差分がありますのでご留意ください。(見比べたところモデルの構成や処理フローに大きな変更はありません) https://github.com/keras-team/keras-io/blob/master/examples/nlp/lstm_seq2seq.py seq2seqとは エンコーダとデコーダで構成される、機械翻訳で使用される深層学習アルゴリズムです。 エンコーダは翻訳対象の単語を受け取ると、その単語の意味情報が圧縮された「状態」を出力してデコーダに受け渡し、それを基にデコーダが別言語の単語に翻訳するというものです。デコーダでは全文字を一発で出力するのではなく先頭から1文字ずつ出力し、出力した文字を用いてさらに次の文字を出力していくという流れで単語を翻訳します。 ソースコード解説 各処理の概要を順番に説明します。 学習データの用意 ソースコードのコメント文に記載されているURLから英語とフランス語の単語表のテキストファイルを入手し、それを1行ずつ読み取って下記の学習データセットを用意します。 エンコーダの入力データ: 各行の英単語をOneHot表現に置きかえたもの デコーダの入力データ: 各行のフランス語の単語の先頭と終端にそれぞれSOS(\t)とEOS(\n)を付与し、OneHot表現に置きかえたもの デコーダの出力データの正解ラベル: デコーダの入力データを1文字ずつ手前にずらしたもの ちなみに上記の各入出力データは、各単語の文字をOneHotベクトル化したことで下図のような3次元データになっています。seq2seqでは各単語を文字が順番に並んだ時系列データとして扱ってLSTMで処理しているので、このような前準備が必要になるのですね。 モデルの定義 モデルは主にエンコーダとデコーダで構成され、それぞれKerasのLSTMレイヤと、デコーダについては翻訳後の文字を推定するためのDenseレイヤ(全結合層)が使用されています。 また、一般的なDNNやCNN等では一旦モデルを定義したらそれを学習と推定の両方で使用するかと思いますが、seq2seqでは学習完了後にモデルを再定義して推定に使用しています。 学習時: エンコーダとデコーダを1つのモデルインスタンスにパッキングして定義 推定時: エンコーダとデコーダを別々のモデルインスタンスとして定義 なお、推定時にモデルを再定義する際には、学習で使用したLSTMやDenseレイヤのインスタンスを流用して推定用モデルを定義します。これによって、学習した各レイヤのパラメータを保持しつつも、学習時とは異なったモデル構造で推定処理を行うことが可能になります。(個人的にはこの発想が斬新でした) 学習処理 上記で用意したエンコーダとデコーダの入力データ、およびデコーダの出力データの正解ラベルを引数として、学習用モデルのfitメソッドを実行するだけです。fitメソッドの第一引数にエンコーダとデコーダの入力データをリスト化して与えている点以外は、特に変わった点はありません。 推定処理 推定処理は若干複雑です。通常のDNN等ではpredictメソッドを1回実行するだけで各サンプルの推定処理が行われますが、このseq2seqではエンコーダとデコーダで個別にpredictを実行し、さらにデコーダの方では1文字ずつpredictを行い、その出力をさらに次のpredictの入力に手動で渡している点が特徴です。 具体的には、以下の処理を各英単語ごとに実行し、フランス語の各単語を出力していきます。 ① 英単語をOneHotベクトル化したデータを入力として、エンコーダモデルのpredictメソッドを実行  ⇒ 英単語の意味情報が圧縮された状態変数(h,c)が出力される。 ② エンコーダモデルから出力された状態変数と、デコーダの入力データの初期値(\t)を入力として、デコーダモデルのpredictメソッドを実行  ⇒ 状態変数とフランス語の1番目の文字が何であるかを示す確率が出力されるので、    np.argmaxやインデックス⇒フランス語文字への変換テーブルを用いて    フランス語文字へ変換する。 ③ ②で出力された状態変数と、②で推定したフランス語の文字をOneHotベクトル化したものを入力として、デコーダのpredictメソッドを実行  ⇒ 再度状態変数と次のフランス語の文字の推定値が出力されるので、②と同様にして    フランス語の文字に変換する。以降、EOS(\n) or フランス語単語の最大長に    達するまでこれを繰り返す。 さいごに 以上、Kerasを用いたseq2seqのサンプルコードの解説でした。 実際に機械翻訳を実装する際にはパッケージ化されたライブラリ(TensorFlowのAddonプロジェクト等)や翻訳サイト等が公開しているWebAPIを使用することが多いかと思いますが、seq2seqの仕組みの理解の際にご参考にして頂ければ幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC153 C - Fennec vs Monster を解いた

たぶん、やり方は色々あると思う。 abc153c.py N,K = map(int,input().split()) H = list(map(int,input().split())) H.sort(reverse=True) #print(H) if K > N: H =[0] else: for i in range(K): H[i] = 0 print(sum(H))
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC152 C - Low Elements を解いた

文章のまま入力 abc152c.py N = int(input()) P = list(map(int,input().split())) x = P[0] lis = [x] for i in range(1,N): if x >= P[i]: lis.append(P[i]) x = P[i] print(len(lis))
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

畳み込みニューラルネットワークのオートエンコーダ 形状の不一致対処

背景 畳み込みニューラルネットワークによる自前データのオートエンコーダで、エンコード前の画像形状とデコード後の画像形状が一致せず苦労した時に学んだことを備忘録として記載する。 やったこと 畳み込みニューラルネットワークを組み、サマリーを表示 #畳み込みオートエンコーダ #keras.layersからInput関数, Dense関数、Conv2D関数、MaxPooling関数、UpSampling関数、Activation関数をインポート from keras.layers import Input, Dense, Conv2D, MaxPooling2D, UpSampling2D, Activation, Flatten #keras.modelsからModel関数をインポート from keras.models import Model #keras.callbacksからEarlyStopping関数をインポート from keras.callbacks import EarlyStopping es_cb = EarlyStopping(monitor='val_loss', patience=0, verbose=0, mode='auto') ##Encode部 input_img = Input(shape=(750, 750, 1)) #Input関数で入力として受け付けるデータの次元を指定 x = Conv2D(250, (3, 3), padding="same")(input_img) #受け付けたデータを250個からなるレイヤーに流す。3x3フィルター、ゼロパディングを使う x = Activation("relu")(x) x = MaxPooling2D((2, 2), padding="same") (x) #2x2に対してプーリングする x = Conv2D(125, (3, 3), padding="same")(x) #125個のレイヤーに流す。3x3フィルター、ゼロパディングを使う x = Activation("relu")(x) x = MaxPooling2D((2, 2), padding="same") (x) #2x2に対してプーリングする x = Conv2D(50, (3, 3), padding="same")(x) #50個のレイヤーに流す。3x3フィルター、ゼロパディングを使う x = Activation("relu")(x) x = MaxPooling2D((2, 2), padding="same") (x) #2x2に対してプーリングする x = Conv2D(25, (3, 3), padding="same")(x) #25個のレイヤーに流す。3x3フィルター、ゼロパディングを使う encoded = Activation("relu")(x) ##Decode部 x = Conv2D(25, (3, 3), padding="same")(encoded) x = Activation("relu")(x) x = UpSampling2D((2, 2)) (x) x = Conv2D(50, (3, 3), padding="same")(x) #50個のレイヤーに流す。3x3フィルター、ゼロパディングを使う x = Activation("relu")(x) x = UpSampling2D((2, 2)) (x) x = Conv2D(125, (3, 3), padding="same")(x) #125個のレイヤーに流す。3x3フィルター、ゼロパディングを使う x = Activation("relu")(x) x = UpSampling2D((2, 2)) (x) x = Conv2D(250, (3, 3), padding="same")(x) #250個のレイヤーに流す。3x3フィルター、ゼロパディングを使う x = Activation("relu")(x) x = Conv2D(1, (3, 3), padding="same")(x) #3x3フィルター、ゼロパディングを使う decoded = Activation("sigmoid")(x) #decoded変数に入れる model = Model(input_img, decoded) #Model関数で入力と出力を指定。入力と出力が指定した引数のようになるモデルにするということ model.compile(optimizer="adam", loss="binary_crossentropy") model.summary() Layer (type) Output Shape Param # ================================================================= input_11 (InputLayer) [(None, 750, 750, 1)] 0 _________________________________________________________________ conv2d_67 (Conv2D) (None, 750, 750, 250) 2500 _________________________________________________________________ activation_62 (Activation) (None, 750, 750, 250) 0 _________________________________________________________________ max_pooling2d_30 (MaxPooling (None, 375, 375, 250) 0 _________________________________________________________________ conv2d_68 (Conv2D) (None, 375, 375, 125) 281375 _________________________________________________________________ activation_63 (Activation) (None, 375, 375, 125) 0 _________________________________________________________________ max_pooling2d_31 (MaxPooling (None, 188, 188, 125) 0 _________________________________________________________________ conv2d_69 (Conv2D) (None, 188, 188, 50) 56300 _________________________________________________________________ activation_64 (Activation) (None, 188, 188, 50) 0 _________________________________________________________________ max_pooling2d_32 (MaxPooling (None, 94, 94, 50) 0 _________________________________________________________________ conv2d_70 (Conv2D) (None, 94, 94, 25) 11275 _________________________________________________________________ activation_65 (Activation) (None, 94, 94, 25) 0 _________________________________________________________________ activation_66 (Activation) (None, 94, 94, 25) 0 _________________________________________________________________ conv2d_71 (Conv2D) (None, 94, 94, 25) 5650 _________________________________________________________________ activation_67 (Activation) (None, 94, 94, 25) 0 _________________________________________________________________ up_sampling2d_15 (UpSampling (None, 188, 188, 25) 0 _________________________________________________________________ conv2d_72 (Conv2D) (None, 188, 188, 50) 11300 _________________________________________________________________ activation_68 (Activation) (None, 188, 188, 50) 0 _________________________________________________________________ up_sampling2d_16 (UpSampling (None, 376, 376, 50) 0 _________________________________________________________________ conv2d_73 (Conv2D) (None, 376, 376, 125) 56375 _________________________________________________________________ activation_69 (Activation) (None, 376, 376, 125) 0 _________________________________________________________________ up_sampling2d_17 (UpSampling (None, 752, 752, 125) 0 _________________________________________________________________ conv2d_74 (Conv2D) (None, 752, 752, 250) 281500 _________________________________________________________________ activation_70 (Activation) (None, 752, 752, 250) 0 _________________________________________________________________ conv2d_75 (Conv2D) (None, 752, 752, 1) 2251 _________________________________________________________________ activation_71 (Activation) (None, 752, 752, 1) 0 ================================================================= 学んだこと (None, 750, 750, 1)と(None, 752, 752, 1) が不一致のためエラーになったが、要因はmaxpoolingの際に375→188というところでズレが出ていること。 maxpoolingを3回やるなら、2の3乗の8の倍数になるようにする必要があり、その場合750ではなく760などにする必要がある。 しかし3次元のreshapeで掛け算のツジツマ合わせは難しいので、結論は、画像を例えば8の倍数のピクセルにしてから用いるのが良い。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

〇〇っぽく会話できるシステムに初心者が挑戦してみた

目次 1.初めに 2.対象となる人 3.使用した環境・技術 4.手順 5.完成したもの 6.最後に 1.初めに 2021年4月末よりaidemyで、Python(主として自然言語処理)の勉強を開始。 気がつくと半年近くとなり私のAidemy生活も残すところ僅かとなりました。 基礎学習さまざまな学習を行い、当初の目的であった業務に転用可能なプログラムを教えていただいたりと充実した日々を々を送ることができました。ブログねたとして、授業内容の再確認を兼ねて、ジャ〇〇ズぽい会話をしていくシステムづくりに挑戦した内容を書いていきます。 2.対象となる人 ・会話システムに興味のある方 ・自然言語処理に興味のある方 ・前回との成長を比較したい人 3.使用した環境・技術 ☆環境 Windows10 Visual Studio Code python3.8.11(anaconda3) ☆技術 Sequence to Sequence Model: mecab:形態素解析に使用します Chainer: フレームワークのひとつ ↓詳しくはこちらで解説されています Chainer チュートリアル BiLSTM: 2つの入力させる向きを組み合わせた双方向再帰ニューラルネットです。 ミニバッチ学習:  機械学習のパラメータ更新方法のひとつ  学習に用いるデータ全てで勾配を計算した後にモデルのパラメータを更新する  バッチ学習と学習データ1つごとにモデルのパラメータを更新するオンライン学習 の中間的手法となります。 1万件のデータがあった場合、例えば、その1万件のデータからランダムに100件 (ミニバッチ)、選び、その損失関数の平均を求め学習させ、学習が終わったら、 また100件ランダムに選び学習、といったのを繰り返していくといった手法です。 Attention : Attentionは、入力データのどの部分に注意を向けるのかを指示します ↓こちらの記事でわかりやすく解説されています 【深層学習】Attention機構とは何のか? モデルの全体図や手順はAidemy教材にわかりやすくまとめられていましたのでそれを引用させていただきます。 モデルの全体像は図。(図は1方向となっていますが、双方向の場合でも使用できます。) まずQuestionとAnswerを別々にBiLSTMに入力します。 次にQuestionからAnswerに対してAttentionをし、Questionを考慮したAnswerの情報を得ることができます。 その後にQuestionの各時刻の隠れ状態ベクトルの平均をとって(mean pooling)ベクトルqを得ます。 一方でQuestionからAttentionを施した後、Answerの各時刻の隠れ状態ベクトルの平均をとってベクトル$a$を得ます。 最後にこの2つのベクトルを$[q;a;|q-a|;q*a]$のように$q$, $a$, $|q-a|$, $q*a$ベクトルを結合して、順伝播ニューラルネット、Softmax関数を経て2つのユニットからなる出力になります。 この結合の仕方はFacebook researchが発表したInferSentという有名な手法を参考にしています。 このモデルの出力層はユニットが2つありますが、正解の回答文については[1,0]を、不正解の回答文については[0,1]を予測するように学習していきます。 図2.3.1-1 モデルの全体像 4.手順 ①必要なものをインポートしていきます。 # -*- coding: utf-8 -*- import datetime import numpy as np import chainer import chainer.functions as F import chainer.links as L import MeCab ②問と答えの組み合わせを用意します。最初の[]が問で後[]がその答えとなるようにデータを準備します。本来は何千、何万というものを用意し、きちんと学習させていくのですが、、今回は流れを理解することに重点を置いていますので少しだけの教師データとなっています。 # 教師データ data = [ [["初めまして。"], ["初めまして。camiよろしくね。"]], [["どこから来たんですか?"], ["日本から来ました。"]], [["日本のどこに住んでるんですか?"], ["東京に住んでいます。"]], [["仕事は何してますか?"], ["夢を売る仕事です。"]], [["お会いできて嬉しかったです。"], ["YOU誰?"]], [["おはよう。"], ["おはようございます。"]], [["こんにちわ"], ["おはようございます。"]], [["こんばんわ"], ["おはようございます。"]], [["いつも何時に起きますか?"], ["入りの2時間前置きます。"]], [["朝食は何を食べますか?"], ["たいていトーストと卵を食べます。"]], [["朝食は毎日食べますか?"], ["たまに朝食を抜くことがあります。"]], [["野菜をたくさん取っていますか?"], ["毎日野菜を取るようにしています"]], [["週末は何をしていますか?"], ["メンバーと会っていることが多いです。"]], [["どこに行くのが好き?"], ["私たちは帝劇に行くのが好きです。"]], [["挑戦した方がいいかな?"], ["YOUやっちゃいなよ"]], [["ありがとう"], ["セクシィーサンキュー"]] ] ③最初にGPUが入っている環境であればGPUを使うように設定します。 #GPUが入っている場合は、0以上に設定する。GPUがあると学習時間が早くなります # ない場合はCPUを使って学習されます gpu = -1 if gpu >= 0: # numpyかcuda.cupyか xp = chainer.cuda.cupy chainer.cuda.get_device(gpu).use() else: xp = np ④まずは、データ変換の定義を行っていきます。 # データ変換クラスの定義 class DataConverter: def __init__(self, batch_col_size): """クラスの初期化 Args: batch_col_size: 学習時のミニバッチ単語数サイズ """ self.mecab = MeCab.Tagger(r'-Owakati -d "C:\mecab-ipadic-neologd"') # 形態素解析器 self.vocab = {"<eos>":0, "<unknown>": 1} # 単語辞書 self.batch_col_size = batch_col_size def load(self, data): """学習時に、教師データを読み込んでミニバッチサイズに対応したNumpy配列に変換する Args: data: 対話データ """ # 単語辞書の登録 self.vocab = {"<eos>":0, "<unknown>": 1} # 単語辞書を初期化 for d in data: sentences = [d[0][0], d[1][0]] # 入力文、返答文 for sentence in sentences: sentence_words = self.sentence2words(sentence) # 文章を単語に分解する for word in sentence_words: if word not in self.vocab: self.vocab[word] = len(self.vocab) # 教師データのID化と整理 queries, responses = [], [] for d in data: query, response = d[0][0], d[1][0] # エンコード文、デコード文 queries.append(self.sentence2ids(sentence=query, train=True, sentence_type="query")) responses.append(self.sentence2ids(sentence=response, train=True, sentence_type="response")) self.train_queries = xp.vstack(queries) self.train_responses = xp.vstack(responses) def sentence2words(self, sentence): """文章を単語の配列にして返却する Args: sentence: 文章文字列 """ sentence_words = [] for m in self.mecab.parse(sentence).split("\n"): # 形態素解析で単語に分解する w = m.split("\t")[0].lower() # 単語 if len(w) == 0 or w == "eos": # 不正文字、EOSは省略 continue sentence_words.append(w) sentence_words.append("<eos>") # 最後にvocabに登録している<eos>を代入する return sentence_words def sentence2ids(self, sentence, train=True, sentence_type="query"): """文章を単語IDのNumpy配列に変換して返却する Args: sentence: 文章文字列 train: 学習用かどうか sentence_type: 学習用でミニバッチ対応のためのサイズ補填方向をクエリー・レスポンスで変更するため"query"or"response"を指定  Returns: ids: 単語IDのNumpy配列 """ ids = [] # 単語IDに変換して格納する配列 sentence_words = self.sentence2words(sentence) # 文章を単語に分解する for word in sentence_words: if word in self.vocab: # 単語辞書に存在する単語ならば、IDに変換する ids.append(self.vocab[word]) else: # 単語辞書に存在しない単語ならば、<unknown>に変換する ids.append(self.vocab["<unknown>"]) # 学習時は、ミニバッチ対応のため、単語数サイズを調整してNumpy変換する if train: if sentence_type == "query": # クエリーの場合は前方にミニバッチ単語数サイズになるまで-1を補填する while len(ids) > self.batch_col_size: # ミニバッチ単語サイズよりも大きければ、ミニバッチ単語サイズになるまで先頭から削る ids.pop(0) ids = xp.array([-1]*(self.batch_col_size-len(ids))+ids, dtype="int32") elif sentence_type == "response": # レスポンスの場合は後方にミニバッチ単語数サイズになるまで-1を補填する while len(ids) > self.batch_col_size: # ミニバッチ単語サイズよりも大きければ、ミニバッチ単語サイズになるまで末尾から削る ids.pop() ids = xp.array(ids+[-1]*(self.batch_col_size-len(ids)), dtype="int32") else: # 予測時は、そのままNumpy変換する ids = xp.array([ids], dtype="int32") return ids def ids2words(self, ids): """予測時に、単語IDのNumpy配列を単語に変換して返却する Args: ids: 単語IDのNumpy配列 Returns: words: 単語の配列 """ words = [] # 単語を格納する配列 for i in ids: # 順番に単語IDを単語辞書から参照して単語に変換する words.append(list(self.vocab.keys())[list(self.vocab.values()).index(i)]) return words ⓹実際に学習するためのモデルを作成していきます # モデルクラスの定義 # LSTMエンコーダークラス class LSTMEncoder(chainer.Chain): def __init__(self, vocab_size, embed_size, hidden_size): """Encoderのインスタンス化 Args: vocab_size: 使われる単語の種類数 embed_size: 単語をベクトル表現した際のサイズ hidden_size: 隠れ層のサイズ """ super(LSTMEncoder, self).__init__( xe = L.EmbedID(vocab_size, embed_size, ignore_label=-1), eh = L.Linear(embed_size, 4 * hidden_size), hh = L.Linear(hidden_size, 4 * hidden_size) ) def __call__(self, x, c, h): """Encoderの計算 Args: x: one-hotな単語 c: 内部メモリ h: 隠れ層 Returns: 次の内部メモリ、次の隠れ層 """ e = F.tanh(self.xe(x)) return F.lstm(c, self.eh(e) + self.hh(h)) # Attention Model + LSTMデコーダークラス class AttLSTMDecoder(chainer.Chain): def __init__(self, vocab_size, embed_size, hidden_size): """Attention ModelのためのDecoderのインスタンス化 Args: vocab_size: 語彙数 embed_size: 単語ベクトルのサイズ hidden_size: 隠れ層のサイズ """ super(AttLSTMDecoder, self).__init__( ye = L.EmbedID(vocab_size, embed_size, ignore_label=-1), # 単語を単語ベクトルに変換する層 eh = L.Linear(embed_size, 4 * hidden_size), # 単語ベクトルを隠れ層の4倍のサイズのベクトルに変換する層 hh = L.Linear(hidden_size, 4 * hidden_size), # Decoderの中間ベクトルを隠れ層の4倍のサイズのベクトルに変換する層 fh = L.Linear(hidden_size, 4 * hidden_size), # 順向きEncoderの中間ベクトルの加重平均を隠れ層の4倍のサイズのベクトルに変換する層 bh = L.Linear(hidden_size, 4 * hidden_size), # 順向きEncoderの中間ベクトルの加重平均を隠れ層の4倍のサイズのベクトルに変換する層 he = L.Linear(hidden_size, embed_size), # 隠れ層サイズのベクトルを単語ベクトルのサイズに変換する層 ey = L.Linear(embed_size, vocab_size) # 単語ベクトルを語彙数サイズのベクトルに変換する層 ) def __call__(self, y, c, h, f, b): """Decoderの計算 Args: y: Decoderに入力する単語 c: 内部メモリ h: Decoderの中間ベクトル f: Attention Modelで計算された順向きEncoderの加重平均 b: Attention Modelで計算された逆向きEncoderの加重平均 Returns: 語彙数サイズのベクトル、更新された内部メモリ、更新された中間ベクトル """ e = F.tanh(self.ye(y)) # 単語を単語ベクトルに変換 c, h = F.lstm(c, self.eh(e) + self.hh(h) + self.fh(f) + self.bh(b)) # 単語ベクトル、Decoderの中間ベクトル、順向きEncoderのAttention、逆向きEncoderのAttentionを使ってLSTM t = self.ey(F.tanh(self.he(h))) # LSTMから出力された中間ベクトルを語彙数サイズのベクトルに変換する return t, c, h # Attentionモデルクラス class Attention(chainer.Chain): def __init__(self, hidden_size): """Attentionのインスタンス化 Args: hidden_size: 隠れ層のサイズ """ super(Attention, self).__init__( fh = L.Linear(hidden_size, hidden_size), # 順向きのEncoderの中間ベクトルを隠れ層サイズのベクトルに変換する線形結合層 bh = L.Linear(hidden_size, hidden_size), # 逆向きのEncoderの中間ベクトルを隠れ層サイズのベクトルに変換する線形結合層 hh = L.Linear(hidden_size, hidden_size), # Decoderの中間ベクトルを隠れ層サイズのベクトルに変換する線形結合層 hw = L.Linear(hidden_size, 1), # 隠れ層サイズのベクトルをスカラーに変換するための線形結合層 ) self.hidden_size = hidden_size # 隠れ層のサイズを記憶 def __call__(self, fs, bs, h): """Attentionの計算 Args: fs: 順向きのEncoderの中間ベクトルが記録されたリスト bs: 逆向きのEncoderの中間ベクトルが記録されたリスト h: Decoderで出力された中間ベクトル Returns: 順向きのEncoderの中間ベクトルの加重平均、逆向きのEncoderの中間ベクトルの加重平均 """ batch_size = h.data.shape[0] # ミニバッチのサイズを記憶 ws = [] # ウェイトを記録するためのリストの初期化 sum_w = chainer.Variable(xp.zeros((batch_size, 1), dtype='float32')) # ウェイトの合計値を計算するための値を初期化 # Encoderの中間ベクトルとDecoderの中間ベクトルを使ってウェイトの計算 for f, b in zip(fs, bs): w = F.tanh(self.fh(f)+self.bh(b)+self.hh(h)) # 順向きEncoderの中間ベクトル、逆向きEncoderの中間ベクトル、Decoderの中間ベクトルを使ってウェイトの計算 w = F.exp(self.hw(w)) # softmax関数を使って正規化する ws.append(w) # 計算したウェイトを記録 sum_w += w # 出力する加重平均ベクトルの初期化 att_f = chainer.Variable(xp.zeros((batch_size, self.hidden_size), dtype='float32')) att_b = chainer.Variable(xp.zeros((batch_size, self.hidden_size), dtype='float32')) for f, b, w in zip(fs, bs, ws): w /= sum_w # ウェイトの和が1になるように正規化 # ウェイト * Encoderの中間ベクトルを出力するベクトルに足していく att_f += F.reshape(F.batch_matmul(f, w), (batch_size, self.hidden_size)) att_b += F.reshape(F.batch_matmul(b, w), (batch_size, self.hidden_size)) return att_f, att_b # Attention Sequence to Sequence Modelクラス class AttSeq2Seq(chainer.Chain): def __init__(self, vocab_size, embed_size, hidden_size, batch_col_size): """Attention + Seq2Seqのインスタンス化 Args: vocab_size: 語彙数のサイズ embed_size: 単語ベクトルのサイズ hidden_size: 隠れ層のサイズ """ super(AttSeq2Seq, self).__init__( f_encoder = LSTMEncoder(vocab_size, embed_size, hidden_size), # 順向きのEncoder b_encoder = LSTMEncoder(vocab_size, embed_size, hidden_size), # 逆向きのEncoder attention = Attention(hidden_size), # Attention Model decoder = AttLSTMDecoder(vocab_size, embed_size, hidden_size) # Decoder ) self.vocab_size = vocab_size self.embed_size = embed_size self.hidden_size = hidden_size self.decode_max_size = batch_col_size # デコードはEOSが出力されれば終了する、出力されない場合の最大出力語彙数 # 順向きのEncoderの中間ベクトル、逆向きのEncoderの中間ベクトルを保存するためのリストを初期化 self.fs = [] self.bs = [] def encode(self, words, batch_size): """Encoderの計算 Args: words: 入力で使用する単語記録されたリスト batch_size: ミニバッチのサイズ """ c = chainer.Variable(xp.zeros((batch_size, self.hidden_size), dtype='float32')) h = chainer.Variable(xp.zeros((batch_size, self.hidden_size), dtype='float32')) # 順向きのEncoderの計算 for w in words: c, h = self.f_encoder(w, c, h) self.fs.append(h) # 計算された中間ベクトルを記録 # 内部メモリ、中間ベクトルの初期化 c = chainer.Variable(xp.zeros((batch_size, self.hidden_size), dtype='float32')) h = chainer.Variable(xp.zeros((batch_size, self.hidden_size), dtype='float32')) # 逆向きのEncoderの計算 for w in reversed(words): c, h = self.b_encoder(w, c, h) self.bs.insert(0, h) # 計算された中間ベクトルを記録 # 内部メモリ、中間ベクトルの初期化 self.c = chainer.Variable(xp.zeros((batch_size, self.hidden_size), dtype='float32')) self.h = chainer.Variable(xp.zeros((batch_size, self.hidden_size), dtype='float32')) def decode(self, w): """Decoderの計算 Args: w: Decoderで入力する単語 Returns: 予測単語 """ att_f, att_b = self.attention(self.fs, self.bs, self.h) t, self.c, self.h = self.decoder(w, self.c, self.h, att_f, att_b) return t def reset(self): """インスタンス変数を初期化する """ # Encoderの中間ベクトルを記録するリストの初期化 self.fs = [] self.bs = [] # 勾配の初期化 self.zerograds() def __call__(self, enc_words, dec_words=None, train=True): """順伝播の計算を行う関数 Args: enc_words: 発話文の単語を記録したリスト dec_words: 応答文の単語を記録したリスト train: 学習か予測か Returns: 計算した損失の合計 or 予測したデコード文字列 """ enc_words = enc_words.T if train: dec_words = dec_words.T batch_size = len(enc_words[0]) # バッチサイズを記録 self.reset() # model内に保存されている勾配をリセット enc_words = [chainer.Variable(xp.array(row, dtype='int32')) for row in enc_words] # 発話リスト内の単語をVariable型に変更 self.encode(enc_words, batch_size) # エンコードの計算 t = chainer.Variable(xp.array([0 for _ in range(batch_size)], dtype='int32')) # <eos>をデコーダーに読み込ませる loss = chainer.Variable(xp.zeros((), dtype='float32')) # 損失の初期化 ys = [] # デコーダーが生成する単語を記録するリスト # デコーダーの計算 if train: # 学習の場合は損失を計算する for w in dec_words: y = self.decode(t) # 1単語ずつをデコードする t = chainer.Variable(xp.array(w, dtype='int32')) # 正解単語をVariable型に変換 loss += F.softmax_cross_entropy(y, t) # 正解単語と予測単語を照らし合わせて損失を計算 return loss else: # 予測の場合はデコード文字列を生成する for i in range(self.decode_max_size): y = self.decode(t) y = xp.argmax(y.data) # 確率で出力されたままなので、確率が高い予測単語を取得する ys.append(y) t = chainer.Variable(xp.array([y], dtype='int32')) if y == 0: # EOSを出力したならばデコードを終了する break return ys ⓹作成したモデルに教師データを読込学習させていきます # 学習 # 定数 embed_size = 100 hidden_size = 100 batch_size = 6 # ミニバッチ学習のバッチサイズ数 batch_col_size = 15 epoch_num = 50 # エポック数 N = len(data) # 教師データの数 # 教師データの読み込み data_converter = DataConverter(batch_col_size=batch_col_size) # データコンバーター data_converter.load(data) # 教師データ読み込み vocab_size = len(data_converter.vocab) # 単語数 # モデルの宣言 model = AttSeq2Seq(vocab_size=vocab_size, embed_size=embed_size, hidden_size=hidden_size, batch_col_size=batch_col_size) opt = chainer.optimizers.Adam() opt.setup(model) opt.add_hook(chainer.optimizer.GradientClipping(5)) if gpu >= 0: model.to_gpu(gpu) model.reset() # 学習 st = datetime.datetime.now() for epoch in range(epoch_num): # ミニバッチ学習 perm = np.random.permutation(N) # ランダムな整数列リストを取得 total_loss = 0 for i in range(0, N, batch_size): enc_words = data_converter.train_queries[perm[i:i+batch_size]] dec_words = data_converter.train_responses[perm[i:i+batch_size]] model.reset() loss = model(enc_words=enc_words, dec_words=dec_words, train=True) loss.backward() loss.unchain_backward() total_loss += loss.data opt.update() if (epoch+1)%10 == 0: ed = datetime.datetime.now() print("epoch:\t{}\ttotal loss:\t{}\ttime:\t{}".format(epoch+1, total_loss, ed-st)) st = datetime.datetime.now() def predict(model, query): enc_query = data_converter.sentence2ids(query, train=False) dec_response = model(enc_words=enc_query, train=False) response = data_converter.ids2words(dec_response) print(query, "=>", response) ⑥ 5.完成したもの eos は end of sentence で文末を意味しています 会話モデルの結果、 初めまして。 => ['初め まして 。 cami よろしく ね 。 ', '<eos>'] どこから来たんですか? => ['日本 から 来 まし た 。 ', '<eos>'] 日本のどこに住んでるんですか? => ['you 東京 に 住ん で い ます 。 ', '<eos>'] 仕事は何してますか? => ['夢 を 売る 仕事 です 。 ', '<eos>'] おはよう。 => ['おはよう ござい ます 。 ', '<eos>'] こんにちわ => ['おはよう ござい ます 。 ', '<eos>'] こんばんわ => ['おはよう ござい ます 。 ', '<eos>'] いつも何時に起きますか? => ['6時 に 起き ます 。 ', '<eos>'] 朝食は何を食べますか? => ['たいてい トースト と 卵 を 食べ ます 。 ', '<eos>'] 朝食は毎日食べますか? => ['たまに 朝食 を 抜く こと が あり ます 。 ', '<eos>'] 野菜をたくさん取っていますか? => ['毎日 野菜 を 取る よう に し て い ます ', '<eos>'] 週末は何をしていますか? => ['メンバー と 会っ て いる こと が 多い です 。 ', '<eos>'] どこに行くのが好き? => ['私たち は 帝劇 に 行く の が 好き です 。 ', '<eos>'] 挑戦した方がいいかな? => ['you やっ ちゃ い な よ ', '<eos>'] お会いできて嬉しかったです。 => ['you 誰 ? ', '<eos>'] 6.最後に この記事を書くにあたり以下の記事を参考とさせていただきました。 ↓こちらの記事でやってみたいことが見えてきました 機械学習でツイートが炎上するか予測してみた ↓こちらの記事を参考にしながら少しアレンジし作成していきました 戦略コンサルで働くデータサイエンティストのブログ 記事を書いて下さった皆様ありがとうございます。またAidemyの先生方にもたくさんお力を貸していただきありがとうございます。 最後は、ジャニさんが出てきて、お決まりの?「YOU誰?」で終わってみました。 この事務所を作ってくださったジャニさんには感謝です。 今回は、教師データにした数が少なかったので、教師データのままでしたが、教師データに様々な会話パターンを入れていくと、より〇〇っぽい会話ができるようになると思います。 これをアプリなどに展開できれば面白くなっていくのではないか?と思います。 。。。いや思うだけでなく、これからそれを多分挑戦してみるぞ!!  しらんけど
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

緑になったのでメモ書き

ギリギリですがなんとか入緑することができました!!! ということで、緑になるためには何々した方が良いみたいな記事はたくさんあるので、この記事は自分がこれまでやったこととこれからやっていきたいことのメモ書きみたいな感じで書いて行こうと思います。ここはこうした方が良いみたいなことがあればコメントお願い致します。 今までやったこと 灰のとき A,B,C問題をそれぞれ20問ずつくらいやった。D,E問題はほとんど触れず。C++の方が速度が速く競プロ向きだということで最初はC++を使ってた。普段の研究やインターンなどではPythonの方が使う機会が多そうなことと、ライブラリが充実しており、記述も簡単であり、Pythonerも少なくとも青までは速度が出なくて困ったことはないという記事があったため、途中からPythonに移行。 初めは茶diff前後の問題を中心にやっていた。最初はC++やPythonの文法、Atcoderの方式に慣れるという意味でもA,B問題を解くことに意味があったと思うが、徐々に簡単に思えてきてやる意味あるのかな?と思ったので、それからはCを中心にやるようになった。 使った教材 ・初心者用の記事にあった問題(何やったかよく覚えてない) ・ABCの過去問数年分 ・atcoder版蟻本 https://qiita.com/drken/items/e77685614f3c6bf86f44 しくじり ・ツイッターやってたけど実際に一緒に競プロのチャとかをやることはせず、ほとんど完全な1人プレイだった。他の競プロerと繋がった方が楽しい。 ・途中までA,B問題埋めてて、解いてる時は出来てる感があって楽しいけど、それやってもC,Dの正答率は大して上がらないのでA,B埋める時間あったらC,D問題やった方が良かった。 ・問題のdiffではなくA,B,Cというアルファベットで難しさを判断していた。たまにC問題だけど青diffみたいな問題もあって、そのような問題も一応取り組んでいたけどしっかり理解できてなかった。アルファベットではなくdiffで判断するべき。 ・解説みてもイマイチ理解できない時頭の中で何時間も考えてたけど、わからなくてもとりあえずコード書いて、コードの途中の変数を出力してみたりすると理解できたりする。 茶のとき 茶,緑,水diffの問題中心にやった。 使った教材 ・競プロ典型90問 ・螺旋本 ・Atcoder版蟻本 しくじり ・途中院試があって精進しなくなったとき、精進しないでコンテストやってもレート上がらなかった。レートを上げるという意味では精進していない時はコンテストやらない方が無難。もちろんコンテストによって定期的にコーディングすることに強制力を持たせる分には良いと思う。 ・DPどっから勉強すれば良いのかわからずとりあえず場当たり的に蟻本に乗ってる問題解いてたけど、アルゴ式だったら段階的にDPのc勉強できるのでアルゴ式とか使って典型からひとつずつ段階的にちゃんと抑えたい。 ・atcoderの拡張機能入れてなかったが、入れといた方が多方面に便利なので早めに入れた方が良かった。 これまでやったアルゴリズム 単純な全探索 ビット全探索 順列全探索(next_permutation) 最大公約数,最小公倍数 高速素数判定 エラトステネスの篩 素因数分解 約数列挙 半分全列挙 bit全探索 二分探索(単純) BFS DFS ダイクストラ法 ワーシャルフロイド法 クラスカル法・プリム法 DP(基本) LIS Union-Find木 ModInt(剰余をとる必要がある四則演算やべき乗、nCr、階乗) XORの問題 今後やりたいアルゴリズム DP(応用)←最重要 累積和 いもす法 尺取り法 高速な冪乗計算 逆元の利用 座圧 BIT 今後 一応入緑したけど今のレートだと一回でも茶パフォ出すと茶色に戻るので、なんとか緑キープできるように頑張っていきたい。話を聞くところによると、緑から水になるまでが結構大変そうなので頑張る。 やりたいと思ってること ・競プロerの繋がりをもっと広げたい ・1日1AC。精進ツリー作って、streakを稼ぐのをモチベにしつつ、茶色以下diffの問題やっても実力伸びないと思うから、緑~水diffに絞ってやっていきたい。 ・とはいえ、今は研究やKaggleに重きを置いているからやる頻度は減っていくかも 今後使う教材 ・Atcoder版蟻本 ・アルゴ式 ・競プロ典型90問 ・精選100問 おまけ 参考までにユーザ情報
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

リスト,辞書

今回の授業資料 リスト 複数の値を代入したい時に使用.数字でも文字でも代入が可能. 例えば,名簿を作るとしましょう. インデックス番号 0 1 2 値 alfred beck charlie 実際のコード記述 ↓ VS CodeやAtomなどのエディタに書く. array_sample.py # 変数名 = [要素0,要素1,要素2, …] name_array=['alfred','beck','charlie'] # ['alfred','beck','charlie']と出力 print(name_array) # 'alfred'と出力 print(name_array[0]) 書いたコードの実行 ターミナルやコマンドプロンプトにて,先程保存したエディタを開き,実行. print関数内に指定した変数のみ表示されます.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC149 C - Next Prime を解いた

素数判定ってなんだっけ? 過去の自分に聞いてみた。 ok なるほど。 以下で通った。 abc149c.py X = int(input()) def judge(n): from math import floor for i in range(2,floor(n**0.5)+1): if n%i == 0: return False return True for j in range(1000): if judge(X+j): print(X+j) exit()
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC148 C - Snack を解いた

最小公倍数ってどうやって求めるんだったか、調べた 以下で通った。 abc148c.py a,b = map(int,input().split()) from math import gcd print( (a*b)//gcd(a,b) )
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC145 C - Average Length を解いた

N が max 8 と小さいから floating で平均を求めても問題ないのでは? 以下で通った。 abc145c.py N = int(input()) lis = [] for i in range(N): x,y = map(int,input().split()) lis.append([x,y]) from itertools import permutations cnt = 0 score = 0 for num in permutations(range(N),N): cnt += 1 num = list(num) #print(num) for i in range(N-1): #print(lis[num[i]], lis[num[i+1]]) x = lis[num[i]][0]-lis[num[i+1]][0] y = lis[num[i]][1]-lis[num[i+1]][1] score += (x**2 + y**2)**(0.5) #print(score) #print() print("{:.6f}".format(score/cnt))
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

算術計算

今回の授業のゴール Python3での,算術演算子,変数を用いた基本的な計算を, インタラクティブシェル(ターミナルやコマンドプロンプト等)で実行できる. この授業資料の前提 とある中学校の授業資料として作成しております.開発環境やカリキュラムなどに関してはこちらを参照してください. 加減乗除,剰余,累乗 算術計算の種類 算術演算子 キー(JISの場合) 加算(足し算) + Shift +「れ」 減算(引き算) - Shift +「ほ」 乗算(掛け算) * Shift +「け」 除算(割り算) / Shift +「め」 剰余(余り) % Shift +「え・5」 累乗(同じ数字を掛ける) ** Shift +「け」 【実習】 【演習1】計算してみよう(授業資料1 演習) このページの演習を解き,スクリーンショットをまなBOXにて提出しましょう.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

いまさらだけどGithub actions上でseleniumを動かしたのでまとめてみた

今回はgithub actions上で「seleniumを動かすことだけ」にスポットを当てます。 用意するのはseleniumとgithub actionsワークフロー。 selenium アクセス先のURLを出力するだけです。 test_selenium.py from selenium import webdriver from selenium.webdriver.chrome.options import Options import chromedriver_binary options = Options() # ヘッドレスモード(Linux上で動かすとき必ずこのモードにしておく) options.add_argument('--headless') driver = webdriver.Chrome(options=options) driver.get('https://example.com') print(driver.current_url) github actionsワークフロー test_selenium.pyを置いているリポジトリにGithub actionsワークフロー.github/workflows/test_selenium.ymlを作成します。 test_selenium.yml name: test-selenium on: push: branches: - master jobs: build: runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v2 - name: Setup Python uses: actions/setup-python@v2 - name: Install Chrome run: | sudo wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - sudo apt update sudo apt-get install google-chrome-stable - name: Install Package run: | pip install chromedriver-binary==94.* pip install selenium - name: Test Selenium run: python test_selenium.py commitするとActionsでワークフローの実行が確認できます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Discord.py ver2.0.0aでボタンの実装をしてみる

Discord.pyがまさかの更新停止。 でもDannyは残してくれた。alpha版のDiscord.py、バージョン2.0.0aを―――――しかし。 Discord.py 2.0.0aの記事がどこにも載っていない! すること DiscordのUI機能?のボタンを作ってみる。 インストールするもの Python 3.9以上 Discord.py 2.0.0a (alpha) その他プログラムに必要なものがあればインストール インストール手順 Pythonは割愛。 Discord.py 2.0.0aのインストール pip install git+https://github.com/Rapptz/discord.py でok。 ボタンを作ってみる とりあえず表示だけ。 from discord.ext import commands import discord class ButtonBot(commands.Bot): def __init__(self): super().__init__(command_prefix="!") class CreateButton(discord.ui.View): def __init__(self): super().__init__() self.add_item(discord.ui.Button(label="ボタンです")) bot = ButtonBot() @bot.command() async def button(ctx: commands.Context): await ctx.send("下にボタンがあるはず", view=CreateButton()) bot.run('TOKEN') こんな感じでできる。 ボタンを押しても何も無いのは寂しい(というか実用性がない)ので、メッセージを折り返し送ってみよう。 class CreateButton(discord.ui.View): def __init__(self): super().__init__() @discord.ui.button(label="ボタンです") async def return_message(self, button: discord.ui.Button, interaction: discord.Interaction): await interaction.response.send_message("折り返しのメッセージだよ") こんな感じ。 interactionについては https://discordpy.readthedocs.io/ja/latest/api.html#interaction を見れば詳しく書いてあります。 ちなみに await interaction.response.send_message("折り返しのメッセージだよ", ephemeral=True) と、ephemeralパラメータをTrueにするとボタンを押した人だけに見えるメッセージが送られる。すごい。 他にもいろいろ機能があるので、ぜひDiscord.py 2.0.0aをインストールしてみてください!!!(懇願) また、他の機能を試してみたいけどどうやってプログラミングするか分からないって方はコメントしていただければ反応できます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

OCI Data Integration から OCI Functions を呼び出す

はじめに OCI Data Integration のデータフローで「ファンクション演算子」が利用できるようになりました。これにより従来 OCI Data Integration の組み込み機能だけでは対応が難しかったデータ変換処理を OCI Functions のアプリケーションに任せることができます。 ドキュメントはこちらから ここでは、OCI Data Integration と OCI Functions 間のインターフェース(入出力データ)の話と、それに即した Pythonアプリケーションの書き方についてお話ししたいと思います。 OCI Data Integration 側の準備 ファンクション演算子のプロパティ設定で 入力属性 (Input Attributes) 出力属性 (Output Attributes) 機能属性 (Function Configuration) を構成します。入力属性と出力属性はOCI Functions アプリケーションのリクエスト/レスポンスの Json データのスキーマとなります。機能属性の情報もリクエストデータに含まれますので、これをアプリケーションの実行パラメータとして使うことができます。 OCI Functions の送受信データ Request: Jsonオブジェクト { "data" : "{{ 出力属性スキーマを持つレコードのjsonオブジェクトを複数改行区切りでまとめてbase64エンコードした文字列 }}" "parameters : {{ 機能属性のjsonオブジェクト}} } 具体的には、このようなJsonとなります。 { "data": "eyJmaXJzd...(途中略)...WMwNi02MDExLTMwYjQtNTllOC1kMTY0N2VlZDQ5ZjEifQo=", "parameters": { "param1": "param1value" } } さらに、"data" の値であるbase64エンコードされた文字列をデコードすると {"firstname":"James","lastname":"Brown","secret_id_field":"0927e5a8-9097-4cad-a7fa-b6167184c744"} {"firstname":"David","lastname":"Paich","secret_id_field":"58e25c06-6011-30b4-59e8-d1647eed49f1"} のように、各レコードが改行で区切られた形になっています。 "secret_id_field" はOCI Data Integrationによって入力データの各レコードに振られる一意のIDで、出力データを返す時も各レコードに必ず同じIDをつけなければなりません。OCI Data IntegrationはこのIDを使って、レコードの紐付けをおこないます。 Response: Jsonオブジェクト [ {{ 出力属性スキーマを持つレコードのjsonオブジェクト }}, {{ 出力属性スキーマを持つレコードのjsonオブジェクト }}, ... {{ 出力属性スキーマを持つレコードのjsonオブジェクト }} ] こちらはごく一般的なJson配列です。 OCI Functions で変換アプリケーションを書く 多分一番シンプルな "無変換" する変換アプリケーションを公開しています。入力データをそのまま出力データとして返すプログラムです。 プログラム本体が func.py テストプログラムの方が functest.py ですが、functest.py ではOCI Data Integration に代わって入力データを作成しているので、こちらを参考にしてもらうと、全体の入出力が理解できると思います。 @pytest.mark.asyncio async def test_parse_request_without_data(): rows = [ {"firstname":"James","lastname":"Brown","secret_id_field":"0927e5a8-9097-4cad-a7fa-b6167184c744"}, {"firstname":"David","lastname":"Paich","secret_id_field":"58e25c06-6011-30b4-59e8-d1647eed49f1"} ] parameters = {"param1" : "param1value"} data = '' for row in rows: data = data + json.dumps(row) + '\n' request = { "data" : base64.b64encode(data.encode('utf-8')).decode('utf-8'), "parameters" : parameters } input_content = io.BytesIO(json.dumps(request).encode("utf-8")) call = await fixtures.setup_fn_call(func.handler, content=input_content) content, status, headers = await call assert 200 == status assert rows == json.loads(content) 変換処理側のポイントとしては、改行区切りのJsonレコードを扱うために pandas の DataFrame を使っている点です。 df = pandas.read_json(rows, lines=True) 読み込んだ後 DataFrame のまま処理を続けて最後にJson配列の文字列に落とすと、そのままレスポンスの出力データとして使えます。実際に変換処理を行う場合は def process(df: pandas.DataFrame) -> str: df['lastname'] = df['lastname'].apply(lambda x: str(x).upper()) # 姓を大文字に変換 return df.to_json(orient='records') などとやって下さい。 注意点など 一度にOCI Functionsに渡されるレコード数は、OCI Data Integration の機能属性 BATCH_SIZE でコントロールできます。OCI Functionsのメモリーが足りなかったり、タイムアウトにひっかかるような場合は BATCH_SIZE を小さな値にします。 出力データに "secret_id_field" を忘れずに。 まとめ ということで、OCI Data Integration から OCI Functions に渡すデータが少しだけ分かりづらいですが、この投稿を参考していただいて、バリバリ OCI Data Integration を活用していただければ幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CIFファイルの記法をpymatgenやVESTAで整形する

背景 結晶構造を記述するCIFファイルの記法には混乱があり、インターネットからダウンロードしたり、リートベルト解析等で自分で作成したCIFが他のソフトウェア(e.g. ASE)で読めないということがたまにある。 中身はテキストファイルなので手動で修正することもできるが、手軽なworkaroundとして、様々なCIFファイルを読み込めるソフトウェアを用いて、一旦(ASE等で読めない)CIFを開いてから書き出す方法がある。以下で解説する。 方法 この目的で使えるソフトウェアはいろいろとあるが、ここでは2つ紹介する pymatgenを使う方法 サーバー上でPythonを使って多数バッチ処理するならこっちが便利 VESTAを使う方法 手元でGUIベースで数件やるならこっちが便利。 一応コマンドラインでも使えるが、まだexperimentalなように見受けられるので注意 pymatgenを使う方法 pymatgen (https://pymatgen.org/) は、材料解析用のPythonライブラリ。インストールは公式サイトを参照のこと。サーバー上でPythonスクリプトを使って自動処理する場合には特に便利。 pymatgenでCIFを扱う注意点 pymatgenではCIFファイルの全ての属性をサポートしているわけではなく、CIF読み込み→書き出しの過程で情報が落ちる場合がある。構造解析では重要なUiso(熱振動因子)の情報もCIFから落ちるので注意。 これらの情報が必要な場合は後述するVESTAを使うほうが良い pymatgenでCIFを書き出す2通りの方法 pymatgenでCIFを書き出すには、structureオブジェクトから .to() 属性を呼ぶ方法と、CifWriterクラスを使う方法の2つがある。 c.f. Unintuitive behavior when saving to .cif related to space groups .to() 属性を呼ぶ方法は便利だが、CIFから空間群の情報が落ちてP1として記録されるので、空間群の情報が必要な場合は問題になるかも CifWriterを使う方法だと空間群を認識してCIFを書き出すので行儀は良い ただし、空間群が正規化されるので、長軸をc→bに取り直した等価な空間群に変換されるなどの変換が伴う場合がある また、空間群の分析にちょっと(数秒程度)時間がかかる うまくいかない場合はsymprecの値を見直すこと それらを踏まえて、pymatgenでCIFを読んで書き出すにはこんな感じでできる from pymatgen.core import Structure from pymatgen.io.cif import CifParser, CifWriter # CIFファイルを読み込んでstructureオブジェクトを作る parser = CifParser("NaCl.cif") structure = parser.get_structures()[0] # structureオブジェクトをCIFファイルとして書き出し(to属性を使う方法) # ただし、CIFファイルに空間群の情報が書き込まれず空間群P1として記述される structure.to(filename="NaCl_fixed.cif") # structureオブジェクトをCIFファイルとして書き出し(CifWriterを使う方法) # この倍は空間群の情報もCIFに書き込まれる writer = CifWriter(structure, symprec=0.001) writer.write_file("NaCl_fixed.cif") 多数のcifファイルをまとめて処理するにはこんな感じで import glob from pymatgen.core import Structure from pymatgen.io.cif import CifParser, CifWriter # 指定したディレクトリ内でcifファイルを全件列挙し、 # ファイル名末尾に_fixedをつけて同じディレクトリ内に書き出す cif_files = glob.glob(f"cif_files/*.cif") suffix="_fixed" for cif_file in cif_files: parser = CifParser(cif_file) structure = parser.get_structures()[0] # .to()属性を使う場合 structure.to(fmt="cif", filename=cif_file[:-4]+suffix+".cif") # CifWriterを使う場合 writer = CifWriter(structure, symprec=0.001) writer.write_file(cif_file[:-4]+suffix+".cif") VESTAを使う方法 VESTA (https://jp-minerals.org/vesta/jp/) は結晶構造の可視化のためのアプリケーションだが、CIFファイルの処理にも使える。 GUIの場合 単にVESTAを起動してCIFファイルを開いてから、CIFファイルとして書き出せばok CLIを使う場合 注意点: VESTAは、引数を渡すことで一応コマンドでも使えるが、正式にドキュメンテーションされた機能ではない。突然変更されたり消えたりするかもしれない。またVESTAはGUIアプリケーションなので、ディスプレイやXserverが設定されていないサーバー上では起動しない。 参考にした記事: https://qiita.com/inashiro/items/2cf50f0a84dd98a729a7 macの場合 VESTA.app(普段はクリックして開くアイコン)はディレクトリであり、実行ファイルの実体は VESTA.app/Contents/MacOS/VESTAであることに注意 /Applications/VESTA/VESTA.app/Contents/MacOS/VESTA -open NaCl.cif /Applications/VESTA/VESTA.app/Contents/MacOS/VESTA -save NaCl_fixed.cif Linuxの場合 # インストール(URLやファイル名は例) wget https://jp-minerals.org/vesta/archives/3.5.7/VESTA-gtk3.tar.bz2 tar -jxvf VESTA-gtk3.tar.bz2 cd VESTA-gtk3/ # 使い方は基本macと同じ ./VESTA -open NaCl.cif # (ここでVESTAのウィンドウが開く) ./VESTA -save NaCl_fix.cif Windowsの場合(未確認) C:\Program Files\VESTA-win64\VESTA.exe -open NaCl.cif C:\Program Files\VESTA-win64\VESTA.exe -save NaCl.cif おわりに CIFは闇
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC143 C - Slimes を解いた

たぶん、そのまま書けば行ける abc142c.py N = int(input()) S = list(input()) s = S[0] if N == 1: print(1) else: lis = [s] for i in range(1,N): if s != S[i]: lis.append(S[i]) s = S[i] print(len(lis))
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC142 C - Go to School を解いた

特に注意点はないと思う。 そのまま書けばok abc142c.py N = int(input()) A = list(map(int,input().split())) memo = {} for i in range(N): memo[i] = A[i] memo = sorted(memo.items(),key=lambda x:x[1]) #print(memo) ans = [] for a,b in memo: ans.append(str(a+1)) print(" ".join(ans))
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHREEQC、PHREEQPYによる溶液の物理化学シミュレーション

PHREEQC、PHREEQPYとは? PHREEQC、PHREEQPYは、地球科学分野?で開発された、溶液内のイオンがどのような形態で存在するかをシミュレーションするためのソフトウェアです。 自分の研究の備忘録みたいな感じで作っている記事なので、あんまり親切じゃないかも PHREEQの後についているCとかPYとかは、動かしている言語の名前です。(Rもあります。) 多分PHREEQCが一番メジャーに使われていて、PYとかRは利用者が少ないのかな?なんてイメージですが、絶対RとかPythonでやったほうが便利なので、後々RやPyhton用に記事を発展させるつもりです。 PHREEQシリーズは熱力学的シミュレーションですが、シミュレーションするための基盤になる熱力学的なデータベースが何種類かあります。 多分データベースによって、計算値が若干異なりますが、簡単なシミュレーションをする分にはあまり困らないのでは?? 一応自分はminteq.v4.datを使うことが多いです。 シミュレーションの例 例えば、リン酸、硫酸マグネシウム、炭酸カルシウムを水に溶かしたとしましょう。 まずpHはどうなるか?酸性のリン酸と弱塩基の炭酸カルシウムがぶつかるので、pHはリン酸と炭酸カルシウムの量によって決まりますよね? こういったpHの変化はシミュレーション可能です。 またリン酸はカルシウムやマグネシウムと凝集し、塩をつくってしまうので、水溶液中にCaHPO4やMgHPO4が沈殿します。こういった沈殿の量も同時にシミュレーション可能です! 諸々のソース PHREEQCの公式サイト →PHREEQCはまずココから。 簡単なターミナルやコマンドプロンプトの知識があれば、ここからダウンロードしたPHREEQCで色々出来ます。 C言語知らない自分が使えるので、ご安心ください。 一応GUI付きのソフトウェアも入っているので、それが利用できればPCの知識0でも大丈夫かもしれません。(自分のMacでは動きませんでした。) ちょっとPython触れるくらいの知識だと、PHREEQCを直接使うのは難しいかも。。 PHREEQC公式の取り扱い説明書 →PHREEQCとありますが、多分PHREEQPYもPHREEQRも一緒です。 中身に色々なコマンドがあるので、それを理解するためにコイツは必須です。 特に例1~22まである実装例が超役に立ちます。 最終的には、微生物の反応なども同時に記述できるらしい。。 PHREEQPYの実装例 →ちょくちょくお世話になるhatari labのPHREEQPY解説です。ライブラリや使用したプログラムはサイト下部のリンクから手に入ります。 一応pip installでもphreeqpyは入手可能なんですが、このhatari labでは別のソースを使っている気がします。。。 PHREEQPY公式ドキュメント(pip版) PHREEQRの実装例 全体の流れ 以下のテストケースを、自分でなぞれるようになればOKです。 環境構築 正直あんまり覚えてないですが、公式サイトのBatch Versions of PHREEQCからご自分の環境にあったプログラムをインストール、解答してください。多分問題は起きないはず。 Run PHREEQC インストールしたファイル内に、RUN PHREEQCというGUIが入っているので、動かしてみてください。(これが動けば一番ラクなはず。。。) 詳細は僕わかんないです。 もし動かない人は次の方法に行きましょう。 Testフォルダ このTestフォルダの中に、test.commandというコマンドがあります。 こいつをダブルクリックして動かしてみましょう。 これが、実際のPHREEQCの計算になります。 test.command test.commandの中身を理解できれば、もうPHREEQCは使えたも同然です。 詳しい解説はとりあえず飛ばしますが、流れとしては 最初に実行するための基本情報が記述してあり、(実行フォルダ名とか) 中盤の繰り返し部分では、スクリプトを読み込んで計算を実行しています。 計算を実行する部分では、利用データベースとか条件を記述したスクリプトを指定。 条件を記述したスクリプトは、test.commandの場合は、examplesフォルダのex1~ex22です。 シミュレーション内容を記述 testフォルダ内のex1~ex22はシミュレーション内容を記述したテキストファイルです。 中身の詳しい説明は、公式取説の例1~22と対応しています。 今後は自分で、このシミュレーション内容を自分好みに書き換えればPHREEQCを使えたも同然です。 シミュレーションファイルの記述 結局PHREEQCはPythonだろうがRだろうがCだろうが、シミュレーション内容が記述できれば、完了です。(RとかPythonなら結果はグラフにしやすい) SOLUTION 公式まず何をするにしろ、最初に使用する溶液を定義する必要があります。 その際に使うコマンドがSOLUTION。 ただ全ての分子を記述できるわけではなく(例えばシュウ酸。データベースにない)、その場合は未知の分子として、なにかしらのパラメータを与えて記述する必要あり。 ちなみにminteqのデータベースは、クエン酸(citrate)のデータあり。 ! 各元素の量を多くしすぎると、エラーが発生する。その場合は、-waterの量を減らす等で対応。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC141C - Attack Survival を解いた

そのまま解いた。 abc141c.py N,K,Q = map(int,input().split()) memo = {} for i in range(N): memo[i] = 0 for i in range(Q): a = int(input()) memo[a-1] += 1 #print(memo) for i in memo.keys(): if K-(Q-memo[i]) > 0: print("Yes") else: print("No")
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む