🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

1回答

2611閲覧

時系列データにおける外れ値の除外について

multinguish

総合スコア6

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/12/27 03:16

編集2020/12/27 11:07

python初心者です。

前提・実現したいこと

1秒ごとに皮下血流量の測定を行っております。
血流低下をアラートするシステムの実装を目指しております。
専用のセンサーにて血流量測定を行なっておりますが、体動によるノイズで流量がたまに異常高値となってしまうため、外れ値の検出と除外を行いたいと考えています。
[https://qiita.com/hoto17296/items/d337fe0215907432d754#%E5%81%8F%E5%B7%AE%E3%81%8B%E3%82%89%E5%A4%96%E3%82%8C%E5%80%A4%E3%82%92%E6%A4%9C%E5%87%BA%E3%81%99%E3%82%8B]
こちらのサイトを参考に、指数加重移動標準偏差による外れ値の検出と除外を計画しました。
血流量の列をyに格納した状態で以下を実行しました。

df_csv_ewm = y.ewm(span=90).mean() ts=pd.Series(y) fig, ax=plt.subplots() ax.plot(ts, label="original") ax.plot(df_csv_ewm, label="ewma") ax.legend() def plot_outlier(ts, ewm_span=90, threshold=3.0): assert type(ts) == pd.Series fig, ax = plt.subplots() ewm_mean = ts.ewm(span=ewm_span).mean() # 指数加重移動平均 ewm_std = ts.ewm(span=ewm_span).std() # 指数加重移動標準偏差 ax.plot(ts, label='original') ax.plot(ewm_mean, label='ewma') ax.fill_between(ts.index, ewm_mean - ewm_std * threshold, ewm_mean + ewm_std * threshold, alpha=0.2) outlier = ts[(ts - ewm_mean).abs() > ewm_std * threshold] ax.scatter(outlier.index, outlier, label='outlier') ax.legend() return fig plot_outlier(ts)

これにより標準偏差から3.0倍以上外れているデータを外れ値として検出、描画を行うことができました。
次に外れ値の除外を行おうと考えました。
調べたところ「drop」「clear」などが使えるのではないかと思ったのですが、どの位置で実行すべきか構文の理解の問題かわかりませんでした。
outlierの定義の次に
ts.drop(outlier)など入力するのですが

AttributeError: 'Series' object has no attribute 'drop'

と表示されてしまいます。

外れ値を除外した状態のグラフ描画、また除外した状態にして他値との相関評価ができればと考えております。
ご意見いただければ幸いです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

siruku6

2020/12/27 03:59

できたソースコードの掲載と、 >「外れ値を除外したデータフレームの再作成」 をするために試したこと、その結果出たエラーや発生してしまった期待していない結果などは書いた方が回答が得られるかと思います。 何も試されていないわけではないかと思います。 どこまで理解できていて、どの行のどの処理で詰まっているのか、がうまく伝われば回答は得られるかと思います。
multinguish

2020/12/27 10:44

ご指摘ありがとうございます。 具体性のない質問となってしまっていました。 大変参考となりました。 修正させていただきます。
guest

回答1

0

インデクスを指定してdropすれば普通に削除できています。
以下が参考になるでしょうか。

python

1>>> import numpy as np 2>>> import pandas as pd 3>>> rand = np.random.RandomState(seed=20) 4>>> x = np.arange(6) 5>>> y = 500000 \ 6... + x ** 2 \ 7... + np.sin(x/4) * 100000 \ 8... + rand.randn(len(x)) * 100000 \ 9... + rand.gamma(0.01, 1000000, len(x)) 10>>> 11>>> ts = pd.Series(y) 12>>> print(ts) 130 588389.311262 141 544327.898153 152 583700.205458 163 333846.685438 174 475679.839749 185 650893.304559 19dtype: float64 20>>> ts.drop(4, inplace=True) 21>>> print(ts) 220 588389.311262 231 544327.898153 242 583700.205458 253 333846.685438 265 650893.304559 27dtype: float64

元のQuitaのように日付をindexとしている場合は以下です。

python

1import numpy as np 2import pandas as pd 3rand = np.random.RandomState(seed=20) 4idx = pd.date_range(start='2020-12-25', end='2020-12-31', freq='D') 5x = np.arange(len(idx)) 6y = 500000 \ 7 + x ** 2 \ 8 + np.sin(x/4) * 100000 \ 9 + rand.randn(len(x)) * 100000 \ 10 + rand.gamma(0.01, 1000000, len(x)) 11 12ts = pd.Series(y, index=idx) 13print(ts) 14ts.drop(ts.index[5], inplace=True) 15print(ts)

削除したい行が何行目かはわかっているという前提です。
また、削除したい行が複数ある場合は、行が変化しないように下から順に削除してください。
dorpは遅い処理ですので、削除したい行が多い場合は、別に作ったDataFrameに必要な部分だけをコピーしたほうが高速になります。

投稿2021/01/02 14:15

編集2021/01/03 13:30
ppaul

総合スコア24670

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

multinguish

2021/01/03 12:15

ご回答誠にありがとうごいます。 基本的な部分で大変申し訳ないのですが、「ts.drop(4, inplace=True)」の部分の「4」を何に置換して良いかわかりません。 「outlier.index」や「outlier」で置換しても「name 'outlier' is not defined」が返ってきてしまいました。
ppaul

2021/01/03 13:30

指定するのは消したい列のindexです。 multinguishさんのプログラムでは、元のQuitaにあった日付のindexがなくなっていたので、それに合わせたのですが、元の形のほうがわかりやすいかもしれませんね。 そちらも載せておきます。
multinguish

2021/01/03 14:19

補足までしていただき恐縮です。 元々秒刻みの時刻の列、血流量の列のあるcsvを取り込み、血流量をyに格納しています。 ts = pd.Series(y, index=idx)のidxに1刻みの経過秒数を格納することでindexが作れることは理解できました。 その場合idx = pd.date_range(start='2020-12-25', end='2020-12-31', freq='D')はどのように変化するでしょうか? またts[(ts - ewm_mean).abs() > ewm_std * threshold]となる行数はどのように抽出すれば良いでしょうか? 重ね重ね理解が足りず申し訳ございません。
ppaul

2021/01/03 15:14

idx = pd.date_range(start='2020-12-31 00:00:00', end='2020-12-31 00:00:10', freq='S')のように書けば、秒単位となります。 行数の抽出はまだできていないのでしょうか。「これにより標準偏差から3.0倍以上外れているデータを外れ値として検出、描画を行うことができました。」と書かれていたので、行数はわかっていると思っていました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問