2010-06-24 1 views
6

Ho un elenco di date e valori nel formato:Come sottrarre elementi specifici in un elenco utilizzando la programmazione funzionale in Mathematica?

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

Con alcune date e valori effettivi:

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

Per chi fosse curioso, si tratta di un elenco di Stati Uniti contro valori CAD $ tirato dallo FRED database.

vorrei sottrarre semplicemente valore1 dal valore di 2, e quindi creare un nuovo elenco con i dati sotto forma di:

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

(con change1 essendo valore2-valore1)

So che ci deve essere un modo relativamente semplice per farlo usando la programmazione funzionale, al contrario di Do o While con le variabili indice e il conteggio e tutte quelle sciocchezze. Il metodo che sto cercando di realizzare deve essere relativamente robusto, perché sto prelevando automaticamente i set di dati da fonti che hanno la stessa formattazione, ma intervalli di tempo diversi. Sostituire è quindi molto più semplice se non devo specificare gli intervalli di data di ListPlot (cosa che accadrebbe se togliessi la dataInfo dall'elenco).

Ho familiarità con il Centro di documentazione e le capacità di Mathematica non programmabili. Ho imparato a programmare con Mathematica e voglio davvero estendere tale capacità alla programmazione funzionale, ma ho trovato la maggior parte delle risorse sull'argomento un po 'troppo difficile. Mi sento come se fossi a quella gobba nella curva di apprendimento in cui sta per scattare in posizione, ma in questo momento sto lottando. Per lo meno, se hai una buona fonte di programmazione funzionale, sarei più che felice di esaminarli! Ogni aiuto è molto apprezzato! Scusa se è TMI, ma sono sicuro che molti di voi si sono sentiti allo stesso modo.

+0

avrete notato che tutte le solu fornito le cose sono solo un po 'più scomode quando si tenta di mantenere tale 0, che è AFAICT matematicamente privo di significato. Penso che l'universo stia cercando di dirti qualcosa lì ... – Pillsy

+0

Capisco che lo 0 iniziale non abbia senso matematicamente, ma in termini di presentazione, ha più senso. Ad esempio, se si utilizza il 1971 come anno base nell'analisi, allora il cambiamento da gennaio a febbraio dovrebbe essere febbraio-gennaio. Quindi rende la presentazione più logica se quel valore viene visualizzato come la modifica in febbraio, soprattutto dal momento che tratterò i dati. – Alec

risposta

7

Hai un elenco di {date, value} coppie, quindi se hai Transpose avrai un elenco di due elenchi: il primo un elenco di date e il secondo un elenco di valori corrispondenti. È quindi possibile prendere lo Differences dei valori, Prepend 0, quindi Trasporre nuovamente per tornare a un elenco di coppie.

Nel codice,

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}] 

che ritorna:

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

Per concludere che fino in una singola funzione, con grazie al Janus per l'idea:

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

Si noti che il costrutto ... #1 ... #2 ... & è una pura funzione:

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

Il [email protected] sintassi è semplicemente una scorciatoia per f[x].

Infine, [email protected]@list è una scorciatoia per Apply[f, list]:

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

Così taildiffs come sopra definito è solo una versione stringata (forse criptico) di questo:

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

+1 Questo è molto più chiaro (e probabilmente più veloce) del mio. – Max

+0

Quindi, per assicurarmi di progredire nella comprensione della notazione funzionale, la funzione singe funziona in questo modo: 1) i dati vengono trasposti in due elenchi, n. 1 e n. 2) Questi due elenchi sono applicati nel modo seguente; # 1 è rimasto solo, e # 2 è differenziato e preparato con 0. 3) Il n. 1 e il n. 2 modificato vengono quindi trasposti in un'unica lista. È corretto? – Alec

+0

Esattamente. Ben detto. Dovresti sapere più in generale che, ad esempio, foo [# 2, # 1] è una pura funzione di due argomenti che chiama foo su questi due argomenti (in ordine inverso). Altre sintassi fantasiose sono le @ e @@.Consentitemi di aggiungere qualcosa alla risposta per spiegare quelli ... – dreeves

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

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

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

Questo primo elemento nella lista dei risultati

{{dateInfo1},0} 

non si adatta davvero in sequenza, in modo da poter anteporre manualmente all'elenco

2

Si consiglia di utilizzare Reap e Sow per questo:

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}} 

L'uscita del Reap è un po 'complicato se non si ha familiarità con esso, ma Reap e Sow fondamentalmente si invia un modo per "seminare" le cose in liste e poi "raccogliere" loro dopo la valutazione. Reap e Sow sono molto più efficienti rispetto all'utilizzo di AppendTo con un elenco, ad esempio.

HTH!

+0

+1 per l'esempio pratico dell'utilizzo di Reap and Sow. – telefunkenvf14

3

Fatta eccezione per il fatto che vuoi l'iniziale 0, stai cercando Differences. Per lasciare le date da solo, recepire e ad applicare solo alla seconda parte, in questo modo:

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

Applicando questo ai dati cede qualcosa di simile:

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

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

Questa operazione potrebbe essere fatto anche con Part e 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}}