Search a position of pattern in a cell array - matlab

I have a cell array as below which contains 17000 such combinations.
'0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1'
'0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1'
'0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1'
'0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0'
'0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1'
'0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0'
'0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0'
'0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0'
'0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1'
'0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0'
'0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0'
I want to search the patterns in an array in a loop. I am interested in the position of that pattern in the cell array using Matlab. I had tried strcmp() function for comparison but it takes lots of time as each pattern is compared with 17000 elements of the cell array.
Is there any fastest method to search a pattern in cell array?

Use bin2dec to convert all entries in the cell array to integers, then convert the search pattern to int as well and search for ints

Related

Comparison between two rows and change value

i have a matrix 20 rows and 20 columns,
If the value 1 in the row 5 the column take 0
matric=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ;
0 1 1 1 1 0 1 0 1 0 1 1 1 0 1 0 1 1 1 1;
0 1 1 0 1 0 1 0 0 0 1 0 1 0 1 0 0 1 0 1;
0 1 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0 1 0 1;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;];
if (matric(5,:)==1)
matric(1:5,1:end)=0;end
I try to compare the second row and the 5 row
If we have "1" in row 2 and row 5
The row 2 take 0
if (matric(5,:)==matric(2,:)==1)
matric(2,1:end)=0;end
do you have an idea
Thank you
The desired output is:
matric=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
1 0 1 1 0 0 1 1 1 1 0 1 0 1 1 1 1 0 1 0 ;2row will change
0 1 1 1 1 0 1 0 1 0 1 1 1 0 1 0 1 1 1 1;
0 1 1 0 1 0 1 0 0 0 1 0 1 0 1 0 0 1 0 1;
0 1 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0 1 0 1; % 5 row
You can use logical indexing.
I strongly encourage you to read the following references:
Mathworks documentation page: Find Array Elements That Meet a Condition
Loren on the Art of MATLAB blog entry: Logical Indexing – Multiple
Conditions
Use the following lines of code:
Put 0 in all those columns that have a value of 1 in row 5:
matric(:, matric(5, :) == 1) = 0;
Put 0 in all those columns of row 2 that have a value of 1 both in rows 2 and 5:
matric(2, matric(2, :) == matric(5, :)) = 0;
You can use logical indexing to achieve this. Now I must say I am a bit confused by what exactly you want to achieve based on your description, but based on the your code the first statement can be done as follow:
matric(1:5,matric(5,:)==1) = 0;
and the second would look like:
matric(2,matric(5,:)==1 & matric(2,:)==1)=0;

Print between patterns -awk

I have the following input file
-------------------------------------
--- A-TKE spectrum (post-neutron)---
-------------------------------------
2-dim. array: (A = 73 To 162 Step 1) (E = 122 To 198 Step 1)
(The data are written according to the loop structure specified above.
The last loop is the inner-most one. Line breaks are not related to the data structure!
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 1 0 0 0 1 0 0 2 0 0 1 0 0 0 0
</A_TKE>
</Results>
This file is part of a bigger file, which contains more number block similar to the above one.
What I want to do is print in a seperate file the numbers that are within the file. As a first try, I thought "Let's print what is between two patters". The START pattern will be --- A-TKE spectrum (post-neutron)--- and the END pattern will </A_TKE>
I used
awk '/--- A-TKE spectrum (post-neutron)---/{flag=1;next}/</A_TKE>/{flag=0}flag{print}' input
To my surprise nothing is printed on the screen. Any idea on why is this happening?
I would also like to now if I can substitue next with a number that will correspond to the line that I want to print after the given pattern.
In perl (because whilst you start with awk, this is tagged as perl too):
perl -ne 'print if m/post-neutron/...m/A_TKE/' input
Which will do what your thingy was trying to.
It works by using the range operator - which is a perl construct which tests if the current file is between two markers.
And the fact that perl can run inline in the same way as awk or sed. -ne says "wrap this code in a while loop" that iterates a line at a time. (e.g. as sed/awk/grep do by default).
Otherwise ... it depends a little on what else is in your file. Because from the sample you gave - the only lines starting with a number are the ones you want. So:
perl -ne 'print if m/^\s*\d+\s*\d+/'
(Or combine the two tests:
perl -ne 'print if m/post-neutron/...m/A_TKE/ and m/^\s*\d+\s*\d+/'
Which will output anything between the two text markers that has number-space-number at the start of line.
Your awk script is almost there. I'd build it like this:
awk '
/<\/A_TKE>/ {exit}
flag && NF==50 {print}
/--- A-TKE spectrum .post-neutron.---/ {flag=1}
' input
You could optimize it of course, but just looking at the logic of it, the idea is that you need do no further processing once you hit your end marker .. and you only want to start printing AFTER your start marker.
Note that I've replaced the brackets in your start marker with dots, since brackets are interpreted as PART OF THE REGULAR EXPRESSION. I believe you may be considering these simple strings to search for, but they are regex.
Some working ideas
Awk can print between two matching lines with this simple command:
awk '/PATTERN1/,/PATTERN2/' file.txt
If you want more control over what happens when the lines are found, you can use the flag approach.
awk '/A-TKE/{f=1;for (i=0;i<7;i++){getline}}/A_TKE/{f=0}f' file.txt
Adjust i<7 to specify how many lines you would like to skip.
Also, in this particular case, you can exploit the fact that you have 50 fields of numbers, which is unlikely to occur anywhere else in the file. Thus, you could also get the numbers of interest out with:
awk 'NF>40' file.txt
NF is a special awk variable that stores the number of fields (columns) in the current record (line).
Why your approach does not work
Your approach does not work, because everything that is between // in awk is treated as a regular expression. In your case you have several - and () in the string, which are not escaped, and thus assume their special meaning and therefore the expression you typed never matches, thus the flag is never set to 1 and awk does not print a line.
Try this simple sed command
sed -n '/A-TKE/,/<\/A_TKE>/p' FileName
If you want to extract rows with just numbers
awk 'NF && !/[a-zA-Z\-]+/' input.file
will generate
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 1 0 0 0 1 0 0 2 0 0 1 0 0 0 0
with patterns and smart counters you can write it as
awk '/\/A_TKE/{exit}
f&&s&&s--{next}
f&&NF{print}
/A-TKE spectrum/{f=1;s=7}' input.file
fine tune patterns as you like.

Matlab: keeping non-zero matrix elements adjacent to each other and ignoring lone elements

Here is an example matrix (but the result shouldn't be constrained to only working on this):
a=zeros(7,7);
a(5,3:6)=1;
a(2,2)=1;
a(2,4)=1;
a(7,1:2)=1
a=
0 0 0 0 0 0 0
0 1 0 1 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 1 1 1 1 0
0 0 0 0 0 0 0
1 1 0 0 0 0 0
I want to get rid of all the 1's that are alone (the noise), such that I only have the line of 1's on the fifth row.
rules:
-the 1's are in 'connected lines' if there are adjacent 1's (including diagonally) e.g.:
0 0 0 1 0 0 1 0 1
1 1 1 0 1 0 0 1 0
0 0 0 0 0 1 0 0 0
(The connected lines are what I want to keep. I want to get rid of all the 1's that are not in connected lines, the connected lines can intersect each other)
the 'connected lines need to be at least 3 elements long. So in the 7x7 example, there would only be one line that matches this criteria. If a(7,3) was set to 1, then there would be a connected line at the bottom left also
I am currently looking at this through a column by column approach, and here is the first draft of my code so far:
for nnn=2:6
rowPoss=find(a(:,nnn)==1);
rowPoss2=find(a(:,nnn+1)==1);
for nn=1:length(rowPoss)
if myResult(rowPoss(nn)-1:rowPoss(nn)+1,n-1)==0 %
%then?
end
end
end
My difficulty is, during this column by column process, I'd have to enable a way to recognise the beginning of the connected line, the middle of the connected line, and when a connected line ends. The same rules for this, when applied to noise (the lone 1's), would just ignore the lone 1's.
The output I want is basically:
b=
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 1 1 1 1 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
If you have image processing toolbox, try bwareaopen
b = bwareaopen(a, 3);
Sample Run #1:
>> a
a =
0 0 0 0 0 0 0
0 1 0 1 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 1 1 1 1 0
0 0 0 0 0 0 0
1 1 0 0 0 0 0
>> b
b =
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 1 1 1 1 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
Sample Run #2:
>> a
a =
0 0 0 0 0 0 0
0 1 0 1 0 0 0
0 0 1 0 0 0 0
0 0 0 0 0 0 0
0 0 1 1 1 1 0
0 0 0 0 0 0 0
1 1 0 0 0 0 0
>> b
b =
0 0 0 0 0 0 0
0 1 0 1 0 0 0
0 0 1 0 0 0 0
0 0 0 0 0 0 0
0 0 1 1 1 1 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0

Flipping Around 5 percent of 1's and 0's

For the following letter, I wish to add noise to it by changing 5 percent of the 1's into 0's. So far, I have the following code which turns them all into 0's. Can someone please point me in the right direction? Thank you!
letterA = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ...
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ...
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ...
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ...
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ...
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 ...
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 ...
0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 ...
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 ...
0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 ...
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 ...
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 ...
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 ...
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 ...
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 ...
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 ...
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 ...
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 ...
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0];
for i=1:numel(letterA)
if letterA(i)==1
letterA(i)=0;
end
end
disp(letterA)
try this:
letterA( letterA == 1 & rand(size(letterA)) <= 0.05 ) = 0;
In fact you could also do
letterA( rand(size(letterA)) <= 0.05 ) = 0;
which sets each element with probability of 5% to zero. The already zero elements are not affected. I think what causes confusion here is that you have to recognize that each element is independently handled from each other. It makes no difference if you do the first or the second version.
You can check it:
letterA = (rand(1e5,1) < 0.2); N1 = nnz(letterA);
letterA( rand(size(letterA)) <= 0.05 ) = 0;
(N1 - nnz(letterA))/N1
which gives values around 0.05, i.e. 5%. And it is not true what EitanT says, that it will flip at maximum 5%. It can be more than 5% or less, but on average it is 5%.
EitanTs version flippes exactly 5%, so which version to select depends on the application. For EitanT version the noise is correlated to the signal (because it is exact), which may or may not be what you want.
The basic approach is to find the indices of the 1's and count them, randomly pick a desired amount of indices out of them, and then operate on them:
one_flip_ratio = 0.05;
idx_ones = find(letterA == 1); %// Indices of 1's
flips = round(one_flip_ratio * numel(idx_ones)); %// Number of flips
idx_flips = idx_ones(randperm(numel(idx_ones), flips)); %// Indices of elements
letterA(idx_flips) = 0; %// Flip elements
This will flip 5% of the 1's to 0's.
Thanks for throwing out all these ideas, but eventually I came up with this. It will allow me to easily control both letter and background noise, which is what I intend to do. I'm just a novice, so this may not be the most efficient code, but it gets the job done! (I'm not looking for exactly 5%, the naked eye display value is what I'm more worried about.) PLEASE let me know how this can be improved! Thank you.
background_noise_intensity=0.05;
letter_noise_intensity=0.05;
for i=1:numel(letterA)
if letterA(i)==0
if rand < background_noise_intensity
letterA(i)=1;
end
elseif letterA(i)==1
if rand < letter_noise_intensity
letterA(i)=0;
end
end
end
noisy_letters=letterA;
reshaped_noisy_letters=reshape(noisy_letters,37,19)';
imshow(reshaped_noisy_letters);

How to replace elements of a matrix by an another matrix in MATLAB?

How to replace elements of a matrix by an another matrix in MATLAB?
Ex: let say if we have a matrix A, where
A=[1 0 0; 0 1 0; 1 0 1]
I want to replace all ones by
J=[1 0 0; 0 1 0; 0 0 1]
and zeros by
K=[0 0 0; 0 0 0; 0 0 0]
So that I can get 9x9 matrix. So how we will code it in MATLAB
Thanks
Sounds like you might want to take a look at the kronecker tensor product. This is not a general case but the idea should work for what you want
>> kron(A==1,J)+kron(A==0,K)
ans =
1 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0 0
1 0 0 0 0 0 1 0 0
0 1 0 0 0 0 0 1 0
0 0 1 0 0 0 0 0 1
which, for the example case, would simplify to a simpler command:
>> kron(A,J)
ans =
1 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0 0
1 0 0 0 0 0 1 0 0
0 1 0 0 0 0 0 1 0
0 0 1 0 0 0 0 0 1
You can do:
A2=imresize(A,size(A).*size(J),'nearest');
J2=repmat(J,size(A));
K2=repmat(K,size(A));
A2(A2==1)=J2(A2==1);
A2(A2==0)=K2(A2==0)