python関係の研究室内Tips

jupyter notebook関係

ノートブックをプリントする

さまざまな形式のデータを含むノートブックで試してはいないが、"File > Download as"のメニューでPDFを選択してそれを印刷するのが楽。

ただし、8tops上のjupyter notebookでは日本語の出力ができない。

その場合の回避策としては、

  1. Markdownにしてから、vscode使ってpdfに変換
    • md (Markdown)形式を選択してダウンロード
    • 解凍
    • vscodeでmdファイルを読み込んでPDFに変換する。
    • もちろんvscodeで、markdown及びpdfを出力するための拡張機能をインストールしておく必要がある。(vscodeは大変便利であるのでぜひ使ってみてほしい。)
  2. htmlに変換して、Webブラウザのプリント機能を利用
    • 試した範囲では、こちらの方がよさそうだ。(上記ではファイルによってはうまくmdに変換されない。)
    • いきなりプリンタに出すのではなく、プリンタの種類としてpdfを選んでpdfファイルにしてから必要な部分を印刷するのが良いだろう。

画像関係

スケーラブル形式画像ファイルの作成

WordやPowerPointなどに貼るには、jpegやpng形式の画像よりスケーラブル(アウトライン、ベクトル形式)画像を用いたほう高品質な印刷物が得られる。

Microsoft Officeで使えるスケーラブル画像形式はemfである一方、matplotlibで使えるスケーラブル画像はsvgやeps形式での出力ができる。後者から前者への変換ソフトとして、ubuntuにはInkspaceが備わっているので、いったんsvg形式のファイルをつくり、それをInkspaceに渡してemfにする。

そのためには、外部プログラムを呼び出すsubprocessという関数を用いる。

import subprocess
# 中略
plt.savefig('sample_image.svg', bbox_inches='tight') # tight指定は周辺の余白を取り除くため
subprocess.call('inkscape sample_image.svg -M sample_image.emf', shell=True)
  • LaTeXに取り込む図ファイルを作るには、eps形式ではなくpdf形式がよい。後者の方が、figure環境での図の位置を適切にセットできる。
    • ファイル名に拡張子以外のところでドットを使うとBBboxの設定がなされないことがある。"_"を使うのが無難(?)
      plt.savefig("prob2_10_5.pdf", bbox_inches="tight", pad_inches=0.05)
      

matplotlib

フォントサイズの一括変更

https://www.it-swarm.dev/ja/python/matplotlib%E3%83%97%E3%83%AD%E3%83%83%E3%83%88%E3%81%AE%E3%83%95%E3%82%A9%E3%83%B3%E3%83%88%E3%82%B5%E3%82%A4%E3%82%BA%E3%82%92%E5%A4%89%E6%9B%B4%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/970648288/

fontsize = 14
plt.rcParams.update({'font.size': fontsize})
fig = plt.figure( figsize=fig_size)
plt.subplots_adjust(hspace=0.25) # plt.figureの後に置く必要がある

subplot間の間隔設定

フォントの大きさを変えたり、軸ラベルが長かったりすると字が重なる場合がある。その時の調整は

plt.subplots_adjust(wspace=0.4, hspace=0.6)

タイトル

  • figure全体のタイトル

    fig.suptitle("時間ごとのパケット数分布")
    
  • 凡例のタイトル

    ax.legend(title="時")
    

日付・日時関数

Web上にいろいろな情報があるが、研究室で用いそうなものをメモしておく。

文字列と日付の変換

In [1]:
from datetime import datetime as dt
from datetime import timedelta

date_str = "20191001" # 文字列
date_datetype = dt.strptime(date_str, "%Y%m%d") # 第2引数で文字列の形式を指定
date_datetype
Out[1]:
datetime.datetime(2019, 10, 1, 0, 0)
In [4]:
print(date_datetype)
2019-10-01 00:00:00
In [6]:
# 1日後
tomorrow = dt.strptime(date_str, "%Y%m%d") + timedelta(days=1)
print(tomorrow)
2019-10-02 00:00:00
In [8]:
# 1日後の日付を文字列に直す
dt.strftime(tomorrow, "%Y%m%d")
Out[8]:
'20191002'
In [9]:
# epoch time(1970-01-1 00:00:00)からの秒数を日付型に変換する
dt.fromtimestamp(1569989110.042173000)
Out[9]:
datetime.datetime(2019, 10, 2, 13, 5, 10, 42173)

timestampからdatetime

In [10]:
# date型 ⇒ epoch time (date型のオブジェクトのメンバ関数を利用)
a = dt.fromtimestamp(1569989110.042173000)
print(a)
a.timestamp()
2019-10-02 13:05:10.042173
Out[10]:
1569989110.042173
In [12]:
dt.fromtimestamp(2147483648) # 2^31 ← 2038年問題
Out[12]:
datetime.datetime(2038, 1, 19, 12, 14, 8)

datetimeの一部置き換え

In [1]:
import datetime as dt
d = dt.datetime(2020, 9, 26, 12,1,0)
d2 = d.replace(minute=59, second = 59)
print(d2)
2020-09-26 12:59:59

pandasの日付変換

ある列にtimestampが入っている場合、それをdatetime型の列を新設する

df['start_date'] =df.start.apply(lambda x: datetime.fromtimestamp(x))

次のようにすると、timezoneがUTCになってしまう。

df['start_date'] = pd.to_datetime(df['start'],unit='s')

次のようにtimezoneを明示して変換すればよいようだ。

In [2]:
import pandas as pd
d = pd.to_datetime(1592233213, unit='s', utc=True).tz_convert('Asia/Tokyo')
d
Out[2]:
Timestamp('2020-06-16 00:00:13+0900', tz='Asia/Tokyo')

DataFrameの日付列から平日週末をわける例

df['date']に文字列で日時が入っているとする

詳しくは、 hakushuTraffic.html参照

df['date_obj'] = pd.to_datetime(
     df[p]['date'])  # dateは文字列なので、datetime型の列を新設
df['hour_min'] = df['date_obj'].dt.strftime("%H:%M")  # 時分の文字列の列を新設
df['day-of-week'] = df['date_obj'].dt.dayofweek
df4av_weekend = df[(dt.strptime(from_date, "%Y-%m-%d") <= df['date']) &
                   (df['date'] <= dt.strptime(to_date, "%Y-%m-%d")) &
                   (df['date_obj'].dt.dayofweek >= 5)]
df4av_weekday = df[(dt.strptime(from_date, "%Y-%m-%d") <= df['date']) &
                   (df['date'] <= dt.strptime(to_date, "%Y-%m-%d")) &
                   (df['date_obj'].dt.dayofweek < 5)]

コマンドライン・シェル上での実行

コマンドライン引数を格好良く

Linux上でスクリプトを実行するときには、パラメータを実行時に指定できるようにしておくと便利である。

繰り返しあるいは同時並行でプログラムを実行できるから。

下のように1行目にコマンドを書いておく。

簡単には、

#!/usr/bin/env python3
import sys

args = sys.argv
print(args[0])
print(args[1])
print(args[2])

のように、sys.argvにコマンドライン引数の値が入る。順序を間違わなければこれでもよいが、引数の数や順序にかかわらず、指定できるようにするには、 ライブラリargsparseを利用する。

たとえば、

./xxx.py -s 20180821 -e 20180911 xxxx.csv

のように指定する。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
実用的なコマンドライン引数: argparse
  標準では sys.argv[0], sys.argv[1], のように順番にsys.argvに入るが、
  たくさんの引数や、あってもなくてもよい引数を使いたい場合には
  argparseを利用するのが便利
 - "-s"のようなのはなくても良い
 - filenameは必須
 - 規則に合わない場合は使い方を表示してくれる。
"""
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("filename")
parser.add_argument("-s","--stime")
parser.add_argument("-e","--etime")
args = parser.parse_args()
print(args)

パラメータを変えて同じスクリプトを並列にバックグラウンドで実行するにはbatchというコマンドを利用する。

利用方法については、

https://toyoki-lab.ee.yamanashi.ac.jp/~toyoki/labTips/batchTutorial.html

の下の方に書いてある。

In [ ]: