2010-06-24 3 views
6

J'ai une liste des dates et des valeurs dans le format:Comment soustraire des éléments spécifiques dans une liste en utilisant la programmation fonctionnelle dans Mathematica?

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

Avec quelques dates et valeurs réelles:

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

Pour les curieux, il y a une liste des États-Unis par rapport aux valeurs de $ CAD tiré du FRED database.

je voudrais soustraire simplement valeur1 à partir de la valeur 2, et puis créer une nouvelle liste avec les données sous la forme de:

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

(avec Évolution1 étant valeur2-valeur1)

Je sais qu'il doit y avoir une manière relativement facile de faire cela en utilisant la programmation fonctionnelle, par opposition à Do ou While avec des variables d'index et de comptage et tout ce non-sens. La méthode que j'essaie d'accomplir doit être relativement robuste, car j'insère automatiquement des ensembles de données provenant de sources qui ont la même mise en forme, mais avec des intervalles de temps différents. Le repositionnement est alors beaucoup plus facile si je n'ai pas besoin de spécifier les intervalles de date ListPlot (ce qui arriverait si je supprimais le dateInfo de la liste). Je connais le Centre de documentation et les capacités Mathematica hors programmation. J'ai appris la programmation avec Mathematica, et je veux vraiment étendre cette capacité à la programmation fonctionnelle, mais j'ai trouvé la plupart des ressources sur le sujet un peu trop difficile. J'ai l'impression d'être à cette bosse dans la courbe d'apprentissage où il est sur le point de se mettre en place, mais pour l'instant je me bats. À tout le moins, si vous avez une bonne source sur la programmation fonctionnelle, je serais plus qu'heureux de regarder dans ceux-ci! Toute aide est très appréciée! Désolé si c'est TMI, mais je suis sûr que beaucoup d'entre vous ont ressenti la même chose.

+0

Vous avez sans doute remarqué que tous les solu fournis Les choses sont un peu plus gênantes quand vous essayez de garder ce premier 0, qui est mathématiquement dénué de sens à l'AFAICT. Je pense que l'univers essaye de te dire quelque chose là ... – Pillsy

+0

Je comprends que le 0 principal n'a pas autant de sens mathématique, mais en terme de présentation, il a plus de sens. Par exemple, si on utilise 1971 comme année de référence dans l'analyse, alors le changement de janvier à février devrait être février-janvier. Il rend alors la présentation plus logique si cette valeur est affichée comme le changement de février, d'autant plus que je vais tracer les données. – Alec

Répondre

7

Vous avez une liste de paires {date, valeur}, donc si vous Transpose vous avez une liste de deux listes - la première une liste de dates et la seconde une liste de valeurs correspondantes. Vous pouvez ensuite prendre le Differences des valeurs, Prepend 0, puis Transposer à nouveau pour revenir à une liste de paires.

Dans le code,

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

qui retourne:

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

Pour conclure que en une seule fonction, avec grâce à Janus l'idée:

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

Notez que la construction ... #1 ... #2 ... & est une fonction pure:

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

La syntaxe [email protected] est simplement un raccourci pour f[x].

Enfin, [email protected]@list est un raccourci pour Apply[f, list]:

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

donc taildiffs tel que défini ci-dessus est juste un laconique (peut-être cryptique) version de ceci:

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

+1 Ceci est beaucoup plus clair (et probablement plus rapide) que le mien. – Max

+0

Donc, pour m'assurer que je progresse dans la compréhension de la Notation Fonctionnelle, la fonction singe fonctionne comme ceci: 1) les données sont Transposées en deux listes, # 1 et # 2. 2) Ces deux listes sont appliquées de la manière suivante; # 1 est laissé seul, et # 2 est Différé et préfixé avec 0. 3) # 1 et le # 2 modifié sont ensuite Transposés dans une seule liste. Est-ce exact? – Alec

+0

Exactement. Bien dit. Vous devriez savoir plus généralement que, par exemple, foo [# 2, # 1] & est une fonction pure de deux arguments qui appelle foo sur ces deux arguments (dans l'ordre inverse). Autre syntaxe de fantaisie, il y a le @ et @@.Laissez-moi ajouter quelque chose à la réponse pour expliquer ces ... – dreeves

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

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

donne

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

Ce premier élément dans la liste des résultats

{{dateInfo1},0} 

ne rentre pas vraiment dans la séquence, de sorte que vous pouvez manuellement préfixer à la liste

2

Je recommande d'utiliser Reap et Sow pour cela:

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 sortie de Reap est un peu compliqué si vous n'êtes pas familier avec elle, mais Reap et Sow vous donnent essentiellement un moyen de « semer » les choses dans des listes, puis les « récolter » après l'évaluation. Reap et Sow sont beaucoup plus efficaces que d'utiliser AppendTo avec une liste, par exemple.

HTH!

+0

+1 pour l'exemple pratique d'utilisation de Reap et Sow. – telefunkenvf14

3

A l'exception du fait que vous voulez l'initiale 0, vous cherchez Differences. Pour quitter les dates seul, transposent et appliquent à la deuxième partie seulement, comme ceci:

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

Appliqué à vos données fournissent quelque chose comme ceci:

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

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

Cette opération pourrait également être fait avec Part et 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}}
Questions connexes