mecobalamin’s diary

人間万事塞翁が馬

https://help.hatenablog.com/entry/developer-option

pandasでgroupbyを使う

pythonのpandasで表の集計をしている
groupbyが便利だったのでメモ

groupbyについて参考にした
Pandasのgroupbyを使った要素をグループ化して処理をする方法 - DeepAge

例えばirisのデータで種毎に平均値を計算してみる

pythonでもirisのデータが使えた
【python】iris(アヤメ)のデータセットをpandasとseabornを使って可視化する
ライブラリscikit-learnに含まれている

irisのカラムは5つ

[5 rows x 5 columns] Index(['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)',
       'petal width (cm)', 'target'],
      dtype='object')

targetが種の名前

   sepal length (cm)  sepal width (cm)  petal length (cm)  petal width (cm)  \
0                5.1               3.5                1.4               0.2   
1                4.9               3.0                1.4               0.2   
2                4.7               3.2                1.3               0.2   
3                4.6               3.1                1.5               0.2   
4                5.0               3.6                1.4               0.2   

   target  
0  setosa  
1  setosa  
2  setosa  
3  setosa  
4  setosa

groupbyでtargetを指定するとtargetで各行がまとめられて
mean()で平均値を計算してくれる

df.groupby(['target']).mean()

df.groupby(['target'])の出力は以下の通りで数値を確認できない

<pandas.core.groupby.generic.DataFrameGroupBy object at 0x07FE0310>

dict(list(df.groupby(['target'])))とすると表示できる


実際に使用したコードはこれ

import pandas as pd
from sklearn import datasets

pd.set_option('display.max_columns', 5)

iris = datasets.load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df['target'] = iris.target_names[iris.target]

print(df.head())
print(df.columns)

print(df.groupby(['target']).mean())


計算結果

            sepal length (cm)  sepal width (cm)  petal length (cm)  \
target                                                               
setosa                  5.006             3.428              1.462   
versicolor              5.936             2.770              4.260   
virginica               6.588             2.974              5.552   

            petal width (cm)  
target                        
setosa                 0.246  
versicolor             1.326  
virginica              2.026  
[Finished in 1.624s]

列が省略されないようにするにはset_optionで指定する
Pandas DataFrameの表示を省略したくない時. Jupyter… | by takkii | Music and Technology | Medium

Atomで出力している
結果が折り返されるのが修正できない。。。

Pythonista3でTableviewを使う


PythonではじめるiOSプログラミング

PythonではじめるiOSプログラミング

Pythonisata3でui.tableviewを使うときにハマったのでメモ

.pyuiファイルにTextFieldを配置したとき
TextFieldの中身はsuperviewで読み出せる
例えばTextFieldの名前をtextfield1とするとき
以下のように書く

def on_textfield(sender):
    a = sender.superview['textfield1']

これがTableViewの場合だとsuperviewの前にtableviewを挟まないといけない
例えばTableViewの名前がtableview1とするとき
このように書く

def on_tableview(sender):
    b = sender.tableview.superview['tableview'1]

これでTableViewの読み書きできる

こんな感じで任意のリストを
TableViewに加えることができる

list = ui.ListDataSource([{'title':'dog'}, {'title':'cat'}, {'title':'bird'}])
tableview.data_source.items = []
for i in list.items:
    tableview.data_source.items.append(i)
tableview.reload_data()

関数の引数であるsenderは
.pyui上のどのパーツをタップしたかで
内容が異なっている

for key in sender.__dict__.keys():
    print(key)

で内容を確認できて
_pyuiが含まれていると
superviewを使えるっぽい

以下が確認した内容で
TableViewではsender.tablevewに_pyuiが含まれる

---sender@TextField---
<class '_ui.TextField'>
_pyui
None
---sender@TableView---
<class 'ui.ListDataSource'>
tableview
reload_disabled
delete_enabled
move_enabled
action
edit_action
accessory_action
tapped_accessory_row
selected_row
_items
text_color
highlight_color
font
number_of_lines
None
---sender.tableview@TableView---
<class '_ui.TableView'>
_pyui
None

WSLとJupyter-notebookでCNN、その2、CNNを試す

前回の続き
mecobalamin.hatenablog.com

環境ができたので手持ちのデータセットを試してみる

こちらのサイトを参考にコードを作成した
kerasでCNN 自分で拾った画像でやってみる - Qiita

主な変更点は以下の3点

  • 画像の読み込み
  • mnist_cnn.pyのモデルを使用
  • label、predict、画像ファイル名を保存する

こちらの環境ではlist_picturesが動かなかったので
ファイルを読み込む関数Image_Listを定義した
globは引数で指定したパスのファイル名を再帰的に取得する
ファイル名だけ取得したいのでrelpathで処理している

モデルはmnist_cnn.pyのと同じモデルを使ってみた

画像の分類は手動で行って
negativeとpositiveのディレクトリに保存してある
それぞれの画像がどのように分類されているかを知りたかったので
画像のファイル名とそれぞれがどのようにpredictされているかを
csvファイルに保存した

fit()で出力されるlistのindexも
バージョン違いのせいか"accu"ではエラーが出るので
"accuracy"に修正してある

実際のコードは以下の通り

# ライブラリのインポート
import keras
from keras.utils import np_utils
from keras.layers.convolutional import Conv2D, MaxPooling2D
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation, Flatten
from keras.preprocessing.image import array_to_img, img_to_array, load_img
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt

import pandas as pd
import numpy as np
from glob import glob
from os.path import relpath

# ファイル名の取得
def Image_List(Path_Images, Ext):
    List_Images = glob(Path_Images + "/*." + Ext)
    List_Names = []
    for i in List_Images:
        List_Names.append(relpath(i, Path_Images))
    return List_Names

# 画像の拡張子
Ext_Type = "png"

# 画像のパス
Path_Negative = '/path/to/negative/'
Path_Positive = '/path/to/positive/'

X = []
Y = []

# ネガティブ画像の読み込み
Image_Negative = Image_List(Path_Negative, Ext_Type)
for picture in Image_Negative:
    img = img_to_array(load_img(Path_Negative + picture, color_mode = "grayscale", target_size=(256, 256)))
    X.append(img)

    Y.append(0)


# ポジティブ画像の読み込み
Image_Positive = Image_List(Path_Positive, Ext_Type)
for picture in Image_Positive:
    img = img_to_array(load_img(Path_Positive + picture, color_mode = "grayscale", target_size=(256, 256)))
    X.append(img)

    Y.append(1)


# arrayに変換
# Zはファイル名のリスト
X = np.asarray(X)
Y = np.asarray(Y)
Z = pd.DataFrame(Image_Negative + Image_Positive)

# 画素値を規格化
X = X.astype('float32')
X = X / 255.0

# one-hot表現に変換
Y = np_utils.to_categorical(Y, 2)

# 学習用データとテストデータに分割
# ファイル名のリストも分割
X_train, X_test, y_train, y_test, indices_train, indices_test = train_test_split(X, Y, Z, test_size=0.33, random_state=111)

# モデルの構築
model = Sequential()

model.add(Conv2D(20, kernel_size=(3, 3),
                 activation='relu',
                 input_shape=X_train.shape[1:]))
model.add(Conv2D(40, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

model.add(Flatten())
model.add(Dense(512))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(2))       # クラスは2個
model.add(Activation('softmax'))

# コンパイル
model.compile(loss='categorical_crossentropy',
              optimizer='SGD',
              metrics=['accuracy'])

# 実行
# 出力有り(verbose=1)。
history = model.fit(X_train, y_train, batch_size=300, epochs=4[f:id:mecobalamin:20200608101008p:plain]0,
                   validation_data = (X_test, y_test), verbose = 1)

plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.title('model accuracy')
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.legend(['acc', 'val_acc'], loc='lower right')
plt.show()

# テストデータに適用
predict_classes = model.predict_classes(X_test)

# マージ。yのデータは元に戻す
mg_df = pd.DataFrame({'predict': predict_classes, 'class': np.argmax(y_test, axis=1)})

# confusion matrix
pd.crosstab(mg_df['class'], mg_df['predict'])

# 結果の保存
# テストに使った画像ファイルのリストも保存
df_h = pd.concat([pd.DataFrame(y_test), indices_test], axis = 1)
pd.DataFrame(y_test).to_csv("/path/to/y_test.csv")
indices_test.to_csv("/path/to/indices_test.csv")
pd.DataFrame(predict_classes).to_csv("/path/to/predict_test.csv")

jupyter-notebookの複数のcellをまとめたが
gistを使うとそのまま貼り付けられるらしい



計算結果は以下の通り
Core i5-7200UのノートPCで
大体6時間ぐらいかかった

Train on 3287 samples, validate on 1619 samples
Epoch 1/40
3287/3287 [==============================] - 522s 159ms/step - loss: 0.6425 - accuracy: 0.5117 - val_loss: 0.5973 - val_accuracy: 0.5374
Epoch 2/40
3287/3287 [==============================] - 494s 150ms/step - loss: 0.5793 - accuracy: 0.6693 - val_loss: 0.5340 - val_accuracy: 0.7739
Epoch 3/40
3287/3287 [==============================] - 493s 150ms/step - loss: 0.5429 - accuracy: 0.7478 - val_loss: 0.5146 - val_accuracy: 0.7573

~~~ 省略 ~~~

Epoch 38/40
3287/3287 [==============================] - 501s 152ms/step - loss: 0.4346 - accuracy: 0.8059 - val_loss: 0.4734 - val_accuracy: 0.7900
Epoch 39/40
3287/3287 [==============================] - 493s 150ms/step - loss: 0.4001 - accuracy: 0.8190 - val_loss: 0.5238 - val_accuracy: 0.7622
Epoch 40/40
3287/3287 [==============================] - 497s 151ms/step - loss: 0.4388 - accuracy: 0.8026 - val_loss: 0.4895 - val_accuracy: 0.7857

Epochが増えると学習データに対するAccuracyは増えているが
テストデータに対するAccuracyはあまり増えていない
Jupyter Notebookをはてなブログに貼り付ける方法 - akatak’s blog

画像の分類は以下の通り
classは学習時に使った画像のラベルで
0はnegative、1はpositiveを表す
predictはcnnで分類された画像で
0/1はやはりnegative/positiveを表す

predict
0 1
class 0 652 104
1 243 620

10%-30%程度間違っている

グラフにしてないけれど損失関数も
mnistのデータを使ったときほど減っていない

使ったモデルが合っていないのか
教師データの分類が不十分なのか
そもそもデータの数が足りないのか

分類できた画像を確認したら
見た目にも分類が不十分に感じる
この画像がネガティブに分類?みたいな

計算はできたけど
ここからの修正はどうしたらいいだろうか

WSLとJupyter-notebookでCNN、その1、環境構築

画像の分類をしたくてDeep Learningについて勉強している
ネットで調べながらこの本を何度も読み直している
ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装
(Amazonのサイトに飛びます)

CourseraのMachine Learningの講義もおすすめ
mecobalamin.hatenablog.com

試してみたいデータもあるのでどこか
似たようなことをやっている人がないか探してみたら
Kerasの開発者がCNNを使ってMNISTの画像認識を行っていた
https://github.com/keras-team/keras/tree/master/examples
いくつもファイルがあるがこの中からmnist_cnn.pyを利用した

mnist_cnn.pyについてはググるといくつも情報が出てくる
https://pondad.net/deep-learning/2016/12/25/keras-mnist.html
【AI初心者向け】mnist_cnn.pyを1行ずつ解説していく(KerasでMNISTを学習させる) - Qiita

手持ちの画像データを使いたいので
画像を読み込ませるために以下のサイトを参考にした
kerasでCNN 自分で拾った画像でやってみる - Qiita
Google Colaboratory で Keras 自作データセットを読み込み - Qiita
sklearn の train_test_split でデータの順番の情報を保持しておく - Qiita

実際に行ったのは

  1. mnist_cnn.pyを動かす環境の構築と実行
  2. 手持ち画像を読み込ませるコードの実行

今回はmnist_cnn.pyを動かす環境の構築
実行環境はWSLに作った
WSLを利用したのはPower Shellには
tensorflowをインストールできなかったためだ

まずはkeras/tensorflowをインストールする仮想環境を用意する
以下の過去記事を参考にした
mecobalamin.hatenablog.com

condaのコマンドを使ってtfという仮想環境を作る

conda create -n tf python=3.7 anaconda

環境の切り替えは

conda activate tf

conda deactivate

で行う

この環境にkerasとtensorflowをWSLにインストールした

keras/tensorflowの関係がいまいちよくわかっていないけど
tensorflowはバックエンドで実際の作業をするライブラリで
kerasはtensorflowを効率よく使うためのライブラリという認識

インストールは以下の通り

pip install --upgrade tensorflow
conda install keras

しようがないとはいえpipとcondaを混ぜて使ってしまったのが若干気になる
condaとpip:混ぜるな危険 - onoz000’s blog
仮想環境下にインストールしているので
やり直しをしやすいと思う

pythonコードの実行環境としてJupyterもインストール

pip install Jupyter

jupyter-notebookを使えるようになる
jupyter-notebookはデータサイエンス・機械学習の分野で
よく使われているらしい
セル毎にコードを実行できるので
修正箇所だけ実行とかできて便利

インストール後にjupyter-notebookを起動すると

jupyter-notebook

以下の表示が出るのでURLを
windowsのbrowserにコピペすると
jupyter-notebookを利用できる

To access the notebook, open this file in a browser:
    file:///home/hogehoge/.local/share/jupyter/runtime/nbserver-hogehoge-fugafuga.html
Or copy and paste one of these URLs:
    http://localhost:8888/?token=hogehogefugafuga
or
    http://127.0.0.1:8888/?token=hogehogefugafuga

実際にはtokenにアルファベットと数字の文字列が入っている

jupyter-notebookで新規にnotebookを作って
mnist_cnn.pyの中身をコピペするとこんな感じ

実行結果は以下の通り

Downloading data from https://s3.amazonaws.com/img-datasets/mnist.npz
11493376/11490434 [==============================] - 5s 0us/step
x_train shape: (60000, 28, 28, 1)
60000 train samples
10000 test samples
Train on 60000 samples, validate on 10000 samples
Epoch 1/12
60000/60000 [==============================] - 138s 2ms/step - loss: 0.2544 - accuracy: 0.9218 - val_loss: 0.0638 - val_accuracy: 0.9800
Epoch 2/12
60000/60000 [==============================] - 133s 2ms/step - loss: 0.0873 - accuracy: 0.9743 - val_loss: 0.0448 - val_accuracy: 0.9861
Epoch 3/12
60000/60000 [==============================] - 134s 2ms/step - loss: 0.0651 - accuracy: 0.9802 - val_loss: 0.0327 - val_accuracy: 0.9894
Epoch 4/12
60000/60000 [==============================] - 139s 2ms/step - loss: 0.0539 - accuracy: 0.9836 - val_loss: 0.0291 - val_accuracy: 0.9901
Epoch 5/12
60000/60000 [==============================] - 130s 2ms/step - loss: 0.0445 - accuracy: 0.9866 - val_loss: 0.0301 - val_accuracy: 0.9900
Epoch 6/12
60000/60000 [==============================] - 131s 2ms/step - loss: 0.0407 - accuracy: 0.9874 - val_loss: 0.0292 - val_accuracy: 0.9900
Epoch 7/12
60000/60000 [==============================] - 123s 2ms/step - loss: 0.0368 - accuracy: 0.9891 - val_loss: 0.0254 - val_accuracy: 0.9907
Epoch 8/12
60000/60000 [==============================] - 74s 1ms/step - loss: 0.0326 - accuracy: 0.9899 - val_loss: 0.0300 - val_accuracy: 0.9908
Epoch 9/12
60000/60000 [==============================] - 77s 1ms/step - loss: 0.0310 - accuracy: 0.9905 - val_loss: 0.0243 - val_accuracy: 0.9921
Epoch 10/12
60000/60000 [==============================] - 76s 1ms/step - loss: 0.0272 - accuracy: 0.9919 - val_loss: 0.0268 - val_accuracy: 0.9921
Epoch 11/12
60000/60000 [==============================] - 76s 1ms/step - loss: 0.0264 - accuracy: 0.9916 - val_loss: 0.0268 - val_accuracy: 0.9917
Epoch 12/12
60000/60000 [==============================] - 77s 1ms/step - loss: 0.0261 - accuracy: 0.9920 - val_loss: 0.0247 - val_accuracy: 0.9922
Test loss: 0.024740188298751492
Test accuracy: 0.9922000169754028

mnist_cnn.pyには

Gets to 99.25% test accuracy after 12 epochs
(there is still a lot of margin for parameter tuning).
16 seconds per epoch on a GRID K520 GPU.

とある

test accuracyは0.9920で大体あっているようだ

また今回使用した
Intel Core i5 7200U、GPUなしのnotebook PCでは
74-139s/Epochなので1/5 - 1/9 程度の計算速度か

値段の差を考えるとまあ順当
NVIDIA GRID k520 8 GB gddr5 PCIe gen3 x16クラウドゲームケプラーGPUグラフィックス900 – 12055 – 0020 – 000

とりあえず環境ができたので
次は手持ちのデータで試してみる

Pythonで数値のみの入力

以前、選択肢を数字で選ばせる
pythonスクリプトの記事を書いた
mecobalamin.hatenablog.com

該当する部分は以下のコード

print('計算の種類を選んで数字を入力してね')
print('1: 少数のたし算・ひき算')
print('2: 大きな数のかけ算')
print('3: あまりのあるわり算')
print('4: 分数のたし算・ひき算')
while True:
	eq_type = input('数値を入力 (1 - 4): ')
	if eq_type > '0' and eq_type < '5':
		break

動いていたから気にしていなかったが
入力は文字なのに大小の比較ができている

なぜだ?

文字列にも等号記号が使えることは知っていたが
調べてみると比較演算子も使えた
Pythonで文字列を比較(完全一致、部分一致、大小関係など) | note.nkmk.me
比較演算子の使い方 | Python入門

unicodeのコードポイントを比較しているそうだ

pythonではord()でコードポイントを取得できる

>>> ord('0')
48
>>> ord('1')
49
>>> ord('2')
50
>>> ord('9')
57

数字の0から9には
48から57が割り当てられている

なので過去記事で使ったコードでも
問題なく動いたようだ

本来ならint()で数値にして
大小比較するのが筋かも
ただし数値以外の文字・記号を
int()の引数にした場合はエラーになるので
try/except文を使って
エラーを弾きつつ
数値の入力を受け付けるように書き直した

try/excptの使い方は以下のサイトを参考にさせてもらった
Pythonの例外処理(try, except, else, finally) | note.nkmk.me

書き直したコードはこんな感じ
確認のためprint()を追加している

while True:
    eq_type = input('数値を入力 (1 - 4): ')
    try:
        int(eq_type)
    except ValueError as e:
        print('1から4までの数字を入力してね')
    else:
        if int(eq_type) >= 1 and int(eq_type) <= 4:
            break
        else:
            print('1から4までの数字を入力してね')

print(eq_type)

もっと簡潔にかけそうな気がする

あと全角・半角の区別はしていない
出力は半角になる
そのうち区別できるようにしたい

Pythonista3でpythonプログラミング

pythonプログラミングに利用している
iOSアプリのPythonista3
mecobalamin.hatenablog.com
mecobalamin.hatenablog.com

割と色々できて便利

まずはpythonistaについて

iOS上で動作する革命的ものづくり環境「Pythonista 3」の魅力をとくと語る
iOS上で動作する革命的ものづくり環境「Pythonista 3」の魅力をとくと語る
iPad ProでPythonプログラム
iPad ProでPythonプログラム - Qiita

Deep Learningの勉強にも使っていたり
「ゼロから作るDeep Learning」をiPhoneのPythonistaだけで学ぶ(2)
「ゼロから作るDeep Learning」をiPhoneのPythonistaだけで学ぶ(2) - blog.tmp.tokyo
iPadで「ゼロから作るDeep Learning」を勉強するために必要なこと
poipoides.hatenablog.com

自分でも試してみたけどコードに変更が必要で
上記のリンク先の方が変更したコードを載せてくれている
3章か4章ぐらいまではpythonistaで動くことを確認した
その先は結局PCのpythonで。


今までやったのは
コンソールに結果を表示する
プログラミング

希望する機能を実装できていたけど
せっかくiPadを使っているのだから
タッチ操作できるプログラミングをしてみたい

pythonistaにはいくつもサンプルコードが入っていて
そのいくつかはタッチ操作のゲームだったりする
実際ゲームを作っている人達もいる
Pythonistaで作るポーカー作成講座(全5回)
Pythonistaで作るポーカー作成講座(全5回) | みやびのどっとぴーわい
Pythonista+sceneでトランプをランダムに表示する
Pythonista+sceneでトランプをランダムに表示する - Qiita

公式でXcodeに変換するコードを公開しているので
その気になればiOSアプリも作れそう

python2に対応
github.com



で、試しに作ってみた
作ったのは例えば何かカードゲームをして
得点を記録するプログラム

一度コンソールに表示するバージョンは書いていて
こんな感じ
f:id:mecobalamin:20200514110316j:plain
それをこのように表示したい
f:id:mecobalamin:20200514110333j:plain
プレイヤーは3人で
ポイントを入力してsubmitを押すと
totalに加算される
そしてroundが一つ進む

コードはpythonプログラムのui.pyと
ボタン等を配置したui.pyuiの2つで一セット
実際のコードはこの記事の最後に載せるとして
ui.pyの説明を書く

import ui
import console

pythonistaにはsceneというライブラリもあるが
今回使用したのはui
consoleもpythonistaのライブラリで
コンソールを操作するのに使う

	v = ui.load_view()
	
	v['num1'].keyboard_type = ui.KEYBOARD_NUMBER_PAD
	v['num2'].keyboard_type = ui.KEYBOARD_NUMBER_PAD
	v['num3'].keyboard_type = ui.KEYBOARD_NUMBER_PAD
	v.present('fullscreen')

ui.load_view()でui.pyuiをロードしている
v['num1'].keyboard_typeは
num1に入力するときのキーボードの種類を設定する
num1は得点の入力なので数値のみ
なので最初から数字入力になっている
キーボードが表示されるようにしている

present('fullsucreen')で
フルスクリーン表示でコードを実行する

よくわかっていないんだけど
このときプログラムは×印をタップして停止させるまで
入力待ちになっているっぽい

関数を実行するにはui.pyに書かれた関数を
ui.pyuiのボタンに紐付けしておく
ボタンをタップすると
紐付けされた関数on_buttonが実行される

def on_button(sender):

引数のsenderには画面上の情報が入っているようで
superview[]とボタンやtextfieldの名前を使って値を取り出す

text_label1 = sender.superview['label1']
Num_1 = sender.superview['num1']

label1やnum1はtextfieldの名前であり
ui.pyuiで編集できる

print文はconsol画面に表示されるため
プログラムを停止するまで表示を見られない

書いただけなので読みやすく修正したいけど
とりあえずここまででやりたいことは実装できた
ui.pyuiも見やすいデザインにしたい

まだ読んでいないけどpytonista3を使った
プログラミング教本らしいのでメモ
PythonではじめるiOSプログラミング 〜iOS+Pythonで数値処理からGUI、ゲーム、iOS機能拡張まで〜

実際のコードは以下の通り

ui.py

import ui
import console

def on_button(sender):

	text_label1 = sender.superview['label1']
	Num_1 = sender.superview['num1']
	Re_1 = sum_score(text_label1.text, Num_1.text)
	text_label1.text = str(Re_1)
	Num_1.text = ''
	
	text_label2 = sender.superview['label2']
	Num_2 = sender.superview['num2']
	Re_2 = sum_score(text_label2.text, Num_2.text)
	text_label2.text = str(Re_2)
	Num_2.text = ''
	
	text_label3 = sender.superview['label3']
	Num_3 = sender.superview['num3']
	Re_3 = sum_score(text_label3.text, Num_3.text)
	text_label3.text = str(Re_3)
	Num_3.text = ''
	
	num_round = sender.superview['num_round']
	num_round.text = str(int(num_round.text) + 1)
	#print(Num_3.text_color)
	
	print('round' + str(int(num_round.text) - 1), Re_1, Re_2, Re_3)
	
def sum_score(m, n):
	r = 0
	if m == '':
		r = int(n)
	elif n == '':
		r = int(m)
	else:
		r = int(m) + int(n)
	
	return r

if __name__ == '__main__':

	console.clear()
	console.set_font('Menlo',20)

	v = ui.load_view()
	
	v['num1'].keyboard_type = ui.KEYBOARD_NUMBER_PAD
	v['num2'].keyboard_type = ui.KEYBOARD_NUMBER_PAD
	v['num3'].keyboard_type = ui.KEYBOARD_NUMBER_PAD
	v.present('fullscreen')

ボタンや数字の入力場所の配置はこんな感じ
f:id:mecobalamin:20200514110503j:plain
赤でマークしたactionにon_button関数を登録した
submitのボタンを押すと
on_button関数が実行される

ui.pyuiはテキストファイルなのでエディタで中身が読める
よくわからないけどファイルの形式はJSON?っぽく見える

ui.pyui

[
  {
    "nodes" : [
      {
        "nodes" : [

        ],
        "frame" : "{{119, 54}, {77, 43}}",
        "class" : "TextField",
        "attributes" : {
          "uuid" : "EB343BBB-5CFB-4AE7-8BCC-41EE1ACDE42E",
          "font_size" : 17,
          "frame" : "{{60, 224}, {200, 32}}",
          "custom_attributes" : "",
          "action" : "",
          "alignment" : "right",
          "autocorrection_type" : "default",
          "text" : "",
          "font_name" : "<System>",
          "spellchecking_type" : "default",
          "class" : "TextField",
          "name" : "num1",
          "flex" : "WHLRTB"
        },
        "selected" : false
      },
      {
        "nodes" : [

        ],
        "frame" : "{{16, 54}, {95, 43}}",
        "class" : "TextField",
        "attributes" : {
          "uuid" : "EB343BBB-5CFB-4AE7-8BCC-41EE1ACDE42E",
          "font_size" : 17,
          "frame" : "{{60, 224}, {200, 32}}",
          "action" : "",
          "alignment" : "left",
          "autocorrection_type" : "default",
          "text" : "",
          "font_name" : "<System>",
          "spellchecking_type" : "default",
          "class" : "TextField",
          "name" : "usr1",
          "flex" : "WHLRTB"
        },
        "selected" : false
      },
      {
        "nodes" : [

        ],
        "frame" : "{{16, 105}, {95, 43}}",
        "class" : "TextField",
        "attributes" : {
          "flex" : "WHLRTB",
          "uuid" : "EB343BBB-5CFB-4AE7-8BCC-41EE1ACDE42E",
          "frame" : "{{60, 224}, {200, 32}}",
          "action" : "",
          "alignment" : "left",
          "autocorrection_type" : "default",
          "text" : "",
          "font_name" : "<System>",
          "spellchecking_type" : "default",
          "class" : "TextField",
          "name" : "usr2",
          "font_size" : 17
        },
        "selected" : false
      },
      {
        "nodes" : [

        ],
        "frame" : "{{16, 156}, {95, 43}}",
        "class" : "TextField",
        "attributes" : {
          "flex" : "WHLRTB",
          "uuid" : "EB343BBB-5CFB-4AE7-8BCC-41EE1ACDE42E",
          "frame" : "{{60, 224}, {200, 32}}",
          "action" : "",
          "alignment" : "left",
          "autocorrection_type" : "default",
          "text" : "",
          "font_name" : "<System>",
          "spellchecking_type" : "default",
          "class" : "TextField",
          "name" : "usr3",
          "font_size" : 17
        },
        "selected" : false
      },
      {
        "nodes" : [

        ],
        "frame" : "{{119, 105}, {77, 43}}",
        "class" : "TextField",
        "attributes" : {
          "uuid" : "EB343BBB-5CFB-4AE7-8BCC-41EE1ACDE42E",
          "font_size" : 17,
          "frame" : "{{60, 224}, {200, 32}}",
          "action" : "",
          "alignment" : "right",
          "autocorrection_type" : "default",
          "text" : "",
          "font_name" : "<System>",
          "spellchecking_type" : "default",
          "class" : "TextField",
          "name" : "num2",
          "flex" : "WHLRTB"
        },
        "selected" : false
      },
      {
        "nodes" : [

        ],
        "frame" : "{{119, 156}, {77, 43}}",
        "class" : "TextField",
        "attributes" : {
          "uuid" : "EB343BBB-5CFB-4AE7-8BCC-41EE1ACDE42E",
          "font_size" : 17,
          "frame" : "{{60, 224}, {200, 32}}",
          "action" : "",
          "alignment" : "right",
          "autocorrection_type" : "default",
          "text" : "",
          "font_name" : "<System>",
          "spellchecking_type" : "default",
          "class" : "TextField",
          "name" : "num3",
          "flex" : "WHLRTB"
        },
        "selected" : false
      },
      {
        "nodes" : [

        ],
        "frame" : "{{204, 54}, {97, 43}}",
        "class" : "Label",
        "attributes" : {
          "uuid" : "F3870D2E-9FCF-4C83-B5AF-C393166D3D4E",
          "flex" : "WHLRTB",
          "corner_radius" : 0,
          "frame" : "{{85, 224}, {150, 32}}",
          "number_of_lines" : 0,
          "border_width" : 1,
          "border_color" : "RGBA(0.000000,0.000000,0.000000,1.000000)",
          "alignment" : "center",
          "text" : "0",
          "font_name" : "<System>",
          "class" : "Label",
          "name" : "label1",
          "font_size" : 18
        },
        "selected" : false
      },
      {
        "nodes" : [

        ],
        "frame" : "{{204, 105}, {97, 43}}",
        "class" : "Label",
        "attributes" : {
          "uuid" : "F3870D2E-9FCF-4C83-B5AF-C393166D3D4E",
          "flex" : "WHLRTB",
          "corner_radius" : 0,
          "frame" : "{{85, 224}, {150, 32}}",
          "number_of_lines" : 0,
          "border_width" : 1,
          "border_color" : "RGBA(0.000000,0.000000,0.000000,1.000000)",
          "alignment" : "center",
          "text" : "0",
          "font_name" : "<System>",
          "class" : "Label",
          "name" : "label2",
          "font_size" : 18
        },
        "selected" : false
      },
      {
        "nodes" : [

        ],
        "frame" : "{{204, 156}, {97, 43}}",
        "class" : "Label",
        "attributes" : {
          "flex" : "WHLRTB",
          "uuid" : "F3870D2E-9FCF-4C83-B5AF-C393166D3D4E",
          "corner_radius" : 0,
          "frame" : "{{85, 224}, {150, 32}}",
          "border_color" : "RGBA(0.000000,0.000000,0.000000,1.000000)",
          "border_width" : 1,
          "alignment" : "center",
          "text" : "0",
          "font_name" : "<System>",
          "class" : "Label",
          "name" : "label3",
          "font_size" : 18
        },
        "selected" : false
      },
      {
        "nodes" : [

        ],
        "frame" : "{{95, 207}, {142, 41}}",
        "class" : "Button",
        "attributes" : {
          "action" : "on_button",
          "flex" : "WHLRTB",
          "border_width" : 1,
          "frame" : "{{120, 224}, {80, 32}}",
          "title" : "submit",
          "uuid" : "BD6B3517-3570-46B3-B6E4-E967C932197B",
          "class" : "Button",
          "corner_radius" : 0,
          "name" : "button1",
          "font_size" : 15
        },
        "selected" : false
      },
      {
        "nodes" : [

        ],
        "frame" : "{{174, 6}, {73, 19}}",
        "class" : "Label",
        "attributes" : {
          "font_size" : 18,
          "flex" : "WHLRTB",
          "frame" : "{{85, 224}, {150, 32}}",
          "uuid" : "AC87D8D9-39BC-4DA0-90E3-861257E72023",
          "class" : "Label",
          "alignment" : "left",
          "text" : "1",
          "custom_attributes" : "",
          "name" : "num_round",
          "font_name" : "<System>"
        },
        "selected" : false
      },
      {
        "nodes" : [

        ],
        "frame" : "{{16, 6}, {150, 19}}",
        "class" : "Label",
        "attributes" : {
          "name" : "Round_title",
          "flex" : "WHLRTB",
          "frame" : "{{85, 224}, {150, 32}}",
          "uuid" : "7CBBD8E2-1DAE-471D-B7D6-2EAA890A3C7F",
          "class" : "Label",
          "alignment" : "right",
          "text" : "Round",
          "font_size" : 18,
          "font_name" : "<System>"
        },
        "selected" : false
      },
      {
        "nodes" : [

        ],
        "frame" : "{{16, 33}, {95, 20}}",
        "class" : "Label",
        "attributes" : {
          "flex" : "WHLRTB",
          "font_name" : "<System>",
          "frame" : "{{85, 224}, {150, 32}}",
          "uuid" : "7CBBD8E2-1DAE-471D-B7D6-2EAA890A3C7F",
          "class" : "Label",
          "alignment" : "center",
          "text" : "User name",
          "name" : "",
          "font_size" : 18
        },
        "selected" : false
      },
      {
        "nodes" : [

        ],
        "frame" : "{{119, 33}, {77, 20}}",
        "class" : "Label",
        "attributes" : {
          "flex" : "WHLRTB",
          "font_size" : 18,
          "frame" : "{{85, 224}, {150, 32}}",
          "uuid" : "7CBBD8E2-1DAE-471D-B7D6-2EAA890A3C7F",
          "class" : "Label",
          "alignment" : "center",
          "text" : "point",
          "name" : "",
          "font_name" : "<System>"
        },
        "selected" : false
      },
      {
        "nodes" : [

        ],
        "frame" : "{{204, 33}, {97, 20}}",
        "class" : "Label",
        "attributes" : {
          "flex" : "WHLRTB",
          "font_name" : "<System>",
          "frame" : "{{85, 224}, {150, 32}}",
          "uuid" : "7CBBD8E2-1DAE-471D-B7D6-2EAA890A3C7F",
          "class" : "Label",
          "alignment" : "center",
          "text" : "total",
          "font_size" : 18,
          "name" : ""
        },
        "selected" : false
      }
    ],
    "frame" : "{{0, 0}, {320, 480}}",
    "class" : "View",
    "attributes" : {
      "tint_color" : "RGBA(0.000000,0.478000,1.000000,1.000000)",
      "enabled" : true,
      "border_color" : "RGBA(0.000000,0.000000,0.000000,1.000000)",
      "background_color" : "RGBA(1.000000,1.000000,1.000000,1.000000)",
      "name" : "",
      "flex" : ""
    },
    "selected" : false
  }
]

RNA-seqその10、Dockerで環境構築

RNA-Seqのパイプラインに限らず
他人のスクリプトが自分の環境では
うまく動かないことはよくある話

かと言ってクリーンな環境を
毎回用意もできない

そこでDockerをつかって
クリーンなubuntu
RNA-Seqのパイプラインを実行できる
環境を作ってみた


作ったのはTrinityを動かす環境

以下の過去記事を参考に構築した
mecobalamin.hatenablog.com
mecobalamin.hatenablog.com
mecobalamin.hatenablog.com

1番目の記事を参考にDockerを動かすことができたら
今回は2番目の記事を参考に120GBのストレージをもつ
Virtual Machineを作成する
3番目の記事を参考にしてWindows-Docker間で
ファイルのやり取りができるようにする

Trinityは出力ディレクトリに
ファイルのシンボリックリンクを作成するが
現状Windows10 homeでは仮想マシンから
ホストにシンボリックリンクを貼れない

そのため出力先はDocker内にし
生成されたファイルは終了後に
Widows側に移動して次の作業に使用する
ホストからゲストにはシンボリックリンクを貼れるので
入力するbamファイルはホストにある


環境構築にDockerfileを利用した
Dockerfileとは以下のようなもの

Docker は Dockerfile の命令を読み込み、自動的にイメージを構築できます。

docs.docker.jp

平たく言えばダウンロードしたubuntuのイメージファイルに
必要なコマンドをインストールする操作を
記述したファイル

このファイルをdockerを使ってビルドすると
必要なコマンドの入ったubuntu imageを作成できる

実際に作ったDockerfileは以下の通り

# install ubuntu
FROM ubuntu

# set shell type
SHELL ["/bin/bash", "-c"]

# update apt-get and install commands
RUN apt-get update && \
    apt-get install -y openjdk-8-jre && \
    apt-get install -y less && \
    apt-get install -y wget && \
    apt-get install -y unzip && \
    apt-get install -y vim

ENV RNASEQ_PATH=/RNA-Seq
ENV TMP_PATH=${RNASEQ_PATH}/tmp
ENV CONDA_PATH=${RNASEQ_PATH}/miniconda3

WORKDIR ${TMP_PATH}

# install miniconda3
RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
RUN chmod 755 ${TMP_PATH}/Miniconda3-latest-Linux-x86_64.sh && \
    ${TMP_PATH}/Miniconda3-latest-Linux-x86_64.sh -b -p ${CONDA_PATH}

ENV PATH=${CONDA_PATH}/bin:${PATH}

RUN conda update conda && \
    conda install -c bioconda trimmomatic=0.39 && \ 
    conda install -c bioconda trinity=2.6.6 && \ 
    conda install -c bioconda ea-utils=1.1.2.779 && \
    conda install -c bioconda numpy=1.15.0 && \
    conda install -c bioconda hisat2=2.1.0 && \
    conda install -c bioconda stringtie=2.1.1

# make directory for shared directory and scripts
RUN mkdir -p ${RNASEQ_PATH}/data && \
    mkdir -p ${RNASEQ_PATH}/scripts

# Perl setting
RUN ln -sf ${CONDA_PATH}/lib/libcrypto.so.1.1 ${CONDA_PATH}/lib/libcrypto.so.1.0.0
RUN mv -f /usr/bin/perl /usr/bin/perl.5.30.0 && \
    ln -sf ${CONDA_PATH}/bin/perl /usr/bin/
ENV PERL5LIB=${PERL5LIB}:${CONDA_PATH}/lib/5.26.2

# change working directory
WORKDIR ${RNASEQ_PATH}

この内容をDockerfileという名前のファイルに保存する
DockerfileのあるディレクトリにはDockerfileのみを保存する

Dockerfileのあるディレクトリで以下のコマンドでビルドする

$ docker build -t hogehoge:hugahuga .

Dockerfileにエラーがなければ
Repositoryがhogehoge
tagがhugahugaの
imageが作成される

作成したimageは以下のコマンドで実行する

docker run --rm -v /e/hoge:/tmp/fuga -it hogehoge:hugahuga /bin/bash

ディレクトリのhogeとfugaは
windowsディレクトhoge
dockerのディレクトリfugaをマウントしつつ
imageのhogehoge:hugahugaを起動している

例えばwindowsのeドライブにあるtmpディレクトリを
今回作ったイメージ内の/RNA-Seq/dataにマウントするなら
この様になる

docker run --rm -v /e/tmp:/RNA-Seq/data -it hogehoge:hugahuga /bin/bash

imageの作り方などは以下の本を参考にした
(Amazonのページに飛びます)
自宅ではじめるDocker入門―人気のコンテナ型「仮想化ソフト」を使ってみる! (I・O BOOKS)


これよりDockerfileの説明
ベースになるのはubuntuのイメージ
Dockerのデフォルトではshを使うのでbashに変更している

スクリプトファイルやマウント先のディレクトリを作る

/RNA-Seq

というディレクトリを作成し、
それ以下にdata、tmp、scriptsというディレクトリを作成する
dataはwindowsとファイルのやり取りをするディレクト
scriptsはTrinityのスクリプトファイルを保存するディレクト
tmpはTrinityの一時ファイルを保存する作業ディレクト

過去記事をもとにTrinityで使うコマンドを追加する
mecobalamin.hatenablog.com

Javaのバージョンが古いのでアップデートする
lessやwgetも含まれていないことに驚いた
ほんと最小限
もっとサイズの小さなディストリビューションだとどうなるんだろう

pythonも使うのでminicondaをインストール
condaでいくつかパッケージをインストールするが
バージョン指定でインストールしている

Trinityは使えるオプションの関係で2.6.6をインストールしている
指定しないともっと古いバージョンがインストールされる
2.6.6よりも新しいバージョンも存在するが使ったことがない

コンテナ内で使うファイルパスはENVで指定する
${HOME}/.bashrcに記入するのと同じなのかもしれないが
Dockerfileから.bashrcに記入して
sourceコマンドで.bashrcの再読み込みでは
上手くパスを設定できなかった

perlもコマンドとライブラリのシンボリックリンクを貼り直している

最後にWORKDIRを変更している
これでWORKDIRが${HOME}になる

ここまでがDockerfileに記述した処理

以前Trinityの処理に使用したシェルスクリプトにも変更を加えて
/RNA-Seq/scritps/
に保存した
シェルスクリプトは以下の通り

#!/bin/bash

echo "Trinity has began"

date_begin=`date`

dir_scripts="/RNA-Seq/scripts"
dir_working="/RNA-Seq/data"
dir_tmp="/RNA-Seq/tmp"

echo "open sra list"

dir_list_sra=${dir_scripts}
name_sra="list_sra.txt"
list_filename=$(cat ${dir_list_sra}/${name_sra} | sed 's/\.sra//')

for i in ${list_filename}
  do
    echo "analyze ${i}"
    file_in="sort_${i}.bam"
    dir_in="hisat_${i}"
    dir_out="trinity_${i}"

    echo "makind directories"
    mkdir -p ${dir_tmp}/${dir_out}
    mkdir -p ${dir_tmp}/${dir_out}

    Trinity \
      --genome_guided_bam ${dir_working}/${dir_in}/${file_in} \
      --genome_guided_max_intron 10000 \
      --verbose \
      --output ${dir_tmp}/${dir_out} \
      --workdir ${dir_tmp}/${dir_out} \
      --CPU 1 \
      --max_memory 10G

    mv ${dir_tmp}/${dir_out}/Trinity-GG.fasta ${dir_tmp}/${dir_out}/Trinity-GG_${i}.fasta

    TrinityStats.pl ${dir_tmp}/${dir_out}/Trinity-GG_${i}.fasta > \
      ${dir_tmp}/${dir_out}/Trinity-GG_${i}.stats

  done

 echo ${date_begin}
 echo `date`

bamファイルはwindows側に保存されていて
結果はDocker側に出力される

スクリプトファイルを加えたimageを保存するなら
docker commitコマンドを使う

$ docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

今回作成したimageのIDはdf2113fdef5eなので

$ docker commit df2113fdef5e hogehoge:hugahuga

とすると
Repositoryがhogehoge
Tagがhugahuga
のimageを作成できる

また

$ docker save hogehoge:hugahuga > hogehoge_hugahuga.tar

を実行するとtar形式で保存されて持ち出せるようになる
つまり他のPCやvirtual machineで使用できるようになる
image idでも保存はできるがそれだと
tarファイルを読み込んだときに
repositoryとtagの情報を失っているので
repository:tagを使ってtarファイルを作るのがよさげ

ここまででDockerにRNA-Seqのパイプラインを実行できる環境を構築できた
Dockerfileを使えば異なるVirtual Machine上にも
Trinityを実行する全く同じ環境が作成できる


あとはDockerの環境構築と
直接WSL上に環境を構築するのとで
どっちが手間がかかるか
ってことかもしれない

Dockerだと他のパイプラインに影響を与えずに
コマンドのアップデートができたり
うまくいかないときに
作り直しするのも楽なのは助かる

それと作成したimageのサイズは2.56GBになった
ベースのubuntuが80MB以下だったので
シークエンスのデータを含まずにこのサイズは
かなり大きい気がする


dfとdocker statsは使用頻度が高かった
【 df 】コマンド――ディスクの空き領域を表示する:Linux基本コマンドTips(58) - @IT
docker stats — Docker-docs-ja 20.10 ドキュメント


Dockerの使い方で調べると
ウェブサーバーとして使っていたりするらしい
もしかしたらJBrowseを実行するのに良かったりして
そのうち時間があれば作ってみたい

8 May 2020 追記
計算に使っていたPCが落ちてた
つい3時間前までは動いていたのに・・・
再起動後にログイン画面ならわかるが
BIOS画面になっていたのが気になる

20時間ぐらいやっていたことが全部消えてしまった
virtual machineも当然落ちたので記録なし
出力先をホスト側にしないとこんなとき何も残らないな
追記ここまで