はじめに
Python を使って時系列データの前処理を行った際、使ったコードをつらつらと書き足していく。全く同じことをRでも行っているのでそれを読みたい方はこちら。
開発環境
- python 3.8.5
- pandas 1.1.3
- numpy 1.19.2
- jupyter lab 1.2.6
更新履歴
- 2021/02/05:初投稿。データの読み込みから欠損の確認まで。
参考にした記事
モジュールのインポートとデータの読み込み
データは時系列かつ多変量であるWater Treatment Plantを利用した。
必要なモジュールをimport し、データを読み込む。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv("./water-treatment.data", header=None, index_col=0)
df
後々のために日付のカラムをindexとして指定している。
データの結合(複数ある場合)
データのcsvファイルが複数ある場合は、それを結合し一つのDataFrameとして扱いたい。各列の要素が同じであることをチェックしたら、
df = pd.concat([df0, df1, df2])
で結合すればよい。#今回の場合は1ファイルなので不要。
index の datetime化と時刻でのソート
index に時刻がD-日付/月/年という形式で入っているので、それをdatetime型に直す。pandas では、to_datetime
という便利な関数があるので、それを使用する。
df.index = pd.to_datetime(df.index, format='D-%d/%m/%y') #datetimeに変換
df = df.sort_index() #時刻でソートする
df
データの重複の確認
各列のデータに対して重複が無いかをチェックする。列を直接比較する方法は難しそうなので、一旦転置し重複行を探して削除し、再度転置して戻すという方法を取る。
df.T.duplicated() #重複の確認
今回のデータの場合全てFalse
なので重複は無し。重複があった場合は、
df = df.T.drop_duplicates().T
で重複を削除できる。(参考記事1)
因みに要素ではなく列名で重複を確認する場合は以下に示す。
print(df.columns.duplicated()) #重複があればnp.array にTrueが入る
df = df.loc[:,~df.columns.duplicated()] #重複していない項目だけでdfを再構成
データのサンプル間隔を調べる
よくよくデータを見てみると等サンプルのデータではなさそうなので、サンプリング間隔のヒストグラムを作る。日付の配列df.index
を一つずらした配列を作り順次引き算していくことでデータのサンプル間隔を調べる。
flag = 0 #最初の値を回避する用
dt_day = [] #サンプル間隔を入れる配列
for now, pre in zip(df.index, np.roll(df.index, 1)):
if flag == 0:
flag = 1
continue
_tmp = ((now - pre).total_seconds())/(60*60*24) #サンプル間隔を日に変換
dt_day.append(_tmp)
plt.hist(dt_day, bins=range(0,33))
plt.ylabel("Count")
plt.xlabel("Sample interval [days]")
plt.show()
見難いので対数で取ったヒストグラムも作成する。
plt.hist(dt_day, bins=range(0,33), log=True) #y軸をlogにする。
plt.ylabel("Count")
plt.xlabel("Sample interval [days]")
plt.show()
ほとんどが一日間のサンプリングデータだが1/5程度は二日間、ごくまれに三日間、1データだけ一か月くらい(三十二日間)データが飛んでいる箇所があるよう。
これを「等サンプリングに直す」のは次回。
データの欠損の確認
このデータは欠損を含んでいる(欠損は?で表されている。)ので、その可視化を行う。列ごとに欠損の数を数え、その割合を棒グラフにする。
df = df.replace("?", np.nan) #?をnp.nanに変換
nan_count = df.isnull().sum() #NaNの数を数える
nan_per = nan_count/len(df)*100
plt.bar(df.columns, nan_per)
plt.ylabel("Percentage of NaNs [%]")
plt.xlabel("Columns")
plt.show()
ほとんどのデータは10%以下、多くても12%程度の欠損であることが分かった。
欠損をどう埋めるかは次回。
おわりに
以上、データの下準備とちょっとした分析を行った結果を示した。もし加えて何かをした場合は記事に追記していきたい。