26 votos

Detectando cambios en series de tiempo (ejemplo en R)

Me gustaría detectar cambios en datos de series temporales, que generalmente tienen la misma forma. Hasta ahora he trabajado con el paquete changepoint para R y las funciones cpt.mean(), cpt.var() y cpt.meanvar(). cpt.mean() con el método PELT funciona bien cuando los datos generalmente se mantienen en un nivel. Sin embargo, también me gustaría detectar cambios durante descensos. Un ejemplo de un cambio, me gustaría detectar, es la sección donde la curva negra cae repentinamente mientras que realmente debería seguir la línea punteada roja ejemplar. He experimentado con la función cpt.var(), sin embargo no obtuve buenos resultados. ¿Tienes alguna recomendación (no necesariamente tiene que usar R)?

Curva de cambio

Aquí están los datos con el cambio (como objeto R):

dat.change <- c(12.013995263488, 11.8460207231808, 11.2845153487846, 11.7884417180764, 
11.6865425802022, 11.4703118125303, 11.4677576899063, 11.0227199625084, 
11.274775836817, 11.03073498338, 10.7771805591742, 10.7383206158923, 
10.5847230134625, 10.2479315651441, 10.4196381241735, 10.467607842288, 
10.3682422713283, 9.7834431752935, 9.76649842404295, 9.78257968297228, 
9.87817694914062, 9.3449034905713, 9.56400153361727, 9.78120084558148, 
9.3445162813738, 9.36767436354887, 9.12070987223648, 9.21909859069157, 
8.85136359917466, 8.8814423003979, 8.61830163359642, 8.44796977628488, 
8.06957847272046, 8.37999165387824, 7.98213210294954, 8.21977468333673, 
7.683960439316, 7.73213584532496, 7.98956476021092, 7.83036046746187, 
7.64496198988985, 4.49693528397253, 6.3459274845112, 5.86993447552116, 
4.58301192892403, 5.63419551523625, 6.67847511602895, 7.2005344054883, 
5.54970477623895, 6.00011922569104, 6.882667104467, 4.74057284230894, 
6.2140437333397, 6.18511450451019, 5.83973575417525, 6.57271194428385, 
5.36261938326723, 5.48948831338016, 4.93968645996861, 4.52598133247377, 
4.56372558828803, 5.74515428123725, 5.45931581984165, 5.58701112949141, 
6.00585679276365, 5.41639695946931, 4.55361875158434, 6.23720558202826, 
6.19433060301002, 5.82989415940829, 5.69321394985076, 5.53585871082265, 
5.42684812413063, 5.80887522466946, 5.56660158483312, 5.7284521523444, 
5.25425775891636, 5.4227645808924, 5.34778016248718, 5.07084809927736, 
5.324066161355, 5.03526881241705, 5.17387528516352, 5.29864121433813, 
5.36894461582415, 5.07436929444317, 4.80619983525015, 4.42858947882894, 
4.33623051506001, 4.33481791951228, 4.38041031792294, 3.90012900415342, 
4.04262777674943, 4.34383842876647, 4.36984816425014, 4.11641092254315, 
3.83985887104645, 3.81813419810962, 3.85174630901311, 3.66434598962311, 
3.4281724860426, 2.99726515704766, 2.96694634792395, 2.94003031547181, 
3.20892607367132, 3.03980832743458, 2.85952185077593, 2.70595278908964, 
2.50931109659839, 2.1912274016859)

0 votos

Tenga en cuenta que si solo está solicitando código R, eso sería inapropiado aquí. Si está solicitando consejos metodológicos generales, eso está bien. Podría incluir algo de código R, pero de nuevo, podría no ser así.

1 votos

Buen comentario, estoy interesado en una solución general, usando R sería conveniente.

20voto

forecaster Puntos 3015

Puedes utilizar la detección de valores atípicos en series temporales para detectar cambios en series temporales. Los procedimientos de Tsay o de Chen y Liu son métodos populares para la detección de valores atípicos en series temporales. Consulta mi pregunta anterior en este sitio.

El paquete tsoutlier de R utiliza el método de Chen y Liu para detectar valores atípicos. SAS/SPSS/Autobox también pueden hacer esto. Observa abajo el código de R para detectar cambios en series temporales.

library("tsoutliers")
dat.ts<- ts(dat.change,frequency=1)
data.ts.outliers <- tso(dat.ts)
data.ts.outliers
plot(data.ts.outliers)

La función tso en el paquete tsoutlier identifica los siguientes valores atípicos. Puedes leer la documentación para averiguar el tipo de valores atípicos.

Outliers:
  type ind time coefhat   tstat
1   TC  42   42 -2.9462 -10.068
2   AO  43   43  1.0733   4.322
3   AO  45   45 -1.2113  -4.849
4   TC  47   47  1.0143   3.387
5   AO  51   51  0.9002   3.433
6   AO  52   52 -1.3455  -5.165
7   AO  56   56  0.9074   3.710
8   LS  62   62  1.1284   3.717
9   AO  67   67 -1.3503  -5.502

El paquete también proporciona gráficos útiles. Observa abajo. El gráfico muestra dónde están los valores atípicos y también qué habría pasado si no hubiera valores atípicos.

enter image description here

También he utilizado el paquete R llamado strucchange para detectar cambios de nivel. Como ejemplo en tus datos

library("strucchange")
breakpoints(dat.ts~1)

El programa identifica correctamente los puntos de quiebre o cambios estructurales.

Optimal 4-segment partition: 

Call:
breakpoints.formula(formula = dat.ts ~ 1)

Breakpoints at observation number:
17 41 87 

Corresponding to breakdates:
17 41 87 

Espero que esto sea de ayuda

1 votos

Gracias, tso funciona bien, sin embargo es un poco lento para conjuntos de datos más grandes. Las posiciones de punto de quiebre de struccchange parecen un poco arbitrarias (excepto la posición 41).

8voto

Owen Fraser-Green Puntos 642

Mi respuesta usando AUTOBOX es bastante similar a la de @forecaster pero con un modelo mucho más simple. Box, Einstein y otros han reflexionado sobre mantener las soluciones simples pero no demasiado simples. El modelo que se desarrolló automáticamente fue introducir descripción de la imagen aquí. El gráfico real y depurado es muy similar introducir descripción de la imagen aquí. Un gráfico de los residuos (que siempre se debe mostrar) está aquí introducir descripción de la imagen aquí junto con el acf obligatorio de los residuos introducir descripción de la imagen aquí. Las estadísticas de los residuos siempre son útiles para hacer comparaciones entre "modelos en competencia" introducir descripción de la imagen aquí. El gráfico de Actual/Ajuste/Previsión está aquí introducir descripción de la imagen aquí

7voto

AusTravel Puntos 6

Abordaría este problema desde las siguientes perspectivas. Estas son solo algunas ideas que se me vienen a la mente - tómalas con precaución. Sin embargo, espero que esto sea útil.

  • Clustering de series temporales. Por ejemplo, utilizando el popular dynamic time warping (DTW) u enfoques alternativos. Consulta mis respuestas relacionadas: sobre DTW para clasificación/clustering y sobre DTW o alternativas para series temporales desiguales. La idea es clusterizar series temporales en categorías "normal" y "anormal" (o similar).

  • Medidas de entropía. Consulta mi respuesta relevante sobre medidas de entropía de series temporales. La idea es determinar la entropía de una serie temporal "normal" y luego compararla con otras series temporales (esta idea supone una desviación de entropía en caso de desviación de la "normalidad").

  • Detección de anomalías. Consulta mi respuesta relevante sobre detección de anomalías (incluye recursos en R). La idea es detectar anomalías directamente mediante diversos métodos (consultar referencias). La caja de herramientas Early Warning Signals (EWS) y el paquete R earlywarnings parecen especialmente prometedores.

1voto

MrMeritology Puntos 1013

Parecería que tu problema se simplificaría mucho si eliminaras la tendencia de tus datos. Parece disminuir de forma lineal. Una vez que elimines la tendencia de los datos, podrías aplicar una amplia variedad de pruebas para la no estacionariedad.

3 votos

Este enfoque fracasará porque claramente hay pendientes diferentes en la historia. A menos que estés incorporando múltiples "tendencias / pendientes", este enfoque no producirá resultados significativos. Las soluciones simples y directas a menudo son simplemente demasiado simples.

1voto

polfosol Puntos 131

Todas son respuestas excelentes, pero aquí hay una simple, como sugirió @MrMeritology, que parece funcionar bien para la serie temporal en cuestión, y probablemente para muchos otros conjuntos de datos "similares".

Aquí hay un fragmento de R que produce los gráficos autoexplicativos a continuación.

outl = rep( NA, length(dat.change))
detr = c( 0, diff( dat.change))

ix = abs(detr) > 2*IQR( detr)
outl[ix] = dat.change[ix]

plot( dat.change, type='l', lwd=2, main="dat.change TS")
points( outl, col=2, pch=18)

plot( detr, col=4, main="detrended TS", type='l', lwd=2 )
acf( detr, main="ACF of detrended TS")

introducir descripción de la imagen aquí introducir descripción de la imagen aquí introducir descripción de la imagen aquí

0 votos

Pueden haber múltiples cambios de tendencia y múltiples cambios de intercepción (desplazamientos de nivel) ... por lo tanto, es necesario encontrar soluciones que realmente diagnostiquen los datos para determinar estos ...

0 votos

Sí, de hecho, he leído tu comentario anterior arriba. Sin embargo, diagnosticar la serie temporal para detectar múltiples tendencias / niveles es un problema en sí mismo. Mi punto aquí es mostrar que el enfoque simple anterior funciona a veces, en particular para los datos dados. Por el contrario, ningún enfoque único funcionará siempre bien. Un enfoque de R.Hyndman (función R tsoutliers) es algo que de otra manera recomendaría.

0 votos

AUTOBOX es el enfoque único que siempre funcionará bien (al menos para los millones de series de tiempo que hemos visto) y hay una versión en R. Si deseas chatear fuera de línea, puedo explicar el proceso, que es completamente comprensible y transparente pero no fácilmente duplicable.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X