皆さん、こんにちは!
今回はPythonを用いてデータロガーなどから出力される大量のCSVファイルの圧縮を行っていきたいと思います。
みなさんは、CSVファイルを開くとき、時間が掛かって「重いなぁ」と感じたことはありませんか?
私は、大学院生ですが研究でデータロガーやシミュレーションソフトを扱っていて、その結果をCSVファイルとして出力し分析を行うのですが、大量のCSVファイルの操作に手を焼いてきました。
今回は、そのような私の経験から、CSVファイルそのものを軽くしたり、欲しいデータごとにファイルを分割するコードをPythonで組みましたので紹介していきます。
- Pythonを用いたCSVファイルの読み込み出力
- CSVファイルの圧縮(不要データの削除)
- 読み込んだデータの分割
- Python上でコードの進捗を表示してくれるProgresbar
ちなみに、私がPython初心者なので、この記事は私より初心者の「超初心者向け」の内容になっています。
コードの書き方など非効率なところもあるとは思いますが、ご容赦ください。
Contents
データロガーなどで出力されるデータは量が多い
理系の研究では、データロガーやセンサー、アプリケーションから大量のデータを取得することがよくあります。
多くの場合は、時間分解能やサンプリング間隔を設定することで調整できますが、どうせデータを取るなら、細かく取った方がいいのでは?と考えてしまい、必要以上にデータを取ってしまった経験があるかもしれません。
少し多いくらいならいいですが、私の場合は何百列、数万行といった量のデータになってしまい、ファイルを開くのも一苦労、グラフを作るのにも時間が掛かるという有様でした。
上記のデータはほとんどが不要なデータだったため、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は、timeとtqdm.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)
