pythonを使った時系列データの解析をやっていると、外れ値のデータが邪魔でどうにかしたいケースが多くあります。筆者は三次元動作分析をメインでやっているのですが、その場合には、三次元動作解析装置自体に備わっているラベリングツールで事前に補完作業とかができます。
しかしながら、近年の画像や動画を使った三次元動作解析アルゴリズムを使うと、自動でラベリング作業が行われる一方で、誤推定してしまった部分などを事後的に直したりするといったことが困難になります。特に全身が映っていない動画や背面から人物の動画は比較的荒れやすく、修正箇所も多い場合が想定されます。
そういった骨格推定のエラーを修正するために具体的にはどのような方法をとったら良いかというと、一番単純なのは、エラーが起きている個所を空白にして、その区間の両端のデータから補完するといった方法が挙げられます。
今回はpythonのパッケージであるpandasを使って外れ値の除去からの欠損値補完の例について紹介していこうと思います。
※あくまでも一例です。これだけが正解ということではなく、一部だと思ってもらえると幸いです。
第一手順は、外れ値データの同定と欠損値化から
外れ値のデータをどのように除去、補完していくかというと、大きく3つのプロセスがあります。①外れ値に該当するデータの同定、②該当データの欠損値化、③欠損値を含んだデータに対する補完といった順番になります。
pythonのパッケージとして何を使っていくかというと、基本的にはpandasとnumpyです。pandasとnumpy自体に欠損値に置換する処理や欠損値を補完する処理が含まれているので、他のマニアックなパッケージを使わなくても良いというのが利点です。前に書いたAnacondaの導入記事を見て同じ環境を作ってくれればそれで全く問題ありません。
想定するデータは時系列データを想定し、特定のフレームに外れ値があるというケースでいきます。1フレームだけとかが外れ値の場合にはフィルタリング処理をすることで解決するのですが、動作の時系列データの場合には簡単には除去できないケースが多いです。
こういったケースの場合には、ループ回路をかませて特定の時点のデータが特定の基準値を逸脱していた場合に、空欄にするといった処理を行います。
具体的なコードの例は以下の通りです。今回のケースは特定の時系列データの平均値の2SDを超えた時点のデータを欠損値にするという感じでいきましょう。
import numpy
import pandas
#必要なパッケージのインポート
data = data #ここは個々人の想定している時系列データの配列になります。
mean_data = np.mean(data)#平均値
std_data = np.std(data)#標準偏差
range = mean_data+(2*std_data)#平均値+標準偏差の二倍の値(今回の基準値)
for x in range (len(data)):#時系列データの数だけループ
if data[x]>range
data[x]=np.nan
具体的な処理としては、特定の基準値(今回の場合は平均値の2SDを超える値)を超えた場合を外れ値として定義して、その値をdataのx行目が超えたときに欠損値(np.nan)にするという感じです。
これで欠損値と数値が入った時系列データを作ることができました。
欠損値のデータに対して補完処理を行うコードにはpandasの関数を使う。
先ほどの欠損値化した処理をしたdataに対して以下のコードをかけると欠損値を補完することができます。補完の種類にはいろいろありますが、今回のケースでは線形補完(ざっくりというと欠損値を挟んだ両端のデータを直線でつなぐように補完する方法)で行っています。
data = pd.DataFrame(data).interpolate(method='linear')
基本的には一行で完結するのでコード自体は簡単です。事前にpandasの配列に変換しておく必要があります。このコードで想定しているのは一列複数行の一元の配列データなので、複数列複数行(例えばxyz座標が一つにまとまった時系列データ)の場合には、個別に配列を作り直す必要があるのでそこは要注意です。スプライン補完などに代表されるように補完方法にはいろいろあるので、そこは状況に応じて使い分けましょう。
このコードは単に外れ値を欠損値化させて補完するだけの用途ではなく、当然そもそものデータ計測で欠損値がcsvデータに入ってしまっている場合でもつかえるので便利です。