timeitモジュールで呼び出し可能オブジェクトの時間を計測する。
tensorflowのドキュメントを見てたら、timeitというモジュールを使っていたので、これなんやねんと思って調べた。
Pythonからtimeitをimportして使う場合は、式を文字列として渡すか、呼び出し可能な式あれば時間を計測することができる。
例1
import timeit timeit.timeit(lambda: print(1), number=10)
1 1 1 1 1 1 1 1 1 1 0.0006752069998583465
例2
import timeit def test(i): for i in range(i): print("aaa") timeit.timeit(lambda: test(1), number=10)
aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa 0.0003541580000501199
例3
import timeit timeit.timeit("print(1)", number= 10)
1 1 1 1 1 1 1 1 1 1 0.00039979700000003504
なお、文字列を渡す例3のような場合は、以下のように文字列の外側で定義した関数だとダメだった。難しい。
例4(NG)
import timeit def test(i): for i in range(i): print("aaa") timeit.timeit("test(10)", number= 10)
NameError Traceback (most recent call last) <ipython-input-8-e602a5cee3d7> in <module>() ----> 1 timeit.timeit("test(10)", number= 10) /usr/lib/python3.7/timeit.py in timeit(stmt, setup, timer, number, globals) 231 number=default_number, globals=None): 232 """Convenience function to create Timer object and call timeit method.""" --> 233 return Timer(stmt, setup, timer, globals).timeit(number) 234 235 def repeat(stmt="pass", setup="pass", timer=default_timer, /usr/lib/python3.7/timeit.py in timeit(self, number) 175 gc.disable() 176 try: --> 177 timing = self.inner(it, self.timer) 178 finally: 179 if gcold: /usr/lib/python3.7/timeit.py in inner(_it, _timer) NameError: name 'test' is not defined
ちなみに文字列で無理やり食わせると動いた。
例4(OK)
import timeit formula_str = """ def test(i): for i in range(i): print('aaa') test(10)""" timeit.timeit(formula_str, number= 1)
aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa 0.0010455369999817776
SQLのクエリ書いたり、PyStanのコード書いたりするときは文字列でよく渡すけど、標準ライブラリで求められることがなかったので、新鮮な体験だった。
Seabornのプロットでマーカーの色を変える
最近、Seabornでプロットをすることが増えたのですが、デフォルトだと色味がパッとしなかったり、サブプロットしたら全部同じ色になったりして困ったので、色を変える方法を調べてみました。
サマリ
- seaborn.scatterplotのpaletteにパレット名を指定することで、色の系列を変えることができる。
- 単色の場合は、seaborn.scatterplotのcolorにmatplotlibのnamed colorsの色名を渡すことで色を変えることができる。
前提
seabornのバージョン:'0.10.0'
seaborn.scatterplotは以下のドキュメントを参照(ただし、リンクは最新のバージョン)。
seaborn.pydata.org
散布図の色を変えてみる。
データのロード
今回は、ペンギンデータセットを使います。
github.com
penguins = pd.read_csv("https://github.com/allisonhorst/palmerpenguins/raw/5b5891f01b52ae26ad8cb9755ec93672f49328a8/data/penguins_size.csv")
penguins.head()
単純にscatterplotで散布図を書くとこのようになります。
hueを使う場合
ご存知の通り、hueを使うことで、あるカテゴリで層別し、色を変えてプロットすることができます。
ペンギンの場合は、種類を表すspecies_shortの値が{'Adelie', 'Chinstrap', 'Gentoo'}のどれかなので、これをhueに指定しましょう。
sns.scatterplot(data=penguins, x="culmen_length_mm", y="culmen_depth_mm", hue="species_short")
paletteにpaletteの名前を指定することで、色味を変えることができます。パステルカラーにしてみましょう。
sns.scatterplot(data=penguins, x="culmen_length_mm", y="culmen_depth_mm", hue="species_short", palette="Pastel1")
パレットの文字列の一覧は、こちらの記事を参考にできます。少々乱暴ですが、エラーを起こして指定できる文字列を吐き出させています。
medium.com
サブプロットなどで層別ごとに個別にグラフを書く場合
さて、先ほどはhueを指定することで一つのグラフに3種のデータを描画しました。しかし、色が違うものの、点の分布が混ざっていて少々見にくいです。そう言う場合は、subplotを使って、species_shortごとに異なるデータとして散布図を描くことになるかもしれません。
fig, axs = plt.subplots(1, 3, sharey=True) #'Adelie', 'Chinstrap', 'Gentoo' g_Adelie = sns.scatterplot(data=penguins[penguins["species_short"] == "Adelie"], x="culmen_length_mm", y="culmen_depth_mm", ax=axs[0]) g_Adelie.set_title("Adelie") g_Adelie.set(xlim=(30, 60)) g_Adelie.set(ylim=(13, 22)) g_Chinstrap = sns.scatterplot(data=penguins[penguins["species_short"] == "Chinstrap"], x="culmen_length_mm", y="culmen_depth_mm", ax=axs[1]) g_Chinstrap.set_title("Chinstrap") g_Chinstrap.set(xlim=(30, 60)) g_Chinstrap.set(ylim=(13, 22)) g_Gentoo = sns.scatterplot(data=penguins[penguins["species_short"] == "Gentoo"], x="culmen_length_mm", y="culmen_depth_mm", ax=axs[2]) g_Gentoo.set_title("Gentoo") g_Gentoo.set(xlim=(30, 60)) g_Gentoo.set(ylim=(13, 22))
さて、無事に描くことができましたが、見ての通り、色が同じなので視覚的にパッとしません。
色を変えたい場合は、colorにmatplotlibのnamed colorsの色名を渡すことで色を変えることができます。
matplotlib.org
fig, axs = plt.subplots(1, 3, sharey=True) #'Adelie', 'Chinstrap', 'Gentoo' g_Adelie = sns.scatterplot(data=penguins[penguins["species_short"] == "Adelie"], x="culmen_length_mm", y="culmen_depth_mm", color="aqua", ax=axs[0]) g_Adelie.set_title("Adelie") g_Adelie.set(xlim=(30, 60)) g_Adelie.set(ylim=(13, 22)) g_Chinstrap = sns.scatterplot(data=penguins[penguins["species_short"] == "Chinstrap"], x="culmen_length_mm", y="culmen_depth_mm", color="fuchsia", ax=axs[1]) g_Chinstrap.set_title("Chinstrap") g_Chinstrap.set(xlim=(30, 60)) g_Chinstrap.set(ylim=(13, 22)) g_Gentoo = sns.scatterplot(data=penguins[penguins["species_short"] == "Gentoo"], x="culmen_length_mm", y="culmen_depth_mm", color="lightgreen", ax=axs[2]) g_Gentoo.set_title("Gentoo") g_Gentoo.set(xlim=(30, 60)) g_Gentoo.set(ylim=(13, 22))
コードにTODOのコメントを埋め込むvimプラグインを作った。
コードの未実装の箇所に、「こんな感じで実装していこうと思います、リファレンスはこれです。」とTODOのコメントを入れるvimプラグインを作りました。
github.com
インストール
{packpath}/pack/plugins/start 配下にgit cloneしてください。
dein.vimを使っている方は、dein.tomlなどに追記してインストールしてください。
[[plugins]] repo = 'tasotasoso/vim-TodoComment'
dein.vimの使い方は本家レポジトリやさくらのナレッジの記事を参照のこと。
使い方
1. vimのnormalモードで :TodoComment を入力する。
2. コメントの入力を促されるので、任意のコメントを入力する。
3. コメントの根拠になるURLの入力を促されるので、ドキュメントなどのURLを入力する。
GithubのReadmeにgifを入れために、gifの作成からReadmeの編集までやってみた。
Vimプラグインを作った際に、Readmeに挙動が分かるようなGif動画を入れたかったので、
gifの作り方から調べてReadmeに入れるところまでやってみた。
出来栄えは、こんな感じ。
github.com
一番最後の画像。
手順
1. デモ画面の動画を撮影する。
MacだとQuickTime Playerがあるのでこれを使う。
Mac用QuickTime Playerユーザガイド - Apple サポート
[ファイル] > [新規画面収録] からデモ画面の撮影ができる。このとき、画面の一部だけ指定して撮影できるので、その機能を使う。
これで、デモ画面を撮影した.movファイルができる。
2. Gifに変換する。
以下の記事などを参考に、1で作成した.movをgifに変換する。
.mov を gif に変換【Mac】 - Qiita
まずインストールする。
brew install ffmpeg
上手くインストールできていそうだったら、1で作成した.movを指定してgifに変換する。
ffmpeg -i sample.mov -r 10 sample.gif
3. Readmeを作成するレポジトリに、gifを格納するbranchを作成して、gifを上げる。
gifの保存先はいろいろ候補があるようだったが、githubに上げておくのが一番スマートそうだったのでそうする。
一方で、masterにgifを入れておくとダウンロードする際にも容量が大きくなり、使ってくれる人に迷惑をかけてしまいかねないので、
gifを入れておくようのmediaというbranchを作成してそこに入れておく。
具体的な操作がわからない場合は、以下が参照になる。
GitHubでREADMEにgif画像を表示する簡単な方法 - Qiita
4. Readmeにリンクを挿入する。
Readmeに先ほどアップロードしたgif動画のリンクを挿入する。リンクはブラウザでgithub上のgif動画を開いて、そのURLをコピペすればいい。
挿入方法は、以下の一行をreadmeに差し込むだけ。
![TodoComment](【皆さんのgif動画のURL】)
Sparkで"使い方が誤っています"でJavaが読み込めない。
PythonでAESの暗号化を試した
PythonでAESの暗号化を学んだのでメモ。
やりたいこと
C#で暗号化されたものをPythonで再現する。
c#の暗号化クラスを使ってみた(AES,RSA) - Qiita
PythonでAESの暗号化を行う
CBCモードで行うAESにより暗号化するサンプルコードは、以下が参考になる。
pycryptodome.readthedocs.io
PyCryptodomeを選択した理由は、Developers.IOから、PyCryptodomeがよさそうだったため。
AES対応のPython暗号化ライブラリを比較検証してみた | Developers.IO
実験
サンプルコードを参考に、鍵とinitialization vectorを指定して、暗号が再現できるか確認する。
※initialization vectorは本当は固定しないが、今回は実験のため固定する。
from base64 import b64encode from Crypto.Cipher import AES from Crypto.Random import get_random_bytes from Crypto.Util.Padding import pad import json data = "Hello, World!".encode('utf-8') key = "9Fix4L4HB4PKeKWY".encode('utf-8') iv = "pf69DL6GrWFyZcMK".encode('utf-8') #get_random_bytes(16) cipher = AES.new(key=key, mode=AES.MODE_CBC, iv=iv) ct_bytes = cipher.encrypt(pad(data, AES.block_size)) iv = b64encode(iv).decode('utf-8') ct = b64encode(ct_bytes).decode('utf-8') result = json.dumps({'iv':iv, 'ciphertext':ct}) print(result) #{"iv": "cGY2OURMNkdyV0Z5WmNNSw==", "ciphertext": "p8ITppfvm6QnVtL/Ji9/ZQ=="}
確かに暗号化した文が一致している。
参考
C#のAESについて
System.Security.CryptographyにAESのクラス群が定義されている。抽象基底クラスは以下。
docs.microsoft.com
Wikiの記載によると、AESに採用されたのはRijndaelで、これもクラスがある。
ただし、AESとの違いが以下に説明されている。
docs.microsoft.com
CloudTrailの証跡機能にだいぶ詳しくなったのでまとめる
CloudTrailの証跡機能にだいぶ詳しくなったので、個人的なまとめです。
CloudTrailの概要
CloudTrailはアカウントの操作ログを記録し、ログを Amazon S3 バケットに送信することができます。
90日分の管理イベントを無料で保存、検索することが可能です。
証跡の作成により、管理イベントを、S3などにエクスポートすることができます。
また、オプションでデータイベントとCloudTrail Insightsも保存することができます。
各々のログの概要と料金は下記のようになります。
種類 | 概要 | 料金 |
管理イベント | AWSアカウントの操作履歴 | イベント 10 万件あたり 2.00USD(証跡一つ目は無料) |
データイベント | Amazon S3 オブジェクトレベルの API 呼び出し、Lambda 関数の実行履歴 | イベント 10 万件あたり 0.10USD |
CloudTrail Insights | AWS アカウントの異常な操作履歴 | 100,000 の書き込み管理イベントごとに 0.35USD |
管理イベントは一つ目が無料なため、とりあえず、管理イベントのみ保存して、データイベントとCloudTrail Insightsは要件によって保存する場合が多いかと思います。
ログは、デフォルトで以下のプレフィクスに保存されます。
S3バケット名/AWSLogs/アカウントID/
オプションでAWSLogsの前にプレフィクスを追加することも可能です。
この場所には以下の2種のデータが作成されます。
- CloudTrailログ
CloudTrailの階層が掘られ、そのさらに下に、リージョン/YY/mm/dd/にjson.gzで保存されます。
https://docs.aws.amazon.com/ja_jp/awscloudtrail/latest/userguide/cloudtrail-log-file-examples.html
- ダイジェストファイル
CloudTrail-Digest配下に作成される。ログファイルの名前、これらのログファイルのハッシュ値、前のダイジェストファイルのデジタル署名が含まれます。
https://docs.aws.amazon.com/ja_jp/awscloudtrail/latest/userguide/cloudtrail-log-file-validation-digest-file-structure.html
CloudTrailログの例
レコードの項目は全て公式ドキュメントに記載されています。
CloudTrail レコードの内容 - AWS CloudTrail
具体的には以下のようなログが出力されます。
#From https://docs.aws.amazon.com/ja_jp/awscloudtrail/latest/userguide/cloudtrail-log-file-examples.html {"Records": [{ "eventVersion": "1.0", "userIdentity": { "type": "IAMUser", "principalId": "EX_PRINCIPAL_ID", "arn": "arn:aws:iam::123456789012:user/Alice", "accountId": "123456789012", "accessKeyId": "EXAMPLE_KEY_ID", "userName": "Alice" }, "eventTime": "2014-03-24T21:11:59Z", "eventSource": "iam.amazonaws.com", "eventName": "CreateUser", "awsRegion": "us-east-2", "sourceIPAddress": "127.0.0.1", "userAgent": "aws-cli/1.3.2 Python/2.7.5 Windows/7", "requestParameters": {"userName": "Bob"}, "responseElements": {"user": { "createDate": "Mar 24, 2014 9:11:59 PM", "userName": "Bob", "arn": "arn:aws:iam::123456789012:user/Bob", "path": "/", "userId": "EXAMPLEUSERID" }} }]}
CloudTrailログの検索
Athenaを使ってクエリをかけることも可能です。
テーブルは以下のクエリで作成できます。
#From https://docs.aws.amazon.com/ja_jp/athena/latest/ug/cloudtrail-logs.html CREATE EXTERNAL TABLE cloudtrail_logs ( eventversion STRING, useridentity STRUCT< type:STRING, principalid:STRING, arn:STRING, accountid:STRING, invokedby:STRING, accesskeyid:STRING, userName:STRING, sessioncontext:STRUCT< attributes:STRUCT< mfaauthenticated:STRING, creationdate:STRING>, sessionissuer:STRUCT< type:STRING, principalId:STRING, arn:STRING, accountId:STRING, userName:STRING>>>, eventtime STRING, eventsource STRING, eventname STRING, awsregion STRING, sourceipaddress STRING, useragent STRING, errorcode STRING, errormessage STRING, requestparameters STRING, responseelements STRING, additionaleventdata STRING, requestid STRING, eventid STRING, resources ARRAY<STRUCT< ARN:STRING, accountId:STRING, type:STRING>>, eventtype STRING, apiversion STRING, readonly STRING, recipientaccountid STRING, serviceeventdetails STRING, sharedeventid STRING, vpcendpointid STRING ) PARTITIONED BY (region string, year string, month string, day string) ROW FORMAT SERDE 'com.amazon.emr.hive.serde.CloudTrailSerde' STORED AS INPUTFORMAT 'com.amazon.emr.cloudtrail.CloudTrailInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat' LOCATION 's3://CloudTrail_bucket_name/AWSLogs/Account_ID/CloudTrail/';
パーティションはリージョン・年・月・日で設定することを推奨されています。
リージョンは、CloudTrailの証跡設定作成時に、全リージョンで作成することを指定しなければ、証跡を設定したリージョンのみになります。
後から設定するのは面倒臭いので、とりあえずリージョンもパーティションに含めておくと良さそうです。
注意点としては、CloudTrail証跡は現状、以下のプレフィクスで出力されるため、
MSCK REPAIR TABLE でパーティションデータを自動的に追加できません。
S3バケット/AWSLogs/アカウントID/CloudTrail/リージョン/YY/mm/dd/
そのため、バッチ処理などでADD PARTITIONでパーティションを追加する必要があります。
Athenaのクエリだと以下のようになります。
ALTER TABLE [テーブル名] ADD PARTITION (region='[リージョン]',year='[設定値]',month='[設定値]',day='[設定値]') location 's3://[バケット]/[プレフィックス]/';
バッチ処理での実行方法は、Lambda・Fargate・Glueなどいろいろな方法があります。lambdaでの実行方法は、以下のサイトが参考になります。
dev.classmethod.jp
ログの記録をOFFにした時
ログの記録をOFFにすると、当然ですがログの保存は中止されます。
ONにしても、OFFにしていた間のログは勝手には配信されません。
ログの記録のON/OFFは、[CloudTrai]l >[ 証跡情報] > (各証跡の)設定 から行えます。
配信エラーになった時
こちらにまとめがあるので参考にしてください。
tasotasoso.hatenablog.com