データロガーから出力される大量のCSVファイルをPythonで圧縮

Python

こんにちは

悟です。

今回はPythonを用いてデータロガーなどから出力される大量のCSVファイルの圧縮を行っていきたいと思います。

みなさんは、CSVファイルを開くとき、時間が掛かって「重いなぁ」と感じたことはありませんか?

私は、大学院生ですが研究でデータロガーやシミュレーションソフトを扱っていて、その結果をCSVファイルとして出力し分析を行うのですが、大量のCSVファイルの操作に手を焼いてきました。

今回は、そのような私の経験から、CSVファイルそのものを軽くしたり、欲しいデータごとにファイルを分割するコードをPythonで組みましたので紹介していきます。

この記事を読むと出来るようになること
  1. Pythonを用いたCSVファイルの読み込み出力
  2. CSVファイルの圧縮(不要データの削除)
  3. 読み込んだデータの分割
  4. Python上でコードの進捗を表示してくれるProgresbar

ちなみに、私がPython初心者なので、この記事は私より初心者の「超初心者向け」の内容になっています。

コードの書き方など非効率なところもあるとは思いますが、ご容赦ください。

データロガーなどで出力されるデータは量が多い

理系の研究では、データロガーセンサーアプリケーションから大量のデータを取得することがよくあります。

多くの場合は、時間分解能やサンプリング間隔を設定することで調整できますが、どうせデータを取るなら、細かく取った方がいいのでは?と考えてしまい、必要以上にデータを取ってしまった経験があるかもしれません。

少し多いくらいならいいですが、私の場合は何百列、数万行といった量のデータになってしまい、ファイルを開くのも一苦労、グラフを作るのにも時間が掛かるという有様でした。

上記のデータはほとんどが不要なデータだったため、Pythonを使って不要なデータを削除することにしました。

インポートする前の注意点

Pythonのread_csvを使う際には、入力するCSVファイルが表形式である必要があります。

そのため、表形式になっていない場合は、手動で開いて成形してやってください。

行番号や、列名はあっても問題ありません。

データロガーあるあるだと思いますが、この表では1Aのセルに「Measurement text output」の表示が出てしまっています。


csvファイルをインポート

それでは、インポートしていきます。

使うライブラリは「pandas」です。

pd.read_csv(“ファイル名”)で、データフレーム形式でインポートすることができます。

直接ファイル名を入れても出来るのですが、コードが長くなっていくとゴチャゴチャしてくるのでfile_passという変数に入れておきます。

手持ちのデータを使ってやってみてください。

私が使うデータは2420×1801と、1つずつチャックするには少々面倒なデータ量です(これでも少ない方)

df.head()で上から5行までの表示にしています。


# -----------------------ライブラリをインポート-------------------------------- import pandas as pd import numpy as np ### ---インポートする前に、シート全体をデータフレームとして加工できるか確認する--- # ---------------------インポートするファイルを指定----------------------------- file_pass = "test.csv" # ----------------------CSVファイルをインポートする----------------------------- df = pd.read_csv(file_pass) # -----------------------データフレームを表示する------------------------------- df.head()

最終行の番号を読み取り圧縮する(1つ飛ばしでデータを削除or一定時間感覚で削除)

次は圧縮です。

基本は行番号を参照しつつ、任意の行をまるごと削除する方法とします。

データを1つ飛ばしで削除する方法(データ量は半分になります)と、一定時間間隔でデータを残す方法を紹介します。

といってもシンプルに圧縮するだけでは芸が無いので、Python上でコードの進捗を表示する方法も合わせて解説します。

今回のコードでは、大きなファイルを処理するため計算時間が少し長くなり、何分もデバックが「*」になっているとコードがしっかり動いているか不安になりますよね。

後はコード実行中にアニメーションで進捗が見れると、なんかカッコいいです。

データを1つ飛ばしで削除する方法

Progressbarは、timetqdm.autonotebookをインポートする必要があります。

インストールはAnacondaプロンプトからpip install tqdm で行ってください。

ProgressBarはいくつか種類があり、使っている開発環境によって相性があるようです。

私はJpyterNotebookを使っており、異なる環境で行っている方は、ProgressBarでエラーが出る可能性があります。

for 文の中の、range(開始点,終わり点,ステップ)で変更することが可能です。

今回はシンプルにデータ量を半分にするということでステップを2としています。(デフォルトでは1)

# 進捗を表示するProgressBar
import time
from tqdm.autonotebook import tqdm
# 最後の行番号を取得
# この行までループさせる
last_data = df.index.values[-1]
# absは()内を整数にします
t = abs(1 / last_data)
# ファイルが重すぎるのでデータ量を半分にする
for i in tqdm(range(0,last_data,2)):
        df = df.drop(index=i)
        time.sleep(t)
# ファイルが4分の1まで圧縮できます
df.to_csv(file_pass)
print("ファイルの圧縮が終わりました")

圧縮が終了すると、以下のようにインデックスが1つ飛ばしになっており、圧縮できていることがわかります。

一定時間間隔で削除

先ほどは、データを1つおきに削除するというものでした。

次は少し工夫して、一定時間間隔でデータを残すようにしてみようと思います。

例えば、1秒間隔でデータを取ったけど、そんなにいらないから5秒ごとのデータにしたい場合や、データ処理の関係から切りの良い時間間隔(1秒間隔や5秒、60秒など)でデータを残すようにしてみます。

(圧縮対象となっているデータが、時系列データであることが前提となっています)

データフレーム内の時間データの列名を「TIME」としておきます。

お手持ちのデータによって、コードを変更してやれば対応できます。

途中までは、前述のコードと同じです。

今回は5秒間隔のデータにしたいのですが、最初のデータは残しておきたいので、ループの範囲をrange(1, last_data)としておきます。

削除するかどうかの判定はif文で行いますが、私のデータのように小数点を含むデータだと判定が出来なくなってしまいます。

そこで、round()を使って四捨五入してやります。

これで5で割り切れない時間を持つ行を削除することが可能になります。

# 進捗を表示するProgressBar
import time
from tqdm.autonotebook import tqdm
# 最後の行番号を取得
# この行までループさせる
last_data = df.index.values[-1]
# absは()内を整数にします
t = abs(1 / last_data)
### ここまで同じ ###
# 1つ目のデータはどんな値でも残したいので、range(1,last_data)
for i in tqdm(range(1,last_data)):
    # df["TIME"]の列のi番目を整数にする
    s = round(df["TIME"][i])
    # 5秒ごとに
    if s % 5 != 0:
        df = df.drop(index=i)
    time.sleep(t)