Уменьшить массив 1D numpy
У меня есть массив 1-d numpy, который я хотел бы уменьшить. Любой из следующих методов допустим, если растровый диск с понижающей дискретизацией не идеально подходит для данных:
- перекрывать интервалы с интервалом
- конвертировать любое количество значений в конце в отдельное значение с пониженной дискретизацией
- интерполировать в соответствии с растром
в принципе, если у меня
1 2 6 2 1
и я понижаю дискретизацию в 3 раза, все из них выглядят нормально:
3 3
3 1.5
или что бы там ни была интерполяция.
Я просто ищу самый быстрый/простой способ сделать это.
Я нашел scipy.signal.decimate
, но похоже, что он уничтожает значения (выводит их по мере необходимости и оставляет только один в X). scipy.signal.resample
, кажется, имеет правильное имя, но я не понимаю, куда они идут со всей фразой в описании. Мой сигнал не является особенно периодическим.
Не могли бы вы дать мне руку здесь? Это кажется очень простой задачей, но все эти функции довольно сложны...
Ответы
Ответ 1
В простом случае, когда размер вашего массива делится на коэффициент понижающего дискретизации (R
), вы можете reshape
ваш массив и принять среднее значение по новой оси:
import numpy as np
a = np.array([1.,2,6,2,1,7])
R = 3
a.reshape(-1, R)
=> array([[ 1., 2., 6.],
[ 2., 1., 7.]])
a.reshape(-1, R).mean(axis=1)
=> array([ 3. , 3.33333333])
В общем случае вы можете поместить свой массив с помощью NaN
в размер, делящийся на R
, и взять среднее значение с помощью scipy.nanmean
.
import math, scipy
b = np.append(a, [ 4 ])
b.shape
=> (7,)
pad_size = math.ceil(float(b.size)/R)*R - b.size
b_padded = np.append(b, np.zeros(pad_size)*np.NaN)
b_padded.shape
=> (9,)
scipy.nanmean(b_padded.reshape(-1,R), axis=1)
=> array([ 3. , 3.33333333, 4.])
Ответ 2
Если размер массива не делится на коэффициент понижающего дискретизации (R), преобразование (разбиение) массива может быть выполнено с использованием np.linspace, за которым следует среднее каждого подмассива.
input_arr = np.arange(531)
R = 150 (number of split)
split_arr = np.linspace(0, len(input_arr), num=R+1, dtype=int)
dwnsmpl_subarr = np.split(input_arr, split_arr[1:])
dwnsmpl_arr = np.array( list( np.mean(item) for item in dwnsmpl_subarr[:-1] ) )
Ответ 3
Вот несколько подходов, использующих линейную интерполяцию или метод Фурье. Эти методы поддерживают как повышающую, так и понижающую дискретизацию.
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import resample
from scipy.interpolate import interp1d
def ResampleLinear1D(original, targetLen):
original = np.array(original, dtype=np.float)
index_arr = np.linspace(0, len(original)-1, num=targetLen, dtype=np.float)
index_floor = np.array(index_arr, dtype=np.int) #Round down
index_ceil = index_floor + 1
index_rem = index_arr - index_floor #Remain
val1 = original[index_floor]
val2 = original[index_ceil % len(original)]
interp = val1 * (1.0-index_rem) + val2 * index_rem
assert(len(interp) == targetLen)
return interp
if __name__=="__main__":
original = np.sin(np.arange(256)/10.0)
targetLen = 100
# Method 1: Use scipy interp1d (linear interpolation)
# This is the simplest conceptually as it just uses linear interpolation. Scipy
# also offers a range of other interpolation methods.
f = interp1d(np.arange(256), original, 'linear')
plt.plot(np.apply_along_axis(f, 0, np.linspace(0, 255, num=targetLen)))
# Method 2: Use numpy to do linear interpolation
# If you don't have scipy, you can do it in numpy with the above function
plt.plot(ResampleLinear1D(original, targetLen))
# Method 3: Use scipy resample
# Converts the signal to frequency space (Fourier method), then back. This
# works efficiently on periodic functions but poorly on non-periodic functions.
plt.plot(resample(original, targetLen))
plt.show()