【業務効率化】後輩「フォルダにある大量のcsvファイルからグラフを自動生成するプログラム作ってくれないっすか？」

## はじめに
**フォルダにある大量のcsvファイルからグラフを自動生成するプログラムを作った方法についてご紹介いたします。**具体的には以下について解説致します。

- フォルダにあるcsvファイルを一括で読み込む方法
- 読み込んだcvsファイルからファイル名を取り出す方法

※プログラミング関係の内容を他にも投稿していますので、よろしければ[こちら](https://qiita.com/oki_kosuke/items/34b1071224953776c211#%E6%8A%95%E7%A8%BF%E4%B8%80%E8%A6%A7)の一覧から他の投稿も見て頂けますと幸いです。

## やりたいこと
今回実現したいことを以下に図で示します。（y2_sumについては後述します）

- csvファイルからグラフを作成する
- 作成するグラフのファイル名は元のcvsのファイル名をつける（a.csv→a.png）
- フォルダ内にcsvファイルが大量にあるので、このグラフ作成をループ処理にて自動で行う

![syuusei.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057114/35e55d13-6f47-02a8-6ff4-d3b286d3612d.png)

### 環境

- conda 4.8.3
- python 3.8.3
- pandas 1.0.5

### 試行錯誤
まずは処理するcsvファイルの中身を確認します。今回処理するcsvファイルはすべて同じ形式でデータが保存されています。

```python
import pandas as pd

# CSV名に日本語が含まれるとエラーが出る
data = pd.read_csv("確認したいcsvファイル名.csv", encoding="shift_jis", header=None)
data.head(10)
```

![data_head.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057114/aa45c106-826e-d024-9908-740ea2f0df4d.png)

4行目以下の1列目をx、2列目をy1、3列目をy2として折れ線グラフを書いていきます。y2に関しては合計値が必要なので、各行の総和を求めておきます。

```python
# 変数の定義
# 1列目をxとして定義
x = data.iloc[3:,0]
# 2列目をy1として定義
y1 = data.iloc[3:,1]X
# 3列目をy2として定義
y2 =  data.iloc[3:,2]
# 3列目のy2の値の和を定義
y2_sum = sum(y_radiation)

import matplotlib.pyplot as plt
import numpy as np

plt.figure(figsize=(16, 10))
plt.plot(x, y1, label='y1', marker="o", markersize=5, linestyle="solid", color="blue")
plt.plot(x, y2, label='y2', marker="o", markersize=5, linestyle="solid", color="orange")
plt.title("graph_title", fontsize=16)
# 他のデータとの関係でy軸の範囲は0～3500で500刻みに設定しておきます
plt.yticks(np.arange(0,4000,500))
plt.grid()
plt.legend(fontsize=16)
plt.show()

print("y2_sum:"+str(y2_sum))
```

![test_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057114/022552c6-2626-8769-9d35-be5a10c0bf94.png)

```:出力結果
# この値は一例です
y2_sum:1192873
```

続いて、フォルダ内の全てのcsvファイルに対してこのグラフ作成の操作を自動で実行できるように考えていきます。

大量のデータがあるので、保存したグラフを判別しやすくするために元データのcsvの名前を"画像の保存名"と"グラフタイトル"につける仕様にします。そのためには元データのcsvファイル名が必要です。まずは[こちら](https://qiita.com/kawai_mizugorou/items/dac9c98dc7f01fe0489e)を参考にフォルダ内にある全てのcsvファイルの取得を試みます。

```python
import glob
all_csv = glob.glob('C:/Users/参照しているディレクトリ/*.csv')
all_csv
```
```:出力結果
# a.csv, b.csv, … x.csvがある場合
'C:/Users/参照しているディレクトリ/a.csv'
'C:/Users/参照しているディレクトリ/b.csv'
︙
'C:/Users/参照しているディレクトリ/x.csv'
```

[こちら](https://ja.stackoverflow.com/questions/49388/pandas-read-csv%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%82%93%E3%81%A0csv%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E5%90%8D%E3%82%92%E5%87%BA%E5%8A%9B%E3%81%99%E3%82%8B%E7%94%BB%E5%83%8F%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E5%90%8D%E3%81%AB%E8%BF%BD%E5%8A%A0%E3%81%97%E3%81%9F%E3%81%84)や[こちら](https://note.nkmk.me/python-pathlib-name-suffix-parent/)を参考に読み込んだcsvファイルのパスを取得します。

```python
from pathlib import Path
# 例として上で取得したcsvファイルの1番目のパスを表示
p = Path(all_csv[0])
p
```
```:出力結果
WindowsPath('C:/Users/参照しているディレクトリ/a.csv')
```

取得したパス名からファイル名を取得していきます。

```python
p.stem
```
```:出力結果
a
```

無事に元データのcsvの名前を取得することができました。取得したcsvの名前を"画像の保存名"と"グラフタイトル"につける際に**「f文字列」**を使用するので少し解説します。

```python
label = "abc"
print("label")
```
```:出力結果
label
```

上記のようにlabelを定義しても、printする際に"label"とするとそのままlabelが出力されます。しかし、次のようにf文字列を使うことで初めに定義した"abc"を出力することが可能です。

```python
label = "abc"
print(f"{label}")
```
```:出力結果
abc
```

## 完成したコード
これらの試行錯誤を経て完成したコードです。処理時間を記録する仕様も追加しています。

```python
# ライブラリのインポート
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import glob
from pathlib import Path
import datetime

# プログラムの開始時間
start_time = datetime.datetime.today()
print ("開始時刻: " + start_time.strftime('%Y-%m-%d_%H-%M-%S'))

# ラベルとy2の和のリストを作る（このリストをのちにデータフレームに変形してcsvとして出力）
label_list = []
y2_sum_list = []

# 以下の繰り返し処理でcvsファイルからグラフを作成して、y2の値の和を計算
for i in glob.glob('C:/Users/参照しているディレクトリ/*.csv'):
    # csvのデータをdataとして取得
    data = pd.read_csv(i, encoding="shift_jis", header=None)
    # .stemでファイル名をlabelとして取得
    label = Path(i).stem
    # 変数の定義
    # 1列目をxとして定義
    x = data.iloc[3:,0]
    # 2列目をy1として定義
    y1 = data.iloc[3:,1]
    # 3列目をy2として定義
    y2 =  data.iloc[3:,2]
    # 3列目のy2の値の和を定義
    y2_sum = sum(y2)
    # 各csvのラベルとy2の値の和をリストとして保持
    label_list.append(label)
    y2_sum_list.append(y2_sum)
    # グラフの作成
    plt.figure(figsize=(16, 10))
    plt.plot(x, y1, label='y1', marker="o", markersize=5, linestyle="solid", color="blue")
    plt.plot(x, y2, label='y2', marker="o", markersize=5, linestyle="solid", color="orange")
    plt.yticks(np.arange(0,4000,500))
    plt.title(f"{label}", fontsize=16)
    plt.grid()
    plt.legend(fontsize=16)
    plt.savefig(f"{label}.png")
    
# ラベルとy2の値の和をリストをデータフレームに変換して保持
# columnsは[]でくくって定義しないとエラーが出る
df_label_list = pd.DataFrame(label_list, columns=["label"])
df_y2_sum_list = pd.DataFrame(y2_sum_list, columns=["y2_sum"])
df = pd.concat([df_label_list, df_y2_sum_list], axis=1)
# データフレームをcsvとして書き出す
df.to_csv("y2_sum_data.csv")

# プログラムの終了時刻
end_time =  datetime.datetime.today()
print ("終了時刻: " + end_time.strftime('%Y-%m-%d_%H-%M-%S'))
print ("所要時間: " + str(end_time - start_time))
```

実行すると同じディレクトリにcsvファイルと同じ名前のグラフ名をpngファイルが保存されます

```:保存結果
a.png
b.png
︙
x.png
```

また"y2_sum_data.csv"には以下のようにy2の総和のデータが保存されています。（y2_sumの数字は一例です）

|  |label  |y2_sum  |
|:-:|:-:|--:|
|0  |a  |1192873  |
|1  |b  | 1287319 |
|︙  |︙  |︙  |

これにて完成です。後輩も喜んでくれました！！

### 追記
上記のプログラムだとディレクトリをわざわざ指定する必要があるので、カレントディレクトリを自動で指定できる以下のコードの方が便利かなと思いましたので修正案を書きます。修正案で動作することは確認済みです。

```python
# 修正箇所
for i in glob.glob('C:/Users/参照しているディレクトリ/*.csv'):
```

```python
import os
# 修正案
for i in glob.glob(os.getcwd()+"/*.csv"):
```

## まとめ
フォルダにある大量のcsvファイルからグラフを自動生成するプログラムを作った方法についてご紹介いたしました。

### 参考
- [フォルダ内のcsvファイルを全て読み込む方法3選](https://qiita.com/kawai_mizugorou/items/dac9c98dc7f01fe0489e)
- [スタック・オーバーフロー](https://ja.stackoverflow.com/questions/49388/pandas-read-csv%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%82%93%E3%81%A0csv%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E5%90%8D%E3%82%92%E5%87%BA%E5%8A%9B%E3%81%99%E3%82%8B%E7%94%BB%E5%83%8F%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E5%90%8D%E3%81%AB%E8%BF%BD%E5%8A%A0%E3%81%97%E3%81%9F%E3%81%84)
- [note.nkmk.me](https://note.nkmk.me/python-pathlib-name-suffix-parent/)
- [note.nkmk.me](https://note.nkmk.me/python-os-getcwd-chdir/)