Your puzzle comes from a collision of two somewhat subtle facts that i) sapply() is a wrapper for lapply(), not apply() and ii) data.frame()s are secretly columnwise lists. Because of this, sapply = lapply takes each list element = data.frame column and passes it to the column individually. Compare this behavior to
lapply(1:4, function(x) max(x^2)) which converts its not-list input (=c(1,2,3,4)) into a list (= list(1,2,3,4)) before processing. This is different than lapply(list(1:4), function(x) max(x^2)) If you want to work element wise, you can work with apply() rather than sapply(), Vectorize(), or just a plain-ol' for loop. Does this help? Michael PS -- You should nag your collaborator about making a non-vectorized function. If you got the warning message that started this all off, there's likely a bug in his code of the if+else vs ifelse variety. If you've never seen a document called "the R inferno" before, Google it, and take a look through: it's full of all sorts of helpful intermediate level tips and these sorts of subtleties are well documented. On Tue, Dec 27, 2011 at 4:03 PM, Alex Zhang <alex.zh...@ymail.com> wrote: > John, > > Thank you for your comment. > > There is no secret. But the actual function I need to call is rather > irrelevant. However don't take it as the "abs" function. If you like to know, > it is a function that converts 4 kinds of old ids from several old database > tables into a new id in a new database. Again, I don't think providing such > detail is better than saying MyDummyFunc maps a number into a number but > doesn't work with vectors. > > All I need to do, is to call DummyFunc for every element in a column of a > data.frame and returns the resulted vector. But, I cannot change DummyFunc. > Correct me if I am wrong: this is rather common in a group collaboration > enviroment. Person A may be responsible for writing a function and person B > who needs to use that function cannot or better not change it. > > Obviously, I could write a loop. Michael in a previous post suggested using > vectorize which works perfectly. As a newbie of R, I would wish to learn more > ways to achieve my goal (sorry, it automatically involves "how" not just > "what" ;). Is there a way using a "*apply" function to do it where * stands > for any function. > > Thanks a lot! > > > ________________________________ > From: John Fox <j...@mcmaster.ca> > To: 'Alex Zhang' <alex.zh...@ymail.com> > Cc: r-help@r-project.org > Sent: Tuesday, December 27, 2011 4:06 PM > Subject: RE: [R] sapply Call Returning " the condition has length > 1" Error > > Dear Alex, > >> -----Original Message----- >> From: Alex Zhang [mailto:alex.zh...@ymail.com] >> Sent: December-27-11 3:34 PM >> To: John Fox >> Cc: r-help@r-project.org >> Subject: Re: [R] sapply Call Returning " the condition has length > 1" >> Error >> >> John, >> >> Thanks for the pointers. >> >> The DummyFunc is just a made-up example. The true function I need to >> use is more complicated and would be distractive to include. > > You'll probably get a better answer if you don't keep what you want to do a > secret. > >> >> Do you mean that sapply would take columns in the input data.frame and >> feed them into "FUN" as "whole" vectors? That explains the behavior. > > Yes. As I said, a data frame is a list of columns, so FUN is called with > each column as its argument. > >> Is there an "*apply" function that will fee elements of the input >> data.frame into "FUN" instead of whole columns? Thanks. > > I'm afraid that I don't know what you mean. Do you want to deal with the > columns of the data frame separately (in general, they need not all be of > the same class), and within each column, apply a function separately to each > element? You could nest calls to lapply() or sapply(), as in > > sapply(D, function(DD) sapply(DD, abs)) > > assuming, of course, that D is an entirely numeric data frame. But in this > case, > > abs(as.matrix(D)) > > would be more sensible, and using sapply() like this isn't necessarily > better than a loop. Again, not knowing what you want to do makes it hard to > suggest a solution. > > Best, > John > >> >> ________________________________ >> >> From: John Fox <j...@mcmaster.ca> >> To: 'Alex Zhang' <alex.zh...@ymail.com> >> Cc: r-help@r-project.org >> Sent: Tuesday, December 27, 2011 3:10 PM >> Subject: RE: [R] sapply Call Returning " the condition has length > 1" >> Error >> >> Dear Alex, >> >> > -----Original Message----- >> > From: r-help-boun...@r-project.org [mailto:r-help-bounces@r- >> > project.org] On Behalf Of Alex Zhang >> > Sent: December-27-11 2:14 PM >> > To: r-help@r-project.org >> > Subject: [R] sapply Call Returning " the condition has length > 1" >> > Error >> > >> > Dear all, >> > >> > Happy new year! >> > >> > I have a question re using sapply. Below is a dummy example that >> would >> > replicate the error I saw. >> > >> > ##Code Starts here >> > DummyFunc <- function(x) { >> > >> > if (x > 0) { >> > return (x) >> > } else >> > { >> > return (-x) >> > } >> > >> > } >> > >> > Y = data.frame(val = c(-3:7)) >> > sapply(Y, FUN = DummyFunc) >> > ##Code ends here >> > >> > When I run it, I got: >> > val >> > [1,] 3 >> > [2,] 2 >> > [3,] 1 >> > [4,] 0 >> > [5,] -1 >> > [6,] -2 >> > [7,] -3 >> > [8,] -4 >> > [9,] -5 >> > [10,] -6 >> > [11,] -7 >> > Warning message: >> > In if (x > 0) { : >> > the condition has length > 1 and only the first element will be >> used >> > >> > The result is different from what I would expect plus there is such >> an >> > error message. >> >> This is a warning, not really an error message. A data frame is >> essentially a list of variables (columns), and sapply() applies its >> FUN argument to each list element, that is, each variable -- the one >> variable val in your case. >> That produces a warning because val > 0 is a vector of 11 elements, >> and the first comparison, 3 > 0, which is TRUE, controls the result. >> >> > >> > I guess if the DummyFunc I provided is compatible with vectors, the >> > problem would go away. But let's suppose I cannot change DummyFunc. >> Is >> > there still a way to use sapply or alike without actually writing a >> > loop? Thanks. >> >> Well, you could just use >> >> > abs(Y$val) >> [1] 3 2 1 0 1 2 3 4 5 6 7 >> >> but I suppose that you didn't really want to write your own version of >> the absolute-value function as something more than an exercise. >> >> An alternative is >> >> > with(Y, ifelse(val > 0, val, -val)) >> [1] 3 2 1 0 1 2 3 4 5 6 7 >> >> I hope this helps, >> John >> >> -------------------------------- >> John Fox >> Senator William McMaster >> Professor of Social Statistics >> Department of Sociology >> McMaster University >> Hamilton, Ontario, Canada >> http://socserv.mcmaster.ca/jfox >> >> >> >> > >> > - Alex >> > [[alternative HTML version deleted]] >> >> >> >> > [[alternative HTML version deleted]] > > > ______________________________________________ > R-help@r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code. > ______________________________________________ R-help@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.