Alternative à Lag() lorsque vous travaillez avec des matrices au lieu de tables de donnéesTous,
Existe-t-il une alternative au lag() que je pourrais utiliser lorsque je travaille avec des matrices au lieu de tableaux de données ? Essentiellement, j'aimerais pouvoir regarder la valeur de la ligne précédente de ma colonne dans une matrice pour déterminer la valeur de la ligne actuelle. Ceci peut facilement être réalisé en utilisant la fonction lag() dans une table de données. Quel est un moyen efficace autre que le bouclage pour y parvenir si vous travaillez avec des matrices ?
dt = New Table("Test");
dt << New Column("Random-1",Numeric,Continuous,<< set values(Random Index(10^3,10^2)));
dt << New Column("AltToLag",Numeric,Continuous,Formula(If(Row()==1,0,Lag(:Name("Random-1")))));Re : Alternative à Lag() lorsque vous travaillez avec des matrices au lieu de tables de donnéesVoici une variante de la solution de Vince avec laquelle je jouais. Il pourrait ou pourrait ne capture pas les exigences mais peut expliquer comment effectuer les manipulations dont vous avez besoin.
R = [4, 6, 6, 5, 8, 7];
lag = 1;
// describe the adjustment
modamount = [1, -1];
// lagged values dont need the last value
lagged = R[1 :: N Rows( R ) - lag];// [4, 6, 6, 5, 8]
// adjustment is based on lagged values. add 1 for indexing.
adjust = modamount[1 + Mod( lagged, 2 )];// [1, 1, 1, -1, 1]
// source data does not need the first value
source = R[1 + lag :: N Rows( R )]; // [6, 6, 5, 8, 7]
// combine the adjustment with the source
combine = adjust + source; // [7, 7, 6, 7, 8]
// prepend a zero
answer = 0 |/ combine; // [0, 7, 7, 6, 7, 8]
Re : Alternative à Lag() lorsque vous travaillez avec des matrices au lieu de tables de donnéesBien sûr.Donc si on regarde votre formule (autre que la première ligne = 0)
If( Mod( Lag( :RandomList ), 2 ) == 0,
:RandomList[Row()] + 1,
:RandomList[Row()] - 1
)
Je le vois comme 3 parties, le décalage, la vérification mod == 0 du décalage et l'expression else de cela.
Alors je fais d'abord le décalage
lv = lag_matrix(v, 1);
puis j'obtiens le vecteur mod
mod_vector = lv / 2 - floor(lv/2);
mais je viens de réaliser que le mod fonctionne sur les vecteurs donc vous pouvez le faire
mod_vector = mod(lv, 2);
ce qui est nettement plus rapide
alors j'obtiens un vecteur booléen en faisant
mod_vector == 0 et loc() pour trouver les lignes où le mod(2) du lag(1) est 0
loc_vector = loc(mod_vector==0);
loc_vector correspond aux lignes qui correspondent à votre instruction if
Mod( Lag( :RandomList ), 2 ) == 0
puis pour obtenir les lignes de l'instruction else, j'inverse la sélection en créant un vecteur composé uniquement de 1 et en définissant les lignes loc_vector sur 0 et en effectuant un loc()
invert_vector = J(nrows(v), 1);
invert_vector[loc_vector] = 0;
invert_vector = loc(invert_vector);
donc si vous avez concaténé les deux vecteurs et trié, cela devrait juste être 1::nrows()
après cela, je viens de définir les lignes de l'expression if sur +1 et de l'expression else sur -1
v[loc_vector] = v[loc_vector] + 1;
v[invert_vector] = v[invert_vector] - 1;
et enfin mettre la première ligne à 0
v[1] = 0;
Re : Alternative à Lag() lorsque vous travaillez avec des matrices au lieu de tables de données@vince_faller ,
Merci pour la solution, pouvez-vous bien vouloir expliquer le processus de réflexion et comment il fonctionne si ce n'est pas trop demander.
Je vois que vous utilisez la combinaison de la fonction lag_matrix, de la fonction mod et de loc() mais je ne comprends pas bien la logique.
J'apprécierais grandement un aperçu de la logique afin que je puisse apprendre le processus de réflexion (encore une fois seulement si ce n'est pas trop demander)
Re : Alternative à Lag() lorsque vous travaillez avec des matrices au lieu de tables de donnéesCe n'est pas vraiment très convivial, mais même toutes ces étapes sont toujours environ 3 fois plus rapides (436 : 135 us) sur mon ordinateur lors de l'exécution du vecteur par rapport à la colonne.Il existe certainement des optimisations que vous pourriez apporter à cela pour le rendre plus rapide également. Lorsque je l'ai mis à 1 000 lignes, c'était environ 4 fois plus rapide (1057 : 227us). De plus, apparemment, ils se sont débarrassés d'Apply, c'est ma faute.
dt = New Table( "Test" );
dt << New Column( "RandomList", Numeric, Continuous, <<SET values=""> 0,
lag_vector = lag_vector[1 :: n - Abs( lag )];
new_mat = empty_mat |/ mat[lag_vector, 0];
, //else
lag_vector = lag_vector[Abs( lag ) + 1 :: n];
new_mat = mat[lag_vector, 0] |/ empty_mat;
);
new_mat;
);
v = Column( dt, "RandomList" ) << Get Values;
check_vector = Column(dt, "DesFunc") << Get Values;
time_vector = HPTime();
//lag the vector
lv = lag_matrix(v, 1);
//mod the vector
mod_vector = lv / 2 - floor(lv/2);
//find the mods you want
loc_vector = loc(mod_vector==0);
//invert to find the mods you don't want
invert_vector = J(nrows(v), 1);
invert_vector[loc_vector] = 0;
invert_vector = loc(invert_vector);
//assign values
v[loc_vector] = v[loc_vector] + 1;
v[invert_vector] = v[invert_vector] - 1;
//set first row to 0
v[1] = 0;
time_vector = HPTime()-time_vector;
show(all(v == check_vector));
show(time_column, time_vector);
</SET>
Espérons que cela aide un peu.
Re : Alternative à Lag() lorsque vous travaillez avec des matrices au lieu de tables de données@vince_faller ,
Pouvez-vous m'aider à implémenter ce qui suit dans une matrice sans boucle ?
dt = New Table("Test");
dt << New Column("RandomList",Numeric,Continuous,<< Set Values(Random Index(10^3,10^2)))
<< New Column("DesFunc",Numeric,Continuous,Formula(If(Row() == 1,0,If(Mod(Lag(:RandomList),2)==0,:RandomList[Row()]+1,:RandomList[Row()]-1))));De plus, je n'ai pas trouvé les fonctions apply() ou applyOver() dans mon index de script. J'utilise JMP 14. Est-ce un truc de JMP Pro ?
Re : Alternative à Lag() lorsque vous travaillez avec des matrices au lieu de tables de donnéesQu'essayez-vous de faire?Vous avez raison, les matrices sont généralement plus rapides, mais les parcourir en boucle perdra généralement (d'après mon expérience) tout avantage.JMP 14 possède désormais les fonctions apply() et applyOver() mais je n'ai pas eu beaucoup de chance de les utiliser.
Re : Alternative à Lag() lorsque vous travaillez avec des matrices au lieu de tables de données@XanGregg , @Craige_Hales
Xan ou Craige - si cela est possible, je vous demanderais en fait de bien vouloir rédiger un article de blog expliquant en détail comment effectuer la vectorisation avec de nombreux exemples en JSL. Ce sujet est abordé en détail dans SAS , R , Matlab et d'autres environnements. J'adorerais voir quelque chose de similaire pour JMP. Si quelque chose de similaire existe déjà, je vous demanderais d'attirer mon attention dessus.
Blogues SAS - https://blogs.sas.com/content/iml/2013/05/15/vectorize-computations.html
Re : Alternative à Lag() lorsque vous travaillez avec des matrices au lieu de tables de données@gzmorgan0 ,
Ce que j'essaie de demander, c'est un moyen d'éviter la boucle et de m'appuyer sur du code vectorisé. Il est conseillé de remplacer les boucles par des fonctions matricielles pour rendre le code plus efficace ( https://community.jmp.com/t5/JMP-Blog/JSL-Tip-Replace-Loops-with-Functions-on-Matrices/ba-p/29783 ) . Ceci est réalisé dans R grâce aux fonctions de la famille apply et dans Matlab grâce à certaines fonctions matricielles ou fonctions personnalisées. Je demande s'il existe un moyen d'implémenter un tel code vectorisé sur des matrices plutôt que d'essayer d'écrire une boucle dans ce cas pour trouver le décalage ().
@gzmorgan0 a écrit:
Aujourd'hui,
Je ne sais pas ce que vous demandez. Vous pouvez simplement référencer la ligne j-1. Le script affiche les résultats lag1 et dif1.
Names Default to Here(1);
dt = Open("$sample_data/Big Class.jmp");
bcmat = dt << get as matrix; //Matrix(40,3)
for(j=2, j<=nrow(dt), j++,
lag1 = bcmat[j-1,0];
dif1 = bcmat[j,0] - bcmat[j-1,0];
show( lag1, dif1)
);
Dans l'exemple que vous avez fourni, je comprends parfaitement qu'il est facile d'écrire une boucle et d'obtenir l'équivalent lag(), mais à mesure que la taille de vos ensembles de données ou le nombre de vos itérations augmentent, cela ralentira votre code. Je recherche un remplacement efficace, c'est-à-dire un équivalent vectorisé à l'implémentation d'opérations répétitives sur des matrices en JSL.
Re : Alternative à Lag() lorsque vous travaillez avec des matrices au lieu de tables de donnéesAujourd'hui,
Je ne sais pas ce que vous demandez. Vous pouvez simplement référencer la ligne j-1. Le script affiche les résultats lag1 et dif1.
Names Default to Here(1);
dt = Open("$sample_data/Big Class.jmp");
bcmat = dt << get as matrix; //Matrix(40,3)
for(j=2, j<=nrow(dt), j++,
lag1 = bcmat[j-1,0];
dif1 = bcmat[j,0] - bcmat[j-1,0];
show( lag1, dif1)
);Re : Alternative à Lag() lorsque vous travaillez avec des matrices au lieu de tables de données@vince_faller ,
Merci pour la solution que vous avez proposée, existe-t-il un moyen de modifier cette fonction pour obtenir uniquement la ligne précédente plutôt que la matrice entière ?
Peut-être que la question appropriée serait de savoir quel est le format vectorisé de boucle autour d'une matrice avec la fonction - similaire à l'application de fonctions dans R qui sont beaucoup plus rapides que les boucles.
Re : Alternative à Lag() lorsque vous travaillez avec des matrices au lieu de tables de donnéesEst-ce que ça marche pour toi?
names default to here(1);
lag_matrix = function({mat, lag}, {DEFAULT LOCAL},
n = nrows(mat);
lag_vector = 1::n;
empty_mat = J(abs(lag), ncols(mat), .);
if(lag>0,
lag_vector = lag_vector[1::n-abs(lag)];
new_mat = empty_mat|/mat[lag_vector, 0];
, //else
lag_vector = lag_vector[abs(lag)+1::n];
new_mat = mat[lag_vector, 0]|/empty_mat;
);
new_mat;
);
lag_matrix((14::28)`||(28::42)`, -1);