Inserting zeros for missing values in a vector

% ID is an index
% IDx is a 'result' (Values in Vx conform to IDx)
% Index values 1 and 4 and missing in IDx (when compared with ID)
% I want to put a zero in Vx at positions 1 and 4
% This code works - newVx has zeros in right places
ID=[1:5]';
IDx=[2,3,5]';
Vx=[10,15,20]';
newVx=NaN( size( ID ) );
newVx (ismember(ID,IDx)) = Vx;
newVx = fillmissing(newVx,'constant',0)
%
% but if the problem is repeated (below)
% I get an error message:
% Unable to perform assignment because the left and right sides have a different number of elements.
%
ID=[1:5]';
ID2=repmat(ID,2,1);
IDx=[2,3,5,1, 4]';
Vx=[10,15,20, 30, 40]';
newVx=NaN( size( ID2 ) );
newVx (ismember(ID2,IDx)) = Vx;
newVx = fillmissing(newVx,'constant',0)
%
% In this case newVx should look like this:
% ID newVx
% 1 0
% 2 10
% 3 15
% 4 0
% 5 20
% 1 30
% 2 0
% 3 0
% 4 40
% 5 0
%
% Appreciate suggestions for a solution - my ID vector is of length 97 and is repeated 15 times(1455 x 1)
% Length of (IDx &) Vx is 1208

2 Comments

You could do this:
% define number of products
numProducts = 5;
% Define products and there export values
products = [2,3,5,1,4]
value = [10,15,20,30,40];
% Assume that when product list goes to a lower value we are on to the next
% country, then assign corresponding row index in full matrix
country = cumsum([1 diff(products)<0])% gives country number
rowIdx = (country-1)*numProducts + products;
% Make output data array with first column product id's second column
% export value
numCountries = max(country);
exportValues = zeros(numCountries*numProducts,2);
expValues(:,1) = repmat((1:numProducts)',2,1); % product id's
expValues(rowIdx,2) = value
Please note the above solution will not work if you have some countries that do not export anything, as there will be no way to detect that there is a missing country in your products vector. If you have to cover this edge case then further development will be required

Sign in to comment.

 Accepted Answer

At line 22 on the right hand side you have the vector Vx which has 5 elements. On the left hand side you have newVx indexed by ismember(ID2,IDx). Evaluating ismember(ID2,IDx) you see that it is true for all 10 elements of ID2. So you are trying to assign a 5 element vector to a 10 element vector and MATLAB can't do that, thus the error.

7 Comments

Above I have detailed why you get the error with the code you presented, but to help you further I need to get a better understanding of what it is you are actually trying to do. I see that your indices "ID" repeat so there are multiple locations in ID where ID has the same value. For example, in your code above the value of the vector ID is 4 in elements 4 and 9, that is ID(4) = 4 and ID(9) = 4. You then make a vector newVx which has the same number of elements as ID and you want to assign elements to it based upon the indices listed in IDx. But since the ID values repeat, if you have the value n in IDx how do you know if you want to modify newVx(n) or newVx(n+M) or newVx(n+2M) etc?
Thank you Jon, for spending time thinking about this issue.
Just a few points. The first example works. The second does not. In both cases there is a difference in the number of elements.
Case 1: dim(ID)>dim(IDx) Case 2: dim(ID2)>dim(IDx). So the issue I think as you have identifed in your comment is: The elements of ID are unique, but the elements of ID2 are not since they repeat themselves. So I suspect that is where the problem is.
Let me try and explain again what I am trying to do. Suppose I have 5 products and 2 countries.
Products are indexed 1 through 5. - so ID repeats twice (ID2).
Then I have two vectors or a matrix with two columns: Col 1 (or vector 1) - contains an index of the product that country 1 exports. It typically does not export all 5 products. In my second example Country 1 exports products 2, 3 and 5 and Country 2 exports products 1 and 4 (IDx=[2,3,5,1, 4]';). Vx (or column 2 of a matrix) is the value of exports for the products exported by countries 1 and 2. (so dim(IDx)=dim(Vx)).
I want newVx to look like what I wrote out above. The new Vx has zero values for products that each country does not export. And dim(ID)=dim(newVx).
Thank you again,
Dom
Hi Jon: Thanks for forcing me to think harder about this. I have tried to solve the issue of uniqueness, by adding a country index. What follows is not elegant, but it does the job.
C1=ones(5,1);
C2=ones(5,1)+1;
C=vertcat(C1,C2);
ID=[1:5]';
ID2=repmat(ID,2,1);
ID2=horzcat(C,ID2);
IDx=[2,3,5,1, 4]';
c1=ones(3,1);
c2=ones(2,1)+1;
c=vertcat(c1,c2);
IDx=horzcat(c,IDx);
Vx=[10,15,20, 30, 40]';
newVx (ismember(ID2,IDx,'rows')) = Vx;
newVx = fillmissing(newVx,'constant',0);
newIDVx=horzcat(ID2,newVx(:,1))
You could do this:
% define number of products
numProducts = 5;
% Define products and there export values
products = [2,3,5,1,4];
value = [10,15,20,30,40];
% Assume that when product list goes to a lower value we are on to the next
% country, then assign corresponding row index in full matrix
country = cumsum([1 diff(products)<0]);% gives country number
rowIdx = (country-1)*numProducts + products;
% Make output data array with first column product id's second column
% export value
numCountries = max(country);
exportValues = zeros(numCountries*numProducts,2);
expValues(:,1) = repmat((1:numProducts)',2,1); % product id's
expValues(rowIdx,2) = value
expValues = 10×2
1 0 2 10 3 15 4 0 5 20 1 30 2 0 3 0 4 40 5 0
Seems though that you might be better off organizing your data somewhat differently. For example you could use a MATLAB table with columns for country, productID, and exportValue
Thanks Jon, That works. Appreciate your effort.
Your welcome, interesting problem. If this solved your problem could you please accept the answer. This way if someone else has a similar issue they will know that a solution is available.

Sign in to comment.

More Answers (0)

Products

Release

R2023a

Asked:

Dom
on 3 Apr 2023

Commented:

Jon
on 6 Apr 2023

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!