2015-11-24 2 views
1

ProblèmeInterpolate avec spline et garder exactement les valeurs nouée

Je joue autour de cannelures et d'essayer de se connecter à mi mois interpoler toute l'année à partir 15 Janvier avec; Cependant, je veux m'assurer que les mois intermédiaires sont correctement définis pour toute l'année. C'est-à-dire, chaque mois, je veux que le point médian (15ème) soit le même à partir des données mensuelles d'origine. Actuellement, le code que j'ai ne le fait pas et certaines des valeurs sont assez différentes du code original. Je voudrais m'assurer, si possible, que ces valeurs exactes correspondent aux données au milieu (15e) de chaque mois.

Y a-t-il un moyen de s'assurer que ces points des données d'origine sont correctement définis dans les données interpolées afin qu'ils soient à la position exacte du point médian (15ème) de chaque mois?

Exemple:

# Monthly data 
df <- data.frame(x <- seq(1,12), 
       y <- c(45, 54, 50 ,63, 70, 75, 80, 88, 76, 81, 63, 54)) 

# Interpolate with spline to daily data starting with 15th of January (351 days) 
values <- spline(df$x, df$y, n = 351)$y 

# Check values 
# Original values 
df$y 

# New values at 15th of each month 
values[c(1,31, 60,91,121,152,182,213,244,274,305,335)] 

sortie (Une bonne ronde, mais la plupart sont éteints):

> df$y 
[1] 45 54 50 63 70 75 80 88 76 81 63 54 

> values[c(1,31, 60,91,121,152,182,213,244,274,305,335)] 
[1] 45.00000 54.21321 49.65891 60.61385 68.91151 73.89644 77.62606 87.33305 79.66860 79.27115 73.10543 54.71480 

sortie souhaitée:

> df$y 
    [1] 45 54 50 63 70 75 80 88 76 81 63 54 

    > values[c(1,31, 60,91,121,152,182,213,244,274,305,335)] 
    [1] 45 54 50 63 70 75 80 88 76 81 63 54 

Image:

rouge: points de mois originaux

Ligne noire: Points d'interpolation spline

Répondre

2

Si vous essayez d'aligner les choses avec les jours civils, vous pourriez laisser R faire le travail de garder la trace des dates . Cette approche prendrait également soin des années bissextiles. A la fin, vous pouvez alors l'index par jour à partir de janvier 15. L'utilisation de cette année à titre d'exemple, le code pourrait ressembler à:

df <- data.frame(x=seq.Date(as.Date("2015-01-15"), by="month", length.out=12), 
        y = c(45, 54, 50 ,63, 70, 75, 80, 88, 76, 81, 63, 54)) 
    values_by_date <- splinefun(df$x, df$y) 
# 
# To get a value at every day between Jan 15 and Dec 15 
# 
values <- values_by_date(seq.Date(df$x[1], tail(df$x,1), by="day")) 
# 
# Check dates at mid month 
# Note that second index should be 32, not 31 
# 
values[c(1,32, 60,91,121,152,182,213,244,274,305,335)] 

[1] 45 54 50 63 70 75 80 88 76 81 63 54 
+0

Si je comprends bien votre question, vous pourriez constater que 'df' peut contenir un ensemble de dates (stockées sous forme de R' Date' objets) et les valeurs pour les jours à être utilisé comme base pour interpolation y compris pour plusieurs années. Vous pouvez ensuite générer un vecteur de valeurs pour tous les jours dans l'intervalle comme indiqué dans le code ou vous pouvez utiliser la fonction 'values_by_date' directement pour obtenir des valeurs pour n'importe quel ensemble de dates. – WaltS

+0

Désolé, j'ai mal compris comment vous présentez la réponse. Cela fonctionne parfait! Merci – Vedda

1

Peut-être qu'il est plus compliqué que la réponse fournie par Walts, mais il fonctionne:

# Input data: 
df <- data.frame(x <- seq(1,12), 
       y <- c(45, 54, 50 ,63, 70, 75, 80, 88, 76, 81, 63, 54)) 
# I use this dataframe to get the right position for the ticks 
# The "offset_days" column is left 'empty' at start: 
days_of_month <- data.frame(months=c('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'), 
          days = c(31,28,31,30,31,30,31,31,30,31,30,31), 
          offset_days = 0) 
# Offset: The day of month you want your ticks to be placed (should be between 1 and 28): 
offset <- 15 

# Fill the "offset_days" column with the appropriate day 
for(i in 1:nrow(days_of_month)) { 
    if(i == 1) 
    days_of_month$offset_days[i] <- offset 
    else 
    days_of_month$offset_days[i] <- days_of_month$offset_days[i-1] + days_of_month$days[i-1] 
} 

# Calculate the spline with the offset days as x value: 
sp <- spline(days_of_month$offset_days, df$y, 351) 

plot(sp$x, sp$y, type='l', xlim=c(0,365), xaxt='n') 
lines(days_of_month$offset_days, df$y, type='o', col='red') 
axis(side=1, at=cumsum(days_of_month$days), lab=rep('',12)) 
axis(side=1, at=days_of_month$offset_days, lab=days_of_month$months, tck=0) 

la sortie:

Output

la ligne rouge indique vos données d'origine, et la ligne noire est les données lissées.

Hope this helps

+0

Merci pour la réponse. En quoi est-ce différent de @WaltS? Pourquoi pensez-vous que cette approche est meilleure? – Vedda

+0

@Amstell C'est un peu plus compliqué, car il faut que vous alimentiez manuellement la longueur de chaque mois ... Cela évite de traiter les valeurs de date (qui me confondent souvent), et définissons le décalage (vous pouvez placer les données n'importe quel jour du mois en changeant la variable 'offset') – Barranka

+0

Ok merci.Je vais m'y accrocher si je dois utiliser une spline en dehors des dates. Réponse géniale! – Vedda