Pandas Rolling Apply с функцией Scipy FindPeaks: TypeError: могут быть преобразованы только массивы размера 1 - PullRequest
0 голосов
/ 30 ноября 2018

Я ищу помощь с помощью функции scipy Find_Peaks в пределах функциональности pandas.Series.Rolling.apply.Я бросаю TypeError: только массивы размера 1 могут быть преобразованы в скаляры Python в каждой из моих попыток, и я не могу понять 1.) Почему 2.) Как правильно писать

Моя конечная цель: Начиная сПерспективная дата, найти исторические вершины в сигнале.

Функция find_peaks определяет пики внутри сигнала на основе свойств пиков.Я использую полезный пример методологии выдаемости из Mathworks -> методология выдачи

Сама функция принимает одномерный массив и возвращает кортеж (peaks: ndarray, properties: dict).

Желаемый вывод:

x = np.ones((12,))
x[3] = 10
x[7] = 10
x[11] = 10
x = pd.Series(x)
x.rolling(4).apply(lambda x: find_peaks(x,prominence=.2)[0])

0      []
1      []
2      []
3      [3]
4      [3]
5      [3]
6      [3]
7      [3,7]
8      [3,7]
9      [3,7]
10     [3,7]
11     [3,7]
dtype: float64

Попытки / сообщения об ошибках:

x.rolling(4).apply(lambda x: find_peaks(x,prominence=.2)[0])

Ошибка типа: только массивы размера 1 могут быть преобразованы в скаляры Python

from SO36680402 Эта ошибка возникает Ошибка "только массивы длины 1 могут быть преобразованы в скаляры Python" возникает, когда функция ожидает одно значение, но вместо этого передается массив.

Но, SO45254174 , по-видимому, противоречит этой ошибке TypeError в следующем примере:

import numpy as np
import pandas as pd

n = 3
a = np.arange(5)
df = pd.DataFrame(a, columns=['a'])

def keep(window, windows):
    windows.append(window.copy())
    return window[-1]

windows = list()
df['a'].rolling(n).apply(keep, args=(windows,))
df = df.tail(n)
df['a_window'] = windows

, который добавляет массивы / векторы к каждому подвижному блоку, в результате чего получается:

   a         a_window
2  2  [0.0, 1.0, 2.0]
3  3  [1.0, 2.0, 3.0]
4  4  [2.0, 3.0, 4.0]

Первая попытка:

x.rolling(4).apply(lambda x: find_peaks(x,prominence=.2)[0])

Ошибка: Ошибка типа: в скаляры Python могут быть преобразованы только массивы размера 1

Вторая попытка:

def _find_peaks(array,prominence=.2):
   peaks,_ = find_peaks(array,prominence=prominence)
   return np.empty((0,0)) if peaks.shape[0]==0 else peaks

x.rolling(4).apply(_find_peaks)

Ошибка типа: возможны только массивы размера 1быть преобразованным в Python скаляры

Буду очень признателен за любые мысли о том, как писать и почему я выкидываю ошибки!

Ответы [ 2 ]

0 голосов
/ 04 декабря 2018

Спасибо, Никсон, за ваши мысли.Мне на самом деле очень понравился вариант выпуклости, как способ определения моих пиков.Я нашел два решения проблемы, не совсем в том же формате, что и желаемый результат.

Вот что я придумал.Решение 1 появляется быстрее, но решение 2 мне легче читать.

enter image description here

enter image description here

Решение 1 : As_Strided RollingWindow

Функция as_strided от numpy позволяет очень быстро создавать скользящие окна.

import numpy as np
import pandas as pd
from numpy.lib import stride_tricks
from scipy.signal import find_peaks

x = np.ones((12,))
x[3] = 10
x[7] = 10
x[11] = 10

frames_example_1 = pd.DataFrame(stride_tricks.as_strided(x,shape=(len(x)-7+1,7),strides=(8,8)))

peaks = frames_example_1.apply(find_peaks,axis=1,prominence=0.2).apply(lambda x: x[0])

aligned_peaks = np.arange(1,7).reshape(6,1) + \ 
pd.DataFrame(peaks.tolist(),index=np.arange(6,12),columns=['first_peak','second_peak'])
aligned_peaks.index.name = 'perspective date'

Output Date

Решение 2 : Индекс причудливой фантазии Объяснение причудливой индексации Тем не менее усиливая Numpy, как яне мог придумать способ выполнить оригинальный код через панд.

window = 7 
frames, frame_length = len(x) - window +1, window 

indexer = np.tile(np.arange(frame_length),frames).reshape(frames,frame_length) + \
 np.arange(frames).reshape(frames,1)


 peaks = pd.DataFrame(x[indexer],index=np.arange(6,12)).apply(find_peaks,axis=1,prominence=0.2).apply(lambda x: x[0])

Затем выполняется та же процедура, что и раньше:

aligned_peaks = np.arange(1,7).reshape(6,1) + pd.DataFrame(peaks.tolist(),index=np.arange(6,12),columns=['first_peak','second_peak'])
aligned_peaks.index.name = 'perspective date'

enter image description here

0 голосов
/ 30 ноября 2018

Что вы могли бы сделать, это вместо этого работать с массивом и использовать параметр wlen в find_peaks, чтобы установить длину окна вместо использования pd.rolling:

Из документации :

wlen: int или float, необязательно: Длина окна в выборках, которая дополнительно ограничивает оцениваемую областьдля каждого пика до подмножества х.Пик всегда размещается в середине окна, поэтому данная длина округляется до следующего нечетного целого числа.Этот параметр может ускорить вычисления

Так что вместо этого вы можете сделать:

find_peaks(x.values, prominence=0.2, wlen=4)

(array([3, 7], dtype=int64),
 {'left_bases': array([2, 6], dtype=int64),
  'prominences': array([9., 9.]),
  'right_bases': array([4, 8], dtype=int64)})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...