- 投稿日:2020-09-23T23:44:13+09:00
ゼロから始めるDjango(part:1)
理由
仕事をしていてDjangoのライブラリに関連するものが多く、一度触ってみたいと思ったため
目的
- アプリケーションの作成の流れを理解する
- 使うことができるライブラリを理解する
参考文献
はじめての Django アプリ作成、その 1 | Django ドキュメント | Django
実践
djangoのプロジェクトのスタート
django-admin startproject mysite上記コードを実行するとdjango用のプロジェクトを
mysite
という名前で作成してくれる。プロジェクトの中身
そのプロジェクト構造は以下のようになっている。
mysite/ manage.py mysite/ __init__.py settings.py urls.py asgi.py wsgi.py*外側のmysiteは重要ではないため好きな名前でよい
- manage.py プロジェクトの様々な操作を行うやつ
- 内側のmysiteはPythonパッケージ
- mysite/settings.py: Django プロジェクトの設定ファイル
- mysite/urls.py: Django プロジェクトの URL 宣言(コントローラーみたいなやつ?)
mysite/asgi.py: プロジェクトを提供する ASGI 互換 Web サーバーのエントリポイント
エントリポイント:プログラムを実行するうえで、プログラムやサブルーチンの実行を開始する場所のこと(main.pyみたいなやつ)mysite/wsgi.py: Webサーバー
開発用サーバー
manage.pyのあるディレクトリ、つまりは外側のmysiteで上記コードを実行すると立ち上がる。
python manage.py runserverサーバーのポートを変えたい場合は下記のようにする。
python manage.py runserver 8080pollsアプリケーション
作成準備
manage.pyと同じ階層で下記のコマンドを実行
python manage.py startapp pollspollsというディレクトリが自動生成される。中身は下記のようになっている。
polls/ __init__.py admin.py apps.py migrations/ __init__.py models.py tests.py views.py
polls
の部分は任意。startappが大事。urls.pyを追加し、urls.pyとviews.pyを作成する。
polls/views.pyfrom django.http import HttpResponse def index(request): return HttpResponse("Hello, world. You're at the polls index.")polls/urls.pyfrom django.urls import path from . import views urlpatterns = [ path('', views.index, name='index'), ]ルートURLconf
mysite/urls.pyfrom django.contrib import admin from django.urls import include, path urlpatterns = [ path('polls/', include('polls.urls')), path('admin/', admin.site.urls), ]
- urlpatternsのリスト内にurlconfを追加。
- djangoではinclude()に遭遇するとそのポイントまでに一致したurlのところまでを切り取る。
- 次の処理のために残りの文字列をインクルードされたURLconfへ渡す。
http://polls/hogehoge/
の場合はhttp://polls/(ここまで切り落とす)
,hogehoge/(ここまでをpolls.urlsへ渡す)
実行結果の確認
下記のコマンドで実行結果を確認する
$ python manage.py runserverhttp://localhost:8000/polls/ にアクセスして、
「Hello, world.You`re at the polls index.」と表示されていれば成功
- 投稿日:2020-09-23T22:52:52+09:00
PytorchのDatasetを層状にfoldingする
既存の
Dataset
をN-foldするときに、先頭から順に1,2,...N,1,2,...,N,1,2,...,N,1,2,...とデータセットを分割する。時系列データを分割するときに、特定の月や季節にデータが偏らないようにするときに使用する。from torch.utils.data import Dataset class LayeredFoldWrapper(Dataset): def __init__(self, dataset, n_splits=5, fold=0, valid=False): self.dataset = dataset self.n_splits = n_splits self.fold = fold self.valid = valid self.valid_index = list(self._valid_index(len(dataset), n_splits, fold)) self.train_index = list(set(range(len(dataset))) - set(self.valid_index)) def __len__(self): return len(self._get_index_list(self.valid)) def __getitem__(self, i): return self.dataset.__getitem__(self._get_index_list(self.valid)[i]) def _valid_index(self, N, n_splits, fold): """ N: 全データの数 n_splits: foldのスプリットの数 fold: 各foldを指定する値 0<=fold<=n_splits-1 """ assert(0<=fold<=n_splits-1) return range(n_splits - fold - 1, N+1, n_splits) def _get_index_list(self, valid): if valid: return self.valid_index else: return self.train_index
- 投稿日:2020-09-23T22:28:53+09:00
超個人的略語備忘録
Linuxコマンド
apt : Advanced Packaging Tools
sudo : SUbstitute user DO / SUperuser DO
pwd : Print Working Directory
cd : Change Directory
ls : List Segment
cp : CoPy
mv : MoVe
rm : ReMove
cat : CATenate (連結する)
Python
- pip : Pip Install Package/Python
その他
GUI : Graphical User Interface
CUI : Character User Interface / Character-based User Interface / Console User Interface
CLI : Command Line Interface
CPU : Central Processing Unit
GPU : Graphical Processing Unit
IDE : Integrated Development Environment
- 投稿日:2020-09-23T21:56:40+09:00
Codeforces Round #486 (Div. 3) バチャ復習(9/23)
今回の成績
今回の感想
D問題を永遠にバグらせていたら一時間半を無駄にしました。E問題も面倒だと思って避けましたが、結果的に場合分けをきっちりしていけばupsolveできたので悔しい限りです。D,E問題共にコーナーケースやバグを発見することができなかったのも今までの反省が生かせていないので次に生かせるように頭の中を整理しておこうと思います。
A問題
レーティングが異なるようにしたいので、set構造でレーティングの種類数を数えて$k$を超えるか判定します。$k$以上の場合は適当な$k$個を出力します。ここでは実装が楽になるようにindexを使いましたが、計算量的には別の方法が良いです(ここでは紹介しませんが$O(k)$でできます)。
A.pyn,k=map(int,input().split()) a=list(map(int,input().split())) b=list(set(a)) if len(b)>=k: print("YES") ans=[] for i in range(k): ans.append(a.index(b[i])+1) print(" ".join(map(str,ans))) else: print("NO")B問題
題意を満たす文字列の順番がある時、(最初の文字列を除く)任意の文字列は直前の文字列を部分列として持つので、この文字列の順番は長さの昇順になります($\because$背理法により示せます。)。
よって、与えられた文字列を長さの昇順に直し、それぞれ直前の文字列に含むかをinによって判定すれば良いです。この時、計算量は$O(N^2)$となります。
B.pyn=int(input()) a=[input() for i in range(n)] a.sort(key=lambda x:len(x)) for i in range(n-1): if a[i] not in a[i+1]: print("NO") break else: print("YES") for i in range(n): print(a[i])C問題
二つのsequenceを選んでそれぞれから一つずつ要素を抜き出して和が同じものを見つけます。ここで、$i$番目の長さ$n_i$のsequenceから一つ要素を抜き出す和はどの要素を抜き出すかで$n_i$通りあります。また、制約より$\sum_{i=1}^{k}{n_i} \leqq 2 \times 10^5$なので、この和は全列挙することができます。
ここで、$i$番目の長さ$n_i$のsequenceの$j$番目の要素を抜き出した時の和は($i$番目のsequenceの和)-($j$番目の要素の値)となり、それぞれのsequenceの和を予め求めておけば、$O(\sum_{i=1}^{k}{n_i})$で求めることができます。また、keyをsequenceの和の値,valueを"その値になる(sequenceのインデックス,抜き出した要素のインデックス)"を保存したvectorとして辞書$m$を置けば、先ほど求めたsequenceの和を順に格納することができます。また、この際にkeyが等しいものの中でsequenceのインデックスが異なるものが二つ以上あれば答えとして出力することができます。逆に二つ以上あるものが一つもない場合はNoを出力すれば良いです。
(気づかなかったですが、Pythonでも書けましたね。なぜC++で書いたのでしょうか…?)
C.cc//デバッグ用オプション:-fsanitize=undefined,address //コンパイラ最適化 #pragma GCC optimize("Ofast") //インクルードなど #include<bits/stdc++.h> using namespace std; typedef long long ll; //マクロ //forループ //引数は、(ループ内変数,動く範囲)か(ループ内変数,始めの数,終わりの数)、のどちらか //Dがついてないものはループ変数は1ずつインクリメントされ、Dがついてるものはループ変数は1ずつデクリメントされる //FORAは範囲for文(使いにくかったら消す) #define REP(i,n) for(ll i=0;i<ll(n);i++) #define REPD(i,n) for(ll i=n-1;i>=0;i--) #define FOR(i,a,b) for(ll i=a;i<=ll(b);i++) #define FORD(i,a,b) for(ll i=a;i>=ll(b);i--) #define FORA(i,I) for(const auto& i:I) //xにはvectorなどのコンテナ #define ALL(x) x.begin(),x.end() #define SIZE(x) ll(x.size()) //定数 #define INF 1000000000000 //10^12:∞ #define MOD 1000000007 //10^9+7:合同式の法 #define MAXR 100000 //10^5:配列の最大のrange //略記 #define PB push_back //挿入 #define MP make_pair //pairのコンストラクタ #define F first //pairの一つ目の要素 #define S second //pairの二つ目の要素 signed main(){ //入力の高速化用のコード //ios::sync_with_stdio(false); //cin.tie(nullptr); ll k;cin>>k; map<ll,vector<pair<ll,ll>>> m; REP(i,k){ ll ni;cin>>ni; vector<ll> a(ni);REP(j,ni)cin>>a[j]; ll s=0;REP(j,ni)s+=a[j]; REP(j,ni){ m[s-a[j]].PB(MP(i+1,j+1)); } } FORA(i,m){ if(SIZE(i.S)>1){ map<ll,ll> x; //同じ数列被り排除 FORA(j,i.S){ x[j.F]=j.S; } if(SIZE(x)>1){ auto y=x.begin(); cout<<"YES"<<endl; cout<<y->F<<" "<<y->S<<endl; y++; cout<<y->F<<" "<<y->S<<endl; return 0; } } } cout<<"NO"<<endl; }D問題
(UnionFindによる操作はほぼ定数とみなして計算量を表記しています。)
全体から部分集合を選ぶというイメージで行うと沼にハマってしまうかもしれません。ここでは、二つの点の距離が$2^d$かつ最大で$2 \times 10^9$なので、$d=$0~30のみを調べれば良いことに注目します。
この時、それぞれの$d$について最大の部分集合を求めることを考えます。また、ある点$x$に注目した時$2^d$だけ離れている点は$x-2^d,x+2^d$であり、全ての点をsetで管理すれば離れている点が存在するかを$O(\log{n})$で確かめることができます(任意の点で調べれば$O(n \log{n})$)。したがって、UnionFindを用いて間が$2^d$離れている点どうしをつないでいくことで下図のような点の部分集合がいくつかできます。
また、上図の部分集合に含まれる点は全て題意を満たすような部分集合に含まれるとしたいのですが、高々3つの点までしか含めることができません。なぜなら、3つより点が大きい場合は距離が2の冪乗にならない点の組が必ず含まれるからです。
以上より、$d=$0~30それぞれでUnionFindを行って(集合内の要素を昇順に並べると座標の間隔が$2^d$である)素集合系を求め、要素数が三以上の集合が少なくとも一つある場合はその集合を昇順で並べた時に隣合う三つの点を出力し、(前述の条件を満たさず)要素数が2のものが少なくとも一つある場合はその集合に含まれる二点を出力し、それ以外の場合は適当な一点を出力すれば良いです。
また、点同士をuniteする場合にindexを指定したかったので値に対してのインデックスを与えるmapとして
ind
を用意し、出力の際にインデックスから要素の値に直すためのvectorとしてval
を用意しました。また、UnionFindで得られた集合はインデックスの昇順になっているので、値の昇順と一致させるためにval
を昇順に直してからind
に格納する必要があります。(昇順のソートをしていなかったのに気づかず、デバッグに数時間かかりました…。考察段階では気づいていたミスなので、焦ったときは自分の考察と照らし合わせるようにしたいです。)D.cc//デバッグ用オプション:-fsani //コンパイラ最適化 #pragma GCC optimize("Ofast") //インクルードなど #include<bits/stdc++.h> using namespace std; typedef long long ll; //マクロ //forループ //引数は、(ループ内変数,動く範囲)か(ループ内変数,始めの数,終わりの数)、のどちらか //Dがついてないものはループ変数は1ずつインクリメントされ、Dがついてるものはループ変数は1ずつデクリメントされる //FORAは範囲for文(使いにくかったら消す) #define REP(i,n) for(ll i=0;i<ll(n);i++) #define REPD(i,n) for(ll i=n-1;i>=0;i--) #define FOR(i,a,b) for(ll i=a;i<=ll(b);i++) #define FORD(i,a,b) for(ll i=a;i>=ll(b);i--) #define FORA(i,I) for(const auto& i:I) //xにはvectorなどのコンテナ #define ALL(x) x.begin(),x.end() #define SIZE(x) ll(x.size()) //定数 #define INF 1000000000000 //10^12:∞ #define MOD 1000000007 //10^9+7:合同式の法 #define MAXR 100000 //10^5:配列の最大のrange //略記 #define PB push_back //挿入 #define MP make_pair //pairのコンストラクタ #define F first //pairの一つ目の要素 #define S second //pairの二つ目の要素 //以下、素集合と木は同じものを表す class UnionFind { public: vector<ll> parent; //parent[i]はiの親 vector<ll> siz; //素集合のサイズを表す配列(1で初期化) map<ll,vector<ll>> group;//素集合ごとに管理する連想配列(keyはそれぞれの素集合の親、valueはその素集合の要素の配列) ll n;//要素の個数 //コンストラクタ UnionFind(ll n_):parent(n_),siz(n_,1),n(n_){ //全ての要素の根が自身であるとして初期化 for(ll i=0;i<n;i++){parent[i]=i;} } //データxの属する木の根を取得(経路圧縮も行う) ll root(ll x){ if(parent[x]==x) return x; return parent[x]=root(parent[x]);//代入式の値は代入した変数の値なので、経路圧縮できる } //xとyの木を併合 void unite(ll x,ll y){ ll rx=root(x);//xの根 ll ry=root(y);//yの根 if(rx==ry) return;//同じ木にある時 //小さい集合を大きい集合へと併合(ry→rxへ併合) if(siz[rx]<siz[ry]) swap(rx,ry); siz[rx]+=siz[ry]; parent[ry]=rx;//xとyが同じ木にない時はyの根ryをxの根rxにつける } //xとyが属する木が同じかを判定 bool same(ll x,ll y){ ll rx=root(x); ll ry=root(y); return rx==ry; } //xの素集合のサイズを取得 ll size(ll x){ return siz[root(x)]; } //素集合をそれぞれグループ化 void grouping(){ //経路圧縮を先に行う REP(i,n)root(i); //mapで管理する(デフォルト構築を利用) REP(i,n)group[parent[i]].PB(i); } void clear(){ for(ll i=0;i<n;i++){parent[i]=i;} siz=vector<ll>(n,1); group.clear(); } }; signed main(){ ios::sync_with_stdio(false); cin.tie(nullptr); ll n;cin>>n; set<ll> x; //値に対してのind map<ll,ll> ind; //indに対しての値 vector<ll> val(n); REP(i,n){ ll y;cin>>y; x.insert(y); val[i]=y; } sort(ALL(val)); REP(i,n){ ind[val[i]]=i; } vector<ll> v(1,0); pair<ll,vector<ll>> ans=MP(1,v); UnionFind uf(n); REP(i,31){ uf.clear(); FORA(j,val){ if(x.find(j+(1LL<<i))!=x.end()){ uf.unite(ind[j],ind[j+(1LL<<i)]); } } uf.grouping(); for(auto j=uf.group.begin();j!=uf.group.end();j++){ if(SIZE(j->S)>ans.F){ //3は超えない //sortされてない(valは)はー??????? if(ans.F==1){ if(SIZE(j->S)==2){ vector<ll> w(2); w={j->S[0],j->S[1]}; ans=MP(2,w); }else{ cout<<3<<endl; cout<<val[j->S[0]]<<" "<<val[j->S[1]]<<" "<<val[j->S[2]]<<endl; return 0; } } if(ans.F==2){ if(SIZE(j->S)>2){ cout<<3<<endl; cout<<val[j->S[0]]<<" "<<val[j->S[1]]<<" "<<val[j->S[2]]<<endl; return 0; } } } } } cout<<ans.F<<endl; REP(i,ans.F){ if(i==ans.F-1){ cout<<val[ans.S[i]]<<endl; }else{ cout<<val[ans.S[i]]<<" "; } } }E問題
(実装がキツかったです。解説は可及的速やかにあげます。)
E.pyn=[int(i) for i in input()] l=len(n) #長さが2の場合も if len(n)==1: print(-1) exit() #これだけの場合 if n in [[2,5],[7,5],[5,0]]: print(0) exit() if n in [[5,2],[5,7]]: print(1) exit() inf=10**12 #一番左にある場合はめんどいので場合分けしちゃう(逆にする) #00も場合分け def calc1(x,y): global n,l,inf m=n[::-1] if x not in n or y not in n: #print(x,y,0) return inf ix,iy=m.index(x),m.index(y) #一番右にない場合 if max(ix,iy)<l-1: if iy<ix: #print(x,y,1) return iy+(ix-1) else: #print(x,y,2) return iy+(ix-1)+1 else: ret=0 #print(ix,iy) if ix==l-1: #右から探して左を見る(0かつ他の選択するやつでない) for i in range(l-2,-1,-1): if m[i]!=0 and i!=iy: break else: #print(x,y,3) return inf if i<iy: iy-=1 ret+=(l-1-i) ix-=1 ret+=(iy+(ix-1)) #print(x,y,4,ret) return ret else: ret+=iy ret+=(l-1-i) ix-=1 ret+=(ix-1) #print(x,y,5,ret) return ret else: #右から探して左を見る(0かつ他の選択するやつでない) #他の選択するやつだけの可能性(最初に排除) #外でやる for i in range(l-2,-1,-1): if m[i]!=0 and i!=ix: break else: #print(x,y,6) return inf if i<ix: iy-=1 ret+=(l-1-i) ix-=1 ret+=(iy+(ix-1)+1) #print(x,y,7,ret) return ret else: ret+=iy ret+=(l-1-i) ix-=1 ret+=((ix-1)+1) #print(x,y,8,ret) return ret #00の時 def calc2(x,y): #一番右には絶対ない global n,l,inf if n.count(0)<2: return inf m=[l-1-i for i in range(l) if n[i]==0][::-1] return m[0]+m[1]-1 ans=min([calc1(2,5),calc1(7,5),calc1(5,0),calc2(0,0)]) #print([calc1(2,5),calc1(7,5),calc1(5,0),calc2(0,0)]) print(-1 if ans==inf else ans)F問題
今回は飛ばします
- 投稿日:2020-09-23T21:44:21+09:00
ラズパイで今後やりたいことをメモしていく
この記事は
勉強と興味のためにRaspberryPi 3を買ったはいいが、やってみたいことだらけなのに触る時間がなくやりたいことがどんどん増えていく。
ので、このページに備忘録としてまとめていく。
そういう記事。やりたいこと
IoT関係
- 自室の4箇所+窓の外の1箇所に温度センサー(温湿度?)を設置し、一定時間ごとに温度を計測してログをためこむ。最終的にspreadsheetやwebブラウザなどでグラフ化して表示する
参考
Raspberry Piのセンサーで検出したデータをPythonでテキストログに出力させる - Qiita
CO2センサを部屋につけてログを取る - Qiita
ログローテーションの設定方法 - Qiita
Raspberry Pi(ラズパイ)で温度測定してログを取ってみる - WICの中から
- 赤外線LEDとリモコン受信つきの照明を使って、部屋の照明を音声認識やtwitterからの指示でONOFFできるようにする。
参考
Raspberry Pi Zero で赤外線リモコンを作る - Qiita
Raspberry Pi3で赤外線リモコンを作る - なになれ
ラズパイとTwitter(ツイッター)を連携 - Raspberry Π
Raspberry PiからTwitterへ情報発信!(1) Twitter API編 | Device Plus - デバプラ
- 投稿日:2020-09-23T20:49:37+09:00
置換する方法
pythonの文字列に変数を埋め込む方法
・ここでは、2つ紹介します。
・1,f-string
・2,format()f-string
先頭にfをつけて定義する文字列
a="apple" f"I like an {a}"#変数の値で置換実行結果I like an appleformat()
文字列内の{}が、メソッドstr.format()の引数に渡した値に置換される。
a="apple" "I like an {}".format(a)実行結果I like an apple複数の引数を置換する
・1.f-string
a="apple" b="orange" f"I like an {a} and an {b}"実行結果I like an apple and an orange2.format()
a="apple" b="orange" "I like an {} and {}".format(a,b)実行結果I like an apple and an orange
- 投稿日:2020-09-23T20:49:37+09:00
pythonの文字列に変数を埋め込む方法
pythonの文字列に変数を埋め込む方法
・ここでは、2つ紹介します。
・1,f-string
・2,format()f-string
先頭にfをつけて定義する文字列
a="apple" f"I like an {a}"#変数の値で置換実行結果I like an appleformat()
文字列内の{}が、メソッドstr.format()の引数に渡した値に置換される。
a="apple" "I like an {}".format(a)実行結果I like an apple複数の引数を置換する
・1.f-string
a="apple" b="orange" f"I like an {a} and an {b}"実行結果I like an apple and an orange2.format()
a="apple" b="orange" "I like an {} and {}".format(a,b)実行結果I like an apple and an orange
- 投稿日:2020-09-23T20:18:22+09:00
VS CodeでFortranをデバッグ設定までやってみる。【Win10】
初めに
FortranをWindowsでビルド・デバッグする場合は、どういうツールを組み合わせればいいのか調べた。
デバッグでブレークポイントに止まらない問題でやや詰まったが解決。
必要最小限の構成で考えている。使用するツールや環境
・Windows 10
・Visual Studio Code
※エクステンションは2つ:Modern Fortran、C/C++
・gfortran(フリーのコンパイラ)1.Fortranコンパイラの準備
・TDM-GCCから、「tdm64-gcc-***.exe」をダウンロード
※gccだけど、gfortranも入っている。
・インストールする。fortranのチェックを忘れずに。
・インストールされたか確認。以下2つのファイルが重要。
2.VS Codeの準備
※VS Codeインストールは割愛。
・画面一番左の「拡張機能」から「Modern Fortran」を検索してインストール。
※自動的に「C/C++」もインストールされる。
・インストールされた「Modern Fortran」を右クリック→拡張機能の設定
・gfortranの場所を指定
・実行→構成を開く→C++(GDB/LLDB)
※Fortranだけど、C++を選ぶ。というか、そもそもFortranがない。
下のように、"program"と"miDebuggerPath"を自分の環境に合わせて設定。他はそのままでいいかな。{ // IntelliSense を使用して利用可能な属性を学べます。 // 既存の属性の説明をホバーして表示します。 // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "(gdb) 起動", "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/a.exe", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], "externalConsole": false, "MIMode": "gdb", "miDebuggerPath": "C:/TDM-GCC-64/bin/gdb.exe", "setupCommands": [ { "description": "gdb の再フォーマットを有効にする", "text": "-enable-pretty-printing", "ignoreFailures": true } ] } ] }3.Fortranのビルド
・ビルド作業はVS Code上ではなく、コマンドプロンプトで実行。
・今回はデバッグをするためには、必ずオプション 「-g」を付ける。C:\Temp>gfortran -g fortran_program.f904.VS Codeによるデバッグ
・VS Codeでフォートランファイルを開き、行数の左にデバッグポイントを打つ
・実行→デバッグの実行。
すると、ちゃんとデバッグポイントで止まる!
終わり
ビルド時にオプション必要というのがやや詰まりましたが、できて良かった。
学生時代はprint文によるデバッグしかできなかったから、Fortranでもデバッグできるんだなぁと感慨深いです。
宜しければお使いください。「gfortran -g」がVS Codeから実行できるかどうかは、わからないです。どうやるんだろ、多分簡単だろうけどここまでにしておきます。
- 投稿日:2020-09-23T19:28:13+09:00
macOS上にpydicomをセットアップするためのメモ
公式のセットアップ手順 はDebian系のLinux環境を前提としている部分があるため、macOS上でセットアップした際の手順を残しておく
環境情報
- macOS Catalina 10.15.6
- Python 3.8.5 on pyenv 1.2.20
※Anacondaは利用しない
セットアップ手順
pydicom
$ pip install pydicomOptional libraries
$ pip install numpy $ pip install pillowCharPyLS
$ pip install cython $ pip install git+https://github.com/Who8MyLunch/CharPyLSGDCM
Anacondaなしでは少々手間のかかる部分
Installing the Python GDCM bindings without Conda を参考に、Ubuntu/Debian向けの記述をmacOS向けにアレンジする$ brew install gdcm # インストールされた関連ファイルの場所を確認する $ find /usr -name gdcm.py /usr/local/lib/python3.8/site-packages/gdcm.py /usr/local/Cellar/gdcm/3.0.7_1/lib/python3.8/site-packages/gdcm.py $ find /usr -name "libgdcmCommon.*" /usr/local/lib/libgdcmCommon.3.0.dylib /usr/local/lib/libgdcmCommon.3.0.7.dylib /usr/local/lib/libgdcmCommon.dylib /usr/local/Cellar/gdcm/3.0.7_1/lib/libgdcmCommon.3.0.dylib /usr/local/Cellar/gdcm/3.0.7_1/lib/libgdcmCommon.3.0.7.dylib /usr/local/Cellar/gdcm/3.0.7_1/lib/libgdcmCommon.dylib # pyenv環境へ関連ファイルをコピー $ cd ~/.pyenv/versions/3.8.5/lib/python3.8/site-packages/ $ cp /usr/local/lib/python3.8/site-packages/gdcm.py . $ cp /usr/local/lib/python3.8/site-packages/gdcmswig.py . $ cp /usr/local/lib/python3.8/site-packages/_gdcmswig* . $ cp /usr/local/lib/libgd* .Pythonのプロンプト上で
import gdcm
してエラーが出なければOK
- 投稿日:2020-09-23T19:15:33+09:00
YOLOを利用した物体検出(python)(【高等学校情報科 情報Ⅱ】教員研修用教材)
はじめに
YOLO(You Only Look Once)とは、その名の通り人間のように一度見ただけで物体の認識・検出をしてしまうという画期的なアルゴリズムです。
従来の手法に比べて、処理が高速であり物体と背景の認識の区別に強く、汎用化しやすいという特徴を持っています。
今回は、教材内でTiny YOLOとRを使って物体検出を行っている個所を、YOLOとpythonを使用して写真上の物体の検出を行っていきます。教材
高等学校情報科「情報Ⅱ」教員研修用教材(本編):文部科学省
第3章 情報とデータサイエンス 後半 (PDF:7.6MB)環境
- ipython
- Colaboratory - Google Colab
教材内で取り上げる箇所
学習18 テキストマイニングと画像認識:「3.TinyYOLOを利用した物体検出」
pythonでの実装例と結果
今回は、darknetをgithubのリポジトリからclone(コピー)し、YOLOv3の学習済み重みデータyolov3.weightsを使用して、画像認識を行います。
今回はpythonでの実装例と書いてありますが、darknetでYOLOv3を動かすためコマンドの実行を中心に行い、なるべく自前でコーディングしないような形で物体検出できるようにしていきたいと思います。!git clone https://github.com/pjreddie/darknet実行結果は以下のようになりました
Cloning into 'darknet'... remote: Enumerating objects: 5913, done. remote: Total 5913 (delta 0), reused 0 (delta 0), pack-reused 5913 Receiving objects: 100% (5913/5913), 6.34 MiB | 9.93 MiB/s, done. Resolving deltas: 100% (3918/3918), done.
git cloneできたので、darknetディレクトリ配下に移動し、makeを実行します。
import os os.chdir('darknet') !makemakeが完了したら、YOLOv3の学習済み重みデータyolov3.weightsを同じディレクトリにダウンロードしておきます。今回はwgetコマンドを使用しました。
!wget https://pjreddie.com/media/files/yolov3.weights本題の、YOLOで物体検出をさせたいと思いますが、今回はdataディレクトリ内のgiraffe.jpgを使用して、物体検出をしてみたいと思います。
!./darknet detect cfg/yolov3.cfg yolov3.weights data/giraffe.jpglayer filters size input output 0 conv 32 3 x 3 / 1 608 x 608 x 3 -> 608 x 608 x 32 0.639 BFLOPs 1 conv 64 3 x 3 / 2 608 x 608 x 32 -> 304 x 304 x 64 3.407 BFLOPs 2 conv 32 1 x 1 / 1 304 x 304 x 64 -> 304 x 304 x 32 0.379 BFLOPs 3 conv 64 3 x 3 / 1 304 x 304 x 32 -> 304 x 304 x 64 3.407 BFLOPs : 103 conv 128 1 x 1 / 1 76 x 76 x 256 -> 76 x 76 x 128 0.379 BFLOPs 104 conv 256 3 x 3 / 1 76 x 76 x 128 -> 76 x 76 x 256 3.407 BFLOPs 105 conv 255 1 x 1 / 1 76 x 76 x 256 -> 76 x 76 x 255 0.754 BFLOPs 106 yolo Loading weights from yolov3.weights...Done! data/giraffe.jpg: Predicted in 19.677707 seconds. giraffe: 98% zebra: 98%キリン(giraffe)とシマウマ(zebra)が検出できました。
実際の検出された画像を見てみましょう。from IPython.display import Image Image("predictions.jpg")うまく検出できました。
ソースコード
https://gist.github.com/ereyester/46a25e70c866c581320a66a77153aa2d
- 投稿日:2020-09-23T18:37:44+09:00
内包表記
内包表記
Pythonには内包表記と呼ばれる記法があります。
内包表記とは、リストコンプリヘンションと同じ意味です。三種類ありますが、リストの内包表記から説明していきます。
リストオブジェクトとループを利用して新たなリストを生成する構文。
他の言語にはあまりない独特な構文ですが、慣れると非常に便利そして非常に高速というのがメリット内包表記の基本的な書き方
[式 for 変数 in シーケンス]リスト内包表記を使用しない場合
num_list = [1, 2, 3, 4, 5]
number_list = []
for num in num_list:
> new_num = num * 2
> number_list.append(new_num)
print(number_list)[2, 4, 6, 8, 10]
リスト内包表記を使用する場合
num_list = [1, 2, 3, 4, 5]
number_list = [num * 2 for num in num_list ]
print(number_list)[2, 4, 6, 8, 10]
要はリスト内包表記を使うことによって、短くまとまった記載にできるということです。
以下のように表記することでif文を使用することも可能です。
[式 for 変数 in シーケンス if リスト要素に対する条件]
num = “1, 2, 3, 4, a,5"
number = [int(s) for s in num.split() if s.isdigit()]
print(number)[1, 2, 3, 4, 5]
ディクショナリ内包表記
リスト内包表記と同じく、辞書型の要素をまとめて処理することができる。 使い方はリスト内包表記と同じ。
内包表記の基本的な書き方
{キー:for 変数 in シーケンス (if 条件)}subject = {‘kokugo’: 75, ‘suugaku’: 64, ‘eigo’: 92}
num = {point: str(n) + ‘点’ for point, n in subject.items()}
print(num)
{‘kokugo’: 75点, ‘suugaku’: 64点, ‘eigo’: 92点}セット内包表記
集合内包表記とも呼ばれますセット内包表記の基本的な書き方
{式 for 変数 in シーケンス (if 条件)}num_set = {number for number in range(19) if number % 3 == 0}
print(num_set)
{0, 3, 6, 9, 12, 15, 18}イテレータとは、
集合の要素に準々にアクセスする場合に使用するインターフェースで、コレクションを繰り返し使うためにあるものです。
リスト、セット、マップなど複数の種別がありますが、イテレータはそれらにアクセスするための仕組みです。
例えば、javaでは、Set#iteratorメソッドIteratorを取りだし、順番に要素を取得しますが、Pythsonではイテレータオブジェクトを使用します。
イテレータを使用することで、要素へのアクセスを記述することが可能です。
Pythonのfor文においてはiterableを範囲にとって、暗黙的にiteratorを利用する点を指して内部イテレータと呼ばれる場合もある。※インターフェース
コンピュータで、異なる機器・装置のあいだを接続して、交信や制御を可能にする装置やソフトウェアのこと※コレクション
リストやSetのように、複数の要素を扱うオブジェクトです。
- 投稿日:2020-09-23T17:31:25+09:00
文字列まとめ1
- 投稿日:2020-09-23T17:26:26+09:00
kivy JsonStore でUnicodeDecodeError を解決する
問題のエラー
Kivyでstorageモジュールを使ってjsonを扱う際、以下のようなエラーに遭遇した。
※環境はpython3.8 ですが、大した差異はないと思います。File "C:\programing\project\hoge\main.py", line 33, in _init_load self.store = JsonStore('test.json', ) File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\kivy\storage\jsonstore.py", line 29, in __init__ super(JsonStore, self).__init__(**kwargs) File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\kivy\storage\__init__.py", line 134, in __init__ self.store_load() File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\kivy\storage\jsonstore.py", line 43, in store_load data = fd.read() UnicodeDecodeError: 'cp932' codec can't decode byte 0x82 in position 85: illegal multibyte sequence親の顔より見たUnicodeDecodeErrorですね。日本語が入ってることが原因ですかね?
このエラーは基本的にopen関数の引数にencoding='utf-8'を追加すれば解決できます。
というわけでstorageモジュールの中でjsonファイルを開く部分をサクッと変更します。
31行目に読み込みを行う関数があるので、そこのopen部分にキーワード引数を追加します。kivy/storage/jsonstore.pydef store_load(self): if not exists(self.filename): folder = abspath(dirname(self.filename)) if not exists(folder): not_found = IOError( "The folder '{}' doesn't exist!" "".format(folder) ) not_found.errno = errno.ENOENT raise not_found return with open(self.filename, encoding='utf-8') as fd: # ココ data = fd.read() if len(data) == 0: return self._data = loads(data)結果
正常に読み込むことに成功しました。
日本語はややこしいですね。。。
- 投稿日:2020-09-23T17:02:15+09:00
Missing key(s) in state_dict: "bert.embeddings.position_ids".
transformers3でそれ以前のモデルをロードするとこのエラーがでる.
対策としては,ダウングレードすれば良い
- 投稿日:2020-09-23T15:38:14+09:00
E資格取得を目指して〜その1〜
E資格取得にむけて、不定期で投稿しています。
状況
- ゼロから作るDeep Learningの1章から7章まで読了、8章を途中まで
- ゼロから作るDeep Learningの第2章を学習中
- JDLA認定プログラムの講座を適宜受講。課題への着手。
所感
エンジニアの幅を広げるために取り組みを開始しましたが、思った以上に難しい。
なんとなく(G検定持ってない)理解している状態からスタートしたのでまずは全体感を理解するためにゼロつくシリーズをやってます。
1ヶ月前は講座の内容に合わせ計画を作ってみましたが、あまり意味がないことに気付き、まず全部やってみる。
後から個々の細かい部分を肉付けしていくやり方にしています。(今のところ、マッチしていると思っている)その他
もう少し余裕が出てくるくらいの習熟度に慣れたら、学習内容を自分なりの理解をアウトプットすることにもチャレンジしたいと思ってます。
ただ、今はまずは内容を把握するところから・・・
- 投稿日:2020-09-23T15:13:08+09:00
機械学習概論 メモ書き
Aidemy 2020/9/23
はじめに
こんにちは、んがょぺです!文系大学生ですが、AI分野に興味が湧いたのでAI特化型スクール「Aidemy」に通い、勉強しています。ここで得られた知識を皆さんと共有したいと思い、Qiitaでまとめています。以前のまとめ記事も多くの方に読んでいただけてとても嬉しいです。ありがとうございます!
今回は機械学習概論について、重要なところのメモ書きを行なって行こうと思います。機械学習概論1 要点
・機械学習には「教師あり学習」「教師なし学習」「強化学習」がある。
・教師あり学習は学習データと正解(教師)データを与えて正解するまで思考する方法。最頻。
・教師なし学習は学習データのみを与え、コンピュータ自身が規則性を見つける方法。
・強化学習は、行動主体が得られる利益(報酬)を最大化するよう思考し続ける方法。機械学習概論2 要点
・教師あり学習の手順:データ収集→データクレンジング→学習→テストデータでチェック→実装
・教師あり学習の実践1:ホールドアウト法:データを学習データとテストデータに分けて使用。train_test_split()関数を使う。
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=テストデータの割合,random_state=0)
*Xは正解ラベル以外、yは正解ラベル。trainが学習データ、testがテストデータ。random_stateはテストデータを選ぶseed。・教師あり学習の実践2:k-分割交差検証:データをk分割しそのうち1つをテストデータとして使用。テストデータを毎回変えて計k回検証してその平均性能を算出する。(ex 20個のデータなら、19個を学習データ、1個をテストデータとし、計20回検証する)
・過学習:学習の精度が高すぎて適切に抽象化できず、未知のデータに対応できない状態。
・ドロップアウト:過学習回避の手段。明らかな例外を無視する。
・アンサンブル学習:複数のモデルに学習させ、結果の平均を取ることで精度を高める。機械学習概論3 要点
・混同行列:モデルの精度を評価する際に使われる表。結果を「真陽性」「偽陽性」「真陰性」「偽陰性」に分類する。「真偽」は正解したかどうか、「陽陰」はモデルの解答を示す。(つまり「偽陽性」なら、モデルはTrueと解答したが、答えはFalseだったということ)
・混同行列の実装:以下のように記述(「y_true」には[正解のリスト]を、「y_pred」には[モデルの解答のリスト]を与える。)
from sklearn.metrics import confusion_matrix #「正解」と「解答」をリストで定義(0が陽性、1が陰性) y_true=[1,1,1,1,1,1] y_pred=[1,1,1,0,0,0] confmat = confusion_matrix(y_true, y_pred) #[[0 0] #[[真陽性 偽陰性] # [3 3]] # [偽陽性 真陰性]]・正解率:全解答のなかで、「真」だった割合。(真陽性+真陰性/全体)
・適合率/精度:「陽」と解答したもののうち、「真」だった割合。(真陽性/真陽性+偽陽性)
・再現率:「実際の陽」のうち、「真」だった割合。(真陽性/真陽性+偽陰性)
・F値:適合率と再現率の調和平均(2*適合率*再現率/適合率+再現率)
*これらは全て0〜1で表され、1に近い方が性能が良いと言える。・上記評価指標を実装:関数をインポートして、それぞれ「y_true」と「y_pred」を引数として与えることで計算してくれる。
#precision_score:適合率, recall_score:再現率, f1_score:F値 のインポート from sklearn.metrics import precision_score,recall_score,f1_score y_true=[0,0,1,1] y_pred=[0,1,1,1] #F値の出力 print("F1".format(f1_score(y_true,y_pred))) # 0.666666・PR曲線:縦軸に適合率(Precision)、横軸に再現率(Recall)をとったグラフ。
・適合率と再現率はトレードオフの関係であり、場合によってどちらに重きを置くかを考える必要がある。特にこだわりがない時は、F値や、PR曲線においてPとRが一致する点(ブレークイーブンポイント(BEP))を用いると良い。
- 投稿日:2020-09-23T15:11:18+09:00
データクレンジング3
Aidemy 2020/9/23
はじめに
こんにちは、んがょぺです!文系大学生ですが、AI分野に興味が湧いたのでAI特化型スクール「Aidemy」に通い、勉強しています。ここで得られた知識を皆さんと共有したいと思い、Qiitaでまとめています。以前のまとめ記事も多くの方に読んでいただけてとても嬉しいです。ありがとうございます!
今回は、データクレンジングの3つ目の投稿になります。どうぞよろしくお願いします。*本記事は「Aidemy」での学習内容を「自分の言葉で」まとめたものになります。表現の間違いや勘違いを含む可能性があります。ご了承ください。
今回学ぶこと
・画像データについて
・OpenCV(画像を扱うライブラリ)でできること1 画像データについて
コンピュータ上の「色」
・データ上、色はRGBデータとして、赤、緑、青で表現される(255,0,255 など)。
・画像は点(ピクセル)の集まりでできている。
・1つのピクセルを表すための色要素の数をチャンネル数という(RGBなら三色なので「3」)。画像データの種類
・BMP 圧縮不可でサイズ大
・JPG 高圧縮可だが解凍不可
・PNG 圧縮解凍可 透過処理可
・GIF アニメをサポート 透過処理可2 OpenCV
OpenCVで画像の読み込み、表示
・OpenCVは画像を扱う際に使われるライブラリ。cv2をインポートして使う。
・cv2.imread("ファイル名")で読み込み
cv2.imshow("ウィンドウ名",読込済みの画像データ)で表示(ウィンドウ名は自由に付けてOK)import cv2 #sample.jpgというファイル名の画像を読み込む img = cv2.imread("./4050_data_cleansing_data/sample.jpg") #ウィンドウ名をwindowにしてimgを出力 cv2.imshow("window",img)画像の作成と保存(単色)
・画像を作成するには、np.array()関数(NumPyの行列を作る関数)を使う。また、range()を変数なしで多重ループさせて、縦横のピクセル情報(順番は青緑赤)を設定する。
・np.array([[[B,G,Rの値]for _ in range(横のサイズ)] for_ in range(縦のサイズ)],dtype="uint8")
*uint8型とは、int型の中でも0〜255の値しか取らないもの。
・画像の保存はcv2.imwrite("ファイル名",画像)で行う。#(512*512)の一面緑(0,255,0)の画像を作成 img = np.array([[[0,255,0]for _ in range(512)]for _ in range(512)],dtype="uint8") #imgを保存(ファイル名は「green.img」) cv2.imwrite("green.img",img)トリミング(切り取り)、リサイズ(拡大・縮小)
・トリミングは画像データ[y軸始点:y軸終点,x軸始点:x軸終点] 0は左上
・リサイズはcv2.resize(画像データ,(幅,高さ))で変更。#トリミング用に画像サイズを取得(高さ,幅,色数) size = img.shape #(1000,667,3) #高さが1/2、幅が1/3になるようトリミング(始点を指定せず、余りが出ないように割る) new_img=img[:size[0]//2,:size[1]//3] #高さ2倍、幅3倍にリサイズ new_img=cv2.resize(new_img,(new_img.shape[0]*2,new_img.shape[1]*3))回転・反転
・画像の回転にはアフィン変換という変換が必要であり、変換行列を取得しなければならない。
・cv2.getRotationMatrix2D(画像の中心座標,回転角度,拡大縮小の倍率)で変換行列を取得する。
・そしてcv2.warpAffine(画像,変換行列,出力サイズ)で実際に回転させる。・反転はcv2.flip(画像,flipCode)で行う。第二引数には、「0」と指定すれば上下反転、正の数を指定すれば左右反転、負の数を指定すれば上下左右反転となる。
#変換行列の取得(倍率2倍で90度回転) mat=cv2.getRotationMatrix(tuple(np.array([img.shape[1],img.shape[0]])/2),90,2.0) #実際に回転 cv2.warpAffine(img,mat,img.shape[::-1][1:3])色調変換・色反転
・今までは「BGR色空間」しか使っていなかったが、OpenCV上には他の色空間も存在する。
・cv2.cvtColor(画像,変換コード)で色空間を変更できる。変換コードは、例えばBGR色空間をLabという色空間に変換したい時は「cv2.COLOR_BGR2LAB」となる。・色反転は、各ピクセルを順番に取り出して、値xについて「255-x」とすることで行うこともできるが、
cv2.bitwise_not(画像)で簡単に反転できる。#imgの色空間をLabに変更 c_img=cv2.cvtColor(img,cv2.COLOR_BGR2LAB) #imgの色を反転 r_img=cv2.bitwise_not(img)OpenCVの応用
閾値処理
・画像の容量を小さくするために、色のデータを「白」「黒」のみにする。
・cv2.threshold(画像,閾値,最大値(濃度),閾値処理の種類)
*閾値より大きいか小さいかでデータを分ける。その分け方を第4引数に指定する。#閾値127、最大値255、種類はcv2.THRESH_TOZERO(閾値以下は0、閾値以上は変更なし) new_img=cv2.threshold(img,127,255,cv2.THRESH_TOZERO)マスキング
・白黒のマスク画像を別途準備し、cv2.bitwise_and()関数で元の画像と合わせると、元の画像のうち、マスク画像の白の部分しか出力されなくなる。これを「マスキング」という。
・cv2.bitwise_and(元の画像1,元の画像2(マスク時に使用),mask=マスク用の白黒画像)#マスク用画像を読み込み(チャンネル数1の白黒画像)、リサイズして大きさを揃える。 mask=cv2.imread("./4050_cleansing_data/mask.png", 0) mask=cv2.resize(mask,(img.shape[1],img.shape[0])) #マスキングする cv2.bitwise_and(img,img,mask=mask)画像をぼかす
・画像をぼかすには「ガウシアンフィルタ」を使う。1ピクセルの周りn*n(nは奇数)を平均化してぼかす。
・cv2.GaussianBlur(画像,(n*nの値),標準偏差)
*標準偏差は通常0。n*nの値と標準偏差が大きくなるほどぼかしが強くなる。#(51*51)のぼかしを行う new_img=cv2.GaussianBlur(img,(51,51),0)ノイズ(荒)の除去
・cv2.fastNlMeansDenoisingColored(画像)で行う。カラー画像でなければ関数名の「Colored」は抜いて良い。(NlMeansとは、Non-local Means Filterというノイズ除去のフィルターを指す、Denoisingはノイズを除去するという意味)
new_img=cv2.fastNlMeansDenoisingColored(img)収縮・膨張
・ノイズ処理の別の方法として、画像を一度収縮してから再度膨張させる方法がある。この方法は「閾値処理」のノイズ除去に使われることが多い。
・cv2.dilate(画像,フィルタ) で膨張、cv2.erode(画像,フィルタ) で収縮。#imgを閾値処理 new_img=cv2.threshold(img,127,255,cv2.THRESH_BYNARY) #フィルタの定義 filter=np.array([[0,1,0],[1,0,1],[0,1,0]],np.uint8) #収縮して膨張 new_img=cv2.erode(new_img,filter) new_img=cv2.dilate(new_img,filter)まとめ
・画像データはOpenCVで処理する。
・OpenCVでは、imread()で画像読み込み、imshow()で画像出力、resize()でリサイズ、flip()で反転、bitwise_notで色反転ができる。その他、画像作成やトリミング、回転などもできる。
・応用として、threshold()で閾値処理、bitwise_and()でマスキング、GaussianBlur()でぼかしを行う。その他、ノイズを除去することもできる。
- 投稿日:2020-09-23T15:11:18+09:00
データクレンジング3 OpenCVの利用と画像データの前処理
Aidemy 2020/9/23
はじめに
こんにちは、んがょぺです!文系大学生ですが、AI分野に興味が湧いたのでAI特化型スクール「Aidemy」に通い、勉強しています。ここで得られた知識を皆さんと共有したいと思い、Qiitaでまとめています。以前のまとめ記事も多くの方に読んでいただけてとても嬉しいです。ありがとうございます!
今回は、データクレンジングの3つ目の投稿になります。どうぞよろしくお願いします。*本記事は「Aidemy」での学習内容を「自分の言葉で」まとめたものになります。表現の間違いや勘違いを含む可能性があります。ご了承ください。
今回学ぶこと
・画像データについて
・OpenCV(画像を扱うライブラリ)でできること1 画像データについて
コンピュータ上の「色」
・データ上、色はRGBデータとして、赤、緑、青で表現される(255,0,255 など)。
・画像は点(ピクセル)の集まりでできている。
・1つのピクセルを表すための色要素の数をチャンネル数という(RGBなら三色なので「3」)。画像データの種類
・BMP 圧縮不可でサイズ大
・JPG 高圧縮可だが解凍不可
・PNG 圧縮解凍可 透過処理可
・GIF アニメをサポート 透過処理可2 OpenCV
OpenCVで画像の読み込み、表示
・OpenCVは画像を扱う際に使われるライブラリ。cv2をインポートして使う。
・cv2.imread("ファイル名")で読み込み
cv2.imshow("ウィンドウ名",読込済みの画像データ)で表示(ウィンドウ名は自由に付けてOK)import cv2 #sample.jpgというファイル名の画像を読み込む img = cv2.imread("./4050_data_cleansing_data/sample.jpg") #ウィンドウ名をwindowにしてimgを出力 cv2.imshow("window",img)画像の作成と保存(単色)
・画像を作成するには、np.array()関数(NumPyの行列を作る関数)を使う。また、range()を変数なしで多重ループさせて、縦横のピクセル情報(順番は青緑赤)を設定する。
・np.array([[[B,G,Rの値]for _ in range(横のサイズ)] for_ in range(縦のサイズ)],dtype="uint8")
*uint8型とは、int型の中でも0〜255の値しか取らないもの。
・画像の保存はcv2.imwrite("ファイル名",画像)で行う。#(512*512)の一面緑(0,255,0)の画像を作成 img = np.array([[[0,255,0]for _ in range(512)]for _ in range(512)],dtype="uint8") #imgを保存(ファイル名は「green.img」) cv2.imwrite("green.img",img)トリミング(切り取り)、リサイズ(拡大・縮小)
・トリミングは画像データ[y軸始点:y軸終点,x軸始点:x軸終点] 0は左上
・リサイズはcv2.resize(画像データ,(幅,高さ))で変更。#トリミング用に画像サイズを取得(高さ,幅,色数) size = img.shape #(1000,667,3) #高さが1/2、幅が1/3になるようトリミング(始点を指定せず、余りが出ないように割る) new_img=img[:size[0]//2,:size[1]//3] #高さ2倍、幅3倍にリサイズ new_img=cv2.resize(new_img,(new_img.shape[0]*2,new_img.shape[1]*3))回転・反転
・画像の回転にはアフィン変換という変換が必要であり、変換行列を取得しなければならない。
・cv2.getRotationMatrix2D(画像の中心座標,回転角度,拡大縮小の倍率)で変換行列を取得する。
・そしてcv2.warpAffine(画像,変換行列,出力サイズ)で実際に回転させる。・反転はcv2.flip(画像,flipCode)で行う。第二引数には、「0」と指定すれば上下反転、正の数を指定すれば左右反転、負の数を指定すれば上下左右反転となる。
#変換行列の取得(倍率2倍で90度回転) mat=cv2.getRotationMatrix(tuple(np.array([img.shape[1],img.shape[0]])/2),90,2.0) #実際に回転 cv2.warpAffine(img,mat,img.shape[::-1][1:3])色調変換・色反転
・今までは「BGR色空間」しか使っていなかったが、OpenCV上には他の色空間も存在する。
・cv2.cvtColor(画像,変換コード)で色空間を変更できる。変換コードは、例えばBGR色空間をLabという色空間に変換したい時は「cv2.COLOR_BGR2LAB」となる。・色反転は、各ピクセルを順番に取り出して、値xについて「255-x」とすることで行うこともできるが、
cv2.bitwise_not(画像)で簡単に反転できる。#imgの色空間をLabに変更 c_img=cv2.cvtColor(img,cv2.COLOR_BGR2LAB) #imgの色を反転 r_img=cv2.bitwise_not(img)OpenCVの応用
閾値処理
・画像の容量を小さくするために、色のデータを「白」「黒」のみにする。
・cv2.threshold(画像,閾値,最大値(濃度),閾値処理の種類)
*閾値より大きいか小さいかでデータを分ける。その分け方を第4引数に指定する。#閾値127、最大値255、種類はcv2.THRESH_TOZERO(閾値以下は0、閾値以上は変更なし) new_img=cv2.threshold(img,127,255,cv2.THRESH_TOZERO)マスキング
・白黒のマスク画像を別途準備し、cv2.bitwise_and()関数で元の画像と合わせると、元の画像のうち、マスク画像の白の部分しか出力されなくなる。これを「マスキング」という。
・cv2.bitwise_and(元の画像1,元の画像2(マスク時に使用),mask=マスク用の白黒画像)#マスク用画像を読み込み(チャンネル数1の白黒画像)、リサイズして大きさを揃える。 mask=cv2.imread("./4050_cleansing_data/mask.png", 0) mask=cv2.resize(mask,(img.shape[1],img.shape[0])) #マスキングする cv2.bitwise_and(img,img,mask=mask)画像をぼかす
・画像をぼかすには「ガウシアンフィルタ」を使う。1ピクセルの周りn*n(nは奇数)を平均化してぼかす。
・cv2.GaussianBlur(画像,(n*nの値),標準偏差)
*標準偏差は通常0。n*nの値と標準偏差が大きくなるほどぼかしが強くなる。#(51*51)のぼかしを行う new_img=cv2.GaussianBlur(img,(51,51),0)ノイズ(荒)の除去
・cv2.fastNlMeansDenoisingColored(画像)で行う。カラー画像でなければ関数名の「Colored」は抜いて良い。(NlMeansとは、Non-local Means Filterというノイズ除去のフィルターを指す、Denoisingはノイズを除去するという意味)
new_img=cv2.fastNlMeansDenoisingColored(img)収縮・膨張
・ノイズ処理の別の方法として、画像を一度収縮してから再度膨張させる方法がある。この方法は「閾値処理」のノイズ除去に使われることが多い。
・cv2.dilate(画像,フィルタ) で膨張、cv2.erode(画像,フィルタ) で収縮。#imgを閾値処理 new_img=cv2.threshold(img,127,255,cv2.THRESH_BYNARY) #フィルタの定義 filter=np.array([[0,1,0],[1,0,1],[0,1,0]],np.uint8) #収縮して膨張 new_img=cv2.erode(new_img,filter) new_img=cv2.dilate(new_img,filter)まとめ
・画像データはOpenCVで処理する。
・OpenCVでは、imread()で画像読み込み、imshow()で画像出力、resize()でリサイズ、flip()で反転、bitwise_notで色反転ができる。その他、画像作成やトリミング、回転などもできる。
・応用として、threshold()で閾値処理、bitwise_and()でマスキング、GaussianBlur()でぼかしを行う。その他、ノイズを除去することもできる。
- 投稿日:2020-09-23T14:51:20+09:00
Quip APIを作成してみた
はじめに
Quip上のスプレットシートに保存されたテキストを解析するために、Quip APIでQuipの特定のドキュメントにアクセスした。その際のアクセス方法を個人用にメモしておく。
※個人メモなので省略しまくってます。Access Tokenの取得
POSTMANでTokenを取得する。
詳しくは、Quip API Documentationを参照GET https://platform.quip.com/1/users/current実際にアクセスする
Github上のスプレットシートを取得する関数を用いてフォルダとドキュメントを取得する。
quip_analysis.pyimport quip # access to the quip client = quip.QuipClient(access_token=<access_token>) # Get your thread_id from the URL of your document user = client.get_authenticated_user() starred = client.get_folder(user["starred_folder_id"]) # get the spreadsheet spreadsheet = client.get_second_spreadsheet(thread_id=<thread_id>) parsedSpreadsheet = client.parse_spreadsheet_contents(spreadsheet)スプレット形式のデータを取得できるのでデータフレームに落とし込む
quip_analysis.py# create the dataframe counter = 0 spreadsheetData = [] colNames = [] for rows in parsedSpreadsheet["rows"]: cells = rows["cells"] rowData = [] for key, value in cells.items(): if counter == 0: colNames.append(key) rowData.append(value['content']) spreadsheetData.append(rowData) counter += 1 l = pd.DataFrame(spreadsheetData, columns=colNames)このあと形態素解析でドキュメント上の頻出ワードを抽出した。
- 投稿日:2020-09-23T14:35:28+09:00
Djangoで日本語出力がとまどった話
取りあえず、Djangoを使ってDBから出力をしていたのですが、どうにもうまくいかない感じ。
そこでバグ解決メモ。原因:Python3はUbuntuの環境変数で文字コードを変える!
Python 3で日本語をprintする際のUnicodeEncodeErrorはLANGに気をつける
こちらの記事によると、Python3はOSの環境変数によって使用する文字コードを変える
わたし、さくらVPSを使っているのですが、さくらのUbuntuはデフォルトで日本語パッケージを入っていないので、
DB側がUTF8、Pythonコンソール上がLatin1になっており、
Pythonコンソールで文字コードエラーが発生していた模様解決策:Ubuntuの日本語パッケージを導入する
という訳で、Ubuntuのデフォルトロケールを変更します!
'''
% sudo apt-get install language-pack-ja
% sudo update-locale LANG=ja_JP.UTF-8
% sudo reboot
'''取りあえず、テキストは動作
- 投稿日:2020-09-23T13:54:34+09:00
CentOS でJupyter Notebookをサービス化する
はじめに
Python 環境をCent OS で構築する際の手順をメモする.
あくまでも構築手順に関するメモなので,実際に本番環境で構築する際は,今回の情報で本番環境を構築・運用するわけではない.
環境は以下の通りで,VMware 上の仮想マシンで構築する.
- OS: Cent OS 7.5.1804
- 仮想化ソフト: VMware Workstation Pro 15.5.6 build-16341506
- CPU: 1 Processors
- メモリ: 1 GB
- ディスク: 50.0 GB
- Network Adapter: NAT (192.168.249.129/24)
やりたいことは以下のとおりである.
- Python 3 のインストール
- Qiskit のインストール
- Anaconda のインストール
- Jupyter のインストール
- Jupyter のサービス化
以下の手順からは,OS インストール済みで実施することを前提としている.
約束事として,#はroot ユーザー,$ は一般ユーザー,>>> はpython実行中を表すプロンプトとする.
初めて実施するので,遠回りや設定被りは上等です.まず初めに,アップデートしておく.
OSのアップデート# yum updatePython 3 のインストール
標準で使用できるPython 2 ではなく,Python 3 を使用したいので,インストールする.
実行コマンド# yum update python3インストール後,インストール確認も含めバージョン情報を表示する.
Python 3.6.8 がインストールされていることが分かる.Pythonのバージョン確認# python3 --version Python 3.6.8また,python コマンドで今回導入したpython3 を使用したいため,設定を行う.
プロファイル編集# vim ~/.bashrc.bashrc の末尾に,以下の内容を追記する.
追記後,一度ログアウトし,再度ログインする./root/.bashrcalias python="python3" alias pip="pip3"試しに,python コマンドでバージョン確認してみる.
python3 が指定されていることが分かる.Pythonのバージョン確認# python --version Python 3.6.8Anaconda のインストール
pyenv のインストールにgit が必要なため,まずはgit をインストールする.
gitのインストール# yum install gitpyenv をインストールしていく.
pyenvのインストール# git clone https://github.com/yyuu/pyenv.git ~/.pyenv # pyenv install -l | grep anaconda anaconda-1.4.0 anaconda-1.5.0 anaconda-1.5.1 anaconda-1.6.0 anaconda-1.6.1 anaconda-1.7.0 anaconda-1.8.0 anaconda-1.9.0 anaconda-1.9.1 anaconda-1.9.2 anaconda-2.0.0 anaconda-2.0.1 anaconda-2.1.0 anaconda-2.2.0 anaconda-2.3.0 anaconda-2.4.0 anaconda-4.0.0 anaconda2-2.4.0 anaconda2-2.4.1 anaconda2-2.5.0 anaconda2-4.0.0 anaconda2-4.1.0 anaconda2-4.1.1 anaconda2-4.2.0 anaconda2-4.3.0 anaconda2-4.3.1 anaconda2-4.4.0 anaconda2-5.0.0 anaconda2-5.0.1 anaconda2-5.1.0 anaconda2-5.2.0 anaconda2-5.3.0 anaconda2-5.3.1 anaconda2-2018.12 anaconda2-2019.03 anaconda2-2019.07 anaconda3-2.0.0 anaconda3-2.0.1 anaconda3-2.1.0 anaconda3-2.2.0 anaconda3-2.3.0 anaconda3-2.4.0 anaconda3-2.4.1 anaconda3-2.5.0 anaconda3-4.0.0 anaconda3-4.1.0 anaconda3-4.1.1 anaconda3-4.2.0 anaconda3-4.3.0 anaconda3-4.3.1 anaconda3-4.4.0 anaconda3-5.0.0 anaconda3-5.0.1 anaconda3-5.1.0 anaconda3-5.2.0 anaconda3-5.3.0 anaconda3-5.3.1 anaconda3-2018.12 anaconda3-2019.03 anaconda3-2019.07 anaconda3-2019.10 anaconda3-2020.02最新のanaconda をインストールする.
anacondaのインストール# pyenv install anaconda3-5.3.1設定をしていく.
anacondaの設定# pyenv rehash # pyenv global anaconda3-5.3.1 # echo 'export PATH="$PYENV_ROOT/versions/anaconda3-5.3.1/bin/:$PATH"' >> ~/.bashrc # source ~/.bashrc # conda update condaバージョンを確認してみる.
condaのバージョン確認# conda --version conda 4.8.4Qiskit のインストール
ここまでで,anaconda のインストールが完了したので,次にQiskit をインストールする.
Qiskitのインストール# pip install qiskitインストールされているか,確認する.
Qiskitのインストール確認# conda list | grep qiskit qiskit 0.21.0 pypi_0 pypi qiskit-aer 0.6.1 pypi_0 pypi qiskit-aqua 0.7.5 pypi_0 pypi qiskit-ibmq-provider 0.9.0 pypi_0 pypi qiskit-ignis 0.4.0 pypi_0 pypi qiskit-terra 0.15.2 pypi_0 pypi次に,インストールされているQiskit のバージョンを確認する.
python実行# pythonQiskitのバージョン確認>>> import qiskit >>> qiskit.__qiskit_version__ {'qiskit-terra': '0.15.2', 'qiskit-aer': '0.6.1', 'qiskit-ignis': '0.4.0', 'qiskit-ibmq-provider': '0.9.0', 'qiskit-aqua': '0.7.5', 'qiskit': '0.21.0'}確認が完了したら,Ctrl-D で,python を終了する.
Jupyter のインストール
次に,jupyter をインストールしてみる.
コマンド補完をしてみると,すでに jupyter がインストールされているようなので,実行してみると以下のエラーが出力された.jupyterの実行エラー# jupyter --version Traceback (most recent call last): File "/root/.pyenv/versions/anaconda3-5.3.1/bin/jupyter", line 7, in <module> from jupyter_core.command import main ModuleNotFoundError: No module named 'jupyter_core'一度conda からjupyter をインストールしてみる.
jupyterのインストール# conda install jupyterすると,以下のようなエラーが出力されてインストールが完了しない.
jupyterインストール時のエラーfailed with initial frozen solve. Retrying with flexible solve. Solving environment: - 強制終了
ググってみて,以下のコマンドを実行してみた.
condaのアップデート# conda update --all上記のコマンドでもエラーがでた.次に試しに以下のコマンドを実行した.
OpenCVのインストール# conda install -c menpo opencvこっちはうまくいった.再度jupyter をインストールしてみる.
jupyterのインストール再挑戦# conda install jupyter Collecting package metadata (repodata.json): done Solving environment: done # All requested packages already installed.ちゃんとインストールされているようにみえる.
バージョン情報を確認してみる.jupyterのバージョン確認# jupyter --version 4.4.0ちゃんとインストールされていて,動作もする.
Jupyter Notebook の設定を行う.
jupyterの起動準備# jupyter --path config: /root/.jupyter /root/.pyenv/versions/anaconda3-5.3.1/etc/jupyter /usr/local/etc/jupyter /etc/jupyter data: /root/.local/share/jupyter /root/.pyenv/versions/anaconda3-5.3.1/share/jupyter /usr/local/share/jupyter /usr/share/jupyter runtime: /run/user/1000/jupyter # mkdir ~/.jupyter # touch ~/.jupyter/jupyter_notebook_config.py # mkdir ~/jupyter_files # touch ~/jupyter_files/test.py # ipythonログインパスワードの設定Python 3.7.0 (default, Oct 9 2018, 10:31:47) Type 'copyright', 'credits' or 'license' for more information IPython 6.5.0 -- An enhanced Interactive Python. Type '?' for help. In [1]: from notebook.auth import passwd In [2]: passwd() Enter password: Verify password: Out[2]: 'sha1:da72b0981831:41b14f79bbfeda08322cfdb3a056a58fc70c65ea' In [3]: exitOut[2] のパスワードのハッシュ値は次のコンフィグファイルの編集で使用するため,テキストエディタ等に控えておく.
コンフィグファイルの編集vim ~/.jupyter/jupyter_notebook_config.py
コンフィグファイルに以下を追記する.
パスワードのハッシュ値については,ログインパスワードの設定のところで出力された値をそれぞれコピー&ペーストすること./root/.jupyter/jupyter_notebook_config.pyc = get_config() c.NotebookApp.ip = '*' c.NotebookApp.open_browser = False c.NotebookApp.port = 8888 c.NotebookApp.password = u'sha1:da72b0981831:41b14f79bbfeda08322cfdb3a056a58fc70c65ea' c.NotebookApp.notebook_dir = '/root/jupyter_files/'Jupyter Notebook を起動する.本環境はお試し環境であり,root ユーザーで設定しているので,以下のコマンドを実行する.
notebookの起動# jupyter notebook --allow-rootその後,Web ブラウザを用いてhttp://localhost:8888/ にアクセスしてみる.
アクセスできたので,先ほど設定したログインパスワードでログインしてみる.
無事ログインできた.先ほど作成した確認用のファイルtest.py も確認できる.
次に,ホストマシンのWeb ブラウザを用いてアクセスできるようにする.
ファイアウォールでポート8888 を許可する.ファイアウォールの許可設定# firewall-cmd --add-port=8888/tcp --zone=public --permanent success # firewall-cmd --reload successホストマシンのWeb ブラウザからhttp://192.168.249.129:8888/ にアクセスしてみる.
無事にアクセスできた.
Jupyter のサービス化
Jupyter をsystemd で制御できるように設定する.まずは,jupyter のパスを確認する.
jupyterのパス確認# which jupyter /root/.pyenv/versions/anaconda3-5.3.1/bin/jupyter定義ファイルの作成# vim /etc/systemd/system/notebook.service※以下の内容ではうまく実行できません
/etc/systemd/system/notebook.service[Unit] Description = Jupyter Notebook [Service] Type=simple PIDFile=/var/run/jupyter-notebook.pid ExecStart=/root/.pyenv/versions/anaconda3-5.3.1/bin/jupyter notebook WorkingDirectory=/root/ User=root Group=root Restart=always [Install] WantedBy = multi-user.target設定ファイル再読み込み# systemctl daemon-reloadサービス起動# systemctl start notebookサービスの状態を確認すると,失敗していた.
サービスの状態確認(失敗)# systemctl status notebook ● notebook.service - Jupyter Notebook Loaded: loaded (/etc/systemd/system/notebook.service; disabled; vendor preset: disabled) Active: failed (Result: start-limit) since 金 2020-09-18 15:21:44 JST; 1min 8s ago Process: 18766 ExecStart=/root/.pyenv/versions/anaconda3-5.3.1/bin/jupyter notebook (code=exited, status=1/FAILURE) Main PID: 18766 (code=exited, status=1/FAILURE) 9月 18 15:21:44 localhost.localdomain systemd[1]: notebook.service: main process exited, code=exited, status=1/FAILURE 9月 18 15:21:44 localhost.localdomain systemd[1]: Unit notebook.service entered failed state. 9月 18 15:21:44 localhost.localdomain systemd[1]: notebook.service failed. 9月 18 15:21:44 localhost.localdomain systemd[1]: notebook.service holdoff time over, scheduling restart. 9月 18 15:21:44 localhost.localdomain systemd[1]: Stopped Jupyter Notebook. 9月 18 15:21:44 localhost.localdomain systemd[1]: start request repeated too quickly for notebook.service 9月 18 15:21:44 localhost.localdomain systemd[1]: Failed to start Jupyter Notebook. 9月 18 15:21:44 localhost.localdomain systemd[1]: Unit notebook.service entered failed state. 9月 18 15:21:44 localhost.localdomain systemd[1]: notebook.service failed.原因をいろいろ考えていると,最初の起動は--allow-root を付与していたのに,今回の設定ファイルでは付与し忘れていたのを思い出した.
以下のように設定ファイルを再編集する./etc/systemd/system/notebook.service[Unit] Description = Jupyter Notebook [Service] Type=simple PIDFile=/var/run/jupyter-notebook.pid ExecStart=/root/.pyenv/versions/anaconda3-5.3.1/bin/jupyter notebook --allow-root WorkingDirectory=/root/ User=root Group=root Restart=always [Install] WantedBy = multi-user.target再度,設定ファイルの読み込みをしてサービスを起動させる.
設定ファイル再読み込みとサービス起動# systemctl daemon-reload # systemctl start notebookサービスの状態を確認する.
サービスの状態確認(成功)# systemctl status notebook ● notebook.service - Jupyter Notebook Loaded: loaded (/etc/systemd/system/notebook.service; enabled; vendor preset: disabled) Active: active (running) since 金 2020-09-18 15:29:38 JST; 3min 8s ago Main PID: 19068 (jupyter-noteboo) Tasks: 1 CGroup: /system.slice/notebook.service └─19068 /root/.pyenv/versions/anaconda3-5.3.1/bin/python /root/.pyenv/versions/anaconda3-5.3.1/bin/jupyter-notebook --... 9月 18 15:29:38 localhost.localdomain systemd[1]: Started Jupyter Notebook. 9月 18 15:29:39 localhost.localdomain jupyter[19068]: [W 15:29:39.391 NotebookApp] WARNING: The notebook server is listeni...nded. 9月 18 15:29:39 localhost.localdomain jupyter[19068]: [I 15:29:39.393 NotebookApp] The port 8888 is already in use, trying...port. 9月 18 15:29:39 localhost.localdomain jupyter[19068]: [I 15:29:39.423 NotebookApp] JupyterLab extension loaded from /root/...erlab 9月 18 15:29:39 localhost.localdomain jupyter[19068]: [I 15:29:39.423 NotebookApp] JupyterLab application directory is /ro...r/lab 9月 18 15:29:39 localhost.localdomain jupyter[19068]: [I 15:29:39.426 NotebookApp] Serving notebooks from local directory:...files 9月 18 15:29:39 localhost.localdomain jupyter[19068]: [I 15:29:39.426 NotebookApp] The Jupyter Notebook is running at: 9月 18 15:29:39 localhost.localdomain jupyter[19068]: [I 15:29:39.426 NotebookApp] http://(localhost.localdomain or 127.0....8889/ 9月 18 15:29:39 localhost.localdomain jupyter[19068]: [I 15:29:39.427 NotebookApp] Use Control-C to stop this server and s...ion). Hint: Some lines were ellipsized, use -l to show in full.今度は無事に立ち上がった見たい.
自動実行を有効にする.自動実行の有効化と確認# systemctl enable notebook # systemctl is-enabled notebook enabled自動起動が有効化された.確認のため,ゲストOSを再起動したあと,ホストマシンから先ほどのURL でアクセスしてみたが,無事にアクセスできた.これで常にJupyter Notebook が立ち上がっている状態になり,Web ブラウザを用いて利用可能になった.
おわりに
今回試してみて思ったのが,root ユーザーでの実行は推奨されていないうえ,コマンドもオプションが必要になってきていろいろ面倒なので,サービスユーザーを作成して当ユーザーでサービスを実行したほうが良いと感じた.
あと,別記事で書いていますが,これやるならJupyterHub の方がよいと感じた.参考文献
- 投稿日:2020-09-23T13:23:30+09:00
スタックを Python で書いてみた
スタックって、そもそも何?
はい、データを貯めて、取り出す。それだけです。
但し、取り出し方は最後に貯めたデータを最初に取り出せるようにしたいです。
Σ(oдΟ;)例えばですが以下にあるようにデータを 6 個、縦に積み上げながら
格納できる箱があったとします。
まずは、箱を空にして、A を格納した後に、取り出してみましょう。
A を格納して、取り出したら、元の空の状態に戻りました。
簡単ですね。ではデータの格納を Push , 取り出しを Pop と命名したうえで、
データの Push / Pop を動きをもう少し図にしてみました。
A , B を Push し、最後に pop してみました。最後に箱に残るのは A ですよね。
このようにして、最後に Push したデータを最初に Pop するスタックの動きをイメージできるようになりました。箱の深さが 6 無くても良かったんでは!?
細かい事は気にしない(笑)。
さぁ、次は Python で書いてみましょう。っとその前に、ここでの記述が分からない場合は、
Progate での学習をお勧めします!!
https://prog-8.com/では最初にスタックを実現するための箱を用意しましょう。
イメージはこんな感じです。
str という名の箱を用意し、何個データが入るかを capacity としました。
ptr は 1 ~ 6 の位置を表しています。
先ほどの図に ptr の動きを足してみました。
こんな感じで、ptr(ポインタ)は Push 出来る箱の位置を表しています。
ptr をイメージできたところで、やっと Python です。
箱を作ってみました。stack.pydef __init__(self,capacity:int = 10): self.str = [None] * capacity self.capa = capacity self.ptr = 0" def __ init __ " 用意したプログラム内の初期値を定めます! っという決まり文句です。
プログラムが走るときに最初に読み込んで貰わないと話が始まらないですよね。
次に Push です。stack.pydef push(self,value): if self.ptr >= self.capa: raise top.full self.str[self.ptr] = value print(self.str[self.ptr]) self.ptr += 1間に print が入っていますが、無視しても良いです。
大切なのは、最初に ptr の位置が Full になっていないか確認することです。
ptr == capacity であれば Full (お腹いっぱい)
ptr > capacity であれば、プログラムが暴走してる!! ってことになります。
if self.ptr >= self.capa: で確認していることが分かります。
Full でなければ self.str[self.ptr] = value とし、無事に Push 完了です。
次の Push に備えて ptr を一つインクリメントしておきます。
Push でやっていることは以上です。次に Pop です。
stack.pydef pop(self): if self.ptr <= 0: raise top.empty self.ptr -= 1 return self.str[self.ptr]ポインタ ptr が マイナスになっていたとすると、
底を突き抜けて、地面にデータをねじ込むことになるので
一応 if 文でチェックを掛けます。
ここで疑問に思った方も居ると思いますので
補足しますが、Python の世界では格納領域は 1 から始まるわけではなく、
0 から始まります。
最初の図が良くなかった、すいません。
よって ptr = 0 の場合は、空を意味します。Empty ってやつです。
空じゃなければ以下のように ptr を 1 減らして、
取り出すデータを指定します。
後は return self.str[self.ptr] とすることで、格納したデータを取り出すことが出来ます。いやいや、return でデータは返せたけど、
指定した領域は空になってないよね!?
Yes ! その通り!!バコ~ン!( - -)/☆(_)実はですね、スタックは ptr の位置でデータの管理をしています。
たとえ、空にする処理をしていなくても、次の Push で自動的に書き換えられますよね?
だから ptr の動きだけ見ていればスタックは出来てしまうのです。
っというわけで、取り急ぎ用意したスタックの全体像を載せておきます。stack.pyclass top: class full(Exception): pass class empty(Exception): pass def __init__(self,capacity:int = 10): self.str = [None] * capacity self.capa = capacity self.ptr = 0 def push(self,value): if self.ptr >= self.capa: raise top.full self.str[self.ptr] = value print(self.str[self.ptr]) self.ptr += 1 def pop(self): if self.ptr <= 0: raise top.empty self.ptr -= 1 return self.str[self.ptr] test = top() while True: num = int(input("select 1.push , 2.pop : ")) if num == 1 : s = int(input("enter data: ")) try: test.push(s) except test.full: print("full!") elif num == 2: try: x = test.pop() print(x) except test.empty: print("empty!") else: break多分、"__ init __" , push , pop が肝なので、そこが分かれば、
ご理解いただけると思っています。初めての投稿ですので、不足分、分かりにくい所があれば
ガンガン優しくご指摘御願い致します!!m(_ _)m
- 投稿日:2020-09-23T13:01:52+09:00
Amazon LinuxにLightFMをインストールしようとしてハマった話
タイトルそのままなんですが、備忘録として。
結論から言うと「Amazon LinuxのgccにはOpenMPの実行環境が入っていないので手動再インストールが必要」ということ。
LightFMに関してはこの辺を確認してみてください
- 教師あり機械学習で映画を推薦するモデルを作成する【LightFM】
https://sja-analysis.org/python-lightfm/- LightFMをMovielensに適用してみた
https://qiita.com/guglilac/items/757fc665510c9b68f385さて、ひとまずLightFMのインストールは
pip install lightfmでOKなのですが、これをAmazon Linux上で普通に実施すると
omp.h: そのようなファイルやディレクトリはありません
というエラーが出てきます。で、ここの記事を参考にすると以下の通り
原因ですが、yumでインストールされるgcc7.2には、Qulacsが使っているOpenMPのヘッダーファイルomp.hが含まれていない様子。
で、どうするかというと
sudo yum erase gcc72 gcc72-c++ libgcc72で一旦gcc7.2を削除します。その上で、あらためてgcc 7.4.0を手作業でインストールします。
お~そういうことですか。
というわけで、gccをソースからビルド/インストールしないといけないわけですが、そのまんまな記事が。大変参考になりました。
- gccをソースからビルド/インストールする
https://qiita.com/liveralmask/items/6ed4a98ebb3bf6b7f707ほぼこちらに書いてあることそのまんまですが、バージョンに関しては2020/9/23現在は10.2.0が最新ということでそこだけ変えて。実行コマンドは以下の通り。
wget http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gcc-10.2.0/gcc-10.2.0.tar.gz tar zxvf gcc-10.2.0.tar.gz cd gcc-10.2.0 ./contrib/download_prerequisites mkdir build cd build ../configure --enable-languages=c,c++ --prefix=/usr/local --disable-bootstrap --disable-multilib make > /dev/null sudo make install allmake実施時に結構時間かかりますので、気長に待ちましょう。
で、上記実施後再度
pip install lightfmを実行するとすんなりインストール出来ます。
- 投稿日:2020-09-23T12:48:22+09:00
KintoneのREST API用スニペット(APIトークン認証用ヘッダーの書き方、ログイン名パスワード用認証ヘッダーの書き方、クエリの書き方)
一通り使ってみたのでよく使うものに関しての備忘録
インターン先でKintoneから一部のデータを利用するためにREST APIを初めてしっかり勉強しました。そのうえでKintone特有の書き方っぽいものだけまとめました。
基本的にKintoneのドキュメントにはJavaScriptのスニペットしか置いていないので、どこまでがREST APIの仕様でどこからがKintone REST APIの仕様なのかわからない部分が多かったのでKintone REST APIの仕様の部分だけをピックアップした感じです。
下記URLの一部をpythonように書き下しました。
https://developer.cybozu.io/hc/ja/articles/201941754APIトークン利用時のヘッダー
headers = {"X-Cybozu-API-Token": api_token}IDとパスワードで認証するときのヘッダー
import base64 str_ = str(id_) +':' + str(password)#'id:password' encoded = base64.b64encode(str_.encode('utf-8')) header = { "X-Cybozu-Authorization":encoded }レコードをとるときにクエリを書いて一括取得するときのURLの書き方
参考URL
https://developer.cybozu.io/hc/ja/articles/202331474import urllib url = 'https://{ドメイン名}.cybozu.com/k/v1/records.json?app={}&query={}'.format('アプリ番',urllib.parse.quote('クエリを記入'))
- 投稿日:2020-09-23T12:23:41+09:00
Machine Learning : Supervised - Linear Discriminant Analysis
目標
フィッシャーの線形判別分析を数式で理解して、scikit-learn で試す。
微分積分、線形代数が既習であることを前提としています。
理論
フィッシャーの線形判別分析は、データを射影した後のカテゴリー間の分布が重ならないような $w$ を求める教師あり手法で、判別という名前が付いていますが実用上は次元削減に用いられます。
フィッシャーの線形判別分析
フィッシャーの線形判別分析の導出
データ $x$ を $w$ で射影すると、射影後のデータ $y$ は、
y = w^T xとなります。このとき、$y$ におけるカテゴリーの分布ができるだけ離れるような $w$ を求めることになります。下図のような場合、最適な $w$ は青の点群と橙の点群を黒の直線上の中抜きの点に射影します。
ここで、上図のような 2カテゴリーのデータについて考えます。カテゴリー 1, 2 の平均ベクトルは以下のように表せます。
\mu_1 = \frac{1}{N_1} \sum^{N_1}_{i \in C_1} x_i \\ \mu_2 = \frac{1}{N_2} \sum^{N_2}_{i \in C_2} x_i平均ベクトルを $w$ で射影したものを $m_1 = w^T\mu_1, m_2 = w^T\mu_2$ で表すと、射影後の平均値の差
m_1 - m_2 = w^T (\mu_1 - \mu_2)が大きいほどカテゴリー間の分離度が大きくなります。したがって、$w$ を最大すればよいことになります。しかし本当に求めたいのは $w$ の射影方向なので、$|w|^2 = 1$ という制約を付けておきます。しかしこれだけでは上手くいかないので、各カテゴリーの分散も考慮します。各カテゴリーの射影後のクラス内分散 $s^2_1, s^2_2$ は、
s^2_1 = \sum^{N_1}_{i \in C_1} (w^T x_i - w^T \mu_1)^2 \\ s^2_2 = \sum^{N_2}_{i \in C_2} (w^T x_i - w^T \mu_2)^2射影後の分散は小さいほどよいので、$s^2_1, s^2_2$ を合わせた全クラス内分散 $s^2 = s^2_1 + s^2_2$ を最小化すればよいことになります。
ここで、射影後の平均値の最大化と射影後の分散の最小化の両方を考慮する評価関数として、以下のフィッシャーの基準 $J(w)$ を定義します。
J(w) = \frac{(m_1 - m_2)^2}{s^2_1 + s^2_2}また、クラス間共分散行列を $S_B = (\mu_1 - \mu_2)(\mu_1 - \mu_2)^T$ とすると、クラス間変動 $(m_1 - m_2)^2$ は、
\begin{align} (m_1 - m_2)^2 &= \left( w^T(\mu_1 - \mu_2) \right)^2 \\ &= \left( w^T(\mu_1 - \mu_2) \right) \left( w^T(\mu_1 - \mu_2) \right)^T \\ &= w^T (\mu_1 - \mu_2)(\mu_1 - \mu_2)^T w \\ &= w^T S_B w \end{align}と表せます。さらにクラス内分散 $s^2_k$ は、
\begin{align} s^2_k &= \sum_{i \in C_k} (y_i - m_k)^2 \\ &= \sum_{i \in C_k} \left( w^T (x_i - \mu_k) \right)^2 \\ &= \sum_{i \in C_k} \left( w^T(x_i - \mu_k) \right) \left( w^T(x_i - \mu_k) \right)^T \\ &= w^T \sum_{i \in C_k} (x_i - \mu_k)(x_i - \mu_k)^T w \\ &= w^T S_k w \end{align}と表せるので、全クラス内分散 $s^2_1 + s^2_2$ は、総クラス内共分散行列を $S_W = S_1 + S_2$ として、
s^2_1 + s^2_2 = w^T (S_1 + S_2) w = w^T S_W wと表せます。したがって、フィッシャーの基準 $J(w)$ は、
J(w) = \frac{w^T S_B w}{w^T S_W w}となり、これを最大化することになります。
フィッシャーの線形判別分析の学習
求めるべきは最大値なので、フィッシャーの基準 $J(w)$ を $w$ について微分して 0 として解きます。
\begin{align} \frac{\partial J(w)}{\partial w} &= \frac{2S_B w \cdot w^TS_Ww - w^TS_Bw \cdot 2S_Ww}{(w^TS_Ww)^2} \\ &= \frac{2}{w^TS_Ww} \left( S_Bw - \frac{w^TS_Bw}{w^TS_Ww} S_Ww \right) = 0 \end{align}ここで、$\lambda = \frac{w^TS_Bw}{w^TS_Ww}$ とおいて、
\frac{\partial J(w)}{\partial w} = \frac{2}{w^TS_Ww} (S_Bw - \lambda S_Ww) = 0 \\ (S_Bw - \lambda S_Ww) = 0したがって、下の式の一般化固有値問題を解くことになります。
S_Bw = \lambda S_Wwここで、$S_W$ が正則行列であれば、
\lambda w = S^{-1}_WS_Bwとできて、通常の固有値問題になります。さらに、
S_Bw = (\mu_1 - \mu_2)(\mu_1 - \mu_2)^Tw \propto (\mu_1 - \mu_2)となることから、
w \propto S^{-1}_WS_Bw \propto S^{-1}_W (\mu_1 - \mu_2)として、最適な $w$ を求めることができます。
実装
実行環境
ハードウェア
・CPU Intel(R) Core(TM) i7-6700K 4.00GHz
ソフトウェア
・Windows 10 Pro 1909
・Python 3.6.6
・matplotlib 3.3.1
・numpy 1.19.2
・scikit-learn 0.23.2実行するプログラム
実装したプログラムは GitHub で公開しています。
fisher_lda.py結果
今回は scikit-learn の提供する iris dataset を用いることにしました。
実行結果は以下のようになります。setosa はよく分離されており、versicolor と virginica は一部被っていますが、まずまず分離できているように見えます。
参考
1.2. Linear and Quadratic Discriminant Analysis
平井有三.『はじめてのパターン認識』,森北出版,2012.
- 投稿日:2020-09-23T12:04:41+09:00
Python(スライス表記)を読むときの2つのルール
今回はPython のスライス表記について書いていきます。
スライスは単純なルールで表記されますが、初学者に方にとっては
何回か使用していると、ややこしくなってしまう瞬間があるかと思います。その際、意識しておくべき2つのルールについてお話していきます。
■ スライスを読むときの、2つのルール
①データの順番は0番目から始まる(リストの基本)
②スライスの終わりは $n-1$ となる実際に例をあげて説明していきます。
下記のようなデータを用意します。
ルール①では単純に、先頭データから0番目、1番目、2番目・・・と順番が決められているので
それをもとに、数字を抽出していきます。
上記のように、インデックス番号(0から始まる順位付け)をもとに数字の抽出ができました。
このルールだけならば、まだ簡単だとは思います。次に、②のルールについて説明していきます。
ここで、ややこしい問題が発生します。
今回のリストでは、0から数えて5番目のデータが10でしたが
スライスで5番目までを指定して抽出しても、9までしか出力されていません。このようにスライスでは、インデックス番号の範囲を指定する際に
終わりの番号の一歩手前、 $n-1$ までの順番までしか抽出されません。(今回は $n=5$)
実際に他の数字も入れて確かめてみます。
初学者の方は、学習中にルール①は意識して写経などをされるかと思いますが
いきなり上記のようなスライスの表記が出てくると、複雑に考えてしまうことがあるかと思います。その際には、最初にお伝えした2つのルールをもとに考えてみてください。
- 投稿日:2020-09-23T11:43:28+09:00
cronでGithubにPushするプロセスを自動化する
やったこと
Pythonとcrontabを使って、データファイル(pklフォーマット)を一週間に一回(土曜日の午後7時)に更新されるようにしました。
毎週更新されるデータをGithubに自動的にPushしたく、同じくcrontabを使ってやってみた。
環境
- Linux Mint 19
- Python 3.6.9
- git 2.17.1
GithubでSSH接続する
ssh接続する方法はたくさんネットに上がっているので割愛します。
(参考: GitHubにssh接続できるようにする)GITコマンドでプッシュしてみる
ssh接続が出来たら、gitコマンドでPushしてみる。
アップしたいデータファイルはplayers_data.pklというpythonのpickleというモジュールを使用したフォーマットです。
git add players_data.pkl git commit -m "最初のコミット" git remote add origin git@github.com:<ユーザー名>/<レポジトリ名> git push origin master自動化のPythonコードを作成
この一連の作業を自動化するPythonのコードを書きます。
使用するのはsubprocessというModuleで、bashコマンドをPythonで実行することが出来ます。(参考:Python の subprocess)
new_data.pyimport os import datetime import subprocess as cmd #input values new_date = datetime.datetime.now().strftime('%Y%m%d') current_dir = os.getcwd() #Subprocessで自動化 cp = cmd.run(f"git -C {current_dir} add players_score.pkl", check=True, shell=True) cp = cmd.run(f"git -C {current_dir} commit -m 'scoresheet updated on {new_date}'", check=True, shell=True) cp = cmd.run(f"git -C {current_dir} push origin master", check=True, shell=True) print('Githubへのアップ成功!')この段階で
python3 new_data.py
をbashで実行し、ちゃんとGithubにアップされているか確認してもよいでしょう。SSH のラッパースクリプト(git-ssh.sh)を作成
ここが今回引っかかったところなのですが、crontabでgit push origin masterを実行しようとすると、以下のようなエラーがでます。
Command 'git -C /path/to/folder/ push origin master' returned non-zero exit status 128.
cron から自動で git push するを参考にすると、
cron から自動で git push したい時、ssh の秘密鍵を明示的に指定して git push する必要があります。
というわけで以下のSHファイルを.sshのあるフォルダーに置いてやることが必要です。
/path/to/.ssh/git-ssh.sh#!/bin/sh exec ssh -oIdentityFile=/path/to/.ssh/id_rsa "$@"このSHファイルに実行権限を与えることも必要。
cd /path/to/.ssh chmod +x git-ssh.shSHファイルでPythonを動かす
直接Crontabでやってもいいのですが、今回はSHファイルを作成してPythonを動かすようにします。
scripts.sh#!/bin/sh cd /path/to/folder export GIT_SSH=/path/to/.ssh/git-ssh.sh python3 new_data.py > output_newdata.txtcrontabでSHファイルを定期的に実行する
最後にcrontabで定期実行の方法です。
まず
crontab -e
をbashで実行し、crontabを開けます。Cronの設定の仕方は割愛しますが、毎週土曜日の午後7:00にscripts.shを定期実行したいときは下記のようにします。(参考:crontabのガイドライン)
00 19 * * 6 bash /path/to/folder/scripts.shこれでうまく定期実行のできるようになりました。
参考サイトまとめ
- 投稿日:2020-09-23T11:09:49+09:00
【音響解析】xeno-cantoで鳥の鳴き声データを集める
xeno-cantoとは
鳥の鳴き声データベース。jsonで扱えるAPIがある。
今回はPythonを使って日本におけるFulica属(オオバン属)の鳴き声を一括収集した。ソースコード
import requests import json import urllib url = "https://www.xeno-canto.org/api/2/recordings?query=gen:Fulica+cnt:japan" # json取得(requests.get) response = requests.get(url) jsonData = response.json()["recordings"] # ダウンロード部(ファイル名は{id}.mp3) for data in jsonData: url = ("http:"+data["file"]) title = data["id"] urllib.request.urlretrieve(url,"{0}.mp3".format(title))urlについて
Xeno-cantoのAPIドキュメントによると、クエリには、
*gen
: 一般名
*sp
: specific name
*ssp
: subsupecific name
*en
: english name
*cnt
: country
などを指定できる。今回の
url = "https://www.xeno-canto.org/api/2/recordings?query=gen:Fulica+cnt:japan"では、
gen : Fulica
,cut : Japan
で指定している。ダウンロード部について
url = ("http:"+data["file"])において、
["file"]
というキーの中に、ダウンロード用urlが入っている。
(http:
がついていないので、追記。)環境
python 3.7.4 (Anaconda)
MacOS Catalina 10.15.5
- 投稿日:2020-09-23T11:09:49+09:00
【音声解析】xeno-cantoで鳥の鳴き声データを集める
xeno-cantoとは
鳥の鳴き声データベース。jsonで扱えるAPIがある。
今回はPythonを使って日本におけるFulica属(オオバン属)の鳴き声を一括収集した。ソースコード
import requests import json import urllib url = "https://www.xeno-canto.org/api/2/recordings?query=gen:Fulica+cnt:japan" # json取得(requests.get) response = requests.get(url) jsonData = response.json()["recordings"] # ダウンロード部(ファイル名は{id}.mp3) for data in jsonData: url = ("http:"+data["file"]) title = data["id"] urllib.request.urlretrieve(url,"{0}.mp3".format(title))urlについて
Xeno-cantoのAPIドキュメントによると、クエリには、
*gen
: 一般名
*sp
: specific name
*ssp
: subsupecific name
*en
: english name
*cnt
: country
などを指定できる。今回の
url = "https://www.xeno-canto.org/api/2/recordings?query=gen:Fulica+cnt:japan"では、
gen : Fulica
,cut : Japan
で指定している。ダウンロード部について
url = ("http:"+data["file"])において、
["file"]
というキーの中に、ダウンロード用urlが入っている。
(http:
がついていないので、追記。)環境
python 3.7.4 (Anaconda)
MacOS Catalina 10.15.5