トライ&エラーのサイクル

前回更新したのが2017年末なので半年ぶりの更新になります。今日は最近考えていることを書こうかと思います。

前振り

早めに就活も終わり(某IT大手に決まった。嬉しい。)、今は大学院を修了するための修士論文に向けた実験及び修論に取り組んでいます。正直に言うとあまり実験が好きではありません。実験よりは修論執筆のために論文を読んで情報収集しているときの方がまだ楽しいと感じます。それよりも楽しいと感じるのがプログラムを書いているときです。プログラミング >> 論文読み >> 実験ですね。

なぜなのか

なんででしょうか。何が実験を楽しくなくさせているのでしょうか。

自分の答えはタイトルに書いてあるとおりです。トライ&エラーのサイクルが速い順に楽しいと感じるようになっています。もともと自分はかなりせっかちな人間です。何事も早く進めたい人なんですね。

自分がプログラムを書くときは、

こうかな?と思ったことを書く->実行する->エラーが出る->エラーが出たとこを突き止める->修正する(最初に戻る)

というサイクルで書いていきます。プログラムを書いて集中しだすとこのサイクルがものすごい速度で回っていきます(あくまで体感の話です)。この集中してる時間はめちゃめちゃ楽しいし、プログラム書くのが捗ります。では論文読みはどうでしょうか。自分はあまり英語が得意ではありません。しかし仮にも3年近く取り組んでいる分野ですので普通の洋書を読むよりは速く読めます。そして論文の意図がわかり始めるとなおのこと速く読めます。さらに集中しだすともっと速く読めます。読んだあとに文章に起こすのが少し時間がかかります。実感としてはトライ&エラーのサイクルの速さはプログラミング >> 論文読みですね。さて実験に話を移しましょう。自分が取り組んでいる実験は有機材料の応用物性みたいなことをやっています(あんまり詳しく書いてバレるのも嫌なのでざっくりと)。合成とかではないです。どちらかというと評価側の実験をしています。今取り組んでいる実験がまあ時間がかかります(合成とかではないのでそこまでめちゃめちゃ拘束時間が長いとかではないです。あくまで個人の感想です)。実験サンプルを用意するのに2日(準備も含めて)ぐらいかかります。そこから自分のやりたいことを行うのですが、そこも完成されたやり方がまだなく試行錯誤しながらやっています。実験系を組み立てて試そうとするもうまく行かず、また実験系を組み直してまた実験…みたいなことをやっています。化学合成系とかをやっている人からするとその程度まだまだと思われるかもしれませんが、自分の比較対象はプログラミングなのでスピード感は雲泥の差です。サンプル準備の2日の間に何行プログラムが書けるのか。webアプリくらいならプロトタイプぐらいは出来てるんじゃないですかね。分野が違いすぎて比較すること自体がナンセンスな気もしますね笑

あくまでも

これらはすべて個人の意見です。誰かに押し付けるとかではないです。上でごちゃごちゃ述べてますが、要は好き嫌いです。せっかちでスピード感のあることが好きな自分は時間のかかる実験があまり好きではないだけです。それしか知らなければ文句もそこまで出ませんが、残念なのか幸運なのかスピード感のあることを知ってしまいました。就職したらもっと楽しいのかなと夢見つつ、今日はこんな感じで

年の瀬に徒然と

2017年もそろそろ終わりに近づいてきましたね。最近更新していなかったので2017年最後の更新をして今年を締めくくりたいと思います。

Webアプリのデプロイ

オンプレでWebアプリをデプロイするときのサーバの構成についてなんとなくこうかなと思うことがあったのでそれについて書きます。Webアプリのデプロイの方法をインターネットで検索するとflask + uwsgi + nginxといった構成がヒットします。そもそもuwsgiってなによという感じだったのですが、uwsgiはアプリケーションサーバと呼ばれるもののようです。自分のイメージではユーザからのアクセスをWebサーバで受け付けてアプリケーションサーバに渡し、アプリケーションサーバからアプリケーションが呼ばれるという感じなのかなーと考えております。

ユーザ ー> Webサーバ ー> アプリケーションサーバ ー> アプリケーション

こんなかんじなんですかねー。そこまできちんと調べたわけではないので間違っていたらすいません…笑。また勉強しておきます。

Google カレンダー

所属研究室ではGoogleカレンダーで予定を管理しております。時々プライベートなGoogleアカウントと混同したまま予定を入力して研究室内に予定を暴露している人がままいます。Googleが想定している本来の使い方は個人のアカウントで予定を作成して予定を共有する方法だと思われます。しかし予定を共有するとなると共有相手に参加の許諾をしてもらう必要があります。いくつも予定がある場合は参加許諾をしてもらうのが面倒だと思います。ここで本来ならその解決策を書くべきなのでしょうが、全くそれについては調べてないのでもう少し便利にならんかな−というただの愚痴になってしまってますね笑。

大したことも書いてないですが今年の締めはこんな感じでご容赦ください。それでは皆さん良いお年を。

ひさしぶりに

どうやら前投稿してから128日経っているようです。128日というとおよそ4ヶ月ですか。なかなかに書いてないですね。書いてないのは勉強していないからというわけではなく、単純にアウトプットをサボっているだけです。前回の投稿を見るとどうもWebアプリの勉強をしていた頃らしく、herokuのことについて書くと宣言しています。ただあの頃に比べてかなりWebアプリ熱は自分の中で冷めており、herokuのこともあまり勉強していないですし、ぶっちゃけかなり使い方を忘れています笑。Webアプリ熱が冷めているだけであり、プログラミング自体はまだ書いています。また気が向いたら更新するつもりなのでよろしければ御覧ください。

pandas.read_clipboad()

Pandasのread_clipboardでデータをデータフレームにしてからプロットしたり解析したりというアプリをつくってここ半年ほど使っていました。しかし、データの出力が1行目に全く関係ない[0, 0, 0]という文字列が出力されていて、欲しいデータは2行目からという状態でした。今までは1行目を削除してからデータをコピーしていたのですが、ワンステップ工程が増えてしまいます。最近そのプログラムのスリム化を図っていたこともあり、ちょっと手を加えることにしました。といっても元からある引数を指定してやるだけですが笑

pandas.read_clipboard()はpandas.read_table()関数に渡しているらしく、引数もread_tableの引数をread_clipboardに渡せるようです参考。また、read_tableにはskiprowsという引数があり、読み込まない行番号を指定してやることができるそうです参考。というわけで1行目を読み込まないようにpandas.read_clipboard(skiprows=1)としてやると目的達成です。と言いたいところですがそうではなく、半角スペースも'\t'とみなされているのか、新たな列としてカウントされていました。そこでpandas.read_clipboard(sep='\t', skiprows=1)としてやると無事に目的が達成されました。

Webアプリ関連 (heroku) のことを書こうと思ったのですが、その記事を書き終わる前にあっさりかけるネタが見つかったので順番が前後してしまいました。herokuのことはいずれ書きます笑

Webアプリ

最近の状況

前回の記事でWebアプリの開発のためにPythonのマイクロフレームワークであるFlaskについて学んでいますと書きましたが、ネット上のサンプルをいじりながら簡単なものなら書けるようになりました。ですので自分なりの知識の整理をするためにFlaskでつくったアプリと実際にHerokuで公開するまでを簡単にまとめてみたいと思います。

経緯について

自分の所属している研究室ではデータの解析をNgraphExcelで行っています。当研究室に代々受け継がれているデータ解析用のExcel等があるので皆さんそれを使ってらっしゃるのですが、Excelは重いしデータ解析の前に無駄な動作があるなと思っておりました。無駄な動作というのは生データの入れ替えをExcelでいちいち行わなければならないということです。入れ替えの動作自体は単純な作業なのですが、逆に言えば単純な作業ならプログラムに任せるべきでもあります。そこで生データの入れ替えを行うWebアプリを開発して公開しようと思い立ちました(データの入れ替えだけならそんなに難しくないだろうと思ったので笑)。

Flask Web app

つくったWebアプリですが自分で一からつくったわけではなく、ネット上のサンプルをいじりながら作りました。参考サイトは以下です。

qiita.com

この例では

<input type=text>

に入力された名前をHTMLに埋め込んで返すということを行っております。自分の場合だと十数行×十数行のタブ区切りのテキストデータなのでtextareaにする必要がありました。また変更後のデータも十数行×十数行となるためtextareaに埋め込んでレンダリングしようと考えました。また変更後のデータはコピペのみができたら良いのでreadonly=“true"にすることと、大量のデータはwrapされると読みにくいのでwrap="off"としています。pythonファイル側はデータのならび変えをするだけなのでなにか特別なことをしているわけではないです。なにはともあれとりあえず以下に載せます。

"""filename : main.py"""

# Flask などの必要なライブラリをインポートする
from flask import Flask, render_template, request, redirect, url_for
from operator import methodcaller
import pandas as pd


def group(dataframe):
    dataframe_col = dataframe.shape[1]
    RANGE = range(1, int(dataframe_col/4)+1)
    dv = ['Voltage_1 ({})'.format(i) for i in RANGE]
    dc = ['Current_1 ({})'.format(i) for i in RANGE]
    gv = ['Voltage_2 ({})'.format(i) for i in RANGE]
    gc = ['Current_2 ({})'.format(i) for i in RANGE]
    drain_v = dataframe[dv]
    drain_c = dataframe[dc]
    gate_v = dataframe[gv]
    gate_c = dataframe[gc]

    return pd.concat([drain_v, drain_c, gate_v, gate_c], axis=1)


def toNestedList(data):
    data = data.splitlines()
    splitedData = list(map(methodcaller("split", "\t"), data))

    return splitedData


# 自身の名称を app という名前でインスタンス化する
app = Flask(__name__)


# ここからウェブアプリケーション用のルーティングを記述
# index にアクセスしたときの処理
@app.route('/')
def index():
    title = "Transform data"
    # index.html をレンダリングする
    return render_template('index.html',
                           title=title)


# /post にアクセスしたときの処理
@app.route('/transformed', methods=['GET', 'POST'])
def transformed():
    title = "Data is transformed!"
    if request.method == 'POST': 
        data = request.form['textarea']  # データを取得
        NestedList = toNestedList(data)
        df = pd.DataFrame(NestedList[1:], columns=NestedList[0])
        df2 = group(df)

        return render_template('index.html',
                               title=title,
                               originalData=data,
                               transformedData=df2.to_csv(
                                          index=False, sep='\t'))
    
    else:
        # エラーなどでリダイレクトしたい場合はこんな感じで
        return redirect(url_for('index'))


if __name__ == '__main__':
    app.debug = True  # デバッグモード有効化
    app.run()  # どこからでもアクセス可能に

個人的に悩んだのはHTMLのtextareaから取得するのはtsvではなくただのstring型なのでどうやってpandasのDataFrameに読み込ませるかということですね。最初はそもそもファイルをアップロードしてもらう方式を取ろうかとも考えていたのですが、HTML5についてあまり良く知らなかったため諦めました笑 結局stringデータとなったものをsplitを二回して2次元配列とし、それをDataFrameとするように実装しました。

また出力に関しても悩んだのですがこれはpandas公式ドキュメントを読むと、pandas.DataFrame.to_csvメソッドで引数を与えないと文字列として返すようになるのを利用しました。

この他にindex.htmlとlayout.htmlも書く必要があります。以下に記載します。

<!-- index.html -->
{% extends "layout.html" %}
{% block content %}
  <!-- Form
  ================================================== -->
<div class="form">
  <div class="container">
    <div class="row">
      <div class="col-md-12">
      <h2>Transform data for mobility of linear or saturation region</h2>
      <h4><a href="https://www.youtube.com/watch?v=xAH6VFGCX6Q">Tutorial video</a></h4>
        <form action="/transformed" method="post">
          <h3>Original data</h3>
          <textarea class="form-control" rows="5" id="textarea" name="textarea" placeholder="Original data" wrap="off">{% if originalData %}{{originalData}}{% endif %}</textarea>
          <button type="submit" class="btn btn-default">Transform</button>
        </form>
        <h3 for="comment">Transformed data</h3>
        <form>
          <textarea class="form-control" rows="5" id="textarea2" placeholder="Transformed data" readonly="true" wrap="off">{% if transformedData %}{{transformedData}}{% endif %}
          </textarea>
        </form>
      </div>
    </div>
  </div>
</div>
{% endblock %}
<!-- layout.html -->
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    {% if title %}
        <title>{{title}}</title>
    {% else %}
        <title>Bootstrap 101 Template</title>
    {% endif %}
    <!-- Bootstrap -->
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
  <body>
    {% block content %}{% endblock %}
    <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
    <!-- Include all compiled plugins (below), or include individual files as needed -->
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script> 
    </body>
</html>

layout.htmlは上に挙げた参考サイトのものをほとんどそのまま引用してます。参考サイトの方もBootstrapの公式をそのまま使ったというようなことが書いてあったはずです。layout.html内の{% block content %}{% endblock %}にindex.htmlの内容を埋め込むようなかたちでレンダリングしているようです。index.htmlの<form action=/transformed method="POST">でボタンを押すといった動作が検知されたときにどこに移動先のURLを示すようです。

たぶんまだ色々書いたほうが良いのでしょうが、文章ですべてを説明しようとするのはなかなか難しいですね。main.pyのFlaskのルーティングのこととかの説明は他サイトを見て頂くと分かるかと思われます。質問していただければ自分も分かる範囲で答えさせて頂きます。

長くなったのでHerokuでデプロイするところはまた別記事で書きます。それでは

Flask勉強中

先日

バイト帰りにメールチェックをしているとはてなブログからメールが届いていました。いつもどおりフォローしてるはてなブロガーの新記事が出たよというお知らせメールかと思いきや、一ヶ月ぐらい何も書いてないけどそろそろ書けば?という催促メールでした。

というわけで催促されたので大した実りもない勉強中のことを書きます。

前フリ

最近はwebアプリをデプロイしたいためwebアプリケーションフレームワークについて勉強しています。今まではフルスタックのフレームワークの方が将来的にも使う頻度が高いのかな−という理由からDjangoについて勉強していました。しかしフレームワークというものについても知らない人間がネットの情報を漁りつつデプロイまでたどり着くということは到底不可能に近く、自分の飽き性もあって全く勉強は進んでいませんでした。そこでPythonで有名なフレームワークとしてDjangoとは別にFlaskという名前をよく見かけることに気づきました。(そもそもなんでPythonなのかというとPythonしか書けないからです…)Flaskはマイクロフレームワークと呼ばれており、非常に軽量なフレームワークだそうです。設定ファイルが一つだけで良いらしいということから初心者である自分はこちらから学び始めた方が良いのではと考え、現在学んでおります。

所感

Djangoを学んでいるときに感じていた「今自分は何を書いているのだろう」という疑問は少ないです。Flaskは簡単なものならあまりプログラムを書く必要がありません。(十数行程度で書けるときもあります)その程度の分量なら自分でもがんばれば読めるし、理解できます。なのでとりあえずFlaskでWebアプリを自由に作れる程度までは頑張って勉強していきたいと思います。

Anacondaから標準のPythonに

Raspberry Pi 3にPythonの環境を構築してて思ったのですが、環境構築ってAnacondaじゃなくてもよくない?と思ったのでAnacondaから標準のPythonに移行しました。環境はMacで行っております。

まずhomebrewをインストールします。この手順は他サイトで紹介されていると思うので探してみてください。

brew install python3

とするとPython 3系がインストールできます。Pythonがインストールできたらpip3コマンドが使えるので必要なライブラリをそれぞれインストールしたらおしまいです。自分はnumpy, scipy, matplotlib等をインストールしました。

pip3 install numpy scipy matplotlib

こんな感じです。

仮想環境も作れると思ったのでつくてみたのですがなんかエラーが出ました。めげずにもう一回同じコマンドを打つと仮想環境が構築できました。結果仮想環境が作れたのでいいのですが、なぜエラーがでるのか少し気になりますね。