はじめに
測定データが縦方向に複数保存されているcsvファイルから、必要な情報を抜き出して横方向に結合していく方法についてご紹介いたします。具体的には以下について解説致します。
- csvファイルの読み込み、書き出し
- DataFrameで特定の値の行番号を抜き出す方法
- DataFrameの扱い方(結合、行や列名の設定方法)
※プログラミング関係の内容を他にも投稿していますので、よろしければこちらの一覧から他の投稿も見て頂けますと幸いです。
取り組み内容
やりたいこと
以下のように複数の測定データが縦方向に保存されたcsvファイルがあります。測定データから欲しいデータのみを抜き出し、測定データごとに横方向に結合していきます。この最終的に欲しいデータをもとに測定データをグラフにまとめていくという感じです。
csvファイルについて具体的に見ていきます。各測定データは"WAVE 1000"から始まり、欲しいデータは黄色で示した"DISP"と"ANALOG1"の部分の値です。元データでは離散的に縦に並んでいますが、これらを抜き出して横方向に並べていきます。なお、測定データはそれぞれの測定ごとにデータ数が異なります。以下の画像の例では最初の測定データ数は557ですが、2つ目の測定データ数は381です。(Total Dataの数を見ています)
環境
pythonを使って、先輩のお願いを何とかしていこか~と思います。
- conda 4.8.3
- python 3.8.3
- pandas 1.0.5
試行錯誤
まずはしっかり方向性を決めないとね。以下の方針で進めていきますか。
- ① 測定データの始まりの目印である"WAVE 1000"を探す
- ② "WAVE 1000"の1列右で4行下にある"Total Data"を読み込む
- ③ "WAVE 1000"の3~4列右で6行下から始まる"DISP"と"ANALOG1"の値を"Total Data"の数だけ読み込む(例では赤枠で示した557行分のデータ)
- ④ ①~③を繰り返して次の測定データから"DISP"と"ANALOG1"の値を読み込む(例では青枠で示した381行分のデータ)
- ⑤ 赤枠で示したデータに青枠で示したデータを結合する
- ⑥ ④~⑤を繰り返す
とりあえず、データ読み込んでいきますか。(もとのデータはdata.csvとして保存しているものとします)
# ライブラリーのインポート
import pandas as pd
import numpy as np
# 元データの読み込み(1行目からデータとして扱いたいので"header=None"を指定)
data = pd.read_csv("data.csv", encoding="shift_jis", header=None)
data.head(10)
読み込んだデータの大きさを確認っと。
data.shape
(17671, 5)
測定データのかたまりの一番最初は"WAVE 1000"で始まり、Total Dataの数(最初のデータでは557)を取得するためにも、まずは"WAVE 1000"が記入されている行数を取得したい。
for i in range(data.shape[0]):
if data[0][i] == 'WAVE 1000':
print(i)
0
563
950
1437
1916
⁝
よし、これで"WAVE 1000"が記入されている行番号は取得できそうだ!この情報をもとに"DISP"と"ANALOG1"が含まれる部分を抜き出したい。
for i in range(data.shape[0]):
if data[0][i] == 'WAVE 1000':
num = data[1][i+4]
sample_data = data.iloc[i+6:i+6+int(num), 3:5]
print(sample_data)
3 4
6 1184 495.56
7 1152 495.8
8 1179 495.5
⁝
562 1596 468.34
[557 rows x 2 columns]
3 4
569 1105 499.22
570 1069 499.22
571 1100 499.16
⁝
949 1525 480.36
[381 rows x 2 columns]
3 4
956 1123 500.2
957 1089 500.26
958 1118 500.02
⁝
おぉ、結構ええ感じ!でも、行番号が測定データごとに異なるのでこのまま結合することは難しそう。行番号はリセットしておこう。
for i in range(data.shape[0]):
if data[0][i] == 'WAVE 1000':
num = data[1][i+4]
sample_data = data.iloc[i+6:i+6+int(num), 3:5]
sample_data = sample_data.reset_index(drop=True)
print(sample_data)
3 4
0 1184 495.56
1 1152 495.8
2 1179 495.5
⁝
556 1596 468.34
[557 rows x 2 columns]
3 4
0 1105 499.22
1 1069 499.22
2 1100 499.16
⁝
380 1525 480.36
[381 rows x 2 columns]
3 4
0 1123 500.2
1 1089 500.26
2 1118 500.02
⁝
これでデータフレームとして結合出来そうやな!ついでに列名も定義しておいた方が先輩喜ぶかな~
for i in range(data.shape[0]):
if data[0][i] == 'WAVE 1000':
num = data[1][i+4]
sample_data = data.iloc[i+6:i+6+int(num), 3:5]
sample_data.columns = ["DISP","ANALOG1"]
sample_data = sample_data.reset_index(drop=True)
print(sample_data)
DISP ANALOG1
0 1184 495.56
1 1152 495.8
2 1179 495.5
⁝
556 1596 468.34
[557 rows x 2 columns]
DISP ANALOG1
0 1105 499.22
1 1069 499.22
2 1100 499.16
⁝
380 1525 480.36
[381 rows x 2 columns]
DISP ANALOG1
0 1123 500.2
1 1089 500.26
2 1118 500.02
⁝
これで完璧やな~いや、待てよ。データフレームは元となるデータフレームがないと結合できへん!それやったらNo.列を入れるデータフレームを作っておいてそこに測定データを横に結合していくか!(最終的に下のようなイメージにしようとしています)
df = pd.DataFrame(columns=["No."])
df
よっしゃ、これに測定データを結合していこう。こんな感じでどないや!
df = pd.DataFrame(columns=["No."])
for i in range(data.shape[0]):
if data[0][i] == 'WAVE 1000':
num = data[1][i+4]
sample_data = data.iloc[i+6:i+6+int(num), 3:5]
sample_data.columns = ["DISP","ANALOG1"]
sample_data = sample_data.reset_index(drop=True)
df = pd.concat([df, sample_data], axis=1)
df.head()
大きさも確認しとこか!
df.shape
(557, 81)
No.列に数字入れてしまいやな!
df["No."] = np.arange(1, df.shape[0]+1)
df.head()
これでcsvに書き出して、先輩に送ろ!!
df.to_csv("new_data.csv", index=False)
完成したコード
試行錯誤の結果、完成したコードは以下です。
# ライブラリーのインポート
import pandas as pd
import numpy as np
# 元データの読み込み
data = pd.read_csv("data.csv", encoding="shift_jis", header=None)
# No.列を持った空のデータフレームを作成する
# 空のデータフレームを作っておかないと後でデータフレームを結合できない
df = pd.DataFrame(columns=["No."])
# 元データに含まれる個別の測定データをそれぞれデータフレームで保存してdfに集約する
for i in range(data.shape[0]):
if data[0][i] == 'WAVE 1000':
num = data[1][i+4]
sample_data = data.iloc[i+6:i+6+int(num), 3:5]
sample_data.columns = ["DISP","ANALOG1"]
sample_data = sample_data.reset_index(drop=True)
df = pd.concat([df, sample_data], axis=1)
# No.列に数値を当てはめる
df["No."] = np.arange(1, df.shape[0]+1)
# 編集したデータフレームをcsvに出力
df.to_csv("new_data.csv", index=False)
まとめ
測定データが縦方向に複数保存されているcsvファイルから、必要な情報を抜き出して横方向に結合していく方法についてご紹介いたしました。もっと用方法があれば是非コメント下さい。