Crear una descripción resumida de un horario dada una lista de turnos

Suponiendo que tengo una lista de turnos para un evento (en el formato de fecha / hora de inicio, fecha / hora de finalización), ¿hay algún tipo de algoritmo que pueda usar para crear un resumen generalizado de la progtwigción? Es bastante común que la mayoría de los cambios caigan en algún tipo de patrón de recurrencia común (es decir, los lunes de 9:00 a.m. a 1:00 p.m., los martes de 10:00 a.m. a 3:00 p.m., etc.). Sin embargo, puede (y habrá) excepciones a esta regla (por ejemplo, uno de los turnos cayó en un día festivo y se reprogramó para el día siguiente). Estaría bien excluirlos de mi “resumen”, ya que estoy buscando dar una respuesta más general de cuándo ocurre este evento en general .

Supongo que estoy buscando algún tipo de método estadístico para determinar las ocurrencias del día y la hora y crear una descripción basada en las ocurrencias más frecuentes encontradas en la lista. ¿Hay algún tipo de algoritmo general para algo como esto? ¿Alguien ha creado algo similar?

Idealmente, estoy buscando una solución en C # o VB.NET, pero no me importa portar desde cualquier otro idioma.

¡Gracias por adelantado!

Puede utilizar el análisis de clúster .

La agrupación en clústeres es una forma de segregar un conjunto de datos en componentes similares (subconjuntos). El concepto de “similitud” implica alguna definición de “distancia” entre puntos. Existen muchas fórmulas habituales para la distancia, entre otras, la distancia euclidiana habitual.

Caso practico

Antes de señalarle las peculiaridades del comercio, veamos un caso práctico para su problema, para que pueda involucrarse en los algoritmos y paquetes, o descartarlos por adelantado.

Para simplificar, modelé el problema en Mathematica, porque el análisis de clústeres está incluido en el software y es muy sencillo de configurar.

En primer lugar, generar los datos. El formato es {DÍA, HORA DE INICIO, HORA FINAL}.
Las horas de inicio y finalización tienen una variable aleatoria agregada (+ media hora, cero, media hora) para mostrar la capacidad del algoritmo para hacer frente al “ruido”.

Hay tres días, tres turnos por día y un turno “anómalo” adicional (el último), que comienza a las 7 AM y termina a las 9 AM (¡pobres!).

Hay 150 eventos en cada turno “normal” y solo dos en el excepcional.

Como puede ver, algunos cambios no están muy separados entre sí.

Incluyo el código en Mathematica, en caso de que tenga acceso al software. Estoy tratando de evitar el uso de la syntax funcional, para hacer que el código sea más fácil de leer para “extranjeros”.

Aquí está el código de generación de datos:

Rn[] := 0.5 * RandomInteger[{-1, 1}]; monshft1 = Table[{ 1 , 10 + Rn[] , 15 + Rn[] }, {150}]; // 1 monshft2 = Table[{ 1 , 12 + Rn[] , 17 + Rn[] }, {150}]; // 2 wedshft1 = Table[{ 3 , 10 + Rn[] , 15 + Rn[] }, {150}]; // 3 wedshft2 = Table[{ 3 , 14 + Rn[] , 17 + Rn[] }, {150}]; // 4 frishft1 = Table[{ 5 , 10 + Rn[] , 15 + Rn[] }, {150}]; // 5 frishft2 = Table[{ 5 , 11 + Rn[] , 15 + Rn[] }, {150}]; // 6 monexcp = Table[{ 1 , 7 + Rn[] , 9 + Rn[] }, {2}]; // 7 

Ahora unimos los datos, obteniendo un gran conjunto de datos:

 data = Join[monshft1, monshft2, wedshft1, wedshft2, frishft1, frishft2, monexcp]; 

Vamos a ejecutar un análisis de cluster para los datos:

 clusters = FindClusters[data, 7, Method->{"Agglomerate","Linkage"->"Complete"}] 

“Aglomerado” y “Enlace” -> “Completo” son dos opciones de ajuste fino de los métodos de agrupación implementados en Mathematica. Sólo especifican que estamos tratando de encontrar grupos muy compactos.

Especifiqué para tratar de detectar 7 grupos. Si desconoce el número correcto de turnos, puede probar varios valores razonables y ver los resultados, o dejar que el algoritmo seleccione el valor más apropiado.

Podemos obtener un gráfico con los resultados, cada grupo en un color diferente (no importa el código)

 ListPointPlot3D[ clusters, PlotStyle->{{PointSize[Large], Pink}, {PointSize[Large], Green}, {PointSize[Large], Yellow}, {PointSize[Large], Red}, {PointSize[Large], Black}, {PointSize[Large], Blue}, {PointSize[Large], Purple}, {PointSize[Large], Brown}}, AxesLabel -> {"DAY", "START TIME", "END TIME"}] 

Y el resultado es:

texto alternativo http://sofes.miximages.com/c%23/2hmdlab.png

Donde se pueden ver nuestros siete grupos claramente separados.

Eso resuelve parte de tu problema: identificar los datos. Ahora también quieres poder etiquetarlo.

Entonces, obtendremos cada cluster y tomaremos los medios (redondeados):

 Table[Round[Mean[clusters[[i]]]], {i, 7}] 

El resultado es:

 Day Start End {"1", "10", "15"}, {"1", "12", "17"}, {"3", "10", "15"}, {"3", "14", "17"}, {"5", "10", "15"}, {"5", "11", "15"}, {"1", "7", "9"} 

Y con eso vuelves a conseguir tus siete clases.

Ahora, quizás quieras clasificar los turnos, sin importar el día. Si las mismas personas realizan la misma tarea a la misma hora todos los días, no es útil llamarlo “Lunes de 10 a 15”, porque también ocurre los miércoles y viernes (como en nuestro ejemplo).

Analicemos los datos sin tener en cuenta la primera columna:

 clusters= FindClusters[Take[data, All, -2],Method->{"Agglomerate","Linkage"->"Complete"}]; 

En este caso, no estamos seleccionando el número de clusters para recuperar, dejando la decisión al paquete.

El resultado es

imagen http://sofes.miximages.com/c%23/mise9.png

Se puede ver que se han identificado cinco grupos.

Intentemos “etiquetarlos” como antes:

 Grid[Table[Round[Mean[clusters[[i]]]], {i, 5}]] 

El resultado es:

  START END {"10", "15"}, {"12", "17"}, {"14", "17"}, {"11", "15"}, { "7", "9"} 

Que es exactamente lo que “sospechamos”: hay eventos repetidos cada día a la misma hora que podrían agruparse.

Edición: turnos de noche y normalización

Si tiene (o planea tener) turnos que comienzan un día y terminan en lo siguiente, es mejor modelar

 {Start-Day Start-Hour Length} // Correct! 

que

 {Start-Day Start-Hour End-Day End-Hour} // Incorrect! 

Esto se debe a que, como con cualquier método estadístico, la correlación entre las variables debe hacerse explícita, o el método falla estrepitosamente. El principio podría ejecutar algo como “mantener los datos de su candidato normalizados”. Ambos conceptos son casi iguales (los atributos deben ser independientes).

— Editar fin —

A estas alturas, creo que entiendes bastante bien qué tipo de cosas puedes hacer con este tipo de análisis.

Algunas referencias

  1. Por supuesto, Wikipedia , sus “referencias” y “lecturas adicionales” son una buena guía.
  2. Un buen video aquí que muestra las capacidades de Statsoft, pero puede obtener muchas ideas sobre otras cosas que puede hacer con el algoritmo.
  3. Aquí hay una explicación básica de los algoritmos involucrados.
  4. Aquí puede encontrar la impresionante funcionalidad de R para Cluster Analysis ( R es una opción MUY buena)
  5. Finalmente, aquí puede encontrar una larga lista de software gratuito y comercial para estadísticas en general, incluido el agrupamiento.

HTH!

No creo que exista ningún algoritmo ya hecho, por lo que, lamentablemente, usted debe crear algo. Debido a que el problema no está realmente bien definido (desde la perspectiva matemática), se requerirán pruebas en algunos datos “reales” que serían razonablemente representativos, y un poco de ajustes.

Comenzaría dividiendo sus turnos en días de la semana (porque si entiendo correctamente, está buscando una vista semanal), por lo que para cada día de la semana tenemos turnos para ese día. Luego, por cada día, agruparía los cambios que ocurren al mismo tiempo (o “aproximadamente” al mismo tiempo; aquí es necesario elaborar una heurística, es decir, tanto las horas de inicio como de finalización no se desvían del promedio en el grupo por más de 15 minutos o 30 minutos). Ahora necesitamos otra heurística para decidir si este grupo es relevante, es decir, si un turno de 1 pm a 3 pm en un lunes ocurrió solo una vez, es probable que no sea relevante, pero si ocurrió en al menos el 70% de los lunes cubiertos por los datos, entonces es pertinente. Y ahora sus grupos relevantes para cada día de la semana formarán el horario que está buscando.

¿Podríamos ver un conjunto de datos de ejemplo? Si se trata de datos realmente “limpios”, simplemente puede encontrar el modo de las horas de inicio y finalización.

Una opción sería etiquetar todos los tiempos de inicio como +1 y los tiempos de finalización como -1, luego crear una tabla de tres columnas de tiempos (tanto inicio como final), etiqueta (+1 o -1) y número de personas en ese número tiempo (comienza con cero y agrega o resta personal usando la etiqueta) y ordena todo en orden de tiempo.

Esta serie de tiempo ahora es un descriptor resumido de sus niveles de personal y las tags también son una serie también. Ahora puede aplicar estadísticas de series de tiempo a ambos para buscar patrones diarios, semanales o mensuales.