How to transform 'double' into 'cell array'? - arrays

My code:
B = zeros(height(A),1);
col_names = A.Properties.VariableNames; % Replicate header names
for k = 1:height(A)
% the following 'cellfun' compares each column to the values in A.L{k},
% and returns a cell array of the result for each of them, then
% 'cell2mat' converts it to logical array, and 'any' combines the
% results for all elements in A.L{k} to one logical vector:
C = any(cell2mat(...
cellfun(#(x) strcmp(col_names,x),A.L{k},...
'UniformOutput', false).'),1);
% then a logical indexing is used to define the columns for summation:
B(k) = sum(A{k,C});
end
generates the following error message.
Error using cellfun
Input #2 expected to be a cell array, was double instead.
How do I solve this error?
This is how table 'A' looks like:
A.L{1,1} contains:

C = any(cell2mat(...
cellfun(#(x) strcmp(col_names,x),A.L{k},...
'UniformOutput', false).'),1);
here A.L{k} gets the contents of the cell located at the kth position of A.L. Using A.L(k) you get the cell itself which is located at A.L:
tmp = A.L(k);
C = any(cell2mat(...
cellfun(#(x) strcmp(col_names,x),tmp{1},...
'UniformOutput', false).'),1);
Bit of a hacky way, as you first need to get the cell at A.L(k) and then need the contents of that cell, so you need a temporary variable.

I'm not entirely sure quite what's going on here, but here's a fabricated example that I think is similar to what you're trying to achieve.
%% Setup - fabricate some data
colNames = {'xx', 'yy', 'zz', 'qq'};
h = 20;
% It looks like 'L' contains something related to the column names
% so I'm going to build something like that.
L = repmat(colNames, h, 1);
% Empty some rows out completely
L(rand(h,1) > 0.7, :) = {''};
% Empty some other cells out at random
L(rand(numel(L), 1) > 0.8) = {''};
A = table(L, rand(h,1), rand(h, 1), rand(h, 1), rand(h, 1), ...
'VariableNames', ['L', colNames]);
%% Attempt to process each row
varNames = A.Properties.VariableNames;
B = zeros(height(A), 1);
for k = 1:height(A)
% I think this is what's required - work out which columns are
% named in "A.L(k,:)". This can be done simply by using ISMEMBER
% on the row of A.L.
C = ismember(varNames, A.L(k,:));
B(k) = sum(A{k, C});
end
If I'm completely off-course here, then perhaps you could give us an executable example.

Related

Get Matrix 2D from Matrix 3D with a given choice of the third dimension corresponding to the first dimension

I have:
A matrix 3D: A = (m, n, k).
An array of choices for the third dimension corresponding to each index of the first dimension. idn = (m, 1) (wherein the value of any idn is a random integer in [1,k].
I need to capture the 2D matrix B (m,n) wherein the referred third dimension to A is taken from the corresponding choice. For example:
idn(1) = 1;
idn(2) = k;
idn(j) = k-1;
Then:
B(1,:) = A(1,:,idn(1)) = A(1,:,1);
B(2,:) = A(2,:,idn(2)) = A(2,:,k);
B(j,:) = A(j,:,idn(j)) = A(j,:,k-1);
Since idn is not constant, a simple squeeze could not help.
I have also tried the below code, but it does not work either.
B = A(:,:,idn(:));
It is very much appreciated if anyone could give me a solution.
This could be done with sub2ind and permute, but the simplest way I can think of is using linear indexing manually:
A = rand(3, 4, 5); % example data
idn = [5; 1; 2]; % example data
ind = (1:size(A,1)).' + size(A,1)*size(A,2)*(idn(:)-1); % 1st and 3rd dimensions
ind = ind + size(A,1)*(0:size(A,2)-1); % include 2nd dimension using implicit expansion
B = A(ind); % index into A to get result

In MATLAB how can I write out a multidimensional array as a string that looks like a raw numpy array?

The Goal
(Forgive me for length of this, it's mostly background and detail.)
I'm contributing to a TOML encoder/decoder for MATLAB and I'm working with numerical arrays right now. I want to input (and then be able to write out) the numerical array in the same format. This format is the nested square-bracket format that is used by numpy.array. For example, to make multi-dimensional arrays in numpy:
The following is in python, just to be clear. It is a useful example though my work is in MATLAB.
2D arrays
>> x = np.array([1,2])
>> x
array([1, 2])
>> x = np.array([[1],[2]])
>> x
array([[1],
[2]])
3D array
>> x = np.array([[[1,2],[3,4]],[[5,6],[7,8]]])
>> x
array([[[1, 2],
[3, 4]],
[[5, 6],
[7, 8]]])
4D array
>> x = np.array([[[[1,2],[3,4]],[[5,6],[7,8]]],[[[9,10],[11,12]],[[13,14],[15,16]]]])
>> x
array([[[[ 1, 2],
[ 3, 4]],
[[ 5, 6],
[ 7, 8]]],
[[[ 9, 10],
[11, 12]],
[[13, 14],
[15, 16]]]])
The input is a logical construction of the dimensions by nested brackets. Turns out this works pretty well with the TOML array structure. I can already successfully parse and decode any size/any dimension numeric array with this format from TOML to MATLAB numerical array data type.
Now, I want to encode that MATLAB numerical array back into this char/string structure to write back out to TOML (or whatever string).
So I have the following 4D array in MATLAB (same 4D array as with numpy):
>> x = permute(reshape([1:16],2,2,2,2),[2,1,3,4])
x(:,:,1,1) =
1 2
3 4
x(:,:,2,1) =
5 6
7 8
x(:,:,1,2) =
9 10
11 12
x(:,:,2,2) =
13 14
15 16
And I want to turn that into a string that has the same format as the 4D numpy input (with some function named bracketarray or something):
>> str = bracketarray(x)
str =
'[[[[1,2],[3,4]],[[5,6],[7,8]]],[[[9,10],[11,12]],[[13,14],[15,16]]]]'
I can then write out the string to a file.
EDIT: I should add, that the function numpy.array2string() basically does exactly what I want, though it adds some other whitespace characters. But I can't use that as part of the solution, though it is basically the functionality I'm looking for.
The Problem
Here's my problem. I have successfully solved this problem for up to 3 dimensions using the following function, but I cannot for the life of me figure out how to extend it to N-dimensions. I feel like it's an issue of the right kind of counting for each dimension, making sure to not skip any and to nest the brackets correctly.
Current bracketarray.m that works up to 3D
function out = bracketarray(in, internal)
in_size = size(in);
in_dims = ndims(in);
% if array has only 2 dimensions, create the string
if in_dims == 2
storage = cell(in_size(1), 1);
for jj = 1:in_size(1)
storage{jj} = strcat('[', strjoin(split(num2str(in(jj, :)))', ','), ']');
end
if exist('internal', 'var') || in_size(1) > 1 || (in_size(1) == 1 && in_dims >= 3)
out = {strcat('[', strjoin(storage, ','), ']')};
else
out = storage;
end
return
% if array has more than 2 dimensions, recursively send planes of 2 dimensions for encoding
else
out = cell(in_size(end), 1);
for ii = 1:in_size(end) %<--- this doesn't track dimensions or counts of them
out(ii) = bracketarray(in(:,:,ii), 'internal'); %<--- this is limited to 3 dimensions atm. and out(indexing) need help
end
end
% bracket the final bit together
if in_size(1) > 1 || (in_size(1) == 1 && in_dims >= 3)
out = {strcat('[', strjoin(out, ','), ']')};
end
end
Help me Obi-wan Kenobis, y'all are my only hope!
EDIT 2: Added test suite below and modified current code a bit.
Test Suite
Here is a test suite to use to see if the output is what it should be. Basically just copy and paste it into the MATLAB command window. For my current posted code, they all return true except the ones more than 3D. My current code outputs as a cell. If your solution output differently (like a string), then you'll have to remove the curly brackets from the test suite.
isequal(bracketarray(ones(1,1)), {'[1]'})
isequal(bracketarray(ones(2,1)), {'[[1],[1]]'})
isequal(bracketarray(ones(1,2)), {'[1,1]'})
isequal(bracketarray(ones(2,2)), {'[[1,1],[1,1]]'})
isequal(bracketarray(ones(3,2)), {'[[1,1],[1,1],[1,1]]'})
isequal(bracketarray(ones(2,3)), {'[[1,1,1],[1,1,1]]'})
isequal(bracketarray(ones(1,1,2)), {'[[[1]],[[1]]]'})
isequal(bracketarray(ones(2,1,2)), {'[[[1],[1]],[[1],[1]]]'})
isequal(bracketarray(ones(1,2,2)), {'[[[1,1]],[[1,1]]]'})
isequal(bracketarray(ones(2,2,2)), {'[[[1,1],[1,1]],[[1,1],[1,1]]]'})
isequal(bracketarray(ones(1,1,1,2)), {'[[[[1]]],[[[1]]]]'})
isequal(bracketarray(ones(2,1,1,2)), {'[[[[1],[1]]],[[[1],[1]]]]'})
isequal(bracketarray(ones(1,2,1,2)), {'[[[[1,1]]],[[[1,1]]]]'})
isequal(bracketarray(ones(1,1,2,2)), {'[[[[1]],[[1]]],[[[1]],[[1]]]]'})
isequal(bracketarray(ones(2,1,2,2)), {'[[[[1],[1]],[[1],[1]]],[[[1],[1]],[[1],[1]]]]'})
isequal(bracketarray(ones(1,2,2,2)), {'[[[[1,1]],[[1,1]]],[[[1,1]],[[1,1]]]]'})
isequal(bracketarray(ones(2,2,2,2)), {'[[[[1,1],[1,1]],[[1,1],[1,1]]],[[[1,1],[1,1]],[[1,1],[1,1]]]]'})
isequal(bracketarray(permute(reshape([1:16],2,2,2,2),[2,1,3,4])), {'[[[[1,2],[3,4]],[[5,6],[7,8]]],[[[9,10],[11,12]],[[13,14],[15,16]]]]'})
isequal(bracketarray(ones(1,1,1,1,2)), {'[[[[[1]]]],[[[[1]]]]]'})
I think it would be easier to just loop and use join. Your test cases pass.
function out = bracketarray_matlabbit(in)
out = permute(in, [2 1 3:ndims(in)]);
out = string(out);
dimsToCat = ndims(out);
if iscolumn(out)
dimsToCat = dimsToCat-1;
end
for i = 1:dimsToCat
out = "[" + join(out, ",", i) + "]";
end
end
This also seems to be faster than the route you were pursing:
>> x = permute(reshape([1:16],2,2,2,2),[2,1,3,4]);
>> tic; for i = 1:1e4; bracketarray_matlabbit(x); end; toc
Elapsed time is 0.187955 seconds.
>> tic; for i = 1:1e4; bracketarray_cris_luengo(x); end; toc
Elapsed time is 5.859952 seconds.
The recursive function is almost complete. What is missing is a way to index the last dimension. There are several ways to do this, the neatest, I find, is as follows:
n = ndims(x);
index = cell(n-1, 1);
index(:) = {':'};
y = x(index{:}, ii);
It's a little tricky at first, but this is what happens: index is a set of n-1 strings ':'. index{:} is a comma-separated list of these strings. When we index x(index{:},ii) we actually do x(:,:,:,ii) (if n is 4).
The completed recursive function is:
function out = bracketarray(in)
n = ndims(in);
if n == 2
% Fill in your n==2 code here
else
% if array has more than 2 dimensions, recursively send planes of 2 dimensions for encoding
index = cell(n-1, 1);
index(:) = {':'};
storage = cell(size(in, n), 1);
for ii = 1:size(in, n)
storage(ii) = bracketarray(in(index{:}, ii)); % last dimension automatically removed
end
end
out = { strcat('[', strjoin(storage, ','), ']') };
Note that I have preallocated the storage cell array, to prevent it from being resized in every loop iteration. You should do the same in your 2D case code. Preallocating is important in MATLAB for performance reasons, and the MATLAB Editor should warm you about this too.

Matlab- split cell array column by delimiter

I have many 33213168x1 cell arrays, where each cell contains an 85 x 1 column.
Each cell in the column is in the form
[0.55;0.25;0.75]
[0.33;0.66;0.99]
I want to split up this single column by the semi-colon delimiter so that each cell in the cell array is 85x3, like:
[0.55][0.25][0.75]
[0.33][0.66][0.99]
I've tried numerous techniques to solve this, but most commonly get the errors 'cell elements must be character arrays' or 'input must be a string.'
Some of the approaches I've tried:
splitcells = strsplit(regress_original_053108,';');
splitcells = cellfun(#(x) strsplit(regress_original_053108, ';'),regress_original_053108 , 'UniformOutput',0);
splitcells = regexp(regress_original_053108, ';', 'split');
splitcells = textscan(regress_original_053108, 'delimiter', ';');
Etc. Any feedback about how to do this would be appreciated.
Hope this solves your problem:
% Example input
input = {[0.55;0.25;0.75]};
cellArray(1:85,1) = input;
% Create array
doubleArray = zeros(85,3);
% Fill array
for i=1:85
doubleArray(i,:) = cellArray{i,1}';
end
Each cell you have is not a string, hence you can't use strsplit. Use this approach:
for ii = length(X) % Here X denotes your 33213168x1 cell array
X{ii} = cell2mat(cellfun(#(y) y.', X{ii}, 'UniformOutput', false));
end

Matlab find indexes of x min values in column

I there any build function in Matlab which would find in column indexes of x(parameter) min values?
For example:
a = [1; 2; 3; 4; 0; 5]
someFindFunction(a, 2)
ans = [5, 1]
someFindFunction(a, 1)
ans = [5]
someFindFunction(a, 3)
ans = [5, 1, 2]
If you don't mind doing them all, then [~, ans] = sort(a) will do the trick. You can then take the first few elements of ans that you actually need. The build in sort is extremely fast and this should be performant enough despite finding all the mins and not just the ones you need.
#NirFriedman actually did answer your question, but this is an answer that is more self-contained. sort with the second output parameter tells you where each of the values appear in the original matrix after you sort them. As such, if you wanted to make what you asked into a function, you would use the second parameter to index into the second output and only produce those values from the first element up to as many as you desire. Let's also call this something else instead of someFindFunction, like findSmallestLocations. As such:
function [out] = findSmallestLocations(a, ind)
%// Sort the values and get where they're located
[~,b] = sort(a);
%// Retrieve the locations that you want from 1 up to ind
out = b(1:ind);
end
This should now produce what you want. If you want to run this on your own, copy and paste the above code into a M-file called findSmallestLocations.m, then set your current working directory to where this file is located so you can call this function.
Going with your example input and expected outputs, this is what we get:
>> a = [1; 2; 3; 4; 0; 5]
>> findSmallestLocations(a, 2)
ans =
5
1
>> findSmallestLocations(a, 1)
ans =
5
>> findSmallestLocations(a, 3)
ans =
5
1
2

MATLAB: Write string into Excel

I am trying to write an array of coefficients into an Excel file under 1 column (A1). Here is my snippet:
filename = 'cheby2coefs.xlsx';
for Order = 1:1
fprintf('This is');
disp(Order);
[b,a] = cheby2(Order, 20, 300/500);
disp([b,a]);
%xlswrite(filename,{'Order ',Order},'A1'); %string
xlswrite(filename,'b','A1'); %string
xlswrite(filename,b');
xlswrite(filename,'a'); %string
xlswrite(filename,a');
end
The output that i aim for is something like this:
However, my code just keeps creating other sheets. What is the proper way to implement this?
The problem is in the xlswrite lines:
From xlswrite documentation:
xlswrite(filename,A,sheet) writes to the specified worksheet.
That means you are writing string 'b' to sheet 'A1' with xlswrite(filename,'b','A1');
xlswrite(filename,A) writes array A to the first worksheet in Excel
file, filename, starting at cell A1.
You actually do not need to do anything to start writing at A1. Assuming b is a row vector:
xlswrite(filename,b');
as you have written, should suffice.
If you want to specify sheet and column you can use
xlswrite(filename,A,sheet,xlRange)
Update: I cannot try this right now but I think it should work.
You can calculate a and b for every order and write them to an xls file like this:
r = 1; % row number
str = {'a', 'b'};
order = [1 3 5]; % The orders you want to calculate a and b with
for idx = 1:size(order, 2)
[b,a] = cheby2(order(idx), 20, 300/500); % I do not know about second
% and third parameters, you should
% check them.
vals = [a; b]; % assuming they are row vectors
cellName = strcat('A', r);
orderName = strcat('Order ', order(idx));
xlswrite(filename, orderName, 1, cellName)
r = r + 1;
for jdx=1:2
cellName = strcat('A', r);
xlswrite(filename, str{jdx}, 1, cellName);
r = r + 1;
cellName = strcat('A', r);
xlswrite(filename, vals(jdx, :), 1, cellName);
r = r + size(vals, 2);
end
end
xlswrite keeps creating new sheets with every call because you didn't specify the worksheet number.
Instead, try this:
%// Write b under column A1 in the 1st worksheet
xlswrite(filename, 'b', 1, 'A1')
xlswrite(filename, b(:), 1, 'A2')
It's good practice to make sure that b is written as a column by converting it to a column vector first with the b(:) syntax.
In addition, if you want to write the next set of coefficients under column B1, you can do the following:
%// Write a under column B1 in the 1st worksheet
xlswrite(filename, 'a', 1, 'B1')
xlswrite(filename, a(:), 1, 'B2')
Note that the passed sheet number remains 1.
Have you tried xlswrite1 ? You can download the module from here here
Here is the complete module :
filename = 'cheby2coefs.xlsx';
Excel = actxserver('Excel.Application');
Workbook = invoke(Excel.Workbooks, 'open', filename);
set(Excel,'Visible',1);
temp_text= [{'Text'}];
Location = ['A1:A1'];
sheetname = 'Sheet1';
%%
[status, message] = xlswrite1(ExcelFilename, temp_text, sheetname, Location);
if status == 0,
errordlg(message.message);
end
invoke(Workbook,'Save');
invoke(Excel,'Quit');
delete(Excel);
Hope it helps.

Resources