কিভাবে সঠিকভাবে একটি বক্ররেখা মসৃণ?


200

ধরে নেওয়া যাক আমাদের কাছে একটি ডেটাসেট রয়েছে যা প্রায় দ্বারা দেওয়া যেতে পারে

import numpy as np
x = np.linspace(0,2*np.pi,100)
y = np.sin(x) + np.random.random(100) * 0.2

অতএব আমাদের ডেটাসেটের 20% প্রকরণ রয়েছে। আমার প্রথম ধারণাটি ছিল স্কিপিটির ইউনিভারিটসপ্লাইন ফাংশনটি ব্যবহার করা, তবে সমস্যাটি হ'ল এটি ছোট আওয়াজটিকে ভাল উপায়ে বিবেচনা করে না। আপনি যদি ফ্রিকোয়েন্সি বিবেচনা করেন, পটভূমিটি সংকেতের চেয়ে অনেক ছোট, সুতরাং কেবলমাত্র কাটফের একটি স্প্লাইনের ধারণা হতে পারে তবে এটি পিছনে পিছনে ফুরিয়ার রূপান্তরকে জড়িত করে, যার ফলে খারাপ আচরণ হতে পারে। আর একটি উপায় চলমান গড় হবে, তবে এটির জন্যও বিলম্বের সঠিক পছন্দ প্রয়োজন।

এই সমস্যা মোকাবেলা করার জন্য কোনও ইঙ্গিত / বই বা লিঙ্কগুলি কীভাবে?

উদাহরণ


1
আপনার সিগন্যাল কি সর্বদা সাইন ওয়েভ হতে পারে, বা আপনি কেবল এটি উদাহরণের জন্য ব্যবহার করছেন?
মার্ক রান্সম

না, আমার বিভিন্ন সংকেত থাকবে, এমনকি এই সহজ
উদাহরণেও

কলম্যান ফিল্টারিং এই ক্ষেত্রে অনুকূল। এবং পাইকালম্যান পাইথন প্যাকেজটি ভাল মানের।
টয়াইন

আমি আরও কিছুটা সময় দিলে এটি পুরো উত্তরে প্রসারিত করব, তবে একটি শক্তিশালী রিগ্রেশন পদ্ধতি যা এখনও উল্লেখ করা হয়নি তা হ'ল জিপি (গাউসিয়ান প্রক্রিয়া) রিগ্রেশন।
Ori5678

উত্তর:


261

আমি একটি সাভিটস্কি-গোলে ফিল্টার পছন্দ করি । এটি আপনার উপাত্তের একটি ছোট উইন্ডোটিকে বহুবর্ষে নিয়ে যেতে কমপক্ষে স্কোয়ার ব্যবহার করে, তারপরে উইন্ডোটির কেন্দ্রের বিন্দুটি অনুমান করার জন্য বহুভুজ ব্যবহার করে। শেষ পর্যন্ত উইন্ডোটি একটি ডেটা পয়েন্ট দ্বারা এগিয়ে স্থানান্তরিত হয় এবং প্রক্রিয়া পুনরাবৃত্তি হয়। প্রতি পয়েন্টের প্রতিবেশীদের তুলনায় সর্বোত্তমভাবে সামঞ্জস্য না করা পর্যন্ত এটি অব্যাহত থাকে। এটি অ পর্যায়ক্রমিক এবং অ-লিনিয়ার উত্সগুলি থেকে শোরগোলের নমুনাগুলি সহ দুর্দান্ত কাজ করে।

এখানে একটি পুঙ্খানুপুঙ্খ কুকবুক উদাহরণ । এটি ব্যবহার করা কতটা সহজ তা সম্পর্কে ধারণা পেতে নীচের আমার কোডটি দেখুন। দ্রষ্টব্য: savitzky_golay()ফাংশনটি সংজ্ঞায়নের জন্য আমি কোডটি ছেড়ে দিয়েছি কারণ আপনি উপরে উল্লিখিত কুকবুক উদাহরণ থেকে আক্ষরিকভাবে এটি অনুলিপি / পেস্ট করতে পারেন।

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0,2*np.pi,100)
y = np.sin(x) + np.random.random(100) * 0.2
yhat = savitzky_golay(y, 51, 3) # window size 51, polynomial order 3

plt.plot(x,y)
plt.plot(x,yhat, color='red')
plt.show()

সর্বোত্তমভাবে একটি গোলমাল সাইনোসয়েড স্মুথ

আপডেট: এটা আমার নজরে এসেছে যে আমি যে কুকবুকের উদাহরণটি দিয়েছি তা সরিয়ে নেওয়া হয়েছে। সৌভাগ্যবসত, Savitzky-Golay ফিল্টার অন্তর্ভুক্ত করা হয়েছে SciPy গ্রন্থাগার মধ্যে দ্বারা সরু আউট হিসাবে, @dodohjk । উপরের কোডটি সায়পাই উত্স ব্যবহার করে মানিয়ে নিতে, টাইপ করুন:

from scipy.signal import savgol_filter
yhat = savgol_filter(y, 51, 3) # window size 51, polynomial order 3

আমি ত্রুটিটি পেয়েছি (সর্বশেষতম কলটি শেষ): ফাইল "এইচপি.পি.", লাইন 79, <মডুল> ysm2 = সেভিটস্কি_গোলে (y_data, 51,3) ফাইল "এইচপি.পি", লাইন 42, সেভিটস্কি_গোলে প্রথম প্রথমগুলিতে = y [0] - np.abs (y [1: অর্ধ_ উইন্ডো + 1] [:: - 1] - y [0])
মার্চ হো


14
সাভিৎস্কি-গোলে ফিল্টারটি প্রবর্তনের জন্য আপনাকে ধন্যবাদ! সুতরাং মূলত এটি একটি নিয়মিত "মুভিং এভারেজ" ফিল্টারটির মতো, তবে কেবল গড় গণনা করার পরিবর্তে প্রতিটি পয়েন্টের জন্য একটি বহুপদী (সাধারণত ২ য় বা চতুর্থ ক্রম) ফিট করা হয় এবং কেবল "মধ্যম" পয়েন্টটি বেছে নেওয়া হয়। যেহেতু ২ য় (বা চতুর্থ) আদেশের তথ্য প্রতিটি পয়েন্টে উদ্বিগ্ন, তাই স্থানীয় ম্যাক্সিমা বা মিনিমাতে "চলমান গড়" পদ্ধতির প্রবর্তিত পক্ষপাতটি সুস্পষ্ট হয়ে যায়। সত্যিই মার্জিত।
np8

2
এর জন্য আপনাকে ধন্যবাদ বলতে চাই, আমি স্মুথড ডেটা পেতে ওয়েভলেট পচনগুলি বের করার চেষ্টা করতে গিয়ে পাগল হয়ে যাচ্ছি, এবং এটি এত সুন্দর।
এল্ডার এম

5
এক্স তথ্য নিয়মিতভাবে ব্যবধানে করা না থাকলে আপনি X এর পাশাপাশি ফিল্টার প্রয়োগ করতে চান করতে পারেন: savgol_filter((x, y), ...)
টিম কুইপার্স

127

চলমান গড় বাক্সের ভিত্তিতে (কনভলভেশন দ্বারা) আমি ব্যবহার করি ডেটা মসৃণ করার দ্রুত এবং নোংরা উপায়:

x = np.linspace(0,2*np.pi,100)
y = np.sin(x) + np.random.random(100) * 0.8

def smooth(y, box_pts):
    box = np.ones(box_pts)/box_pts
    y_smooth = np.convolve(y, box, mode='same')
    return y_smooth

plot(x, y,'o')
plot(x, smooth(y,3), 'r-', lw=2)
plot(x, smooth(y,19), 'g-', lw=2)

এখানে চিত্র বর্ণনা লিখুন


9
এর কয়েকটি দুর্দান্ত সুবিধা রয়েছে: (1) কোনও পর্যায়ক্রমিক নয়, কোনও ফাংশনের জন্য কাজ করে এবং (২) অনুলিপি বা কপির পেস্ট করার জন্য কোনও বৃহত ফাংশন নেই। আপনি খাঁটি নিম্পি দিয়ে এটি এখনই করতে পারেন। এছাড়াও, এটি খুব নোংরা নয় --- এটি উপরে বর্ণিত অন্যান্য কয়েকটি পদ্ধতির একটি সহজ ঘটনা (যেমন স্বল্প তবুও কার্নেলটি একটি তীক্ষ্ণ ব্যবধান এবং স্যাভিটস্কি-গোলেয়ের মতো তবে বহুপদী ডিগ্রি শূন্য)।
জিম পিভারস্কি

2
চলমান গড়ের একমাত্র সমস্যাটি হ'ল এটি ডেটা থেকে পিছিয়ে। আপনি এটিকে সর্বাধিক আপাতদৃষ্টিতে দেখতে পাবেন যেখানে শীর্ষে আরও বেশি বিন্দু রয়েছে এবং নীচে কম রয়েছে, তবে সবুজ বক্ররেখা বর্তমানে গড়ের নীচে রয়েছে কারণ এগুলি অ্যাকাউন্টে নেওয়ার জন্য উইন্ডো ফাংশনটি এগিয়ে যেতে হবে to
নুরেটিন

এবং এটি এনডি অ্যারেতে কাজ করে না, কেবল 1 ডি। scipy.ndimage.filters.convolve1d()ফিল্টারিং করতে আপনাকে এনডি-অ্যারের অক্ষটি নির্দিষ্ট করতে দেয়। তবে আমি মনে করি উভয়ই মুখোশযুক্ত মূল্যবোধের কিছু সমস্যায় ভুগছে।
জেসন

1
@ নুরেটিন আমি মনে করি আপনি যা বর্ণনা করছেন তা প্রান্তিক প্রভাব। সাধারণভাবে, যতক্ষণ না কনভ্যুশনাল কার্নেল তার ব্যাপ্তিটি সিগন্যালের মধ্যে আবরণ করতে সক্ষম হয়, ততক্ষণ আপনি বললে এটি "পিছিয়ে" থাকে না। তবে শেষে, গড় হিসাবে অন্তর্ভুক্ত করার জন্য 6 টিরও বেশি মান নেই, তাই কার্নেলের কেবল "বাম" অংশ ব্যবহার করা হচ্ছে। এজ এফেক্টগুলি প্রতিটি স্মুথিং কার্নেলে উপস্থিত থাকে এবং পৃথকভাবে পরিচালনা করতে হবে।
জন

4
@ নুরেটিন না, আমি এটি পড়ে অন্যদের জন্য পরিষ্কার করার চেষ্টা করছিলাম যে আপনার মন্তব্য "মুভিং এভারেজের একমাত্র সমস্যা হ'ল এটি ডেটার পিছনে পিছিয়ে গেছে" বিভ্রান্তিকর। যে কোনও উইন্ডো-ফিল্টার পদ্ধতি কেবল মুভিং এভারেজ নয়, এই সমস্যায় ভোগে। স্যাভিটস্কি-গোলেও এই সমস্যায় ভুগছেন। সুতরাং আপনার বক্তব্য "আমি যা বর্ণনা করছি তা হ'ল সেভিটস্কি_গোলে অনুমানের দ্বারা সমাধান করা হয়" ঠিক ভুল। হয় স্মুথিং পদ্ধতির প্রান্তগুলি পরিচালনা করার জন্য একটি উপায় প্রয়োজন যা স্মুথিং পদ্ধতির থেকে পৃথক।
জন

79

আপনি যদি পর্যায়ক্রমিক (আপনার উদাহরণের মতো) একটি সংকেতটির "মসৃণ" সংস্করণে আগ্রহী হন, তবে এফএফটি হ'ল সঠিক উপায়। ফুরিয়ার রূপান্তর নিন এবং নিম্ন-অবদানকারী ফ্রিকোয়েন্সিগুলি বিয়োগ করুন:

import numpy as np
import scipy.fftpack

N = 100
x = np.linspace(0,2*np.pi,N)
y = np.sin(x) + np.random.random(N) * 0.2

w = scipy.fftpack.rfft(y)
f = scipy.fftpack.rfftfreq(N, x[1]-x[0])
spectrum = w**2

cutoff_idx = spectrum < (spectrum.max()/5)
w2 = w.copy()
w2[cutoff_idx] = 0

y2 = scipy.fftpack.irfft(w2)

এখানে চিত্র বর্ণনা লিখুন

এমনকি যদি আপনার সিগন্যাল পুরোপুরি পর্যায়ক্রমিক না হয় তবে এটি সাদা গোলমাল বাদ দেওয়ার জন্য দুর্দান্ত কাজ করবে। প্রচুর পরিমাণে ফিল্টার ব্যবহার করার জন্য রয়েছে (উচ্চ-পাস, লো-পাস, ইত্যাদি ...), উপযুক্তটি আপনি যা খুঁজছেন তার উপর নির্ভরশীল।


কোন ভেরিয়েবলের জন্য কোন প্লট? আমি একটি সমাবেশে টেনিস বলের জন্য স্থানাঙ্কগুলি সহজ করার চেষ্টা করছি, অর্থাত্। আমার প্লটটিতে সামান্য প্যারোবোলাসের মতো দেখতে পাওয়া সমস্ত
বাউন্সগুলি বের করুন

44

আপনার ডেটাতে মুভিং এভারেজ ফিট করা আওয়াজকে আরও সহজ করবে, কীভাবে এটি করতে হয় এই উত্তরটি দেখুন ।

আপনি যদি নিজের ডেটা ফিট করার জন্য স্বল্পতা ব্যবহার করতে চান (এটি একটি চলন্ত গড়ের মতো তবে আরও পরিশীলিত) তবে আপনি স্ট্যাটাস মডেলস লাইব্রেরিটি ব্যবহার করে এটি করতে পারেন :

import numpy as np
import pylab as plt
import statsmodels.api as sm

x = np.linspace(0,2*np.pi,100)
y = np.sin(x) + np.random.random(100) * 0.2
lowess = sm.nonparametric.lowess(y, x, frac=0.1)

plt.plot(x, y, '+')
plt.plot(lowess[:, 0], lowess[:, 1])
plt.show()

অবশেষে, আপনি যদি নিজের সিগন্যালের কার্যকরী ফর্মটি জানেন তবে আপনি আপনার ডেটাতে একটি বক্ররেখা ফিট করতে পারেন যা সম্ভবত সবচেয়ে ভাল জিনিস হবে।


যদি কেবল loessপ্রয়োগ করা হত ।
স্ক্রুতারী

18

আরেকটি বিকল্প ব্যবহার করা KernelReg মধ্যে statsmodels :

from statsmodels.nonparametric.kernel_regression import KernelReg
import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0,2*np.pi,100)
y = np.sin(x) + np.random.random(100) * 0.2

# The third parameter specifies the type of the variable x;
# 'c' stands for continuous
kr = KernelReg(y,x,'c')
plt.plot(x, y, '+')
y_pred, y_std = kr.fit(x)

plt.plot(x, y_pred)
plt.show()

7

এটা দেখ! 1D সিগন্যালটি মসৃণ করার সুস্পষ্ট সংজ্ঞা রয়েছে।

http://scipy-cookbook.readthedocs.io/items/SignalSmooth.html

সংক্ষিপ্ত:

import numpy

def smooth(x,window_len=11,window='hanning'):
    """smooth the data using a window with requested size.

    This method is based on the convolution of a scaled window with the signal.
    The signal is prepared by introducing reflected copies of the signal 
    (with the window size) in both ends so that transient parts are minimized
    in the begining and end part of the output signal.

    input:
        x: the input signal 
        window_len: the dimension of the smoothing window; should be an odd integer
        window: the type of window from 'flat', 'hanning', 'hamming', 'bartlett', 'blackman'
            flat window will produce a moving average smoothing.

    output:
        the smoothed signal

    example:

    t=linspace(-2,2,0.1)
    x=sin(t)+randn(len(t))*0.1
    y=smooth(x)

    see also: 

    numpy.hanning, numpy.hamming, numpy.bartlett, numpy.blackman, numpy.convolve
    scipy.signal.lfilter

    TODO: the window parameter could be the window itself if an array instead of a string
    NOTE: length(output) != length(input), to correct this: return y[(window_len/2-1):-(window_len/2)] instead of just y.
    """

    if x.ndim != 1:
        raise ValueError, "smooth only accepts 1 dimension arrays."

    if x.size < window_len:
        raise ValueError, "Input vector needs to be bigger than window size."


    if window_len<3:
        return x


    if not window in ['flat', 'hanning', 'hamming', 'bartlett', 'blackman']:
        raise ValueError, "Window is on of 'flat', 'hanning', 'hamming', 'bartlett', 'blackman'"


    s=numpy.r_[x[window_len-1:0:-1],x,x[-2:-window_len-1:-1]]
    #print(len(s))
    if window == 'flat': #moving average
        w=numpy.ones(window_len,'d')
    else:
        w=eval('numpy.'+window+'(window_len)')

    y=numpy.convolve(w/w.sum(),s,mode='valid')
    return y




from numpy import *
from pylab import *

def smooth_demo():

    t=linspace(-4,4,100)
    x=sin(t)
    xn=x+randn(len(t))*0.1
    y=smooth(x)

    ws=31

    subplot(211)
    plot(ones(ws))

    windows=['flat', 'hanning', 'hamming', 'bartlett', 'blackman']

    hold(True)
    for w in windows[1:]:
        eval('plot('+w+'(ws) )')

    axis([0,30,0,1.1])

    legend(windows)
    title("The smoothing windows")
    subplot(212)
    plot(x)
    plot(xn)
    for w in windows:
        plot(smooth(xn,10,w))
    l=['original signal', 'signal with noise']
    l.extend(windows)

    legend(l)
    title("Smoothing a noisy signal")
    show()


if __name__=='__main__':
    smooth_demo()

3
একটি সমাধানের একটি লিঙ্ক স্বাগত, তবে দয়া করে আপনার উত্তরটি কার্যকর না হওয়া নিশ্চিত করুন: লিঙ্কটির চারপাশে প্রসঙ্গটি যুক্ত করুন যাতে আপনার সহ ব্যবহারকারীদের কিছু ধারণা থাকতে পারে এটি কী এবং কেন সেখানে রয়েছে, তবে আপনি পৃষ্ঠার সর্বাধিক প্রাসঙ্গিক অংশটি উদ্ধৃত করুন লক্ষ্য পৃষ্ঠাটি অনুপলব্ধ ক্ষেত্রে লিঙ্কটি পুনরায় সংযুক্ত করুন। লিঙ্কের চেয়ে সামান্য বেশি উত্তরগুলি মুছতে পারে।
শ্রী

-4

যদি আপনি সময় সিরিজের গ্রাফ প্লট করে থাকেন এবং যদি আপনি গ্রাফগুলি আঁকার জন্য mtplotlib ব্যবহার করেন তবে গ্রাফটি মসৃণ করতে মিডিয়ান পদ্ধতিটি ব্যবহার করুন

smotDeriv = timeseries.rolling(window=20, min_periods=5, center=True).median()

timeseriesআপনার ডেটা সেটটি কোথায় পাস হয়েছে আপনি windowsizeআরও মসৃণতার জন্য পরিবর্তন করতে পারেন ।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.