memorandums

日々の作業ログです。

ぱんだすくんを使ったメモ

■経緯

自分のお仕事を効率化するために時間割表示ツール(個人ツールと呼ぶ)を作りました。

memorandums.hatenablog.com

大学には正式?の時間割ツール(大学ツールと呼ぶ)がありまして、今年度からWebインタフェースの新ツールに切り替わりました。

このツールは導入されたばかりなので基本的な機能しかありません。時間割はリスト表示しかできません。今後開発予定とのことです。

個人ツールで時間割配置を検討した結果をみながら手動で大学ツールに入力していきました。

手動なので間違える可能性はあります。正しく入力できたのか確認するため、大学ツールでCSVデータを出力してもらい、個人ツールに読み込ませようとしたのがこのエントリーの始まりです。

当然ですが、個人ツールの方を先に作ったので大学ツールとはデータ形式が異なります。変換しないと個人ツールで時間割のマトリクス表示ができません。。。

変換のために、RubyCSVライブラリであれこれやっていたのですが、文字コードや改行コードの取り扱いが難しかった。。。あれこれ数時間調べて、とりあえず読み込ませるところまではいったんですが、データを整理したり集約したりする処理はコードを書かなければなりません。この前段だけで力尽きました。

GASを使おうかとも思いましたが、これも集約など考えると結局はコードをたくさん書かなければならなそうで。

試しにpandasを使ってみたら。。。恐ろしく簡単だった。

pythonはあまり使う機会がないので、せっかく覚えたことをメモしておこうっていうことです。


■本題

macpythonを使うときにはpipenvがオススメです。python使いではないので自信はありませんが。。。anacondaは環境を汚すので嫌いです。

pipenvの導入はhomebrewがあれば簡単。

brew install pipenv

続いてpipenvのプロジェクト?を作ります。

mkdir test
cd test
pipenv --python=3
pipenv install pandas
pipenv shell

あとは、ターミナル上で好きなエディタでpythonコードを書いて(例えばa.py)、普通に「python a.py」とすれば実行できます。

以下、コードの断片です。ちなみに、コード中のラベル名や数字をそのまま晒すのはもしかすると問題があるかもしれないので(無いとは思いますが)適当に変えています。

a.pyの冒頭にこれ書きます。

import pandas as pd

CSVファイル(ここではa.pyと同じ位置にa.csvというファイルを置いています)を読み込みます。RubyCSVライブラリを使うとこの読み込みだけでエラーが表示されてしまい解決するまでに数時間要しましたが、pandasではネットに掲載されている基本的なサンプルをただ貼り付けるだけで難なく動作しました。

df = pd.read_csv('./a.csv', sep=',')

うちの学科以外の科目データも含まれいたのでこれを除外します。

df = df[df['学科コード'] == 200]

集中講義などを通常授業以外のデータも含まれていたのでこれを除外します。

df = df[df['授業種類'] == '普通']

元々のデータから必要な列だけ残し、かつ、列の並び直しをします。これ、コード書いたら結構大変ですよね。。。たったこれだけでできちゃうんです。。。pandas様さまです。

df = df[['科目名','学年','学期','開講曜日','時限','氏名','教室']]

個人ツールでは、月曜を月、前期を前としていましたので、それぞれ一括変換します。これもちょー簡単です。

df['曜日'] = df['曜日'].str.replace('曜', '')
df['学期'] = df['学期'].str.replace('期', '')

教員名の姓と名の間になぜか空白(しかも全角だったり半角だったり。。。)が入っていたのでこれを除外します。

df['氏名'] = df['氏名'].str.replace(' ', '')
df['氏名'] = df['氏名'].str.replace(' ', '')

教室はみかけ数字なのでpandasでint型になるようです。これだとあとで文字列として扱うのが難しいのでここで一括でstr型にしておきます。

df['教室'] = df['教室'].astype(str)

1つの科目を複数の教員で担当すること、そのため教室が複数にわかれることがあります。大学ツールのCSVファイルでは、同一科目でも教員が異なるとCSVに別の行として出力されてしまいます。DBをフラットファイルに出力する機能を考えるとわからなくはない発想ですが。。。個人ツールでは教員や教室はカンマ区切りで表現しているので(つまりCSVで1科目は必ず1行にする)、科目名でグルーピングして、教員名や教室をカンマ区切りに変換します。以下がそれです。ググってあちこちの情報をまとめて以下のようにしました。集約すると集約したデータしが出力されないので。。。使い方を間違えているような気もするのですが。。。集約以外の項目(学年、学期、曜日、時限)も出力されるようにしています。しかも集約関数で文字列は結合されてしまうし数値は計算されてしまうので、そのまま出力するためにlastとかfirstという関数を使っています。あまりこの情報はなかったので。。。探すのに苦労しましたが。

df = df.groupby(['科目名']).agg({
    '学年': "last",
    '学期': "last",
    '曜日': "last",
    '時限': "last",
    '氏名': lambda x: ', '.join(x),
    '教室': lambda x: ', '.join(x),
})

これはデバック用です。データフレームに入っているデータを省略していい感じに表示してくれます。計算結果が想定通りか確認できます。

print(df)

最後に、変換した結果を再びCSVファイルとして出力します。Excelでみることを想定して文字コードをUTF8からcp932などに変換しています。データ分析ではExcelを使うこともあるでしょうから、この辺が普通に用意されているのが嬉しいですね。

df.to_csv('./a2.csv', encoding='cp932')

研究でRを使ったことはありますが、pandasは真面目に使ったことはありませんでした。それでも、ネットに情報が豊富にあるので、コード片を見様見真似でコピぺするだけで動きました。

しかもコードが短い!

もしこれを他の言語で書いたら。。。

とりあえず私得なメモでした。