メモリ使用状況の取得
前回、Pythonでメモリの使用状況を取得する方法として、psutilを使う方法とJupyter Notebookで表示する方法を紹介しました。

今回はそのおまけとして、取得したメモリ使用量とメモリ使用率をグラフ化してみたいと思います。
まずは前回、取得したデータがこちら。

メモリ使用量とメモリ使用率に関しては数値なので、このまま使えそうですが、問題は「Time」の列。
こちらは日時(Str型)となっているので、ここから経過時間(秒)に変更する必要があります。
それでは始めていきましょう。
プログラム全体
まずはプログラム全体を見てみましょう。
import os
import matplotlib.pyplot as plt
import pandas as pd
def fileListGet(dirpath):
    filelist = [] 
    for file in os.listdir(dirpath):
        if file.endswith('.csv'):
            if not f'{file[:-4]}.png' in os.listdir(dirpath):
                filelist.append(file)
            
    return filelist
def csv2df(file_path):
    df = pd.read_csv(file_path)
    df['Datetime'] = pd.to_datetime(df['Time'], format='%Y/%m/%d %H:%M:%S')
    df['Time'] = (df['Datetime'] - df['Datetime'][0])
    df['Time'] = [row.total_seconds() for row in df['Time']] 
    
    return df
    
def graphMake(df, dirpath, file): 
    fig = plt.figure()
    ax1 = fig.subplots()
    ax2 = ax1.twinx()
    
    ax1.plot(df['Time'], df['Used'], c='b', label='Used')
    ax2.plot(df['Time'], df['PercentUsed'], c='r', ls='--', label='%Used')
    
    ax1.set_xlabel('Time(Sec)', fontsize=12)
    ax1.set_ylabel('Used', fontsize=12)
    ax2.set_ylabel('%Used', fontsize=12)
    
    ax1.tick_params(labelsize=12)
    ax2.tick_params(labelsize=12)
    
    h1, l1 = ax1.get_legend_handles_labels()
    h2, l2 = ax2.get_legend_handles_labels()
    ax1.legend(h1 + h2, l1 + l2)
    
    fig.tight_layout()
    output_figpath = os.path.join(dirpath, f'{file[:-4]}.png')
    plt.savefig(output_figpath)
def main():
    default_dirpath = os.getcwd()
    filelist = fileListGet(default_dirpath)
    for file in filelist:
        file_path = os.path.join(default_dirpath, file)
        df = csv2df(file_path)
        graphMake(df, default_dirpath, file)
if __name__ == '__main__':
    main()ライブラリのインポート
今回、使用するライブラリは「os」、「matplotlib」、「pandas」の三つです。
いつも通りインポートします。
import os
import matplotlib.pyplot as plt
import pandas as pdfileListGet関数
「fileListGet関数」はフォルダ内にあるファイルから特定のファイルを抽出する関数です。
def fileListGet(dirpath):
    filelist = [] 
    for file in os.listdir(dirpath):
        if file.endswith('.csv'):
            if not f'{file[:-4]}.png' in os.listdir(dirpath):
                filelist.append(file)
            
    return filelist「for file in os.listdir(dirpath):」で特定のフォルダ内にあるファイルの名前を一つずつ取得します。
そしてファイル名が「.csv」で終わっているものを選択(if file.endswith(‘.csv’):)し、さらに同じフォルダ内に同じファイル名で拡張子が「.png」になっているものがない場合(if not f'{file[:-4]}.png’ in os.listdir(dirpath):)、リストfilelistに追加します。
今回、読み込むファイル名は「ファイル名.csv」であり、出力されるグラフのファイル名は「ファイル名.png」とするためです。
そしてグラフが出力されているCSVファイルに関してはリストfilelistに追加しない、つまり今後の処理を行わないようにするためです。
csv2df関数
次はCSVファイルを読み込み、Pandasのデータフレームに変換するための「csv2df関数」です。
def csv2df(file_path):
    df = pd.read_csv(file_path)
    df['Datetime'] = pd.to_datetime(df['Time'], format='%Y/%m/%d %H:%M:%S')
    df['Time'] = (df['Datetime'] - df['Datetime'][0])
    df['Time'] = [row.total_seconds() for row in df['Time']] 
    
    return df後ほど「main関数」の中でファイルを一つずつ取得します。
その取得したファイルをPandasのデータフレームに変換するのですが、最初にお話しした通り、「Time」が日時になっているので、プログラムを開始してからの経過時間に変更する必要があります。
ということでまずは「df = pd.read_csv(file_path)」でCSVファイルを読み込み、Pandasのデータフレームに変換します。
「Time」の列は全てStr型の日時になっていますので、これを「pd.to_datetime(変換するデータ位置)」を使い、一括で変換します。
またその際、オプションで「format」を指定すると、日時のフォーマット形式を指定することができます。
今回はそれを「Datetime」という新しい列を作成し、データフレームに追加します。
df['Datetime'] = pd.to_datetime(df['Time'], format='%Y/%m/%d %H:%M:%S')そして日時を経過時間とするために、各行の日時のデータを最初の行の日時のデータで引き算します。
df['Time'] = (df['Datetime'] - df['Datetime'][0])これで経過時間にはなったのですが、Datetime型という年月日時分秒という形のままです。
試しに出力してみたのがこちらです。
0    0 days 00:00:00
1    0 days 00:00:01
2    0 days 00:00:02
3    0 days 00:00:03
4    0 days 00:00:04
5    0 days 00:00:05
6    0 days 00:00:06
7    0 days 00:00:07
8    0 days 00:00:08
9    0 days 00:00:09
10   0 days 00:00:10
11   0 days 00:00:11
12   0 days 00:00:12
13   0 days 00:00:13
14   0 days 00:00:14
15   0 days 00:00:15
16   0 days 00:00:16
17   0 days 00:00:17
18   0 days 00:00:18
19   0 days 00:00:19
Name: Time, dtype: timedelta64[ns]これを秒にするには「Datetime型のデータ.total_seconds()」としますが、Pandasのデータフレームの列全体にこの関数を使うことはできません。
そのためデータを一つずつ変換して、再度「Time」の列に格納するということが必要になります。
この場合はリスト内包表記を使うと楽です。
df['Time'] = [row.total_seconds() for row in df['Time']] これで「Time」の列を経過時間に変更することができました。
graphMake関数
次はグラフを作成する「graphMake関数」です。
def graphMake(df, dirpath, file): 
    fig = plt.figure()
    ax1 = fig.subplots()
    ax2 = ax1.twinx()
    
    ax1.plot(df['Time'], df['Used'], c='b', label='Used')
    ax2.plot(df['Time'], df['PercentUsed'], c='r', ls='--', label='%Used')
    
    ax1.set_xlabel('Time(Sec)', fontsize=12)
    ax1.set_ylabel('Used', fontsize=12)
    ax2.set_ylabel('%Used', fontsize=12)
    
    ax1.tick_params(labelsize=12)
    ax2.tick_params(labelsize=12)
    
    h1, l1 = ax1.get_legend_handles_labels()
    h2, l2 = ax2.get_legend_handles_labels()
    ax1.legend(h1 + h2, l1 + l2)
    
    fig.tight_layout()
    output_figpath = os.path.join(dirpath, f'{file[:-4]}.png')
    plt.savefig(output_figpath)今回は左のY軸にはメモリ使用量、右のY軸にはメモリ使用率を出すため、Y軸が2軸のグラフとしました。
    ax1 = fig.subplots()
    ax2 = ax1.twinx()Y軸が2軸のグラフに関してはこちらの記事で解説していますので、良かったらどうぞ。

あとは特段変わったところはなく、それぞれのデータのプロットがこちら。
    ax1.plot(df['Time'], df['Used'], c='b', label='Used')
    ax2.plot(df['Time'], df['PercentUsed'], c='r', ls='--', label='%Used')X軸、Y軸のラベルの設定。
    ax1.set_xlabel('Time(Sec)', fontsize=12)
    ax1.set_ylabel('Used', fontsize=12)
    ax2.set_ylabel('%Used', fontsize=12)X軸、Y軸の数値のフォントサイズの設定。
    ax1.tick_params(labelsize=12)
    ax2.tick_params(labelsize=12)凡例の設定。
    h1, l1 = ax1.get_legend_handles_labels()
    h2, l2 = ax2.get_legend_handles_labels()
    ax1.legend(h1 + h2, l1 + l2)グラフサイズの調整とグラフの出力。
    fig.tight_layout()
    output_figpath = os.path.join(dirpath, f'{file[:-4]}.png')
    plt.savefig(output_figpath)といった感じでグラフを作成しています。
main関数
最後にmain関数です。
def main():
    default_dirpath = os.getcwd()
    filelist = fileListGet(default_dirpath)
    for file in filelist:
        file_path = os.path.join(default_dirpath, file)
        df = csv2df(file_path)
        graphMake(df, default_dirpath, file)
if __name__ == '__main__':
    main()ここでは最初に現在のフォルダのパスを取得(default_dirpath = os.getcwd())し、そのフォルダ内でグラフ化するCSVファイルをfileListGet関数で取得しています(filelist = fileListGet(default_dirpath))。
そして取得したファイルのリストからfor文を使って、ファイル名を一つずつ取得(for file in filelist:)し、ファイルパスを作成(file_path = os.path.join(default_dirpath, file))します。
そしてcsv2df関数とgraphMake関数を使って、グラフ化するという流れです。
このプログラムを使って作成したグラフがこちらです。

基本的にメモリ使用量とメモリ使用率は一致するはずなので、両方出す意味がなかったかなと思いつつ、とりあえず量も率も一目瞭然なのでいいかなと思っています。
次回はメモリの使用状況を把握するためのもう一つの方法「各変数で使用しているメモリ量の取得」を試していきたいと思います。

ではでは今回はこんな感じで。

コメント