2011-12-07 7 views
10

Más en cross validated Le pregunté a question sobre el análisis de datos por fecha, pero no quería generar picos y valles espurios al agrupar los datos por mes. Por ejemplo, si uno paga una factura el último día de cada mes, pero en una ocasión paga uno con unos días de retraso, entonces el mes reflejará un gasto cero y el mes siguiente reflejará el doble del gasto habitual. Todo basura chatarra.¿Cómo obtengo las pendientes de una interpolación en puntos de tiempo regulares en una gráfica de suma acumulativa?

Uno de los answers a mi pregunta explicaba el concepto de interpolación utilizando suavizado lineal de spline en la suma acumulada para superar el hipo en el binning. Estoy intrigado y quiero implementarlo en R pero no puedo encontrar ningún ejemplo en línea. No solo quiero imprimir tramas. Quiero obtener la pendiente instantánea en cada punto de tiempo (tal vez cada día), pero esa pendiente debe derivarse de una spline que ingrese puntos desde unos días (o tal vez unas pocas semanas o unos meses) antes de unos pocos días después del punto de tiempo. En otras palabras, al final del día quiero obtener algo como un marco de datos en el que una columna es dinero por día o pacientes por semana, pero eso no está sujeto a caprichos como si pagué unos días tarde o si sucedieron 5 días operativos en el mes (a diferencia de los 4 habituales).

Aquí hay una simulación simplificada y un trazado para mostrar a qué me enfrentas.

library(lubridate) 
library(ggplot2) 
library(reshape2) 
dates <- seq(as.Date("2010-02-01"), length=24, by="1 month") - 1 
dates[5] <- dates[5]+3 #we are making one payment date that is 3 days late 
dates#look how the payment date is the last day of every month except for 
#2010-05 where it takes place on 2010-06-03 - naughty boy! 
amounts <- rep(50,each=24)# pay $50 every month 
register <- data.frame(dates,amounts)#this is the starting register or ledger 
ggplot(data=register,aes(dates,amounts))+geom_point()#look carefully and you will see that 2010-05 has no dots in it and 2010-06 has two dots 
register.by.month <- ddply(register,.(y=year(dates),month=month(dates)),summarise,month.tot=sum(amounts))#create a summary of totals by month but it lands up omiting a month in which nothing happened. Further badness is that it creates a new dataframe where one is not needed. Instead I created a new variable that allocates each date into a particular "zone" such as month or 
register$cutmonth <- as.Date(cut(register$dates, breaks = "month"))#until recently I did not know that the cut function can handle dates 
table(register$cutmonth)#see how there are two payments in the month of 2010-06 
#now lets look at what we paid each month. What is the total for each month 
ggplot(register, aes(cutmonth, amounts))+ stat_summary(fun.y = sum, geom = "bar")#that is the truth but it is a useless truth 

When one is late with a payment by a couple of days it appears as if the expense was zero in one month and double in the next. That is spurious

#so lets use cummulated expense over time 
register$cumamount <- cumsum(register$amounts) 
cum <- ggplot(data=register,aes(dates,cumamount))+geom_point() 
cum+stat_smooth() 

cumulative amount over time smooths out variability that changes an item's bin

#That was for everything the same every month, now lets introduce a situation where there is a trend that in the second year the amounts start to go up, 
increase <- c(rep(1,each=12),seq(from=1.01,to=1.9,length.out=12)) 
amounts.up <- round(amounts*increase,digits=2)#this is the monthly amount with a growth of amount in each month of the second year 
register <- cbind(register,amounts.up)#add the variable to the data frarme 
register$cumamount.up <- cumsum(register$amounts.up) #work out th cumulative sum for the new scenario 
ggplot(data=register,aes(x=dates))+ 
    geom_point(aes(y=amounts, colour="amounts",shape="amounts"))+ 
    geom_point(aes(y=amounts.up, colour="amounts.up",shape="amounts.up"))# the plot of amount by date 
#I am now going to plot the cumulative amount over time but now that I have two scenarios it is easier to deal with the data frame in long format (melted) rather than wide format (casted) 
#before I can melt, the reshape2 package unforutnately can't handle date class so will have to turn them int o characters and then back again. 
register[,c("dates","cutmonth")] <- lapply(register[,c("dates","cutmonth")],as.character) 
register.long <- melt.data.frame(register,measure.vars=c("amounts","amounts.up")) 
register.long[,c("dates","cutmonth")] <- lapply(register.long[,c("dates","cutmonth")],as.Date) 
ggplot(register.long, aes(cutmonth,value))+ stat_summary(fun.y = sum, geom = "bar")+facet_grid(. ~ variable) #that is the truth but it is a useless truth, 
cum <- ggplot(data=register,aes(dates,cumamount))+geom_point() 
#that is the truth but it is a useless truth. Furthermore it appears as if 2010-06 is similar to what is going on in 2011-12 
#that is patently absurd. All that happened was that the 2010-05 payment was delayed by 3 days. 

two scenarios but showing the amount of money paid in each month

#so lets use cummulated expense over time  
ggplot(data=register.long,aes(dates,c(cumamount,cumamount.up)))+geom_point() + scale_y_continuous(name='cumulative sum of amounts ($)') 

Here we see the cumulative sum data for the two scenarios

Por lo tanto, para la gráfica simple, la variable interpolate.daily sería de aproximadamente $ 50/30.4 = $ 1.64 por día para cada día del año. Para la segunda parcela, donde el monto que se paga cada mes comienza a subir cada mes en el segundo año, se mostraría una tasa diaria de $ 1.64 por día para cada día en el primer año y para las fechas en el segundo año uno vería las tasas diarias aumentando gradualmente de $ 1.64 por día a aproximadamente $ 3.12 por día.

Muchas gracias por leer todo el proceso hasta el final. ¡Debes haber estado tan intrigado como yo!

+1

Creo que tienes un mal consejo - de manera estadística más común de hacer esto sería usar una estimación de densidad de grano – hadley

+0

@hadley Uno de los que respondieron a mi pregunta [sí habló sobre estimaciones de densidad y kernels] (http://stats.stackexchange.com/a/2737/104). Desafortunadamente no lo entendí mucho y me proporcionó una implementación en Matlab con la que nunca he trabajado. – Farrel

+1

Bueno, es trivial en ggplot2 - simplemente use 'geom =" densidad "' – hadley

Respuesta

1

Aquí hay una forma básica de hacerlo. Por supuesto, hay opciones más complejas y parámetros para modificar, pero este debería ser un buen punto de partida.

dates <- seq(as.Date("2010-02-01"), length=24, by="1 month") - 1 
dates[5] <- dates[5]+3 
amounts <- rep(50,each=24) 
increase <- c(rep(1,each=12),seq(from=1.01,to=1.9,length.out=12)) 
amounts.up <- round(amounts*increase,digits=2) 

df = data.frame(dates=dates, cumamount.up=cumsum(amounts.up)) 

df.spline = splinefun(df$dates, df$cumamount.up) 

newdates = seq(min(df$dates), max(df$dates), by=1) 
money.per.day = df.spline(newdates, deriv=1) 

Si traza, puede ver el comportamiento interesante de las estrías:

plot(newdates, money.per.day, type='l') 

enter image description here

+0

Muchas gracias. De la persona que me contó sobre esta técnica, se me informó que la suma acumulativa aumentaría monótonamente debido a la no negatividad de los valores originales. Dicho esto, creo que la spline debe ser lineal o monótona. Exploraré la función splinefun. Pero me alegro de que me hayas mostrado cómo lanzar un montón de x contra la fórmula derivada. – Farrel

+0

@Farrel Genial Me alegro de que ayude. Definitivamente inteligente para explorar las opciones como dijiste. La cumsum es de hecho monótonamente creciente (prueba 'plot (df); lines (newdates, df.spline (newdates))' para ver), pero la primera derivada que querías (es decir. dinero/día) no lo es. Subirá y bajará a medida que avance de un mes largo a uno corto, etc. –

+0

Voy a jugar con esto mañana. No puedo esperar – Farrel

Cuestiones relacionadas