Suppose I have:
$a = [
[1, 0, 1]
[0, 1, 0]
[0, 1, 1]
]
and I want to extract all rows where $row[2] == 1. My resulting piddle would look like:
$b = [
[1, 0, 1]
[0, 1, 1]
]
Is this possible with PDL?
You need to use which to generate a list of indexes of your matrix which have a value of 1 in the third column
which($aa->index(2) == 1)
and pass this to dice_axis, which will select the rows with the given indexes. Axis 0 is the columns and axis 1 is the rows, so the code looks like this
use strict;
use warnings 'all';
use PDL;
my $aa = pdl <<__END_PDL__;
[
[1, 0, 1]
[0, 1, 0]
[0, 1, 1]
]
__END_PDL__
my $result = $aa->dice_axis(1, which($aa->index(2) == 1));
print $result;
output
[
[1 0 1]
[0 1 1]
]
I'm new to PDL, but it seems like you can use which result as a mask.
You need to transpose original variable first, then transpose it back after using slice.
pdl> $a = pdl [[1, 0, 1], [0, 1, 0], [0, 1, 1]]
pdl> p which($a(2) == 1)
[0 2]
pdl> p $a->transpose
[
[1 0 0]
[0 1 1]
[1 0 1]
]
pdl> p $a->transpose->slice(which($a(2) == 1))->transpose
[
[1 0 1]
[0 1 1]
]
Related
I have created a 5x4 matrix with entries only 1 and -1. I have also created the code which gives me randomly possible configurations for this kind of matrix. Every time I check manually if the determinant of the D'*D product is equal to 512 or not. Until now, I have only got the results of determinants 0, +-64, 192 and +-128.
I want to get the matrix configurations automatically:
whose determinant is equal to 512,
whose determinant is between 0 and 512.
So far I have done this line of code. It is right, even though I have to run the code by myself after each calculation.
valueset = [1,-1];
desiredsize = [5, 4];
desiredmatrix = valueset(randi(numel(valueset), desiredsize))
b=desiredmatrix.'
a=desiredmatrix.'*D
det(a)
and I got these kinds of calculations:
>desired
desiredmatrix =
1 -1 1 -1
1 -1 1 -1
-1 -1 1 -1
1 -1 -1 -1
1 1 -1 -1
b =
1 1 -1 1 1
-1 -1 -1 -1 1
1 1 1 -1 -1
-1 -1 -1 -1 -1
a =
1 3 3 1
-1 1 -3 -5
-1 -3 1 3
-3 -1 -5 -3
ans = 64
> desired
desiredmatrix =
-1 1 1 1
1 1 1 1
-1 -1 1 1
1 -1 -1 -1
1 -1 -1 -1
b =
-1 1 -1 1 1
1 1 -1 -1 -1
1 1 1 -1 -1
1 1 1 -1 -1
a =
3 1 1 -1
-3 -1 -1 1
-1 -3 1 3
-1 -3 1 3
ans = 0
etc, etc
It takes me around 23 milliseconds to compute first such matrix. And about 29-30 seconds to find all such matrices.
Now, we have 20 values in a matrix, so we have 2^20=1048576 such matrices.
So I run a for loop first to iterate through all these numbers (0 to 1048575). Now we go to fill the matrix. Now each i in the first for loop, I take the binary representation of i and pad it with 0s till I get a 20-element binary list.
So, 140 whose binary is 10001100 will become a list of 0000 0000 0000 1000 1100 (spaces added for visibility) which will be,
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0] (say its named bin_list)
Now, to fill the 20 elements of my matrix (say 0 to 19) I fill
the jth element as valueset[bin_list[j]] so if the element of bin_list is 0, the corresponding element of my array A is 1 and if its 1 then A gets the value (-1). So, for the case of 140, the matrix A will be
[[ 1, 1, 1, 1],
[ 1, 1, 1, 1],
[ 1, 1, 1, 1],
[-1, 1, 1, 1],
[-1, -1, 1, 1]]
Note: I have to convert A into a matrix using numpy.matrix since we need to calculate transpose and determinant.
This is depreciated as pointed out by user S Guogeon. So, for matrix multiplication, one can directly use # instead of * with numoy.array
After calculating this matrix A, I calculate the transpose using numpy.transpose(), say it is B. now I calculate the determinant using numpy.linalg.det(B*A). Now due to the return datatype of numpy.linalg.det(), I round it off to the nearest integer.
I check if this determinant is 512. If it is, bingo, I have the correct matrix.
The first solution I have is 854 (i=854)
The bin_list for this would be,
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0]
The matrix A would be,
matrix([[ 1, 1, 1, 1],
[ 1, 1, 1, 1],
[ 1, 1, -1, -1],
[ 1, -1, 1, -1],
[ 1, -1, -1, 1]])
A'*A will be,
matrix([[5, 1, 1, 1],
[1, 5, 1, 1],
[1, 1, 5, 1],
[1, 1, 1, 5]])
The determinant of this will be 512 (after converting the determinant into an int)
The code for converting 140 to the binary list is:
def int_to_binlist(n, b = 8):
res=[]
strb = str(b)+'b'
str1 = format(n, strb)
res = list(map(int, list(str1)))
return res
The code snippet for filling the matrix A with the bits of 1 and -1 is,
n_mat = desiredsize[0]*desiredsize[1] #so 5*4=20
for j in range(n_mat):
a[int(j/4)][j%4] = valueset[li[j]]
References:
numpy.linalg.det documentation
numpy.matrix documentation
I have two matrices (size 4x4) and I want to find the minimum between the two. For example:
A = [ 3, 2, 4, 5;
1, 2, 0, 6;
9, 8, 5, 4;
0, 1, 0, 3 ];
B = [ 1, 1, 6, 8;
0, 4, 6, 3;
5, 6, 7, 1;
0, 2, 3, 4 ];
Now, if I did a min(A,B) in Octave, it gives me
[ 1, 1, 4, 5;
0, 2, 0, 3;
5, 6, 5, 1;
0, 1, 0, 3 ]
Is there a way to get the matrix that 'won', by which I mean which matrix contained the minimum, in each element-wise comparison?
Like, for the first element of both matrices, matrix B won and so on.
I don't want to loop through the matrices.
You can compare A and B to find out in which matrix the minimum occurred.
With A > B, you will get a matrix containing False if the entry from A was chosen, and True if the entry from B was chosen. By adding 1 to it, you will get 1 if A was chosen and 2 if B was chosen.
>> 1 + (A > B)
ans =
2 2 1 1
2 1 1 2
2 2 1 2
1 1 1 1
Alternatively, you can concatenate A and B to form a 3-dimensional array with dimensions [4, 4, 2], where C(:, :, 1) = A and where C(:, :, 2) = B. Then you can call min on this matrix C along the third axis. When calling min on one matrix, you can get the index of the "winner" directly as a second return value:
>> C = cat(3, A, B);
>> [res, idx] = min(C, [], 3)
res =
1 1 4 5
0 2 0 3
5 6 5 1
0 1 0 3
idx =
2 2 1 1
2 1 1 2
2 2 1 2
1 1 1 1
Consider as examples:
interp1([0, 1], [2, 3], 0 , 'previous')
interp1([0, 1], [2, 3], 0 , 'next')
which produces
ans =
2
ans =
2
That is, in each respective case it finds the value in [0, 1] closest to and not exceeding 0 (respectively closest to and not below 0), then returns the corresponding value of [2,3]. I would like to change the second condition to "closest to and above 0", that is, it should return the same results as:
interp1([0, 1], [2, 3], 0.1 , 'previous')
interp1([0, 1], [2, 3], 0.1 , 'next')
which gives
ans =
2
ans =
3
In this case this works as 0.1 is a value in between [0, 1].
I've been trying to come up with a smart way of doing this for a while. Given a matrix (or cell) with the following structure:
A = [-1 1
-1 2
1 3
3 5
2 3
2 4
2 7
4 5
5 6
6 7
7 -2 ]
(Note that the above matrix/cell is unsorted in both columns and contains negative numbers).
How could one group it by the unique values of a particular column. E.g. the desired output for grouping by the second column would be something like:
B{1} = [-1]
B{2} = [-1]
B{3} = [1,2]
B{4} = [2]
B{5} = [3,4]
B{6} = [5]
B{7} = [2,6]
B{-2} = [7]
Thanks in advance!
You can use accumarray:
[~,~,subs] = unique(A(:,2));
values = accumarray(subs,A(:,1),[],#(x) {x});
ofGroup = accumarray(subs,A(:,2),[],#(x) {x(1)});
out = [ofGroup values]
out =
[-2] [ 7]
[ 1] [ -1]
[ 2] [ -1]
[ 3] [2x1 double]
[ 4] [ 2]
[ 5] [2x1 double]
[ 6] [ 5]
[ 7] [2x1 double]
If you REALLY insist on your order proposed, you could do the following, but I don't think that should be necessary.
% positives
pos = A( A(:,2) >= 0 , :);
[~,~,subs] = unique(pos(:,2));
posvalues = accumarray(subs,pos(:,1),[],#(x) {x});
posofGroup = accumarray(subs,pos(:,2),[],#(x) {x(1)});
% negatives
neg = A( A(:,2) < 0 , :);
[~,~,subs] = unique(neg(:,2));
negvalues = flipud( accumarray(subs,neg(:,1),[],#(x) {x}) );
negofGroup = flipud( accumarray(subs,neg(:,2),[],#(x) {x(1)}) );
out = [posofGroup posvalues; negofGroup negvalues ]
out =
[ 1] [ -1]
[ 2] [ -1]
[ 3] [2x1 double]
[ 4] [ 2]
[ 5] [2x1 double]
[ 6] [ 5]
[ 7] [2x1 double]
[-2] [ 7]
How about:
[group, ~, subs] = unique(A(:,2))
B = accumarray(subs, A(:,1), [], #(x){x'})
Results in
B=
[ 7]
[ -1]
[ -1]
[2,1]
[ 2]
[4,3]
[ 5]
[2,6]
and group matches the index of B to the number of the group it represents
Also if you are attached to your ordering then you can do this:
[group, ~, subs] = unique(A(end:-1:1,2), 'stable');
B = flipud(accumarray(subs, A(end:-1:1,1), [], #(x){x'}));
group = flipud(group);
B =
[ -1]
[ -1]
[1x2 double]
[ 2]
[1x2 double]
[ 5]
[1x2 double]
[ 7]
group =
1
2
3
4
5
6
7
-2
Consider this :
a = [1 ; 7 ; 13];
edges = [1, 3, 6, 9, 12, 15];
[~, bins] = histc(a, edges)
bins =
1
3
5
Now I would like to have the same output, but with a different "edges" vector for each a value, i.e. a matrix instead of a vector for edges. Exemple :
a = [1 ; 7 ; 13];
edges = [ 1, 3, 6 ; 1, 4, 15 ; 1, 20, 30];
edges =
1 3 6
1 4 15
1 20 30
indexes = theFunctionINeed(a, edges);
indexes =
1 % 1 inside [1, 3, 6]
2 % 7 indide [1, 4, 15]
1 %13 inside [1, 20, 30]
I could do this with histc inside a for loop, by I'm trying to avoid loops.
If you transform your arrays to cell arrays, you can try
a = {1 ; 7 ; 13};
edges = {[ 1, 3, 6 ];[ 1, 4, 15] ; [1, 20, 30]};
[~, indexes] = cellfun(#histc, a, edges,'uniformoutput', false)
This results in
indexes =
[1]
[2]
[1]
~edit~
To transform your matrices into cell arrays you can use num2cell:
a = num2cell(a);
edges = num2cell(edges, 2);
You could also do:
a = [1; 7; 13];
edges = [1 3 6; 1 4 15; 1 20 30];
bins = sum(bsxfun(#ge, a, edges), 2)
The result:
>> bins
bins =
1
2
1