2010-06-24 9 views
6

que tienen una lista de fechas y valores en el formato:¿Cómo restar elementos específicos en una lista usando programación funcional en Mathematica?

{{{dateInfo1},value1},{{dateInfo2},value2},...,{{dateInfoN},valueN}} 

Con algunas fechas y los valores reales:

{{{1971, 1, 31, 0, 0, 0.}, 1.0118}, {{1971, 2, 28, 0, 0, 0}, 1.0075}, 
..., {{2010, 5, 31, 0, 0, 0.}, 1.0403}} 

Para los curiosos, que es una lista de los Estados Unidos frente a los valores de CAD $ tirado desde el FRED database.

me gustaría simplemente restar valor1 de valor 2, y a continuación, crear una nueva lista con los datos en la forma de:

{{{dateInfo1},0},{{dateInfo2},change1},...,{{dateInfoN},changeN-1}} 

(con change1 ser valor2-valor1)

Sé que debe haber una manera relativamente fácil de hacer esto usando programación funcional, en oposición a Do o While con variables de índice y conteo y todas esas tonterías. El método que estoy tratando de lograr tiene que ser relativamente robusto, porque automáticamente estoy recogiendo datasets de fuentes que tienen el mismo formato, pero diferentes intervalos de tiempo. Volver a trazar es mucho más fácil si no tengo que especificar los intervalos de fecha de ListPlot (lo que sucedería si eliminase dateInfo de la lista).

Estoy familiarizado con el Centro de documentación y las capacidades de Mathematica sin programación. He estado aprendiendo programación con Mathematica, y realmente quiero extender esa habilidad a la programación funcional, pero he encontrado que la mayoría de los recursos sobre el tema son demasiado difíciles. Siento que estoy en esa curva en la curva de aprendizaje donde está a punto de encajar en su lugar, pero ahora estoy luchando. ¡Por lo menos, si tienes una buena fuente de programación funcional, estaría más que feliz de investigar sobre eso! ¡Cualquier ayuda es muy apreciada! Lo siento si es TMI, pero estoy seguro de que muchos de ustedes han sentido lo mismo.

+0

Usted puede haber notado que todo el Solu proporcionado Las opciones son un poco más difíciles cuando tratas de mantener ese 0, que es AFAICT matemáticamente sin sentido. Creo que el universo está tratando de decirte algo allí ... – Pillsy

+0

Entiendo que el 0 inicial no tiene mucho sentido matemáticamente, pero en términos de presentación, tiene más sentido. Por ejemplo, si usa 1971 como el año base en el análisis, entonces el cambio de enero a febrero debería ser de febrero a febrero. A continuación, hace la presentación más lógica si ese valor se muestra como el cambio en febrero, especialmente porque voy a trazar los datos. – Alec

Respuesta

7

Tiene una lista de pares {date, value} así que si tiene Transpose tendrá una lista de dos listas: la primera una lista de fechas y la segunda una lista de valores correspondientes. Puede tomar el Differences de los valores, Prepend 0, y luego Transponer de nuevo para volver a una lista de pares.

En el código,

data = {{{1971,1,31,0,0,0}, 1.0118}, 
     {{1971,2,28,0,0,0}, 1.0075}, 
     {{2010,5,31,0,0,0}, 1.0403}} 
{dates, values} = Transpose[data]; 
diffs = Prepend[Differences[values], 0]; 
answer = Transpose[{dates, diffs}] 

que devuelve:

{{{1971,1,31,0,0,0}, 0}, 
{{1971,2,28,0,0,0}, -0.0043}, 
{{2010,5,31,0,0,0}, 0.0328}} 

Envolver que hasta en una sola función, con gracias a Janus de la idea:

taildiffs[data_]:= 
    Transpose @ {#1, Prepend[Differences[#2], 0]}& @@ [email protected] 

Tenga en cuenta que la construcción ... #1 ... #2 ... & es una función pura:

http://reference.wolfram.com/mathematica/ref/Function.html

La sintaxis [email protected] es simplemente la abreviatura de f[x].

Por último, [email protected]@list es la abreviatura de Apply[f, list]:

http://reference.wolfram.com/mathematica/ref/Apply.html

Así taildiffs como se definió anteriormente es sólo una (quizás críptica) versión concisa de este:

Apply[Transpose[Function[{x,y}, {x, Prepend[Differences[y],0]}], Transpose[data]] 
+1

+1 Esto es mucho más claro (y probablemente más rápido) que el mío. – Max

+0

Por lo tanto, para asegurarme de que estoy progresando en la comprensión de la notación funcional, la función singe funciona de la siguiente manera: 1) los datos se transponen a dos listas, n. ° 1 y n. ° 2. 2) Esas dos listas se aplican de la siguiente manera; # 1 se deja solo, y # 2 se Diferencia y se antepone con 0. 3) # 1 y el # 2 modificado se vuelven a transponer en una sola lista. ¿Es correcto? – Alec

+0

Exactamente. Bien dicho. Debería saber de manera más general que, por ejemplo, foo [# 2, # 1] & es una función pura de dos argumentos que llama a foo en esos dos argumentos (en orden inverso). Otra sintaxis sofisticada es el @ y @@.Déjame agregar algo a la respuesta para explicar eso ... – dreeves

2
data = {{{dateInfo1}, value1}, {{dateInfo2}, value2}, {{dateInfo3}, value3}} 

Map[{#[[2,1]], #[[2,2]] - #[[1,2]]}&, {Take[data, Length[data] - 1], Rest[data]}] 

da

{{{dateInfo2}, -value1 + value2}, {{dateInfo3}, -value2 + value3}} 

Este primer elemento en su lista de resultados

{{dateInfo1},0} 

no encaja realmente en la secuencia, por lo que puede anteponer manualmente a la lista

2

Recomiendo usar Reap y Sow para esto:

In[13]:= lis= {{{1971,1,31,0,0,0.},1.0118},{{1971,2,28,0,0,0},1.0075},{{2010,5,31,0,0,0.},1.0403}}; 

In[14]:= [email protected]@Reap[ 
    (* set first previous to first value to get 0 *) 
    Module[{prev = lis[[1, 2]]}, 
    Scan[ 
    (
     (* First[#] = date, Last[#] = value *) 
     Sow[{First[#], Last[#] - prev}]; 
     (* set new previous to this value *) 
     prev = Last[#] 
     ) &, 
    lis]] 
    ] 

Out[14]= {{{1971, 1, 31, 0, 0, 0.}, 0.}, 
    {{1971, 2, 28, 0, 0, 0}, -0.0043}, 
    {{2010, 5, 31, 0, 0, 0.}, 0.0328}} 

La salida de Reap es un poco complicado si no está familiarizado con él, pero ReapSow y básicamente le dan una forma de "sembrar" las cosas en las listas y luego "cosechar" ellos después de la evaluación. Reap y Sow son mucho más eficientes que usar AppendTo con una lista, por ejemplo.

HTH!

+0

+1 para el ejemplo práctico del uso de Reap and Sow. – telefunkenvf14

3

Excepto por el hecho de que usted quiere la inicial 0, usted está buscando Differences. Para salir de la fecha solo, transposición y de aplicación a la segunda parte única, así:

TailDifferences[data_]:= 
    [email protected][{#1,{0}~Join~Differences[#2]}&,Transpose[data]] 

Aplicando esto a sus datos produce algo como esto:

data={{{dateInfo1},value1},{{dateInfo2},value2},{{dateInfo3},value3}}; 
TailDifferences[data] 

{{{dateInfo1},0},{{dateInfo2},-value1+value2},{{dateInfo3},-value2+value3}} 
1

Esta operación también se podría hacer con Part y Set:

data = {{{1971,1,31,0,0,0}, 1.0118}, 
     {{1971,2,28,0,0,0}, 1.0075}, 
     {{2010,5,31,0,0,0}, 1.0403}}; 

Module[{a = data}, 
    a[[2 ;;, 2]] = Differences[a[[All, 2]]]; 
    a[[1, 2]] = 0; 
    a 
] 
{{{1971, 1, 31, 0, 0, 0}, 0}, 
{{1971, 2, 28, 0, 0, 0}, -0.0043}, 
{{2010, 5, 31, 0, 0, 0}, 0.0328}}
Cuestiones relacionadas