find location of string in matrix - string

I want to find the location of 'N' in a matrix. After this I want to replace that 'N' with the median of that vector in the matrix. I already used these codes for this but I get several errors.
%% put test data in matrix
k=1;
m=1;
n=3;
for j=1:99
percentage2 = j/99
mDataTest(m,1) = str2double(data{1}{j});
mDataTest(m,2) = 0;
for i = 3:50
percentage1 = j/50
if(strcmp(data{i}{j},''))
mDataTest(m,i) = 'N'; %give each "" the median value
elseif(strcmp(data{i}{j},'NULL'))
mDataTest(m,i) = 'N'; %give each "NULL" the median value
else
mDataTest(m,i) = str2double(data{i}{j}); %make matrix with data
end
end
m=m+1;
n=3;
end
Index = find(contains(mDataTest,'N'));
for i = 1 :50
vMedian=median(vDataTest(:,i));
end
mDataTest(Index)= vMedian(Index(2));
Here I use the 'contains' function but I get errors.
Is there someone that can help me?
Thanks!

Your code seems a bit strange to me. Let me try to understand what it is you want to do.
So you start out with a 2D cell variable with text and you want to convert it to a numeric matrix. When cells are empty or contain 'NULL' you want them to have the median value of the row that they are in.
I would start with the conversion and make the empty and 'NULL' cells NaN. (Not a Number) Then find alle the nans and use median with the omitnan flag to replace the nans.
for j=1:99
for i = 1:50
if(strcmp(data{i}{j},'')||strcmp(data{i}{j},'NULL'))
mDataTest(j,i) = nan; %replace with nan
else
mDataTest(j,i) = str2double(data{i}{j}); %convert to number
end
end
end
for j=1:99
for i = 1:50
if isnan(mDataTest(j,i))
mDataTest(j,i) = median(mDataTest(j,:),'omitnan')
end
end
end

Related

why does the code stuck in the while loop even though i try to break on the loop?(matlab)

The code
ite = 5 ;
cell = 5;
MRJIT = xlsread('5 Node.xlsm',1,'L62: P67');
max_col = 5 ;
for m=1:ite
for n=1:max_col
a = randi(cell)
b = randi(cell)
while (eq(a,b) ||(MRJIT(a,n)==0 && MRJIT(b,n)==0))
if (a~=b)&&(MRJIT(a,n)> 0 || MRJIT(b,n)>0)
break;
end
a = randi(cell)
b = randi(cell)
end
MRJIT([a,n b,n]) = MRJIT([b,n a,n]) %swap value
end
end
Code explanation
there are 5 column on this table, 5 node.xls
the point of this code is to swap values between 2 cell on each column from the table above that are selected by choosing 2 random number that is a and b but only if one of the selected cell value is not zero, if both of the cell values equal to zero, it will need to select another 2 random number until the one of the selected cells values is not equal to zero
The Question
1.why does the code stuck in the while loop? when i try to force stop the program, it shows some of the a and b values are not the same or equal to zero, but it kept stuck on the while loop
Why does the program only run on column 1 and not the others?
This statement
MRJIT([a,n b,n]) = MRJIT([b,n a,n])
does not swap two values. [a,n b,n] is the same as [a,n,b,n]. That is, you are addressing three values using linear indexing (one of them twice). Alternatives: use sub2ind to compute linear indices to your two values, so you can swap them in one statement like you tried, or use a temporary variable to store the one value, and swap them indexing one item at the time. There is no direct way in MATLAB to index two elements in one operation, unless the elements are on the same row or column (except using linear indices, of course).
Using the sub2ind alternative, you could write:
a = sub2ind(a,n);
b = sub2ind(b,n)
MRJIT([a,b]) = MRJIT([b,a]);
Note the difference between MRJIT([a,b]) and MRJIT(a,b).
The other alternative is:
tmp = MRJIT(a,n);
MRJIT(a,n) = MRJIT(b,n);
MRJIT(b,n) = tmp;
--
As an aside, you might be able to improve (speed up) the way you find a and b by (not tested):
a = 0;
while(MRJIT(a,n)==0)
a = randi(cell);
end
b = 0;
while (a==b || MRJIT(b,n)==0)
b = randi(cell);
end

Finding indexes of strings in a string array in Matlab

I have two string arrays and I want to find where each string from the first array is in the second array, so i tried this:
for i = 1:length(array1);
cmp(i) = strfind(array2,array1(i,:));
end
This doesn't seem to work and I get an error: "must be one row".
Just for the sake of completeness, an array of strings is nothing but a char matrix. This can be quite restrictive because all of your strings must have the same number of elements. And that's what #neerad29 solution is all about.
However, instead of an array of strings you might want to consider a cell array of strings, in which every string can be arbitrarily long. I will report the very same #neerad29 solution, but with cell arrays. The code will also look a little bit smarter:
a = {'abcd'; 'efgh'; 'ijkl'};
b = {'efgh'; 'abcd'; 'ijkl'};
pos=[];
for i=1:size(a,1)
AreStringFound=cellfun(#(x) strcmp(x,a(i,:)),b);
pos=[pos find(AreStringFound)];
end
But some additional words might be needed:
pos will contain the indices, 2 1 3 in our case, just like #neerad29 's solution
cellfun() is a function which applies a given function, the strcmp() in our case, to every cell of a given cell array. x will be the generic cell from array b which will be compared with a(i,:)
the cellfun() returns a boolean array (AreStringFound) with true in position j if a(i,:) is found in the j-th cell of b and the find() will indeed return the value of j, our proper index. This code is more robust and works also if a given string is found in more than one position in b.
strfind won't work, because it is used to find a string within another string, not within an array of strings. So, how about this:
a = ['abcd'; 'efgh'; 'ijkl'];
b = ['efgh'; 'abcd'; 'ijkl'];
cmp = zeros(1, size(a, 1));
for i = 1:size(a, 1)
for j = 1:size(b, 1)
if strcmp(a(i, :), b(j, :))
cmp(i) = j;
break;
end
end
end
cmp =
2 1 3

Can you group data with similar written column headings on xlswrite, matlab?

Very new to matlab and still learning the basics. I'm trying to write a script which calculates the distance between two peaks in a waveform. That part I have managed to do, and I have used xlswrite to put the values I have obtained onto an excel file.
For each file, I have between about 50-250 columns, with just two rows: the second row has the numerical value, and the first has the column headings, copied from original excel files I extracted the data from.
Some of the columns have similar, but not identical, headings, e.g. 'green227RightEyereading3' and 'green227RightEyereading4' etc. Is there a way I can group columns with similar headings, e.g. which have the same number/colour in the heading (I.e.green227) and either 'right eye' or 'left eye', and calculate an average of their numerical values? Link to file here: >https://www.dropbox.com/s/ezpyjr3raol31ts/SampleBatchForTesting.xls?dl=0>
>[Excel_file,PathName] = uigetfile('*.xls', 'Pick a File','C:\Users\User\Documents\Optometry\Year 3\Dissertation\A-scan3');
>[~,name,ext] = fileparts(Excel_file);
>sheet = 2;
>FullXLSfile = [PathName, Excel_file];
>[number_data,txt_data,raw_data] = xlsread(FullXLSfile,sheet);
>HowManyWide = size(txt_data);
>NumberOfTitles = HowManyWide(1,2);
>xlRangeA = txt_data;
>Chickens = {'Test'};
>for f = 1:xlRangeA; %%defined as top line of cells on sheet;
>Text = xlRangeA{f};
>HyphenLocations = find(Text == '-');
>R = HyphenLocations(1,1) -1;
>Chick = Text(1:R);
>Chick = cellstr(Chick);
>B = length(Chick);
>TF = strncmp(Chickens,Chick,B);
>if any(TF == 1); %do nothing
>else
>Chickens = {Chickens;Chick};
>end
>end
Here also is a link to the file that is created when I run my entire script. The values below the headings are the calculated thickesses of the tissue I'm analysing. https://www.dropbox.com/s/4p6iu9kk75ecyzl/Choroid_Thickness.xls?dl=0
Thanks very much
If the different characters are located at the very end (or the very beginning) of the heading, you can go with strncmp buit-in function and compare only part of the string. See more here. But please, provide some code and a part of your excel file. It would help.
Also, if I am not mistaken, you are saving all the data into excel and then re-call it again in order to sort it. Maybe you should consider saving only the final result in excel, it will save you some time, especially if you want to run your script many times.
EDIT:
Here is the code I came up with. It is not the best possible solution for sure, but it works with the file you uploaded. I have omitted the unnecessary lines and variables. The code works only if the numbers of each reading have the same amount of digits. They can be 4 digits as long as every entry has 4 digits. Since in each file you have waves of the same color, the only thing that you care about is whether the reading was recorded with the left or the right eye (correct?). Based on that and the code you wrote, the comparison concerns the part of the string that contains the words "Right" or "Left", i.e. the characters between the hyphens.
[Excel_file,PathName] = uigetfile('*.xls', 'Pick a File',...
'C:\Users\User\Documents\Optometry\Year 3\Dissertation\A-scan3');
sheet = 1;
FullXLSfile = [PathName,Excel_file];
[number_data,txt_data,raw_data] = xlsread(FullXLSfile,sheet);
%% data manipulation
NumberOfTitles = length(txt_data);
TextToCompare = txt_data{1};
r1 = 1; % counter for Readings1 vector
r2 = 1; % counter for Readings2 vector
for ff = 1:NumberOfTitles % in your code xlRangeA is a cell vector not a number!
Text = txt_data{ff};
HyphenLocations = find(Text == '-');
Text = Text(HyphenLocations(1,1):HyphenLocations(1,2)); % take only the part that contains the "eye" information
TextToCompare = TextToCompare(HyphenLocations(1,1):HyphenLocations(1,2)); % same here
if (Text == TextToCompare)
Readings1(r1) = number_data(ff); % store the numerical value in a vector
r1 = r1 + 1; % increase the counter of this vector
else
Readings2(r2) = number_data(ff); % same here
r2 = r2 + 1;
end
TextToCompare = txt_data{1}; % TextToCompare re-initialized for the next comparison
end
mean_readings1 = mean(Readings1); % Find the mean of the grouped values
mean_readings2 = mean(Readings2);
I am positive that this can be done in a more efficient and delicate way. I don't know exactly what kind of calculations you want to do so I only included the mean values as an example. Inside the if statement you can also store the txt_data if you need it. Below I have also included a second way which I find more delicate. Just substitute the %%data manipulation part with the part below if you want to test it:
%% more delicate way
Text_Vector = char(txt_data);
TextToCompare2 = txt_data{1};
HyphenLocations2 = find(TextToCompare2 == '-');
TextToCompare2 = TextToCompare2(HyphenLocations2(1,1):HyphenLocations2(1,2));
Text_Vector = Text_Vector(:,HyphenLocations2(1,1):HyphenLocations2(1,2));
Text_Vector = cellstr(Text_Vector);
dummy = strcmpi(Text_Vector,TextToCompare2);
Readings1 = number_data(dummy);
Readings2 = number_data(~dummy);
I hope this helps.

MATLAB - Only first column variable gets read when generating function

it might be a basic question. I am a beginner.
When I am trying to import an excel file with 5 columns and row 1 as column header, and generating a function for doing the same, MATLAB is not generating 5 variable as per the column headers, but only one variable and that too with the default name, ans.
Kindly help.
Here is the code:
function [Date,Open,High,Low,Close] = importfile(workbookFile,sheetName,startRow,endRow)
% If no sheet is specified, read first sheet
if nargin == 1 || isempty(sheetName)
sheetName = 1;
end
% If row start and end points are not specified, define defaults
if nargin <= 3
startRow = 2;
endRow = 250;
end
%% Import the data, extracting spreadsheet dates in MATLAB serial date number format (datenum)
[~, ~, raw, dateNums] = xlsread(workbookFile, sheetName, sprintf('A%d:E%d',startRow(1),endRow(1)),'' , #convertSpreadsheetDates);
for block=2:length(startRow)
[~, ~, tmpRawBlock,tmpDateNumBlock] = xlsread(workbookFile, sheetName, sprintf('A%d:E%d',startRow(block),endRow(block)),'' , #convertSpreadsheetDates);
raw = [raw;tmpRawBlock]; %#ok<AGROW>
dateNums = [dateNums;tmpDateNumBlock]; %#ok<AGROW>
end
%% Replace date strings by MATLAB serial date numbers (datenum)
R = ~cellfun(#isequalwithequalnans,dateNums,raw) & cellfun('isclass',raw,'char'); % Find spreadsheet dates
raw(R) = dateNums(R);
%% Create output variable
data = reshape([raw{:}],size(raw));
%% Allocate imported array to column variable names
Date = data(:,1);
Open = data(:,2);
High = data(:,3);
Low = data(:,4);
Close = data(:,5);
Do [Date,Open,High,Low,Close] = importfile('filename.xlsx');

Is it possible to concatenate a string with series of number?

I have a string (eg. 'STA') and I want to make a cell array that will be a concatenation of my sting with a numbers from 1 to X.
I want the code to do something like the fore loop here below:
for i = 1:Num
a = [{a} {strcat('STA',num2str(i))}]
end
I want the end results to be in the form of {<1xNum cell>}
a = 'STA1' 'STA2' 'STA3' ...
(I want to set this to a uitable in the ColumnFormat array)
ColumnFormat = {{a},... % 1
'numeric',... % 2
'numeric'}; % 3
I'm not sure about starting with STA1, but this should get you a list that starts with STA (from which I guess you could remove the first entry).
N = 5;
[X{1:N+1}] = deal('STA');
a = genvarname(X);
a = a(2:end);
You can do it with combination of NUM2STR (converts numbers to strings), CELLSTR (converts strings to cell array), STRTRIM (removes extra spaces)and STRCAT (combines with another string) functions.
You need (:) to make sure the numeric vector is column.
x = 1:Num;
a = strcat( 'STA', strtrim( cellstr( num2str(x(:)) ) ) );
As an alternative for matrix with more dimensions I have this helper function:
function c = num2cellstr(xx, varargin)
%Converts matrix of numeric data to cell array of strings
c = cellfun(#(x) num2str(x,varargin{:}), num2cell(xx), 'UniformOutput', false);
Try this:
N = 10;
a = cell(1,N);
for i = 1:N
a(i) = {['STA',num2str(i)]};
end

Resources