質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.50%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

Q&A

解決済

2回答

2700閲覧

波形のpeak値検出プログラムを作りたい

H.K2

総合スコア88

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

0グッド

0クリップ

投稿2019/03/14 14:41

前提・実現したいこと

python3で、波形のピーク値検出のメソッドを作成しようと思っています。
inputは、pandasのseriesで、ロジックは、離散値の2点を順番に読み込み、それらのPeakを更新していくプログラムとなります。
イメージとしては下記となります。
イメージ説明

発生している問題・エラーメッセージ

一通りロジックを作成したのですが、下記エラーが出てきて先に進めなくなってしまいました。
ネットで検索してみたのですが、解決方法がよくわかりませんでした。。。

---> 19 if (wav.iloc[i] * wav.iloc[i+1] < 0): ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

解決したいこと

①エラーコードが出ている原因が知りたい(下記コードがなぜNGか)
②他にプログラム上、まずいところがあればご教示いただきたい

該当のソースコード

ソースコードは下記となります。

Python3

1 2def f_A95pp(wav=None): 3 # peakのリスト 4 peaks = pd.Series([0]) 5 6 # 各サンプルごとのpeak(最大の絶対値)のみを格納していく。 7 for i, _ in enumerate(wav): 8 if i == len(wav)-1: 9 break 10 11 print(i, wav.iloc[i], wav.iloc[i+1], type(wav.iloc[i]), type(wav.iloc[i+1])) 12 # i,i+1サンプルの積が負の場合は次のpeakの入れ物を作る。 13 if (wav.iloc[i] * wav.iloc[i+1] < 0): 14 print("***i:{}, i+1:{}***".format(wav.iloc[i], wav.iloc[i+1])) 15 peaks.append(wav.iloc[i:i+1].copy().abs()) 16 print("peaks_len:{}***".format(len(peaks))) 17 # peaksの末尾のデータを越えた値がくる場合は、peaksの末尾を更新 18 elif(abs(peaks.iloc[-1]) < abs(wav.iloc[i])): 19 peaks.iloc[-1] = wav.iloc[i].copy() 20 21 print("peaks:",peaks) 22 23 # peaksが2個以下(1周期着てない場合)は、Noneを代入する。 24 if(len(peaks) < 2): 25 peaks = None 26 27 # peak_max(peakの最大値をとる。) 28# print(peaks) 29 dif_peak = peaks.iloc[0:-1].copy()-peaks.iloc[1:].copy() 30 peak_max = dif_peak.max() 31 32 # p2p:peaksのリスト(indexが,時間tとなっている) 33 p2p = dif_peak.abs() 34 print("temp:",temp) 35 p2p.sort_index(ascending=False) 36# temp.sort(key=lambda x: x[1], reverse=True) # 37 38 # PA95(peaksの上位5%を除いた値のリストの中の最大値を取りたい) 39 temp_a95pp = p2p[round(len(ptp)*0.95+0.5):] 40 print("temp_a95pp:",temp_a95pp) 41 42 if temp_a95pp is None: 43 a95pp = 0 44 else: 45 a95pp = max(temp_a95pp) 46 47 return (peak_max, a95pp, ptp) 48

試したこと

エラーコードについて検索した。
テストコードを描いて試してみた。

補足情報(FW/ツールのバージョンなど)

Python3.6

ご回答いただけましたら幸甚に存じます。

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

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

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

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

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

guest

回答2

0

ベストアンサー

ザッと見てみましたが、かなり問題が・・・
順番に
【1】
hayataka2049さんが既に指摘しておりますが、
peaks.append(wav.iloc[i:i+1].copy().abs())
の箇所は
peaks = peaks.append(wav.iloc[i:i+1].copy().abs())
ですね
【2】
dif_peak = peaks.iloc[0:-1].copy()-peaks.iloc[1:].copy()
の箇所ですが、Series同士の引き算では同じIndexでの引き算となるので、結果全ての値が0となってしまいます
やるならば
dif_peak = peaks.diff(-1)[:-1]
で良いかと思います。
【3】
peak_max = dif_peak.max()
の箇所ですが、負の値の無視されますがこれは問題ないのでしょうか?(仕様なのかもしれませんが)
【4】
p2p.sort_index(ascending=False)
の箇所は 【1】と同じく
p2p = p2p.sort_index(ascending=False)
でしょうね。
【5】
上と同じ箇所で
p2p.sort_index(ascending=False)
ですが、ソートは Indexで行うのではなくValueで行うのでは?と思うのですが違いますかね?
であれば
p2p = p2p.sort_values(ascending=False)
となります。
【6】
途中でいきなり出現するtemp って何でしょう???
更には ptpも不明です。これはp2pの間違いなのでしょうか?
【7】
temp_a95pp = p2p[round(len(ptp)*0.95+0.5):]
の箇所ですが、p2pは降順に(多分)並んでおりますので、上方から95%以降のデータを抜き出すと下位5%のデータだけが残りませんかね???
ここは
temp_a95pp = p2p[round(len(p2p)*0.05+0.5):]
が正解なのではないでしょうか
【8】
あとは全体的にかなり冗長な気がします。
Pandasを使うのであればPandasっぽい記述ってのがありますので是非覚えてください。(【2】で挙げたdiff()など)
例えば最初の peaksを求める箇所もループを使わずに groupby()を使ってかけば

Python

1peaks = wav[wav.groupby((wav*wav.shift(1)<0).cumsum()).apply(lambda d: d.abs().idxmax())]

の一行(わかりやすいように分割しても2・3行)で収まるコード量で記述できます。

投稿2019/03/15 03:13

magichan

総合スコア15898

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

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

H.K2

2019/03/19 14:09

お返事遅くなりました。。すみません。 ありがとうございます。pandasの使い方とかもっと勉強しないとですね…。色々調べてみます。
guest

0

wavはほんとうにSeriesですか? うっかりDataFrameで渡しているというのが一番ありそうなケースです。

そうだった場合、(wav.iloc[i] * wav.iloc[i+1] < 0)で、wav.iloc[i]wav.iloc[i+1]Series型になり、Series同士の掛け算もまたSeriesを返します。ベクトルの要素同士の演算のようなものです。そして比較演算を行うとboolSeriesになます。if文は条件式を単一のboolに変換しようとしますが、boolSeriesはこの変換ができないことになっています(「一意に決まらない仕様」が自然であるため。それを踏まえた上でメッセージを読んでみてください)。

投稿2019/03/14 14:51

hayataka2049

総合スコア30933

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

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

hayataka2049

2019/03/14 14:58

print(i, wav.iloc[i], wav.iloc[i+1], type(wav.iloc[i]), type(wav.iloc[i+1])) しているようですが、 数字、数字、数字、intやfloatなどに類する型、intやfloatなどに類する型 という感じで出てこなければ引数が間違っています。
H.K2

2019/03/14 15:21

すみません。失礼しました・・・。ご指摘の通りdataframeとなってました…。 seriesに変換したら、上記エラーコードはとることができました。ありがとうございます。 ただ、別の問題が発生しており、今悩んでおります。(下記のエラーコードが出ます) 34 # print(peaks) ---> 35 dif_peak = peaks.iloc[0:-1].copy()-peaks.iloc[1:].copy() 36 peak_max = dif_peak.max() AttributeError: 'NoneType' object has no attribute 'iloc' プログラムを追ってみたところ、どうも、peaksが1つしか検出されず、2個以下となっているため、 Noneが代入されてしまっているようです・・・。。 入力波形としては、ただのsin波を数十周期分入れているだけなのですが、forが一通り回っても peakが増えない状況となっています。。。
hayataka2049

2019/03/14 15:35

ロジックの正しさを判断するにはコードをちゃんと読まないといけないのですが、ちょっとしんどいのでざっくり見て思うことを書きます。 まず、 print("***i:{}, i+1:{}***".format(wav.iloc[i], wav.iloc[i+1])) peaks.append(wav.iloc[i:i+1].copy().abs()) print("peaks_len:{}***".format(len(peaks))) あたりのprintは何回表示されますか? 一応ここの回数個分だけ追加されるという意図だと思うので、まずはそれを確認してください。
hayataka2049

2019/03/14 15:37

peaks.append(wav.iloc[i:i+1].copy().abs()) は意図通り動かないと思います。Seriesのappendはin-place処理ではありません。やるとしたらpeaks=のように再代入すればよいのですが、そんな面倒で遅いことをするなら最初からリストを使うといいかと。
hayataka2049

2019/03/14 15:39

正直に言ってしまうと、pandasでごちゃごちゃやるより、numpy配列でデータを受け取り、可変長のコレクションが必要ならlistを使う実装にした方が余計な手間がかからないし速度的にもいいと思います。
H.K2

2019/03/14 16:01

ご回答ありがとうございます。 上記のprintは、回数個数分だけ回っていることを確認しています。 >peaks.append(wav.iloc[i:i+1].copy().abs()) >は意図通り動かないと思います。Seriesのappendはin-place処理ではありません。 >やるとしたらpeaks=のように再代入すればよいのですが、 >そんな面倒で遅いことをするなら最初からリストを使うといいかと。 なるほど。。listか、numpyで実装したほうがよさそうですか…。検討してみます。 ありがとうございます。。。
hayataka2049

2019/03/14 16:05

peaks = peaks.append(wav.iloc[i:i+1].copy().abs()) こんな風に書けば確かにそこは動くようになると思うんですが(他にエラーがあるかどうかは知らない)、なんていうかpandasで書くのが苦行だろうし、慣れていればともかく不慣れだとエラー箇所を増やすだけだろうというのがコードを見ていて想像できるので・・・
H.K2

2019/03/14 16:31

ありがとうございます。確かに、ほかにもエラーを生み出しそうですね…。 とはいえ入力および出力はseriesで変えられなさそうなので(諸般の事情で)、、、 (中で変換して、最期にまたseriesに変換ですかね…。 ともあれ、ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問