MATLAB R2014b's library function fitglme is acting up. It seems to be producing invalid intermediate results, cf. following run:
>> formula = 'Y ~ A + (1|B)';
>> glme = fitglme(ds,formula,'Verbose',2);
Starting PL iterations.
============================================================================================
ITER FUN VALUE NORM GRAD NORM STEP CG TERM RHO TRUST RAD ACCEPT
============================================================================================
0 -1.798e+308 0.000e+00 1.250e+03 BNDRY +1.747e+305 1.250e+03 YES
Infinity norm of the final gradient = 0.000e+00
Two norm of the final step = 1.250e+03, TolX = 1.000e-12
Relative infinity norm of the final gradient = 0.000e+00, TolFun = 1.000e-06
EXIT: Local minimum found.
-----------------------------------------------------------------------------------
PL ITER LOGLIK ||ETA|| ||ERR: ETA|| ||W|| ||ERR: ETA->MU->ETA||
-----------------------------------------------------------------------------------
1 NaN 2.797e+00 NaN 4.000e+00 NaN
Error using
classreg.regr.lmeutils.StandardLinearLikeMixedModel/validatey (line
299)
NaN or Inf values are not allowed in y.
Error in classreg.regr.lmeutils.StandardLinearMixedModel/set.y (line
265)
newy = validatey(slme,newy);
Error in
classreg.regr.lmeutils.StandardGeneralizedLinearMixedModel/fitUsingPL
(line 1661)
slme.y = ypw;
Error in
classreg.regr.lmeutils.StandardGeneralizedLinearMixedModel/refit
(line 4315)
[sglme,cause] = fitUsingPL(sglme,numIter,kappa);
Error in classreg.regr.lmeutils.StandardGeneralizedLinearMixedModel
(line 4288)
sglme = refit(sglme);
Error in GeneralizedLinearMixedModel/fitStandardLMEModel (line 1317)
slme =
classreg.regr.lmeutils.StandardGeneralizedLinearMixedModel(X,model.y,Zs,Psi,model.FitMethod,dofit,dostats,args{:});
Error in GeneralizedLinearMixedModel/fitter (line 891)
model.slme = fitStandardLMEModel(model);
Error in classreg.regr.FitObject/doFit (line 220)
model = fitter(model);
Error in GeneralizedLinearMixedModel.fit (line 2411)
model = doFit(model);
Error in fitglme (line 389)
glme = GeneralizedLinearMixedModel.fit(T,formula,varargin{:});
where
ds =
Y A B
2.7971 1 1
2.3801 2 1
1.7125 1 2
0.13291 2 2
0.70898 1 3
1.3898 2 3
0.55758 1 4
0.43072 2 4
-1.3622 1 5
-1.4441 2 5
-0.0781 1 6
0.48738 2 6
-0.77377 1 7
-1.4891 2 7
-1.149 1 8
-0.70913 2 8
Plese help. I am running thousands of these fittings, and I cannot tell why e.g. the data set here does not work, while e.g. the following DOES:
ds =
Y A B
2.8272 1 1
2.4091 2 1
1.6445 1 2
0.11834 2 2
0.66552 1 3
1.3342 2 3
0.53821 1 4
0.35225 2 4
-1.3412 1 5
-1.4446 2 5
-0.092893 1 6
0.44625 2 6
-0.805 1 7
-1.5075 2 7
-1.1167 1 8
-0.7717 2 8
Related
If I have this vector:
x = [1 1 1 1 1 2 2 2 3 4 4 6 6 6 6]
I would like to get the position of each unique number according to itself.
y = [1 2 3 4 5 1 2 3 1 1 2 1 2 3 4]
At the moment I'm using:
y = sum(triu(x==x.')) % MATLAB 2016b and above
It's compact but obviously not memory efficient.
For the pure beauty of MATLAB programming I would avoid using a loop. Do you have a better simple implementation ?
Context:
My final goal is to sort the vector x but with the constraint that a number that appear N times has the priority over another number that has appeared more than N times:
[~,ind] = sort(y);
x_relative_sort = x(ind);
% x_relative_sort = 1 2 3 4 6 1 2 4 6 1 2 6 1 6 1
Assuming x is sorted, here's one vectorized alternative using unique, diff, and cumsum:
[~, index] = unique(x);
y = ones(size(x));
y(index(2:end)) = y(index(2:end))-diff(index).';
y = cumsum(y);
And now you can apply your final sorting:
>> [~, ind] = sort(y);
>> x_relative_sort = x(ind)
x_relative_sort =
1 2 3 4 6 1 2 4 6 1 2 6 1 6 1
If you have positive integers you can use sparse matrix:
[y ,~] = find(sort(sparse(1:numel(x), x, true), 1, 'descend'));
Likewise x_relative_sort can directly be computed:
[x_relative_sort ,~] = find(sort(sparse(x ,1:numel(x),true), 2, 'descend'));
Just for variety, here's a solution based on accumarray. It works for x sorted and containing positive integers, as in the question:
y = cell2mat(accumarray(x(:), x(:), [], #(t){1:numel(t)}).');
You can be more memory efficient by only comparing to unique(x), so you don't have a large N*N matrix but rather N*M, where N=numel(x), M=numel(unique(x)).
I've used an anonymous function syntax to avoid declaring an intermediate matrix variable, needed as it's used twice - this can probably be improved.
f = #(X) sum(cumsum(X,2).*X); y = f(unique(x).'==x);
Here's my solution that doesn't require sorting:
x = [1 1 1 1 1 2 2 2 3 4 4 6 6 6 6 1 1 1];
y = cell2mat( splitapply(#(v){cumsum(v)},x,cumsum(logical([1 diff(x)]))) ) ./ x;
Explanation:
% Turn each group new into a unique number:
t1 = cumsum(logical([1 diff(x)]));
% x = [1 1 1 1 1 2 2 2 3 4 4 6 6 6 6 1 1 1];
% t1 = [1 1 1 1 1 2 2 2 3 4 4 5 5 5 5 6 6 6];
% Apply cumsum separately to each group:
t2 = cell2mat( splitapply(#(v){cumsum(v)},x,t1) );
% t1 = [1 1 1 1 1 2 2 2 3 4 4 5 5 5 5 6 6 6];
% t2 = [1 2 3 4 5 2 4 6 3 4 8 6 12 18 24 1 2 3];
% Finally, divide by x to get the increasing values:
y = t2 ./ x;
% x = [1 1 1 1 1 2 2 2 3 4 4 6 6 6 6 1 1 1];
% t2 = [1 2 3 4 5 2 4 6 3 4 8 6 12 18 24 1 2 3];
I have tried the following code to select the features in the data. The first two columns represent features and the last column represent classes:
clear all;
close all;
data = [27 9 2
11.6723281 28.93422177 2
25 9 2
23 8 2
5.896096039 23.97745722 1
21 6 2
21.16823369 5.292058423 2
4.242640687 13.43502884 1
22 6 2];
Attributes = data(:,1:2);
Classes = data(:,3);
train = [1 3 4 5 6 7];
testInds = [2 8 9];
BC = Classes == 2;
I = rankfeatures(data,BC);
Error using rankfeatures (line 208)
The length of GROUP must equal the number of columns in X.
Error in selection (line 16)
I = rankfeatures(data,BC);
Is there any other function to do this???
I have a vector of 10 random numbers from 1 to 11 (median of the vector 1:11 is 6).
min = 1;
max = 11;
nVector = 10;
VectorRand = randi([min max],1,nVector);
I would like to convert the values in VectorRand to a circular array of 11 values, but with a different median. For example, median 2:
-5(8) -4(9) -3(10) -2(11) -1(1) 0(2) +1(3) +2(4) +3(5) +4(6) +5(7)
Result: 8 9 10 11 1 - 2 - 3 4 5 6 7
in the case of VectorRand = [1 3 8 4 6 8 5 2 6 8 10]
Result: -1 1 -5 2 4 -5 3 0 4 -5 -3
where the median (2 in this case) becomes zero and all the other values are translated in terms of distance from the median (e.g. 8=-5, 9=-4 10=-3 and so on).
The description is confusing, but here's my guess as to what you want:
>> % Set parameters
>> minVal = 1;
>> maxVal = 11;
>> newMedian = 2;
>> % Determine mapping
>> currMedian = median(minVal:maxVal);
>> map = circshift((minVal:maxVal) - currMedian, [0 newMedian - currMedian]);
This is shifting the range of values so that the median is 0 (this will eventually give you the distances from the target median), and then rotating it so the target median is at the center value of the ordering of values. Now, with the mapping built, you can map your vector to this new circulant ring:
>> VectorRand = [1 3 8 4 6 8 5 2 6 8 10];
>> Result = map(VectorRand)
Result =
-1 1 -5 2 4 -5 3 0 4 -5 -3
a contains indices and their occurrences. Now the indexing needs to be changed with Hamming weight so that indices with equal hamming weight will be summed up. How to do the Hamming weight indexing? Any ready command for this in Matlab?
>> a=[1,2;2,3;5,2;10,1;12,2]
1 2
2 3
5 2
10 1
12 2
13 8
>> dec2bin(a(:,1))
ans =
0001
0010
0101
1010
1100
1101
Goal: index things by Hamming weight
HW Count
1 5 (=2+3)
2 5 (=2+1+2)
3 8 (=8)
You can do it as follows:
a = [1,2;2,3;5,2;10,1;12,2;13,8]
the following line needs to be added, to consider also a hammingweight of zero:
if nnz(a(:,1)) == numel(a(:,1)); a = [0,0;a]; end
% or just
a = [0,0;a]; %// wouldn't change the result
to get the indices
rowidx = sum( de2bi(a(:,1)), 2 )
to get the sums
sums = accumarray( rowidx+1, a(:,2) ) %// +1 to consider Hammingweight of zero
to get the Hammingweight vector
HW = unique(rowidx)
returns:
rowidx =
1
1
2
2
2
3
sums =
5
5
8
and all together:
result = [HW, sums]
%or
result = [unique(rowidx), accumarray(rowidx+1,a(:,2))]
result =
0 0
1 5
2 5
3 8
If you are bothered by the 0 0 line, filter it out
result(sum(result,2)>0,:)
The result for a = [0,2;2,3;5,2;10,1;12,2;13,8] would be:
result =
0 2
1 3
2 5
3 8
Try this -
a = [1 2
2 3
5 2
10 1
12 2
13 8]
HW = dec2bin(a(:,1)) - '0';
out = accumarray(sum(HW,2), a(:,2), [], #sum);%%// You don't need that "sum" option it seems, as that's the default operation with accumarray
final_out = [unique(sum(HW,2)) out]
Output -
a =
1 2
2 3
5 2
10 1
12 2
13 8
final_out =
1 5
2 5
3 8
My matrix is this:
0 3 0
0 1 2
4 4 1
I use im2col on it like this:
im2col(A, [2 2], 'sliding')
which correctly yields this:
0 0 3 1
0 4 1 4
3 1 0 2
1 4 2 1
I call this matrix K. Now I use col2im to go back to my original matrix. From the Matlab documentation I use this:
col2im(K, [2 2], [5 5],'sliding')
But this doesn't gives me my original matrix A. Reason being [5 5] should be [4 4] to get a 3*3 matrix for starters. But when I do that I get
??? Error using ==> reshape
To RESHAPE the number of elements must not change.
Why is that? And how can I get my original matrix back?
Fromthe docs:
A = col2im(B,[m n],[mm nn],'sliding') rearranges the row vector B into
a matrix of size (mm-m+1)-by-(nn-n+1). B must be a vector of size
1-by-(mm-m+1)*(nn-n+1). B is usually the result of processing the
output of im2col(...,'sliding') using a column compression function
(such as sum).
So that says to me you should be trying something like:
col2im(sum(K), [2 2], [4 4],'sliding')
however that would require K to have 9 columns. I don't have the image processing toolbox handy to test this right now
Your col2im doesn't work because it uses reshape and for that the number of elements of the matrix you wish to reshape (K) and the new one, need to be the same. This is not the case anymore, as through your transformation of A with im2col you obviously changed that. A has 9 and K 16 elements.
So you basically need to get back to a 3*3 matrix again by getting rid of the redundand doubled elements (due to the overlapping 2*2 blocks used in im2col) in K.
For that you could just make a new matrix (C) with the elements that you need:
C = [K([1,3,11;2,4,12;6,8,16])]
As long as you first went from a 3*3 to a 4*4 matrix using the same order of blocks this should work.
Maybe you could tell us more about what you really want to achieve, because I don't see any reason for this in the first place. It may also be possible that you might be better off using other functions instead, but I can only see that if I know what the reasoning behind your question is.
clear
clc
img = double(imread('tire.tif'));
[r c] = size(img);
w = 8;
imgBlock = im2col(img,[w w],'sliding'); imgBlock = imgBlock(:);
[x y] = meshgrid(1:c,1:r);
xx = im2col(x,[w w], 'sliding'); xx = xx(:);
yy = im2col(y,[w w], 'sliding'); yy = yy(:);
img2 = accumarray([yy xx], imgBlock, [], #mean);
figure,imshow(img, []);
figure,imshow(img2,[]);
% random matrix as image
img = randi(10,4)
img =
6 2 2 7
5 8 7 8
1 4 3 5
4 6 7 1
% matrix size
[r c] = size(img)
% patch size
w = 2;
% image to patch
imgBlock = im2col(img,[w w],'sliding')
% image patchs matrix to a vector
imgBlock = imgBlock(:);
r =
4
c =
4
imgBlock =
6 5 1 2 8 4 2 7 3
5 1 4 8 4 6 7 3 7
2 8 4 2 7 3 7 8 5
8 4 6 7 3 7 8 5 1
% index matrix size equal image size
[x y] = meshgrid(1:c,1:r)
% index matric to patchs;to vector
xx = im2col(x,[w w], 'sliding'); xx = xx(:);
yy = im2col(y,[w w], 'sliding'); yy = yy(:);
x =
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
y =
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
% yy :row index xx: column index
% applies the function mean to each subset of elements in imgBlock that have identical subscripts in [yy xx].
img2 = accumarray([yy xx], imgBlock, [], #mean);
img
img2
img =
6 2 2 7
5 8 7 8
1 4 3 5
4 6 7 1
img2 =
6 2 2 7
5 8 7 8
1 4 3 5
4 6 7 1
% [col,row,value]
a = [xx,yy,imgBlock]
a =
1 1 6
1 2 5
2 1 2
2 2 8
1 2 5
1 3 1
2 2 8
2 3 4
1 3 1
1 4 4
2 3 4
2 4 6
2 1 2
2 2 8
3 1 2
3 2 7
2 2 8
2 3 4
3 2 7
3 3 3
2 3 4
2 4 6
3 3 3
3 4 7
3 1 2
3 2 7
4 1 7
4 2 8
3 2 7
3 3 3
4 2 8
4 3 5
3 3 3
3 4 7
4 3 5
4 4 1
% The number of times that img(2,2) occurs in the matrix img
a(xx == 2 & yy == 2,:)
ans =
2 2 8
2 2 8
2 2 8
2 2 8