2011-10-31 28 views
6

Ho bisogno di confrontare alcuni dati teorici con dati reali in python. I dati teorici derivano dalla risoluzione di un'equazione. Per migliorare il confronto vorrei rimuovere i punti dati che sono lontani dalla curva teorica. Voglio dire, voglio rimuovere i punti sotto e sopra le linee tratteggiate in rosso nella figura (fatti con matplotlib). Data points and theoretical curvesRimuovere i punti dati sotto una curva con python

Entrambe le curve teoriche e i punti di dati sono matrici di diversa lunghezza.

posso cercare di eliminare i punti in modo approssimativamente occhi, per esempio: il primo punto superiore può essere rilevato utilizzando:

data2[(data2.redshift<0.4)&data2.dmodulus>1] 
rec.array([('1997o', 0.374, 1.0203223485103787, 0.44354759972859786)], dtype=[('SN_name', '|S10'), ('redshift', '<f8'), ('dmodulus', '<f8'), ('dmodulus_error', '<f8')])  

Ma vorrei utilizzare un meno modo approssimativamente occhi.

Quindi, qualcuno può aiutarmi a trovare un modo semplice per rimuovere i punti problematici?

Grazie!

+18

Solo da un punto di vista scientifico, non rimuoverei i punti a meno che non vi sia una ragione ESTREMAMENTE valida che pensi che siano sbagliati. Hai abbastanza dati che i punti periferici non avranno alcun effetto sull'adattamento, quindi rimuoverli serve solo a far apparire il grafico bello, senza servire a scopi scientifici. – NickLH

+0

Hai ragione, ma mi è stato detto di farlo. –

risposta

1

Basta guardare la differenza tra la curva rossa e i punti, se è più grande della differenza tra la curva rossa e la curva rossa tratteggiata rimuoverla.

diff=np.abs(points-red_curve) 
index= (diff>(dashed_curve-redcurve)) 
filtered=points[index] 

Ma si prega di prendere il commento da NickLH serio. I tuoi dati sembrano abbastanza buoni senza alcun filtro, i tuoi "outlieres" hanno tutti un errore molto grande e non influenzano molto la misura.

+1

È un buon ide, ma trovo difficile calcolare la differenza tra la curva rossa e i punti, poiché entrambi gli array hanno una lunghezza diversa. Si potrebbe usare l'interpolazione per creare un array di curve rosse con la lunghezza dell'array dei punti. –

+0

Le curve_curve sono probabilmente fatte con una funzione, ma solo i valori x rilavoranti in essa. – tillsten

4

Questo potrebbe essere eccessivo e si basa sul tuo commento

Entrambe le curve teoriche ed i punti dati sono array di diversa lunghezza.

vorrei fare quanto segue:

  1. troncare i set di dati in modo che i suoi valori x si trovano all'interno del valori massimi e minimi del set teorico.
  2. Interpolare la curva teorica utilizzando scipy.interpolate.interp1d e i valori x dei dati troncati di cui sopra. Il motivo del passaggio (1) è quello di soddisfare i vincoli di interp1d.
  3. Utilizzare numpy.where per trovare i valori di dati y che sono fuori dal campo di valori teorici accettabili.
  4. NON rimuovere questi valori, come suggerito nei commenti e altre risposte. Se vuoi chiarezza, indicali tracciando il colore di un "inliner" e i "valori anomali" di un altro colore.

Ecco uno script che è vicino a quello che stai cercando, penso. E speriamo che vi aiuterà a realizzare ciò che si vuole:

import numpy as np 
import scipy.interpolate as interpolate 
import matplotlib.pyplot as plt 

# make up data 
def makeUpData(): 
    '''Make many more data points (x,y,yerr) than theory (x,y), 
    with theory yerr corresponding to a constant "sigma" in y, 
    about x,y value''' 
    NX= 150 
    dataX = (np.random.rand(NX)*1.1)**2 
    dataY = (1.5*dataX+np.random.rand(NX)**2)*dataX 
    dataErr = np.random.rand(NX)*dataX*1.3 
    theoryX = np.arange(0,1,0.1) 
    theoryY = theoryX*theoryX*1.5 
    theoryErr = 0.5 
    return dataX,dataY,dataErr,theoryX,theoryY,theoryErr 

def makeSameXrange(theoryX,dataX,dataY): 
    ''' 
    Truncate the dataX and dataY ranges so that dataX min and max are with in 
    the max and min of theoryX. 
    ''' 
    minT,maxT = theoryX.min(),theoryX.max() 
    goodIdxMax = np.where(dataX<maxT) 
    goodIdxMin = np.where(dataX[goodIdxMax]>minT) 
    return (dataX[goodIdxMax])[goodIdxMin],(dataY[goodIdxMax])[goodIdxMin] 

# take 'theory' and get values at every 'data' x point 
def theoryYatDataX(theoryX,theoryY,dataX): 
    '''For every dataX point, find interpolated thoeryY value. theoryx needed 
    for interpolation.''' 
    f = interpolate.interp1d(theoryX,theoryY) 
    return f(dataX[np.where(dataX<np.max(theoryX))]) 

# collect valid points 
def findInlierSet(dataX,dataY,interpTheoryY,thoeryErr): 
    '''Find where theoryY-theoryErr < dataY theoryY+theoryErr and return 
    valid indicies.''' 
    withinUpper = np.where(dataY<(interpTheoryY+theoryErr)) 
    withinLower = np.where(dataY[withinUpper] 
        >(interpTheoryY[withinUpper]-theoryErr)) 
    return (dataX[withinUpper])[withinLower],(dataY[withinUpper])[withinLower] 

def findOutlierSet(dataX,dataY,interpTheoryY,thoeryErr): 
    '''Find where theoryY-theoryErr < dataY theoryY+theoryErr and return 
    valid indicies.''' 
    withinUpper = np.where(dataY>(interpTheoryY+theoryErr)) 
    withinLower = np.where(dataY<(interpTheoryY-theoryErr)) 
    return (dataX[withinUpper],dataY[withinUpper], 
      dataX[withinLower],dataY[withinLower]) 
if __name__ == "__main__": 

    dataX,dataY,dataErr,theoryX,theoryY,theoryErr = makeUpData() 

    TruncDataX,TruncDataY = makeSameXrange(theoryX,dataX,dataY) 

    interpTheoryY = theoryYatDataX(theoryX,theoryY,TruncDataX) 

    inDataX,inDataY = findInlierSet(TruncDataX,TruncDataY,interpTheoryY, 
            theoryErr) 

    outUpX,outUpY,outDownX,outDownY = findOutlierSet(TruncDataX, 
                TruncDataY, 
                interpTheoryY, 
                theoryErr) 
    #print inlierIndex 
    fig = plt.figure() 
    ax = fig.add_subplot(211) 

    ax.errorbar(dataX,dataY,dataErr,fmt='.',color='k') 
    ax.plot(theoryX,theoryY,'r-') 
    ax.plot(theoryX,theoryY+theoryErr,'r--') 
    ax.plot(theoryX,theoryY-theoryErr,'r--') 
    ax.set_xlim(0,1.4) 
    ax.set_ylim(-.5,3) 
    ax = fig.add_subplot(212) 

    ax.plot(inDataX,inDataY,'ko') 
    ax.plot(outUpX,outUpY,'bo') 
    ax.plot(outDownX,outDownY,'ro') 
    ax.plot(theoryX,theoryY,'r-') 
    ax.plot(theoryX,theoryY+theoryErr,'r--') 
    ax.plot(theoryX,theoryY-theoryErr,'r--') 
    ax.set_xlim(0,1.4) 
    ax.set_ylim(-.5,3) 
    fig.savefig('findInliers.png') 

Questa cifra è il risultato: enter image description here

0

O si potrebbe utilizzare il numpy.where() per identificare quali coppie xy soddisfano il criterio di plotting, o forse elencare per fare più o meno la stessa cosaEsempio:

x_list = [ 1, 2, 3, 4, 5, 6 ] 
y_list = ['f','o','o','b','a','r'] 

result = [y_list[i] for i, x in enumerate(x_list) if 2 <= x < 5] 

print result 

sono sicuro che si potrebbe modificare le condizioni affinche '2' e '5' nell'esempio di cui sopra sono le funzioni delle vostre curve

4

Alla fine ho utilizzare alcune delle Yann codice:

def theoryYatDataX(theoryX,theoryY,dataX): 
'''For every dataX point, find interpolated theoryY value. theoryx needed 
for interpolation.''' 
f = interpolate.interp1d(theoryX,theoryY) 
return f(dataX[np.where(dataX<np.max(theoryX))]) 

def findOutlierSet(data,interpTheoryY,theoryErr): 
    '''Find where theoryY-theoryErr < dataY theoryY+theoryErr and return 
    valid indicies.''' 

    up = np.where(data.dmodulus > (interpTheoryY+theoryErr)) 
    low = np.where(data.dmodulus < (interpTheoryY-theoryErr)) 
    # join all the index together in a flat array 
    out = np.hstack([up,low]).ravel() 

    index = np.array(np.ones(len(data),dtype=bool)) 
    index[out]=False 

    datain = data[index] 
    dataout = data[out] 

    return datain, dataout 

def selectdata(data,theoryX,theoryY): 
    """ 
    Data selection: z<1 and +-0.5 LFLRW separation 
    """ 
    # Select data with redshift z<1 
    data1 = data[data.redshift < 1] 

    # From modulus to light distance: 
    data1.dmodulus, data1.dmodulus_error = modulus2distance(data1.dmodulus,data1.dmodulus_error) 

    # redshift data order 
    data1.sort(order='redshift') 

    # Outliers: distance to LFLRW curve bigger than +-0.5 
    theoryErr = 0.5 
    # Theory curve Interpolation to get the same points as data 
    interpy = theoryYatDataX(theoryX,theoryY,data1.redshift) 

    datain, dataout = findOutlierSet(data1,interpy,theoryErr) 
    return datain, dataout 

Utilizzando queste funzioni posso finalmente ottenere:

Data selection

Grazie a tutti per il vostro aiuto.

+2

+1 Per mostrarci la tua soluzione e anche per mantenere i punti periferici sul grafico. – NickLH

Problemi correlati