"Únete" de series de tiempo
-
04-07-2019 - |
Pregunta
Estoy diseñando un marco interno simple para manejar datos de series de tiempo. Dado que LINQ es mi martillo de juguete actual, quiero golpear todo con él.
Quiero implementar métodos en la clase TimeSeries (Select (), Where (), etc.) para poder usar la sintaxis de LINQ para manejar datos de series de tiempo
Algunas cosas son sencillas, por ejemplo, (de x en A, seleccione x + 10), dando una nueva serie de tiempo.
¿Cuál es el mejor diseño de sintaxis para combinar dos o más series temporales? (de a en A de b en B, seleccione a + b) no es muy bueno, ya que expresa un bucle anidado. Tal vez algunos se unen? Esto debería corresponder a unirse en la variable de tiempo implícita. (Lo que tengo en mente corresponde a la función lisp 'zip')
EDITAR: Es necesaria alguna aclaración.
Una serie de tiempo es un tipo de función que depende del tiempo, por ejemplo, cotizaciones de bolsa. Una combinación de series de tiempo podría ser la diferencia entre dos precios de las acciones, en función del tiempo.
Stock1.MyJoin(Stock2, (a,b)=>a-b)
es posible, pero ¿se puede expresar claramente usando alguna sintaxis de LINQ?
Espero implementar los métodos LINQ en la class MyTimeSeries
a mí mismo.
Solución
Si estoy entendiendo la pregunta correctamente, ¿quieres unir varias secuencias en función de su posición dentro de la secuencia?
No hay nada en la clase System.Linq.Enumerable
para hacer esto, ya que tanto los métodos Join
como GroupJoin
se basan en unir teclas Sin embargo, por coincidencia escribí un método de PositionalJoin
solo para este propósito hace unos días, utilizado como en su ejemplo:
sequenceA.PositionalJoin(sequenceB, (a, b) => new { a, b });
La semántica del método que se muestra a continuación es que no requiere que las secuencias tengan la misma longitud, pero sería trivial modificarlas para requerir esto. También comenté dónde debería estar la verificación de argumentos, ya que estaba usando nuestras clases de ayuda interna.
public static IEnumerable<TResult> PositionalJoin<T1, T2, TResult>(
this IEnumerable<T1> source1,
IEnumerable<T2> source2,
Func<T1, T2, int, TResult> selector)
{
// argument checking here
return PositionalJoinIterator(source1, source2, selector);
}
private static IEnumerable<TResult> PositionalJoinIterator<T1, T2, TResult>(
IEnumerable<T1> source1,
IEnumerable<T2> source2,
Func<T1, T2, TResult> selector)
{
using (var enumerator1 = source1.GetEnumerator())
using (var enumerator2 = source2.GetEnumerator())
{
bool gotItem;
do
{
gotItem = false;
T1 item1;
if (enumerator1.MoveNext())
{
item1 = enumerator1.Current;
gotItem = true;
}
else
{
item1 = default(T1);
}
T2 item2;
if (enumerator2.MoveNext())
{
item2 = enumerator2.Current;
gotItem = true;
}
else
{
item2 = default(T2);
}
if (gotItem)
{
yield return selector(item1, item2);
}
}
while (gotItem);
}
}
No estoy seguro de si esto es exactamente lo que estás buscando, pero espero que te ayude.
Otros consejos
Union
suena como el camino correcto, no hay soporte para expresiones de consulta, pero creo que expresa lo que quieres decir.
Es posible que le interese consultar las clases basadas en rango en MiscUtil que puede ser muy bien utilizado para los tiempos. Combinado con un poco de diversión de método de extensión, puede hacer:
foreach (DateTime day in 19.June(1976).To(DateTime.Today).Step(1.Day()))
{
Console.WriteLine("I'm alive!");
}
No estoy sugiriendo que esto deba reemplazar lo que estés haciendo, solo que puedes tomar algunas ideas para hacerlo aún más ordenado. No dude en contribuir de nuevo, también :)
De mi NExtension :
public static IEnumerable<TResult> Zip<T1, T2, TResult>(
this IEnumerable<T1> source1,
IEnumerable<T2> source2,
Func<T1, T2, TResult> combine)
{
if (source1 == null)
throw new ArgumentNullException("source1");
if (source2 == null)
throw new ArgumentNullException("source2");
if (combine == null)
throw new ArgumentNullException("combine");
IEnumerator<T1> data1 = source1.GetEnumerator();
IEnumerator<T2> data2 = source2.GetEnumerator();
while (data1.MoveNext() && data2.MoveNext())
{
yield return combine(data1.Current, data2.Current);
}
}
La sintaxis es:
Stock1.Zip(Stock2, (a,b)=>a-b)
Bjarke, eche un vistazo a NEsper, es una aplicación de procesamiento de eventos complejos de código abierto que, entre otras cosas, realiza consultas de series de tiempo similares a SQL. Puede aprender cómo lo han hecho o quizás incluso aprovechar su código para lograr su objetivo. enlace aquí http://esper.codehaus.org/about/nesper/nesper.html