Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

replace values in a cell with nan

366 views
Skip to first unread message

Andrew Stevens

unread,
Feb 10, 2010, 8:09:06 PM2/10/10
to
Hi all,

I am trying to figure out a way to replace values in a cell array with NaN. I can do it with a loop, but I have somehow got myself into the CELLFUN habit and don't much like the look of the loop:

%generate some data
data=cellfun(@(x)(rand(x,1)),...
num2cell(ceil(rand(5,1)*100)),'un',0);

data =

[26x1 double]
[42x1 double]
[34x1 double]
[30x1 double]
[91x1 double]

%now if I want to replace values greater than 0.5 in each cell I could:

for i=1:length(data)
data{i}(data{i}>0.5)=NaN;
end

Is there a way to do it using CELLFUN? My initial attempt looked something like this:

data=cellfun(@(x)(x(x>0.5)=NaN),data,'un',0);

but that syntax is not valid. Any ideas?

Andrew

Bastian

unread,
Feb 17, 2010, 2:35:10 PM2/17/10
to
"Andrew Stevens" <aste...@JUNKusgs.gov> wrote in message <hkvlbi$14j$1...@fred.mathworks.com>...


I think this should work. It is a vectorized form of your loop:
data(data > 0.5) = NaN;

Bastian

unread,
Feb 17, 2010, 2:35:10 PM2/17/10
to
"Andrew Stevens" <aste...@JUNKusgs.gov> wrote in message <hkvlbi$14j$1...@fred.mathworks.com>...

Bastian

unread,
Feb 17, 2010, 2:54:04 PM2/17/10
to
"Bastian " <bastian...@trentu.removethistext.ca> wrote in message <hlhgde$oqu$1...@fred.mathworks.com>...

sorry, brain malfunction :) that obviously will not work!

Oleg Komarov

unread,
Feb 17, 2010, 3:03:06 PM2/17/10
to
"Andrew Stevens" <aste...@JUNKusgs.gov> wrote in message <hkvlbi$14j$1...@fred.mathworks.com>...

cellfun doesn't support explicit assignment (=).

cellfun(@(x) accumarray(find(x > 0.5),x(x > 0.5),[],[],NaN) , data,'un',0);

This one works only if any values of ALL cell meets the condition > 0.5.

If somebody finds another way...else you can convert to double with cell2mat and riconvert back to cell.
Oleg

Oleg Komarov

unread,
Feb 17, 2010, 3:11:22 PM2/17/10
to
"Oleg Komarov" <oleg.komaro...@hotmail.it> wrote in message <hlhi1q$can$1...@fred.mathworks.com>...

Typo, reverse the condition in the cellfun...still limitations remain, not to talk about performance...I would go for a loop...
Oleg

Walter Roberson

unread,
Feb 17, 2010, 3:08:18 PM2/17/10
to
Oleg Komarov wrote:
> "Andrew Stevens" <aste...@JUNKusgs.gov> wrote in message
> <hkvlbi$14j$1...@fred.mathworks.com>...
>> Hi all,
>>
>> I am trying to figure out a way to replace values in a cell array with
>> NaN. I can do it with a loop, but I have somehow got myself into the
>> CELLFUN habit and don't much like the look of the loop:
>>
>> %generate some data
>> data=cellfun(@(x)(rand(x,1)),...
>> num2cell(ceil(rand(5,1)*100)),'un',0);
>>
>> data =
>> [26x1 double]
>> [42x1 double]
>> [34x1 double]
>> [30x1 double]
>> [91x1 double]
>>
>> %now if I want to replace values greater than 0.5 in each cell I could:
>>
>> for i=1:length(data)
>> data{i}(data{i}>0.5)=NaN;
>> end
>>
>> Is there a way to do it using CELLFUN?

data = cellfun(@(x) x + (sign(inf * (x <= 0.5)) - 1), data);

Oleg Komarov

unread,
Feb 17, 2010, 3:34:22 PM2/17/10
to
Walter Roberson <robe...@hushmail.com> wrote in message <hlhis4$jtb$1...@canopus.cc.umanitoba.ca>...
Nice one, I should remember it...
data = cellfun(@(x) x + (sign(inf * (x <= 0.5)) - 1), data,'un',0);
Just missing the 'un',0.

Oleg

Andrew Stevens

unread,
Feb 17, 2010, 7:58:05 PM2/17/10
to
Walter Roberson <robe...@hushmail.com> wrote in message <hlhis4$jtb$1...@canopus.cc.umanitoba.ca>...

Walter,
That works perfectly. Now if only I could figure it out!

Thanks, Andrew

Nathan

unread,
Feb 17, 2010, 8:16:06 PM2/17/10
to
On Feb 17, 4:58 pm, "Andrew Stevens" <astev...@JUNKusgs.gov> wrote:
> Walter Roberson <rober...@hushmail.com> wrote in message <hlhis4$jt...@canopus.cc.umanitoba.ca>...
> > Oleg Komarov wrote:
> > > "Andrew Stevens" <astev...@JUNKusgs.gov> wrote in message
> > > <hkvlbi$14...@fred.mathworks.com>...

> > >> Hi all,
>
> > >> I am trying to figure out a way to replace values in a cell array with
> > >> NaN.  I can do it with a loop, but I have somehow got myself into the
> > >> CELLFUN habit and don't much like the look of the loop:
>
> > >> %generate some data
> > >> data=cellfun(@(x)(rand(x,1)),...
> > >>     num2cell(ceil(rand(5,1)*100)),'un',0);
>
> > >> data =
> > >>     [26x1 double]
> > >>     [42x1 double]
> > >>     [34x1 double]
> > >>     [30x1 double]
> > >>     [91x1 double]
>
> > >> %now if I want to replace values greater than 0.5 in each cell I could:
>
> > >> for i=1:length(data)
> > >>     data{i}(data{i}>0.5)=NaN;
> > >> end
>
> > >> Is there a way to do it using CELLFUN?
>
> > data = cellfun(@(x) x + (sign(inf * (x <= 0.5)) - 1), data);
>
> Walter,
> That works perfectly.  Now if only I could figure it out!
>
> Thanks, Andrew

The logic behind the algorithm seems to be as follows:
If x is larger than .5, the logic returns 0. 0 * inf = NaN. The sign
of NaN returns NaN. NaN - 1 = NaN. Therefore, NaN replaces the data.
If x is smaller than or equal to .5, the logic returns 1. 1 * inf =
inf. The sign of NaN returns 1. 1 - 1 = 0, therefore no change occurs
to the data.

I hope that helps.

-Nathan

Walter Roberson

unread,
Feb 17, 2010, 8:45:31 PM2/17/10
to
Nathan wrote:

> The logic behind the algorithm seems to be as follows:
> If x is larger than .5, the logic returns 0. 0 * inf = NaN. The sign
> of NaN returns NaN. NaN - 1 = NaN. Therefore, NaN replaces the data.
> If x is smaller than or equal to .5, the logic returns 1. 1 * inf =
> inf. The sign of NaN returns 1. 1 - 1 = 0, therefore no change occurs
> to the data.

Exactly, Nathan. It was just a matter of fishing through my memory and
doing a couple of tests until I found something an asymmetric operation
that produced NaN under some conditions and a numeric value under other
conditions. It helps that I've been doing a lot of stress-testing of
Maple lately, so I knew the kinds of corner-cases to look for.

Nathan

unread,
Feb 17, 2010, 8:54:22 PM2/17/10
to

Ah. One small word switch: "The sign of NaN returns 1." to "The sign
of Inf returns 1."

Brilliant algorithm, by the way. It takes a lot of thinking to come up
with seemingly simple tasks like this.
-Nathan

Yair Altman

unread,
Feb 18, 2010, 3:35:07 AM2/18/10
to
Walter Roberson <robe...@hushmail.com> wrote...

> data = cellfun(@(x) x + (sign(inf * (x <= 0.5)) - 1), data);

A minor improvement to Walt's great answer:
cellfun(@(x)x*sign(inf*(x<=.5)), data);

i.e., there is no need for -1 if we use x* instead of x+

Now, if Matlab only had a much-requested built-in IFF function (if x then y else z) we could have simplified this further to the much more readable:
cellfun(@(x) iff(x>.5,NaN,x), data);

of course, you can always code your own personal iff function for this:

function result = iff(flag, posResult, result)
if flag, result=posResult; end
end % iff

Yair Altman
http://UndocumentedMatlab.com

Jos (10584)

unread,
Feb 18, 2010, 9:02:23 AM2/18/10
to
Nathan <ngre...@gmail.com> wrote in message <8cf70092-e55e-49ac...@l12g2000prg.googlegroups.com>...

Here is a somewhat simpler alternative for the function:

@(x) x + 0 ./ ~(x>0.5)

hth
Jos

Steven Lord

unread,
Feb 18, 2010, 10:19:51 AM2/18/10
to

"Yair Altman" <altma...@gmailDEL.comDEL> wrote in message
news:hliu3r$khr$1...@fred.mathworks.com...

... and this function would NOT do what the user wanted. Remember that when
you call IF with a nonscalar condition (as would be the case using the data
from the OP's example and your CELLFUN call) that ALL the elements of that
condition must be true in order for the condition to be considered true.
Therefore, to make it more explicit, your IFF function would actually be
equivalent to:

function result = iff(flag, posResult, result)

if all(flag)


result=posResult;
end
end % iff

So for the "much-requested built-in IFF function", would you want it to
demonstrate this behavior or to operate element-by-element, and more
importantly how many people do you believe would expect it to work the other
way? [I'm genuinely interested in your answers to the two parts of this
question.]

--
Steve Lord
sl...@mathworks.com
comp.soft-sys.matlab (CSSM) FAQ: http://matlabwiki.mathworks.com/MATLAB_FAQ


Jan Simon

unread,
Feb 18, 2010, 11:05:23 AM2/18/10
to
Dear Andrew!

> I am trying to figure out a way to replace values in a cell array with NaN. I can do it with a loop, but I have somehow got myself into the CELLFUN habit and don't much like the look of the loop:

After some nice solutions have been found, could you be so kind and compare the execution speed with a simple loop?

for iC = 1:numel(C)
aC = C{iC};
aC(aC >= 0.5) = NaN;
C{iC} = aC;
end

Although you don't "like" it, it could be more efficient.

Jan

PS. I do love the "comefrom" command even more than "goto" - but I'm not fond of the debugging hell these flow control methods yield to...

Matt Fig

unread,
Feb 18, 2010, 11:35:15 AM2/18/10
to
"Jan Simon" <matlab.T...@nMINUSsimon.de> wrote in message
> After some nice solutions have been found, could you be so kind and compare the execution speed with a simple loop?
>
> for iC = 1:numel(C)
> aC = C{iC};
> aC(aC >= 0.5) = NaN;
> C{iC} = aC;
> end
>
> Although you don't "like" it, it could be more efficient.

Or even simpler:

for ii = 1:numel(C)
C{ii}(C{ii}(:)>.5) = nan;
end

Oleg Komarov

unread,
Feb 18, 2010, 11:36:05 AM2/18/10
to
> So for the "much-requested built-in IFF function", would you want it to
> demonstrate this behavior or to operate element-by-element, and more
> importantly how many people do you believe would expect it to work the other
> way? [I'm genuinely interested in your answers to the two parts of this
> question.]
>
> --
> Steve Lord
> sl...@mathworks.com
> comp.soft-sys.matlab (CSSM) FAQ: http://matlabwiki.mathworks.com/MATLAB_FAQ

Not sure i understod your question but considering

cellfun(@(x) iff(x>.5,NaN,x), data);

I would expect
for ii = numel(data)
IDX = data{1} > .5
data{1}(IDX) = NaN
data{1}(~IDX) = x % (which is equal to itself in this specific case)
end

I wouldn't want
if all(data{1} > .5)
data{1}(:) = NaN; % neither data{1} = NaN;
else
data{1}(:) = x;
end

Oleg

Andrew Stevens

unread,
Feb 18, 2010, 1:08:05 PM2/18/10
to
"Jan Simon" <matlab.T...@nMINUSsimon.de> wrote in message <hljog3$5sm$1...@fred.mathworks.com>...

> Dear Andrew!
>
> > I am trying to figure out a way to replace values in a cell array with NaN. I can do it with a loop, but I have somehow got myself into the CELLFUN habit and don't much like the look of the loop:
>
> After some nice solutions have been found, could you be so kind and compare the execution speed with a simple loop?
>
> for iC = 1:numel(C)
> aC = C{iC};
> aC(aC >= 0.5) = NaN;
> C{iC} = aC;
> end
>
> Although you don't "like" it, it could be more efficient.
>
> Jan


Jan,
Of course you and Matt are right about the execution speed. For my application, I am not worried about speed.

In many cases for me, using cellfun over a loop is more compact, but that is not the case in this instance (Matt's loop has less characters than Walter's solution). So is there a reason to use the cellfun method for this problem (besides really confusing those you share your code with)? Not sure, but there are cases where Walters method will be slightly more compact:

%generate a structure containing cells
names={'andrew','bastian','walter',...
'oleg','nathan','yair',...
'jos','steven','jan','matt'};
data=cellfun(@(x,y)(rand(50,1)),...
num2cell(1:length(names)),'un',0)';
dstr=cell2struct(data,names);


%replace using walters method
d2=structfun(@(x)(x + (sign(inf * (x <= 0.5)) - 1)),...
dstr,'un',0);

%loop
d2=dstr;
fields=fieldnames(dstr);
for i = 1:length(fields);
d2.(fields{i})(d2.(fields{i})<=0.5) = NaN;
end

Anyway, thanks for all the input!
Andrew

Walter Roberson

unread,
Feb 18, 2010, 1:27:37 PM2/18/10
to
Jos (10584) wrote:

> Here is a somewhat simpler alternative for the function:
>
> @(x) x + 0 ./ ~(x>0.5)

That's a nice improvement, Jos!!

It leads to a simplification by one matrix operation:

@(x) x + 0 ./ (x <= 0.5)

Steven Lord

unread,
Feb 18, 2010, 1:53:33 PM2/18/10
to

"Oleg Komarov" <oleg.komaro...@hotmail.it> wrote in message
news:hljq9l$48t$1...@fred.mathworks.com...

Let me simplify the question by removing the extraneous CELLFUN. What would
your expectation be for the contents of y after these lines of code were
executed?

clear y
x = 0:0.1:1;
y = iff(x > 0.5, NaN, x)

Jan Simon

unread,
Feb 18, 2010, 2:52:02 PM2/18/10
to
Dear Matt!

> > for iC = 1:numel(C)
> > aC = C{iC};
> > aC(aC >= 0.5) = NaN;
> > C{iC} = aC;
> > end

> for ii = 1:numel(C)


> C{ii}(C{ii}(:)>.5) = nan;
> end

Which one is faster on your machine?
I assume the aC method creates a deep copy, while C{ii){C{ii}(:))>.5) is not just a damn tricky smiley but used just shared data copies?

Jan

Oleg Komarov

unread,
Feb 18, 2010, 3:10:22 PM2/18/10
to
"Steven Lord" <sl...@mathworks.com> wrote in message <hlk2b9$fpf$1...@fred.mathworks.com>...
I'd expect element by element:
0.1 0.2 0.3 0.4 0.5 NaN NaN NaN NaN NaN.

The other behavior can be described as follows:
iff(all(x > 0.5), NaN, x)

then if x = .6: .1 :1
x = NaN NaN NaN NaN NaN

Oleg

Yair Altman

unread,
Feb 18, 2010, 6:15:19 PM2/18/10
to
I second Oleg's expectations, but my point with IFF was really simpler - I did not intend IFF to replace CELLFUN, but just to be used by it. This way, it would only work on a single cell-value each time:

cellfun(@(x) iff(x>.5,NaN,x), data)

Of course, data's cell values may themselves be non-scalars, in which case my simple IFF implementation would need to be more complex, but as far as I understood the OP's question, this was not the case, and I just wanted to show a basic solution template.

Again - I fully agree that a built-in IFF would need to handle cells, arrays, structs, objects and other complex types. But even a very basic implementation would be an improvement, because inline conditional statements are currently unavailable in CELLFUN/ARRAYFUN and their kin.

Yair

Matt Fig

unread,
Feb 19, 2010, 2:25:05 PM2/19/10
to
"Jan Simon" <matlab.T...@nMINUSsimon.de> wrote in message <hlk5p2$134$1...@fred.mathworks.com>...


Sorry Jan, I didn't see your reply.
On my machine the C method is consistently 20% faster than the aC and about 6 times faster than cellfun.

0 new messages