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

ABC222 チャレンジ結果

ABC222結果 : ABC3完 相変わらずD問題で詰まってしまう... 以下ソースコード A : Four Digits パッと構文が分からないときのとりあえずfor文で回す. N = input() k = 4 - len(N) for i in range(k): print(0, end="") print(N) B : Failing Grade 問題文そのまま. 解説見たら内包表記使えば行数少なくできることに気づかされる. N, P = list(map(int, input().split(" "))) list_N = list(map(int, input().split(" "))) num = 0 for i in range(N): if list_N[i] < P: num += 1 print(num) C : Swiss-System Tournament 勝数とindexでソートするために, 勝った場合は減算することに. 途中でindexもいると気づいてコードいじったため, リストが[勝数, じゃんけんの情報, index]の順になり見栄え悪し. import operator def janken(p, q, i): if (hito_list[p][1][i] == "G" and hito_list[q][1][i] == "C") \ or (hito_list[p][1][i] == "C" and hito_list[q][1][i] == "P") \ or (hito_list[p][1][i] == "P" and hito_list[q][1][i] == "G"): hito_list[p][0] -= 1 elif (hito_list[p][1][i] == "C" and hito_list[q][1][i] == "G") \ or (hito_list[p][1][i] == "P" and hito_list[q][1][i] == "C") \ or (hito_list[p][1][i] == "G" and hito_list[q][1][i] == "P"): hito_list[q][0] -= 1 N, M = list(map(int, input().split(" "))) hito_list = [] for i in range(2 * N): GCP_list = input() hito_list.append([0, GCP_list, i+1]) for i in range(M): for j in range(N): janken(2 * j , 2 * j + 1, i) hito_list = sorted(hito_list, key=operator.itemgetter(0, 2)) for num in range(2 * N): print(hito_list[num][2]) D : Between Two Arrays ・間違いコード 自分なりに一通り組んでみたが, 提出すると後半実行時エラーのオンパレード. 再帰でうまくいくと思ったのにー TLEはしょうがないが, REになるのは未だ分かっておらず泣 DP使う発想が全くなく使い方も分かってないので修行を重ねるしかあるまい... N = int(input()) a_list = list(map(int, input().split())) b_list = list(map(int, input().split())) num = 0 d = 0 def ktz_kosuu(list1, list2, N): global d, num d = max(list1[0], d) if N == 1: erabikata = list2[0] - d + 1 num += erabikata else: e = d for j in range(e, list2[0]+1): d = j x = list1.pop(0) y = list2.pop(0) ktz_kosuu(list1, list2, N-1) list1.insert(0, x) list2.insert(0, y) return num % 998244353 kotae = ktz_kosuu(a_list, b_list, N) print(kotae)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Python機械学習/pickleファイルを使ったオブジェクトの保存

Summary Pythonで機械学習をする際のデータやモデルの保存にはpickleファイルを使用するのが非常に便利なので,その使い方についてメモを残しておく. データの準備 今回はScikit-learnのガンデータを使用. from sklearn.datasets import load_breast_cancer import pandas as pd cancer = load_breast_cancer() data_feature = pd.DataFrame(cancer.data, columns=cancer.feature_names) data_target = pd.DataFrame(cancer.target) csvファイルでデータ管理 まずは一般的なCSVファイルでのデータ読み書きについて記す. csvファイルで保存 data_feature.to_csv('data_feature.csv') data_target.to_csv('data_target.csv') csvファイルの読込 feature_csv = pd.read_csv('data_feature.csv', index_col=0) target_csv = pd.read_csv('data_target.csv', index_col=0) pickleファイルでデータ管理 では本題のpickleファイルでのデータ読み書きについて記す. pickleファイルで保存 data_feature.to_pickle('data_feature.pkl') data_target.to_pickle('data_target.pkl') pickleファイルの読込 feature_pkl = pd.read_pickle('data_feature.pkl') target_pkl = pd.read_pickle('data_target.pkl') pickleファイルで保存することで,ヘッダーやインデックスの有無など気にすることなく,保存時のデータをそのまま読み込めるので非常に便利. 機械学習モデルをpickleファイルで管理 生成した機械学習モデルもpickleで保存できるので,その方法について記す. とりあえずロジスティック回帰でモデル生成. from sklearn.linear_model import LogisticRegression model = LogisticRegression() model.fit(feature_pkl, target_pkl) print(model.score(feature_pkl, target_pkl)) Out: 0.945518453427065 モデルの保存 import pickle pickle.dump(model, open('model.pkl', 'wb')) モデルの読込 model_pkl = pickle.load(open('model.pkl', 'rb')) print(model_pkl.score(feature_pkl, target_pkl)) Out: 0.945518453427065 Conclusion 今回使用した関数. - DF.to_pickle():データフレームをpickleファイルで保存 - DF.read_pickle():pickleファイルで保存されたデータフレームの読込 - pickle.dump():機械学習モデルをpickleファイルで保存 - pickle.load():pickleファイルで保存された機械学習モデルの読込 pythonによる機械学習が捗ると思うので,pickleファイルを活用されたし. Code # データの準備 from sklearn.datasets import load_breast_cancer import pandas as pd cancer = load_breast_cancer() data_feature = pd.DataFrame(cancer.data, columns=cancer.feature_names) data_target = pd.DataFrame(cancer.target) # csvファイルでデータ管理 ## データの保存 data_feature.to_csv('data_feature.csv') data_target.to_csv('data_target.csv') ## データの読込 feature_csv = pd.read_csv('data_feature.csv', index_col=0) target_csv = pd.read_csv('data_target.csv', index_col=0) # pickleファイルでデータ管理 ## データの保存 data_feature.to_pickle('data_feature.pkl') data_target.to_pickle('data_target.pkl') ## データの読込 feature_pkl = pd.read_pickle('data_feature.pkl') target_pkl = pd.read_pickle('data_target.pkl') # 機械学習モデルをpickleファイルで管理 ## モデル生成 from sklearn.linear_model import LogisticRegression model = LogisticRegression() model.fit(feature_pkl, target_pkl) print(model.score(feature_pkl, target_pkl)) ## データ保存 import pickle pickle.dump(model, open('model.pkl', 'wb')) ## データの読込 model_pkl = pickle.load(open('model.pkl', 'rb')) print(model_pkl.score(feature_pkl, target_pkl))
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

poetryを使って外部モジュールからimportできるようにパッケージングする

pythonモジュールをパッケージングして、pip installしたのちに別モジュールでimportして使いたい poetryを使うことでパッケージングは簡単にできたが、肝心な別モジュールでimportして使うところでハマったのでやり方を残す やったこと pyproject.tomlにて[build-system]を下記のように設定 [build-system] requires = ["setuptools", "wheel"]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ubuntuに最新バージョンのPythonをインストールする

ubuntu20.04に最新のPython3.10.0をインストールする Ubuntuのバージョン確認。 cat /etc/lsb-release DISTRIB_ID=Ubuntu DISTRIB_RELEASE=20.04 DISTRIB_CODENAME=focal DISTRIB_DESCRIPTION="Ubuntu 20.04.3 LTS" アーキテクチャは64bit。 arch x86_64 ビルド環境の準備 sudo apt update sudo apt install build-essential libbz2-dev libdb-dev \ libreadline-dev libffi-dev libgdbm-dev liblzma-dev \ libncursesw5-dev libsqlite3-dev libssl-dev \ zlib1g-dev uuid-dev tk-dev ソースコードのダウンロード Python Japanのダウンロードページ https://pythonlinks.python.jp/ja/index.html ダウンロードコマンド wget https://www.python.org/ftp/python/3.10.0/Python-3.10.0.tar.xz 解凍コマンド tar xJf Python-3.10.0.tar.xz ビルドコマンド cd Python-3.10.0 ./configure make sudo make install 再起動 reboot バージョン確認コマンド python3 -V Python 3.10.0
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VGG16によるファインチューニングで胸部X線画像における肺炎の分類をする

概要・目的 Kaggle で公開されているデータセットを使って 胸部 X 線画像から正常 (Normal) か肺炎 (Pneumonia) を分類する 画像データ数は合計5856枚 (train: 5216, val: 16, test: 624) 画像サイズはデータによってまちまち trainデータの Normal とPneumonia の枚数の差が大きい (Normal: 1341, Pneumonia: 3875) テストデータでの accuracy: 95 % となった (画像出典: https://data.mendeley.com/datasets/rscbjbr9sj/2) (Kaggle: https://www.kaggle.com/paultimothymooney/chest-xray-pneumonia) 採用アルゴリズム 画像の前処理 画像データの不要な部分をトリミング 画像両側にうつる背景部分を削除し、分類に必要な部分のみを残す狙い 画像の加工は以下の3種類について学習し、比較した a. 画像を引き延ばさず、224×224 pixel に合わせる b. 画像の両側をトリミングしたうえで 224×224 pixel に引き延ばす c. 画像をトリミングせずに224×224 pixel に引き延ばす テストデータでもっとも精度のよかった (b) を採用した 訓練、検証データの Normal:Pneumonia 比が同じになるよう分割 訓練データは Normal と Pneumonia の枚数がそれぞれ1341枚、3875枚と大きな開きがある。 これらのデータをそのまま結合して分割すると、訓練データにほとんど Normal の画像が無いといった事態が起こりうる。 Normal のデータ、Pneumonia のデータそれぞれを8:2 の割合で訓練データと検証データに分けることで、ばらつきを無くした。 データの学習 データの拡張(回転、拡大、平行移動) 過学習を防ぐために、Keras の ImageDataGenerator を用いて、バッチごとにランダムに回転・拡大・平行移動を施した。 他にも明暗を変化できるが、すべて Pneumonia と予測したため不採用。 (どうやらImageDataGenerator上で問題があるよう 参考: https://qiita.com/Kuru-chan/items/3365d48b3345d2b9cfd2) 回転・拡大・平行移動の最大値および最小値は、 3つのの場合を比較し、以下を採用。 回転: -20~20度 拡大: MAX 15% 平行移動: MAX 15% VGG16を用いてファインチューニング、学習の進行とともに学習率を減少 今回は転移学習によく用いられるVGG16を使用した。 最後の畳み込み層 (conv5) がある部分のみ訓練データを学習させ、ファインチューニングした。 学習が進行するにつれ、精度の改善が見られなくなるため、学習の後半では、徐々に学習率を減少させるようにした。 テストデータでの予測結果 Normal は Pneumonia と比較して学習画像が少ないため、精度が比較的低い 学習回数 (epoch 数) は40回に設定しているが、80回でもほとんど同じ結果であった Normal の画像が少ないことを考慮してNormal の重みを増やし、Pneumonia の重みを減らしてもほとんど同じ結果であった 今回は試していないが、画像ごとにトリミング幅を調整することでさらなる精度向上が望める。 その他、訓練データに偏りがあることへの良い改善策が見つかると、1%程度精度が向上するかもしれない(希望)。 Githubでコードを公開しています
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ケミストリーエンジニアからデータサイエンスを学ぶ!

ケミストリーエンジニアがまず、勉強始めようと思いましたら、 MIの概要、考え方を学んでみるのはいかがでしょうか。 MIの基礎情報(プログラムなし) マテリアルズ・インフォマティクス 材料開発のための機械学習超入門 [ 岩崎 悠真 ] プログラムの内容は書いてなく、 MIとは何か、どのように使うのかを広く浅く書いてあるので 最初の1冊としてはいかがでしょうか。 もう少しプログラムの内容も見てみたいとなりましたら、 下記書籍はいかがでしょうか。 ケミ寄りの機械学習書籍 (プログラムあり) 化学のためのPythonによるデータ解析・機械学習入門 [ 金子 弘昌 ] ケミストリー寄りに機械学習の初歩的なところが記載されている感じです。 プログラムの内容もありますが 考え方が記載されていそうな感じです。 もしRDkitの環境構築に困りましたら下記記事参考にしてみてはいかがでしょうか。 「化学のためのPythonによるデータ解析・機械学習入門 [ 金子 弘昌 ]」 が難しくて挫折しそうな場合、 下記項目について理解しているとより理解しやすいかなと思います。 ・機械学習について ・Pythonの基礎知識 ・Pythonによるデータ分析手法 機械学習の基礎(プログラムあり) 機械学習について図で分かりやすく説明しているので 機械学習の用語のイメージがわかない人はおすすめです。 プログラムの書き方もあるので、今後使いたくなった時にも便利かなと思います。 見て試してわかる機械学習アルゴリズムの仕組み 機械学習図鑑 [ 秋庭 伸也 ] Pythonの基礎を学ぶ Pythonの基礎の基礎から行うのであれば、 下記書籍はいかがでしょうか。 Pythonって何?というところから学ぶことができます。 プログラムを全くさわったことがない人にはおすすめです。 print("Hello") からわかりやすく教えてくれます。 Python 1年生 体験してわかる!会話でまなべる!プログラミングのしくみ [ 森 巧尚 ] Pythonのデータ分析手法の基礎を学ぶ Pythonの基礎がわかってきましたら、 下記書籍でデータ分析手法を勉強してみてはいかがでしょうか。 Pythonエンジニア認定データ分析試験の対策にもなります。 Pythonによるあたらしいデータ分析の教科書 [ 寺田 学 ] MI関連の書籍(紹介) 記事作成者もしっかり読み込んでいないので参考です。 プログラミング不要のMIチャレンジソフト Orange Data Miningではじめるマテリアルズインフォマティクス [ 木野日織 ] マテリアルズインフォマティクスの書籍 (プログラムあり) 実践 マテリアルズインフォマティクス Pythonによる材料設計のための機械学習 [ 船津 公人 ] BIツールのように可視化することができ、機械学習行えるソフトの使い方の説明です。 プログラムの知識は不要ですが、 機械学習の理解は必要です。 何がしたいか、どの手法を使いたいか までは理解していないと使うのは難しそうな感じです。 この中ではプログラム記載量は多いイメージ それなりにしっかり機械学習のプログラムを書いていくような感じです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ケミストリーエンジニアがMIを学ぶには?

ケミストリーエンジニアがまず、勉強始めようと思いましたら、 MIの概要、考え方を学んでみるのはいかがでしょうか。 MIの基礎情報(プログラムなし) マテリアルズ・インフォマティクス 材料開発のための機械学習超入門 [ 岩崎 悠真 ] プログラムの内容は書いてなく、 MIとは何か、どのように使うのかを広く浅く書いてあるので 最初の1冊としてはいかがでしょうか。 もう少しプログラムの内容も見てみたいとなりましたら、 下記書籍はいかがでしょうか。 ケミ寄りの機械学習書籍 (プログラムあり) 化学のためのPythonによるデータ解析・機械学習入門 [ 金子 弘昌 ] ケミストリー寄りに機械学習の初歩的なところが記載されている感じです。 プログラムの内容もありますが 考え方が記載されていそうな感じです。 もしRDkitの環境構築に困りましたら下記記事参考にしてみてはいかがでしょうか。 win10でRDKitの構築をしたときのメモ ・ANACONDA.NAVIGATORを開く ・「Environments」を開く ・「Create」を開く ・名前(Python3_7_11)を決め、パッケージのバージョン(Python3.7.11)決定し、 ・「Create」を選択する。 ・Anaconda Pronmpt(Anaconda3)を開く 新しい環境構築をする conda activate Python3_7_11 下記のような感じです。 (Python3_7_11) C:\Users\Owner> conda activate Python3_7_11 下記コマンドでベースに戻ることができる。 conda deactivate RDKitをインストールする conda install -y -c rdkit rdkit 最初の環境構築は時間がかかるかと思いますが 最初だけなのでめげずに頑張りましょう^^ 「化学のためのPythonによるデータ解析・機械学習入門 [ 金子 弘昌 ]」 が難しくて挫折しそうな場合、 下記項目について理解しているとより理解しやすいかなと思います。 ・機械学習について ・Pythonの基礎知識 ・Pythonによるデータ分析手法 機械学習の基礎(プログラムあり) 機械学習について図で分かりやすく説明しているので 機械学習の用語のイメージがわかない人はおすすめです。 プログラムの書き方もあるので、今後使いたくなった時にも便利かなと思います。 見て試してわかる機械学習アルゴリズムの仕組み 機械学習図鑑 [ 秋庭 伸也 ] Pythonの基礎を学ぶ Pythonの基礎の基礎から行うのであれば、 下記書籍はいかがでしょうか。 Pythonって何?というところから学ぶことができます。 プログラムを全くさわったことがない人にはおすすめです。 print("Hello") からわかりやすく教えてくれます。 Python 1年生 体験してわかる!会話でまなべる!プログラミングのしくみ [ 森 巧尚 ] Pythonのデータ分析手法の基礎を学ぶ Pythonの基礎がわかってきましたら、 下記書籍でデータ分析手法を勉強してみてはいかがでしょうか。 Pythonエンジニア認定データ分析試験の対策にもなります。 Pythonによるあたらしいデータ分析の教科書 [ 寺田 学 ] MI関連の書籍(紹介) 記事作成者もしっかり読み込んでいないので参考です。 プログラミング不要のMIチャレンジソフト Orange Data Miningではじめるマテリアルズインフォマティクス [ 木野日織 ] BIツールのように可視化することができ、機械学習行えるソフトの使い方の説明です。 プログラムの知識は不要ですが、 機械学習の理解は必要です。 何がしたいか、どの手法を使いたいか までは理解していないと使うのは難しそうな感じです。 マテリアルズインフォマティクスの書籍 (プログラムあり) 実践 マテリアルズインフォマティクス Pythonによる材料設計のための機械学習 [ 船津 公人 ] この中ではプログラム記載量は多いイメージ それなりにしっかり機械学習のプログラムを書いていくような感じです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【連続極座標系】円筒形座標系(Cylindrical Coordinate System)による加法群(Additive Group)と乗法群(Multiplicative Group)と商群(Quotient Group)の統合

今回も関数の基本概念(Function Basic Concept)そのものからの再出発となります。最近ずっとこの辺りを堂々巡りしています。よっぽど基礎が出来てなかったとしか思えません。 【Python演算処理】冪算と乗除算の関係について。 二つの数の集合X,Yがあって、Xの要素xに対してYの要素yがただ一つ定まる時、この対応を関数(Function)と呼びy=f(x)などと書き表す(fはfunctionの略だが、複数の関数への言及が不可避となる状況ではそれをy=g(x),y=h(x)などと呼び分ける)。 この時xを独立変数(Independent Variable)、yを従属変数(Dependent Variable)と呼ぶ。 また集合Xを関数fの定義域(Domain)、集合Yの部分集合$(y|y=f(x),x \in X)$をこの関数の値域(Range)という。 関数y=fxの変化の様子はxの値を横座標、yの値を縦座標としxを定義域内で変化させた時の点P(x,y)の軌跡を描くと一目瞭然となる。これが関数y=f(x)のグラフである。 全準同型(Epimorphism)と群同型(Group Isomorphism) かかる関数概念は、これを群演算(Group Operation)に採用した群論(Group Theory)における準同型(Homomorphism)・同型(Isomorphism)の定義にも関わってくるのです。 ここで独立変数集合(Independent Variable Set)Xに含まれる任意のxに対して演算f(x)の結果集合(Operation Result Set)=従属変数集合(Dependent Variable Set)Yに含まれるただ一つのyが定まるものとする。 X_n{\begin{pmatrix}x_1\\x_2\\x_3\\\vdots\\x_n\end{pmatrix}} →f(X_n){\begin{pmatrix}f(x_1)\\f(x_2)\\f(x_3)\\\vdots\\f(x_n)\end{pmatrix}} →Y_n{\begin{pmatrix}y_1\\y_2\\y_3\\\vdots\\y_n\end{pmatrix}}\\ f(\forall x)=\exists! y (x \in X,y \in Y \land X,Y \in \mathbb{C}) かかる演算操作(Operation)を射映(Projection)といい、従属変数集合Yは独立変数集合Xの写像(Map)と呼ばれ、かつ後者と前者は準同型(Homomorphism)の関係にあるとされる。さらにxとyの関係を入れ替えた逆演算(Inverse Operation)x=f(y)も成立する時、二つの集合の間に独立変数集合と従属変数集合の関係が入れ替え可能な一対一対応が生じるが、この状態を全準同型(Surjective Homomorphism, Epimorphism)、その条件を満たさない場合を単準同型(Injective Homomorphism, Monomorphism)と呼び分ける。 X_n{\begin{pmatrix}x_1\\x_2\\x_3\\\vdots\\x_n\end{pmatrix}} →f(X_n){\begin{pmatrix}f(x_1)\\f(x_2)\\f(x_3)\\\vdots\\f(x_n)\end{pmatrix}} →Y_n{\begin{pmatrix}y_1\\y_2\\y_3\\\vdots\\y_n\end{pmatrix}}\\ かつ\\ Y_n{\begin{pmatrix}y_1\\y_2\\y_3\\\vdots\\y_n\end{pmatrix}} →f(Y_n)^{-1}{\begin{pmatrix}f(y_1)^{-1}\\f(y_2)^{-1}\\f(y_3)^{-1}\\\vdots\\f(y_n)^{-1}\end{pmatrix}} →X_n{\begin{pmatrix}x_1\\x_2\\x_3\\\vdots\\x_n\end{pmatrix}}\\ f(\forall x)=\exists! y \land f(\forall y)=\exists! x(x \in X,y \in Y \land X,Y \in \mathbb{C}) ちなみに 単位元0で加減算に立脚する加法群Aの逆演算は反数-A 単位元1で乗除算に立脚する乗法群Aの逆演算は逆数$\frac{1}{A}$ 単位元1で冪乗算に立脚する乗法群$A^{x}$の逆演算は冪乗$A^{-x}$ 単位元Aで冪乗算に立脚する乗法群$A^{x}$の逆演算は冪根$A^{\frac{1}{x}}$ さらに群同型(Group Isomorphism=全単射/双射=Bijective Function, Bijection可能)が成立する為には、集合Aの任意の元a($\forall a \in A$)について$a_n$を定義域とする群演算y=f(x)の値域$a_m$を定義域とする逆演算y=f(x)^{-1}の値域が$a_n$となるのに加え、元aと逆元$a^{-1}、逆元$a^{-1}$と元aの演算結果がどちらも単位元(Identity Element)Iとならねばならない(元aと逆元$a^{-1}$と単位元Iが全て集合Aに包含されるのと同値)。 A_n{\begin{pmatrix}a_1\\a_2\\a_3\\\vdots\\a_n\end{pmatrix}} →f(A_n){\begin{pmatrix}f(a_1)\\f(a_2)\\f(a_3)\\\vdots\\f(a_n)\end{pmatrix}} →A_m{\begin{pmatrix}a_1\\a_2\\a_3\\\vdots\\a_m\end{pmatrix}}\\ かつ\\ A_m{\begin{pmatrix}a_1\\a_2\\a_3\\\vdots\\a_m\end{pmatrix}} →f(A_m)^{-1}{\begin{pmatrix}f(a_1)^{-1}\\f(a_2)^{-1}\\f(a_3)^{-1}\\\vdots\\f(a_m)^{-1}\end{pmatrix}} →A_n{\begin{pmatrix}a_1\\a_2\\a_3\\\vdots\\a_n\end{pmatrix}}\\ ただしm=n\\ f(\forall x)=\exists! y \land f(\forall y)=\exists! x(x \in X,y \in Y \land X,Y \in \mathbb{C})\\ \forall a\exists! a^{-1} \land a*a^{-1}=a^{-1}*a=I(a,a^{-1} \in A) そもそも群(Group)の原義は自己同型(Automorphism)の集合であり、n=mはそれが成立する上での必須規約となっており、この事は群演算でいう直積(Direct Product)n項×n項×…概念、線形代数でいう正方行列(Square Matrix)n行×n列×…概念に対応する。 {\displaystyle {\begin{bmatrix}a_{11}&a_{12}&\cdots &a_{1n}\\a_{21}&a_{22}&\cdots &a_{2n}\\\vdots &\vdots &\ddots &\vdots \\a_{n1}&a_{n2}&\cdots &a_{nn}\end{bmatrix}}}  集合Gとその上の二項演算μ:G×G→Gの組(G, μ)が群となる3条件:  ①結合法則(Associative law)。 {\displaystyle (\forall g,h,k\in G)[\mu (g,\mu (h,k))=\mu (\mu (g,h),k)].}  ②単位元eが一意に定まる。 {\displaystyle (\exists e\in G)(\forall g\in G)[\mu (g,e)=\mu (e,g)=g].}  ③元xに対する逆元gが(群演算ごとに)一意に定まる。 {\displaystyle (\forall g\in G)(\exists x\in G)[\mu (g,x)=\mu (x,g)=e].}  さらにアーベル群(可換群)となる条件:  ④交換法則(Commutative Law)。 μ(g, h) = μ(h, g) 交換法則(Commutative Law)の成立条件。 交換法則は、例えば関数$Y=a^x$において対称式X=Y(a=1)か対称式XY=1(a=-1)になる場合に成立します。 X=Yの場合…y=x,-y=-xのなす平面がy=-x,-y=xのなす平面と直交します。 #Inverse_Proportional_Function %matplotlib nbagg import math as m import cmath as c import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D import matplotlib.animation as animation #反比例データ作成 X=np.linspace(-5,5,41,endpoint = True) #グラフ表示 plt.style.use('default') fig = plt.figure() ax = Axes3D(fig) #関数定義 def Inverse_Proportional_Function(n): plt.cla() #比例曲線描画(0度) ax.plot(X,X,X,color="blue",lw=1) for num in range(len(X)): ax.plot([0,X[num]],[0,X[num]],[X[num],X[num]],color="gray",lw=0.5) #比例曲線描画(180度) ax.plot(-X,-X,X,color="red",lw=1) for num in range(len(X)): ax.plot([0,-X[num]],[0,-X[num]],[X[num],X[num]],color="gray",lw=0.5) #比例曲線描画(90度) ax.plot(X,-X,X,color="green",lw=1) for num in range(len(X)): ax.plot([0,X[num]],[0,-X[num]],[X[num],X[num]],color="gray",lw=0.5) #比例曲線描画(-90度) ax.plot(-X,X,X,color="green",lw=1) for num in range(len(X)): ax.plot([0,-X[num]],[0,X[num]],[X[num],X[num]],color="gray",lw=0.5) #軸線追加 ax.plot([-10,10],[0,0],[0,0],color="black",lw=1) ax.plot([0,0],[-10,10],[0,0],color="black",lw=1) ax.plot([0,0],[0,0],[-10,10],color="black",lw=1) #諸元追加 ax.set_ylim([-5,5]) ax.set_xlim([-5,5]) ax.set_zlim([-5,5]) ax.set_title("Unit Cylinder") ax.set_xlabel("X") ax.set_ylabel("X") ax.set_zlabel("X") # グラフを回転 ax.view_init(elev=45, azim=Time_code[n]) Time_code0=np.arange(0,360,6) Time_code=Time_code0[::-1] #Inverse_Proportional_Function(59) #plt.show() #xy=1=14 #-xy=1=44 #exp(X)=29 #-exp(X)=59 ani = animation.FuncAnimation(fig, Inverse_Proportional_Function, interval=50,frames=len(Time_code)) ani.save("PF003.gif", writer="pillow") 垂直軸に沿って眺めるとこう見えます。 水平軸に沿って眺めるとこう見えます。 全体として円錐を構成してますね。 %matplotlib nbagg import math as m import cmath as c import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D import matplotlib.animation as animation #円柱データ作成 c0=np.linspace(0,m.pi*120,1201,endpoint = True) s0=[] for nm in range(len(c0)): s0.append(complex(m.cos(c0[nm]),m.sin(c0[nm]))) s1=np.array(s0) z0=np.linspace(-1,1,1201,endpoint = True) #「曲率」を計算 cv1=np.linspace(-1,1,1201,endpoint = True) #cv1=num.sqrt(1-cv0**2) #断面線(z) cutz0=np.linspace(-1,1,61,endpoint = True) cutz=cutz0[::-1] cutx=np.abs(cutz) cuty=np.repeat(0,61) #単位円データ作成 u0=np.linspace(0,m.pi*2,61,endpoint = True) u1=[] for nm in range(len(u0)): u1.append(complex(m.cos(u0[nm]),m.sin(u0[nm]))) uc=np.array(u1) uz0=np.repeat(-1,61) uz1=np.repeat(-0,61) uz2=np.repeat(1,61) #グラフ表示 plt.style.use('default') fig = plt.figure() ax = Axes3D(fig) #関数定義 def unit_cylinder(n): plt.cla() #円柱描画 ax.plot(s1.real*cv1,s1.imag*cv1,z0,color="gray",lw=0.5) #スポーク描画 for num in range(len(uc)): ax.plot([0,uc[num].real],[0,uc[num].imag],[0,0],color="purple",lw=0.5) #単位円描画 ax.plot(uc.real,uc.imag,uz0,color="red",lw=1) ax.plot(uc.real,uc.imag,uz1,color="purple",lw=1) ax.plot(uc.real,uc.imag,uz2,color="blue",lw=1) #実数線追加 ax.plot([0,0],[0,0],[-1,1],color="black",lw=1) ax.plot([0,0],[-1,1],[0,0],color="black",lw=1) ax.plot([-1,1],[0,0],[0,0],color="black",lw=1) ax.plot([-1,1],[0,0],[-1,1],color="blue",lw=1) ax.plot([1,-1],[0,0],[-1,1],color="red",lw=1) ax.plot([0,0],[-1,1],[-1,1],color="green",lw=1) ax.plot([0,0],[1,-1],[-1,1],color="green",lw=1) #諸元追加 ax.set_ylim([-1.1,1.1]) ax.set_xlim([-1.1,1.1]) ax.set_zlim([-1.1,1.1]) ax.set_title("Unit Cylinder") ax.set_xlabel("X") ax.set_ylabel("X") ax.set_zlabel("X") # グラフを回転(elev=0にすると水平表示に) ax.view_init(elev=25, azim=Time_code[n]) Time_code0=np.arange(0,360,6) Time_code=Time_code0[::-1] #unit_cylinder(len(s1)) #plt.show() ani = animation.FuncAnimation(fig, unit_cylinder, interval=50,frames=len(Time_code)) ani.save("PF101.gif", writer="pillow") 自然指数関数y=exp(x)と反比例関数xy=1の関係…こちらも完全に対称式の枠内で展開。 #Inverse_Proportional_Function %matplotlib nbagg import math as m import cmath as c import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D import matplotlib.animation as animation #反比例データ作成 Z=np.linspace(-2,2,41,endpoint = True) X1=np.exp(Z) X2=np.exp(-Z) #グラフ表示 plt.style.use('default') fig = plt.figure() ax = Axes3D(fig) #関数定義 def Inverse_Proportional_Function(n): plt.cla() #反比例曲線描画 ax.plot(X1,X2,Z,color="blue",lw=1) # ax.plot(X2,X1,Z,color="red",lw=1) for num in range(len(Z)): ax.plot([0,X1[num]],[0,X2[num]],[Z[num],Z[num]],color="gray",lw=0.5) #軸線追加 ax.plot([-10,10],[0,0],[0,0],color="black",lw=1) ax.plot([0,0],[-10,10],[0,0],color="black",lw=1) ax.plot([0,0],[0,0],[-10,10],color="black",lw=1) #諸元追加 ax.set_ylim([-5,5]) ax.set_xlim([-5,5]) ax.set_zlim([-5,5]) ax.set_title("Unit Cylinder") ax.set_xlabel("exp(X)") ax.set_ylabel("exp(-X)") ax.set_zlabel("X") # グラフを回転 ax.view_init(elev=45, azim=Time_code[n]) Time_code0=np.arange(0,360,6) Time_code=Time_code0[::-1] #Inverse_Proportional_Function(44) #plt.show() #exp(X)=14 #-exp(X)=44 #exp(-X)=29 #-exp(-X)=59 ani = animation.FuncAnimation(fig, Inverse_Proportional_Function, interval=50,frames=len(Time_code)) ani.save("IPF003.gif", writer="pillow") 垂直軸に沿って眺めると反比例関数xy=1のグラフが回転しています。 水平軸に沿って眺めるとこう見えます。 X軸 exp(X)…exp(-X)と直交 exp(X)(逆位相)…exp(-X)(逆位相)と直交 Y軸 exp(-X)…exp(X)と直交 exp(-X)(逆位相)…exp(X)(逆位相)と直交 自然対数関数y=log(x)と反比例関数xy=1の関係…自然対数関数y=log(x)の中身は自然指数関数y=exp(x)のxy逆転、すなわちx=exp(y)に他なりませんが、xy=1はexp(x)とexp(-x)の直積の結果なので以下の2通りの展開が存在するのです。いずれにせよどちらの展開も対称式の条件は満たしません。 x軸exp(x)、y軸x、z軸exp(-x)の置換 #Inverse_Proportional_Function %matplotlib nbagg import math as m import cmath as c import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D import matplotlib.animation as animation #反比例データ作成 Z=np.linspace(-2,2,41,endpoint = True) X1=np.exp(Z) X2=np.exp(-Z) #グラフ表示 plt.style.use('default') fig = plt.figure() ax = Axes3D(fig) #関数定義 def Inverse_Proportional_Function(n): plt.cla() #反比例曲線描画 ax.plot(X1,Z,X2,color="blue",lw=1) for num in range(len(Z)): ax.plot([0,X1[num]],[0,Z[num]],[X2[num],X2[num]],color="gray",lw=0.5) #軸線追加 ax.plot([-10,10],[0,0],[0,0],color="black",lw=1) ax.plot([0,0],[-10,10],[0,0],color="black",lw=1) ax.plot([0,0],[0,0],[-10,10],color="black",lw=1) #諸元追加 ax.set_ylim([-5,5]) ax.set_xlim([-5,5]) ax.set_zlim([-5,5]) ax.set_title("Unit Cylinder") ax.set_xlabel("exp(X)") ax.set_ylabel("X") ax.set_zlabel("exp(-X)") # グラフを回転 ax.view_init(elev=0, azim=Time_code[n]) Time_code0=np.arange(0,360,6) Time_code=Time_code0[::-1] #Inverse_Proportional_Function(59) #plt.show() #xy=1=14 #-xy=1=44 #exp(X)=29 #-exp(X)=59 ani = animation.FuncAnimation(fig, Inverse_Proportional_Function, interval=50,frames=len(Time_code)) ani.save("IPF203.gif", writer="pillow") 垂直軸に沿って眺めるとx=exp(y)すなわちy=log(x)が回転しています。 水平軸に沿って眺めるとこう見えます。 X軸 xy=1…x=exp(-y)と直交 xy=1(逆位相)…x=exp(-y)(逆位相)と直交 Y軸 x=exp(-y)(逆位相)…1/X(逆位相)と直交 x=exp(-y)…xy=1と直交 x軸x、y軸exp(-x)、z軸exp(x)の置換 #Inverse_Proportional_Function %matplotlib nbagg import math as m import cmath as c import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D import matplotlib.animation as animation #反比例データ作成 Z=np.linspace(-2,2,41,endpoint = True) X1=np.exp(Z) X2=np.exp(-Z) #グラフ表示 plt.style.use('default') fig = plt.figure() ax = Axes3D(fig) #関数定義 def Inverse_Proportional_Function(n): plt.cla() #反比例曲線描画 ax.plot(Z,X2,X1,color="blue",lw=1) for num in range(len(Z)): ax.plot([0,Z[num]],[0,X2[num]],[X1[num],X1[num]],color="gray",lw=0.5) #軸線追加 ax.plot([-10,10],[0,0],[0,0],color="black",lw=1) ax.plot([0,0],[-10,10],[0,0],color="black",lw=1) ax.plot([0,0],[0,0],[-10,10],color="black",lw=1) #諸元追加 ax.set_ylim([-5,5]) ax.set_xlim([-5,5]) ax.set_zlim([-5,5]) ax.set_title("Unit Cylinder") ax.set_xlabel("X") ax.set_ylabel("exp(-X)") ax.set_zlabel("exp(X)") # グラフを回転 ax.view_init(elev=0, azim=Time_code[n]) Time_code0=np.arange(0,360,6) Time_code=Time_code0[::-1] #Inverse_Proportional_Function(59) #plt.show() #xy=1=14 #-xy=1=44 #exp(X)=29 #-exp(X)=59 ani = animation.FuncAnimation(fig, Inverse_Proportional_Function, interval=50,frames=len(Time_code)) ani.save("IPF303.gif", writer="pillow") 垂直軸に沿って眺めるとx=exp(-y)が回転しています。 水平軸に沿って眺めるとこう見えます。 X軸 log(x)…1/xと直交 log(x)(逆位相)…1/X(逆位相)と直交 Y軸 1/X(逆位相)…log(x)(逆位相)と直交 1/X…log(x)と直交 以前からどうして対数尺(Logarithmic Scale)はあるのに指数尺(Exponential scale)がないのか疑問だったのですが、「指数写像(Exponential Map)の定義域はあくまで均等尺(Even Scale)」「これを均等尺に戻す為に対数写像(Logarithmic Map)の定義域は対数尺である必要がある**」が正解で、その由来はかかる座標置換にあった訳です。中高生でも理解出来てる人はちゃんと理解出来てる数理?【Python演算】オイラーの公式と等比数列④「中学生には難しいが高校生なら気付くレベル」? で、指数尺といえば思い出すのが「ヴェーバー‐フェヒナーの法則」。この概念自体は「識閾=1を超えてからの認識展開」が対象ですが、ある意味「識閾=1を超えるまでの認識展開」を扱うニューロンコンピューティング(機械学習の始祖)と補完関係にある?【数理考古学】ヴェーバー‐フェヒナーの法則 もはや対称式の条件は満たしていませんが、全てがZ軸に対して正方向のみの展開となる点に有用性が見受けられます。その一方で間違いなく以下の数理とは深い関係がありそうなのです。 import sympy as sp sp.var('x') expr=sp.log(x) eq1 = sp.Eq(sp.Derivative(expr, x), sp.diff(expr, x)) eq2 = sp.Eq(sp.Integral(1/x, x), sp.integrate(1/x, x)) eq3 = sp.Eq(sp.Integral(expr, x), sp.integrate(expr, x)) eq4 = sp.Eq(sp.Integral(expr, (x, 0, 1)), sp.integrate(expr, (x, 0, 1))) #eq5 = sp.Eq(sp.Integral(expr, (x, 1, sp.oo)), sp.integrate(expr, (x, 1, sp.oo))) sp.init_printing() display(expr) print(sp.latex(expr)) display(eq1) print( sp.latex(eq1)) display(eq2) print( sp.latex(eq2)) display(eq3) print( sp.latex(eq3)) display(eq4) print( sp.latex(eq4)) #display(eq5) #print( sp.latex(eq5)) \frac{d}{d x} \log{\left(x \right)} = \frac{1}{x}\\ \int \frac{1}{x}\, dx = \log{\left(x \right)}\\ \int \log{\left(x \right)}\, dx = x \log{\left(x \right)} - x\\ \int\limits_{0}^{1} \log{\left(x \right)}\, dx = -1\\ \int\limits_{1}^{∞} \log{\left(x \right)}\, dx → 計算終わらず log(x)(x=0→1)の定積分は比較的メジャーな問題で、log(x)を不定積分したxlog(x)-x(x=1)を代数的に解いて-1を算出する模様。【Yahoo知恵袋】logx を0から1で積分することはできるのですか?xlogxの極限,グラフ,積分など ちなみにpythonのnumpyライブラリ(以下np)の場合、自由に底が選べずnp.log(a)(底をeとするaの対数)、np.log2(a)(底を2とするaの対数)、np.log10(a)(底を10とするaの対数)np.log1p(a)(底をeとするa+1の対数)を使い分ける事になる。mathライブラリ(以下m)のm.log(x,a)を使えば底aを自由に指定出来るが、mathライブラリはそもそもリスト処理が出来ない。【NumPy入門 np.log】np.arrayの対数を計算する関数4つを紹介 【python】numpyで任意の底でlog 類別(Classification)による互いに排他的関係にある類(Class)の設定 ところで群同型概念と全準同型概念の関係は以下の様に類(Class)の類別(Classification)概念と深く関わってきます。 商群の定義 整数の加法群の剰余類 ある整数pを,整数m(>1)で割ると,ただ一通りに次のように表現する事ができる。 p=km+q kも整数でこれを整商、qを剰余と呼び「mで割ったときの余り」という点だけに着目してpとqを合同と見做すと「mを法とする」合同式(Congruence Expression)が成立し、例えば10を法とした剰余類G=(0,1,2,3,4,5,6,7,8,9) といった形で整商=剰余の数だけ排他的な類が成立し類別が遂行される(余りが0の類のみが部分集合として成立する)。 類別 p \equiv q \ \ ({\rm mod}.m) ところで同値関係の定義は以下である。 【Python演算処理】環論に立脚した全体像再構築②同値関係の再習 \sim a (反射律)\\ \sim b \ \Longrightarrow \ b \sim a (対称律)\\ \sim b, b \sim c \ \Longrightarrow \ a \sim c (推移律) これが合同式にもそのまま当てはまる。 p \equiv p \ ({\rm mod}.m)(反射律)\\ p \equiv q \ ({\rm mod}.m) \ \Longrightarrow \ q \equiv p \ ({\rm mod}.m)(対称律)\\ p \equiv q, \ q \equiv r \ ({\rm mod}.m) \ \Longrightarrow \ p \equiv r \ ({\rm mod}.m)(推移律) 商群 - Wikipedia 以下の様な二項演算はこの集合全体を商群と呼ばれる群にする。 6を法とする加法群G({\rm mod}.6)=(0,1,2,3,4,5)を考える。\\ その部分群N(0,3)を考える。\\ Gが可換で正規なので剰余類G/Nは以下の3元からなる:\\ G/N = \{aN : a ∈ G\} = \{\{0, 3\}, \{1, 4\}, \{2, 5\}\} = \{0 + N, 1 + N, 2 + N\}.\\ これも群であり、位数3の巡回群と同型である。 剰余類 群Gとその部分群Hを考え、aをGの元とする。Hに属する全ての元にaを左から作用させたものを 左剰余類aH ,右から作用させたものを 右剰余類Haと表記する(わざわざ区別するのは,一般にaとhの積は非可換だからである)。 aH = \{ah|h \in H \} \\ Ha = \{ha|h \in H \} 単位元eの剰余類は,左剰余類であっても右剰余類であってもH自身となるので,H自身も剰余類となり、Hには単位元も含まれる。またGは群なので演算結果が閉じているのでhaも ahも全てGの元であり、従ってどちらもGの部分集合(部分群ではない)と目される。そして同じ類に属する元は全て同値関係 にあると呼ばれる。 eH=He=H  \land e \subset H\\ aH,Ha \subset G 商群 - Wikipedia Nを群Gの正規部分群(Normal Subgroup)とすればその正規性により左剰余類と右剰余類が等しくなり($G/N={ aN=Na : a ∈ G}$)、以下の等式が成立する: 正規部分群 - Wikipedia N\triangleleft G\quad (\iff \forall n\in {N},\,\forall g\in {G},\,gng^{{-1}}\in {N})\\ (aN)(bN) = a(Nb)N = a(bN)N = (ab)NN = (ab)N. この演算は結合的で、単位元Nを持ち、G/N の元$a^N$の逆元はa^{−1N}となる事が確かめられるので群成立条件が満たされる。この群をGのNによる商群(Quotient Group)G/Nと呼ぶ。 例えばn進法(n-ary)ではその一時結合表現に立脚して小数点以上の桁を元、小数点以下の桁を逆元とする事で群を成立させる。【Python描画処理】ベン図と組み合わせ計算と確率演算 実際にこれまでの投稿で扱ってきた内容と突き合わせて見ましょう。 偶関数(Even Function)と奇関数(Odd Function)…奇関数集合は偶関数集合を互いに排他的かつ均等にに存在する元と逆元の2つの類に類別する(次に述べるn進数で、n=2の場合に対応)。偶関数と奇関数の意味,性質などまとめ:高校数学の美しい物語 n進法(n-Ary)…nを法とする剰余類(Cosets)$の直積の線型結合表現(Linear Combination Expression)$l_mn^m+l_{m-1}n^{m-1}…+l_{2}n^2+l_{1}n+l_{0}+l_(-1)n^{-1}+l_{-2}n^{-2}+…$(ただしmは桁数、lは各桁の数字=スカラーで0≦l≦n-1の整数)は、元集合を互いに排他的かつ均等に存在するn×n×n×…個の類に類別する。【Python描画処理】ベン図と組み合わせ計算と確率演算 統計学分野において関数y=f(x)のxに対応する説明変数(Explanatory Variable)とyに対応する目的変数(Response Variable)の関係。離散確率分布(Discrete Probability Distribution)の場合は類が互いに排他的に存在し、連続確率分布(Continuous Probability Distribution)の場合は説明変数xに対応する目的変数y、目的変数yに対する説明変数xの値が一意に定まる。なお関数の形として確率密度関数(PDF=Probability Density Function)と累積分布関数(Cumulative Distribution Function)の2つが存在し、微積分演算によって往復可能である。【Pyrhon演算処理】確率密度空間と累積分布空間①記述統計との狭間【Pyrhon演算処理】確率密度空間と累積分布空間②中心極限定理の可視化 まとめると大体以下の2グループに類別される様です。 0を加法単位元(Additive Identity)、加減算を群演算とする加法群(Additive Group)、1を乗法単位元(Multiplicative Identity)、乗除冪乗算を群演算とする乗法群(Multiplicative Group)(さらに加法群と乗法群を統合すると環概念(Ring Concept)となる)。 集合(Set)$N^0=(0,1,2,3,4,5,6,7,8,9)$を単位元とし、10を法とする剰余算(Remainder)を群演算とした十進群(Decimal Group)(小数点以上に対して小数点以下が逆元として対峙する)、半径(Radius)1、直径(Diameter)2、円周長(Circumferential Length)2πの単位円(Unit Circle)上に元が分布する回転群(Rotation Group)/特殊直交群(Special Orthogonal Group)SO(2)/リー群(Lie Group)$S_1$/一次元トーラス((単数形Torus/複数形Tori))(任意の分岐切断点(Branch Cut Point)を単位元と定め、それより逆時計回りに分布する元と時計回りに分布する逆元を対峙させる)などを代表例とする商群(Quotient Group)。 円筒形座標系(Cylindrical Coordinate System)による加法群(Additive Group)と乗法群(Multiplicative Group)と商群(Quotient Group)の統合 これらの諸概念をとりあえず仮統合してみたのが、これまでの投稿で用いてきた「垂直軸に0を加法単位元とする加法実数群、水平軸に1を加法単位元とする加法実数群を絶対値とする極座標系(Polar Coordinate System)を配した円筒座標系(Cylindrical Coordinate System)」のイメージとなります。この考え方は水平座標軸を半径1の単位円で取った時、その傾きが垂直座標軸の数値、すなわち実数列(Real Sequence)そのものとなるので、何かと都合が良かったのです。 【Python演算処理】環論に立脚した全体像再構築①空環と実数環 空和概念(Empty Sum Concept)+空積概念(Empty Product Concept)=空環(Empty Ring) 加法空群は乗法空群と群同型であり、従って環として統合可能である。 (\emptyset,+) \cong (\emptyset,×) ①空和概念(Empty Sum Concept)/加法空群(Additive Empty Group) $\emptyset+\emptyset+\emptyset+…=\emptyset$ ②空積概念(Empty Product Concept))/乗法空群(Multiplicative Empty Group) $a\emptyset=\emptyset,\frac{\emptyset}{a}=\emptyset$ ③両者の違いは観測限界(Observation Limit)としての無限遠点∞の設定が点か円弧(Circle)/球面(Shere)かに過ぎず、ある種の指数/対数写像によって往復可能と考える。 指数写像(Exponential Map) 対数写像(Logarithmic Map) 加法群と乗法群の環概念への統合 加法実数群$(\mathbb{R},+)$は、すべての正の実数が乗法についてなす群$(\mathbb {R}^+,×)$に、同型写像$f(x)=e^x(x \in \mathbb{R})$によって同型である: (\mathbb {R},+) \cong (\mathbb{R}^{+},×) 考え方としては、乗法単位元1以上無限未満の正の整数aを元、その逆数$\frac{1}{a}$を逆元$a^{-1}$に取り、両者を含む(閉じた演算として包括する)全体集合として実数列$\mathbb{R}$を採択する。 環概念への商群の統合 加法整数群$(\mathbb {Z},+)$は加法実数群$(\mathbb{R},+)$の部分群であり、商群$\frac{\mathbb{R}}{\mathbb{Z}}$は、同型写像$f(x+\mathbb {Z})=e^{2πxi}(x \in \mathbb{R} \land 0 \leqq x \leqq 2π)$によって絶対値1の乗法複素数群$S^1$に同型である: \frac{(\mathbb{R},+)}{(\mathbb{Z},+)} \cong S^1 考え方としては、全ての元が半径1の単位円の円周上に存在するリー群(Lie Group)$S_1$から出発する。ここでその円の周回数(Rap=正の整数)を元a、分割数(Partition)を逆元$a^{-1}$に取れば$aa^{-1}=a^{-1}a=単位元I(1周)$が成立し、リー群$S_1$を全体集合とする群が成立する訳である(ただし実際に周回数をカウントする為には分枝切断点(Branch Cut Point)概念の導入が欠かせない)。 どうやら環概念は指数写像/対数写像概念と不可分の関係にある様です。一見群論の様な抽象代数学には無縁そうな垂直軸(均等尺が振られた実数列が分布するスカラー空間)における乗除算/冪算が水平軸(対数尺が振られた正数のみが分布する極座標空間)では加減算/掛け算に置き換えられたり、垂直軸における「2」が垂直軸における「半径π」に対応するといった具体的特徴が顔を出すのも、おそらくその為なのでしょう。 【数理考古学】常用対数表を使った計算 高校数学からヤコビアンに至るまで 上掲の円筒形座標系イメージをさらに抽象化すると「実数列上の任意の元それぞれを基点(Base Point)と想定する連続極座標系(Continuous Polar Coordinate System)」といったイメージに拡張され得る(偶数系数理と奇数系数理の交互出現とその間隔設定といった具体的特徴はそのまま全て継承されるものと考える)。かかるレールめいた独特の座標系において実数列を直線と解釈して直交する座標軸をどんどん増やすならデカルト座標系(Cartesian Coordinate System)、半径1の単位円と解釈するならリー群$S_2$(二次元トーラス)や$S_3$(四元数)へと発展する。デカルト座標系あるいは直交座標系における基底ベクトルと位置ベクトル【Pyrhon演算処理】同心集合①乗法的同心集合とは?【Python演算処理】パスカルの三角形+虚数=四元数? と、まぁそれなりの形には纏まってきましたが、実用に耐えるモデルとして鍛え上げるにはまだまだテストの繰り返しが必要です。 【連続極座標系】「冪乗関数の極限」問題と「距離関数」概念の導入による解決 そんな感じで以下続報…
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Python3.10 新機能!パターンマッチ構文解説

はじめに Python3.10.0 が2021年10月4日にリリースされました。その中でもパターンマッチ構文は大きな機能追加の一つだったため、この記事で解説したいと思います。 私が運営しているYouTubeチャンネルの動画内でも解説しているのですが、動画をみるのが苦手、テキストで知りたい、という人向けにQiitaでも記事を投稿することにしました! 基本構文 パターンマッチは、あるオブジェクトに対して、どのパターンにマッチしているかを評価して処理を分岐させる構文になります。 matchの後ろに、調べたい対象のオブジェクトを指定して、caseの後ろにパターンを記載します。例えば、ひとつ目のcaseのパターン1に当てはまった場合は、caseの中の処理が実施されます。パターンは色々な記載ができるため、いくつか解説していきます。 base.py match 対象オブジェクト: case パターン1: パターン1がマッチした時の処理 case パターン2: パターン2がマッチした時の処理 (今現在はQiitaがPython3.10に対応してないので、シンタックスハイライトが効いてないですね...) サンプル1 (値の一致) 以下のようなアルゴリズムをパターンマッチ構文で記載します。 xが1の時は「値が1です」と表示 xが2の時は「値が2です」と表示 xが1と2以外の時は「値が1,2以外です」と表示 sample1.py x = 2 # 調べたい変数 match x: case 1: print('値が1です') case 2: print('値が2です') case _: print('値が1,2以外です') 詳細解説 最後のcaseの_はワイルドカードパターンで、全ての値を表すパターンになります。なので、最後の case _:はif文のelseと同じと考えてOKです。 変数は上から順番にパターンとマッチしているかを評価されて、一番初めにマッチしたパターンのcase内を通ります。 C言語やJavaのSwitch文と同じと言えます。 サンプル2 (値の一致2) サンプル1のアルゴリズムを少しだけ変更します。 xが0または1の時は「値が0または1です」と表示 xが2の時は「値が2です」と表示 xが0と1と2以外の時は「値が0, 1,2以外です」と表示 sample2.py x = 2 # 調べたい変数 match x: case 0 | 1: print('値が0または1です') case 2: print('値が2です') case _: print('値が0, 1,2以外です') 詳細解説 複数のパターンを|で繋げることで、どちらかのパターンがマッチする、という書き方ができます。(OR条件) またcaseの後ろのパターンを記載するところに、式を記載することはできません。そのため、以下のようなコードはエラーになります。 error.py match x: case 1 + 1: # エラーになる print('値が2です') サンプル3 (辞書) WebAPIのレスポンスを辞書オブジェクトに変換したシチュエーションを考えてみます。 WebAPIは緯度を取得するもので、北半球の場合はnorth latというkeyに北緯が設定されていて、南半球の場合はsouth latというkeyに南緯が設定されているとします。 このような辞書オブジェクトに対して、以下のようなアルゴリズムをパターンマッチ構文で記載します。 'status': 200という要素と、keyがnorth latの要素を持つ辞書の場合は、「北緯 x 度」と表示 'status': 200という要素と、keyがsouth latの要素を持つ辞書の場合は、「南緯 x 度」と表示 それ以外は「データ取得に失敗しました」と表示 dict_sample.py respons_dict = {'status': 200, 'north lat': 10.938} # 調べる変数 match respons_dict: case {'status': 200, 'north lat': x}: print(f'北緯{x}度') case {'status': 200, 'south lat': x}: print(f'南緯{x}度') case _: print('データ取得に失敗しました') 詳細解説 caseの後の'status': 200の記載で「keyがstatusでvalueが200である要素が存在する辞書」というパターンを表しています。 また、'north lat': xの記載で「keyがnorth latである要素が存在する辞書」 というパターンを表しています。この時、valueの部分をxを指定したことで、notch latに対応するvalueの値がxに代入されます。そのため、caseの中でxを使った北緯{x}度という記載ができます。 (一般的な緯度取得WebAPIなら、南半球の緯度はマイナスで表すのが一般的ですが、あくまで例題として...) サンプル4 (リスト) 座標を表すリストのオブジェクトに対して、以下のようなアルゴリズムをパターンマッチ構文で記載します。 要素が1つの場合は一次元の座標を表していて、「一次元の座標(x)です」と表示させる 要素が2つの場合は二次元の座標を表していて、「二次元の座標(x, y)です」と表示させる 原点の場合は「N次元の原点です」と表示させる それ以外は「想定外のデータです」と表示させる list_sample.py cood_list = [10, -30] # 調べる変数 match cood_list: case [0]: print('一次元の原点です') case [x]: print(f'一次元の座標({x})です') case [0, 0]: print('二次元の原点です') case [x, y]: print(f'二次元の座標({x}, {y})です') case _: print('想定外のデータです') 詳細解説 リストは要素の数ごとにパターンマッチができます。[x]なら、要素が1つのリストと表すことができます。そのため、[0]は「0という要素を1つだけ持つリスト」というパターンを表します。辞書のパターンの説明と同様に、[x]は要素が一つのリストで、その値がxに代入されてcaseの中で使うことができます。 [0, 0]と[x, y]のパターンも要素が2つになっただけで、基本的に同じです。 サンプル5 (ガード) caseの後ろにパターンを記載したとにif 条件を記載することで、「パターンにマッチして、かつifの条件もTrueの場合」にcaseの中の処理を実施させるような書き方ができます。これをガードと言います。 base.py match 対象オブジェクト: case パターン1 if 条件1: パターン1がマッチかつ条件1がTrue時の処理 case パターン2 if 条件2: パターン2がマッチかつ条件2がTrue時の処理 . . サンプル4 (リスト)のアルゴリズムを以下のように変更したものを、ガードを使ったパターンマッチ構文で記載します。 要素が1つでかつ値が0以上の場合は、「一次元の座標(x)です」と表示させる 要素が2つでかつ値が両方0以上の場合は、「二次元の座標(x, y)です」と表示させる それ以外は「想定外のデータです」と表示させる list_sample.py cood_list = [10, -30] # 調べる変数 match cood_list: case [x] if x >= 0: print(f'一次元の座標({x})です') case [x, y] if x >= 0 and y >= 0: print(f'二次元の座標({x}, {y})です') case _: print('想定外のエラーです') 詳細説明 ifの後に書く条件の部分には、パターンマッチの記載で値を代入した変数をそのまま使用することができます。ガードは、両方が満たされている場合にcaseの中が実施されます(AND 条件) サンプル6 (クラス) 対象のオブジェクトが、あるクラスのオブジェクトかどうかを調べるにはクラス名()でパターンマッチができます。 以下のようなアルゴリズムをパターンマッチ構文で記載します。 整数型(intクラスのオブジェクト)の場合は「整数です」と表示 文字列型(strクラスのオブジェクト)の場合は「文字列です」と表示 自作クラスのUserクラスのオブジェクトの場合は「ユーザです」と表示 class_sample.py x = User(name='斎藤') match x: case int(): print('整数です') case str(): print('文字列です') case User(): print('ユーザです') サンプル7 (データクラス) データクラスの場合は、オブジェクトのクラスと、オブジェクトがもつ変数(インスタンス変数) の値もパターンで表すことができます。 データクラスのStudentクラス・Teacherクラスがあったとします。それぞれ名前を格納するnameというインスタンス変数を持っています。Teacherクラスには、is_principalという「校長先生ならTrue / それ以外の先生ならFalse」となるboolのインスタンス変数も持っています。 datacalss_sample.py from dataclasses import dataclass @dataclass class Student: name: str @dataclass class Teacher: name: str is_principal: bool # 校長先生フラグ この時、Emailの宛名を以下のアルゴリズムで表記する場合のパターンマッチ構文を記載します。 生徒の場合「◯◯さんへ」 先生の場合「◯◯先生へ」 校長先生の場合「◯◯校長先生へ」 dataclass_sample.py user = Teacher(name='斎藤', is_principal=False) match user: case Student(): print(f'{user.name}さんへ') case Teacher(is_principal=True): print(f'{user.name}校長先生へ') case Teacher(): print(f'{user.name}先生へ') 詳細説明 Teacher(is_principal=True)でTeacherクラスのインスタンス変数is_principalの値がTrueのオブジェクト、というパターンを表している。 校長先生かそれ以外の先生かを判別するためには、is_principalの値を調べる必要があるため、二つ目のcaseに使用した。 この書き方はデータクラスではない普通のクラスで使用する場合、同値の判定の仕方が異なるため、使用が複雑になる(__eq__をオーバーライドする必要がある)ことに注意。(基本的にデータクラスでのみ、使用するものと思います。) おわり パターンマッチ構文は、まだ他にも書き方がいくつかありますが、よく使いそうなケースをピックアップして記載しました!この記事を読んだ人のお役に立てたら嬉しいです! また、私の運営するYouTubeチャンネルPythonプログラミングVTuberサプーでは、基本的なPythonの構文から最新のPythonの書き方まで、初心者でもわかりやすい動画を色々出しているので、良ければ覗いてみてください!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

kivyMDチュートリアル其の参什漆 Components - NavigationRail篇

ハロー、Qiita。清秋の候、すがすがしい秋晴れの 今日この頃、いかがお過ごしでしょうか。 はいー、先週入れられてなかった時候の挨拶ですが、今週で使ってみました。 合ってますかね、使い方。 先日は地震などがありましたが、みなさんはご無事でしたでしょうか。常日頃、 備蓄などはしないといけないなと感じたくらい、身の危険を感じましたね。と、 いってもいざ事が起きたときは何も動けなかったのですが汗 というわけで、少し話は脱線しましたがKivyMDの時間は相変わらずオープン します。今日は、NavigationRail編となります。 NavigationRail いざ始まるといっても、いつものリンクは飛ばすというのはありますが、今日は 少し重要なこともあるので何点か触れてみます。 2点ほどあるのですが、まずは他のナビゲーションと組み合わせてはいけないという ことですね。他のナビゲーションとしては、先週やったNavigationDrawerともう 1つは以前やったBottomNavigationですね。これらと組み合わせると望ましくない と書かれてあります。 もう1点は、デバイスの種類によって使い方を分ける必要もあるということが書かれて います。具体的にはこちらのリンク箇所になりますね。 この節の最下層である、「Responsive patterns」がまさに該当するところなの ですが、この点にも注意が必要です。まずスマホタイプのデバイスでは、Navigati- onDrawerかもしくはBottomNavigationを推奨しているところが注目ポイントです。 タブレットタイプはNavigationRailもしくはmodalタイプのNavigationDrawer、 デスクトップタイプはメニューバーが閉じていないNavigationDrawerという風に それぞれ分けて作った方がよいよと推奨されていることも注意が必要そうです。 まぁ、要点としては今回のNavigationRailはタブレット向きということが分かり ますね。# 個人的にはデスクトップタイプも適しているかなぁとは思いますが ということなので、今日はタブレットサイズを意識して結果の方を映していきたい と思っております。 で、さらにマニュアルの方では以下のように概要が書かれています。 Navigation rails provide ergonomic movement between primary destinations in apps. ergonomicは翻訳を依頼しても「人間工学的に」と結果が返されましたが、その 可能性は多いに高いと思います。他の選択肢としては、生物工学とありますがそれは ねーだろーというのが個人的見解です。これも個人的興味ですが、この分野はすごく 興味があるところです。また、テーマを取り上げてみようかな。 Usage 少し前置きが長くなりましたが、使用方法についてさっそく入っていきます。 MDNavigationRail: MDNavigationRailItem: MDNavigationRailItem: MDNavigationRailItem: 特に難しいということはなさそうですね。実は言うと、この形は初出ではありません。 もう分かっているよという方もいらっしゃるかもしれませんが、そうです、ImageList 篇でやりましたね。全然そんなこと知らないよという方は以下もしくはマニュアルをご覧 頂ければ。 使い方が分かったところで、さっそく動かしていきましょう。下記のコードはマニュアルから ほとんど変更はありません。 xxxvii/navigation_rail.py from kivy.factory import Factory from kivy.lang import Builder from kivymd.app import MDApp KV = ''' #:import get_color_from_hex kivy.utils.get_color_from_hex <MyTile@SmartTileWithStar> size_hint_y: None height: "240dp" MDBoxLayout: orientation: "vertical" MDToolbar: title: "MDNavigationRail" md_bg_color: rail.md_bg_color MDBoxLayout: MDNavigationRail: id: rail md_bg_color: get_color_from_hex("#344954") color_normal: get_color_from_hex("#718089") color_active: get_color_from_hex("#f3ab44") MDNavigationRailItem: icon: "language-cpp" text: "C++" MDNavigationRailItem: icon: "language-python" text: "Python" MDNavigationRailItem: icon: "language-swift" text: "Swift" MDBoxLayout: padding: "24dp" ScrollView: MDList: id: box cols: 3 spacing: "12dp" ''' class Test(MDApp): def build(self): return Builder.load_string(KV) def on_start(self): for i in range(9): tile = Factory.MyTile(source="好きな画像を入れてみるとおもしろいよ!") tile.stars = 5 self.root.ids.box.add_widget(tile) 全てコードを載っけてみると、なにやら難しそう...と思われる方がいらっしゃる かもしれませんが、これまでKivyMDのコードをいっぱい見てきた方はなんだか変わ ったことねーなと思われるかもしれません。カスタムレイアウトのところなんかは、 まさにImageList篇でやったところですしね。 といっても慣れてない方はなんのこっちゃとなりますので、前提知識となるリンクを 載っけておきます。これらを見てから、こちらに戻ると見る景色が変わってくるかと 思われます。 まぁ、これらが分かりにくいんだよ!という方はマニュアルを見てもらえればと思い ます。あと、NavigationDrawer篇を入れている理由としては、レイアウトの実装 する形が似ているからになりますね。メインコンテンツとメニューバーらしきものを 分けているということは共通するところだと考えています。 今回新出のプロパティとかはAPIのところで触れますのでご安心を。あとは漏れている ところですが、MyTileをFactoryしている画像などは好きなものを入れてあげてくだ さい。詳しく仕様を見ているわけではありませんが、よく使われている拡張子はほとんど 対応しているはずです。 結果 ということで、サクサクと触れ込みは終わりましたが、論より証拠ということで 実行結果の方に移りたいと思います。特に動きとかは変わったことないので、画像 キャプチャでお送りします。 動作自体も問題はなさそうでヨシ!という感じですね。今回使った画像は前回同様、以下 サイトから拝借しました。 メニューバーらしきものと全然関わりがないですが、それぞれの言語で案件を募集して いる猫を探すと、このような画面になりそうですね(意味不明)。 Extend Usage 少しこのまま終わるのは寂しい気もしますので、もう少し触ってみます。といっても マニュアルのものからそれほど大きくはハズレはしませんが。。 どんなことをやったかを簡単に説明しますと、もう本当に簡単に言えばAPIでコードなり キャプチャがあるところを実装してみただけになります。まぁそれだけっちゃそれだけ なのですが、思わぬ収穫もあったりで。。 コードについても全て載せても良いのですが、ほとんどベースとしてはUsageのところで やったものなので差分なりを載せておきます。 xxxvii/extend_navigation_rail.py (略) MDToolbar: title: "MDNavigationRail" md_bg_color: rail.md_bg_color left_action_items: [["menu", lambda x: app.rail_open()]] MDBoxLayout: MDNavigationRail: id: rail # item text selected visible: "Selected" # menu( item) color md_bg_color: get_color_from_hex("#407294") color_normal: get_color_from_hex("#e6e6fa") color_active: get_color_from_hex("#e2d0ca") # hover use_hover_behavior: True hover_bg: 1, 1, 1, .2 # rail open/close use_resizeable: True # title use_title: True icon_title: "./genba_neko.png" text_title: "[b][color=#ffffff]Example[/color][/b]" # action button use_action_button: True action_text_button: "COMPOSE" on_action_button: print(args) (略) def rail_open(self): if self.root.ids.rail.rail_state == "open": self.root.ids.rail.rail_state = "close" else: self.root.ids.rail.rail_state = "open" (略) はい、省略が多いですが、上記のようになっております。まずkv側とクラス側ある、 rail_openコールバックメソッドですが、これはツールバーのハンバーガーメニュー で開閉されるメニューバーの実装となっています。これ以上長ければこのままでも よさそうですが、単にif-elseであればkv側でまとめてもよさそうですね。 次のまたkv側に戻り、MDNavigationRailで定義しているプロパティですが、コメ ントにも書いてる通りAPIで書かれているものを使用しています。詳細はAPIの方に お譲りしますというか私が引き受けるんですけどね。簡単に言えば、先ほどはメニュ ーバーがなかったりアカウント画像がなかったりしていましたが、このコードではそれ らが追加されています。 結果 はい、まぁうだうだ言っても、実行結果を見るに越したことはないので先に見てしまい ましょう。 今回も画像ギャラリーということで、マスコットキャラクター(?)のSayaさんに登場 いただきました!もうKivyMDというとこの方しかいませんね!(勝手な決めつけ) 動かしたものも特に問題はないですね、って言いたいところですが問題ありますね。 アクションボタン(黄色いプラスボタン)のテキストなんかは見えていないことが わかっています。あとは、hoverの振る舞いなんかも適用されていないことも 分かりました。その他は特に問題なしだったかと。 すみません、動画だと動きが分かりやすいというのはあるんですけど、なぜか制限 が掛かっちゃってアップができませんでした。。一旦は画像の方でお許しを。 テーマに関しては少し変えてみたというのはありますが、色のことについては ど素人なので、以下を参考にして決めてみました。 API - kivymd.uix.navigationrail.navigationrail ということで、少し触れ込みを端折ったプロパティなどもあるので、もうこちらに入り ます。 class kivymd.uix.navigationrail.navigationrail.MDNavigationRailItem(**kwargs) アイテムとあるので、こちらはメニューアイテムらしきところでしたね。Pythonだとか 設定したやつになります。 icon Icon item. icon is an StringProperty and defaults to ‘checkbox-blank’. text Text item. text is an StringProperty and defaults to ‘’. これらが今回使用したものになります。それぞれデフォルトで持つものが変わりますね。 set_width(self, interval: Union[int, float]) Sets the size of the menu item. 横幅は変えられないのかなと思っていましたが、どうやら変えれそうですね。でも、 試すまではできませんでした汗 どうなるか試してもらい、コメント頂けると嬉しい です。 class kivymd.uix.navigationrail.navigationrail.MDNavigationRail(**kwargs) use_hover_behavior Whether to use the HoverBehavior effect for menu items. hover_bg The background color for the menu item. Used when use_hover_behavior parameter is True. 動かなかったやつですね。次回のバージョンに期待です。Todoが重なっていくよぅ。。 use_resizeable Allows you to change the width of the rail (open/close). use_resizeable is an BooleanProperty and defaults to False. railを開閉するためにはこちらを有効化する必要があるようです。ちなみにExtendの コードはここから持ち出しました。まぁUsageからそれほど変化はありませんが。。 use_title Whether to use an additional panel at the top of the rail. use_title is an BooleanProperty and defaults to False. icon_title Icon (name or path to png file) for NavigationRailTitle class. icon_title is an StringProperty and defaults to ‘menu’. text_title Text title for NavigationRailTitle class. text_title is an StringProperty and defaults to ‘Rail’. タイトルに関するものですね。こちらはちゃんと反映がされました。先述したアカウント 画像はここのアイコン(icon_title)を指し示していました。 use_action_button Should MDFloatingActionButton button be used. use_action_button is an BooleanProperty and defaults to False. action_icon_button Icon of use_action_button. action_icon_button is an StringProperty and defaults to ‘plus’. action_text_button Text of use_action_button. action_text_button is an StringProperty and defaults to ‘’. アクションボタンにまつわるものです。残念ながら、action_text_buttonは有効化 されませんでした。 color_normal Color normal of item menu. color_normal is an ColorProperty and defaults to None. color_active Color active of item menu. color_active is an ColorProperty and defaults to None. ここは分かりにくいところですが、単にメニューアイテムを押す前後の色指定になり ますね。normal/active(選択されていない/されている)という風に分けられてい ます。これだと、説明いらないか。 visible Item label visible type. Available options are: ‘Selected’, ‘Persistent’, ‘Unlabeled’. visible is an OptionProperty and defaults to ‘Persistent’. こちらは、説明通りということになるでしょうか。Extendでは、‘Selected’に設定 して選択したときにラベルを表示していました。 rail_state Closed or open rails. rail_state is a OptionProperty and defaults to ‘close’. コールバックメソッドと一緒に使われるものですね。単にkv側だけでも済ませられ そうなところです(2回目)。 まとめ さて、いかがだったでしょうか。 先週のナビゲーションドローワーと言い、使いこなすのは難しいですが慣れてくると 強力なコンポーネントとなることは間違いないでしょう。 使用するデバイスはタブレットタイプと若干制限が強いですが、専用アプリを作ると 決めてしまえばなかなか心強いのではないでしょうか。頑張ればNetFlixなんかの クローンも作れそうな勢いです。 正直、メニューアイテムの選択でどうやってコンテンツの使い分けをするのだろう という疑問はあるのですが、今後の課題となりそうです。余裕があれば、実現できる よう取り組みます。そのときが来たら、頑張ってみます。 ということで今週はここまでで。来週はPickers篇に入ろうかと思っていましたが、 コンポーネンツの構成が変わったり、前回触れられていないところは0.104.2でも 動かないというように時期尚早な状況です。一旦バージョンアップ後ですね、動かす のは。 なので、1つ飛ばしてSelection篇になりますね。ということで来週もお楽しみにー。 それでは、ごきげんよう。 参照 Components » NavigationRail https://kivymd.readthedocs.io/en/latest/components/navigationrail/ DeepL 翻訳ツール https://www.deepl.com/ja/translator 「そろそろ時間だから行こっか」のフリー素材 https://www.pakutaso.com/20160452095post-7493.html
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【断言】エンジニアを辞めたい人へ。後悔する前にすべきことを経験者が解説

SEやITエンジニアに限らず、社会人は人生のほとんどの時間を仕事に費やしています。 それ故、仕事が辛いとQOLをゴリゴリと下がってしまうことは言うまでもないでしょう。 僕自身も新卒入社した一社目の会社は仕事が肌に合わずわずか3ヶ月で退職するという動きをブチかましたことがあります。 なので仕事が辛い人の気持ちはとてもよくわかります。 特にエンジニアは他の職業よりも技術に対する好奇心が要求されます。 その為仕事へのモチベが下がってしまうことは大問題ですよね。 そこでこの記事では、毎日の仕事が辛いエンジニアに向けて、 エンジニアが仕事を辛いと感じる理由 後悔する前に試すべきこと を僕なりに書いていこうと思います。 【辛い】 ITエンジニア業務を辞めたくなる理由 上司・同僚に不満がある エンジニアが辞めたくなる原因で一番多いのは人間関係ではないでしょうか。 (これに関しては他の職業と同じです。) 優しい人が多めだと言われるエンジニア界隈でも、単純に上司や先輩の人格が終わっているケースは普通にあります。 「こんなことも知らないの?マジ?」的な態度を出してくる人って結構多いですよね。 またエンジニア特有の辛みとして、 プロジェクト設計にそもそも無理があるのに、開発遅延の責任を現場のエンジニアに押し付けられた PMに技術理解がなさ過ぎて技術者側の苦労が伝わっていない といった物もあります。 また、スタートアップだと「創業者(非エンジニア)が無責任にピボット(方向転換)を繰り返した結果、書いたコードが無駄になりまくって非常に辛い」といった声もよく聞きます。 例え普段は悪い人ではなかったとしても、エンジニアの技術に対するリスペクトが無い上司と一緒に働きたくはないですよね。 職場の技術レベルに不満がある エンジニアが辞めたくなる理由その2として職場の技術レベルが挙げられます。 まず職場の技術レベルが高すぎてついていけないというケース。 エンジニアは専門職なので、新入りがキャッチアップするにはそれなりの時間が必要になります。 特に、案件ごとに使用する言語やフレームワーク、インフラ周りの技術資産などはバラつきがあるのが普通です。 覚えること多スギイ!となるのはもはやエンジニアの宿命だと言えるでしょう。 逆に職場の技術レベルが低すぎて会社を辞めたいというケースもよくあります。 できるエンジニアなるほどモダンな技術をどんどん覚えていきたいという本能があります。 その為、未だに「git? Docker? なにそれ?」状態な現場で働き続けるのはかなり不安感があるはずです。 特にWeb系のフロントエンドは新しい技術が次々と出てくるので、いつまでもレガシー環境で働き続けていると市場価値も全く上がっていきません。 給与・労働時間に不満がある 給与や労働時間などの待遇に不満がある場合もエンジニアが辞めたくなりがちです。 エンジニアは比較的給料が良いとされています。 が、 ・ブラックSESに入社してしまった ・派遣元に中抜きされすぎている ・スタートアップに入ったはいいもののストックオプションや生株が全然貰えていない といった不満はよく聞くところです。 また労働時間という点では 「営業がめちゃくちゃな条件で案件を取ってくるせいで、納期直前期がほとんど終電帰りになってしまう」という声を良く聞きます(開発チーム以外は20時頃全員帰宅)。 辞めた結果後悔する人のパターン 辞めたくなった勢いで仕事を辞められればこれほど楽なことはありませんね。 しかし現実にはノリで仕事辞めてしまうと後悔することになります(自省を込めて)。 後悔するパターンは色々とあるのですが、ここでは一番ありがちなパターンを挙げておきます。 ズバリ「年収がダウンしてしまうパターン」です。 「それまでは600万円程度の年収があったのに、転職によって530万円まで下がってしまった」といった人の話を時々聞くと思います。 実際に経験すると分かりますが、例えお金に興味がない人でも年収ダウンは何か心にひっかかるものがあるんですよね。 単純に金銭的な問題というよりも、「社会が自分に下している評価が下がってしまった」といったプライドの問題が大きい気がします。 転職先の人間関係を100%理解することは出来ませんが、金銭的な待遇面であれば事前に把握することができます。 仕事辞める時はとにかく「収入がどう変化するのか」にだけ注意を向けて欲しいというのが僕からのアドバイスです。 エンジニアを辞める前にすべきこと さて、ここからはエンジニアを辞める前にすべきことについて書いていきます。 会社が合わないのかエンジニアが合わないのかハッキリさせる まず最初にすべきなのは、単に今の会社が自分に合わないのか、それともエンジニアという職業自体が合わないのかをはっきりさせるということです。 まずはここを理解していないと先に進むことはできません。 人間関係が嫌で仕事辞めたい人は基本的に会社があっていないと判断すればOKです。 会社を変えればいいだけの話であり、エンジニアという職業自体を変更する必要はないですよね。 もっと別の技術環境に身を置きたいと感じている場合もエンジニア自体を辞める必要はありません。 会社に待遇面の不満を感じている場合も同様です。 では、「エンジニアという職種自体が合わないケース」というのは一体何なんだという話ですね。 これは技術そのものに対して完全に興味がなくなっている状態です。 通常の職種であれば、そもそも仕事への興味がない人も大勢居ますがエンジニアにとっては死活問題です。 いわゆる「エンジニア35歳定年説」も好奇心の枯渇を根拠にした説明を多く見かけますよね。 「技術に一切の興味がない」という状況に陥ったら、 現場のエンジニアを辞めてPM的な立ち位置に行く 全くの別業種に転職する ことを検討する必要が出てきます。 エンジニアというのは新しい技術に興味を持てていないと面白くないですし、スキルも停滞しますからね。 「実際に辞めたらどうなるか」を把握する 実際に辞める前にもう一つやって欲しいのは「ここで会社を辞めたらどうなるか」を熟知しておくことです。 一番手っ取り早いのは、辞めた後に実際に自分が応募可能な求人案件を見てみることです。 エンジニアを続ける場合、実際に転職するしないは置いておいてもエージェントや転職サイトを使えば、次の仕事がどの程度の待遇なのかを8割方知ることが出来ます。 これによって 今の会社を辞めたら年収が上がるのか下がるのか 市場ではどんな技術を持ったエンジニアが求められているのか 労働時間やワークライフバランス面での待遇はどう変化するのか といったことをほぼ正確に把握することができます。 (また、実際に企業との面談まで進めば、その会社の人間関係が自分の会社のそれより良好なのかもなんとなく分かるものです。) ちなみに僕の場合だと、新卒で入った会社を速攻で辞めた後、フリーランス向けの案件をいくつか見せてもらいました。 その結果、世の中の開発案件を受ければ、それまでいた会社よりも金銭的な待遇がかなり良くなることに気付きました。 ぶっちゃけて言うと月の手取り的にはそれまでの2倍以上の案件が結構ありました。 まずは、「自分がここで会社を辞めたとして、状況がどう代わりうるのか」を知ってから見の振り方を考えましょう。 もっと良い環境に行けることが間違いないのであれば、迷わず辞めれば良いです。 逆に今より良い条件の仕事が無いのであれば今の職場で耐えるのも選択肢に浮上してきます。 参考までに定番の転職エージェントを条件別にまとめておきます。 無料で使えて、一定上の評価があるもののみを選びました。 複数利用も可なので、ぜひ活用してください。 特徴 アクシス 外資やアクセンチュアなど高年収を狙いたい人向け。ITコンサル多め。 レバテックキャリア エンジニアの定番転職エージェント。求人数7000超&年収アップ率7割超。 エンジニアルート フリーランスエンジニア向けIT系案件情報サイト。実績12年以上の老舗。 テックゲート リモート、週2回からなど、自由な案件探しにオススメ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Python 基礎

目次 基礎文法 演算子 制御文 関数 モジュールとクラス 1. 基礎文法 基本的なルール 文末のセミコロンは不要(つけることもできる) {}で処理をまとめるのではなく、インデントで処理をまとめる メンバアクセスはドットで行う 処理を複数行にまたぐ場合、改行にはバックスラッシュを使用する 変数 「変数名 = 値」で宣言できる 「変数名:型名 = 値」で型を明示して変数宣言できる ※ただし、実行時に指定型以外の値を入れても、実行時エラーとはならないので注意 型指定はあくまで制作側へのヒント。 # 型指定なし val = 10 # 型指定あり val:str = 'あいうえお' コメント 単一行は「#」 複数行のコメント機能はないが、3重のシングルクォートorダブルクォートで囲むことで、複数行の文字列扱いにできる # 単一行コメント ''' コメント1 コメント2 コメント3 ''' データ型 データ型 説明 例 補足 int 整数 1 float 浮動小数点 2.5 complex 複素数 1 + 1j 数字にjをつけると複素数リテラルになる bool 真偽値 True, False Trueは1, Falseは0扱い str 文字列 'abc', "def", '''ghi''', """jkl""" 3重のクォートを使うと複数行にまたがる文字列を定義できる list リスト型 ['hoge', 1, True] dict 辞書型 {'key1': 'value1', 'key2': 'value2'} tuple タプル型 ('hoge', 1, True) 要素の変更ができない set 集合型 set(['hoge', 1, True]), set('hogehoge') リスト型の値か、文字列を受け取り、重複した値を抜いて返す、文字列の場合は1文字ずつバラす None 何もなし None 2. 演算子 算術演算子 演算子 説明 例 + 加算 1 + 2 # 3 - 減算 1- - 5 # 5 * 乗算 10 * 2 # 20 ** 累乗 2 ** 3 # 8 / 除算 10 / 3 # 3.3333333 // 切り捨て除算 10 // 3 # 3 % 剰余 10 % 3 # 1 比較演算子 演算子 説明 == 等しい != 等しくない > より大きい >= 以上 < より小さい <= 以下 is 同一オブジェクト is not 異なるオブジェクト in a in b aがbに含まれる not in a not in b aがbに含まれない 論理演算子 演算子 説明 and a and b aとbが共に真の場合に真 or a or b aかbの少なくとも1つが真の場合に真 not not a aが真の時に偽、偽の時に真 ビット演算子 演算子 説明 & 論理積 | 論理和 ^ 排他的論理和 << 左シフト >> 右シフト - ビット反転 三項演算子 (条件が真の時の値) if (条件) else (条件が偽の時の値) で書く val = 1 print('OK' if val > 0 else 'NG') # OK 文字列演算 演算子 説明 例 + 文字列の連結 'abc' + 'def' # abcdef * 文字列を繰り返し結合 'ab' * 3 # ababab [n] n番目の文字を切り出す 'abcdef'[2] # c [n:m] n~m-1番目の文字を切り出す 'abcdef'[2:4] # cd [n:] n番目以降の文字を切り出す 'abcdef'[2:] # cdef [:m] m-1番目までの文字を切り出す 'abcdef'[:5] # abcde [n:m :s] n~m-1番目の文字をs個飛ばしで切り出す 'abcdef'[2:5:2] # ce 3. 制御文 条件分岐 if...elif...else文(他言語で言うifelse文) 他言語で言うswitch文はないが、inを使うことで代用できる 範囲指定もできる x = 10 # if...elif...else文 if x == 5: ... elif x == 10: ... else: ... # 範囲指定 if 1 < x < 10: ... # switch文ライクな書き方 # inを使う if x == 5: ... elif x in (2,3): ... elif x in (3,4): ... else: ... # Noneの比較には、isやis notを使う data = None if data is None: ... 繰り返し文 pythonのfor文は他言語のforeach文に相当 while文はあるが、do~while文はない rangeを組み合わせることで、他言語のfor文が実現できる # while文 val = 1 while val < 3: print(val) val += 1 # for文とrange関数 for i in range(2) print(i) # 0, 1 # for文と文字列(リスト, 辞書など) for c in 'hoge' print(c) # h,o,g,e continue, break # continue # xが3の時continueする for x in range(5): if x == 3: continue print(x) # break # xが3の時breakする for x in range(5): if x == 3: break print(x) 4. 関数 「def」を使って定義する # 普通のやつ def fnc(a, b): return a + b # デフォルト値 def fnc(a, b=1): return a + b # 可変長引数 # *をつける def fnc(a, b, *args): print(a, b, args) # キーワード付きの可変長引数 # **をつける def fnc(a, b, **args): print(a, b, args) # 引数、返り値の型指定 # ただし、処理を動かすとエラーは起きないので注意 def fnc(a:int, b:int) -> int: return a + b 例外処理 「try ~ except ~ else ~ finally」で表せる 意図的に例外を起こしたい場合は、「raise」を使う try: ... # 例外発生時の処理 except Exception as e: ... # 例外が発生しなかった場合の処理 else: ... # 例外の有無関係なく、必ず走る処理 finally ... pass文 何もしないことを明示する for i in range(10) if(i == 1): print(i) else: pass # 何もしない def hoge(): pass 5. モジュールとクラス モジュールのインポート 同階層のインポート # sub.py(インポートされる側) def subFnc(): ... # インポートする側 # sub.pyをインポートする import sub # 拡張子は付けない sub.subFnc() # sub.pyのsubFncをインポートする from sub import subFnc subFnc() 他階層に一つだけ存在するファイルのインポート # sub.py(インポートされる側) def subFnc(): ... # インポートする側 # subdirフォルダのsub.pyをインポートする from subdir import sub sub.subFnc() # 次のような書き方でもOK import subdir.sub subidir.sub.subFnc() 他階層に複数存在するファイルのインポート # サブフォルダに複数のファイルがある場合は # __init__.pyを用意し、パッケージ化する必要がある # __init.py from . import sub1 from . import sub2 # sub1.py def subFnc(): ... # sub2.py def subFnc(): ... # main.py(インポートする側) import subdir subdir.sub1.subFnc() subdir.sub2.subFnc() 標準ライブラリのインポート import calendar print(calendar.month(1999,12) 外部ライブラリのインポート PyPI(https://pypi.python.org/pypi)というサービスからインストールする方法が一般的 # インストール $ pip install [モジュール名] # アンインストール $ pip uninstall [モジュール名] # 詳細確認 $ pip show [モジュール名] # インストール済みモジュールの確認 pip list # Macの場合は「pip」を「pip3」に読み替える クラス 基本的なクラスの宣言 インスタンスメソッドの第一引数には、必ず自分自身を示すselfを定義する class Member: # クラス変数 LANG = 'JP' # コンストラクタ # __init__で宣言できる def __init__(self): self.name = '' # getter def getName(self): return self.name # setter def setName(self, name): self.name = name taro = Member() taro.setName('太郎') print(taro.getName()) # 太郎 print(Member.LANG) # JP クラスの継承 「class 子クラス名(親クラス名):」で定義できる # 親クラス class Parent: def __init__(self, a, b): self.a = a self.b = b def hello(self): print("hello"  + self.a) # 子クラス # 親クラスをインポート from dir1 import Parent # 親クラスを継承 class Child(Parent): # 親クラスのオーバーライド(一部上書き) def __init__(self, a, b, c): super().__init__(a, b) self.c = c # 親クラスのオーバーライド(全て上書き) def hello(self): print(self.b) # 子クラスで新たに定義したメソッド def bye(self): print("good bye" + self.c) クラスメソッド インスタンス化しなくても使用できるメソッド メソッドの一番上に@classmethodと付けることで定義できる 第一引数にはそのクラス自身をclsという名前で指定する(これにより、クラスのメンバにアクセスできる) class Coordinate: """ 座標クラス """ def __init__(self): """ 初期化 """ self.x = 0 self.y = 0 def show_coordinate(self): """ 座標を表示する """ print(self.x, self.y) @classmethod def create_new_cood(cls, x, y): """ Coodinateオブジェクトを生成して返す """ new_cood = cls() # Coodinateオブジェクトを生成 new_cood.x = x # 座標を設定 new_cood.y = y # 座標を設定 return new_cood cood = Coordinate() # インスタンスを生成する cood2 = cood.create_new_cood(10, 20) cood2.show_coordinate() スタティックメソッド インスタンス化してなくても使用できるメソッド メソッドの一番上に@staticmethodと付けることで定義できる クラスのメンバにはアクセスできない import math class Coordinate: """ 座標クラス """ def __init__(self): """ 初期化 """ self.x = 0 self.y = 0 def show_coordinate(self): """ 座標を表示する """ print(self.x, self.y) @staticmethod def calc_dist(cood1, cood2): """ 座標間の距離を計算します """ x = cood1.x - cood2.x y = cood1.y - cood2.y return math.sqrt((math.pow(x, 2) + math.pow(y, 2))) cood1 = Coordinate() # インスタンスを生成する cood1.x, cood1.y = 100, 100 cood2 = Coordinate() # インスタンスを生成する cood2.x, cood2.y = 200, 200 dist = Coordinate.calc_dist(cood1, cood2) # スタティックメソッドを実行 print(dist) クロージャ 関数のローカル変数を参照するような関数 def counter(): count = 0 # クロージャ # nonlocalをつけると、一つ外側のスコープに属する変数への代入が可能になる def inner_counter(): nonlocal count count += 1 return count return inner_count cnt = counter() print(cnt()) # 1 print(cnt()) # 2 print(cnt()) # 3
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VSCode での Python 開発環境ことはじめ(Chromebook版)

概要 VSCode で新規に Python 開発するときに せっかくなので Chromebook で試してみます はじめに Python は気軽に手を出せて、かつ実用性も申し分ないのでお気に入りですが、大規模開発に耐えるプロジェクト設計やテストコード開発のやり方については悩ましい部分もあるのではないでしょうか。 ということで、自分的定番構成を紹介してみたいと思います。 Python のアピールポイント numpy 使って大規模な数値演算をするわけでもなく、AWS Lambda の軽量コードを書くくらいの私ですが、下記のようなメリットを感じて利用しております。 学習コストが低い つまり人材採用コストが低い: プログラマー目線だとデメリットにしか映らないでしょうが管理目線だとよいでしょ? (ただし深淵を極めるとそれなりに深いので、難しいのが好きなプログラマーさんも悪くないのでは?) 環境依存しづらい インタプリタ言語だから OS に依存したりしない 例えば Win/Mac の派閥が割れているとして、混合編成でもかなり行ける なんなら 今回は Chromebook で開発 もっと言うと、paiza とかならブラウザでお試し実行できる 2.7 vs 3.x 互換問題とか既に過去のもの 2.7 を新規採用しなければいいので、少なくとも今後の開発には関係ない ユニットテストもだいぶ書きやすくなった(個人比) コードカバレッジ調査や性能計測もお手のもの (このあたりは過去の失敗からノウハウを得た部分が大きい) VisualStudio Code と相性がいい Microsoft 純正の Python エクステンションが大抵のことはやってくれる 環境構築 Windows/Mac でも構わないのですが、せっかくなので (流行り始めの?)Chromebook を使ってみます。 Chromebook の環境構築については参考文献がたくさんあるので、参考にして構築します。 Linux 有効化 Chromebook 上では Debian 10 ベースの Linux を起動することができ、開発環境は基本的に Linux 上へ構築します。 さっそく有効化しましょう。 設定画面を開きます。 デベロッパー > Linux 開発環境 から有効化します。 (今回は有効化済み) (有効化すると、Linuxアプリがメニューに現れます) 続いて、Linux 環境に VSCode を導入します。 (先ほどもう入っていましたが、入れ方のおさらい) 公式に沿って導入すれば大丈夫です。 Debian なので .deb を選びましょう。 導入後は、拡張機能から日本語パックを探し、日本語化しておきます。 (まあ英語のままでも全然大丈夫そうですが) 続いて、Microsoft 公式の Python 拡張機能も導入しておきます。 これでひとまず最初の設定は完了です。 ディレクトリ構成 VSCode を Linux アプリとして導入したので、Chromebook 側における「Linux ファイル」の中が見える仕組みです。 このディレクトリに実際のプロジェクトファイルを作っていきましょう。 プロジェクト構築 この先は、Chromebook 以外の OS でも共通で使えます。 (※ VSCode なら) ディレクトリ構成 新規の Python プロジェクトを作るとして、ひとまず下記のようなテンプレートでディレクトリを切ると快適です。 <project_folder> ┗ src : メインアプリケーションの プロジェクトルート (デプロイ時にはこのディレクトリだけアップします) ┗ application : アプリ本体用 ┗ common : 共通ロジック(エラー処理とか)用 ┗ service : (DBなどのリソースアクセス含む)処理サービス用 ┗ (※この辺はプロジェクトの規模や、チームが信じる設計思想によって自由に足してよいです) ┗ __init__.py : Python プロジェクトのモジュール認識ファイル(各ディレクトリに必要. モジュールの初期化処理など書くこともできるが、空でも可。) ┗ requirements.txt : メインソース用のライブラリ requirements。デプロイコード(AWS SAM とか)に読ませる用です ┗ tests : pytest テストファイル ┗ (※次章へ) ┗ .vscode : VS Code 設定ファイル ┗ settings.json ┗ pytest.ini : pytestの設定ファイル ┗ .env : VS Code に src の プロジェクトルートを伝える(開発環境用) ┗ .gitignore : 作業ディレクトリを git から除外する ┗ README.md : 取り扱い説明 ┗ requirements.txt : 開発環境用の requirements (テスト用ライブラリなど入れてよい) テストコードディレクトリ Python 用のテストスイートはいろいろありますが、今回は pytest を使用します。 自由度と手軽さのトレードオフを考えて、バランスの良さから選定しています。 <project_folder> ┗ tests : pytest テストファイル ┗ __init__.py : Python プロジェクトのモジュール認識ファイル(functions と同様に各ディレクトリへ配置する) ┗ conftest.py : テスト全体の初期処理を定義するファイル。ここでメインソースに path を通す。 ┗ application ┗ __init__.py ┗ conftest.py : テストの前後処理(fixture) を定義するファイル。(同一ディレクトリ内の全ファイルで共用する。) ┗ test_xxx.py : テストファイル本体(pytest に認識させるため、ファイルの接頭辞は「test」である必要がある。原則として src の 1ファイルに付き1つ作成する。) ┗ test_yyy.py ┗ common ┗ __init__.py ┗ conftest.py ┗ test_xxx.py ┗ test_yyy.py ┗ service ┗ __init__.py ┗ conftest.py ┗ test_xxx.py ┗ test_yyy.py (※もちろん、src のディレクトリ構成に合わせて好きに作ってください) 設定ファイル VSCode 上で一通りの作業が行えるよう、設定をチューンしていきます。 VSCode の設定 settings.json に Pytest 拡張を有効化するための設定を書いておきます。 Microsoft 公式の Python Extension が、テストを管理してくれるようになります。 settings.json { "python.testing.pytestEnabled": true } プロジェクト設定 メインソースのルートを src ディレクトリに設定します。 ルートディレクトリではなく、あえて src に変えると、 メリット テストコードや開発用の余計なファイルを、デプロイ時にアップロード対象から除外できる 開発環境用と メインソース用で requirements.txt を別にできる デメリット 放っておくと import とかが上手くいかない というところで、本番ソースが汚れにくいのがうれしいですが、import 周りのセットなど工夫が要ります。 まず、メインソースは 「.env」 内で定義するだけで切り替わります。 .env PYTHONPATH=src これだけだと pytest がインポート失敗で落ちるので、tests の conftest に path を追加します。 tests/conftest.py import sys import os sys.path.append(os.path.abspath(os.path.dirname(os.path.abspath(__file__)) + "/../src/")) この設定ののち、メインソース上での import は src 配下のパスだけ書くようにします。 要は src を書きません。 src/sample.py from service.hoge import HogeService from common.huga import HugaException テストコード上での import は、ルートディレクトリからのフルパスを書くようにします。 要は src を入れます。 tests/test_sample.py from src.service.hoge import HogeService from src.common.huga import HugaException テスト設定 pytest の設定で、性能計測やカバレッジレポートを有効化しておきます。 そんなリッチなテストが不要な場合は設定も不要です。 pytest.ini [pytest] testpaths = . python_files = test_*.py python_classes = Test python_functions = test_ addopts = --durations=0 --cov=src/ --cov-report=html ちなみに、設定で XUnit 形式のレポートを選ぶと、Jenkins などに連動することもできるんですって。 私は使ったことないのですが、可能性を感じられますね。 開発環境向け 開発用の requirements として、例えばこんな設定を書きます。 requirements.txt pytest pytest-cov pytest, pytest-cov は、テストコードを使うにあたって必須です。 gitignore も設定しておきます。 .gitignore *.pyc .coverage htmlcov/ htmlcov にはカバレッジレポートが出るので、エビデンスとして git commit したい場合は外してもよいです。 テストコード pytest のテストコード基本設計です。 (細かい説明をバッサリ省略しますが、詳細は別記事が書けたらいいな) メイン処理 test_hoge.py import os import pytest from src.service.hoge_service import HogeService # Test で始まるクラス名を命名すると、テストとして認識される。(※ただしクラス定義は必須ではない) ## conftest.py で定義した fixture(事前/事後処理)のうち、使用するものを usefixtures として宣言する。 ## fixture のうち、mock_environ などは関数から呼び出していないけれど、ここに書いておく。(テスト開始時に読み込んで、モックなどに必要な環境変数を初期化できる) @pytest.mark.usefixtures( 'mock_environ', 'create_mock', 'get_hoge_service' ) class TestHogeService: ### 関数に入れたいテストパラメータのパターンを parametrize として宣言する @pytest.mark.parametrize( 'subject, request_list, is_valid', [ ('通常', [{'aaa': 'bbb'}, {'ccc': 'ddd'}], True), ('リクエスト対象が空', [], True), ('リクエスト対象がNone', None, False), ] ) ### test で始まる関数名を命名すると、テストとして認識される。 (※ Test で始まるクラス内、もしくはクラス未所属が対象。) #### 引数に必要なもの #### 1.self (クラスの配下である場合) #### 2.parametrize で定義した引数群 #### 3.使用する fixture def test_execute_requests(self, subject, request_list, is_valid, monkeypatch, get_hoge_service, create_mock): with mock(): #### fixture は関数内で普通に呼び出せる。(この例では create_mock が fixture) with create_mock('dammy') as mock_resource: with get_hoge_service() as service: ### monkeypatch という fixture は pytest に標準搭載される。 ### 指定の関数を丸ごと別のダミー関数へ差し替えてくれる。 monkeypatch.setattr(HogeService, 'execute', lambda *args, **kwargs: None) if is_valid: result = service.execute_requests(subject, request_list) ### assert 判定文, エラーの場合表示する文字列 と書くとテスト項目になる。 assert result == None, '関数が何か不要な値を返している' else: ### 例外が発生すること が期待値のときは assert の代わりに raises を使用する。 with pytest.raises(Exception, match=r".*execute_requests.*") as exception_info: service.execute_requests(subject, request_list) ### 発生した例外を受け取って細かくチェックすることも可能 raised_exception = exception_info.value if raised_exception.__cause__: assert isinstance(raised_exception.__cause__, Exception), 'エラーの発生元がハンドリングできていない' else: assert False, '@error_handle し忘れているかもしれない (raise from されていない)' メインソースの1ファイルにつき1つの test ファイルを作る。 1つのクラスにつき、1つの test クラスを作る。 1つのメソッドにつき、1つの test メソッドを作る。 テストパターンは原則として parametrize で制御する。 parametrize でどうしても書きづらいパターン(途中でエラー発生するパターン等)のみ、別のメソッドで表現する。 と、いい感じにテストコードが書ける気がします。 事前/事後処理(fixture) conftest.py import pytest import os import contextlib from src.common.exception import FatalError from src.service.hoge_service import HogeService # @pytest.fixture デコレータを定義すると、fixture として認識される。 # scope の指定内容によって、中身が実行される回数が変わる。 # function テストケースごと 1回 (毎回初期化したいダミーDB作成処理など) # class テストクラス生成ごと 1回 # module テストファイルの読み込みごと 1回 # session テスト実行ごと 1回 (毎回固定値を返せばいい場合など) # 実行される回数に関係なく、return された値はテストケースのどこでも使用できる。 # 何も値を返さない(テストロード時に実行されるだけ) の例 # 念のために function スコープとして各テストケースごと初期化する @pytest.fixture(scope='function') def mock_environ(): os.environ['Region'] = 'ap-northeast-1' # 単純な固定値を返す 例 # 固定の値だから session でよい @pytest.fixture(scope='session') def get_dammy_data(): return 'hoge' # 関数を返す例 # 固定の関数を返すから session でよい。(返した関数を実行するタイミングはテストケース内でコントロール) # ※contextmanager や yield は with 句として呼びたい目的の実装なので pytest の仕様とは関係ないです。 @pytest.fixture(scope='session') def get_hoge_service(): # with 句で行う処理 @contextlib.contextmanager def _create_service(hoge): yield HogeService(input=hoge) return _create_service # ※例外を発生させるダミー関数を返したりもできる @pytest.fixture(scope='session') def dammy_fatal_error(): # with 句で行う処理 @contextlib.contextmanager def _dammy_function(): def _fatal_error(*args, **kwargs): raise FatalError('Mock') yield _fatal_error return _dammy_function # 何らかの処理 + 値の組み合わせを返す例 ## モックリソースを新規作成 + 作ったリソースの参照を返す @pytest.fixture(scope='session') def create_mock(): # with 句で行う処理 @contextlib.contextmanager def _create(name): result = create_hoge(Name=name) yield result return _create 実践 簡単にサンプルを作って動かしてみます。 まず最初に、ルートディレクトリで requirements のインストールを行っておきましょう。 pip3 install -r requirements.txt そして、適当にアプリを作ってみます。 (こんなアプリ作ってみた) (簡単なテストコードも書いてみた) テストコードを VSCode 上で実行してみましょう。 テストコードタブを選び、実行を選択します。 動きました こんな感じでカバレッジレポートが出ます。 メインコードのほうに新しいメソッドを足してみると、カバレッジ missing 判定されましたね。 もう少し複雑なテストコードも組んでみます。 書いてみた テスト用のクラスを fixture で作ってみます。ロジックを複数のコードで使いまわせるようになります。 parametrize で、同じテストコードを複数の入力パターンで試せます。 ちなみに、pytest が標準出力に出してくれる表示項目も確認可能です。 ターミナル出力で「Python Test Log」を選びます。 実行時間のチェック結果などがこちらへ出ています。 おわりに 最初のひと手間を掛ければ、かなり快適な Python 開発ができるかもしれません。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

pytest

前提 pythonインストール済み pytestのインストール pip install pytest テストファイルの作成 testで始まる関数名を作成する testで始まる名前の関数自動的にテスト対象となる テストしたい関数内に assert で評価式を記述する sample.py def add_number(x): return x + 1 def test_sum(): result: int = add_number(4) assert result >= 5 pytestの実行 pytest sample.py  成功した場合 失敗した場合 pythonのカバレッチを調べる 単体テストには処理ルートや分岐条件が網羅されているかという観点のテスト(ガバレッジテスト)をしたい場合は以下のコマンドでpytestのプラグインをインストールする。 pip install pytest-cov pytest-cov 実行オプション -s: print文を出力 -v: 冗長なログ出力 --cov=CODE_DIRECTORY: ディレクトリ内をテストコードを指定する場合 --cov: C0カバレッジの表示 --cov --cov-branch: C1カバレッジの表示 --cov-report=html : HTML形式のカバレッジレポートを出力 実行コマンド例 pytest -s -v --cov sample.py カバレッジのhtml出力 pytest -s -v --cov=../src --cov-report=html pytestでテストをスキップする テストが必要ないコードの場合(テストコード内で呼び出すサブルーチンなど) @pytest.mark.skip(reason="このテストは無条件でスキップします。") def test_sample(): hoge = "hoge" return hoge @pytest.mark.skipif(True, reason="[スキップする理由]") def test_function_1(): moge = 1 return moge 失敗すると期待されるテストにマークを付ける @pytest.mark.xfail() def test_unique_id_is_a_duck(): uid = tasks.unique_id() assert uid == 'a duck'
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【連続極座標系】離心率(Eccentricity)εの極限に現れる虚数(Imaginal)について。

以下の投稿について少し考察が進んだのでまとめておきます。 【数理考古学】離心率①二次曲線(楕円,放物線,双曲線)の極座標表示からの出発。 極座標系(Polar Coordinate System)上における離心率(Eccentricity)εの振る舞い。 離心率(Eccentricity)εが極座標系(r,θ)(θ=-π→π)の半径rにもたらす影響は以下の式で表されます。 r=\frac{1}{1±ε \cos(θ)} ε=0の時,r=1(-πθ)→1(0θ)→1(πθ)、つまり円(Circle) 0<ε<1の範囲の時,楕円(Ellipse) ε=1の時,r=∞(-πθ)→$±\frac{1}{2}$(0θ)→∞(πθ)、つまり放物線(Parebora) ε<1の時、双曲線(Hyperbora) 特にε=$\frac{π}{2}$の時、第一象限上の頂点と第三象限上の頂点、第二象限上の頂点と第四象限上の頂点を結ぶ直線がx軸上の±1で交差する。 ここで式$r=\frac{1}{1+ε \cos(θ)}$と式$r=\frac{1}{1-ε \cos(θ)}$は複素共役()と似た関係にあり、ε=0あるいはε=∞の場合のみその値が重なるのです。 import numpy as np import cmath as c import matplotlib.pyplot as plt import matplotlib.animation as animation #figure()でグラフを表示する領域をつくり,figというオブジェクトにする. plt.style.use('default') fig = plt.figure() ax = fig.add_subplot(111,aspect='equal') #1周分の角度 θ=np.linspace(0,np.pi*2,61,endpoint = True) #ε(離心率) ε=np.linspace(0,5,51,endpoint = True) #円、放物線、双曲線の計算 def eccentric(x): return(1/(1+x*np.cos(θ))) def eccentricity(x): c0=[] for nm in range(len(θ)): c0.append(c.rect(eccentric(x)[nm],θ[nm])) return(np.array(c0)) C1=eccentricity(0) C2=eccentricity(1) C3=eccentricity(np.pi/2) #描画関数 def Eccentricity01(n): plt.cla() fp0=[] for nm in range(len(θ)): fp0.append(c.rect(1/(1+ε[n]*np.cos(θ[nm])),θ[nm])) xyp=np.array(fp0) fm0=[] for nm in range(len(θ)): fm0.append(c.rect(1/(1-ε[n]*np.cos(θ[nm])),θ[nm])) xym=np.array(fm0) #描画 plt.plot(C1.real,C1.imag,color="salmon",lw=0.5,label="ε=0(Circle)") plt.plot(C2.real,C2.imag,color="green",lw=0.5,label="ε=1(Parabola)") plt.plot(-C2.real,C2.imag,color="green",lw=0.5) plt.plot(C3.real,C3.imag,color="olive",lw=0.5,label="ε=π/2(Hyperbola)") plt.plot(-C3.real,C3.imag,color="olive",lw=0.5) es="{:0<+7}".format(round(ε[n],3)) ES="ε="+es plt.plot(xyp.real,xyp.imag,color="blue",marker="o",lw=1,label=ES) plt.plot(xym.real,xym.imag,color="red",marker="o",lw=1,label=ES) plt.axvline(0, 0, 1,color="black",lw=0.5) plt.axhline(0, 0, 1,color="black",lw=0.5) plt.xlim([-18,18]) plt.ylim([-18,18]) plt.xlabel("Real") plt.ylabel("Imaginal") plt.title("Eccentricity") ax.legend(loc='upper right') #Eccentricity01(10) #plt.show() ani = animation.FuncAnimation(fig, Eccentricity01, interval=100,frames=len(ε)) ani.save("Ecc102.gif", writer="pillow") それでは具体的に最終的にどういう重なり方をするのでしょうか。それについてさらに詳しく見ていきたいと思います。 離心率(Eccentricity)εの極限 以降のグラフでは式$r=\frac{1}{1+ε \cos(θ)}$に関心を集中させていきます。 import numpy as np import cmath as c import matplotlib.pyplot as plt import matplotlib.animation as animation #figure()でグラフを表示する領域をつくり,figというオブジェクトにする. plt.style.use('default') fig = plt.figure() ax = fig.add_subplot(111,aspect='equal') #1周分の角度 θ=np.linspace(0,np.pi*2,61,endpoint = True) #ε(離心率) ε=np.linspace(0,5,51,endpoint = True) def eccentric(x): return(1/(1+x*np.cos(θ))) def eccentricity(x): c0=[] for nm in range(len(θ)): c0.append(c.rect(eccentric(x)[nm],θ[nm])) return(np.array(c0)) C1=eccentricity(0) C2=eccentricity(1) C3=eccentricity(np.pi/2) #描画関数 def Eccentricity01(n): plt.cla() C0=eccentricity(ε[n]) #描画 plt.plot(C1.real,C1.imag,color="red",lw=0.5,label="ε=0(Circle)") plt.plot(C2.real,C2.imag,color="purple",lw=0.5,label="ε=1(Parabola)") plt.plot(C3.real,C3.imag,color="blue",lw=0.5,label="ε=π/2(Hyperbola)") es="{:0<+7}".format(round(ε[n],3)) ES="ε="+es plt.plot(C0.real,C0.imag,color="green",marker="o",lw=1,label=ES) plt.axvline(0, 0, 1,color="black",lw=0.5) plt.axhline(0, 0, 1,color="black",lw=0.5) plt.xlim([-10,20]) plt.ylim([-6,6]) plt.xlabel("Real") plt.ylabel("Imaginal") plt.title("Eccentricity") ax = fig.add_subplot(111) ax.set_aspect('equal') ax.legend(loc='lower right') #Eccentricity01(10) #plt.show() ani = animation.FuncAnimation(fig, Eccentricity01, interval=100,frames=len(ε)) ani.save("Ecc003.gif", writer="pillow") この式に登場する双曲線の振る舞いは楕円のそれと同じくらい謎めいていますが、とりあえず角度の変遷に対応した半径(絶対値)の推移に注目すると以下となります。 ε=0の時は一律y=1。以降もxの中心πに対して±$\frac{2}{π}$ラジアン(±90度)の時の値は一貫してy=1であり続ける。 ε=1の時に中央値x=πの値がy=∞に到達し(グラフ形は放物線)、以降はεの値が増加する都度、0へと近付いていく(グラフ形は双曲線)。 import numpy as np import cmath as c import matplotlib.pyplot as plt import matplotlib.animation as animation #figure()でグラフを表示する領域をつくり,figというオブジェクトにする. plt.style.use('default') fig = plt.figure() ax = fig.add_subplot(111,aspect='equal') #1周分の角度 θ=np.linspace(0,np.pi*2,61,endpoint = True) #ε(離心率) ε=np.linspace(0,5,51,endpoint = True) def eccentric(x): return(1/(1+x*np.cos(θ))) def eccentricity(x): c0=[] for nm in range(len(θ)): c0.append(c.rect(eccentric(x)[nm],θ[nm])) return(np.array(c0)) C1=eccentricity(0) C1abs=abs(C1) C2=eccentricity(1) C2abs=abs(C2) C3=eccentricity(np.pi/2) C3abs=abs(C3) #描画関数 def Eccentricity01(n): plt.cla() C0=eccentricity(ε[n]) C0abs=abs(C0) #描画 plt.plot(θ,C1abs,color="red",lw=0.5,label="ε=0(Circle)") plt.plot(θ,C2abs,color="purple",lw=0.5,label="ε=1(Parabola)") plt.plot(θ,C3abs,color="blue",lw=0.5,label="ε=π/2(Hyperbola)") es="{:0<+7}".format(round(ε[n],3)) ES="ε="+es plt.plot(θ,C0abs,color="green",marker="o",lw=1,label=ES) plt.axvline(0, 0, 1,color="black",lw=0.5) plt.axhline(0, 0, 1,color="black",lw=0.5) plt.xlim([0,np.pi*2]) plt.ylim([0,5]) plt.xlabel("Real") plt.ylabel("Imaginal") plt.title("Eccentricity") ax.legend(loc='upper right') #Eccentricity01(10) #plt.show() ani = animation.FuncAnimation(fig, Eccentricity01, interval=100,frames=len(ε)) ani.save("Ecc005.gif", writer="pillow") さらに観察範囲を広げると、εが無限に近付くと以下の極限状態に近付く様子がさらに明瞭となります。 import numpy as np import cmath as c import matplotlib.pyplot as plt import matplotlib.animation as animation #figure()でグラフを表示する領域をつくり,figというオブジェクトにする. plt.style.use('default') fig = plt.figure() ax = fig.add_subplot(111) #1周分の角度 θ=np.linspace(0,np.pi*2,61,endpoint = True) #ε(離心率) ε=np.linspace(0,25,101,endpoint = True) def eccentric(x): return(1/(1+x*np.cos(θ))) def eccentricity(x): c0=[] for nm in range(len(θ)): c0.append(c.rect(eccentric(x)[nm],θ[nm])) return(np.array(c0)) C1=eccentricity(0) C1abs=abs(C1) C2=eccentricity(1) C2abs=abs(C2) C3=eccentricity(np.pi/2) C3abs=abs(C3) #描画関数 def Eccentricity01(n): plt.cla() C0=eccentricity(ε[n]) C0abs=abs(C0) #描画 plt.plot(θ,C1abs,color="red",lw=0.5,label="ε=0(Circle)") plt.plot(θ,C2abs,color="purple",lw=0.5,label="ε=1(Parabola)") plt.plot(θ,C3abs,color="blue",lw=0.5,label="ε=π/2(Hyperbola)") es="{:0<+7}".format(round(ε[n],3)) ES="ε="+es plt.plot(θ,C0abs,color="green",marker="o",lw=1,label=ES) plt.axvline(0, 0, 1,color="black",lw=0.5) plt.axhline(0, 0, 1,color="black",lw=0.5) plt.xlim([0,np.pi*2]) plt.ylim([0,25]) plt.xlabel("Real") plt.ylabel("Imaginal") plt.title("Eccentricity") ax.legend(loc='upper right') #Eccentricity01(10) #plt.show() ani = animation.FuncAnimation(fig, Eccentricity01, interval=100,frames=len(ε)) ani.save("Ecc006.gif", writer="pillow") つまりはこういう事です(半径1の単位円の場合)。 \lim_{ε \to 0}\frac{1}{1±ε \cos(θ)}= \left\{ \begin{array}{ll} 1 & (\forallθ) \end{array} \right.\\ に対し\\ \lim_{ε \to ∞}\frac{1}{1±ε \cos(θ)}= \left\{ \begin{array}{ll} 1 & (θ=±\frac{π}{2}) \\ 0 & (θ≠±\frac{π}{2}) \end{array} \right. 一方、「X軸(実数軸)上の半径(Radius)/直径(Diameter)」の極座表情での認識は以下であり、後者(と中心(0,0)を結ぶ線)はこれ(と中心(0,0)を結ぶ線)と直交(Orthogonal)する形となります。 x(x \in \mathbb{R} \land -1≦x≦1)= \left\{ \begin{array}{ll} 1 & (θ=0 \lor θ=π) \\ 0 & (θ≠0 \land θ≠π) \end{array} \right. まさしく虚数(Imaginal)概念±iと同値(EQ=EQuivalence)なんですね。そしてほのかに伺える(0を挟む連続性と同等の)無限遠点∞を挟む連続性概念の気配… 【連続極座標系】「冪乗関数の極限」問題と「距離関数」概念の導入による解決 反比例関数(Inverse Proportionality Function)との関係 ところで… 双曲線 -Wikipedia 反比例のグラフxy=Cも双曲線の一種である。これは、直角双曲線:$x^2-y^2=2C$を原点の回りに45°=$\frac{π}{4}$だけ回転させた双曲線に等しい。 まず式$y=\frac{1}{1±ε \cos(θ)}$でε=$\frac{π}{2}$と置き、$y\mp$1して原点を中央(0,0)に平行移動させる(この時点で2つの双曲線が1つに重なる)。 このままだとこのま回転させると中央座標(x,y)が($\frac{\sqrt{2}}{2},\frac{\sqrt{2}}{2}$)となってしまうので$\frac{2}{\sqrt{2}}$を掛ける。 次いで45度=$\frac{π}{4}$回転させる。 こうすればれば反比例関数(Inverse Proportionality Function)xy=1と重なりますが、果たしてこの操作にどんな意味が? それについては以下続報…
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Thumbalizr APIでウェブサイトのサムネイル

ウェブサイトのサムネイル画像を提供するAPIです。 FREEプランもあり、100回/月が使えます。 https://www.thumbalizr.com/features 2021年10月時点で サイトにサンプルコードがありますが、Python3では動作しませんでした。 下記はPython3で動作確認しています。 sample.py import hashlib import urllib.parse def thumbalizr(url='', options={}): embed_key = 'your_embed_key' # replace it with you Embed API key secret = 'your_secret' # replace it with your Secret query = 'url=' + urllib.parse.quote(url) for key, value in options.items(): query += '&' + key + '=' + urllib.parse.quote(str(value)) token = hashlib.md5((query + secret).encode('utf-8')).hexdigest() return "https://api.thumbalizr.com/api/v1/embed/%s/%s/?%s" % (embed_key, token, query) print (thumbalizr("https://www.yahoo.co.jp/wordpress/", { 'width': 300, 'size': 'page' })) コードに埋め込むAPIは、ユーザーのProrileページ(https://thumbalizr.com/member/profile)で確認できます。 Secretは非表示になっており、"show"のリンク押下で表示されます。 サンプルを実行すると、下記のようなURLが発行され、サイトのサムネイル画像をAPIで取得できます。 https://api.thumbalizr.com/api/v1/embed/********/?url=https%3A//www.yahoo.co,jp/&width=300&size=page
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GCPでプリエンプティブルのJupyterLab環境を楽して構築

クラウドでJupyter環境を使いたい場合Google Colaboratory(Colab)Proを使えばいいと思います。私も基本的にそうしています。 ですが本稿では、何らかの理由でColabが使えない状況・かつクラウドのリソースを使いたいという時に、Colabのように安価で簡単に使い始められるJupyterLab環境をGoogle Cloud Platform(GCP)に構築します。 Colabぐらい...とはいきませんが、できるだけ楽に・安価に構築します。 "楽"というのは、具体的には下記のようになっています。 構築後のインスタンスに接続してpip install等で内部状態を変える必要がないこと Ansible等のツールを使わなくても環境の再現性が取れる 構成に合わせてIPアドレスやポート番号などのネットワーク構成を変える必要がないこと セキュアな状態を保つためにネットワークを管理したりする必要がない プリエンプティブル VM インスタンスによるコスト削減 GCPには プリエンプティブル VM インスタンス という機能があり、「24時間で停止する」等いくつかの制約を受ける代わりに安価で利用できます。Microsoft Azureで言うAzure Spot Virtual Machinesや、AWSで言うSpot Instancesと似たような物だと思います。 本稿ではこのプリエンプティブルインスタンスを構築することでコストを削減します。 ...ですが、AI PlatformノートブックやVertex AI ノートブックを使ったり、マーケットプレイスのVMイメージを利用した方法ではプリエンプティブルインスタンスにできないようなので、Compute Engineで新規VMインスタンスから構築します。 実行環境 GCPの管理コンソールにアクセスできるWebブラウザだけあれば良いです。 手順 インスタンスの構築 GCPの管理コンソールで「Compute Engine」→「VM インスタンス」→「インスタンスを作成」から、好みの名前やスペックを選んでインスタンスを構築します。必須なのは以下2点です。 「ブートディスク」→「変更」→「公開イメージ」 「OS」を「Deep Learning on Linux」 にする バージョンは使いたいソフトウェアにあわせてお好みで 「ネットワーク、ディスク、セキュリティ、管理、単一テナンシー」→「管理」→「可用性ポリシー」 「プリエンプティブ」を「オン」 にする 必須の設定は以上です。ネットワークのアクセス許可等の設定は基本的に必要ありません。 JupyterLabにアクセスする Deep Learning on Linuxのイメージを使うと8080ポートでJupyterLabが自動的に立ち上がりますが、このままではアクセスする方法がありません。 そこでgcloudコマンドを使っての SSHポートフォワード を使うことで、パブリックネットワークに対してアクセス許可を新規で追加したりすることなくJupyterLabにアクセスできるようになります。さらに、CloudShellには Webプレビュー という公開されたポートに対してGCPログイン済アカウントでのみアクセスできるURLを払い出す機能があります。 これらを利用することで、ブラウザのみで(gcloudコマンド実行環境をローカルに構築したりすること無く)セキュアにJupyterLab環境へアクセスします。 管理コンソール右上「CloudShellをアクティブにする」で、CloudShellを起動します。 Shellが立ち上がったら、下記コマンドを入力します。 $ gcloud compute ssh --project [プロジェクト名] --zone [ゾーン名] [インスタンス名] -- -L 8080:localhost:8080 プロジェクト名やゾーン名は省略しても実行できる場合があります。 実行後、インスタンスに接続できたらShellはそのまま「ウェブでプレビュー」→「ポート 8080 でプレビュー」を選択します。 これでJupyterLabが立ち上がって使えるようになっていると思います。 参考 GCP上にPyTorchが入ったGPUインスタンスを立ち上げる | bassbone's blog GCPでできるだけ安くディープラーニング | Hiho's Blog JupyterLab に接続する  |  Deep Learning VM Image  |  Google Cloud ウェブ プレビューの使い方  |  Cloud Shell  |  Google Cloud
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Python(pandas)でファンチャートを作る

0. はじめに たまには小ネタ記事を。 よくテレビとかで出てくる「ある地点の**を100としたときに」っていうグラフがあります。 これファンチャートって言うらしいんですが、これをPandasのMap関数等でどう作成すればいいか?にお恥ずかしながら30分くらい工数かかってしまったので、どこかの誰かの為に残しておきます。 「pandas ファンチャート」でググってもHitしませんでしたので・・(Excelは多かったけど) 参考:ファンチャートとは? 1. サンプルデータ作成 サンプルとして適当なデータを作成します ※この程度なら実際はごり押しでもできますが、カラム数がうん千だときついですよね。。 import pandas as pd df = pd.DataFrame({ 'A' : [1, 2, 3, 4, 5], 'B' : [10, 20, 30, 40, 50], 'C' : [500, 400, 300, 200, 100] }) display(df.head()) display(df.plot()) 2. ファンチャート作成 今回は0行目を「100」としてPandasのMAP関数を使用して処理していく。 数式は簡単で 変換後の値 = (*行目の要素 × 100) ÷ 0行目の要素 となるわけだが、個人的に詰まったのはMAP関数でどうやって0行目の要素っていうのを処理すればいいか?に関してです。 結論から言うとfunctools.partial()を使用すれば部分的に変数を固定にできます。 from functools import partial def fanchart(x, y): """計算関数""" return (x*100)/y """ ・各カラムにMAP関数+partial関数を適応(for使わなくてもできるかもですが。。) ・y=df[i][0]で関数内の引数yを0行目の要素で固定している """ for i in df.columns: df[i + '_fan'] = list(map(partial(fanchart, y=df[i][0]), df[i])) display(df.head()) display(df.plot(y=['A_fan', 'B_fan', 'C_fan'])) 3.さいごに Pandasも業務やプライベートで結構使ってるので、ようやく慣れてきたかなぁ・・・と思ってたけど全然そんなことなかったですね。 いつも小難しい記事ばかり書いてたので、たまにはと思って小ネタを今回は書かせていただきました。 おっ、ちょうど困ってて参考になった!という人は私の30分との等価交換(笑)でぜひLGTMお願いします!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PyCharm CommunityでDjangoをインストールする方法

無料版だとコマンドラインで環境を作る PyCharm Community番だと、新しいプロジェクトからDjangoを作れないので、 コマンドライン上でDjangoプロジェクトを作る必要があります。 だいたいこんな感じ Python仮想環境をインストールする まず、Python仮想環境を起動します。JavaでいうJava仮想マシンみたいな感じですね このコマンドで、プロジェクトのディレクトリにenvフォルダが出来るはずです。 python -m venv env 仮想環境を起動する 次にインストールした仮想環境を起動します env\Scripts\activate すると、PowerShellの右側に(env)マークが出来るので これが仮想マシン上で動いていることが分かるはずです。 Djangoのインストール 次にDjangoをインストールして pip install django プロジェクトテンプレートを作成します django-admin startproject pycharmtut (この時、ウィルスソフトが反応することがありますが無視) manage.pyを含む下記フォルダが出来ていたら完成です 無事、起動画面も作成できました!ヾ(。>﹏<。)ノ゙✧*。 こんな感じで、無料版でもDjangoプロジェクトは作成できます! どんどんWebサービスを作っていしまいましょう! 参考記事
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

エクサウィザーズプログラミングコンテスト2021(ABC222) A~D問題 ものすごく丁寧でわかりやすい解説 python 灰色~茶色コーダー向け #AtCoder

エクサウィザーズプログラミングコンテスト2021 A~D問題の解説記事です。 (ABC222(AtCoder Beginner Contest 222)) 灰色~茶色コーダーの方向けに解説しています。 その他のABC解説、動画などは以下です。 株式会社エクサウィザーズ様について AIを使った社会課題解決をされている企業様です。 興味のある方は上記採用情報を御覧ください。 A - Four Digits 入力を受け取り、桁数を確認して必要な分"0"を追加して出力します。 コツは数値ではなく文字列として受け取ることです。 文字列として受け取ることで len(N) として文字数=桁数が確認できます。 入力の受け取り、出力がわからない方は以下の記事を参考にしてください。 【提出】 # 入力の受け取り(文字列) N=input() # 桁数 disit=len(N) # 桁数が1なら if disit==1: # 先頭に"000"をつけて出力 print("000"+N) # 桁数が2なら if disit==2: # 先頭に"00"をつけて出力 print("00"+N) # 桁数が3なら if disit==3: # 先頭に"0"をつけて出力 print("0"+N) # 桁数が4なら if disit==4: # そのまま出力 print(N) B - Failing Grade aの各要素についてP未満かを順に確認します。 P未満の人数を数えて出力すれば終わりです。 【提出】 # 入力の受け取り N,P=map(int, input().split()) a=list(map(int, input().split())) # 答えを格納する変数 ans=0 # i=0~N-1まで for i in range(N): # a[i]がP未満なら if a[i]<P: # 答えにプラス1 ans+=1 # 答えを出力 print(ans) C - Swiss-System Tournament 制約が小さいので全ての試合をシュミレーションすればよいです。 やることがそれなりに多いので、実装するのは大変ですが頑張りましょう。 以下の手順で実装します、 (1)手の入力を0インデックスで記録する(hand)  ※0インデックスなので  選手1の1ラウンドの目の手=hand[0][0]  選手1の2ラウンドの目の手=hand[0][1]  選手1の3ラウンドの目の手=hand[0][2]  ...  選手2の1ラウンドの目の手=hand[1][0]  ...  と選手番号とラウンドの番号が1つずつずれることに注意してください。 (2)選手の勝数と番号を記録するリストを用意(wins)  ※コツは[選手の勝数,選手番号]の順に記録することです。  後に勝数順にソートするため、勝数がリストの1番目の要素としてあったほうが楽に実装できます。 (3)Aの手,Bの手を引数→Aの追加勝数,Bの追加勝数を返す関数を作る  勝ったら+1、引き分け、負けたら+0 (4)Mラウンドの試合を行う  順位:2k→選手A  順位:2k+1→選手B  として選手Aと選手Bの試合結果を確認する  ※問題文では「2k-1」と「2k」が試合となっていますが0インデックスにしたため、番号がずれています。 (5)追加勝数をpointsにマイナスで記録する  例:選手0が2勝していたら[-2,0]となる  ※マイナスで記録するのは後のソートを楽にするためです。 (6)winsを勝数,選手番号順にソートする  ※wins.sort()とすることで 「1番目の要素」=「勝数」昇順→「2番目の要素」=「選手番号」昇順 に並び替えができます。  この時並び替えを「1番目の要素」「2番目の要素」ともに昇順で並び替えるため、勝数をマイナスで記録しています。  (勝数をプラスで記録すると 「1番目の要素」=「勝数」降順→「2番目の要素」=「選手番号」昇順 に並び替えが必要となり、実装が非常にめんどくさいことになります) (7)答え(winsの2番目の要素)を出力する 【提出】 # 入力の受け取り N,M=map(int, input().split()) # 手の記録用 hand=[] # 2N回受け取り for i in range(2*N): # 受け取り A=input() # 記録 hand.append(A) # [勝数,選手番号]を格納するリスト # 選手番号は0インデックス(選手1は0,選手2は1,...) wins=[] # 全員0で初期化 for i in range(2*N): wins.append([0,i]) # 試合の結果判定 # 引数;選手Aの手,選手Bの手→選手Aの追加勝数,選手Bの追加勝数を返す def match(A_hand,B_hand): if A_hand=="G" and B_hand=="G": return 0,0 elif A_hand=="G" and B_hand=="C": return 1,0 elif A_hand=="G" and B_hand=="P": return 0,1 if A_hand=="C" and B_hand=="G": return 0,1 elif A_hand=="C" and B_hand=="C": return 0,0 elif A_hand=="C" and B_hand=="P": return 1,0 if A_hand=="P" and B_hand=="G": return 1,0 elif A_hand=="P" and B_hand=="C": return 0,1 elif A_hand=="P" and B_hand=="P": return 0,0 # Mラウンド(0インデックス,i=0~M-1まで) for i in range(M): # k=0~N-1まで for k in range(N): # 順位2kと(2k+1)の試合 # 選手Aの番号(0インデックス) playerA=wins[2*k][1] # 選手Bの番号(0インデックス) playerB=wins[2*k+1][1] # 選手Aの出す手 A_hand=hand[playerA][i] # 選手Bの出す手 B_hand=hand[playerB][i] # A,Bに追加される勝数 A_point,B_point=match(A_hand, B_hand) # Aの勝数を計算(勝ったらマイナス1) wins[2*k][0]-=A_point # Bの勝数を計算(勝ったらマイナス1) wins[2*k+1][0]-=B_point # 勝数,番号順にソート wins.sort() # i=0~2Nまで for i in range(2*N): # 答えの出力 # 選手番号は0インデックスなのでプラス1して戻す print(wins[i][1]+1) D - Between Two Arrays DPを使います。 DPとは「ある状態までの答えがわかっていれば→その次の状態の答えも出せる」という手続きを何度も行って最終的な答えを出す方法です。 具体的な手順は以下です。 (1)表を作る (2)すぐにわかるところを埋める (3)表の小さい方から答えにたどり着くまで埋める (4)答えを出力する 例えば以下の入力を例として考えます。 N:4 A:1 2 3 4 B:5 6 7 8 (1)表を作る 今回作る表は 『Cのi番目まででC[i]がxであるような数列の個数』 とします。 表の名前はdpとします。 本当はx=3000(B[i]の最大値)まで必要ですが見やすいようにx=10までで作ります。 dp[2][3]であれば 『Cの2番目まででC[2]が3であるような数列の個数』 を表します。考えられるのは以下です。 C=(1,3),(2,3),(3,3) ゆえにdp[2][3]=3となります。 (2)すぐにわかるところを埋める すぐにわかるのは1行目(i=1)です。 i=1は 『Cの1番目まででC[1]がxであるような数列の個数』 を表します。 dp[1][1]=1(作れる数列C:(1)) dp[1][2]=1(作れる数列C:(2)) dp[1][3]=1(作れる数列C:(3)) dp[1][4]=1(作れる数列C:(4)) dp[1][5]=1(作れる数列C:(5)) となります。 それ以外の箇所はA[1]≦x≦B[1]でなく、「C[1]がxである」が満たせないので数列が作れません。ゆえに0です。 一般に考えるとx=A[1]~B[1]について dp[1][x]=1 となります。 (3)表の小さい方から答えにたどり着くまで埋める 2行目を考えましょう。2行目は 『Cの2番目まででC[2]がxであるような数列の個数』 を表します。 A[2]~B[2]=2~6ですから、xが2~6以外の箇所は数列Cが作れません。つまり0が埋まります。 ・x=2 dp[1][0]=0 dp[1][1]=1 dp[1][2]=1 であることがわかっています。 例えばdp[1][1]は『Cの1番目まででC[1]が1であるような数列の個数』を表しています。 であればdp[1][1]で作れるCの2番目に「2」をくっつけることで2番目までの数列を作れます。 dp[1][2]も同様に『Cの1番目まででC[1]が2であるような数列の個数』を表していますから、作られた数列Cの2番目に「2」をくっつけることで数列が作れます。 具体的には dp[1][1]:C=(1) dp[1][2]:C=(2) となっているわけですから、それぞれに「2」をくっつけて dp[2][2]:C=(1,2),(2,2) とできるわけです。 ゆえにdp[2][2]=2であることがわかります。 ・x=3 dp[1][0]=0 dp[1][1]=1 dp[1][2]=1 dp[1][3]=1 です。 x=2のときと同様に、dp[1][1]~dp[1][3]で作れるCの2番目に「3」をくっつければよいことがわかります。 具体的には dp[1][1]:C=(1) dp[1][2]:C=(2) dp[1][3]:C=(3) となっているわけですから、それぞれに「3」をくっつけて dp[2][2]:C=(1,3),(2,3),(3,3) とできるわけです。 ゆえにdp[2][3]=3であることがわかります。 ・x=4~6 同じように考えれば dp[2][4]=dp[1][0]~dp[1][4]の和 dp[2][5]=dp[1][0]~dp[1][5]の和 dp[2][6]=dp[1][0]~dp[1][6]の和 となります。 2行目を埋めると以下のようになります。 例えばdp[2][5](青丸部分)はdp[1][0]~dp[1][5](赤枠部分)の和であることがわかります。 一般には以下の式で計算できます。 A[i]≦x≦B[i]の場合 dp[i][x]=dp[i-1][0]~dp[i-1][x]の和 ここまでわかれば表は埋まるのですが、和を取る部分をそのままsum等で実装するとTLEします。 そのため累積和(Cumulative sum)を使います。累積和は数列のある箇所までの値を全て足したものです。 dpのi行目を埋める前にi-1行目の累積和を確認しておくわけです。 例えば次にi=3の行を埋める時は先にi=2の行について累積和を計算しておきます。 2行目:0 0 2 3 4 5 5 0 0 0 0 例えば4番目までの累積和=0+0+2+3+4=9となります。 i-1行目の累積和をcum_sumとして、以下の式で計算できます。 ・cum_sum[0]=dp[i-1][0] ・cum_sum[k]=cum_sum[k-1]+dp[i-1][k] k-1番目までの累積和がわかっていればそれにdp[i-1][k]を足すことでk番目までの累積和も計算できるというわけです。 4番目までの累積和で言えばcum_sum[4]=cum_sum[3]+dp[i-1][4]=5+4=9と計算できます。 事前に累積和を計算しておくことで(dp[i-1][0]~dp[i-1][x]の和)=cum_sum[x]と計算できます。 (4)答えを出力する 表をすべて埋めると以下のようになります。 最後の行(i=4)は『Cの4番目まででC[4]がxであるような数列の個数』を表していますから、これらを全部足したものが答えです。 ゆえに最後の行の値をすべて足し、余りを取って出力すればOKです。 0+0+0+0+14+28+47+66+66+0+0=221 よって221が答えとなります。 pythonだとTLEするのでpypyで提出します。 【提出】 # pypyで提出 # 入力の受け取り N=int(input()) # 0番を埋めるために[0]を先頭へ追加 A=[0]+list(map(int, input().split())) B=[0]+list(map(int, input().split())) # あまりの定義 mod=998244353 # 表の作成 # 『Cのi番目まででC[i]がxであるような数列の個数』 dp=[[0]*3001 for i in range(N+1)] # x=A[i]~B[i] for x in range(A[1],B[1]+1): # dp[1][x]に1を埋める dp[1][x]=1 # i=2~Nまで for i in range(2,N+1): # 累積和 # 累積和リストを作成 cum_sum=[0]*(3001) # 0番目:cum_sum[0]=dp[i-1][0] cum_sum[0]=dp[i-1][0] # k=1~3000まで for k in range(1,3001): # 累積和の計算 cum_sum[k]=cum_sum[k-1]+dp[i-1][k] # 余りを取る cum_sum[k]%=mod # x=0~3001まで for x in range(3001): # A[i]<=x<=B[i]ならば if A[i]<=x<=B[i]: # dp[i][x]=(dp[i-1][0]~dp[i-1][x]の和)=cum_sum[x] dp[i][x]=cum_sum[x] # 表のN行目を全て足す ans=sum(dp[N]) # 余りを取る ans%=mod # 答えの出力 print(ans) 【広告】 「AtCoder 凡人が『緑』になるための精選50問詳細解説」 AtCoderで緑になるための典型50問をひくほど丁寧に解説した本(kindle)、pdf(booth)を販売しています。 値段:100円(Kindle Unlimited対象) 【kindle】 【booth(pdf)】 1~24問目まではサンプルとして無料公開しています
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Python シリアル値 日付変換

時々使用するシリアル値(例:44434.3412172569)から、 日付データ(yyyy/mm/dd HH:MM:SS)に変換する方法のメモです。 個人的に利用する頻度が高いので、備忘として残しておきます。 シリアル値とは 超シンプルに言うと、「1900/1/1」から何日経過したかを数値で扱ったものです。 24時間を「1」として、「1900/1/1」からの経過日時を算出しています。 (シリアル値はExcelなどでもよく見かけます。) ソースコード 下記コードをコピペで利用可能です。 def SerialToDateTime(serialVal:float) -> str: """日付シリアル値からyyyy/MM/dd HH:MM:ss 形式に変換 Args: serialVal (float): シリアル値(Ex: 44434.3412172569) Returns: str: 時刻 yyyy/MM/dd HH:MM:ss 形式 """ sDateTime = (datetime(1899,12,30) + timedelta(serialVal)).strftime('%Y/%m/%d %H:%M:%S') return sDateTime 以上、簡単ですがシリアル値から日付データに変更する方法でした!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VIF(Variance inflation factor; 分散拡大係数)は重回帰モデルの偏回帰係数の分散に現れるという話

はじめに 久しぶりに実務で重回帰分析を使ったのですが、多重共線性が問題になりそうなケースだったのでVIFを見ることに。VIFが偏回帰係数の推定の分散増加させるという話を聞いたことがあったので、実際どのように分散に効いてくるのか計算しました。 偏回帰係数の分散の導出 重回帰モデルは下記のような式で表される。 Y_i = \beta_0 + \beta_1 x_{i1} + \cdots + \beta_p x_{ip} + \varepsilon_i, (i=1,...,n) ここで$x_{ij}$は$i$番目の観測値の$j$番目の説明変数を表す。行列表示をすると次のように書ける。 \boldsymbol{Y} = X\boldsymbol{\beta} + \boldsymbol{\varepsilon} 以下では$Y_i$の観測値を$y_i$で表すことにする。また、以下では$X^\top X$が正則であることを仮定する。 次の式で$y_i$の予測値$\hat y_i$を書くことにする。 \hat{\boldsymbol{y}} = X\hat{\boldsymbol{\beta}} $\boldsymbol{\beta}$の最小二乗推定を行う。 S_e = (\boldsymbol{y} - \hat{\boldsymbol{y}})^2 = (\boldsymbol{y} - X\hat{\boldsymbol{\beta}} )^2 観測値との誤差の二乗が最小になるように、$S_e$を微分して$\hat{\boldsymbol{\beta}}$を求める。 \hat{\boldsymbol{\beta}} = (X^\top X)^{-1}X^\top \boldsymbol{y} $\boldsymbol{y}$は平均$X\boldsymbol{\beta}$、分散$\mathrm{Var}[\boldsymbol{\varepsilon}]$の正規分布に従うから、その線形変換である$\hat{\boldsymbol{\beta}}$もまた正規分布に従う。 $\hat{\boldsymbol{\beta}}$の平均値と分散を求めたい。ここで更に以下を仮定する。 \begin{aligned} E[\boldsymbol{\varepsilon}] &= 0\\ \mathrm{Var}[\boldsymbol{\varepsilon}] &= E[\boldsymbol{\varepsilon}\boldsymbol{\varepsilon}^\top] = \sigma^2 I \end{aligned} このとき$\hat{\boldsymbol{\beta}}$について以下が求まる。 \begin{aligned} E[\hat{\boldsymbol{\beta}}] &= E[(X^\top X)^{-1}X^\top \boldsymbol{y}] \\ &= E[(X^\top X)^{-1}X^\top (X\boldsymbol{\beta} + \boldsymbol{\varepsilon})] \\ &= \boldsymbol{\beta} + (X^\top X)^{-1}X^\top E[\boldsymbol{\varepsilon}] \\ &= \boldsymbol{\beta}\\ \mathrm{Var}[\hat{\boldsymbol{\beta}}] &= \mathrm{Var}[(X^\top X)^{-1}X^\top \boldsymbol{y}] \\ &= (X^\top X)^{-1}X^\top\mathrm{Var}[\boldsymbol{y}] X(X^\top X)^{-1}\\ &= (X^\top X)^{-1}X^\top\mathrm{Var}[\boldsymbol{\varepsilon}] X(X^\top X)^{-1}\\ &= \sigma^2 (X^\top X)^{-1}X^\top X(X^\top X)^{-1}\\ &= \sigma^2 (X^\top X)^{-1} \end{aligned} 以上より、$\hat{\boldsymbol{\beta}}$の分布が求められた。 \hat{\boldsymbol{\beta}} \sim \mathcal N\left(\boldsymbol{\beta}, \sigma^2 (X^\top X)^{-1}\right) $\hat{\beta}_j$の分散を求めたい。$r=X^\top X$とおく。一般性を失うことなく、行と列を入れ替えて$r$の$jj$成分を$(1,1)$成分に置く。 \begin{aligned} \tilde r = \begin{pmatrix} r_{jj} & r_{j,-j} \\ r_{-j,j} & r_{-j, -j} \\ \end{pmatrix} \end{aligned} ここで、$r_{j,-j}$は元の$r$の$j$行目から$j$列目を除いた1行p列ベクトルである。他も同様である。 \begin{aligned} r &= X^\top X \\ r_{jj} &= \sum_k (X^\top)_{jk} X_{kj} \equiv X_j^\top X_j \\ r_{j,-j} &= (X^\top X)_{j,-j} = \sum_k (X^\top)_{jk}X_{k,-j} \equiv X_j^\top X_{-j} \\ r_{-j,j} &= (X^\top X)_{-j,j} = \sum_k (X^\top)_{-j,k}X_{k,j} \equiv X_{-j}^\top X_{j} \\ r_{-j,-j} &= (X^\top X)_{-j,-j} = \sum_k (X^\top)_{-j,k}X_{k,-j} \equiv X_{-j}^\top X_{-j} \end{aligned} ここで、$X_j$は$X$の$j$列目を抜き出した$p$行$1$列ベクトル、$X_{-j}$は$X$から$j$列目を除いた$p$行$p$列の行列である。 シューアの補行列を用いて$\tilde r ^{-1}$の$(1,1)$成分を求める事ができる。 \begin{aligned} (\tilde{r}^{-1})_{1,1} &= \left( \tilde{r}_{1,1} - \tilde{r}_{1,-1}(\tilde{r}_{-1,-1})^{-1}\tilde{r}_{-1,1} \right) ^{-1} \\ &= \left( r_{j,j} - r_{j,-j}(r_{-j,-j})^{-1}r_{-j,j} \right) ^{-1} \\ &= \left( r_{j,j} - r_{j,-j}(r_{-j,-j})^{-1}r_{-j,j} \right) ^{-1} \end{aligned} ここで、カッコ内の二項目について、 \begin{aligned} r_{j,-j}r_{-j,-j}^{-1}r_{-j,j} &= r_{j,-j}(r_{-j,-j})^{-1}r_{-j,-j}(r_{-j,-j})^{-1}r_{-j,j} \end{aligned} とし、右から2つの変数に注目すると、 (r_{-j,-j})^{-1}r_{-j,j} = (X_{-j}^\top X_{-j} )^{-1}X_{-j}^\top X_{j} となる。ところで、$X_{j}$ベクトルを目的変数、$X_{-j}$を説明変数の計画行列としたときの重回帰モデルを最小二乗法で解いたときの偏回帰係数は次のように書ける。 X_j = X_{-j}\hat{\boldsymbol{\beta}}_{\ast j} \xrightarrow{OLS} \hat{\boldsymbol{\beta}}_{\ast j} = (X_{-j}^\top X_{-j})^{-1}X_{-j}^\top X_{j} これは先程の量と一致している。したがって次のようになる。 \begin{aligned} r_{j,-j}r_{-j,-j}^{-1}r_{-j,j} &= r_{j,-j}(r_{-j,-j})^{-1}r_{-j,-j}(r_{-j,-j})^{-1}r_{-j,j} \\ &= \hat{\boldsymbol{\beta}}_{\ast j}^\top r_{-j,-j}\hat{\boldsymbol{\beta}}_{\ast j} \\ &= \hat{\boldsymbol{\beta}}_{\ast j}^\top X_{-j}^\top X_{-j} \hat{\boldsymbol{\beta}}_{\ast j} \end{aligned} したがって、 \begin{aligned} r_{j,j} - r_{j,-j}(r_{-j,-j})^{-1}r_{-j,j} &= X_j^\top X_j - \hat{\boldsymbol{\beta}}_{\ast j}^\top X_{-j}^\top X_{-j} \hat{\boldsymbol{\beta}}_{\ast j} \end{aligned} これは$X_{j}$ベクトルを目的変数、$X_{-j}$を説明変数の計画行列としたときの重回帰モデルの残差平方和$\mathrm{RSS}_j$になっている。また、$\mathrm{RSS}_j$は目的変数の分散と決定係数を用いて次のように書ける。 \begin{aligned} \mathrm{RSS}_j &= nV_{j} (1-R_j^2) \\ V_j &= \mathrm{Var}_j[x_{ij}] = \frac{1}{n}\sum_i(x_{ij} - \bar x_{j})^2 \\ \end{aligned} 以上より、$\hat\beta_j$の分散は次のようになる。 \begin{aligned} \mathrm{Var}[\hat\beta_j] &= \sigma^2 \left((X^\top X)^{-1}\right)_{jj} \\ &= \sigma^2 (\tilde r^{-1})_{1,1}\\ &= \frac{\sigma^2}{\mathrm{RSS}_j} \\ &= \frac{\sigma^2}{nV_{j}}\cdot \frac{1}{1-R_j^2} \end{aligned} もし、説明変数間に相関がなければ$1/(1-R_j^2)=1$となり、シンプルな形になる。$1/(1-R_j^2)$をVariance inflation factor(VIF)と呼び、多重共線性の指標として使われる。 \mathrm{VIF} = \frac{1}{1-R_j^2} 説明変数$x_j$が他の説明変数と相関を持っていると$\mathrm{VIF}$が大きくなり、推定値$\hat \beta_j$の分散が大きくなってしまう。 $\hat \beta_j$を標準化することで標準正規分布に従う統計量を作ることができる。 z = \frac{\hat \beta_j - \beta_j}{\sqrt{\mathrm{Var}[\hat\beta_j]}} ただしこの統計量は分母に未知の母分散$\sigma^2$を含む。そこで$\sigma^2$を標本による不偏推定量$s^2$で置き換える。 s^2 = \frac{\sum_i (\hat y_i - y_i)^2}{n-p-1} これによって$t$統計量が得られる。 t = \frac{\hat \beta_j - \beta_j}{\sqrt{\frac{s^2}{nV_{j}}\cdot \frac{1}{1-R_j^2}}} Pythonで確認 statsmodelsを使って$\hat\beta_j$の標準偏差が計算されていることを確認する。 ライブラリ読み込み。 import numpy as np import statsmodels.api as sm from statsmodels.iolib.summary import Summary from sklearn.linear_model import LinearRegression データ生成。 _rand = np.random.RandomState(0) size = 1000 mean = [0.0, 3.0] s_x, s_y, rho = 1.5, 0.4, 0.9 cov = [[s_x**2, rho*s_x*s_y], [rho*s_x*s_y, s_y**2]] sigma = 1.0 X = _rand.multivariate_normal(mean, cov, size) beta = (11, -7) y = X@beta + _rand.normal(0, sigma, size) 回帰分析。 model = sm.OLS(y, sm.add_constant(X)) res = model.fit() print(res.summary()) OLS Regression Results ============================================================================== Dep. Variable: y R-squared: 0.995 Model: OLS Adj. R-squared: 0.995 Method: Least Squares F-statistic: 1.023e+05 Date: Sun, 10 Oct 2021 Prob (F-statistic): 0.00 Time: 05:21:26 Log-Likelihood: -1371.6 No. Observations: 1000 AIC: 2749. Df Residuals: 997 BIC: 2764. Df Model: 2 Covariance Type: nonrobust ============================================================================== coef std err t P>|t| [0.025 0.975] ------------------------------------------------------------------------------ const 0.3844 0.530 0.726 0.468 -0.655 1.424 x1 11.0419 0.047 233.107 0.000 10.949 11.135 x2 -7.1454 0.176 -40.503 0.000 -7.492 -6.799 ============================================================================== Omnibus: 4.491 Durbin-Watson: 1.843 Prob(Omnibus): 0.106 Jarque-Bera (JB): 3.946 Skew: -0.084 Prob(JB): 0.139 Kurtosis: 2.742 Cond. No. 59.3 ============================================================================== Warnings: [1] Standard Errors assume that the covariance matrix of the errors is correctly specified. beta std err はbseメソッドで取り出せる。 print(res.bse) # [0.52980866 0.04736827 0.17641412] scikit-learnのLinearRegressionを使って説明変数間の回帰分析を行って、$\hat\beta_j$の標準偏差を計算してみる。 clf = LinearRegression() clf.fit(X[:, 1].reshape(-1, 1), X[:, 0]) R2_x = clf.score(X[:, 1].reshape(-1, 1), X[:, 0]) n = len(X) var = np.std(res.resid)**2 / (n * np.var(X[:, 0]) * (1 - R2_x)) std_err = np.sqrt(var) print(std_err) # 0.04729716648088632 clf = LinearRegression() clf.fit(X[:, 0].reshape(-1, 1), X[:, 1]) R2_y = clf.score(X[:, 0].reshape(-1, 1), X[:, 1]) n = len(X) var = np.std(res.resid)**2 / (n * np.var(X[:, 1]) * (1 - R2_y)) std_err = np.sqrt(var) print(std_err) # 0.17614930098797998 多少の誤差はあるが、statsmodelsの結果と一致している。statsmodelsは説明変数間の相関の効果まで含めてstd err を計算してt値を表示していることがわかる。 もちろん、計画行列の$X^\top X$逆行列からも求められる。 X_ = sm.add_constant(X) std_err = np.sqrt(np.std(res.resid)**2*np.diag(np.linalg.inv(X_.T@X_))) print(std_err) # [0.52901335 0.04729717 0.1761493 ]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

書籍「最短コースでわかる PyTorch &深層学習プログラミング」紹介

はじめに  2021年 9月17日に日経BP社より出版した書籍「最短コースでわかる PyTorch &深層学習プログラミング」の筆者です。当記事ではこの本の特徴をご紹介したいと思います。 Amazonリンク(単行本) https://www.amazon.co.jp/dp/4296110322 Amazonリンク(Kindle) https://www.amazon.co.jp/dp/B09G622WB6 本書サポートサイト (Github) https://github.com/makaishi2/pytorch_book_info/blob/main/README.md 本書の目的  本書の目的を一言で簡単に説明すると、 「ディープラーニングのプログラムを自分でバリバリ書いて画像分類ができるようになりたい」 人向けの書籍ということになります。  筆者は、過去に日経BPから出版した2冊が、幸いにも好評を得ているのですが、それぞれの本の目的を同じように一言で表すと次のようになります。 「最短コースでわかる ディープラーニングの数学」 ディープラーニングの学習アルゴリズムを数学の立場で理解したい 「Pythonで儲かるAIをつくる」 AI(機械学習モデル)にどんな種類のものがあり世の中でどのように活用されているのか知りたい 想定読者 当書籍で読者と想定しているのは、およそ下記の4つのパターンの方です。 企業でディープラーニングプログラムを業務で利用している、あるいはこれから利用しようとしているITエンジニアや研究者  Keras/Tensorflowを使った経験がある方は、まずPyTorch独特の「ポリシー」につまずきがちです。PyTorchは「多値分類モデルにおける損失関数」の考え方が独特で、それを分かりやすく解説します。 入門書を読んで機械学習やディープラーニングアルゴリズムの実装イメー ジは持てたが、この先どのように活用したらよいかがわからない方  9 ~ 12 章の「画像認識 実践編」では、最終的に「転移学習」と呼ばれる少ない学習データで学習可能な方法を用いて、自分で集めた画像データを使って 分類モデルを作ります。12 章までたどり着けば、すぐに自分で集めた画像デー タを使って分類モデルが作れるようになります。 また、8 章までの内容は PyTorch でのプログラミング方法を理解すると同時 に、これまで入門書で学んだ機械学習やディープラーニングのアルゴリズムを 復習することにもなります。 理工系の大学・大学院の学生で研究の一環としてディープラーニングのプログラムを開発する必要がある方  今後、論文で公開されている実装コードを試すには、PyTorchの知識が必須になってきます。本書では、ディープラーニングに必要な数学をイメージとして解説するので、公開コードを深く理解し、応用できるようになります。 まだPythonもKeras/TensorFlowも知らないが、ディープラーニングプログラミングをこれから勉強してみたいという方  初心者に向けて、PyTorchプログラミングを理解するのに必要な、Pythonの基本文法と、NumPy、Matplotlibの必要最小限の機能を、巻末の講座として用意しました。目的がディープラーニングだけなら、本書の講座で書いた概念・機能だけを理解すれば十分で、ディープラーニングを学ぶためのスタートラインに立てます。 構成  本書の構成は以下のとおりです。 序章 初めての画像認識 ◆基礎編 1 章 ディープラーニングのためのPython のツボ 2 章 PyTorch の基本機能 3 章 初めての機械学習 4 章 予測関数の定義 ◆機械学習 実践編 5 章 線形回帰 6 章 2 値分類 7 章 多値分類 8 章 MNIST を使った数字認識 ◆画像認識 実践編 9 章 CNN による画像認識 10 章 チューニング技法 11 章 事前学習済みモデルの利用 12 章 カスタムデータの画像分類 講座 Python入門 NumPy入門 Matplotlib入門  大きくは、次のようなことが各パートの目的となっています。 序章: 本書で最終的にめざすことがなんであるかを実習を通じて確認 基礎編: ディープラーニングプロフラミングをする上で最低限必要な基礎知識の習得 機械学習 実践編:モデルのパターンを一歩ずつ進化させることで、最終的な目的である画像を対象とした多値分類モデルに近づく 画像認識 実践編:実用レベルの画像認識モデルの実装理解 講座 : 本書を読み進める上で最低限必要なPyThonやライブラリ知識のまとめ 特徴 当書籍の特徴として以下のような点があげられます。 可視化によるわかりやすさの追求  筆者は、初心者が抽象的概念を理解する上で、可視化が重要な役割を果たすと考えています。本書では、抽象的な概念が多く、理解の難しいPyTorchに対して徹底的な可視化を試みました。具体的には、以下のような点となります。 見開きコースマップ  本書の見開きには、カラーのコースマップがあり、それぞれの章で登場する重要概念が一目でわかるようになっています。全体で500ページ超と大部の書籍ですが、このマップを見ることで、自分が今、どこにいるかを常に確認することができます。   学習アルゴリズムのフロー図  機械学習の繰り返しアルゴリズムとは、結局「予測計算」「損失計算」「勾配計算」「パラメータ修正」の4つのステップの繰り返し処理です。その処理イメージを下の図で表現しました。 PyTorch実装のフロー図  上の機械学習アルゴリズムが、PyTorchではどのような実装(コード)になるか、上の抽象的な処理を実装コードで具体化したフロー図も作りました。 計算グラフの可視化  PyTorchの特徴の一つは「Define by Run」という言葉に代表される「計算グラフ」とよばれるデータ構造を計算式から自動生成し、その計算グラフを元に、勾配(微分)計算を行う点にあります。この計算グラフはフレームワークだけでは、どの様な形になっているか読み取ることができないのですが、別のOSSのツールを利用することで可視化できます。そこで本書ではこの計算グラフの可視化ツールを書籍全体を通じて数多く利用することとしました。下にその例を示します。このような計算グラフの可視化も、可視化により理解しやすくなる一つの事例です。 実装コード  本書はプログラミングを目的とした書籍です。なので実装コードにはこだわったつもりです。具体的には、以下のような点に配慮をしています。 Google Colab で事前セットアップなしにすぐに動かせる  ディープラーニングのプログラム環境の場合、GPUの準備や、ライブラリ追加導入など、プログラムを開始するまでの準備に相当手間がかかるのが通常です。本章で、Google Colabを前提にすることで、その課題をクリアしました。読者は、何の準備もなしにいきなりプログラムができる状態になる様子を序章の実習ですぐに体験することができます。   汎用性を考えた実用的なコード  実装コードは、常に汎用性を考えています。例えば12章の最後の例題では、学習データのzipファイルを差し替えるだけですぐに自分の学習モデルを作ることができます。よく使う機能は共通関数としてGithubにアップしてあり、自分のコードからこの関数を利用することも可能です。 豊富なコメント  コードは、基本的に1行1行に対して詳しいコメントをつけています。ある程度プログラミングに慣れた読者であれば、ソースコードをみるだけでおおよそどんなことをやっているのか、わかるかもしれません。 解説内容  解説内容に関しては、とにかく「丁寧に、どんな読者にも理解できるように」を心がけました。具体的には、以下のような点が特徴になっています。 1冊で全領域をカバー  PyTorchの場合、入門書であっても、PythonやNumPyの基本文法、あるいはオブジェクト指向プログラミングなど、読者にある程度の前提を課してしまうことが多いです。本書では、そのようなことはせず、Pythonの基本文法やNumPy、あるいはオブジェクト指向プログラミングの考え方など、必要な概念はすべて一通り解説しました。その結果、この本1冊で、ディープラーニングプログラミングをするのに必要な知識は一通り付けられるようになったと考えています。 勾配降下法もイメージから理解  ディープラーニングのアルゴリズム理解で、数学的に一番高いハードルは勾配降下法です。本書では山登りのたとえ話をつかって、数式に頼らずイメージで勾配降下法を理解できるようにしました。  Keras/TensorFlowとの違いを丁寧に解説  筆者がPyTorchを勉強して一番戸惑ったのは、特に多値分類の時の損失関数の考え方がKeras/Tensorflowと大きく異なる点でした。この点に関しては、6章と7章で詳しく解説してあり、筆者同様Keras/TensorflowからPyTorchに入った読者が躓くことがなくなります。 リンク集  本書に関しては、Amazonレビューや個人のブログで大変好意的なコメントをいただいています。その一部をご紹介します。 ソース タイトルとリンク 補足 Amazon Amazonレビュー からあげ様ブログ PyTorch入門書の決定版!「最短コースでわかる PyTorch &深層学習プログラミング」 AI関連で有名なブロガーである「からあげ」様による書評です。 新米エンジニアの読んだ技術書を一言まとめるブログ Pytorch&深層学習プログラミングはやはり初心者の見方だった 本書について激賞していただいています
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Python で iterator を使うときに考える初期化のタイミング

Python のクラスで __iter__ や __next__ を定義すると、そのインスタンスは for 文などで利用できます。 for 文で使うインスタンスを作るクラスを作ってみます。next を呼び出した回数をカウントしながら、1ずつ増やした数値を返し、規定の回数に到達したら StopIteration を出してループを終了させるようにします。 forで使うクラス class Iterator: def __init__(self): print("init") self.chunk = 3 self.number = 0 def __iter__(self): print("iter") self.count = 0 return self def __next__(self): if self.count >= 3: raise StopIteration() self.count += 1 self.number += 1 return self.number インスタンスは、複数回にわたって for 文に渡すことができます。 __init__ が呼ばれるときはインスタンスを定義した最初のみで、 __iter__ は for 文に使う度に呼ばれます。出力を見ると、 print("init") が最初に、 __iter__ が first, second, third の出力の前にそれぞれ出現しているのがわかります。 forを3回用いる iterator = Iterator() for i in iterator: print("first:", i) for i in iterator: print("second:", i) for i in iterator: print("third:", i) 出力 init iter first: 1 first: 2 first: 3 iter second: 4 second: 5 second: 6 iter third: 7 third: 8 third: 9 ここで、クラス内の self.count は __iter__ が呼ばれているため3回リセットされていますが、 self.number は __init__ で初期化しているだけのため、前回のループの値から引き続いて数値が増えていっています。 毎回の for で、 1,2,3 を出力したい場合、今回のように単純なクラスを用いる場合は、毎回インスタンスを作るのでも良いかもしれません。 毎回インスタンスを作る for i in Iterator(): print("first:", i) for i in Iterator(): print("second:", i) for i in Iterator(): print("third:", i) ただし、インスタンスの中でファイルの入出力をしたり、複雑な計算の結果を保存したりしている場合、そのインスタンスの使い回しをしたい場合もあるでしょう。 その場合は、 __iter__ に毎回の初期化処理をしっかり記述することが必要です。 具体例として、 gensim の Word2Vec に文章を渡すとき、容量が多いためファイルを読みながら形態素解析をして、文章を一つずつ書き出していくときに使えます。このとき、イテレーターのインスタンスを引数に与えるわけですが、 Word2Vec は学習時に複数回ループを回すため、 __init__ に全ての初期化処理を記述してしまうと、2回目以降の学習データが全部空になってしまいます。 Python の記事を調べていると、多くのコードで def __iter__(self): の中身が return self だけになっているため、筆者もあまり意識していませんでした。場合によっては致命的な不具合に繋がりかねないため、注意が必要です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[AWS Step Functions] EC2とRDS(Aurora)をグループ単位かつ指定した順番に起動/停止する

はじめに EC2とRDS(Aurora)を、グループ単位かつ指定した順番に起動/停止する仕組みを AWS Step FunctionsとLambda(Python 3.9)で作りました。 もう少し詳しく 作成した StepFunctions ステートマシン の詳細を説明します。 以下のように複数のEC2,RDS(Aurora)がある場合に、タグを使いをグループ化と起動順序を設定します。 タグに必要な情報を設定し、起動したいグループと命令(起動命令 or 停止命令)を指定すると、順番に従いリソースを起動or 停止します。 具体的な設定例も含め説明します。以下図のような構成でEC2,RDS(Aurora)を作成します。 ※図にはリソースごとのタグ情報を記載しています 各リソースにはこのようにタグを設定します。 リソース Nameタグ/DB識別子 Groupタグ BootOrderタグ Group2タグ BootOrder2タグ EC2 tmp1 test1 2 ec2only 1 EC2 tmp2 test2 2 ec2only 2 RDS(Aurora) database-a test1 1 - - RDS(Aurora) database-b test2 1 test2A 1 タグ名 Group,Group2はグループの区分け用のタグです。 タグ名 BootOrder,BootOrder2は起動順番を設定するタグです。 作成した StepFunctions ステートマシンは、実行する際にグループ分けのタグと起動順番のタグを指定することができます。これにより、1つのリソースに、グループ分けと起動順番のタグを複数することが可能にしました。 グループ test1 をすぐに起動する場合 グループ test1 に所属するEC2とRDS(Aurora)を起動します。 StepFunctions実行時の 実行入力 は ↓ です。 { "EXEC": "start", "DATE": "now", "GroupTag": "Group", "GroupValue": "test1", "BootOrderTag": "BootOrder" } ※参考※ 実行入力とは以下図のように、作成したStep Functions ステートマシンを実行するときに設定する引数のようなもので、JSON形式で記載します。     実行入力 の各要素の意味はこちら ↓ 要素 説明 EXEC 実行命令 start or stop DATE 実行日時 YYYY-MM-DDThh:mm:ss+09:00例 2021-10-09T21:40:00+09:00now ←即時実行の場合 GroupTag グループ分けのタグ GroupValue グループ名 BootOrderTag 起動順番のタグ 起動処理は、BootOrderタグの値を昇順で処理します。RDS(Aurora)から起動を開始し、すべてのDBインスタンスが起動完了した後に、EC2が起動開始します。EC2が起動を完了するとStepFunctionsの処理が完了します。 グループ test2 を指定した時刻に停止する場合 グループ test2 に所属するEC2とRDS(Aurora)を停止します。 StepFunctions実行時の 実行入力 は ↓ です。 { "EXEC": "stop", "DATE": "2021-10-09T21:40:00+09:00", "GroupTag": "Group", "GroupValue": "test2", "BootOrderTag": "BootOrder" } DATEに指定した日時(2021年10月9日21時40分)に命令(今回は停止命令)を実行します。 停止処理は、BootOrderタグの値を降順で処理します。EC2から停止を開始し、停止が完了した後に、RDS(Aurora)が停止を開始します。RDS(Aurora)が停止を完了するとStepFunctionsの処理が完了します。 グループ ec2only をすぐに起動する場合 グループ ec2only に所属するEC2を停止します。 StepFunctions実行時の 実行入力 は ↓ です。これまでの例ではグループ分け用のタグは Group でしたが今回は Group2 を使用します。 { "EXEC": "start", "DATE": "now", "GroupTag": "Group2", "GroupValue": "ec2only", "BootOrderTag": "BootOrder2" } グループ test2A をすぐに起動する場合 グループ test2A に所属するRDS(Aurora)を停止します。 StepFunctions実行時の 実行入力 は ↓ です。 { "EXEC": "start", "DATE": "now", "GroupTag": "Group2", "GroupValue": "test2A", "BootOrderTag": "BootOrder2" } 以上で使い方の説明はおわりです。 StepFunctions ステートマシン の紹介 概要 ソースはgithubに置きました。 StepFunctionsのフローです。 3種類のLambda(Python 3.9)スクリプトを使用します。 Lambda (GetTargetResources) 対象のリソース(EC2,RDS)の情報を取得し、起動(or停止)の順番に並べる 起動の場合:起動順場を示すタグ(BootOrderタグ)昇順に並べ替えます 停止の場合:起動順場を示すタグ(BootOrderタグ)降順に並べ替えます Lambda (ExecResource) 実行命令(start or stop)を実行する 実行結果をJSON要素 Response に登録する Lambda (StatusCheck) 対象のリソースの状態(起動中,停止中,初期化中など)を取得する 取得した状態をJSON要素 NextAction に登録する EC2のステータス別の判定 EC2のステータス判定は、インスタンスの状態(InstanceStatuses)(図赤枠)とステータスチェック(InstanceStatus,SystemStatus)(図青枠)で判定します。 EC2の状態判定について EC2の状態判定について、running以外はインスタンスの状態(InstanceStatuses)で判定することにしました。 InstanceStatuses 判定 NONE 起動命令(start)→WAIT停止命令(stop)→NEXT pending WAIT terminated SKIP stopping WAIT stopped 起動命令→WAIT停止命令→NEXT shutting-down WAIT running InstanceStatus, SystemStatusで判定 インスタンスの状態(InstanceStatuses)がrunningの場合は、ステータスチェック(InstanceStatus,SystemStatus)で判定します。 InstanceStatus--SystemStatus--命令 判定 備考 ok--ok--stop の場合 WAIT 起動かつ停止命令(stop) ok--ok--start の場合 NEXT 停止かつ起動命令(start) NONE--NONE--stop NEXT 停止かつ停止命令 NONE--NONE--start WAIT 停止かつ起動命令 impaired含む ERROR 障害発生 insufficient-data含む WAIT データ不足 not-applicable含む WAIT 未適用 initializing含む WAIT 初期化中 その他 WAIT RDS(Aurora)の状態判定について RDS(Aurora)には、DBクラスターとDBインスタンスがあります。DBクラスターを起動すると、DBクラスター配下のDBインスタンスも起動を開始します。指定したRDS(Aurora)の起動が完了したかの判定は、そのDBクラスター配下の全DBインスタンスの状態で判定します。 1つのDBクラスターに複数のDBインスタンスが存在する場合があるので、状態判定はそれら全てのDBインスタンスが起動した場合に起動完了と判定するようにします。 DBインスタンスごとに状態の判定は以下表のようにしました。 DB instance status 判定 available 停止命令(stop)→WAIT起動命令(start)→NEXT backing-up NEXT configuring-enhanced-monitoring WAIT configuring-iam-database-auth WAIT configuring-log-exports WAIT converting-to-vpc WAIT creating WAIT deleting WAIT failed ERROR inaccessible-encryption-credentials ERROR incompatible-network ERROR incompatible-option-group ERROR incompatible-parameters ERROR incompatible-restore ERROR insufficient-capacity ERROR maintenance WAIT modifying WAIT moving-to-vpc WAIT rebooting WAIT resetting-master-credentials WAIT renaming WAIT restore-error ERROR starting WAIT stopped 停止命令→NEXT起動命令→WAIT stopping WAIT storage-full ERROR storage-optimization WAIT upgrading WAIT 全DBインスタンスの状態を1つの変数(allRtnVal)に連結して格納し、以下表の判定条件で状態を判定します。 変数allRtnVal 判定 ERROR 含む ERROR WAIT 含む WAIT その他 NEXT 参考 DBインスタンスのステータス Viewing DB instance status SDK(boto3) EC2 https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html SDK(boto3) RDS https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/rds.html さいごに モタモタしてたらStep Functionがアップデートしてました。新機能を使って、今回作ったステートマシンをアップデートできたらまたQiitaで紹介しようと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python】pandas-datareaderで取得した株価データをデータベースにキャッシュして高速化

Pythonを用いて株価を取得した後、同じデータを使って繰り返し分析するときに再度株価を取得するようにしてしまうと時間がかかってしまい、非効率です。 そこで、取得した株価データをデータベースにキャッシュ(cache)して、それを使いまわすことで作業を効率化してみます。 実行環境: Windows10 ※元記事はこちら 株価の取得 株価の取得にはpandas-datareaderを使います。 pandas-datareaderのインストール pip install pandas_datareader ※pandas-datareaderの使い方に関してはPythonのpandas datareaderをインストールして株価データを取得する方法【日本株・米国株】をご覧ください。 株価を取得してキャッシュする 株価をキャッシュするには、requests_cacheというモジュールを使います。 pip install requests_cache キャッシュための下準備 以下は、キャッシュのための準備です。 from datetime import timedelta from requests_cache import CachedSession expire_after = timedelta(days=3) # 3日間キャッシュする session = CachedSession(cache_name='cache', backend='sqlite', expire_after=expire_after) session.headers = { 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0', 'Accept': 'application/json;charset=utf-8'} expire_afterは、キャッする期間です。 sessionのbackend=’sqlite’が、SQLite(データベース)にキャッシュすることを意味します。 株価の取得 import datetime import pandas_datareader.data as web start = datetime.date(2018,1,1) end = datetime.date(2021,1,1) # 株価チャートの取得 origin = web.DataReader('AAPL', 'yahoo', start, end, session=session)['Adj Close'] 株価チャートの取得でのsessionオプションがポイントです(キャッシュしない場合は、これを削除すればよいです)。 これを実行すると、cache.sqliteというファイルが実行ディレクトリに作成され、AAPLの株価チャートのデータはキャッシュされます。 次の実行からは同じデータはキャッシュから呼び出されるので、APIから取得する時間はかかりません。 このような一つの銘柄だけではキャッシュしたありがたみが感じられませんが、たくさんのデータを取得したときにはキャッシュは作業効率化に有用です。 本記事のより詳しい説明および応用は以下の記事をご覧ください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pythonで初めてwebスクレイピングしてみる

この記事で行うこと じゃらんの口コミをスクレイピングで取得し、ローカルのエクセルにcsv形式で出力・保存。 スクレイピング対象のURLは下記になります。 https://www.jalan.net/yad330474/kuchikomi/?screenId=UWW3001&yadNo=330474&smlCd=012102&distCd=01 環境 Python3.9 windows10 jupyter notebookのセットアップ ①jupyterをインストール pip install jupyter ②requestsをインストール pip install requests ③pandasをインストール pip install pandas ④beautiful soup4をインストール pip install bs ⑤jupyter notebook起動 python -m notebook ⑥プルダウンからPython3を選択 ⑦コードを記述&実行 コードを記述し、Alt + Enterまたは実行ボタンで実行するとjupyter上で出力及びローカルにエクセルが出来ています。 今回出力形式が日本語のため、文字化け解消にutf_8_sigを記述しています。 import requests from bs4 import BeautifulSoup r = requests.get("https://www.jalan.net/yad330474/kuchikomi/?screenId=UWW3001&yadNo=330474&smlCd=012102&distCd=01") c = r.content soup = BeautifulSoup(c, "html.parser") all=soup.find_all("p",{"class":"jlnpc-kuchikomiCassette__postBody"}) l=[] for item in all: d={} d["クチコミ"]=item.text l.append(d) import pandas df=pandas.DataFrame(l) df.to_csv("じゃらん.csv", encoding='utf_8_sig') df
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VScodeでpythonの実行pathをInterpreter Pathと一致させる

VScode使用時、PythonのInterPreterPathとPythonPathを一致させるにはどうしたらいいのかと思い色々調べたのでそれのメモです。 Anaconda等を使用していて複数の仮想環境を使う人に向けて参考になればと思います。 すぐに解決したい人向け ${config:python.defaultInterpreterPath}をPython Pathの設定に書き込みましょう。おわり。 Variablesを使おう 拡張機能>Python>拡張機能の設定 で設定画面まで移動したら、まずはInterPreterPathを探します。 検索ボックスに @ext:ms-python.python Default Interpreter Path と入れれば出てきます。 今回はAnaconda3を使用しているとして、次のように設定します。MyNameとMyEnvsはそれぞれあなたのユーザー名と仮想環境名が入ります。 C:\Users\MyName\anaconda3\envs\MyEnvs\python.exe で、問題なのがPython Pathです。同じく検索ボックスから @ext:ms-python.python Python Path で探せば出てきます(下の方にあります)。 そのままパスを入力しても良いのですが、それだと環境を変えてInterPreterPathを変更した時に逐一Python Pathを設定から変える必要があります。InterPreterPathはコマンドパレットなり左下をクリックなりでサッと変更できるのに面倒くさいですね。 ということでVariablesを使います。要は設定で使える特殊な変数群のことです。 VSCodeの公式サイトにリファレンスがあります。 ここでざっと見てみると、 Configuration variables You can reference VS Code settings ("configurations") through \${config:Name} syntax (for example, \${config:editor.fontSize}). これが使えますね。InterPreterPathの設定をそのまま引っ張ることができればよいわけですから、次のようにPython Pathに記述してあげればOKです。 ${config:python.defaultInterpreterPath} これで無事InterPreterPathを変更した時に一緒にPython Pathも変更されるようになりました。おしまい。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

コンピュータとオセロ対戦17 ~遺伝的アルゴリズム、乱数~

前回 今回の目標 前回の考察に従い、15で行った遺伝的アルゴリズムの改善案を試します。 まずは乱数から。 ここから本編 本題ではありませんが、マクロで以下のように表記を変更しています。 static_cast<int>(num) => INT(num) static_cast<double>(num) => DOUBLE(num) 「static_cast<BOARD>(num)」についてはいい別名が思いつかなかったのでそのままです。 また、「read_goal」を要素2個の一次元配列に変更し、それぞれ黒と白の「何手先まで読むか」の数字としました。今回はあまり関係ないです。 srandへの引数を変える クラス内で新たに「srand_num」というpublic変数を用意し、クラス内でこれをsrand関数の引数に使うことで、外部からこの値を書き換えればsrand関数への引数を変えられるようにしました。 実行ファイルは以下の通り。 なお、15で使用した「run_1hand_rand」の改造です。 また、よく考えたらepoc変数が名前と全く関係のないことをしていたのでchildに改名しました。 run_1hand_rand.cpp #include "osero_genetic.h" const int child = 30; const int entire = 1000; int main(void){ int win, win_sum; int i, j, k; double eva[child][64], new_eva[child][64]; osero_genetic * run; FILE * fp = fopen("data_1hand_rand.csv", "w"); printf("progress "); for (i = 0; i < child; i++) printf("."); printf("\n"); fprintf(fp, "num,win_per\n"); srand(0); for (i = 0; i < child; i++) for (j = 0; j < 64; j++) eva[i][j] = DOUBLE(rand()) / (RAND_MAX >> 1) - 1; for (i = 0; i < entire; i++){ printf("%3d/%3d: ", i + 1, entire); win_sum = 0; for (j = 0; j < child; j++){ printf("."); run = new osero_genetic( INT(PLAY_WAY::nhand), eva[j], INT(PLAY_WAY::random) ); run -> read_goal[INT(TURN::black)] = 1; run -> srand_num = i + j; win = INT(run -> play()); if (win) { for (k = 0; k < 64; k++) new_eva[win_sum][k] = eva[j][k]; win_sum++; } delete run; } if (win_sum){ for (j = 0; j < child; j++){ for (k = 0; k < 64; k++){ if (rand() % 100 > 5) eva[j][k] = new_eva[rand() % win_sum][k]; else eva[j][k] = DOUBLE(rand()) / (RAND_MAX >> 1) - 1; } } } printf("\n"); fprintf(fp, "%d,%d\n", i, win_sum); } fclose(fp); fp = fopen("eva_1hand_rand.csv", "w"); for (i = 0; i < child; i++){ for (j = 0; j < 64; j++){ fprintf(fp, "%2.4f", eva[i][63 - j]); if ((j + 1) % 8 == 0) fprintf(fp, "\n"); else fprintf(fp, ","); } fprintf(fp, "\n"); } fclose(fp); return 0; } ここには載せませんが、15で作成した「run_1hand_1hand」についても同様の変更をしました。 実行結果 15と同様、Excelで評価値に色を付け、Pythonでグラフを書きました。 run_1hand_rand run_1hand_1hand run_1hand_1hand 1000回 ここで、run_1hand_randと同様に、run_1hand_1handについても1000回進化させてみました。 run_2hand_2hand ついでに2hand VS 2hand、黒側が強化学習をやってみました。 進化回数は1000回です。 まあまあ時間かかりました。 全体 ついでに、前回作成した、データの平均と分散を求めるプログラムを以下のように改造し実行してみました。 大した改造ではないですが、私自身がこれをできることを知らなかったので載せます。 data.py import pandas as pd import glob for filename in glob.glob("data*.csv"): df = pd.read_csv(filename) per = df["win_per"] print(filename, ": ") print("mean:", per.mean()) print("var: ", per.var()) print() 実行結果は以下の通り。 data_1hand_1hand.csv : mean: 17.639 var: 10.154833833833834 data_1hand_rand.csv : mean: 16.943 var: 7.953704704704704 data_2hand_2hand.csv : mean: 16.62 var: 9.575175175175175 考察 まず本題 まずは本題、「srand関数の引数を逐次変えることで学習結果はどうなるか」ですが、平均を見る限りやはり0は前回予想した通りプレイヤー側に有利となる数字であると考えられます。 理由は同じプログラムなのに今回のほうが勝率が下がったからです。 今後は今回のように、srand関数の引数は逐次更新していきたいと思います。 谷部分 次に気になったのは、1000回学習させたデータについて、800回付近で一度勝率が下がっていることです。 全てのデータを記録したグラフでは分かりづらいですが、数回ごとの平均を記録したグラフでは分かりやすいと思います。 理由として考えられるのは二つあります。一つ目は、「800付近が極端にプレイヤー(役)に有利なsrand引数なのでは?」ということです。これは、実際0がコンピュータに有利な数字だったことからも可能性が高いと思います。 二つ目として考えられるのは過学習や局所解です。しかし、学習後の評価値が本当に正しいのか? がよく分からないため検証の必要があると思います。ですが可能性としてはあり得ると考えます。2hand_2handでその特徴が顕著ですが、青と赤の配置が、3つの最終評価値で似た形になっています。「端の評価値が高く、その隣は低くなるはず」という当初の予想とは違うものの一応一つのパターンを作っているのが分かります。 つまり、「これは局所最適解である」または「実はこれが最適解である」、このどちらかが考えられるのでは? といえます。 フルバージョン randフォルダ内に入っています。 なお、data_1hand_1hand.csv及びeva_1hand_1hand.csvの中身は1000回進化時のものが入っています。 実際にやってみた やってません。 次回は 今回得られた評価値がどの程度正しいものなのかについて検証していきたいと思います。 進化方法や突然変異の割合をいじるのはその後に行いたいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PythonでLINEトークを分析するWebアプリケーションをデプロイしてみた!(Flask + Heroku + PostgreSQL)

概要 この記事では、webアプリケーション開発の「ウェ」の字も知らない筆者が、FlaskとHerokuを利用してwebアプリケーションをデプロイするまでの記事になります。 自作のwebアプリケーションを作ってみたい! Pythonを用いた開発をしてみたい! LINEで話す相手が本当に自分のことを好きなのか確かめたい。 というような願望をふわっと抱いたことのある方に刺さるよう書こうと思いますので、どうぞよろしくお願いします。 こちらが作成したアプリへのリンクです。 本記事の流れ pythonで分析 Flaskサーバー構築 フロントを書く ローカルでの実行テスト 必要機能追加 データベース機能追加 Heroku移行してデプロイ 追記したい記事 ・ 分析のpythonスクリプト一部抜粋 ・ MySQLからPostgreSQLにDB移行する流れ → 本来はダンプするのが常識らしい 前提 以下は筆者のアプリ作成時のステータスです。 サーバーやネットワークの知識は基本情報試験並みかそれ以下 webアプリケーション開発やデプロイは未経験 Pythonによるデータ分析はそこそこできる(調べればわかる) HTML, CSS, JavaScriptが大体書ける(又は見たらわかる) こんな感じの筆者が0→1で作成しました。 開発phaseで一般的な開発常識を外れることがありますがご了承ください。 作成するもの 1番最初に表示されるページがこちらです。 分析結果を表示させるページがこちらです。 実行環境 MacOS BigSur python 3.8.11 Flask 2.0.1 heroku 7.56.1 MySQL postgreSQL 1. LINEのテキスト分析 pythonでLINEのトークスクリプトを分析します。 LINEのテキスト分析は別のQiita記事を書こうと思いますので、そちらを参考にしてください。 [執筆中] 2. Flaskアプリの作成 とりあえずローカル環境でflaskアプリを動作させることを目標にします。 Flaskインストール pip install flask 開発環境はご自身で作成してください。僕はanacondaの仮想環境上で開発しました。 Flaskサーバーの構築 全体のディレクトリ構造はこんな感じです。 project |── app.py // 実際に実行するpythonファイル └── templates                    |── index.html // webページを書くところ                    └── result.html // 分析結果を表示するページ で、app.pyを書いていきます。 from flask import Flask from flask import render_template from flask import url_for app = Flask(__name__, static_folder='static') @app.route('/') def main(): return render_template('index.html', title='LINE TALK ANALYSIS') @app.route("/templates", methods=["GET"]) def index(): return render_template("index.html") if __name__ == "__main__": # webサーバー立ち上げ app.run(debug=True, host="127.0.0.1", port=8085) これでFlaskサーバーを立ち上げることができ、ローカル環境でwebアプリを起動することができます。 この段階ではまだ表示するwebページを何も書いていないのでindex.htmlを書きに行きます。 3. HTMLを書く ひとまずはチュートリアルとしてローカルで動くところまで持っていければいいので、シンプルにいきましょう。 <head> test output </head> <boby> <h1> Hello World </h1> </boby> これを、上記のwebアプリのディレクトリ構造に合うようtemplatesフォルダの内部に作成しておきます。 textファイルをflaskサーバーで受け取ったり、分析結果をwebブラウザに送ったりする作業は少し手間なので保留して、一旦webページを表示させてみます。 4. ローカルでの実行テスト 以下はtarminalで実行する内容です。 // 今回のprojectディレクトリへ移動 $ cd project // python実行 $ python app.py これで表示されるURLをブラウザに打ち込むとHello Worldと表示されるはずです。 以上で、ローカルでの動作確認は完了です。 flaskのチュートリアルはこんな感じで、必要機能の実装をしていきましょう! 5. 必要機能追加 追加で必要な機能は、 ユーザーからflaskサーバーにテキストファイルを送信する機能 取得したテキストファイルを分析する機能 分析結果をクライアント側に返す機能 返ってきた結果をかっこよく表示させるページ です。なのでまず、テキストファイルを受け取りに行きます。 textファイルを送信するボタン追加 下記のrequest.files['ファイル名'] でtextファイルを読み込むことができます。 @app.route('/',methods=['POST']) def post(): input_text = request.files['file1'] 変数 = 分析結果を返す関数(input_text) return render_template('result.html', result.htmlで出力したい変数) html側では、以下をボタンとして追加します。 <form method="post" enctype="multipart/form-data"> <label for="file1">アップロードするファイルを選択してください</label> <input type="file" id="file1" name="file1" multiple> <div> <button>送信</button> </div> </form> 参考にしたドキュメント https://msiz07-flask-docs-ja.readthedocs.io/ja/latest/patterns/fileuploads.html 取得したファイルを分析する機能 詳しくはGithubのコードを参照してもらい、ここでは簡単な関数を記載します。 def get_result(input_text): line_df = pandas.read_csv(input_text, sep='\n') line_df = line_df.rename(columns={line_df.columns[0]:'talks'}) line_df = line_df[1:] # 正規表現でトークから日付を取得し新しいカラムとして結合する date_list = [] date_pattern = '(\d+)/(\d+)/\d+\(.?\)' for talk in line_df['talks']: result = re.match(date_pattern, talk) if result: date_t = result.group() date_list.append(date_t) else: date_list.append(date_t) line_df['date'] = date_list flag = line_df['talks'].isin(line_df['date']) line_df = line_df[~flag] line_df.dropna(inplace=True) time_l = [] user_l = [] talk_l = [] date_l = [] count = 0 for date, talk in zip(line_df['date'], line_df['talks']): # もし正規表現で時間が取れたらスプリットして3つに分ける if(re.match('(\d+):(\d+)', talk)): try: if(len(talk.split('\t')[0]) == 5): date_l.append(date) time_l.append(talk.split('\t')[0]) user_l.append(talk.split('\t')[1]) talk_l.append(talk.split('\t')[2]) count = count + 1 else: continue except: talk_l.append("メッセージの送信取り消し") count = count + 1 else: talk_l[count-1] = talk_l[count-1] + talk line_df = pandas.DataFrame({"date" : date_l, "time" : time_l, "user" : user_l, "talk" : talk_l}) user1 = line_df['user'].unique()[0] user2 = line_df['user'].unique()[1] user1_len = len(line_df[line_df['user']==user1]) user2_len = len(line_df[line_df['user']==user2]) return user1_len, user2_len, user1, user2 テキストファイルをpython側で受け取ったら、データの分析がしやすいようにデータを整形する作業から始めます。 テキストファイルは読み込んだ際、日時:名前:トーク という形式のデータなのですが、トークの中にタブが含まれていたりと不都合が多いので、一旦読み込んでから正規表現でデータを分解してカラムに加えています(ただのゴリ押しなのでお勧めしない方法です。) データの整形が終わったらあとは各々が好きに分析すればよく、今回は簡単にするために、 トークしているユーザーの名前 各ユーザーの喋った総回数 を返す関数を作成しました。 分析結果を返す機能 クライアント側で最終的に表示させたい数値等のデータ(分析結果)を、flaskのrender_templateという関数で返してもらいます。 def post(): input_text = request.files['file1'] user1_len, user2_len, user1, user2 = get_result(input_text) return render_template('result.html', user_name1=user1, user_name2=user2, user1_len=user1_len, user2_len=user2_len) return文でrender_templateを用いており、user_name1,user_name2,user1_len,user2_lenを、それぞれresult.htmlで利用できるように投げています。 こちらがrender_templateのドキュメントで、 https://msiz07-flask-docs-ja.readthedocs.io/ja/latest/tutorial/templates.html こちらが参考にした記事です。 https://qiita.com/nagataaaas/items/4662237cfb7b92f0f839 返ってきた結果をかっこよく表示させるページ ここから先はJava Script書いて行きます。 本記事の趣旨とはズレるため、専用の記事を書くまでは上げているGithubを参考にしてください。 もしくは、自分がこちらの記事を参考にして作成したものなので合わせてご参照ください。 https://qiita.com/Haruka-Ogawa/items/59facd24f2a8bdb6d369 https://news.mynavi.jp/article/zerojavascript-3/ 6. データベース接続 ここからが2つ目の壁でした。 私は最初MySQLを利用していたのですが、HerokuサーバーとMySQLは互換性が悪いらしく、うまくDBを乗っけることができなかったので Flask + Herokuでデータベースと接続したい時はPostgreSQL利用すると楽そうです。 (ローカル環境ではMySQLで動いているので一旦MySQLの接続までを書きます。) DBに接続情報を書く 以下の関数を用いると、ローカルで作成したsampleというDBに接続することができます。 (事前にDBは作成している必要がありますが、作成に関してはこの辺の記事を参考にしました。) https://www.dbonline.jp/mysql/database/index1.html https://prog-8.com/docs/mysql-database-setup app.py def conn_db(): conn = mysql.connector.connect( host = 'localhost', port = '3306', user = 'root', password = 'root', db = 'sample' ) return conn conn = conn_db() # DB接続 cursor = conn.cursor() # カーソルを取得 cursor.execute('####') # クエリを書く conn.close() # DB切断 DBに接続してからは テーブルの作成 データ取得 データ追加 の動作を行って最後に切断すればアプリのバックエンド側でDBを触ることができます。 さぁこれでアプリケーションに必要な機能が全て揃いました! ローカルで遊ぶ分には困らないと思います! が、せっかく作成したのでポートフォリオにするためにもデプロイしたいの思うのが人間の性。 なんならデプロイせんと意味がない。 ですので、MySQL → PostgreSQLに移行することで、 ローカルで作成したアプリをHerokuデプロイします。 7. herokuデプロイ 必要ファイルの作成 Herokuアカウント作成 HerokuでDB作成 Python script側のDB接続情報を変更する この流れでデプロイしていきます。 herokuデプロイに必要なファイル作成 まず最初に、デプロイするプロジェクトファイルの構造を整理しておきます。 project--templates/ |_Procfile |_app.py |_runtime.txt |_requirements.txt このような階層構造にしています。 ここから、まだ作成していない3つのファイルを作成します。 runtime.txt pythonのバージョンを記載したruntime.txtを作成します。 以下のコマンドだと、読み取れる表記と異なる場合があるため、ハイフンの位置等に注意してください。 python --version > runtime.txt requirement.txt 次に、関連モジュールの一覧を記載したrequirements.txtの作成をします。 pip freeze > requirements.txt Procfile プログラムの実行方法を記載したProcfileを記載します。 web: gunicorn app:app --log-file=- 僕はgunicornを使いました。 上記のファイル作成時に参考した記事はこちらです! デプロイする Herokuのアカウント作成→デプロイはrakusのtechブログを参考にしました。 非常にわかりやすかったのでとてもおすすめです。 基本的には上からドキュメントを追っていけば進むのですが、個人的にスタックしたポイントと、それを解決するときに参考にしたリンクを貼って締めたいと思います。 buildpacksの設定 Heroku DBアクセス データベースのアクセスまではこれを参考にしました。 portの指定をなくす ローカル環境だと、8080等でポートを指定しますが、herokuデプロイ時は取り除きます。 webサーバーがapサーバーを叩く時にポートが80だと、root権限が必要なのですが、実行者(クライアント側)はherokuのroot権限を持っていないので弾かれてしまうためです。 (Flaskはデフォルトの設定で大丈夫なのですが、Djangoのデフォルト設定はまた違うため別途で設定する必要があります。) 最後に 後半のデプロイ部分は説明をだいぶ端折りましたが、webアプリケーションを一般公開する流れはなんとなく掴んでいただけたかと思います。 pythonで関数を作ってみたり、アプリを作ってみてもどうやってwebアプリに組み込むのかわからないという方は多いと思いますが、今回の記事が少しでも皆さんのためになれば幸いです。 拙い文章ではありましたが、ここまでご精読ありがとうございました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む