Как получить наклоны интерполяции в обычные моменты времени на графике кумулятивной суммы?

На перекрестной проверке я задал вопрос об анализе данных по дате, но не хотел генерировать ложные всплески и провалы путем биннинга. данные по месяцам. Например, если кто-то оплачивает счет в последний день каждого месяца, но в одном случае он платит с опозданием на несколько дней, тогда один месяц будет отражать нулевые расходы, а следующий месяц будет отражать двойные обычные расходы. Весь ложный хлам.

В одном из ответов на мой вопрос объясняется концепция интерполяции с использованием линейного сплайн-сглаживания кумулятивной суммы для преодоления икоты в биннинг. Я заинтригован этим и хочу реализовать его в R, но не могу найти примеров в Интернете. Я не просто хочу печатать сюжеты. Я хочу получить мгновенный наклон в каждый момент времени (может быть, каждый день), но этот наклон должен быть получен из сплайна, который вводит точки за несколько дней (или, возможно, за несколько недель или несколько месяцев) до нескольких дней. после момента времени. Другими словами, в конце дня я хочу получить что-то вроде фрейма данных, в котором один столбец — это деньги в день или количество пациентов в неделю, но это не зависит от капризов, таких как с опозданием на несколько дней или если в месяце было 5 оперативных дней (в отличие от обычных 4).

Вот несколько упрощенных симуляций и графиков, чтобы показать, с чем я столкнулся.

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

Когда кто-то опаздывает с платежом на пару дней, кажется, что расходы были равны нулю за один месяц и удвоились за месяц.  следующий. Это ложно

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

накопленная сумма с течением времени сглаживает изменчивость, которая изменяет корзину предмета

#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.

два сценария, но с указанием суммы денег, выплачиваемой в каждом месяце

#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 ($)')

Здесь мы видим совокупные данные суммы для двух сценариев

Таким образом, для простого графика переменная interpolate.daily будет составлять около 50/30,4 = 1,64 доллара в день на каждый день года. Для второго графика, где сумма, выплачиваемая каждый месяц, начинает расти каждый месяц во втором году, будет показана дневная ставка в размере 1,64 доллара в день за каждый день в первый год, а для дат во втором году можно будет увидеть дневные ставки. постепенно увеличивается с 1,64 доллара в день примерно до 3,12 доллара в день.

Большое спасибо, что дочитали это до конца. Вы, должно быть, были так же заинтригованы, как и я!


person Farrel    schedule 07.12.2011    source источник
comment
Я думаю, вы получили плохой совет - более распространенный статистический способ сделать это - использовать оценку плотности ядра.   -  person hadley    schedule 08.12.2011
comment
@hadley Один из респондентов на мой вопрос говорил об оценках плотности и ядрах. Увы, я мало что понял, и он предоставил реализацию в матлабе, с которой я никогда не работал.   -  person Farrel    schedule 09.12.2011
comment
Ну, это тривиально в ggplot2 - просто используйте geom = "density"   -  person hadley    schedule 09.12.2011
comment
@hadley Значит ли это, что можно сделать что-то вроде этого cum <- ggplot(data=register,aes(dates,cumamount))+geom_point(), а затем cum+geom_density(). Но, увы, я получаю Error in data.frame(list(x = c(14640, 14641.3679060665, 14642.7358121331, : arguments imply differing number of rows: 512, 1, 91 В любом случае, даже если я использую geom_density, как мне получить таблицу данных с новыми значениями за месяц или за день, которые не испорчены биннингом?   -  person Farrel    schedule 10.12.2011


Ответы (1)


Вот один из основных способов сделать это. Конечно, есть более сложные параметры и параметры для настройки, но это должно быть хорошей отправной точкой.

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)

Если вы построите его, то увидите интересное поведение сплайнов:

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

введите здесь описание изображения

person John Colby    schedule 07.12.2011
comment
Большое тебе спасибо. От человека, который рассказал мне об этой методике, мне сообщили, что накопительная сумма будет монотонно возрастать из-за неотрицательности исходных значений. Тем не менее, я думаю, что сплайн должен быть линейным или монотонным. Я исследую функцию splinefun. Но я рад, что вы показали мне, как поставить кучу крестиков против производной формулы. - person Farrel; 07.12.2011
comment
@Farrel Отлично, я рад, что это помогает. Определенно разумно изучить варианты, как вы сказали. Полная сумма действительно монотонно увеличивается (попробуйте plot(df); lines(newdates, df.spline(newdates)), чтобы увидеть), но первая производная, которую вы хотели (т.е. деньги/день), не увеличивается. Он будет повышаться и понижаться по мере перехода от длинного месяца к короткому и т. д. - person John Colby; 07.12.2011
comment
Я собираюсь поиграть с этим завтра. Не могу дождаться - person Farrel; 08.12.2011
comment
Я не очень разбираюсь в сплайнах и думаю, что deriv=1 — это производная исчисления, и я также мало разбираюсь в исчислении. Достаточно сказать, что приведенный выше график неверен, потому что слишком много колебаний. Да, он будет расти и падать, но очень незначительно, особенно в первый год. Итак, я попытался принудительно запустить splinefun method="mono", но каждый раз, когда я это делаю, я получаю следующий сценарий > money.per.day <- register.spline(newdates, deriv=1) Error in as.Date.numeric(value) : 'origin' must be supplied - person Farrel; 09.12.2011
comment
также к вашему сведению, у профессора Хайндмана есть функция монотонного сплайна здесь: robjhyndman.com/software/monotonic-splines - person tim riffe; 25.08.2012