MATLAB Answers

dpb
0

ISMEMBER() modified result desired

dpb
さんによって質問されました 2019 年 1 月 19 日
最新アクティビティ dpb
さんによって 編集されました 2019 年 1 月 21 日
[lia,locb]=ismember(A,B);
returns the first/last matching location in B of the elements in A that occur in B depending on which optional parameters one chooses. That's fine for many cases, but...
If it is desired to do a 1:1 matching of elements in A to their corresponding mates in B, a modified behavior would be a desirable option if there are repeated elements -- locB could return the next match after the previous for those elements that may not be unique in either array.
This can be done in a loop, of course, by making a search for each element in A in turn, either keeping an indexing variable as to last location for each element previously located or, conversely, marking the location in B with a missing value or somesuch.
That's the problem, the question is --
Is there some function which already does this that I'm not aware of/can't find or a "more cleverer" way to make the match?

  5 件のコメント

dpb
2019 年 1 月 21 日
Hmmm...have to think about that again, perhaps. I rejected sorting initially owing to there being a corollary intent here that I didn't mention in that there's also a need that both matching values occur in a permissible time window which my initial thinking was that sorting would remove the order...
Using the 'stable' optional keyword and removing each found from the target by replacing with NaN kept the order and the index then could be used to look up the appropriate associated time interval.
I'll see about a smallish realistic dataset that illustrates the issues; 200+ isn't terribly large but isn't all that small, either... :) and has quite a few elements that aren't an issue as being unique so they don't test anything much.
Thanks for considering...
Jan
2019 年 1 月 21 日
What about a small example?
A = [1, 2, 3, 1, 2, 3];
B = [2, 2, 2, 3, 3];
Is the wanted output this:
lia = [0, 1, 1, 0, 1, 1] % as logical
locb = [0, 1, 4, 0, 2, 5]
% ^ ^ would be 1 and 4 for standard ISMEMBER
dpb
2019 年 1 月 21 日
Yes, that's the idea...

サインイン to comment.

2 件の回答

Jan
回答者: Jan
2019 年 1 月 21 日
編集済み: Jan
2019 年 1 月 21 日

Do you mean something like this:
function [lia, locb] = ismemberNext(A, B)
lia = false(size(A));
locb = zeros(size(A));
for iA = 1:numel(A)
match = (A(iA) == B);
if any(match)
lia(iA) = true;
index = find(match, 1);
locb(iA) = index;
B(index) = NaN; % Mask first match for following calls
end
end
end

  2 件のコメント

dpb
2019 年 1 月 21 日
That's ok w/o the tolerance problem. I'd written (hadn't posted; didn't want to taint the pool first :) )
nG=numel(g); % number of gifts (formula values)
locV=zeros(size(g)); % preallocate lookup location
inV=zeros(size(g)); % preallocate lookup location
vmatch=zeros(size(g)); % matched values cleared
datematch=nat(size(g)); % and the monthy/yr associated
for j=1:nG % find & pair up matching formula values
[inV(j),locV(j)]=ismembertol(g(j),v,'DataScale',0.01);
if inV(j)
vmatch(j)=v(locV(j));
datematch(j)=MT_AU.Date(o(locV(j))); % MMMYY for the formula gift
v(locV(j))=nan;
end
end
vfail=v(isfinite(v)); % retrieve those not matched
The 0.01 tolerance is owing this particular dataset happens to be financial and from a spreadsheet in which there is rounding error in some returned values. One could wrap the find arguments inside a round call.
The datematch array is the corresponding auxiliary "timestamp" variable, v is the dollar value try to match to the g value between two sets of entries that should match but don't always..
It doesn't seem possible to do without the basic loop over the elements in the first and you used the same 'trick' to hide the already found element
The overall problem is a set of entries were made into a number of spreadsheets over a period of a number of years while a corresponding set of comments of which entry correlated to a given one of those entries. The problem is there are a few for which comments weren't entred and/or there were other accounting entries besides new contributions that may have been composite entries that don't match any particular single other entry. For tracking purposes have stripped the entries in the comments (the g array) and the task is to match the known v entries and then isolate the remainder. There's then another independent way with the value and the timestamp to identify which of those is which to finish the task.
dpb
2019 年 1 月 21 日
for iA = 1:numel(A)
match = (A(iA) == B);
if any(match)
lia(iA) = true;
index = find(match, 1);
...
Slight optimization, maybe -- may as well just find the location first as have to convert the logical array anyway...
for iA = 1:numel(A)
index = find(A(iA) == B, 1);
if ~isempty(index)
lia(iA) = true;
...

サインイン to comment.


Guillaume
回答者: Guillaume
2019 年 1 月 21 日

Maybe I misunderstood the problem, but ismembertol already has the option to return all matching indices in B:
[found, where] = ismembertol(A, B, 'OutputAllIndices', true)

  3 件のコメント

dpb
2019 年 1 月 21 日
I wasn't aware ismembertol had that optional ouput option, indeed.
I'll have to see how one can pick the corresponding elements from the cells that have the 1:1 position match since what it does is return the same full subset for every matching element. If A were unique, that would be the answer; when not then have to associate the cell with the position to get the nth location from the nth cell of the duplicates.
There may be a clever way to do that but it doesn't come to me otomh right now... :)
Guillaume
2019 年 1 月 21 日
Are the A that match the same set of B exactly identical? If so, then it's easily solved. If there's a small tolerance on the As as well, then I'll have to think about it.
dpb
2019 年 1 月 21 日
Not necessarily identical, no...I have no way to know a priori which are those elements that contain the rounding discrepancies.
I was considering that I could just go ahead and round the Excel values when read the spreadsheet...that would certainly be faster and probably then makes the need for ismembertol go away...excepting ismember doesn't have the optional output...Catch-22! :)
It seems to me since TMW went this far, there might as well be the 'OutputMatchedIndices' option as well and imo if they're going to add a feature like this to one of the family member functions, it should go in all when it is first introduced, not create yet more uniqueness in interfaces than already exists.
In the end when I'm past the time crunch I'll see about crafting/submitting an enhancment request.
ADDENDUM
On reflection, I guess it would be possible to write
[inA,locB]=ismembertol(round(A,2), round(B,2), 'OutputAllIndices', true);
which _should_ then make the match identical...

サインイン to comment.



Translated by