How to find the position with if-statement in column in PowerBI/Dax - find

My simplified datasetlooks like:
Step Position Value
A 1 1
A 2 0
A 3 1
A 4 1
A 5 1
A 6 1
B 1 1
B 2 0
B 3 1
B 4 1
B 5 0
B 6 1
I would like to know for each step how many zero's I have and at what position.
I could make a table like this:
Step Countzero
A 1
B 2
by using this code:
CountZero = COUNTX ( FILTER ( 'Table'; 'Table'[Value] == 0 ); 'Table'[Value] )
How can I determine at what positions these zeros occur?
This could, for instance, be presented in a table like the one below, but any other form of presentation would do too.
Step Position of zero
A 2
B 2, 5

You can use CONCATENATEX similarly to how you're using COUNTX:
PositionZero =
CONCATENATEX ( FILTER ( 'Table'; 'Table'[Value] = 0 ); 'Table'[Position]; "," )

Related

I have a 3d matrix in matlab and I need to extract each row to create new matricies

I have a 3d matrix in the following form,
AA = [1,1;2,2];
BB = [1,1;2,2];
CC = [1,1;2,2];
ZZ = cat(3,AA,BB,CC)
NEW_CODE = [1 1; 1 1; 1 1; 2 2; 2 2; 2 2;]
Basically the code that I have creates a matrix in the form NEW_CODE, I need to transfer this back to ZZ.
To be clear, from
NEW_CODE =
1 1
1 1
1 1
2 2
2 2
2 2
To,
ZZ(:,:,1) =
1 1
2 2
ZZ(:,:,2) =
1 1
2 2
ZZ(:,:,3) =
1 1
2 2
I have tried this with no success,
attempt=NEW_CODE(:,1:3+1:end);
You could use reshape to split the top and bottom "halves" of the NEW_DATA matrix, then shiftdim to rearrange the result as desired
ZZ2 = shiftdim( reshape( NEW_CODE, [], 2, 2 ), 1 );
You can check this is correct using isequal(ZZ,ZZ2), which returns true.
I don't have a copy of Matlab to play with right now, so you're going to need to double check this
permute( reshape( NEW_CODE' , 2 , 3 , 2 ) , [ 1 3 2 ] )

Generate all possible column vectors in matlab

I am essentially trying to figure out how to generate code for basis vectors of different configurations of M objects into N different states (for example, if I had 2 snacks between 2 kids, I could have (2,0) (0,2) or (1,1), terrible example, but thats the idea)
I am struggling to figure out how to do this without going into many different loops (I want this to be automatic). The idea would be to create a Matrix where each row is a vector of length M. I would start with vec(1) = N then an if loop where if sum(vec) == N, Matrix(1,:)=vec; Then I could take vec(1)=N-i and do the same.
My only issue is I do not see how to use the if and forget it so that if I had maybe 2 objects in 5 locations, how would I do this to get (1 0 0 0 1).
I am not seeing how to do this.
You could use a recursive function:
function out = combos(M,N)
if N == 1
out = M;
else
out = [];
for i = 0:M
subout = combos(M-i,N-1);
subout(:,end+1) = i;
out = [out;subout];
end
end
I think this does what you want.
The key idea is to generate not the number of elements in each group, but the split points between groups. This can be done via combinations with repetition. Matlab's nchoosek generates combinations without repetition, but these are easily converted into what we need.
M = 5; % number of objects
N = 3; % number of groups
t = nchoosek(1:M+N-1, N-1); % combinations without repetition...
t = bsxfun(#minus, t, 1:N-1); % ...convert into combinations with repetition
t = diff([zeros(size(t,1), 1) t repmat(M, size(t,1), 1) ], [], 2); % the size of each
% group is the distance between split points
In this example, the result is
t =
0 0 5
0 1 4
0 2 3
0 3 2
0 4 1
0 5 0
1 0 4
1 1 3
1 2 2
1 3 1
1 4 0
2 0 3
2 1 2
2 2 1
2 3 0
3 0 2
3 1 1
3 2 0
4 0 1
4 1 0
5 0 0
This is a similar approach to Luis' without bsxfun. Because we don't like fun.
n = 5;
k = 3;
c = nchoosek(n+k-1, k-1);
result = diff([zeros(c, 1) nchoosek(1:(n+k-1), k-1) ones(c, 1)*(n+k)], [], 2) - 1;
This creates the partitions of the integer n with length k. Given an array of length n + (k-1), we find all combinations of (k-1) places to place partitions between the (unary) integers. For 5 items and 3 locations, we have 7 choices of where to put the partitions:
[ 0 0 0 0 0 0 0 ]
If our chosen combination is [2 4], we replace positions 2 and 4 with partitions to look like this:
[ 0 | 0 | 0 0 0 ]
The O's give the value in unary, so this combination is 1 1 3. To recover the values easily, we just augment the combinations with imaginary partitions at the next values to the left and right of the array (0 and n+k) and take the difference and subtract 1 (because the partitions themselves don't contribute to the value):
diff([0 2 4 8]) - 1
ans =
1 1 3
By sliding the partitions in to each possible combination of positions, we get all of the partitions of n.
Output:
result =
0 0 5
0 1 4
0 2 3
0 3 2
0 4 1
0 5 0
1 0 4
1 1 3
1 2 2
1 3 1
1 4 0
2 0 3
2 1 2
2 2 1
2 3 0
3 0 2
3 1 1
3 2 0
4 0 1
4 1 0
5 0 0

A table with 2 columns where one column increases sequentially while the other column displaying the same number till a limit is reached

I have been trying to write a code where the users enters two numbers in order to get 2 columns. It is very hard to explain by words what I am trying to achieve so here is an example:
If the user inputs a = 1 and b = 1, the following table should be created:
ans =
1 1
If the user inputs a = 2 and b = 2:
ans =
1 1
1 2
2 1
2 2
If the user inputs a = 2 and b = 5:
ans =
1 1
1 2
1 3
1 4
1 5
2 1
2 2
2 3
2 4
2 5
For other values of a and b, the matrix should be constructed according to the above shown sequence.
This can be achieved straight-forward by the use of repelem and repmat:
[repelem((1:a).',b),repmat((1:b).',a,1)]
A more elegant way is using meshgrid and reshape it after:
[A,B] = meshgrid(1:a,1:b);
[A(:),B(:)]
Let's create an anonymous function and test the first approach:
>> fun = #(a,b) [repelem((1:a).',b),repmat((1:b).',a,1)];
>> fun(1,1)
ans =
1 1
>> fun(2,2)
ans =
1 1
1 2
2 1
2 2
>> fun(2,5)
ans =
1 1
1 2
1 3
1 4
1 5
2 1
2 2
2 3
2 4
2 5
Here is an alternative way
for example a = 2 and b = 5
A(1:b*a,1) = reshape(mtimes((1:a).',ones(1,b)).',1,b*a)
A(1:b*a,2) = reshape(mtimes((1:b).',ones(1,a)),1,b*a)
A =
1 1
1 2
1 3
1 4
1 5
2 1
2 2
2 3
2 4
2 5
There is just one logic, in the code below you define a matrix of row size and a and column size b
>> mtimes((1:a).',ones(1,b))
ans =
1 1 1 1 1
2 2 2 2 2
and the next step simply reshapes the matrix column wise for a and row wise for b by taking a transpose
A(1:b*a,1) = reshape(mtimes((1:a).',ones(1,b)).',1,b*a)
A(1:b*a,2) = reshape(mtimes((1:b).',ones(1,a)),1,b*a)

Modify parts of a matrix based on linear equation on row and column numbers

For example:
>> tmp = ones(5,5)
tmp =
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
I want a command like:
tmp(colNum - 2*rowNum > 0) = 0
that modifies entries of tmp when the column number is more than twice the row number e.g. it should produce:
tmp =
1 1 0 0 0
1 1 1 1 0
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
As a second example, tmp(colNum - rowNum == 0) = 0 should set the diagonal elements of tmp to be zero.
A possibly more efficient solution is to use bsxfun like so
nRows = 5;
nCols = 5;
bsxfun(#(col,row)~(col - 2*row > 0), 1:nCols, (1:nRows)')
You can generalize this to just accept a function so it becomes
bsxfun(#(col,row)~f(col,row), 1:nCols, (1:nRows)')
And now just replace f with exactly the way you specify the equation in your question i.e.
f = #(colNum, rowNum)(colNum - 2*rowNum > 0)
or
f = #(colNum, rowNum)(colNum - rowNum == 0)
of course it might make more sense to specify your function to accept (row,col) instead of (col,row) as that's how MATLAB indexes
You can use meshgrid to generate a grid of 2D coordinates, then use this to impose any condition you wish. The variant you seek outputs 2 2D matrices where the first matrix gives you the column locations and the second matrix outputs the row locations.
For example, given your situation above:
>> [X,Y] = meshgrid(1:5, 1:5)
X =
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
Y =
1 1 1 1 1
2 2 2 2 2
3 3 3 3 3
4 4 4 4 4
5 5 5 5 5
You can see that each unique spatial location shared between X and Y give you the desired 2D location as if you were envisioning a 2D grid.
Therefore, you would do something like this for your first situation:
[X,Y] = meshgrid(1:5,1:5); % Generate 2D coordinates
tmp = ones(5); % Generate desired matrix
tmp(X > 2*Y) = 0; % Set desired locations to 0
We get:
>> tmp
tmp =
1 1 0 0 0
1 1 1 1 0
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
Finally for your second example:
[X,Y] = meshgrid(1:5,1:5); % Generate 2D coordinates
tmp = ones(5); % Generate desired matrix
tmp(X == Y) = 0; % Set desired locations to 0
We get:
>> tmp
tmp =
0 1 1 1 1
1 0 1 1 1
1 1 0 1 1
1 1 1 0 1
1 1 1 1 0
Simply put, generate a grid of 2D coordinates, then use those directly to index into your desired matrix using logical / Boolean conditions to set the desired locations to 0.

Quick way to sort an array with respect to row sum in Matlab

Here's a small example of what I want. Given the following array:
1 1 2
2 2 1
1 1 1
1 1 6
Sorted (row sum is shown in parenthesis):
1 1 6 (8)
2 2 1 (5)
1 1 2 (4)
1 1 1 (3)
Is there a quick way to achieve this in Matlab?
Since sort returns the indexes in order as well as the sorted matrix, you can use these indices to access the original data -- try this:
% some data
A = [
1 1 2;
2 2 1;
1 1 1;
1 1 6;
];
% compute the row totals
row_totals = sum(A,2);
% sort the row totals (descending order)
[sorted, row_ids] = sort(row_totals, 'descend');
% and display the original data in that order (concatenated with the sums)
disp([A(row_ids,:), row_totals(row_ids)])
>>>
1 1 6 8
2 2 1 5
1 1 2 4
1 1 1 3
The ugliest one-liner I could come up with:
>> subsref( sortrows( [sum(A,2) A], -1 ), struct('type','()','subs',{{':',1+(1:size(A,2))}}) )
ans =
1 1 6
2 2 1
1 1 2
1 1 1
Disclaimer: I don't think anyone should write this kind of code, but it's a nice practice to keep your Matlab's skills sharp.
Just do something very simple like follows
temp = [1 1 2
2 2 1
1 1 1
1 1 6];
rowSums = sum(temp,2);
[~,idx] = sort(rowSums,'descend');
output = [temp(idx,:),rowSums(idx)];
EDIT
Changed the above code to make sure the sum is appended to the last column. I did not notice that this was a requirement when I read the question initially.
I leave it for you to judge if this is uglier than #Shai's:
fliplr(diff([sortrows(fliplr(-cumsum(A,2))) zeros(size(A,1),1) ],1,2))
Let's do some matrix multiplication
>> sortrows([sum(A,2) A], -1)*[zeros(1,size(A,2)); eye(size(A,2))]
returns
ans =
1 1 6
2 2 1
1 1 2
1 1 1