EurekaMoments

ロボットや自動車の自律移動に関する知識や技術、プログラミング、ソフトウェア開発について勉強したことをメモするブログ

個人的なPython逆引きリファレンス

目次

はじめに

Pythonでプログラミングをするようになって暫く経ちますが、
未だに基本的な文法やTipsについて同じことを何度も調べては
忘れ、調べては忘れを繰り返しています。
今回の記事では、そうやって今まで調べてきたことを一通り逆引き
リファレンスとして残して、もっと素早く調べ直せるようにします。

ディレクトリやファイルを開くダイアログを表示

まずは以下のモジュールをimport

import tkinter as tk
import tkinter.filedialog as tkfd

これでただダイアログを表示させると、謎の小さいウィンドウが表示されて
鬱陶しいので、先に以下のコードを書いておけば表示されなくなる。

root = tk.Tk()
root.withdraw()

ディレクトリを選択して開きたい場合は以下のように書くことで、
ディレクトリまでのパスが取得できる。

directory_path = tkfd.askdirectory(title='hogehoge')

ファイルを選択するなら以下のように書く。 複数ファイルをまとめて選択することも出来る。

# For single file
file_path = tkfd.askopenfilename(title='hogehoge')

# For multi files
files_path = tkfd.askopenfilenames(title='hogehoge')

詳細は以下のサイトを参照
Tkinter tkFileDialog module - Python Tutorial

.zipや.gzみたいな圧縮ファイルをバイナリモードで開く

まずは以下のモジュールをimport

import gzip
import struct

解釈させる圧縮ファイルを開く時

# 'rb': read only as binary mode
# 'utf-8': encoding
with gzip.open(file_path, 'rb', 'utf-8') as fp:
    # read contents of file

ファイルの中身のバイト列をバイナリデータとして解釈する時
例えば以下のようなフォーマットのデータが時系列で入っているなら、
unsigned long a(4バイト)
unsigned short b(2バイト)
unsigned short c(2バイト)

while True:
    a_binary = fp.read(4)  
    b_binary = fp.read(2)
    c_binary = fp.read(2)

    #interpret as binary data
    a = struct.unpack('L', a_binary) # 'L': data format, unsigned long
    b = struct.unpack('H', b_binary) # 'H': data format, unsigned short
    c = struct.unpack('H', c_binary) # 'H': data format, unsigned short

ファイルの最後まで到達したことを知りたい場合
例えばprintでメッセージを出すなら、

while True:
    a_binary = fp.read(4)  
    b_binary = fp.read(2)
    c_binary = fp.read(2)

    if a_binary == b'' or b_binary == b'' \
        or c_binary == b'':
            print('end of file')
            break

詳細は以下のサイトを参照。
gzip --- gzip ファイルのサポート — Python 3.9.4 ドキュメント
struct --- バイト列をパックされたバイナリデータとして解釈する — Python 3.9.4 ドキュメント

ループで処理を回している時の進捗率を把握する

以下のモジュールをimport
標準では入っていないので事前にpipでインストールが必要

from tqdm import tqdm

書き方は以下の通り。これで処理しているデータdata_array中の
何%まで処理が進んだかが出力される

for data in tqdm(data_array):
    # do something

pandasで空のデータフレームを作成し、データを逐次追加していく

pandasをimportし、以下のように書く。
この場合、各列に割り当てるカラムは事前に定義しておく。
index方向のデータが空の状態とする。

import pandas as pd

colmuns_list = ['A', 'B', 'C', 'D']
data_frame   = pd.DataFrame(index=[], columns=columns_list)

そしてこれに1行分のデータフレームを作成してindex方向に追加していく。
以下のコードをfor文などのループで回せばよい。

data_series = pd.Series(data_array, index=colmuns_list, name='hoge')
data_frame  = data_frame.append(data_series)

CSVファイルをpandasで読み込んだ時に列をindexに指定する

データフレームの0列目をindexに指定するとしたら、

data_frame = pd.read_csv('hogehoge.csv', index_col=0)

pandasデータフレームをCSVファイルに書き込む時に日本語の文字化けを防ぐ

data_frame.to_csv('hogehoge.csv', encoding='utf-8-sig')

複数のデータフレームを一つに結合する

重複するカラムを区別しないならconcatメソッドを使って結合。
横方向に結合させるならaxis=1とする。

data_frame_integrated = pd.concat([data_frame_1, data_frame_2, data_frame_3], axis=1)

詳細は以下のサイトを参照。
ailaby.com

データフレームからある条件を満たすデータを抽出する

カラムが'A'のデータの中で数値が1である部分と同じ行のデータを全て取り出すなら、

data_frame_extracted = data_frame[data_frame['A'] ==  1]

3次元のデータパネルを作る

最初に空の辞書を作成しておき、それにキーと該当するデータフレームを追加していく。 そして最後にその辞書オブジェクトをパネルに変換する。

dict_data_frame = {}

for key in key_list:
    dict_data_frame[key] = data_frame

data_panel = pd.Panel(dict_data_frame)

辞書オブジェクトの使い方は以下のサイトを参照。
辞書オブジェクトの使い方 - Python Tips

メッセージウィンドウを表示させる

以下のモジュールをimport。

import tkinter.messagebox.tkmsb

例えば何かしらの処理を実行して、それの終了を告げるメッセージを表示させるなら、

tkmsb.showinfo(title='Window title', message='Completed!!')

みたいな感じ。
詳細は以下のサイトを参照。
TkInter message box - Python Tutorial

指定したディレクトリ内にあるファイル名をリストアップする

import os
import tkinter as tk
import tkinter.filedialog as tkfd

root = tk.Tk()
root.withdraw()

directory_path = tkfd.askdirectory(title='hogehoge')
file_list = os.listdir(directory_path)

print(file_list)

日付と時刻を表す文字列をdatetime型として処理する

処理したいテキストデータに日付や時刻を表す文字列が含まれていたり、
読み込むファイルの名前に日付時刻が含まれている場合、その部分を抽出
してdatetime型のデータに変換しておけば、そのファイルやデータを時系列で ソートしたり、時刻を指定して抽出できるようになる。

from datetime import datetime, timedelta

# extracted date and time as string
date_str = '181005'
hour_str = '11'
minutes_str = 19
second_str = 25

# integrate as date and time 
date_time_str = date_str + '-' + hour_str + ':' + minutes_str + ':' + second_str
date_time = datetime.strptime(date_time_str, '%y%m%d-%H%M%S') #181005-11:19:25

これの~分後とか~秒後の時刻を同じdatetime型として求めることが出来る。
timedeltaを用いて例えば30分後の時刻を求めるとしたら、

date_time_after_30min = date_time + timedelta(minutes=30)

ある二つの時刻の比較は以下のようにすればできる。

if date_time_1 < date_time_2:
    # do something
elif date_time_1 > date_time_2:
    # do something

詳細は以下のサイトを参照。
datetime --- 基本的な日付型および時間型 — Python 3.9.4 ドキュメント

datetime型データをCSVファイルに書き込んだ際の注意点

あるデータが日付時刻の順番で並んでいるとして、その日付と時刻をdatetime型に
変換してnumpy配列に格納。

date_time_array = np.append(date_time_array, np.array([date_time]), axis=0)

そしてそれをindexに割り当てたpandasデータフレームを作り、CSV形式で保存したとする。

data_frame = pd.Dateframe(data=data_array, index=date_time_array, columns=columns_array)
data_frame.to_csv('csv_file_name.csv')

ここで注意しなければならないのは、このCSVファイルをpandasデータフレームとしてまた読み込んだ時、そのindex配列(datetime型の日付時刻が入っている)を参照すると、それがdatetime型ではなく、型を持たないただのオブジェクトになってしまうことである。
このまま例えばmatplotlibのplot関数に突っ込んだとするとエラーが起きてしまう。その対処法として、pandasのto_datetimeメソッドを使えばもう一度datetime型のオブジェクトに戻すことができ、エラーは起きなくなる。

ファイルやディレクトリの各種操作

散乱した大量のファイルをジャンル別などでフォルダ分けして自動整理したい時。
必要なモジュールは以下の二つ

import shutil
import os

# Check File or Directory
if os.path.isfile(path) == False:
    # Directory
else:
    # File

# Check path exist or not
if os.path.exists(path) == False:
    # Path doesn't exist
else:
    # Path exists

# Make directory
os.mkdir(path)

# Move file to directory
shutil.move(move_file_path, directory_path)

Figureを表示中にマウスクリックにより別な処理を走らせる

マウスのクリック操作によって呼び出される関数を定義する。
クリック操作がFigureが持つaxes上で行われた時のみ処理を走らせる。

def click(event):
    # get current active axes pointer
    gca = event.inaxes

    # check click operation was done on the current axes
    if hasattr(gca, 'colNum') == True and hasattr(gca, 'rowNum') == True:
        # Right button clicked
        if event.button == 3:
            # do something
        # Left button clicked
        elif event.button == 1:
            # do nothing 

# call click function
figure.canvas.mpl_connect('button_press_event', click)

データフレームからカラム名を指定してデータを抽出

data_frame_extracted = data_frame.loc[:, ['A', 'B', 'C']]

その他詳細は以下のサイトを参照。
note.nkmk.me
Pandas のデータフレームの特定の行・列を削除する – Python でデータサイエンス

データフレームの各データ同士の相関係数を計算してヒートマップ表示する

import seaborn as sbn

corerelation_matrix = data_frame.corr(method='pearson')

sbn.heatmap(corerelation_matrix ,
            vmin=-1.0,
            vmax=1.0,
            center=0,
            annot=True,
            fmt='.2f',
            ax=axes,
            xticklabels=corerelation_matrix .columns.values,
            yticklabels=corerelation_matrix .columns.values)

詳細は以下のサイトを参照。
note.nkmk.me